diff options
| author | Amlal <amlal@nekernel.org> | 2025-04-25 13:14:01 +0200 |
|---|---|---|
| committer | Amlal <amlal@nekernel.org> | 2025-04-25 13:14:01 +0200 |
| commit | 20042235d1f53ae428aa154e64afdbae5d8d91ad (patch) | |
| tree | 6ea42d1b30505a57301f8ff2916c78ce94ff6eaf /dev/LibCompiler/UUID.h | |
| parent | 0561a8d0a6ae7588309a6e3513bbfeeef5f0aa15 (diff) | |
meta: update .clang-format, format codebase.
Signed-off-by: Amlal <amlal@nekernel.org>
Diffstat (limited to 'dev/LibCompiler/UUID.h')
| -rw-r--r-- | dev/LibCompiler/UUID.h | 1582 |
1 files changed, 717 insertions, 865 deletions
diff --git a/dev/LibCompiler/UUID.h b/dev/LibCompiler/UUID.h index 84ffd43..d54eec7 100644 --- a/dev/LibCompiler/UUID.h +++ b/dev/LibCompiler/UUID.h @@ -63,921 +63,773 @@ #endif -namespace uuids -{ +namespace uuids { #ifdef __cpp_lib_span - template <class ElementType, std::size_t Extent> - using span = std::span<ElementType, Extent>; +template <class ElementType, std::size_t Extent> +using span = std::span<ElementType, Extent>; #else - template <class ElementType, std::ptrdiff_t Extent> - using span = gsl::span<ElementType, Extent>; +template <class ElementType, std::ptrdiff_t Extent> +using span = gsl::span<ElementType, Extent>; #endif - namespace Detail - { - template <typename TChar> - [[nodiscard]] constexpr inline unsigned char hex2char(TChar const ch) noexcept - { - if (ch >= static_cast<TChar>('0') && ch <= static_cast<TChar>('9')) - return static_cast<unsigned char>(ch - static_cast<TChar>('0')); - if (ch >= static_cast<TChar>('a') && ch <= static_cast<TChar>('f')) - return static_cast<unsigned char>(10 + ch - static_cast<TChar>('a')); - if (ch >= static_cast<TChar>('A') && ch <= static_cast<TChar>('F')) - return static_cast<unsigned char>(10 + ch - static_cast<TChar>('A')); - return 0; - } - - template <typename TChar> - [[nodiscard]] constexpr inline bool is_hex(TChar const ch) noexcept - { - return (ch >= static_cast<TChar>('0') && ch <= static_cast<TChar>('9')) || - (ch >= static_cast<TChar>('a') && ch <= static_cast<TChar>('f')) || - (ch >= static_cast<TChar>('A') && ch <= static_cast<TChar>('F')); - } - - template <typename TChar> - [[nodiscard]] constexpr std::basic_string_view<TChar> to_string_view( - TChar const* str) noexcept - { - if (str) - return str; - return {}; - } - - template <typename StringType> - [[nodiscard]] constexpr std::basic_string_view<typename StringType::value_type, - typename StringType::traits_type> - to_string_view(StringType const& str) noexcept - { - return str; - } - - class sha1 - { - public: - using digest32_t = uint32_t[5]; - using digest8_t = uint8_t[20]; - - static constexpr unsigned int block_bytes = 64; - - [[nodiscard]] inline static uint32_t left_rotate( - uint32_t value, size_t const count) noexcept - { - return (value << count) ^ (value >> (32 - count)); - } - - sha1() - { - reset(); - } - - void reset() noexcept - { - m_digest[0] = 0x67452301; - m_digest[1] = 0xEFCDAB89; - m_digest[2] = 0x98BADCFE; - m_digest[3] = 0x10325476; - m_digest[4] = 0xC3D2E1F0; - m_blockByteIndex = 0; - m_byteCount = 0; - } - - void process_byte(uint8_t octet) - { - this->m_block[this->m_blockByteIndex++] = octet; - ++this->m_byteCount; - if (m_blockByteIndex == block_bytes) - { - this->m_blockByteIndex = 0; - process_block(); - } - } - - void process_block(void const* const start, void const* const end) - { - const uint8_t* begin = static_cast<const uint8_t*>(start); - const uint8_t* finish = static_cast<const uint8_t*>(end); - while (begin != finish) - { - process_byte(*begin); - begin++; - } - } - - void process_bytes(void const* const data, size_t const len) - { - const uint8_t* block = static_cast<const uint8_t*>(data); - process_block(block, block + len); - } - - uint32_t const* get_digest(digest32_t digest) - { - size_t const bitCount = this->m_byteCount * 8; - process_byte(0x80); - if (this->m_blockByteIndex > 56) - { - while (m_blockByteIndex != 0) - { - process_byte(0); - } - while (m_blockByteIndex < 56) - { - process_byte(0); - } - } - else - { - while (m_blockByteIndex < 56) - { - process_byte(0); - } - } - process_byte(0); - process_byte(0); - process_byte(0); - process_byte(0); - process_byte(static_cast<unsigned char>((bitCount >> 24) & 0xFF)); - process_byte(static_cast<unsigned char>((bitCount >> 16) & 0xFF)); - process_byte(static_cast<unsigned char>((bitCount >> 8) & 0xFF)); - process_byte(static_cast<unsigned char>((bitCount)&0xFF)); - - memcpy(digest, m_digest, 5 * sizeof(uint32_t)); - return digest; - } - - uint8_t const* get_digest_bytes(digest8_t digest) - { - digest32_t d32; - get_digest(d32); - size_t di = 0; - digest[di++] = static_cast<uint8_t>(d32[0] >> 24); - digest[di++] = static_cast<uint8_t>(d32[0] >> 16); - digest[di++] = static_cast<uint8_t>(d32[0] >> 8); - digest[di++] = static_cast<uint8_t>(d32[0] >> 0); - - digest[di++] = static_cast<uint8_t>(d32[1] >> 24); - digest[di++] = static_cast<uint8_t>(d32[1] >> 16); - digest[di++] = static_cast<uint8_t>(d32[1] >> 8); - digest[di++] = static_cast<uint8_t>(d32[1] >> 0); - - digest[di++] = static_cast<uint8_t>(d32[2] >> 24); - digest[di++] = static_cast<uint8_t>(d32[2] >> 16); - digest[di++] = static_cast<uint8_t>(d32[2] >> 8); - digest[di++] = static_cast<uint8_t>(d32[2] >> 0); - - digest[di++] = static_cast<uint8_t>(d32[3] >> 24); - digest[di++] = static_cast<uint8_t>(d32[3] >> 16); - digest[di++] = static_cast<uint8_t>(d32[3] >> 8); - digest[di++] = static_cast<uint8_t>(d32[3] >> 0); - - digest[di++] = static_cast<uint8_t>(d32[4] >> 24); - digest[di++] = static_cast<uint8_t>(d32[4] >> 16); - digest[di++] = static_cast<uint8_t>(d32[4] >> 8); - digest[di++] = static_cast<uint8_t>(d32[4] >> 0); - - return digest; - } - - private: - void process_block() - { - uint32_t w[80]; - for (size_t i = 0; i < 16; i++) - { - w[i] = static_cast<uint32_t>(m_block[i * 4 + 0] << 24); - w[i] |= static_cast<uint32_t>(m_block[i * 4 + 1] << 16); - w[i] |= static_cast<uint32_t>(m_block[i * 4 + 2] << 8); - w[i] |= static_cast<uint32_t>(m_block[i * 4 + 3]); - } - for (size_t i = 16; i < 80; i++) - { - w[i] = left_rotate((w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16]), 1); - } - - uint32_t a = m_digest[0]; - uint32_t b = m_digest[1]; - uint32_t c = m_digest[2]; - uint32_t d = m_digest[3]; - uint32_t e = m_digest[4]; - - for (std::size_t i = 0; i < 80; ++i) - { - uint32_t f = 0; - uint32_t k = 0; - - if (i < 20) - { - f = (b & c) | (~b & d); - k = 0x5A827999; - } - else if (i < 40) - { - f = b ^ c ^ d; - k = 0x6ED9EBA1; - } - else if (i < 60) - { - f = (b & c) | (b & d) | (c & d); - k = 0x8F1BBCDC; - } - else - { - f = b ^ c ^ d; - k = 0xCA62C1D6; - } - uint32_t temp = left_rotate(a, 5) + f + e + k + w[i]; - e = d; - d = c; - c = left_rotate(b, 30); - b = a; - a = temp; - } - - m_digest[0] += a; - m_digest[1] += b; - m_digest[2] += c; - m_digest[3] += d; - m_digest[4] += e; - } - - private: - digest32_t m_digest; - uint8_t m_block[64]; - size_t m_blockByteIndex; - size_t m_byteCount; - }; - - template <typename CharT> - inline constexpr CharT empty_guid[37] = "00000000-0000-0000-0000-000000000000"; - - template <> - inline constexpr wchar_t empty_guid<wchar_t>[37] = - L"00000000-0000-0000-0000-000000000000"; - - template <typename CharT> - inline constexpr CharT guid_encoder[17] = "0123456789abcdef"; - - template <> - inline constexpr wchar_t guid_encoder<wchar_t>[17] = L"0123456789abcdef"; - } // namespace Detail - - // -------------------------------------------------------------------------------------------------------------------------- - // UUID format https://tools.ietf.org/html/rfc4122 - // -------------------------------------------------------------------------------------------------------------------------- - - // -------------------------------------------------------------------------------------------------------------------------- - // Field NDR Data Type Octet # Note - // -------------------------------------------------------------------------------------------------------------------------- - // time_low unsigned long 0 - 3 The low field - // of the timestamp. time_mid unsigned short 4 - 5 - // The middle field of the timestamp. time_hi_and_version unsigned - // short 6 - 7 The high field of the timestamp multiplexed - // with the version number. clock_seq_hi_and_reserved unsigned small 8 - // The high field of the clock sequence multiplexed with the variant. - // clock_seq_low unsigned small 9 The low - // field of the clock sequence. node character 10 - // - 15 The spatially unique node identifier. - // -------------------------------------------------------------------------------------------------------------------------- - // 0 1 2 3 - // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - // | time_low | - // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - // | time_mid | time_hi_and_version | - // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - // |clk_seq_hi_res | clk_seq_low | node (0-1) | - // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - // | node (2-5) | - // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - - // -------------------------------------------------------------------------------------------------------------------------- - // enumerations - // -------------------------------------------------------------------------------------------------------------------------- - - // indicated by a bit pattern in octet 8, marked with N in - // xxxxxxxx-xxxx-xxxx-Nxxx-xxxxxxxxxxxx - enum class uuid_variant - { - // NCS backward compatibility (with the obsolete Apollo Network Computing - // System 1.5 UUID format) N bit pattern: 0xxx > the first 6 octets of the - // UUID are a 48-bit timestamp (the number of 4 microsecond units of time - // since 1 Jan 1980 UTC); > the next 2 octets are reserved; > the next octet - // is the "address family"; > the final 7 octets are a 56-bit host ID in the - // form specified by the address family - ncs, - - // RFC 4122/DCE 1.1 - // N bit pattern: 10xx - // > big-endian byte order - rfc, - - // Microsoft Corporation backward compatibility - // N bit pattern: 110x - // > little endian byte order - // > formely used in the Component Object Model (COM) library - microsoft, - - // reserved for possible future definition - // N bit pattern: 111x - reserved - }; - - // indicated by a bit pattern in octet 6, marked with M in - // xxxxxxxx-xxxx-Mxxx-xxxx-xxxxxxxxxxxx - enum class uuid_version - { - none = 0, // only possible for nil or invalid uuids - time_based = 1, // The time-based version specified in RFC 4122 - dce_security = 2, // DCE Security version, with embedded POSIX UIDs. - name_based_md5 = - 3, // The name-based version specified in RFS 4122 with MD5 hashing - random_number_based = 4, // The randomly or pseudo-randomly generated version - // specified in RFS 4122 - name_based_sha1 = - 5 // The name-based version specified in RFS 4122 with SHA1 hashing - }; - - // Forward declare uuid & to_string so that we can declare to_string as a friend - // later. - class uuid; - template <class CharT = char, class Traits = std::char_traits<CharT>, class Allocator = std::allocator<CharT>> - std::basic_string<CharT, Traits, Allocator> to_string(uuid const& id); - - // -------------------------------------------------------------------------------------------------------------------------- - // uuid class - // -------------------------------------------------------------------------------------------------------------------------- - class uuid - { - public: - using value_type = uint8_t; - - constexpr uuid() noexcept = default; - - uuid(value_type (&arr)[16]) noexcept - { - std::copy(std::cbegin(arr), std::cend(arr), std::begin(data)); - } - - constexpr uuid(std::array<value_type, 16> const& arr) noexcept - : data{arr} - { - } - - explicit uuid(span<value_type, 16> bytes) - { - std::copy(std::cbegin(bytes), std::cend(bytes), std::begin(data)); - } - - template <typename ForwardIterator> - explicit uuid(ForwardIterator first, ForwardIterator last) - { - if (std::distance(first, last) == 16) - std::copy(first, last, std::begin(data)); - } - - [[nodiscard]] constexpr uuid_variant variant() const noexcept - { - if ((data[8] & 0x80) == 0x00) - return uuid_variant::ncs; - else if ((data[8] & 0xC0) == 0x80) - return uuid_variant::rfc; - else if ((data[8] & 0xE0) == 0xC0) - return uuid_variant::microsoft; - else - return uuid_variant::reserved; - } - - [[nodiscard]] constexpr uuid_version version() const noexcept - { - if ((data[6] & 0xF0) == 0x10) - return uuid_version::time_based; - else if ((data[6] & 0xF0) == 0x20) - return uuid_version::dce_security; - else if ((data[6] & 0xF0) == 0x30) - return uuid_version::name_based_md5; - else if ((data[6] & 0xF0) == 0x40) - return uuid_version::random_number_based; - else if ((data[6] & 0xF0) == 0x50) - return uuid_version::name_based_sha1; - else - return uuid_version::none; - } - - [[nodiscard]] constexpr bool is_nil() const noexcept - { - for (size_t i = 0; i < data.size(); ++i) - if (data[i] != 0) - return false; - return true; - } - - void swap(uuid& other) noexcept - { - data.swap(other.data); - } - - [[nodiscard]] inline span<std::byte const, 16> as_bytes() const - { - return span<std::byte const, 16>( - reinterpret_cast<std::byte const*>(data.data()), 16); - } - - template <typename StringType> - [[nodiscard]] constexpr static bool is_valid_uuid( - StringType const& in_str) noexcept - { - auto str = Detail::to_string_view(in_str); - bool firstDigit = true; - size_t hasBraces = 0; - size_t index = 0; - - if (str.empty()) - return false; - - if (str.front() == '{') - hasBraces = 1; - if (hasBraces && str.back() != '}') - return false; - - for (size_t i = hasBraces; i < str.size() - hasBraces; ++i) - { - if (str[i] == '-') - continue; - - if (index >= 16 || !Detail::is_hex(str[i])) - { - return false; - } - - if (firstDigit) - { - firstDigit = false; - } - else - { - index++; - firstDigit = true; - } - } - - if (index < 16) - { - return false; - } - - return true; - } - - template <typename StringType> - [[nodiscard]] constexpr static std::optional<uuid> from_string( - StringType const& in_str) noexcept - { - auto str = Detail::to_string_view(in_str); - bool firstDigit = true; - size_t hasBraces = 0; - size_t index = 0; - - std::array<uint8_t, 16> data{{0}}; - - if (str.empty()) - return {}; - - if (str.front() == '{') - hasBraces = 1; - if (hasBraces && str.back() != '}') - return {}; - - for (size_t i = hasBraces; i < str.size() - hasBraces; ++i) - { - if (str[i] == '-') - continue; - - if (index >= 16 || !Detail::is_hex(str[i])) - { - return {}; - } - - if (firstDigit) - { - data[index] = static_cast<uint8_t>(Detail::hex2char(str[i]) << 4); - firstDigit = false; - } - else - { - data[index] = - static_cast<uint8_t>(data[index] | Detail::hex2char(str[i])); - index++; - firstDigit = true; - } - } - - if (index < 16) - { - return {}; - } - - return uuid{data}; - } - - private: - std::array<value_type, 16> data{{0}}; - - friend bool operator==(uuid const& lhs, uuid const& rhs) noexcept; - friend bool operator<(uuid const& lhs, uuid const& rhs) noexcept; - - template <class Elem, class Traits> - friend std::basic_ostream<Elem, Traits>& operator<<( - std::basic_ostream<Elem, Traits>& s, uuid const& id); - - template <class CharT, class Traits, class Allocator> - friend std::basic_string<CharT, Traits, Allocator> to_string(uuid const& id); - - friend std::hash<uuid>; - }; - - // -------------------------------------------------------------------------------------------------------------------------- - // operators and non-member functions - // -------------------------------------------------------------------------------------------------------------------------- - - [[nodiscard]] inline bool operator==(uuid const& lhs, - uuid const& rhs) noexcept - { - return lhs.data == rhs.data; - } - - [[nodiscard]] inline bool operator!=(uuid const& lhs, - uuid const& rhs) noexcept - { - return !(lhs == rhs); - } - - [[nodiscard]] inline bool operator<(uuid const& lhs, uuid const& rhs) noexcept - { - return lhs.data < rhs.data; - } - - template <class CharT, class Traits, class Allocator> - [[nodiscard]] inline std::basic_string<CharT, Traits, Allocator> to_string( - uuid const& id) - { - std::basic_string<CharT, Traits, Allocator> uustr{Detail::empty_guid<CharT>}; - - for (size_t i = 0, index = 0; i < 36; ++i) - { - if (i == 8 || i == 13 || i == 18 || i == 23) - { - continue; - } - uustr[i] = Detail::guid_encoder<CharT>[id.data[index] >> 4 & 0x0f]; - uustr[++i] = Detail::guid_encoder<CharT>[id.data[index] & 0x0f]; - index++; - } - - return uustr; - } - - template <class Elem, class Traits> - std::basic_ostream<Elem, Traits>& operator<<( - std::basic_ostream<Elem, Traits>& s, uuid const& id) - { - s << to_string(id); - return s; - } - - inline void swap(uuids::uuid& lhs, uuids::uuid& rhs) noexcept - { - lhs.swap(rhs); - } - - // -------------------------------------------------------------------------------------------------------------------------- - // namespace IDs that could be used for generating name-based uuids - // -------------------------------------------------------------------------------------------------------------------------- - - // Name string is a fully-qualified domain name - static uuid uuid_namespace_dns{{0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1, - 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, - 0xc8}}; - - // Name string is a URL - static uuid uuid_namespace_url{{0x6b, 0xa7, 0xb8, 0x11, 0x9d, 0xad, 0x11, 0xd1, - 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, - 0xc8}}; - - // Name string is an ISO OID (See https://oidref.com/, - // https://en.wikipedia.org/wiki/Object_identifier) - static uuid uuid_namespace_oid{{0x6b, 0xa7, 0xb8, 0x12, 0x9d, 0xad, 0x11, 0xd1, - 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, - 0xc8}}; - - // Name string is an X.500 DN, in DER or a text output format (See - // https://en.wikipedia.org/wiki/X.500, - // https://en.wikipedia.org/wiki/Abstract_Syntax_Notation_One) - static uuid uuid_namespace_x500{{0x6b, 0xa7, 0xb8, 0x14, 0x9d, 0xad, 0x11, 0xd1, - 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, - 0xc8}}; - - // -------------------------------------------------------------------------------------------------------------------------- - // uuid generators - // -------------------------------------------------------------------------------------------------------------------------- +namespace Detail { + template <typename TChar> + [[nodiscard]] constexpr inline unsigned char hex2char(TChar const ch) noexcept { + if (ch >= static_cast<TChar>('0') && ch <= static_cast<TChar>('9')) + return static_cast<unsigned char>(ch - static_cast<TChar>('0')); + if (ch >= static_cast<TChar>('a') && ch <= static_cast<TChar>('f')) + return static_cast<unsigned char>(10 + ch - static_cast<TChar>('a')); + if (ch >= static_cast<TChar>('A') && ch <= static_cast<TChar>('F')) + return static_cast<unsigned char>(10 + ch - static_cast<TChar>('A')); + return 0; + } + + template <typename TChar> + [[nodiscard]] constexpr inline bool is_hex(TChar const ch) noexcept { + return (ch >= static_cast<TChar>('0') && ch <= static_cast<TChar>('9')) || + (ch >= static_cast<TChar>('a') && ch <= static_cast<TChar>('f')) || + (ch >= static_cast<TChar>('A') && ch <= static_cast<TChar>('F')); + } + + template <typename TChar> + [[nodiscard]] constexpr std::basic_string_view<TChar> to_string_view(TChar const* str) noexcept { + if (str) return str; + return {}; + } + + template <typename StringType> + [[nodiscard]] constexpr std::basic_string_view<typename StringType::value_type, + typename StringType::traits_type> + to_string_view(StringType const& str) noexcept { + return str; + } + + class sha1 { + public: + using digest32_t = uint32_t[5]; + using digest8_t = uint8_t[20]; + + static constexpr unsigned int block_bytes = 64; + + [[nodiscard]] inline static uint32_t left_rotate(uint32_t value, size_t const count) noexcept { + return (value << count) ^ (value >> (32 - count)); + } + + sha1() { reset(); } + + void reset() noexcept { + m_digest[0] = 0x67452301; + m_digest[1] = 0xEFCDAB89; + m_digest[2] = 0x98BADCFE; + m_digest[3] = 0x10325476; + m_digest[4] = 0xC3D2E1F0; + m_blockByteIndex = 0; + m_byteCount = 0; + } + + void process_byte(uint8_t octet) { + this->m_block[this->m_blockByteIndex++] = octet; + ++this->m_byteCount; + if (m_blockByteIndex == block_bytes) { + this->m_blockByteIndex = 0; + process_block(); + } + } + + void process_block(void const* const start, void const* const end) { + const uint8_t* begin = static_cast<const uint8_t*>(start); + const uint8_t* finish = static_cast<const uint8_t*>(end); + while (begin != finish) { + process_byte(*begin); + begin++; + } + } + + void process_bytes(void const* const data, size_t const len) { + const uint8_t* block = static_cast<const uint8_t*>(data); + process_block(block, block + len); + } + + uint32_t const* get_digest(digest32_t digest) { + size_t const bitCount = this->m_byteCount * 8; + process_byte(0x80); + if (this->m_blockByteIndex > 56) { + while (m_blockByteIndex != 0) { + process_byte(0); + } + while (m_blockByteIndex < 56) { + process_byte(0); + } + } else { + while (m_blockByteIndex < 56) { + process_byte(0); + } + } + process_byte(0); + process_byte(0); + process_byte(0); + process_byte(0); + process_byte(static_cast<unsigned char>((bitCount >> 24) & 0xFF)); + process_byte(static_cast<unsigned char>((bitCount >> 16) & 0xFF)); + process_byte(static_cast<unsigned char>((bitCount >> 8) & 0xFF)); + process_byte(static_cast<unsigned char>((bitCount) & 0xFF)); + + memcpy(digest, m_digest, 5 * sizeof(uint32_t)); + return digest; + } + + uint8_t const* get_digest_bytes(digest8_t digest) { + digest32_t d32; + get_digest(d32); + size_t di = 0; + digest[di++] = static_cast<uint8_t>(d32[0] >> 24); + digest[di++] = static_cast<uint8_t>(d32[0] >> 16); + digest[di++] = static_cast<uint8_t>(d32[0] >> 8); + digest[di++] = static_cast<uint8_t>(d32[0] >> 0); + + digest[di++] = static_cast<uint8_t>(d32[1] >> 24); + digest[di++] = static_cast<uint8_t>(d32[1] >> 16); + digest[di++] = static_cast<uint8_t>(d32[1] >> 8); + digest[di++] = static_cast<uint8_t>(d32[1] >> 0); + + digest[di++] = static_cast<uint8_t>(d32[2] >> 24); + digest[di++] = static_cast<uint8_t>(d32[2] >> 16); + digest[di++] = static_cast<uint8_t>(d32[2] >> 8); + digest[di++] = static_cast<uint8_t>(d32[2] >> 0); + + digest[di++] = static_cast<uint8_t>(d32[3] >> 24); + digest[di++] = static_cast<uint8_t>(d32[3] >> 16); + digest[di++] = static_cast<uint8_t>(d32[3] >> 8); + digest[di++] = static_cast<uint8_t>(d32[3] >> 0); + + digest[di++] = static_cast<uint8_t>(d32[4] >> 24); + digest[di++] = static_cast<uint8_t>(d32[4] >> 16); + digest[di++] = static_cast<uint8_t>(d32[4] >> 8); + digest[di++] = static_cast<uint8_t>(d32[4] >> 0); + + return digest; + } + + private: + void process_block() { + uint32_t w[80]; + for (size_t i = 0; i < 16; i++) { + w[i] = static_cast<uint32_t>(m_block[i * 4 + 0] << 24); + w[i] |= static_cast<uint32_t>(m_block[i * 4 + 1] << 16); + w[i] |= static_cast<uint32_t>(m_block[i * 4 + 2] << 8); + w[i] |= static_cast<uint32_t>(m_block[i * 4 + 3]); + } + for (size_t i = 16; i < 80; i++) { + w[i] = left_rotate((w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16]), 1); + } + + uint32_t a = m_digest[0]; + uint32_t b = m_digest[1]; + uint32_t c = m_digest[2]; + uint32_t d = m_digest[3]; + uint32_t e = m_digest[4]; + + for (std::size_t i = 0; i < 80; ++i) { + uint32_t f = 0; + uint32_t k = 0; + + if (i < 20) { + f = (b & c) | (~b & d); + k = 0x5A827999; + } else if (i < 40) { + f = b ^ c ^ d; + k = 0x6ED9EBA1; + } else if (i < 60) { + f = (b & c) | (b & d) | (c & d); + k = 0x8F1BBCDC; + } else { + f = b ^ c ^ d; + k = 0xCA62C1D6; + } + uint32_t temp = left_rotate(a, 5) + f + e + k + w[i]; + e = d; + d = c; + c = left_rotate(b, 30); + b = a; + a = temp; + } + + m_digest[0] += a; + m_digest[1] += b; + m_digest[2] += c; + m_digest[3] += d; + m_digest[4] += e; + } + + private: + digest32_t m_digest; + uint8_t m_block[64]; + size_t m_blockByteIndex; + size_t m_byteCount; + }; + + template <typename CharT> + inline constexpr CharT empty_guid[37] = "00000000-0000-0000-0000-000000000000"; + + template <> + inline constexpr wchar_t empty_guid<wchar_t>[37] = L"00000000-0000-0000-0000-000000000000"; + + template <typename CharT> + inline constexpr CharT guid_encoder[17] = "0123456789abcdef"; + + template <> + inline constexpr wchar_t guid_encoder<wchar_t>[17] = L"0123456789abcdef"; +} // namespace Detail + +// -------------------------------------------------------------------------------------------------------------------------- +// UUID format https://tools.ietf.org/html/rfc4122 +// -------------------------------------------------------------------------------------------------------------------------- + +// -------------------------------------------------------------------------------------------------------------------------- +// Field NDR Data Type Octet # Note +// -------------------------------------------------------------------------------------------------------------------------- +// time_low unsigned long 0 - 3 The low field +// of the timestamp. time_mid unsigned short 4 - 5 +// The middle field of the timestamp. time_hi_and_version unsigned +// short 6 - 7 The high field of the timestamp multiplexed +// with the version number. clock_seq_hi_and_reserved unsigned small 8 +// The high field of the clock sequence multiplexed with the variant. +// clock_seq_low unsigned small 9 The low +// field of the clock sequence. node character 10 +// - 15 The spatially unique node identifier. +// -------------------------------------------------------------------------------------------------------------------------- +// 0 1 2 3 +// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | time_low | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | time_mid | time_hi_and_version | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// |clk_seq_hi_res | clk_seq_low | node (0-1) | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | node (2-5) | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + +// -------------------------------------------------------------------------------------------------------------------------- +// enumerations +// -------------------------------------------------------------------------------------------------------------------------- + +// indicated by a bit pattern in octet 8, marked with N in +// xxxxxxxx-xxxx-xxxx-Nxxx-xxxxxxxxxxxx +enum class uuid_variant { + // NCS backward compatibility (with the obsolete Apollo Network Computing + // System 1.5 UUID format) N bit pattern: 0xxx > the first 6 octets of the + // UUID are a 48-bit timestamp (the number of 4 microsecond units of time + // since 1 Jan 1980 UTC); > the next 2 octets are reserved; > the next octet + // is the "address family"; > the final 7 octets are a 56-bit host ID in the + // form specified by the address family + ncs, + + // RFC 4122/DCE 1.1 + // N bit pattern: 10xx + // > big-endian byte order + rfc, + + // Microsoft Corporation backward compatibility + // N bit pattern: 110x + // > little endian byte order + // > formely used in the Component Object Model (COM) library + microsoft, + + // reserved for possible future definition + // N bit pattern: 111x + reserved +}; + +// indicated by a bit pattern in octet 6, marked with M in +// xxxxxxxx-xxxx-Mxxx-xxxx-xxxxxxxxxxxx +enum class uuid_version { + none = 0, // only possible for nil or invalid uuids + time_based = 1, // The time-based version specified in RFC 4122 + dce_security = 2, // DCE Security version, with embedded POSIX UIDs. + name_based_md5 = 3, // The name-based version specified in RFS 4122 with MD5 hashing + random_number_based = 4, // The randomly or pseudo-randomly generated version + // specified in RFS 4122 + name_based_sha1 = 5 // The name-based version specified in RFS 4122 with SHA1 hashing +}; + +// Forward declare uuid & to_string so that we can declare to_string as a friend +// later. +class uuid; +template <class CharT = char, class Traits = std::char_traits<CharT>, + class Allocator = std::allocator<CharT>> +std::basic_string<CharT, Traits, Allocator> to_string(uuid const& id); + +// -------------------------------------------------------------------------------------------------------------------------- +// uuid class +// -------------------------------------------------------------------------------------------------------------------------- +class uuid { + public: + using value_type = uint8_t; + + constexpr uuid() noexcept = default; + + uuid(value_type (&arr)[16]) noexcept { + std::copy(std::cbegin(arr), std::cend(arr), std::begin(data)); + } + + constexpr uuid(std::array<value_type, 16> const& arr) noexcept : data{arr} {} + + explicit uuid(span<value_type, 16> bytes) { + std::copy(std::cbegin(bytes), std::cend(bytes), std::begin(data)); + } + + template <typename ForwardIterator> + explicit uuid(ForwardIterator first, ForwardIterator last) { + if (std::distance(first, last) == 16) std::copy(first, last, std::begin(data)); + } + + [[nodiscard]] constexpr uuid_variant variant() const noexcept { + if ((data[8] & 0x80) == 0x00) + return uuid_variant::ncs; + else if ((data[8] & 0xC0) == 0x80) + return uuid_variant::rfc; + else if ((data[8] & 0xE0) == 0xC0) + return uuid_variant::microsoft; + else + return uuid_variant::reserved; + } + + [[nodiscard]] constexpr uuid_version version() const noexcept { + if ((data[6] & 0xF0) == 0x10) + return uuid_version::time_based; + else if ((data[6] & 0xF0) == 0x20) + return uuid_version::dce_security; + else if ((data[6] & 0xF0) == 0x30) + return uuid_version::name_based_md5; + else if ((data[6] & 0xF0) == 0x40) + return uuid_version::random_number_based; + else if ((data[6] & 0xF0) == 0x50) + return uuid_version::name_based_sha1; + else + return uuid_version::none; + } + + [[nodiscard]] constexpr bool is_nil() const noexcept { + for (size_t i = 0; i < data.size(); ++i) + if (data[i] != 0) return false; + return true; + } + + void swap(uuid& other) noexcept { data.swap(other.data); } + + [[nodiscard]] inline span<std::byte const, 16> as_bytes() const { + return span<std::byte const, 16>(reinterpret_cast<std::byte const*>(data.data()), 16); + } + + template <typename StringType> + [[nodiscard]] constexpr static bool is_valid_uuid(StringType const& in_str) noexcept { + auto str = Detail::to_string_view(in_str); + bool firstDigit = true; + size_t hasBraces = 0; + size_t index = 0; + + if (str.empty()) return false; + + if (str.front() == '{') hasBraces = 1; + if (hasBraces && str.back() != '}') return false; + + for (size_t i = hasBraces; i < str.size() - hasBraces; ++i) { + if (str[i] == '-') continue; + + if (index >= 16 || !Detail::is_hex(str[i])) { + return false; + } + + if (firstDigit) { + firstDigit = false; + } else { + index++; + firstDigit = true; + } + } + + if (index < 16) { + return false; + } + + return true; + } + + template <typename StringType> + [[nodiscard]] constexpr static std::optional<uuid> from_string( + StringType const& in_str) noexcept { + auto str = Detail::to_string_view(in_str); + bool firstDigit = true; + size_t hasBraces = 0; + size_t index = 0; + + std::array<uint8_t, 16> data{{0}}; + + if (str.empty()) return {}; + + if (str.front() == '{') hasBraces = 1; + if (hasBraces && str.back() != '}') return {}; + + for (size_t i = hasBraces; i < str.size() - hasBraces; ++i) { + if (str[i] == '-') continue; + + if (index >= 16 || !Detail::is_hex(str[i])) { + return {}; + } + + if (firstDigit) { + data[index] = static_cast<uint8_t>(Detail::hex2char(str[i]) << 4); + firstDigit = false; + } else { + data[index] = static_cast<uint8_t>(data[index] | Detail::hex2char(str[i])); + index++; + firstDigit = true; + } + } + + if (index < 16) { + return {}; + } + + return uuid{data}; + } + + private: + std::array<value_type, 16> data{{0}}; + + friend bool operator==(uuid const& lhs, uuid const& rhs) noexcept; + friend bool operator<(uuid const& lhs, uuid const& rhs) noexcept; + + template <class Elem, class Traits> + friend std::basic_ostream<Elem, Traits>& operator<<(std::basic_ostream<Elem, Traits>& s, + uuid const& id); + + template <class CharT, class Traits, class Allocator> + friend std::basic_string<CharT, Traits, Allocator> to_string(uuid const& id); + + friend std::hash<uuid>; +}; + +// -------------------------------------------------------------------------------------------------------------------------- +// operators and non-member functions +// -------------------------------------------------------------------------------------------------------------------------- + +[[nodiscard]] inline bool operator==(uuid const& lhs, uuid const& rhs) noexcept { + return lhs.data == rhs.data; +} + +[[nodiscard]] inline bool operator!=(uuid const& lhs, uuid const& rhs) noexcept { + return !(lhs == rhs); +} + +[[nodiscard]] inline bool operator<(uuid const& lhs, uuid const& rhs) noexcept { + return lhs.data < rhs.data; +} + +template <class CharT, class Traits, class Allocator> +[[nodiscard]] inline std::basic_string<CharT, Traits, Allocator> to_string(uuid const& id) { + std::basic_string<CharT, Traits, Allocator> uustr{Detail::empty_guid<CharT>}; + + for (size_t i = 0, index = 0; i < 36; ++i) { + if (i == 8 || i == 13 || i == 18 || i == 23) { + continue; + } + uustr[i] = Detail::guid_encoder<CharT>[id.data[index] >> 4 & 0x0f]; + uustr[++i] = Detail::guid_encoder<CharT>[id.data[index] & 0x0f]; + index++; + } + + return uustr; +} + +template <class Elem, class Traits> +std::basic_ostream<Elem, Traits>& operator<<(std::basic_ostream<Elem, Traits>& s, uuid const& id) { + s << to_string(id); + return s; +} + +inline void swap(uuids::uuid& lhs, uuids::uuid& rhs) noexcept { + lhs.swap(rhs); +} + +// -------------------------------------------------------------------------------------------------------------------------- +// namespace IDs that could be used for generating name-based uuids +// -------------------------------------------------------------------------------------------------------------------------- + +// Name string is a fully-qualified domain name +static uuid uuid_namespace_dns{{0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, + 0xc0, 0x4f, 0xd4, 0x30, 0xc8}}; + +// Name string is a URL +static uuid uuid_namespace_url{{0x6b, 0xa7, 0xb8, 0x11, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, + 0xc0, 0x4f, 0xd4, 0x30, 0xc8}}; + +// Name string is an ISO OID (See https://oidref.com/, +// https://en.wikipedia.org/wiki/Object_identifier) +static uuid uuid_namespace_oid{{0x6b, 0xa7, 0xb8, 0x12, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, + 0xc0, 0x4f, 0xd4, 0x30, 0xc8}}; + +// Name string is an X.500 DN, in DER or a text output format (See +// https://en.wikipedia.org/wiki/X.500, +// https://en.wikipedia.org/wiki/Abstract_Syntax_Notation_One) +static uuid uuid_namespace_x500{{0x6b, 0xa7, 0xb8, 0x14, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, + 0xc0, 0x4f, 0xd4, 0x30, 0xc8}}; + +// -------------------------------------------------------------------------------------------------------------------------- +// uuid generators +// -------------------------------------------------------------------------------------------------------------------------- #ifdef UUID_SYSTEM_GENERATOR - class uuid_system_generator - { - public: - using result_type = uuid; +class uuid_system_generator { + public: + using result_type = uuid; - uuid operator()() - { + uuid operator()() { #ifdef _WIN32 - GUID newId; - HRESULT hr = ::CoCreateGuid(&newId); + GUID newId; + HRESULT hr = ::CoCreateGuid(&newId); - if (FAILED(hr)) - { - throw std::system_error(hr, std::system_category(), - "CoCreateGuid failed"); - } + if (FAILED(hr)) { + throw std::system_error(hr, std::system_category(), "CoCreateGuid failed"); + } - std::array<uint8_t, 16> bytes = { - {static_cast<unsigned char>((newId.Data1 >> 24) & 0xFF), - static_cast<unsigned char>((newId.Data1 >> 16) & 0xFF), - static_cast<unsigned char>((newId.Data1 >> 8) & 0xFF), - static_cast<unsigned char>((newId.Data1) & 0xFF), + std::array<uint8_t, 16> bytes = { + {static_cast<unsigned char>((newId.Data1 >> 24) & 0xFF), + static_cast<unsigned char>((newId.Data1 >> 16) & 0xFF), + static_cast<unsigned char>((newId.Data1 >> 8) & 0xFF), + static_cast<unsigned char>((newId.Data1) & 0xFF), - (unsigned char)((newId.Data2 >> 8) & 0xFF), - (unsigned char)((newId.Data2) & 0xFF), + (unsigned char) ((newId.Data2 >> 8) & 0xFF), (unsigned char) ((newId.Data2) & 0xFF), - (unsigned char)((newId.Data3 >> 8) & 0xFF), - (unsigned char)((newId.Data3) & 0xFF), + (unsigned char) ((newId.Data3 >> 8) & 0xFF), (unsigned char) ((newId.Data3) & 0xFF), - newId.Data4[0], newId.Data4[1], newId.Data4[2], newId.Data4[3], - newId.Data4[4], newId.Data4[5], newId.Data4[6], newId.Data4[7]}}; + newId.Data4[0], newId.Data4[1], newId.Data4[2], newId.Data4[3], newId.Data4[4], + newId.Data4[5], newId.Data4[6], newId.Data4[7]}}; - return uuid{std::begin(bytes), std::end(bytes)}; + return uuid{std::begin(bytes), std::end(bytes)}; #elif defined(__linux__) || defined(__unix__) - uuid_t id; - uuid_generate(id); + uuid_t id; + uuid_generate(id); - std::array<uint8_t, 16> bytes = {{id[0], id[1], id[2], id[3], id[4], id[5], - id[6], id[7], id[8], id[9], id[10], - id[11], id[12], id[13], id[14], id[15]}}; + std::array<uint8_t, 16> bytes = {{id[0], id[1], id[2], id[3], id[4], id[5], id[6], id[7], id[8], + id[9], id[10], id[11], id[12], id[13], id[14], id[15]}}; - return uuid{std::begin(bytes), std::end(bytes)}; + return uuid{std::begin(bytes), std::end(bytes)}; #elif defined(__APPLE__) - auto newId = CFUUIDCreate(NULL); - auto bytes = CFUUIDGetUUIDBytes(newId); - CFRelease(newId); - - std::array<uint8_t, 16> arrbytes = { - {bytes.byte0, bytes.byte1, bytes.byte2, bytes.byte3, bytes.byte4, - bytes.byte5, bytes.byte6, bytes.byte7, bytes.byte8, bytes.byte9, - bytes.byte10, bytes.byte11, bytes.byte12, bytes.byte13, bytes.byte14, - bytes.byte15}}; - return uuid{std::begin(arrbytes), std::end(arrbytes)}; + auto newId = CFUUIDCreate(NULL); + auto bytes = CFUUIDGetUUIDBytes(newId); + CFRelease(newId); + + std::array<uint8_t, 16> arrbytes = {{bytes.byte0, bytes.byte1, bytes.byte2, bytes.byte3, + bytes.byte4, bytes.byte5, bytes.byte6, bytes.byte7, + bytes.byte8, bytes.byte9, bytes.byte10, bytes.byte11, + bytes.byte12, bytes.byte13, bytes.byte14, bytes.byte15}}; + return uuid{std::begin(arrbytes), std::end(arrbytes)}; #else - return uuid{}; + return uuid{}; #endif - } - }; + } +}; #endif - template <typename UniformRandomNumberGenerator> - class basic_uuid_random_generator - { - public: - using engine_type = UniformRandomNumberGenerator; - - explicit basic_uuid_random_generator(engine_type& gen) - : generator(&gen, [](auto) {}) - { - } - explicit basic_uuid_random_generator(engine_type* gen) - : generator(gen, [](auto) {}) - { - } - - [[nodiscard]] uuid operator()() - { - alignas(uint32_t) uint8_t bytes[16]; - for (int i = 0; i < 16; i += 4) - *reinterpret_cast<uint32_t*>(bytes + i) = distribution(*generator); - - // variant must be 10xxxxxx - bytes[8] &= 0xBF; - bytes[8] |= 0x80; - - // version must be 0100xxxx - bytes[6] &= 0x4F; - bytes[6] |= 0x40; - - return uuid{std::begin(bytes), std::end(bytes)}; - } - - private: - std::uniform_int_distribution<uint32_t> distribution; - std::shared_ptr<UniformRandomNumberGenerator> generator; - }; - - using uuid_random_generator = basic_uuid_random_generator<std::mt19937>; - - class uuid_name_generator - { - public: - explicit uuid_name_generator(uuid const& namespace_uuid) noexcept - : nsuuid(namespace_uuid) - { - } - - template <typename StringType> - [[nodiscard]] uuid operator()(StringType const& name) - { - reset(); - process_characters(Detail::to_string_view(name)); - return make_uuid(); - } - - private: - void reset() - { - hasher.reset(); - std::byte bytes[16]; - auto nsbytes = nsuuid.as_bytes(); - std::copy(std::cbegin(nsbytes), std::cend(nsbytes), bytes); - hasher.process_bytes(bytes, 16); - } - - template <typename CharT, typename Traits> - void process_characters(std::basic_string_view<CharT, Traits> const str) - { - for (uint32_t c : str) - { - hasher.process_byte(static_cast<uint8_t>(c & 0xFF)); - if constexpr (!std::is_same_v<CharT, char>) - { - hasher.process_byte(static_cast<uint8_t>((c >> 8) & 0xFF)); - hasher.process_byte(static_cast<uint8_t>((c >> 16) & 0xFF)); - hasher.process_byte(static_cast<uint8_t>((c >> 24) & 0xFF)); - } - } - } - - [[nodiscard]] uuid make_uuid() - { - Detail::sha1::digest8_t digest; - hasher.get_digest_bytes(digest); - - // variant must be 0b10xxxxxx - digest[8] &= 0xBF; - digest[8] |= 0x80; - - // version must be 0b0101xxxx - digest[6] &= 0x5F; - digest[6] |= 0x50; - - return uuid{digest, digest + 16}; - } - - private: - uuid nsuuid; - Detail::sha1 hasher; - }; +template <typename UniformRandomNumberGenerator> +class basic_uuid_random_generator { + public: + using engine_type = UniformRandomNumberGenerator; + + explicit basic_uuid_random_generator(engine_type& gen) : generator(&gen, [](auto) {}) {} + explicit basic_uuid_random_generator(engine_type* gen) : generator(gen, [](auto) {}) {} + + [[nodiscard]] uuid operator()() { + alignas(uint32_t) uint8_t bytes[16]; + for (int i = 0; i < 16; i += 4) + *reinterpret_cast<uint32_t*>(bytes + i) = distribution(*generator); + + // variant must be 10xxxxxx + bytes[8] &= 0xBF; + bytes[8] |= 0x80; + + // version must be 0100xxxx + bytes[6] &= 0x4F; + bytes[6] |= 0x40; + + return uuid{std::begin(bytes), std::end(bytes)}; + } + + private: + std::uniform_int_distribution<uint32_t> distribution; + std::shared_ptr<UniformRandomNumberGenerator> generator; +}; + +using uuid_random_generator = basic_uuid_random_generator<std::mt19937>; + +class uuid_name_generator { + public: + explicit uuid_name_generator(uuid const& namespace_uuid) noexcept : nsuuid(namespace_uuid) {} + + template <typename StringType> + [[nodiscard]] uuid operator()(StringType const& name) { + reset(); + process_characters(Detail::to_string_view(name)); + return make_uuid(); + } + + private: + void reset() { + hasher.reset(); + std::byte bytes[16]; + auto nsbytes = nsuuid.as_bytes(); + std::copy(std::cbegin(nsbytes), std::cend(nsbytes), bytes); + hasher.process_bytes(bytes, 16); + } + + template <typename CharT, typename Traits> + void process_characters(std::basic_string_view<CharT, Traits> const str) { + for (uint32_t c : str) { + hasher.process_byte(static_cast<uint8_t>(c & 0xFF)); + if constexpr (!std::is_same_v<CharT, char>) { + hasher.process_byte(static_cast<uint8_t>((c >> 8) & 0xFF)); + hasher.process_byte(static_cast<uint8_t>((c >> 16) & 0xFF)); + hasher.process_byte(static_cast<uint8_t>((c >> 24) & 0xFF)); + } + } + } + + [[nodiscard]] uuid make_uuid() { + Detail::sha1::digest8_t digest; + hasher.get_digest_bytes(digest); + + // variant must be 0b10xxxxxx + digest[8] &= 0xBF; + digest[8] |= 0x80; + + // version must be 0b0101xxxx + digest[6] &= 0x5F; + digest[6] |= 0x50; + + return uuid{digest, digest + 16}; + } + + private: + uuid nsuuid; + Detail::sha1 hasher; +}; #ifdef UUID_TIME_GENERATOR - // !!! DO NOT USE THIS IN PRODUCTION - // this implementation is unreliable for good uuids - class uuid_time_generator - { - using mac_address = std::array<unsigned char, 6>; +// !!! DO NOT USE THIS IN PRODUCTION +// this implementation is unreliable for good uuids +class uuid_time_generator { + using mac_address = std::array<unsigned char, 6>; - std::optional<mac_address> device_address; + std::optional<mac_address> device_address; - [[nodiscard]] bool get_mac_address() - { - if (device_address.has_value()) - { - return true; - } + [[nodiscard]] bool get_mac_address() { + if (device_address.has_value()) { + return true; + } #ifdef _WIN32 - DWORD len = 0; - auto ret = GetAdaptersInfo(nullptr, &len); - if (ret != ERROR_BUFFER_OVERFLOW) - return false; - std::vector<unsigned char> buf(len); - auto pips = reinterpret_cast<PIP_ADAPTER_INFO>(&buf.front()); - ret = GetAdaptersInfo(pips, &len); - if (ret != ERROR_SUCCESS) - return false; - mac_address addr; - std::copy(pips->Address, pips->Address + 6, std::begin(addr)); - device_address = addr; + DWORD len = 0; + auto ret = GetAdaptersInfo(nullptr, &len); + if (ret != ERROR_BUFFER_OVERFLOW) return false; + std::vector<unsigned char> buf(len); + auto pips = reinterpret_cast<PIP_ADAPTER_INFO>(&buf.front()); + ret = GetAdaptersInfo(pips, &len); + if (ret != ERROR_SUCCESS) return false; + mac_address addr; + std::copy(pips->Address, pips->Address + 6, std::begin(addr)); + device_address = addr; #endif - return device_address.has_value(); - } + return device_address.has_value(); + } - [[nodiscard]] long long get_time_intervals() - { - auto start = std::chrono::system_clock::from_time_t(time_t(-12219292800)); - auto diff = std::chrono::system_clock::now() - start; - auto ns = - std::chrono::duration_cast<std::chrono::nanoseconds>(diff).count(); - return ns / 100; - } + [[nodiscard]] long long get_time_intervals() { + auto start = std::chrono::system_clock::from_time_t(time_t(-12219292800)); + auto diff = std::chrono::system_clock::now() - start; + auto ns = std::chrono::duration_cast<std::chrono::nanoseconds>(diff).count(); + return ns / 100; + } - [[nodiscard]] static unsigned short get_clock_sequence() - { - static std::mt19937 clock_gen(std::random_device{}()); - static std::uniform_int_distribution<unsigned short> clock_dis; - static std::atomic_ushort clock_sequence = clock_dis(clock_gen); - return clock_sequence++; - } + [[nodiscard]] static unsigned short get_clock_sequence() { + static std::mt19937 clock_gen(std::random_device{}()); + static std::uniform_int_distribution<unsigned short> clock_dis; + static std::atomic_ushort clock_sequence = clock_dis(clock_gen); + return clock_sequence++; + } - public: - [[nodiscard]] uuid operator()() - { - if (get_mac_address()) - { - std::array<uuids::uuid::value_type, 16> data; + public: + [[nodiscard]] uuid operator()() { + if (get_mac_address()) { + std::array<uuids::uuid::value_type, 16> data; - auto tm = get_time_intervals(); + auto tm = get_time_intervals(); - auto clock_seq = get_clock_sequence(); + auto clock_seq = get_clock_sequence(); - auto ptm = reinterpret_cast<uuids::uuid::value_type*>(&tm); + auto ptm = reinterpret_cast<uuids::uuid::value_type*>(&tm); - memcpy(&data[0], ptm + 4, 4); - memcpy(&data[4], ptm + 2, 2); - memcpy(&data[6], ptm, 2); + memcpy(&data[0], ptm + 4, 4); + memcpy(&data[4], ptm + 2, 2); + memcpy(&data[6], ptm, 2); - memcpy(&data[8], &clock_seq, 2); + memcpy(&data[8], &clock_seq, 2); - // variant must be 0b10xxxxxx - data[8] &= 0xBF; - data[8] |= 0x80; + // variant must be 0b10xxxxxx + data[8] &= 0xBF; + data[8] |= 0x80; - // version must be 0b0001xxxx - data[6] &= 0x1F; - data[6] |= 0x10; + // version must be 0b0001xxxx + data[6] &= 0x1F; + data[6] |= 0x10; - memcpy(&data[10], &device_address.value()[0], 6); + memcpy(&data[10], &device_address.value()[0], 6); - return uuids::uuid{std::cbegin(data), std::cend(data)}; - } + return uuids::uuid{std::cbegin(data), std::cend(data)}; + } - return {}; - } - }; + return {}; + } +}; #endif -} // namespace uuids - -namespace std -{ - template <> - struct hash<uuids::uuid> - { - using argument_type = uuids::uuid; - using result_type = std::size_t; - - [[nodiscard]] result_type operator()(argument_type const& uuid) const - { +} // namespace uuids + +namespace std { +template <> +struct hash<uuids::uuid> { + using argument_type = uuids::uuid; + using result_type = std::size_t; + + [[nodiscard]] result_type operator()(argument_type const& uuid) const { #ifdef UUID_HASH_STRING_BASED - std::hash<std::string> hasher; - return static_cast<result_type>(hasher(uuids::to_string(uuid))); + std::hash<std::string> hasher; + return static_cast<result_type>(hasher(uuids::to_string(uuid))); #else - uint64_t l = static_cast<uint64_t>(uuid.data[0]) << 56 | - static_cast<uint64_t>(uuid.data[1]) << 48 | - static_cast<uint64_t>(uuid.data[2]) << 40 | - static_cast<uint64_t>(uuid.data[3]) << 32 | - static_cast<uint64_t>(uuid.data[4]) << 24 | - static_cast<uint64_t>(uuid.data[5]) << 16 | - static_cast<uint64_t>(uuid.data[6]) << 8 | - static_cast<uint64_t>(uuid.data[7]); - uint64_t h = static_cast<uint64_t>(uuid.data[8]) << 56 | - static_cast<uint64_t>(uuid.data[9]) << 48 | - static_cast<uint64_t>(uuid.data[10]) << 40 | - static_cast<uint64_t>(uuid.data[11]) << 32 | - static_cast<uint64_t>(uuid.data[12]) << 24 | - static_cast<uint64_t>(uuid.data[13]) << 16 | - static_cast<uint64_t>(uuid.data[14]) << 8 | - static_cast<uint64_t>(uuid.data[15]); - - if constexpr (sizeof(result_type) > 4) - { - return result_type(l ^ h); - } - else - { - uint64_t hash64 = l ^ h; - return result_type(uint32_t(hash64 >> 32) ^ uint32_t(hash64)); - } + uint64_t l = + static_cast<uint64_t>(uuid.data[0]) << 56 | static_cast<uint64_t>(uuid.data[1]) << 48 | + static_cast<uint64_t>(uuid.data[2]) << 40 | static_cast<uint64_t>(uuid.data[3]) << 32 | + static_cast<uint64_t>(uuid.data[4]) << 24 | static_cast<uint64_t>(uuid.data[5]) << 16 | + static_cast<uint64_t>(uuid.data[6]) << 8 | static_cast<uint64_t>(uuid.data[7]); + uint64_t h = + static_cast<uint64_t>(uuid.data[8]) << 56 | static_cast<uint64_t>(uuid.data[9]) << 48 | + static_cast<uint64_t>(uuid.data[10]) << 40 | static_cast<uint64_t>(uuid.data[11]) << 32 | + static_cast<uint64_t>(uuid.data[12]) << 24 | static_cast<uint64_t>(uuid.data[13]) << 16 | + static_cast<uint64_t>(uuid.data[14]) << 8 | static_cast<uint64_t>(uuid.data[15]); + + if constexpr (sizeof(result_type) > 4) { + return result_type(l ^ h); + } else { + uint64_t hash64 = l ^ h; + return result_type(uint32_t(hash64 >> 32) ^ uint32_t(hash64)); + } #endif - } - }; -} // namespace std + } +}; +} // namespace std #endif /* STDUUID_H */
\ No newline at end of file |
