uuid.hpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407
  1. #ifndef BOOST_UUID_UUID_HPP_INCLUDED
  2. #define BOOST_UUID_UUID_HPP_INCLUDED
  3. // Copyright 2006 Andy Tompkins
  4. // Copyright 2024 Peter Dimov
  5. // Distributed under the Boost Software License, Version 1.0.
  6. // https://www.boost.org/LICENSE_1_0.txt
  7. #include <boost/uuid/uuid_clock.hpp>
  8. #include <boost/uuid/detail/endian.hpp>
  9. #include <boost/uuid/detail/hash_mix.hpp>
  10. #include <boost/uuid/detail/config.hpp>
  11. #include <boost/type_traits/integral_constant.hpp> // for Serialization support
  12. #include <boost/config.hpp>
  13. #include <boost/config/workaround.hpp>
  14. #include <array>
  15. #include <chrono>
  16. #include <typeindex> // cheapest std::hash
  17. #include <cstddef>
  18. #include <cstdint>
  19. #include <cstring>
  20. #if defined(__has_builtin)
  21. # if __has_builtin(__builtin_is_constant_evaluated)
  22. # define BOOST_UUID_HAS_BUILTIN_ISCONSTEVAL
  23. # endif
  24. #endif
  25. #if !defined(BOOST_UUID_HAS_BUILTIN_ISCONSTEVAL) && defined(BOOST_MSVC) && BOOST_MSVC >= 1925
  26. # define BOOST_UUID_HAS_BUILTIN_ISCONSTEVAL
  27. #endif
  28. #if defined(__cpp_impl_three_way_comparison) && __cpp_impl_three_way_comparison >= 201907L && defined(__has_include)
  29. # if __has_include(<compare>)
  30. # include <compare>
  31. # if defined(__cpp_lib_three_way_comparison) && __cpp_lib_three_way_comparison >= 201907L
  32. # define BOOST_UUID_HAS_THREE_WAY_COMPARISON __cpp_lib_three_way_comparison
  33. # elif defined(_LIBCPP_VERSION)
  34. // https://github.com/llvm/llvm-project/issues/73953
  35. # define BOOST_UUID_HAS_THREE_WAY_COMPARISON _LIBCPP_VERSION
  36. # endif
  37. # endif
  38. #endif
  39. namespace boost {
  40. namespace uuids {
  41. struct uuid
  42. {
  43. private:
  44. using repr_type = std::uint8_t[ 16 ];
  45. struct data_type
  46. {
  47. private:
  48. union
  49. {
  50. #if BOOST_WORKAROUND(BOOST_MSVC, < 1950)
  51. std::uint8_t repr_[ 16 ] = {};
  52. #else
  53. std::uint8_t repr_[ 16 ];
  54. #endif
  55. #if !defined(BOOST_UUID_DISABLE_ALIGNMENT)
  56. std::uint64_t align_u64_;
  57. #endif
  58. };
  59. public:
  60. BOOST_CXX14_CONSTEXPR operator repr_type& () noexcept { return repr_; }
  61. constexpr operator repr_type const& () const noexcept { return repr_; }
  62. BOOST_CXX14_CONSTEXPR std::uint8_t* operator()() noexcept { return repr_; }
  63. constexpr std::uint8_t const* operator()() const noexcept { return repr_; }
  64. #if BOOST_WORKAROUND(BOOST_MSVC, < 1930)
  65. BOOST_CXX14_CONSTEXPR std::uint8_t* operator+( std::ptrdiff_t i ) noexcept { return repr_ + i; }
  66. constexpr std::uint8_t const* operator+( std::ptrdiff_t i ) const noexcept { return repr_ + i; }
  67. BOOST_CXX14_CONSTEXPR std::uint8_t& operator[]( std::ptrdiff_t i ) noexcept { return repr_[ i ]; }
  68. constexpr std::uint8_t const& operator[]( std::ptrdiff_t i ) const noexcept { return repr_[ i ]; }
  69. #endif
  70. };
  71. public:
  72. // data
  73. #if BOOST_WORKAROUND(BOOST_MSVC, < 1950)
  74. data_type data;
  75. #else
  76. data_type data = {};
  77. #endif
  78. public:
  79. // constructors
  80. uuid() = default;
  81. #if defined(BOOST_NO_CXX14_CONSTEXPR)
  82. uuid( repr_type const& r ) noexcept
  83. {
  84. std::memcpy( data, r, 16 );
  85. }
  86. #elif defined(BOOST_UUID_HAS_BUILTIN_ISCONSTEVAL)
  87. constexpr uuid( repr_type const& r ) noexcept
  88. {
  89. if( __builtin_is_constant_evaluated() )
  90. {
  91. for( int i = 0; i < 16; ++i ) data[ i ] = r[ i ];
  92. }
  93. else
  94. {
  95. std::memcpy( data, r, 16 );
  96. }
  97. }
  98. #else
  99. constexpr uuid( repr_type const& r ) noexcept
  100. {
  101. for( int i = 0; i < 16; ++i ) data[ i ] = r[ i ];
  102. }
  103. #endif
  104. // iteration
  105. using value_type = std::uint8_t;
  106. using reference = std::uint8_t&;
  107. using const_reference = std::uint8_t const&;
  108. using iterator = std::uint8_t*;
  109. using const_iterator = std::uint8_t const*;
  110. using size_type = std::size_t;
  111. using difference_type = std::ptrdiff_t;
  112. BOOST_CXX14_CONSTEXPR iterator begin() noexcept { return data; }
  113. constexpr const_iterator begin() const noexcept { return data; }
  114. BOOST_CXX14_CONSTEXPR iterator end() noexcept { return data() + size(); }
  115. constexpr const_iterator end() const noexcept { return data() + size(); }
  116. // size
  117. constexpr size_type size() const noexcept { return static_size(); }
  118. // This does not work on some compilers
  119. // They seem to want the variable defined in
  120. // a cpp file
  121. //BOOST_STATIC_CONSTANT(size_type, static_size = 16);
  122. static constexpr size_type static_size() noexcept { return 16; }
  123. // is_nil
  124. bool is_nil() const noexcept;
  125. // variant
  126. enum variant_type
  127. {
  128. variant_ncs, // NCS backward compatibility
  129. variant_rfc_4122, // defined in RFC 4122 document
  130. variant_microsoft, // Microsoft Corporation backward compatibility
  131. variant_future // future definition
  132. };
  133. variant_type variant() const noexcept
  134. {
  135. // variant is stored in octet 7
  136. // which is index 8, since indexes count backwards
  137. unsigned char octet7 = data[8]; // octet 7 is array index 8
  138. if ( (octet7 & 0x80) == 0x00 ) { // 0b0xxxxxxx
  139. return variant_ncs;
  140. } else if ( (octet7 & 0xC0) == 0x80 ) { // 0b10xxxxxx
  141. return variant_rfc_4122;
  142. } else if ( (octet7 & 0xE0) == 0xC0 ) { // 0b110xxxxx
  143. return variant_microsoft;
  144. } else {
  145. //assert( (octet7 & 0xE0) == 0xE0 ) // 0b111xxxx
  146. return variant_future;
  147. }
  148. }
  149. // version
  150. enum version_type
  151. {
  152. version_unknown = -1,
  153. version_time_based = 1,
  154. version_dce_security = 2,
  155. version_name_based_md5 = 3,
  156. version_random_number_based = 4,
  157. version_name_based_sha1 = 5,
  158. version_time_based_v6 = 6,
  159. version_time_based_v7 = 7,
  160. version_custom_v8 = 8
  161. };
  162. version_type version() const noexcept
  163. {
  164. // version is stored in octet 9
  165. // which is index 6, since indexes count backwards
  166. std::uint8_t octet9 = data[6];
  167. if ( (octet9 & 0xF0) == 0x10 ) {
  168. return version_time_based;
  169. } else if ( (octet9 & 0xF0) == 0x20 ) {
  170. return version_dce_security;
  171. } else if ( (octet9 & 0xF0) == 0x30 ) {
  172. return version_name_based_md5;
  173. } else if ( (octet9 & 0xF0) == 0x40 ) {
  174. return version_random_number_based;
  175. } else if ( (octet9 & 0xF0) == 0x50 ) {
  176. return version_name_based_sha1;
  177. } else if ( (octet9 & 0xF0) == 0x60 ) {
  178. return version_time_based_v6;
  179. } else if ( (octet9 & 0xF0) == 0x70 ) {
  180. return version_time_based_v7;
  181. } else if ( (octet9 & 0xF0) == 0x80 ) {
  182. return version_custom_v8;
  183. } else {
  184. return version_unknown;
  185. }
  186. }
  187. // timestamp
  188. using timestamp_type = std::uint64_t;
  189. timestamp_type timestamp_v1() const noexcept
  190. {
  191. std::uint32_t time_low = detail::load_big_u32( this->data + 0 );
  192. std::uint16_t time_mid = detail::load_big_u16( this->data + 4 );
  193. std::uint16_t time_hi = detail::load_big_u16( this->data + 6 ) & 0x0FFF;
  194. return time_low | static_cast<std::uint64_t>( time_mid ) << 32 | static_cast<std::uint64_t>( time_hi ) << 48;
  195. }
  196. timestamp_type timestamp_v6() const noexcept
  197. {
  198. std::uint32_t time_high = detail::load_big_u32( this->data + 0 );
  199. std::uint16_t time_mid = detail::load_big_u16( this->data + 4 );
  200. std::uint16_t time_low = detail::load_big_u16( this->data + 6 ) & 0x0FFF;
  201. return time_low | static_cast<std::uint64_t>( time_mid ) << 12 | static_cast<std::uint64_t>( time_high ) << 28;
  202. }
  203. timestamp_type timestamp_v7() const noexcept
  204. {
  205. std::uint64_t time_and_version = detail::load_big_u64( this->data + 0 );
  206. return time_and_version >> 16;
  207. }
  208. // time_point
  209. uuid_clock::time_point time_point_v1() const noexcept
  210. {
  211. return uuid_clock::from_timestamp( timestamp_v1() );
  212. }
  213. uuid_clock::time_point time_point_v6() const noexcept
  214. {
  215. return uuid_clock::from_timestamp( timestamp_v6() );
  216. }
  217. std::chrono::time_point<std::chrono::system_clock, std::chrono::milliseconds> time_point_v7() const noexcept
  218. {
  219. return std::chrono::time_point<std::chrono::system_clock, std::chrono::milliseconds>( std::chrono::milliseconds( timestamp_v7() ) );
  220. }
  221. // clock_seq
  222. using clock_seq_type = std::uint16_t;
  223. clock_seq_type clock_seq() const noexcept
  224. {
  225. return detail::load_big_u16( this->data + 8 ) & 0x3FFF;
  226. }
  227. // node_identifier
  228. using node_type = std::array<std::uint8_t, 6>;
  229. node_type node_identifier() const noexcept
  230. {
  231. node_type node = {{}};
  232. std::memcpy( node.data(), this->data + 10, 6 );
  233. return node;
  234. }
  235. // swap
  236. void swap( uuid& rhs ) noexcept;
  237. };
  238. // operators
  239. inline bool operator==( uuid const& lhs, uuid const& rhs ) noexcept;
  240. inline bool operator< ( uuid const& lhs, uuid const& rhs ) noexcept;
  241. inline bool operator!=( uuid const& lhs, uuid const& rhs ) noexcept
  242. {
  243. return !(lhs == rhs);
  244. }
  245. inline bool operator>( uuid const& lhs, uuid const& rhs ) noexcept
  246. {
  247. return rhs < lhs;
  248. }
  249. inline bool operator<=( uuid const& lhs, uuid const& rhs ) noexcept
  250. {
  251. return !(rhs < lhs);
  252. }
  253. inline bool operator>=( uuid const& lhs, uuid const& rhs ) noexcept
  254. {
  255. return !(lhs < rhs);
  256. }
  257. #if defined(BOOST_UUID_HAS_THREE_WAY_COMPARISON)
  258. inline std::strong_ordering operator<=>( uuid const& lhs, uuid const& rhs ) noexcept;
  259. #endif
  260. // swap
  261. inline void swap( uuid& lhs, uuid& rhs ) noexcept
  262. {
  263. lhs.swap( rhs );
  264. }
  265. // hash_value
  266. inline std::size_t hash_value( uuid const& u ) noexcept
  267. {
  268. std::uint64_t r = 0;
  269. r = detail::hash_mix_mx( r + detail::load_little_u32( u.data + 0 ) );
  270. r = detail::hash_mix_mx( r + detail::load_little_u32( u.data + 4 ) );
  271. r = detail::hash_mix_mx( r + detail::load_little_u32( u.data + 8 ) );
  272. r = detail::hash_mix_mx( r + detail::load_little_u32( u.data + 12 ) );
  273. return static_cast<std::size_t>( detail::hash_mix_fmx( r ) );
  274. }
  275. }} //namespace boost::uuids
  276. // Boost.Serialization support
  277. // BOOST_CLASS_IMPLEMENTATION(boost::uuids::uuid, boost::serialization::primitive_type)
  278. namespace boost
  279. {
  280. namespace serialization
  281. {
  282. template<class T> struct implementation_level_impl;
  283. template<> struct implementation_level_impl<const uuids::uuid>: boost::integral_constant<int, 1> {};
  284. } // namespace serialization
  285. } // namespace boost
  286. // std::hash support
  287. namespace std
  288. {
  289. template<> struct hash<boost::uuids::uuid>
  290. {
  291. std::size_t operator()( boost::uuids::uuid const& value ) const noexcept
  292. {
  293. return boost::uuids::hash_value( value );
  294. }
  295. };
  296. } // namespace std
  297. #if defined(BOOST_UUID_USE_SSE2)
  298. # include <boost/uuid/detail/uuid_x86.ipp>
  299. #elif defined(__SIZEOF_INT128__)
  300. # include <boost/uuid/detail/uuid_uint128.ipp>
  301. #else
  302. # include <boost/uuid/detail/uuid_generic.ipp>
  303. #endif
  304. #endif // BOOST_UUID_UUID_HPP_INCLUDED