uuid.hpp 9.7 KB

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