123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355 |
- /**
- * @file lluuid.h
- *
- * $LicenseInfo:firstyear=2000&license=viewergpl$
- *
- * Copyright (c) 2000-2009, Linden Research, Inc.
- *
- * Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
- *
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at
- * http://secondlifegrid.net/programs/open_source/licensing/flossexception
- *
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
- *
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
- * $/LicenseInfo$
- */
- #ifndef LL_LLUUID_H
- #define LL_LLUUID_H
- #include <iostream>
- #include <vector>
- #include "llerror.h"
- #include "hbfastset.h"
- #include "stdtypes.h"
- // Defined to 1 to optimize with 64 bits access: 64 bits aligned UUIDs are in
- // no way guaranteed, but thanks to my careful placing (i.e. where they will be
- // aligned on a 8 bytes boundary) of the LLUUIDs in almost all class members
- // blocks, and the fact that 64 bits viewer builds use aligned memory
- // allocations, properly aligned LLUUIDs do represent the overwhelming majority
- // (around 90-95%) of the UUIDs we have to deal with, meaning that working with
- // 64 bits words instead of 32 bits ones *should* be beneficial. *TODO: write a
- // benchmark to verify, since depending on the CPU architecture (number of
- // integer units, cache lines size and performances when crossing their
- // boundaries), our mileage may vary... HB
- #define LLUUID_OPTIMIZE_64_BITS 1
- // Define to 1 for stats about the aligments of all the LLUUIDs created during
- // the session (reported at the end of the log file on viewer exit): use only
- // in devel builds (since the counting slows down LLUUID constructions) to
- // verify the above affirmation about the 64 bits aligned UUIDs percentage, or
- // to further optimize member variables placement in classes. HB
- #define LL_UUID_ALIGMENT_STATS 0
- constexpr S32 UUID_BYTES = 16;
- constexpr S32 UUID_WORDS = 4;
- // Actually "wrong", but used for sizing char[] buffers with a trailing nul.
- constexpr S32 UUID_STR_LENGTH = 37;
- constexpr S32 UUID_STR_SIZE = 36; // Actual string size
- constexpr S32 UUID_BASE85_LENGTH = 21; // including the trailing NULL.
- struct uuid_time_t
- {
- U32 high;
- U32 low;
- };
- class LLUUID
- {
- protected:
- LOG_CLASS(LLUUID);
- public:
- LL_INLINE LLUUID() noexcept
- {
- #if LL_UUID_ALIGMENT_STATS
- incAlignment((intptr_t)mData);
- #endif
- #if LLUUID_OPTIMIZE_64_BITS
- U64* tmp = (U64*)mData;
- *tmp = tmp[1] = 0;
- #else
- U32* tmp = (U32*)mData;
- tmp[0] = tmp[1] = tmp[2] = tmp[3] = 0;
- #endif
- }
- #if LL_UUID_ALIGMENT_STATS
- LL_INLINE LLUUID(const LLUUID& rhs) noexcept
- {
- incAlignment((intptr_t)mData);
- # if LLUUID_OPTIMIZE_64_BITS
- U64* tmp = (U64*)mData;
- U64* rhstmp = (U64*)rhs.mData;
- *tmp = *rhstmp;
- tmp[1] = rhstmp[1];
- # else
- U32* tmp = (U32*)mData;
- U32* rhstmp = (U32*)rhs.mData;
- tmp[0] = rhstmp[0];
- tmp[1] = rhstmp[1];
- tmp[2] = rhstmp[2];
- tmp[3] = rhstmp[3];
- # endif
- }
- #else
- // Trivially copyable.
- LLUUID(const LLUUID& rhs) noexcept = default;
- #endif
- // Make sure the std (and boost) containers will use the default move
- // constructor whenever possible, by explicitely marking it noexcept. HB
- LLUUID(LLUUID&& ptr) noexcept = default;
- // Conversions from strings:
- explicit LLUUID(const char* in_string) noexcept;
- explicit LLUUID(const char* in_string, bool emit) noexcept;
- explicit LLUUID(const std::string& in_string) noexcept;
- explicit LLUUID(const std::string& in_string, bool emit) noexcept;
- ~LLUUID() = default;
- // Trivially copyable.
- LLUUID& operator=(const LLUUID& rhs) noexcept = default;
- LLUUID& operator=(LLUUID&& rhs) noexcept = default;
- // Generate a new UUID:
- void generate();
- // Generate a new UUID based on hash of input stream:
- void generate(const std::string& stream);
- // Static version of above for use in initializer expressions such as
- // constructor params, etc:
- static LLUUID generateNewID(std::string stream = "");
- // Convert from string, if emit is false, do not emit warnings:
- bool set(const char* in_string, bool emit = true);
- // Convert from string, if emit is false, do not emit warnings:
- bool set(const std::string& in_string, bool emit = true);
- // Faster than setting to LLUUID::null.
- LL_INLINE void setNull()
- {
- #if LLUUID_OPTIMIZE_64_BITS
- U64* tmp = (U64*)mData;
- *tmp = tmp[1] = 0;
- #else
- U32* tmp = (U32*)mData;
- tmp[0] = tmp[1] = tmp[2] = tmp[3] = 0;
- #endif
- }
- S32 cmpTime(uuid_time_t* t1, uuid_time_t* t2);
- static void getSystemTime(uuid_time_t* timestamp);
- void getCurrentTime(uuid_time_t* timestamp);
- // Faster than comparing to LLUUID::null.
- LL_INLINE bool isNull() const
- {
- #if LLUUID_OPTIMIZE_64_BITS
- U64* tmp = (U64*)mData;
- return !(*tmp | tmp[1]);
- #else
- U32* tmp = (U32*)mData;
- return !(tmp[0] | tmp[1] | tmp[2] | tmp[3]);
- #endif
- }
- // Faster than comparing to LLUUID::null.
- LL_INLINE bool notNull() const
- {
- #if LLUUID_OPTIMIZE_64_BITS
- U64* tmp = (U64*)mData;
- return (*tmp | tmp[1]) > 0;
- #else
- U32* tmp = (U32*)mData;
- return (tmp[0] | tmp[1] | tmp[2] | tmp[3]) > 0;
- #endif
- }
- LL_INLINE bool operator==(const LLUUID& rhs) const
- {
- #if LLUUID_OPTIMIZE_64_BITS
- U64* tmp = (U64*)mData;
- U64* rhstmp = (U64*)rhs.mData;
- // Note: binary & to avoid branching
- return (*tmp == *rhstmp) & (tmp[1] == rhstmp[1]);
- #else
- U32* tmp = (U32*)mData;
- U32* rhstmp = (U32*)rhs.mData;
- // Note: binary & to avoid branching
- return (tmp[0] == rhstmp[0]) & (tmp[1] == rhstmp[1]) &
- (tmp[2] == rhstmp[2]) & (tmp[3] == rhstmp[3]);
- #endif
- }
- LL_INLINE bool operator!=(const LLUUID& rhs) const
- {
- #if LLUUID_OPTIMIZE_64_BITS
- U64* tmp = (U64*)mData;
- U64* rhstmp = (U64*)rhs.mData;
- // Note: binary | to avoid branching
- return (*tmp != *rhstmp) | (tmp[1] != rhstmp[1]);
- #else
- U32* tmp = (U32*)mData;
- U32* rhstmp = (U32*)rhs.mData;
- // Note: binary | to avoid branching
- return (tmp[0] != rhstmp[0]) | (tmp[1] != rhstmp[1]) |
- (tmp[2] != rhstmp[2]) | (tmp[3] != rhstmp[3]);
- #endif
- }
- // DO NOT "optimize" these two with U32/U64s or you will scoogie the sort
- // order and this will make me very sad. IW
- LL_INLINE bool operator<(const LLUUID& rhs) const
- {
- for (U32 i = 0; i < UUID_BYTES - 1; ++i)
- {
- if (mData[i] != rhs.mData[i])
- {
- return mData[i] < rhs.mData[i];
- }
- }
- return mData[UUID_BYTES - 1] < rhs.mData[UUID_BYTES - 1];
- }
- LL_INLINE bool operator>(const LLUUID& rhs) const
- {
- for (U32 i = 0; i < UUID_BYTES - 1; ++i)
- {
- if (mData[i] != rhs.mData[i])
- {
- return mData[i] > rhs.mData[i];
- }
- }
- return mData[UUID_BYTES - 1] > rhs.mData[UUID_BYTES - 1];
- }
- // Allowing a bool operator would be dangerous as it would allow UUIDs to
- // be cast automatically to integers, among other things. Use isNull() or
- // notNull() instead.
- explicit operator bool() const = delete;
- // XOR functions. Useful since any two random UUIDs xored together will
- // yield a determinate third random unique id that can be used as a key in
- // a single uuid that represents 2.
- const LLUUID& operator^=(const LLUUID& rhs);
- LLUUID operator^(const LLUUID& rhs) const;
- // Similar to functions above, but not invertible. Yields a third random
- // UUID that can be reproduced from the two inputs but which, given the
- // result and one of the inputs cannot be used to deduce the other input.
- LLUUID combine(const LLUUID& other) const;
- void combine(const LLUUID& other, LLUUID& result) const;
- friend std::ostream& operator<<(std::ostream& s, const LLUUID& uuid);
- friend std::istream& operator>>(std::istream& s, LLUUID& uuid);
- std::string asString() const;
- LL_INLINE void toString(std::string& out) const
- {
- // Convert on stack to avoid allocating a temporary std::string
- char uuid_str[UUID_STR_LENGTH];
- toCString(uuid_str);
- out.assign(uuid_str);
- }
- // IMPORTANT: 'out' must point to a buffer of at least 37 bytes.
- void toCString(char* out) const;
- LL_INLINE U32 getCRC32() const
- {
- U32* tmp = (U32*)mData;
- return tmp[0] + tmp[1] + tmp[2] + tmp[3];
- }
- // Returns a 64 bits digest of the UUID, by XORing its two 64 bits long
- // words. HB
- LL_INLINE U64 getDigest64() const
- {
- U64* tmp = (U64*)mData;
- return tmp[0] ^ tmp[1];
- }
- // Validate that the UUID string is legal:
- static bool validate(const std::string& in_string);
- static bool parseUUID(const std::string& buf, LLUUID* value);
- #if LL_UUID_ALIGMENT_STATS
- private:
- static void incAlignment(intptr_t address);
- #endif
- public:
- U8 mData[UUID_BYTES];
- static const LLUUID null;
- #if LL_UUID_ALIGMENT_STATS
- static U64 sAlignmentCounts[8];
- #endif
- };
- typedef std::vector<LLUUID> uuid_vec_t;
- // NOTE: fast_hset *might* work, but let's not assume anything about how
- // iterators will be used (especially after an erase()) on this generic
- // container type, which is so widely used in the viewer code... HB
- typedef safe_hset<LLUUID> uuid_list_t;
- // Sub-class for keeping transaction IDs and asset IDs straight.
- typedef LLUUID LLAssetID;
- class LLTransactionID : public LLUUID
- {
- public:
- LL_INLINE LLTransactionID()
- : LLUUID()
- {
- }
- LLAssetID makeAssetID(const LLUUID& session) const;
- public:
- static const LLTransactionID tnull;
- };
- // std::hash implementation for LLUUID
- namespace std
- {
- template<> struct hash<LLUUID>
- {
- LL_INLINE size_t operator()(const LLUUID& id) const noexcept
- {
- return id.getDigest64();
- }
- };
- }
- // For use with boost::unordered_map and boost::unordered_set
- LL_INLINE size_t hash_value(const LLUUID& id) noexcept
- {
- return id.getDigest64();
- }
- #endif
|