lluuid.h 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355
  1. /**
  2. * @file lluuid.h
  3. *
  4. * $LicenseInfo:firstyear=2000&license=viewergpl$
  5. *
  6. * Copyright (c) 2000-2009, Linden Research, Inc.
  7. *
  8. * Second Life Viewer Source Code
  9. * The source code in this file ("Source Code") is provided by Linden Lab
  10. * to you under the terms of the GNU General Public License, version 2.0
  11. * ("GPL"), unless you have obtained a separate licensing agreement
  12. * ("Other License"), formally executed by you and Linden Lab. Terms of
  13. * the GPL can be found in doc/GPL-license.txt in this distribution, or
  14. * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  15. *
  16. * There are special exceptions to the terms and conditions of the GPL as
  17. * it is applied to this Source Code. View the full text of the exception
  18. * in the file doc/FLOSS-exception.txt in this software distribution, or
  19. * online at
  20. * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  21. *
  22. * By copying, modifying or distributing this software, you acknowledge
  23. * that you have read and understood your obligations described above,
  24. * and agree to abide by those obligations.
  25. *
  26. * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  27. * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  28. * COMPLETENESS OR PERFORMANCE.
  29. * $/LicenseInfo$
  30. */
  31. #ifndef LL_LLUUID_H
  32. #define LL_LLUUID_H
  33. #include <iostream>
  34. #include <vector>
  35. #include "llerror.h"
  36. #include "hbfastset.h"
  37. #include "stdtypes.h"
  38. // Defined to 1 to optimize with 64 bits access: 64 bits aligned UUIDs are in
  39. // no way guaranteed, but thanks to my careful placing (i.e. where they will be
  40. // aligned on a 8 bytes boundary) of the LLUUIDs in almost all class members
  41. // blocks, and the fact that 64 bits viewer builds use aligned memory
  42. // allocations, properly aligned LLUUIDs do represent the overwhelming majority
  43. // (around 90-95%) of the UUIDs we have to deal with, meaning that working with
  44. // 64 bits words instead of 32 bits ones *should* be beneficial. *TODO: write a
  45. // benchmark to verify, since depending on the CPU architecture (number of
  46. // integer units, cache lines size and performances when crossing their
  47. // boundaries), our mileage may vary... HB
  48. #define LLUUID_OPTIMIZE_64_BITS 1
  49. // Define to 1 for stats about the aligments of all the LLUUIDs created during
  50. // the session (reported at the end of the log file on viewer exit): use only
  51. // in devel builds (since the counting slows down LLUUID constructions) to
  52. // verify the above affirmation about the 64 bits aligned UUIDs percentage, or
  53. // to further optimize member variables placement in classes. HB
  54. #define LL_UUID_ALIGMENT_STATS 0
  55. constexpr S32 UUID_BYTES = 16;
  56. constexpr S32 UUID_WORDS = 4;
  57. // Actually "wrong", but used for sizing char[] buffers with a trailing nul.
  58. constexpr S32 UUID_STR_LENGTH = 37;
  59. constexpr S32 UUID_STR_SIZE = 36; // Actual string size
  60. constexpr S32 UUID_BASE85_LENGTH = 21; // including the trailing NULL.
  61. struct uuid_time_t
  62. {
  63. U32 high;
  64. U32 low;
  65. };
  66. class LLUUID
  67. {
  68. protected:
  69. LOG_CLASS(LLUUID);
  70. public:
  71. LL_INLINE LLUUID() noexcept
  72. {
  73. #if LL_UUID_ALIGMENT_STATS
  74. incAlignment((intptr_t)mData);
  75. #endif
  76. #if LLUUID_OPTIMIZE_64_BITS
  77. U64* tmp = (U64*)mData;
  78. *tmp = tmp[1] = 0;
  79. #else
  80. U32* tmp = (U32*)mData;
  81. tmp[0] = tmp[1] = tmp[2] = tmp[3] = 0;
  82. #endif
  83. }
  84. #if LL_UUID_ALIGMENT_STATS
  85. LL_INLINE LLUUID(const LLUUID& rhs) noexcept
  86. {
  87. incAlignment((intptr_t)mData);
  88. # if LLUUID_OPTIMIZE_64_BITS
  89. U64* tmp = (U64*)mData;
  90. U64* rhstmp = (U64*)rhs.mData;
  91. *tmp = *rhstmp;
  92. tmp[1] = rhstmp[1];
  93. # else
  94. U32* tmp = (U32*)mData;
  95. U32* rhstmp = (U32*)rhs.mData;
  96. tmp[0] = rhstmp[0];
  97. tmp[1] = rhstmp[1];
  98. tmp[2] = rhstmp[2];
  99. tmp[3] = rhstmp[3];
  100. # endif
  101. }
  102. #else
  103. // Trivially copyable.
  104. LLUUID(const LLUUID& rhs) noexcept = default;
  105. #endif
  106. // Make sure the std (and boost) containers will use the default move
  107. // constructor whenever possible, by explicitely marking it noexcept. HB
  108. LLUUID(LLUUID&& ptr) noexcept = default;
  109. // Conversions from strings:
  110. explicit LLUUID(const char* in_string) noexcept;
  111. explicit LLUUID(const char* in_string, bool emit) noexcept;
  112. explicit LLUUID(const std::string& in_string) noexcept;
  113. explicit LLUUID(const std::string& in_string, bool emit) noexcept;
  114. ~LLUUID() = default;
  115. // Trivially copyable.
  116. LLUUID& operator=(const LLUUID& rhs) noexcept = default;
  117. LLUUID& operator=(LLUUID&& rhs) noexcept = default;
  118. // Generate a new UUID:
  119. void generate();
  120. // Generate a new UUID based on hash of input stream:
  121. void generate(const std::string& stream);
  122. // Static version of above for use in initializer expressions such as
  123. // constructor params, etc:
  124. static LLUUID generateNewID(std::string stream = "");
  125. // Convert from string, if emit is false, do not emit warnings:
  126. bool set(const char* in_string, bool emit = true);
  127. // Convert from string, if emit is false, do not emit warnings:
  128. bool set(const std::string& in_string, bool emit = true);
  129. // Faster than setting to LLUUID::null.
  130. LL_INLINE void setNull()
  131. {
  132. #if LLUUID_OPTIMIZE_64_BITS
  133. U64* tmp = (U64*)mData;
  134. *tmp = tmp[1] = 0;
  135. #else
  136. U32* tmp = (U32*)mData;
  137. tmp[0] = tmp[1] = tmp[2] = tmp[3] = 0;
  138. #endif
  139. }
  140. S32 cmpTime(uuid_time_t* t1, uuid_time_t* t2);
  141. static void getSystemTime(uuid_time_t* timestamp);
  142. void getCurrentTime(uuid_time_t* timestamp);
  143. // Faster than comparing to LLUUID::null.
  144. LL_INLINE bool isNull() const
  145. {
  146. #if LLUUID_OPTIMIZE_64_BITS
  147. U64* tmp = (U64*)mData;
  148. return !(*tmp | tmp[1]);
  149. #else
  150. U32* tmp = (U32*)mData;
  151. return !(tmp[0] | tmp[1] | tmp[2] | tmp[3]);
  152. #endif
  153. }
  154. // Faster than comparing to LLUUID::null.
  155. LL_INLINE bool notNull() const
  156. {
  157. #if LLUUID_OPTIMIZE_64_BITS
  158. U64* tmp = (U64*)mData;
  159. return (*tmp | tmp[1]) > 0;
  160. #else
  161. U32* tmp = (U32*)mData;
  162. return (tmp[0] | tmp[1] | tmp[2] | tmp[3]) > 0;
  163. #endif
  164. }
  165. LL_INLINE bool operator==(const LLUUID& rhs) const
  166. {
  167. #if LLUUID_OPTIMIZE_64_BITS
  168. U64* tmp = (U64*)mData;
  169. U64* rhstmp = (U64*)rhs.mData;
  170. // Note: binary & to avoid branching
  171. return (*tmp == *rhstmp) & (tmp[1] == rhstmp[1]);
  172. #else
  173. U32* tmp = (U32*)mData;
  174. U32* rhstmp = (U32*)rhs.mData;
  175. // Note: binary & to avoid branching
  176. return (tmp[0] == rhstmp[0]) & (tmp[1] == rhstmp[1]) &
  177. (tmp[2] == rhstmp[2]) & (tmp[3] == rhstmp[3]);
  178. #endif
  179. }
  180. LL_INLINE bool operator!=(const LLUUID& rhs) const
  181. {
  182. #if LLUUID_OPTIMIZE_64_BITS
  183. U64* tmp = (U64*)mData;
  184. U64* rhstmp = (U64*)rhs.mData;
  185. // Note: binary | to avoid branching
  186. return (*tmp != *rhstmp) | (tmp[1] != rhstmp[1]);
  187. #else
  188. U32* tmp = (U32*)mData;
  189. U32* rhstmp = (U32*)rhs.mData;
  190. // Note: binary | to avoid branching
  191. return (tmp[0] != rhstmp[0]) | (tmp[1] != rhstmp[1]) |
  192. (tmp[2] != rhstmp[2]) | (tmp[3] != rhstmp[3]);
  193. #endif
  194. }
  195. // DO NOT "optimize" these two with U32/U64s or you will scoogie the sort
  196. // order and this will make me very sad. IW
  197. LL_INLINE bool operator<(const LLUUID& rhs) const
  198. {
  199. for (U32 i = 0; i < UUID_BYTES - 1; ++i)
  200. {
  201. if (mData[i] != rhs.mData[i])
  202. {
  203. return mData[i] < rhs.mData[i];
  204. }
  205. }
  206. return mData[UUID_BYTES - 1] < rhs.mData[UUID_BYTES - 1];
  207. }
  208. LL_INLINE bool operator>(const LLUUID& rhs) const
  209. {
  210. for (U32 i = 0; i < UUID_BYTES - 1; ++i)
  211. {
  212. if (mData[i] != rhs.mData[i])
  213. {
  214. return mData[i] > rhs.mData[i];
  215. }
  216. }
  217. return mData[UUID_BYTES - 1] > rhs.mData[UUID_BYTES - 1];
  218. }
  219. // Allowing a bool operator would be dangerous as it would allow UUIDs to
  220. // be cast automatically to integers, among other things. Use isNull() or
  221. // notNull() instead.
  222. explicit operator bool() const = delete;
  223. // XOR functions. Useful since any two random UUIDs xored together will
  224. // yield a determinate third random unique id that can be used as a key in
  225. // a single uuid that represents 2.
  226. const LLUUID& operator^=(const LLUUID& rhs);
  227. LLUUID operator^(const LLUUID& rhs) const;
  228. // Similar to functions above, but not invertible. Yields a third random
  229. // UUID that can be reproduced from the two inputs but which, given the
  230. // result and one of the inputs cannot be used to deduce the other input.
  231. LLUUID combine(const LLUUID& other) const;
  232. void combine(const LLUUID& other, LLUUID& result) const;
  233. friend std::ostream& operator<<(std::ostream& s, const LLUUID& uuid);
  234. friend std::istream& operator>>(std::istream& s, LLUUID& uuid);
  235. std::string asString() const;
  236. LL_INLINE void toString(std::string& out) const
  237. {
  238. // Convert on stack to avoid allocating a temporary std::string
  239. char uuid_str[UUID_STR_LENGTH];
  240. toCString(uuid_str);
  241. out.assign(uuid_str);
  242. }
  243. // IMPORTANT: 'out' must point to a buffer of at least 37 bytes.
  244. void toCString(char* out) const;
  245. LL_INLINE U32 getCRC32() const
  246. {
  247. U32* tmp = (U32*)mData;
  248. return tmp[0] + tmp[1] + tmp[2] + tmp[3];
  249. }
  250. // Returns a 64 bits digest of the UUID, by XORing its two 64 bits long
  251. // words. HB
  252. LL_INLINE U64 getDigest64() const
  253. {
  254. U64* tmp = (U64*)mData;
  255. return tmp[0] ^ tmp[1];
  256. }
  257. // Validate that the UUID string is legal:
  258. static bool validate(const std::string& in_string);
  259. static bool parseUUID(const std::string& buf, LLUUID* value);
  260. #if LL_UUID_ALIGMENT_STATS
  261. private:
  262. static void incAlignment(intptr_t address);
  263. #endif
  264. public:
  265. U8 mData[UUID_BYTES];
  266. static const LLUUID null;
  267. #if LL_UUID_ALIGMENT_STATS
  268. static U64 sAlignmentCounts[8];
  269. #endif
  270. };
  271. typedef std::vector<LLUUID> uuid_vec_t;
  272. // NOTE: fast_hset *might* work, but let's not assume anything about how
  273. // iterators will be used (especially after an erase()) on this generic
  274. // container type, which is so widely used in the viewer code... HB
  275. typedef safe_hset<LLUUID> uuid_list_t;
  276. // Sub-class for keeping transaction IDs and asset IDs straight.
  277. typedef LLUUID LLAssetID;
  278. class LLTransactionID : public LLUUID
  279. {
  280. public:
  281. LL_INLINE LLTransactionID()
  282. : LLUUID()
  283. {
  284. }
  285. LLAssetID makeAssetID(const LLUUID& session) const;
  286. public:
  287. static const LLTransactionID tnull;
  288. };
  289. // std::hash implementation for LLUUID
  290. namespace std
  291. {
  292. template<> struct hash<LLUUID>
  293. {
  294. LL_INLINE size_t operator()(const LLUUID& id) const noexcept
  295. {
  296. return id.getDigest64();
  297. }
  298. };
  299. }
  300. // For use with boost::unordered_map and boost::unordered_set
  301. LL_INLINE size_t hash_value(const LLUUID& id) noexcept
  302. {
  303. return id.getDigest64();
  304. }
  305. #endif