#ifndef BOOST_UUID_UUID_HPP_INCLUDED #define BOOST_UUID_UUID_HPP_INCLUDED // Copyright 2006 Andy Tompkins // Copyright 2024 Peter Dimov // Distributed under the Boost Software License, Version 1.0. // https://www.boost.org/LICENSE_1_0.txt #include #include #include #include #include // for Serialization support #include #include #include #include #include // cheapest std::hash #include #include #include #if defined(__cpp_impl_three_way_comparison) && __cpp_impl_three_way_comparison >= 201907L && defined(__has_include) # if __has_include() # include # if defined(__cpp_lib_three_way_comparison) && __cpp_lib_three_way_comparison >= 201907L # define BOOST_UUID_HAS_THREE_WAY_COMPARISON __cpp_lib_three_way_comparison # elif defined(_LIBCPP_VERSION) // https://github.com/llvm/llvm-project/issues/73953 # define BOOST_UUID_HAS_THREE_WAY_COMPARISON _LIBCPP_VERSION # endif # endif #endif namespace boost { namespace uuids { struct uuid { private: using repr_type = std::uint8_t[ 16 ]; struct data_type { private: union { #if BOOST_WORKAROUND(BOOST_MSVC, < 1910) std::uint8_t repr_[ 16 ] = {}; #else std::uint8_t repr_[ 16 ]; #endif #if !defined(BOOST_UUID_DISABLE_ALIGNMENT) std::uint64_t align_u64_; #endif }; public: operator repr_type& () noexcept { return repr_; } operator repr_type const& () const noexcept { return repr_; } std::uint8_t* operator()() noexcept { return repr_; } std::uint8_t const* operator()() const noexcept { return repr_; } #if BOOST_WORKAROUND(BOOST_MSVC, < 1930) std::uint8_t* operator+( std::ptrdiff_t i ) noexcept { return repr_ + i; } std::uint8_t const* operator+( std::ptrdiff_t i ) const noexcept { return repr_ + i; } std::uint8_t& operator[]( std::ptrdiff_t i ) noexcept { return repr_[ i ]; } std::uint8_t const& operator[]( std::ptrdiff_t i ) const noexcept { return repr_[ i ]; } #endif }; public: // data #if BOOST_WORKAROUND(BOOST_MSVC, < 1910) data_type data; #else data_type data = {}; #endif public: // constructors uuid() = default; uuid( repr_type const& r ) { std::memcpy( data, r, 16 ); } // iteration using value_type = std::uint8_t; using reference = std::uint8_t&; using const_reference = std::uint8_t const&; using iterator = std::uint8_t*; using const_iterator = std::uint8_t const*; using size_type = std::size_t; using difference_type = std::ptrdiff_t; iterator begin() noexcept { return data; } const_iterator begin() const noexcept { return data; } iterator end() noexcept { return data + size(); } const_iterator end() const noexcept { return data + size(); } // size constexpr size_type size() const noexcept { return static_size(); } // This does not work on some compilers // They seem to want the variable defined in // a cpp file //BOOST_STATIC_CONSTANT(size_type, static_size = 16); static constexpr size_type static_size() noexcept { return 16; } // is_nil bool is_nil() const noexcept; // variant enum variant_type { variant_ncs, // NCS backward compatibility variant_rfc_4122, // defined in RFC 4122 document variant_microsoft, // Microsoft Corporation backward compatibility variant_future // future definition }; variant_type variant() const noexcept { // variant is stored in octet 7 // which is index 8, since indexes count backwards unsigned char octet7 = data[8]; // octet 7 is array index 8 if ( (octet7 & 0x80) == 0x00 ) { // 0b0xxxxxxx return variant_ncs; } else if ( (octet7 & 0xC0) == 0x80 ) { // 0b10xxxxxx return variant_rfc_4122; } else if ( (octet7 & 0xE0) == 0xC0 ) { // 0b110xxxxx return variant_microsoft; } else { //assert( (octet7 & 0xE0) == 0xE0 ) // 0b111xxxx return variant_future; } } // version enum version_type { version_unknown = -1, version_time_based = 1, version_dce_security = 2, version_name_based_md5 = 3, version_random_number_based = 4, version_name_based_sha1 = 5, version_time_based_v6 = 6, version_time_based_v7 = 7, version_custom_v8 = 8 }; version_type version() const noexcept { // version is stored in octet 9 // which is index 6, since indexes count backwards std::uint8_t octet9 = data[6]; if ( (octet9 & 0xF0) == 0x10 ) { return version_time_based; } else if ( (octet9 & 0xF0) == 0x20 ) { return version_dce_security; } else if ( (octet9 & 0xF0) == 0x30 ) { return version_name_based_md5; } else if ( (octet9 & 0xF0) == 0x40 ) { return version_random_number_based; } else if ( (octet9 & 0xF0) == 0x50 ) { return version_name_based_sha1; } else if ( (octet9 & 0xF0) == 0x60 ) { return version_time_based_v6; } else if ( (octet9 & 0xF0) == 0x70 ) { return version_time_based_v7; } else if ( (octet9 & 0xF0) == 0x80 ) { return version_custom_v8; } else { return version_unknown; } } // timestamp using timestamp_type = std::uint64_t; timestamp_type timestamp_v1() const noexcept { std::uint32_t time_low = detail::load_big_u32( this->data + 0 ); std::uint16_t time_mid = detail::load_big_u16( this->data + 4 ); std::uint16_t time_hi = detail::load_big_u16( this->data + 6 ) & 0x0FFF; return time_low | static_cast( time_mid ) << 32 | static_cast( time_hi ) << 48; } timestamp_type timestamp_v6() const noexcept { std::uint32_t time_high = detail::load_big_u32( this->data + 0 ); std::uint16_t time_mid = detail::load_big_u16( this->data + 4 ); std::uint16_t time_low = detail::load_big_u16( this->data + 6 ) & 0x0FFF; return time_low | static_cast( time_mid ) << 12 | static_cast( time_high ) << 28; } timestamp_type timestamp_v7() const noexcept { std::uint64_t time_and_version = detail::load_big_u64( this->data + 0 ); return time_and_version >> 16; } // time_point uuid_clock::time_point time_point_v1() const noexcept { return uuid_clock::from_timestamp( timestamp_v1() ); } uuid_clock::time_point time_point_v6() const noexcept { return uuid_clock::from_timestamp( timestamp_v6() ); } std::chrono::time_point time_point_v7() const noexcept { return std::chrono::time_point( std::chrono::milliseconds( timestamp_v7() ) ); } // clock_seq using clock_seq_type = std::uint16_t; clock_seq_type clock_seq() const noexcept { return detail::load_big_u16( this->data + 8 ) & 0x3FFF; } // node_identifier using node_type = std::array; node_type node_identifier() const noexcept { node_type node = {}; std::memcpy( node.data(), this->data + 10, 6 ); return node; } // swap void swap( uuid& rhs ) noexcept; }; // operators inline bool operator==( uuid const& lhs, uuid const& rhs ) noexcept; inline bool operator< ( uuid const& lhs, uuid const& rhs ) noexcept; inline bool operator!=( uuid const& lhs, uuid const& rhs ) noexcept { return !(lhs == rhs); } inline bool operator>( uuid const& lhs, uuid const& rhs ) noexcept { return rhs < lhs; } inline bool operator<=( uuid const& lhs, uuid const& rhs ) noexcept { return !(rhs < lhs); } inline bool operator>=( uuid const& lhs, uuid const& rhs ) noexcept { return !(lhs < rhs); } #if defined(BOOST_UUID_HAS_THREE_WAY_COMPARISON) inline std::strong_ordering operator<=>( uuid const& lhs, uuid const& rhs ) noexcept; #endif // swap inline void swap( uuid& lhs, uuid& rhs ) noexcept { lhs.swap( rhs ); } // hash_value inline std::size_t hash_value( uuid const& u ) noexcept { std::uint64_t r = 0; r = detail::hash_mix_mx( r + detail::load_little_u32( u.data + 0 ) ); r = detail::hash_mix_mx( r + detail::load_little_u32( u.data + 4 ) ); r = detail::hash_mix_mx( r + detail::load_little_u32( u.data + 8 ) ); r = detail::hash_mix_mx( r + detail::load_little_u32( u.data + 12 ) ); return static_cast( detail::hash_mix_fmx( r ) ); } }} //namespace boost::uuids // Boost.Serialization support // BOOST_CLASS_IMPLEMENTATION(boost::uuids::uuid, boost::serialization::primitive_type) namespace boost { namespace serialization { template struct implementation_level_impl; template<> struct implementation_level_impl: boost::integral_constant {}; } // namespace serialization } // namespace boost // std::hash support namespace std { template<> struct hash { std::size_t operator()( boost::uuids::uuid const& value ) const noexcept { return boost::uuids::hash_value( value ); } }; } // namespace std #if defined(BOOST_UUID_USE_SSE2) # include #elif defined(__SIZEOF_INT128__) # include #else # include #endif #endif // BOOST_UUID_UUID_HPP_INCLUDED