14 #include <type_traits>
22 # if (__cplusplus >= 202002L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002L)
23 # define LIBUUID_CPP20_OR_GREATER
32 #ifndef WIN32_LEAN_AND_MEAN
33 #define WIN32_LEAN_AND_MEAN
39 #ifdef UUID_SYSTEM_GENERATOR
43 #ifdef UUID_TIME_GENERATOR
45 #pragma comment(lib, "IPHLPAPI.lib")
48 #elif defined(__linux__) || defined(__unix__)
50 #ifdef UUID_SYSTEM_GENERATOR
51 #include <uuid/uuid.h>
54 #elif defined(__APPLE__)
56 #ifdef UUID_SYSTEM_GENERATOR
57 #include <CoreFoundation/CFUUID.h>
65 template <
class ElementType, std::
size_t Extent>
66 using span = std::span<ElementType, Extent>;
68 template <
class ElementType, std::ptrdiff_t Extent>
69 using span = gsl::span<ElementType, Extent>;
74 template <
typename TChar>
75 [[nodiscard]] constexpr
inline unsigned char hex2char(TChar
const ch) noexcept
77 if (ch >=
static_cast<TChar
>(
'0') && ch <=
static_cast<TChar
>(
'9'))
78 return static_cast<unsigned char>(ch -
static_cast<TChar
>(
'0'));
79 if (ch >=
static_cast<TChar
>(
'a') && ch <= static_cast<TChar>(
'f'))
80 return static_cast<unsigned char>(10 + ch -
static_cast<TChar
>(
'a'));
81 if (ch >=
static_cast<TChar
>(
'A') && ch <= static_cast<TChar>(
'F'))
82 return static_cast<unsigned char>(10 + ch -
static_cast<TChar
>(
'A'));
86 template <
typename TChar>
87 [[nodiscard]] constexpr
inline bool is_hex(TChar
const ch) noexcept
90 (ch >=
static_cast<TChar
>(
'0') && ch <=
static_cast<TChar
>(
'9')) ||
91 (ch >=
static_cast<TChar
>(
'a') && ch <=
static_cast<TChar
>(
'f')) ||
92 (ch >=
static_cast<TChar
>(
'A') && ch <= static_cast<TChar>(
'F'));
95 template <
typename TChar>
96 [[nodiscard]] constexpr std::basic_string_view<TChar>
to_string_view(TChar
const * str) noexcept
102 template <
typename StringType>
104 constexpr std::basic_string_view<
105 typename StringType::value_type,
106 typename StringType::traits_type>
120 [[nodiscard]]
inline static uint32_t
left_rotate(uint32_t value,
size_t const count) noexcept
122 return (value << count) ^ (value >> (32 - count));
129 m_digest[0] = 0x67452301;
130 m_digest[1] = 0xEFCDAB89;
131 m_digest[2] = 0x98BADCFE;
132 m_digest[3] = 0x10325476;
133 m_digest[4] = 0xC3D2E1F0;
134 m_blockByteIndex = 0;
140 this->m_block[this->m_blockByteIndex++] = octet;
144 this->m_blockByteIndex = 0;
151 const uint8_t* begin =
static_cast<const uint8_t*
>(start);
152 const uint8_t* finish =
static_cast<const uint8_t*
>(end);
153 while (begin != finish)
162 const uint8_t* block =
static_cast<const uint8_t*
>(data);
168 size_t const bitCount = this->m_byteCount * 8;
170 if (this->m_blockByteIndex > 56) {
171 while (m_blockByteIndex != 0) {
174 while (m_blockByteIndex < 56) {
179 while (m_blockByteIndex < 56) {
187 process_byte(
static_cast<unsigned char>((bitCount >> 24) & 0xFF));
188 process_byte(
static_cast<unsigned char>((bitCount >> 16) & 0xFF));
189 process_byte(
static_cast<unsigned char>((bitCount >> 8) & 0xFF));
190 process_byte(
static_cast<unsigned char>((bitCount) & 0xFF));
192 memcpy(digest, m_digest, 5 *
sizeof(uint32_t));
201 digest[di++] =
static_cast<uint8_t
>(d32[0] >> 24);
202 digest[di++] =
static_cast<uint8_t
>(d32[0] >> 16);
203 digest[di++] =
static_cast<uint8_t
>(d32[0] >> 8);
204 digest[di++] =
static_cast<uint8_t
>(d32[0] >> 0);
206 digest[di++] =
static_cast<uint8_t
>(d32[1] >> 24);
207 digest[di++] =
static_cast<uint8_t
>(d32[1] >> 16);
208 digest[di++] =
static_cast<uint8_t
>(d32[1] >> 8);
209 digest[di++] =
static_cast<uint8_t
>(d32[1] >> 0);
211 digest[di++] =
static_cast<uint8_t
>(d32[2] >> 24);
212 digest[di++] =
static_cast<uint8_t
>(d32[2] >> 16);
213 digest[di++] =
static_cast<uint8_t
>(d32[2] >> 8);
214 digest[di++] =
static_cast<uint8_t
>(d32[2] >> 0);
216 digest[di++] =
static_cast<uint8_t
>(d32[3] >> 24);
217 digest[di++] =
static_cast<uint8_t
>(d32[3] >> 16);
218 digest[di++] =
static_cast<uint8_t
>(d32[3] >> 8);
219 digest[di++] =
static_cast<uint8_t
>(d32[3] >> 0);
221 digest[di++] =
static_cast<uint8_t
>(d32[4] >> 24);
222 digest[di++] =
static_cast<uint8_t
>(d32[4] >> 16);
223 digest[di++] =
static_cast<uint8_t
>(d32[4] >> 8);
224 digest[di++] =
static_cast<uint8_t
>(d32[4] >> 0);
233 for (
size_t i = 0; i < 16; i++) {
234 w[i] =
static_cast<uint32_t
>(m_block[i * 4 + 0] << 24);
235 w[i] |=
static_cast<uint32_t
>(m_block[i * 4 + 1] << 16);
236 w[i] |=
static_cast<uint32_t
>(m_block[i * 4 + 2] << 8);
237 w[i] |=
static_cast<uint32_t
>(m_block[i * 4 + 3]);
239 for (
size_t i = 16; i < 80; i++) {
240 w[i] =
left_rotate((w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16]), 1);
243 uint32_t a = m_digest[0];
244 uint32_t b = m_digest[1];
245 uint32_t c = m_digest[2];
246 uint32_t d = m_digest[3];
247 uint32_t
e = m_digest[4];
249 for (std::size_t i = 0; i < 80; ++i)
255 f = (b & c) | (~b & d);
263 f = (b & c) | (b & d) | (c & d);
288 size_t m_blockByteIndex;
292 template <
typename CharT>
293 inline constexpr CharT
empty_guid[37] =
"00000000-0000-0000-0000-000000000000";
298 template <
typename CharT>
375 template <
class CharT = char,
376 class Traits = std::char_traits<CharT>,
377 class Allocator = std::allocator<CharT>>
378 std::basic_string<CharT, Traits, Allocator>
to_string(uuid
const &
id);
388 constexpr
uuid() noexcept = default;
392 std::copy(std::cbegin(arr), std::cend(arr), std::begin(data));
395 constexpr
uuid(std::array<value_type, 16>
const & arr) noexcept : data{arr} {}
399 std::copy(std::cbegin(bytes), std::cend(bytes), std::begin(data));
402 template<
typename ForwardIterator>
403 explicit uuid(ForwardIterator first, ForwardIterator last)
405 if (std::distance(first, last) == 16)
406 std::copy(first, last, std::begin(data));
411 if ((data[8] & 0x80) == 0x00)
413 else if ((data[8] & 0xC0) == 0x80)
415 else if ((data[8] & 0xE0) == 0xC0)
423 if ((data[6] & 0xF0) == 0x10)
425 else if ((data[6] & 0xF0) == 0x20)
427 else if ((data[6] & 0xF0) == 0x30)
429 else if ((data[6] & 0xF0) == 0x40)
431 else if ((data[6] & 0xF0) == 0x50)
437 [[nodiscard]] constexpr
bool is_nil() const noexcept
439 for (
size_t i = 0; i < data.size(); ++i)
if (data[i] != 0)
return false;
445 data.swap(other.data);
453 template <
typename StringType>
454 [[nodiscard]] constexpr
static bool is_valid_uuid(StringType
const & in_str) noexcept
457 bool firstDigit =
true;
458 size_t hasBraces = 0;
464 if (str.front() ==
'{')
466 if (hasBraces && str.back() !=
'}')
469 for (
size_t i = hasBraces; i < str.size() - hasBraces; ++i)
471 if (str[i] ==
'-')
continue;
497 template <
typename StringType>
498 [[nodiscard]] constexpr
static std::optional<uuid>
from_string(StringType
const & in_str) noexcept
501 bool firstDigit =
true;
502 size_t hasBraces = 0;
505 std::array<uint8_t, 16> data{ { 0 } };
507 if (str.empty())
return {};
509 if (str.front() ==
'{')
511 if (hasBraces && str.back() !=
'}')
514 for (
size_t i = hasBraces; i < str.size() - hasBraces; ++i)
516 if (str[i] ==
'-')
continue;
545 std::array<value_type, 16> data{ { 0 } };
550 template <
class Elem,
class Traits>
551 friend std::basic_ostream<Elem, Traits> &
operator<<(std::basic_ostream<Elem, Traits> &s,
uuid const &
id);
553 template<
class CharT,
class Traits,
class Allocator>
554 friend std::basic_string<CharT, Traits, Allocator>
to_string(
uuid const&
id);
556 friend std::hash<uuid>;
565 return lhs.data == rhs.data;
570 return !(lhs == rhs);
575 return lhs.data < rhs.data;
578 template <
class CharT,
581 [[nodiscard]]
inline std::basic_string<CharT, Traits, Allocator>
to_string(
uuid const &
id)
583 std::basic_string<CharT, Traits, Allocator> uustr{detail::empty_guid<CharT>};
585 for (
size_t i = 0, index = 0; i < 36; ++i)
587 if (i == 8 || i == 13 || i == 18 || i == 23)
591 uustr[i] = detail::guid_encoder<CharT>[
id.data[index] >> 4 & 0x0f];
592 uustr[++i] = detail::guid_encoder<CharT>[
id.data[index] & 0x0f];
599 template <
class Elem,
class Traits>
600 std::basic_ostream<Elem, Traits>&
operator<<(std::basic_ostream<Elem, Traits>& s,
uuid const&
id)
616 static uuid uuid_namespace_dns{ {0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8} };
619 static uuid uuid_namespace_url{ {0x6b, 0xa7, 0xb8, 0x11, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8} };
622 static uuid uuid_namespace_oid{ {0x6b, 0xa7, 0xb8, 0x12, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8} };
625 static uuid uuid_namespace_x500{ {0x6b, 0xa7, 0xb8, 0x14, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8} };
631 #ifdef UUID_SYSTEM_GENERATOR
632 class uuid_system_generator
635 using result_type = uuid;
642 HRESULT hr = ::CoCreateGuid(&newId);
646 throw std::system_error(hr, std::system_category(),
"CoCreateGuid failed");
649 std::array<uint8_t, 16> bytes =
651 static_cast<unsigned char>((newId.Data1 >> 24) & 0xFF),
652 static_cast<unsigned char>((newId.Data1 >> 16) & 0xFF),
653 static_cast<unsigned char>((newId.Data1 >> 8) & 0xFF),
654 static_cast<unsigned char>((newId.Data1) & 0xFF),
656 (
unsigned char)((newId.Data2 >> 8) & 0xFF),
657 (
unsigned char)((newId.Data2) & 0xFF),
659 (
unsigned char)((newId.Data3 >> 8) & 0xFF),
660 (
unsigned char)((newId.Data3) & 0xFF),
672 return uuid{ std::begin(bytes), std::end(bytes) };
674 #elif defined(__linux__) || defined(__unix__)
679 std::array<uint8_t, 16> bytes =
699 return uuid{ std::begin(bytes), std::end(bytes) };
701 #elif defined(__APPLE__)
702 auto newId = CFUUIDCreate(NULL);
703 auto bytes = CFUUIDGetUUIDBytes(newId);
706 std::array<uint8_t, 16> arrbytes =
725 return uuid{ std::begin(arrbytes), std::end(arrbytes) };
733 template <
typename UniformRandomNumberGenerator>
740 generator(&gen, [](auto) {}) {}
742 generator(gen, [](auto) {}) {}
746 alignas(uint32_t) uint8_t bytes[16];
747 for (
int i = 0; i < 16; i += 4)
748 *
reinterpret_cast<uint32_t*
>(bytes + i) = distribution(*generator);
758 return uuid{std::begin(bytes), std::end(bytes)};
762 std::uniform_int_distribution<uint32_t> distribution;
763 std::shared_ptr<UniformRandomNumberGenerator> generator;
772 : nsuuid(namespace_uuid)
775 template <
typename StringType>
789 std::copy(std::cbegin(nsbytes), std::cend(nsbytes), bytes);
793 template <
typename CharT,
typename Traits>
794 void process_characters(std::basic_string_view<CharT, Traits>
const str)
796 for (uint32_t c : str)
799 if constexpr (!std::is_same_v<CharT, char>)
801 hasher.
process_byte(
static_cast<uint8_t
>((c >> 8) & 0xFF));
802 hasher.
process_byte(
static_cast<uint8_t
>((c >> 16) & 0xFF));
803 hasher.
process_byte(
static_cast<uint8_t
>((c >> 24) & 0xFF));
808 [[nodiscard]] uuid make_uuid()
821 return uuid{ digest, digest + 16 };
829 #ifdef UUID_TIME_GENERATOR
832 class uuid_time_generator
834 using mac_address = std::array<unsigned char, 6>;
836 std::optional<mac_address> device_address;
838 [[nodiscard]]
bool get_mac_address()
840 if (device_address.has_value())
847 auto ret = GetAdaptersInfo(
nullptr, &len);
848 if (ret != ERROR_BUFFER_OVERFLOW)
return false;
849 std::vector<unsigned char> buf(len);
850 auto pips =
reinterpret_cast<PIP_ADAPTER_INFO
>(&buf.front());
851 ret = GetAdaptersInfo(pips, &len);
852 if (ret != ERROR_SUCCESS)
return false;
854 std::copy(pips->Address, pips->Address + 6, std::begin(addr));
855 device_address = addr;
858 return device_address.has_value();
861 [[nodiscard]]
long long get_time_intervals()
863 auto start = std::chrono::system_clock::from_time_t(time_t(-12219292800));
864 auto diff = std::chrono::system_clock::now() - start;
865 auto ns = std::chrono::duration_cast<std::chrono::nanoseconds>(diff).count();
869 [[nodiscard]]
static unsigned short get_clock_sequence()
871 static std::mt19937 clock_gen(std::random_device{}());
872 static std::uniform_int_distribution<unsigned short> clock_dis;
873 static std::atomic_ushort clock_sequence = clock_dis(clock_gen);
874 return clock_sequence++;
878 [[nodiscard]] uuid operator()()
880 if (get_mac_address())
882 std::array<uuids::uuid::value_type, 16> data;
884 auto tm = get_time_intervals();
886 auto clock_seq = get_clock_sequence();
890 memcpy(&data[0], ptm + 4, 4);
891 memcpy(&data[4], ptm + 2, 2);
892 memcpy(&data[6], ptm, 2);
894 memcpy(&data[8], &clock_seq, 2);
904 memcpy(&data[10], &device_address.value()[0], 6);
906 return uuids::uuid{std::cbegin(data), std::cend(data)};
925 #ifdef UUID_HASH_STRING_BASED
926 std::hash<std::string> hasher;
930 static_cast<uint64_t
>(uuid.data[0]) << 56 |
931 static_cast<uint64_t
>(uuid.data[1]) << 48 |
932 static_cast<uint64_t
>(uuid.data[2]) << 40 |
933 static_cast<uint64_t
>(uuid.data[3]) << 32 |
934 static_cast<uint64_t
>(uuid.data[4]) << 24 |
935 static_cast<uint64_t
>(uuid.data[5]) << 16 |
936 static_cast<uint64_t
>(uuid.data[6]) << 8 |
937 static_cast<uint64_t
>(uuid.data[7]);
939 static_cast<uint64_t
>(uuid.data[8]) << 56 |
940 static_cast<uint64_t
>(uuid.data[9]) << 48 |
941 static_cast<uint64_t
>(uuid.data[10]) << 40 |
942 static_cast<uint64_t
>(uuid.data[11]) << 32 |
943 static_cast<uint64_t
>(uuid.data[12]) << 24 |
944 static_cast<uint64_t
>(uuid.data[13]) << 16 |
945 static_cast<uint64_t
>(uuid.data[14]) << 8 |
946 static_cast<uint64_t
>(uuid.data[15]);
954 uint64_t hash64 = l ^ h;
955 return result_type(uint32_t(hash64 >> 32) ^ uint32_t(hash64));