Photon 1.0.0
Loading...
Searching...
No Matches
uuid.h
Go to the documentation of this file.
1#ifndef STDUUID_H
2#define STDUUID_H
3
4#include <cstring>
5#include <string>
6#include <sstream>
7#include <iomanip>
8#include <array>
9#include <string_view>
10#include <iterator>
11#include <random>
12#include <memory>
13#include <functional>
14#include <type_traits>
15#include <optional>
16#include <chrono>
17#include <numeric>
18#include <atomic>
19
20#ifdef __cplusplus
21
22# if (__cplusplus >= 202002L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002L)
23# define LIBUUID_CPP20_OR_GREATER
24# endif
25
26#endif
27
28
29#ifdef LIBUUID_CPP20_OR_GREATER
30#include <span>
31#else
32#include <gsl/span>
33#endif
34
35#ifdef _WIN32
36
37#ifndef WIN32_LEAN_AND_MEAN
38#define WIN32_LEAN_AND_MEAN
39#endif
40#ifndef NOMINMAX
41#define NOMINMAX
42#endif
43
44#ifdef UUID_SYSTEM_GENERATOR
45#include <objbase.h>
46#endif
47
48#ifdef UUID_TIME_GENERATOR
49#include <iphlpapi.h>
50#pragma comment(lib, "IPHLPAPI.lib")
51#endif
52
53#elif defined(__linux__) || defined(__unix__)
54
55#ifdef UUID_SYSTEM_GENERATOR
56#include <uuid/uuid.h>
57#endif
58
59#elif defined(__APPLE__)
60
61#ifdef UUID_SYSTEM_GENERATOR
62#include <CoreFoundation/CFUUID.h>
63#endif
64
65#endif
66
67namespace uuids
68{
69#ifdef __cpp_lib_span
70 template <class ElementType, std::size_t Extent>
71 using span = std::span<ElementType, Extent>;
72#else
73 template <class ElementType, std::ptrdiff_t Extent>
74 using span = gsl::span<ElementType, Extent>;
75#endif
76
77 namespace detail
78 {
79 template <typename TChar>
80 [[nodiscard]] constexpr inline unsigned char hex2char(TChar const ch) noexcept
81 {
82 if (ch >= static_cast<TChar>('0') && ch <= static_cast<TChar>('9'))
83 return static_cast<unsigned char>(ch - static_cast<TChar>('0'));
84 if (ch >= static_cast<TChar>('a') && ch <= static_cast<TChar>('f'))
85 return static_cast<unsigned char>(10 + ch - static_cast<TChar>('a'));
86 if (ch >= static_cast<TChar>('A') && ch <= static_cast<TChar>('F'))
87 return static_cast<unsigned char>(10 + ch - static_cast<TChar>('A'));
88 return 0;
89 }
90
91 template <typename TChar>
92 [[nodiscard]] constexpr inline bool is_hex(TChar const ch) noexcept
93 {
94 return
95 (ch >= static_cast<TChar>('0') && ch <= static_cast<TChar>('9')) ||
96 (ch >= static_cast<TChar>('a') && ch <= static_cast<TChar>('f')) ||
97 (ch >= static_cast<TChar>('A') && ch <= static_cast<TChar>('F'));
98 }
99
100 template <typename TChar>
101 [[nodiscard]] constexpr std::basic_string_view<TChar> to_string_view(TChar const* str) noexcept
102 {
103 if (str) return str;
104 return {};
105 }
106
107 template <typename StringType>
108 [[nodiscard]]
109 constexpr std::basic_string_view<
110 typename StringType::value_type,
111 typename StringType::traits_type>
112 to_string_view(StringType const& str) noexcept
113 {
114 return str;
115 }
116
117 class sha1
118 {
119 public:
120 using digest32_t = uint32_t[5];
121 using digest8_t = uint8_t[20];
122
123 static constexpr unsigned int block_bytes = 64;
124
125 [[nodiscard]] inline static uint32_t left_rotate(uint32_t value, size_t const count) noexcept
126 {
127 return (value << count) ^ (value >> (32 - count));
128 }
129
130 sha1() { reset(); }
131
132 void reset() noexcept
133 {
134 m_digest[0] = 0x67452301;
135 m_digest[1] = 0xEFCDAB89;
136 m_digest[2] = 0x98BADCFE;
137 m_digest[3] = 0x10325476;
138 m_digest[4] = 0xC3D2E1F0;
140 m_byteCount = 0;
141 }
142
143 void process_byte(uint8_t octet)
144 {
145 this->m_block[this->m_blockByteIndex++] = octet;
146 ++this->m_byteCount;
147 if (m_blockByteIndex == block_bytes)
148 {
149 this->m_blockByteIndex = 0;
151 }
152 }
153
154 void process_block(void const* const start, void const* const end)
155 {
156 const uint8_t* begin = static_cast<const uint8_t*>(start);
157 const uint8_t* finish = static_cast<const uint8_t*>(end);
158 while (begin != finish)
159 {
160 process_byte(*begin);
161 begin++;
162 }
163 }
164
165 void process_bytes(void const* const data, size_t const len)
166 {
167 const uint8_t* block = static_cast<const uint8_t*>(data);
168 process_block(block, block + len);
169 }
170
171 uint32_t const* get_digest(digest32_t digest)
172 {
173 size_t const bitCount = this->m_byteCount * 8;
174 process_byte(0x80);
175 if (this->m_blockByteIndex > 56) {
176 while (m_blockByteIndex != 0) {
177 process_byte(0);
178 }
179 while (m_blockByteIndex < 56) {
180 process_byte(0);
181 }
182 }
183 else {
184 while (m_blockByteIndex < 56) {
185 process_byte(0);
186 }
187 }
188 process_byte(0);
189 process_byte(0);
190 process_byte(0);
191 process_byte(0);
192 process_byte(static_cast<unsigned char>((bitCount >> 24) & 0xFF));
193 process_byte(static_cast<unsigned char>((bitCount >> 16) & 0xFF));
194 process_byte(static_cast<unsigned char>((bitCount >> 8) & 0xFF));
195 process_byte(static_cast<unsigned char>((bitCount) & 0xFF));
196
197 memcpy(digest, m_digest, 5 * sizeof(uint32_t));
198 return digest;
199 }
200
201 uint8_t const* get_digest_bytes(digest8_t digest)
202 {
203 digest32_t d32;
204 get_digest(d32);
205 size_t di = 0;
206 digest[di++] = static_cast<uint8_t>(d32[0] >> 24);
207 digest[di++] = static_cast<uint8_t>(d32[0] >> 16);
208 digest[di++] = static_cast<uint8_t>(d32[0] >> 8);
209 digest[di++] = static_cast<uint8_t>(d32[0] >> 0);
210
211 digest[di++] = static_cast<uint8_t>(d32[1] >> 24);
212 digest[di++] = static_cast<uint8_t>(d32[1] >> 16);
213 digest[di++] = static_cast<uint8_t>(d32[1] >> 8);
214 digest[di++] = static_cast<uint8_t>(d32[1] >> 0);
215
216 digest[di++] = static_cast<uint8_t>(d32[2] >> 24);
217 digest[di++] = static_cast<uint8_t>(d32[2] >> 16);
218 digest[di++] = static_cast<uint8_t>(d32[2] >> 8);
219 digest[di++] = static_cast<uint8_t>(d32[2] >> 0);
220
221 digest[di++] = static_cast<uint8_t>(d32[3] >> 24);
222 digest[di++] = static_cast<uint8_t>(d32[3] >> 16);
223 digest[di++] = static_cast<uint8_t>(d32[3] >> 8);
224 digest[di++] = static_cast<uint8_t>(d32[3] >> 0);
225
226 digest[di++] = static_cast<uint8_t>(d32[4] >> 24);
227 digest[di++] = static_cast<uint8_t>(d32[4] >> 16);
228 digest[di++] = static_cast<uint8_t>(d32[4] >> 8);
229 digest[di++] = static_cast<uint8_t>(d32[4] >> 0);
230
231 return digest;
232 }
233
234 private:
236 {
237 uint32_t w[80];
238 for (size_t i = 0; i < 16; i++) {
239 w[i] = static_cast<uint32_t>(m_block[i * 4 + 0] << 24);
240 w[i] |= static_cast<uint32_t>(m_block[i * 4 + 1] << 16);
241 w[i] |= static_cast<uint32_t>(m_block[i * 4 + 2] << 8);
242 w[i] |= static_cast<uint32_t>(m_block[i * 4 + 3]);
243 }
244 for (size_t i = 16; i < 80; i++) {
245 w[i] = left_rotate((w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16]), 1);
246 }
247
248 uint32_t a = m_digest[0];
249 uint32_t b = m_digest[1];
250 uint32_t c = m_digest[2];
251 uint32_t d = m_digest[3];
252 uint32_t e = m_digest[4];
253
254 for (std::size_t i = 0; i < 80; ++i)
255 {
256 uint32_t f = 0;
257 uint32_t k = 0;
258
259 if (i < 20) {
260 f = (b & c) | (~b & d);
261 k = 0x5A827999;
262 }
263 else if (i < 40) {
264 f = b ^ c ^ d;
265 k = 0x6ED9EBA1;
266 }
267 else if (i < 60) {
268 f = (b & c) | (b & d) | (c & d);
269 k = 0x8F1BBCDC;
270 }
271 else {
272 f = b ^ c ^ d;
273 k = 0xCA62C1D6;
274 }
275 uint32_t temp = left_rotate(a, 5) + f + e + k + w[i];
276 e = d;
277 d = c;
278 c = left_rotate(b, 30);
279 b = a;
280 a = temp;
281 }
282
283 m_digest[0] += a;
284 m_digest[1] += b;
285 m_digest[2] += c;
286 m_digest[3] += d;
287 m_digest[4] += e;
288 }
289
290 private:
292 uint8_t m_block[64];
295 };
296
297 template <typename CharT>
298 inline constexpr CharT empty_guid[37] = "00000000-0000-0000-0000-000000000000";
299
300 template <>
301 inline constexpr wchar_t empty_guid<wchar_t>[37] = L"00000000-0000-0000-0000-000000000000";
302
303 template <typename CharT>
304 inline constexpr CharT guid_encoder[17] = "0123456789abcdef";
305
306 template <>
307 inline constexpr wchar_t guid_encoder<wchar_t>[17] = L"0123456789abcdef";
308 }
309
310 // --------------------------------------------------------------------------------------------------------------------------
311 // UUID format https://tools.ietf.org/html/rfc4122
312 // --------------------------------------------------------------------------------------------------------------------------
313
314 // --------------------------------------------------------------------------------------------------------------------------
315 // Field NDR Data Type Octet # Note
316 // --------------------------------------------------------------------------------------------------------------------------
317 // time_low unsigned long 0 - 3 The low field of the timestamp.
318 // time_mid unsigned short 4 - 5 The middle field of the timestamp.
319 // time_hi_and_version unsigned short 6 - 7 The high field of the timestamp multiplexed with the version number.
320 // clock_seq_hi_and_reserved unsigned small 8 The high field of the clock sequence multiplexed with the variant.
321 // clock_seq_low unsigned small 9 The low field of the clock sequence.
322 // node character 10 - 15 The spatially unique node identifier.
323 // --------------------------------------------------------------------------------------------------------------------------
324 // 0 1 2 3
325 // 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
326 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
327 // | time_low |
328 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
329 // | time_mid | time_hi_and_version |
330 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
331 // |clk_seq_hi_res | clk_seq_low | node (0-1) |
332 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
333 // | node (2-5) |
334 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
335
336 // --------------------------------------------------------------------------------------------------------------------------
337 // enumerations
338 // --------------------------------------------------------------------------------------------------------------------------
339
340 // indicated by a bit pattern in octet 8, marked with N in xxxxxxxx-xxxx-xxxx-Nxxx-xxxxxxxxxxxx
341 enum class uuid_variant
342 {
343 // NCS backward compatibility (with the obsolete Apollo Network Computing System 1.5 UUID format)
344 // N bit pattern: 0xxx
345 // > 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);
346 // > the next 2 octets are reserved;
347 // > the next octet is the "address family";
348 // > the final 7 octets are a 56-bit host ID in the form specified by the address family
349 ncs,
350
351 // RFC 4122/DCE 1.1
352 // N bit pattern: 10xx
353 // > big-endian byte order
354 rfc,
355
356 // Microsoft Corporation backward compatibility
357 // N bit pattern: 110x
358 // > little endian byte order
359 // > formely used in the Component Object Model (COM) library
360 microsoft,
361
362 // reserved for possible future definition
363 // N bit pattern: 111x
365 };
366
367 // indicated by a bit pattern in octet 6, marked with M in xxxxxxxx-xxxx-Mxxx-xxxx-xxxxxxxxxxxx
368 enum class uuid_version
369 {
370 none = 0, // only possible for nil or invalid uuids
371 time_based = 1, // The time-based version specified in RFC 4122
372 dce_security = 2, // DCE Security version, with embedded POSIX UIDs.
373 name_based_md5 = 3, // The name-based version specified in RFS 4122 with MD5 hashing
374 random_number_based = 4, // The randomly or pseudo-randomly generated version specified in RFS 4122
375 name_based_sha1 = 5 // The name-based version specified in RFS 4122 with SHA1 hashing
376 };
377
378 // Forward declare uuid & to_string so that we can declare to_string as a friend later.
379 class uuid;
380 template <class CharT = char,
381 class Traits = std::char_traits<CharT>,
382 class Allocator = std::allocator<CharT>>
383 std::basic_string<CharT, Traits, Allocator> to_string(uuid const& id);
384
385 // --------------------------------------------------------------------------------------------------------------------------
386 // uuid class
387 // --------------------------------------------------------------------------------------------------------------------------
388 class uuid
389 {
390 public:
391 using value_type = uint8_t;
392
393 constexpr uuid() noexcept = default;
394
395 uuid(value_type(&arr)[16]) noexcept
396 {
397 std::copy(std::cbegin(arr), std::cend(arr), std::begin(data));
398 }
399
400 constexpr uuid(std::array<value_type, 16> const& arr) noexcept : data{ arr } {}
401
403 {
404 std::copy(std::cbegin(bytes), std::cend(bytes), std::begin(data));
405 }
406
407 template<typename ForwardIterator>
408 explicit uuid(ForwardIterator first, ForwardIterator last)
409 {
410 if (std::distance(first, last) == 16)
411 std::copy(first, last, std::begin(data));
412 }
413
414 [[nodiscard]] constexpr uuid_variant variant() const noexcept
415 {
416 if ((data[8] & 0x80) == 0x00)
417 return uuid_variant::ncs;
418 else if ((data[8] & 0xC0) == 0x80)
419 return uuid_variant::rfc;
420 else if ((data[8] & 0xE0) == 0xC0)
422 else
424 }
425
426 [[nodiscard]] constexpr uuid_version version() const noexcept
427 {
428 if ((data[6] & 0xF0) == 0x10)
430 else if ((data[6] & 0xF0) == 0x20)
432 else if ((data[6] & 0xF0) == 0x30)
434 else if ((data[6] & 0xF0) == 0x40)
436 else if ((data[6] & 0xF0) == 0x50)
438 else
439 return uuid_version::none;
440 }
441
442 [[nodiscard]] constexpr bool is_nil() const noexcept
443 {
444 for (size_t i = 0; i < data.size(); ++i) if (data[i] != 0) return false;
445 return true;
446 }
447
448 void swap(uuid& other) noexcept
449 {
450 data.swap(other.data);
451 }
452
453 [[nodiscard]] inline span<std::byte const, 16> as_bytes() const
454 {
455 return span<std::byte const, 16>(reinterpret_cast<std::byte const*>(data.data()), 16);
456 }
457
458 template <typename StringType>
459 [[nodiscard]] constexpr static bool is_valid_uuid(StringType const& in_str) noexcept
460 {
461 auto str = detail::to_string_view(in_str);
462 bool firstDigit = true;
463 size_t hasBraces = 0;
464 size_t index = 0;
465
466 if (str.empty())
467 return false;
468
469 if (str.front() == '{')
470 hasBraces = 1;
471 if (hasBraces && str.back() != '}')
472 return false;
473
474 for (size_t i = hasBraces; i < str.size() - hasBraces; ++i)
475 {
476 if (str[i] == '-') continue;
477
478 if (index >= 16 || !detail::is_hex(str[i]))
479 {
480 return false;
481 }
482
483 if (firstDigit)
484 {
485 firstDigit = false;
486 }
487 else
488 {
489 index++;
490 firstDigit = true;
491 }
492 }
493
494 if (index < 16)
495 {
496 return false;
497 }
498
499 return true;
500 }
501
502 template <typename StringType>
503 [[nodiscard]] constexpr static std::optional<uuid> from_string(StringType const& in_str) noexcept
504 {
505 auto str = detail::to_string_view(in_str);
506 bool firstDigit = true;
507 size_t hasBraces = 0;
508 size_t index = 0;
509
510 std::array<uint8_t, 16> data{ { 0 } };
511
512 if (str.empty()) return {};
513
514 if (str.front() == '{')
515 hasBraces = 1;
516 if (hasBraces && str.back() != '}')
517 return {};
518
519 for (size_t i = hasBraces; i < str.size() - hasBraces; ++i)
520 {
521 if (str[i] == '-') continue;
522
523 if (index >= 16 || !detail::is_hex(str[i]))
524 {
525 return {};
526 }
527
528 if (firstDigit)
529 {
530 data[index] = static_cast<uint8_t>(detail::hex2char(str[i]) << 4);
531 firstDigit = false;
532 }
533 else
534 {
535 data[index] = static_cast<uint8_t>(data[index] | detail::hex2char(str[i]));
536 index++;
537 firstDigit = true;
538 }
539 }
540
541 if (index < 16)
542 {
543 return {};
544 }
545
546 return uuid{ data };
547 }
548
549 private:
550 std::array<value_type, 16> data{ { 0 } };
551
552 friend bool operator==(uuid const& lhs, uuid const& rhs) noexcept;
553 friend bool operator<(uuid const& lhs, uuid const& rhs) noexcept;
554
555 template <class Elem, class Traits>
556 friend std::basic_ostream<Elem, Traits>& operator<<(std::basic_ostream<Elem, Traits>& s, uuid const& id);
557
558 template<class CharT, class Traits, class Allocator>
559 friend std::basic_string<CharT, Traits, Allocator> to_string(uuid const& id);
560
561 friend std::hash<uuid>;
562 };
563
564 // --------------------------------------------------------------------------------------------------------------------------
565 // operators and non-member functions
566 // --------------------------------------------------------------------------------------------------------------------------
567
568 [[nodiscard]] inline bool operator== (uuid const& lhs, uuid const& rhs) noexcept
569 {
570 return lhs.data == rhs.data;
571 }
572
573 [[nodiscard]] inline bool operator!= (uuid const& lhs, uuid const& rhs) noexcept
574 {
575 return !(lhs == rhs);
576 }
577
578 [[nodiscard]] inline bool operator< (uuid const& lhs, uuid const& rhs) noexcept
579 {
580 return lhs.data < rhs.data;
581 }
582
583 template <class CharT,
584 class Traits,
585 class Allocator>
586 [[nodiscard]] inline std::basic_string<CharT, Traits, Allocator> to_string(uuid const& id)
587 {
588 std::basic_string<CharT, Traits, Allocator> uustr{ detail::empty_guid<CharT> };
589
590 for (size_t i = 0, index = 0; i < 36; ++i)
591 {
592 if (i == 8 || i == 13 || i == 18 || i == 23)
593 {
594 continue;
595 }
596 uustr[i] = detail::guid_encoder<CharT>[id.data[index] >> 4 & 0x0f];
597 uustr[++i] = detail::guid_encoder<CharT>[id.data[index] & 0x0f];
598 index++;
599 }
600
601 return uustr;
602 }
603
604 template <class Elem, class Traits>
605 std::basic_ostream<Elem, Traits>& operator<<(std::basic_ostream<Elem, Traits>& s, uuid const& id)
606 {
607 s << to_string(id);
608 return s;
609 }
610
611 inline void swap(uuids::uuid& lhs, uuids::uuid& rhs) noexcept
612 {
613 lhs.swap(rhs);
614 }
615
616 // --------------------------------------------------------------------------------------------------------------------------
617 // namespace IDs that could be used for generating name-based uuids
618 // --------------------------------------------------------------------------------------------------------------------------
619
620 // Name string is a fully-qualified domain name
621 static uuid uuid_namespace_dns{ {0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8} };
622
623 // Name string is a URL
624 static uuid uuid_namespace_url{ {0x6b, 0xa7, 0xb8, 0x11, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8} };
625
626 // Name string is an ISO OID (See https://oidref.com/, https://en.wikipedia.org/wiki/Object_identifier)
627 static uuid uuid_namespace_oid{ {0x6b, 0xa7, 0xb8, 0x12, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8} };
628
629 // 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)
630 static uuid uuid_namespace_x500{ {0x6b, 0xa7, 0xb8, 0x14, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8} };
631
632 // --------------------------------------------------------------------------------------------------------------------------
633 // uuid generators
634 // --------------------------------------------------------------------------------------------------------------------------
635
636#ifdef UUID_SYSTEM_GENERATOR
637 class uuid_system_generator
638 {
639 public:
640 using result_type = uuid;
641
642 uuid operator()()
643 {
644#ifdef _WIN32
645
646 GUID newId;
647 HRESULT hr = ::CoCreateGuid(&newId);
648
649 if (FAILED(hr))
650 {
651 throw std::system_error(hr, std::system_category(), "CoCreateGuid failed");
652 }
653
654 std::array<uint8_t, 16> bytes =
655 { {
656 static_cast<unsigned char>((newId.Data1 >> 24) & 0xFF),
657 static_cast<unsigned char>((newId.Data1 >> 16) & 0xFF),
658 static_cast<unsigned char>((newId.Data1 >> 8) & 0xFF),
659 static_cast<unsigned char>((newId.Data1) & 0xFF),
660
661 (unsigned char)((newId.Data2 >> 8) & 0xFF),
662 (unsigned char)((newId.Data2) & 0xFF),
663
664 (unsigned char)((newId.Data3 >> 8) & 0xFF),
665 (unsigned char)((newId.Data3) & 0xFF),
666
667 newId.Data4[0],
668 newId.Data4[1],
669 newId.Data4[2],
670 newId.Data4[3],
671 newId.Data4[4],
672 newId.Data4[5],
673 newId.Data4[6],
674 newId.Data4[7]
675 } };
676
677 return uuid{ std::begin(bytes), std::end(bytes) };
678
679#elif defined(__linux__) || defined(__unix__)
680
681 uuid_t id;
682 uuid_generate(id);
683
684 std::array<uint8_t, 16> bytes =
685 { {
686 id[0],
687 id[1],
688 id[2],
689 id[3],
690 id[4],
691 id[5],
692 id[6],
693 id[7],
694 id[8],
695 id[9],
696 id[10],
697 id[11],
698 id[12],
699 id[13],
700 id[14],
701 id[15]
702 } };
703
704 return uuid{ std::begin(bytes), std::end(bytes) };
705
706#elif defined(__APPLE__)
707 auto newId = CFUUIDCreate(NULL);
708 auto bytes = CFUUIDGetUUIDBytes(newId);
709 CFRelease(newId);
710
711 std::array<uint8_t, 16> arrbytes =
712 { {
713 bytes.byte0,
714 bytes.byte1,
715 bytes.byte2,
716 bytes.byte3,
717 bytes.byte4,
718 bytes.byte5,
719 bytes.byte6,
720 bytes.byte7,
721 bytes.byte8,
722 bytes.byte9,
723 bytes.byte10,
724 bytes.byte11,
725 bytes.byte12,
726 bytes.byte13,
727 bytes.byte14,
728 bytes.byte15
729 } };
730 return uuid{ std::begin(arrbytes), std::end(arrbytes) };
731#else
732 return uuid{};
733#endif
734 }
735 };
736#endif
737
738 template <typename UniformRandomNumberGenerator>
740 {
741 public:
742 using engine_type = UniformRandomNumberGenerator;
743
745 generator(&gen, [](auto) {}) {}
747 generator(gen, [](auto) {}) {}
748
749 [[nodiscard]] uuid operator()()
750 {
751 alignas(uint32_t) uint8_t bytes[16];
752 for (int i = 0; i < 16; i += 4)
753 *reinterpret_cast<uint32_t*>(bytes + i) = distribution(*generator);
754
755 // variant must be 10xxxxxx
756 bytes[8] &= 0xBF;
757 bytes[8] |= 0x80;
758
759 // version must be 0100xxxx
760 bytes[6] &= 0x4F;
761 bytes[6] |= 0x40;
762
763 return uuid{ std::begin(bytes), std::end(bytes) };
764 }
765
766 private:
767 std::uniform_int_distribution<uint32_t> distribution;
768 std::shared_ptr<UniformRandomNumberGenerator> generator;
769 };
770
772
774 {
775 public:
776 explicit uuid_name_generator(uuid const& namespace_uuid) noexcept
777 : nsuuid(namespace_uuid)
778 {}
779
780 template <typename StringType>
781 [[nodiscard]] uuid operator()(StringType const& name)
782 {
783 reset();
785 return make_uuid();
786 }
787
788 private:
789 void reset()
790 {
791 hasher.reset();
792 std::byte bytes[16];
793 auto nsbytes = nsuuid.as_bytes();
794 std::copy(std::cbegin(nsbytes), std::cend(nsbytes), bytes);
796 }
797
798 template <typename CharT, typename Traits>
799 void process_characters(std::basic_string_view<CharT, Traits> const str)
800 {
801 for (uint32_t c : str)
802 {
803 hasher.process_byte(static_cast<uint8_t>(c & 0xFF));
804 if constexpr (!std::is_same_v<CharT, char>)
805 {
806 hasher.process_byte(static_cast<uint8_t>((c >> 8) & 0xFF));
807 hasher.process_byte(static_cast<uint8_t>((c >> 16) & 0xFF));
808 hasher.process_byte(static_cast<uint8_t>((c >> 24) & 0xFF));
809 }
810 }
811 }
812
813 [[nodiscard]] uuid make_uuid()
814 {
816 hasher.get_digest_bytes(digest);
817
818 // variant must be 0b10xxxxxx
819 digest[8] &= 0xBF;
820 digest[8] |= 0x80;
821
822 // version must be 0b0101xxxx
823 digest[6] &= 0x5F;
824 digest[6] |= 0x50;
825
826 return uuid{ digest, digest + 16 };
827 }
828
829 private:
832 };
833
834#ifdef UUID_TIME_GENERATOR
835 // !!! DO NOT USE THIS IN PRODUCTION
836 // this implementation is unreliable for good uuids
837 class uuid_time_generator
838 {
839 using mac_address = std::array<unsigned char, 6>;
840
841 std::optional<mac_address> device_address;
842
843 [[nodiscard]] bool get_mac_address()
844 {
845 if (device_address.has_value())
846 {
847 return true;
848 }
849
850#ifdef _WIN32
851 DWORD len = 0;
852 auto ret = GetAdaptersInfo(nullptr, &len);
853 if (ret != ERROR_BUFFER_OVERFLOW) return false;
854 std::vector<unsigned char> buf(len);
855 auto pips = reinterpret_cast<PIP_ADAPTER_INFO>(&buf.front());
856 ret = GetAdaptersInfo(pips, &len);
857 if (ret != ERROR_SUCCESS) return false;
858 mac_address addr;
859 std::copy(pips->Address, pips->Address + 6, std::begin(addr));
860 device_address = addr;
861#endif
862
863 return device_address.has_value();
864 }
865
866 [[nodiscard]] long long get_time_intervals()
867 {
868 auto start = std::chrono::system_clock::from_time_t(time_t(-12219292800));
869 auto diff = std::chrono::system_clock::now() - start;
870 auto ns = std::chrono::duration_cast<std::chrono::nanoseconds>(diff).count();
871 return ns / 100;
872 }
873
874 [[nodiscard]] static unsigned short get_clock_sequence()
875 {
876 static std::mt19937 clock_gen(std::random_device{}());
877 static std::uniform_int_distribution<unsigned short> clock_dis;
878 static std::atomic_ushort clock_sequence = clock_dis(clock_gen);
879 return clock_sequence++;
880 }
881
882 public:
883 [[nodiscard]] uuid operator()()
884 {
885 if (get_mac_address())
886 {
887 std::array<uuids::uuid::value_type, 16> data;
888
889 auto tm = get_time_intervals();
890
891 auto clock_seq = get_clock_sequence();
892
893 auto ptm = reinterpret_cast<uuids::uuid::value_type*>(&tm);
894
895 memcpy(&data[0], ptm + 4, 4);
896 memcpy(&data[4], ptm + 2, 2);
897 memcpy(&data[6], ptm, 2);
898
899 memcpy(&data[8], &clock_seq, 2);
900
901 // variant must be 0b10xxxxxx
902 data[8] &= 0xBF;
903 data[8] |= 0x80;
904
905 // version must be 0b0001xxxx
906 data[6] &= 0x1F;
907 data[6] |= 0x10;
908
909 memcpy(&data[10], &device_address.value()[0], 6);
910
911 return uuids::uuid{ std::cbegin(data), std::cend(data) };
912 }
913
914 return {};
915 }
916 };
917#endif
918}
919
920namespace Photon
921{
923}
924
925namespace std
926{
927 template <>
928 struct hash<uuids::uuid>
929 {
931 using result_type = std::size_t;
932
933 [[nodiscard]] result_type operator()(argument_type const& uuid) const
934 {
935#ifdef UUID_HASH_STRING_BASED
936 std::hash<std::string> hasher;
937 return static_cast<result_type>(hasher(uuids::to_string(uuid)));
938#else
939 uint64_t l =
940 static_cast<uint64_t>(uuid.data[0]) << 56 |
941 static_cast<uint64_t>(uuid.data[1]) << 48 |
942 static_cast<uint64_t>(uuid.data[2]) << 40 |
943 static_cast<uint64_t>(uuid.data[3]) << 32 |
944 static_cast<uint64_t>(uuid.data[4]) << 24 |
945 static_cast<uint64_t>(uuid.data[5]) << 16 |
946 static_cast<uint64_t>(uuid.data[6]) << 8 |
947 static_cast<uint64_t>(uuid.data[7]);
948 uint64_t h =
949 static_cast<uint64_t>(uuid.data[8]) << 56 |
950 static_cast<uint64_t>(uuid.data[9]) << 48 |
951 static_cast<uint64_t>(uuid.data[10]) << 40 |
952 static_cast<uint64_t>(uuid.data[11]) << 32 |
953 static_cast<uint64_t>(uuid.data[12]) << 24 |
954 static_cast<uint64_t>(uuid.data[13]) << 16 |
955 static_cast<uint64_t>(uuid.data[14]) << 8 |
956 static_cast<uint64_t>(uuid.data[15]);
957
958 if constexpr (sizeof(result_type) > 4)
959 {
960 return result_type(l ^ h);
961 }
962 else
963 {
964 uint64_t hash64 = l ^ h;
965 return result_type(uint32_t(hash64 >> 32) ^ uint32_t(hash64));
966 }
967#endif
968 }
969 };
970}
971
972#endif /* STDUUID_H */
Definition format.h:4610
UniformRandomNumberGenerator engine_type
Definition uuid.h:742
uuid operator()()
Definition uuid.h:749
std::uniform_int_distribution< uint32_t > distribution
Definition uuid.h:767
std::shared_ptr< UniformRandomNumberGenerator > generator
Definition uuid.h:768
basic_uuid_random_generator(engine_type *gen)
Definition uuid.h:746
basic_uuid_random_generator(engine_type &gen)
Definition uuid.h:744
Definition uuid.h:118
void process_bytes(void const *const data, size_t const len)
Definition uuid.h:165
size_t m_byteCount
Definition uuid.h:294
sha1()
Definition uuid.h:130
size_t m_blockByteIndex
Definition uuid.h:293
digest32_t m_digest
Definition uuid.h:291
uint8_t[20] digest8_t
Definition uuid.h:121
void process_block(void const *const start, void const *const end)
Definition uuid.h:154
uint8_t const * get_digest_bytes(digest8_t digest)
Definition uuid.h:201
void reset() noexcept
Definition uuid.h:132
uint8_t m_block[64]
Definition uuid.h:292
void process_byte(uint8_t octet)
Definition uuid.h:143
uint32_t[5] digest32_t
Definition uuid.h:120
static constexpr unsigned int block_bytes
Definition uuid.h:123
static uint32_t left_rotate(uint32_t value, size_t const count) noexcept
Definition uuid.h:125
uint32_t const * get_digest(digest32_t digest)
Definition uuid.h:171
void process_block()
Definition uuid.h:235
Definition uuid.h:774
detail::sha1 hasher
Definition uuid.h:831
void reset()
Definition uuid.h:789
void process_characters(std::basic_string_view< CharT, Traits > const str)
Definition uuid.h:799
uuid operator()(StringType const &name)
Definition uuid.h:781
uuid_name_generator(uuid const &namespace_uuid) noexcept
Definition uuid.h:776
uuid make_uuid()
Definition uuid.h:813
uuid nsuuid
Definition uuid.h:830
Definition uuid.h:389
constexpr uuid(std::array< value_type, 16 > const &arr) noexcept
Definition uuid.h:400
static constexpr std::optional< uuid > from_string(StringType const &in_str) noexcept
Definition uuid.h:503
friend std::basic_string< CharT, Traits, Allocator > to_string(uuid const &id)
Definition uuid.h:586
void swap(uuid &other) noexcept
Definition uuid.h:448
uint8_t value_type
Definition uuid.h:391
span< std::byte const, 16 > as_bytes() const
Definition uuid.h:453
friend bool operator<(uuid const &lhs, uuid const &rhs) noexcept
Definition uuid.h:578
friend bool operator==(uuid const &lhs, uuid const &rhs) noexcept
Definition uuid.h:568
constexpr uuid_variant variant() const noexcept
Definition uuid.h:414
uuid(span< value_type, 16 > bytes)
Definition uuid.h:402
constexpr uuid() noexcept=default
constexpr uuid_version version() const noexcept
Definition uuid.h:426
friend std::basic_ostream< Elem, Traits > & operator<<(std::basic_ostream< Elem, Traits > &s, uuid const &id)
Definition uuid.h:605
constexpr bool is_nil() const noexcept
Definition uuid.h:442
std::array< value_type, 16 > data
Definition uuid.h:550
uuid(ForwardIterator first, ForwardIterator last)
Definition uuid.h:408
static constexpr bool is_valid_uuid(StringType const &in_str) noexcept
Definition uuid.h:459
Definition core.h:1598
constexpr auto count() -> size_t
Definition core.h:1538
This file is also about defining core js concepts.
Definition BasePhotonWindow.hpp:22
Definition args.h:20
Definition uuid.h:926
constexpr std::basic_string_view< TChar > to_string_view(TChar const *str) noexcept
Definition uuid.h:101
constexpr bool is_hex(TChar const ch) noexcept
Definition uuid.h:92
constexpr CharT guid_encoder[17]
Definition uuid.h:304
constexpr wchar_t empty_guid< wchar_t >[37]
Definition uuid.h:301
constexpr unsigned char hex2char(TChar const ch) noexcept
Definition uuid.h:80
constexpr wchar_t guid_encoder< wchar_t >[17]
Definition uuid.h:307
constexpr CharT empty_guid[37]
Definition uuid.h:298
Definition uuid.h:68
gsl::span< ElementType, Extent > span
Definition uuid.h:74
std::basic_ostream< Elem, Traits > & operator<<(std::basic_ostream< Elem, Traits > &s, uuid const &id)
Definition uuid.h:605
basic_uuid_random_generator< std::mt19937 > uuid_random_generator
Definition uuid.h:771
bool operator!=(uuid const &lhs, uuid const &rhs) noexcept
Definition uuid.h:573
std::basic_string< CharT, Traits, Allocator > to_string(uuid const &id)
Definition uuid.h:586
uuid_variant
Definition uuid.h:342
bool operator==(uuid const &lhs, uuid const &rhs) noexcept
Definition uuid.h:568
uuid_version
Definition uuid.h:369
bool operator<(uuid const &lhs, uuid const &rhs) noexcept
Definition uuid.h:578
#define NULL
Definition strtod.cpp:30
Definition format.h:1901
std::size_t result_type
Definition uuid.h:931
result_type operator()(argument_type const &uuid) const
Definition uuid.h:933
b
Definition tag_strings.h:61
s
Definition tag_strings.h:47
a
Definition tag_strings.h:43
i
Definition tag_strings.h:60
hr
Definition tag_strings.h:30