Elaztek Developer Hub
Blamite Game Engine - Strings  00386.06.16.23.0646.blamite
A library containing general purpose utilities and classes for use in multiple projects.
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 #include <span>
29 
30 #ifdef _WIN32
31 
32 #ifndef WIN32_LEAN_AND_MEAN
33 #define WIN32_LEAN_AND_MEAN
34 #endif
35 #ifndef NOMINMAX
36 #define NOMINMAX
37 #endif
38 
39 #ifdef UUID_SYSTEM_GENERATOR
40 #include <objbase.h>
41 #endif
42 
43 #ifdef UUID_TIME_GENERATOR
44 #include <iphlpapi.h>
45 #pragma comment(lib, "IPHLPAPI.lib")
46 #endif
47 
48 #elif defined(__linux__) || defined(__unix__)
49 
50 #ifdef UUID_SYSTEM_GENERATOR
51 #include <uuid/uuid.h>
52 #endif
53 
54 #elif defined(__APPLE__)
55 
56 #ifdef UUID_SYSTEM_GENERATOR
57 #include <CoreFoundation/CFUUID.h>
58 #endif
59 
60 #endif
61 
62 namespace uuids
63 {
64 #ifdef __cpp_lib_span
65  template <class ElementType, std::size_t Extent>
66  using span = std::span<ElementType, Extent>;
67 #else
68  template <class ElementType, std::ptrdiff_t Extent>
69  using span = gsl::span<ElementType, Extent>;
70 #endif
71 
72  namespace detail
73  {
74  template <typename TChar>
75  [[nodiscard]] constexpr inline unsigned char hex2char(TChar const ch) noexcept
76  {
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'));
83  return 0;
84  }
85 
86  template <typename TChar>
87  [[nodiscard]] constexpr inline bool is_hex(TChar const ch) noexcept
88  {
89  return
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'));
93  }
94 
95  template <typename TChar>
96  [[nodiscard]] constexpr std::basic_string_view<TChar> to_string_view(TChar const * str) noexcept
97  {
98  if (str) return str;
99  return {};
100  }
101 
102  template <typename StringType>
103  [[nodiscard]]
104  constexpr std::basic_string_view<
105  typename StringType::value_type,
106  typename StringType::traits_type>
107  to_string_view(StringType const & str) noexcept
108  {
109  return str;
110  }
111 
112  class sha1
113  {
114  public:
115  using digest32_t = uint32_t[5];
116  using digest8_t = uint8_t[20];
117 
118  static constexpr unsigned int block_bytes = 64;
119 
120  [[nodiscard]] inline static uint32_t left_rotate(uint32_t value, size_t const count) noexcept
121  {
122  return (value << count) ^ (value >> (32 - count));
123  }
124 
125  sha1() { reset(); }
126 
127  void reset() noexcept
128  {
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;
135  m_byteCount = 0;
136  }
137 
138  void process_byte(uint8_t octet)
139  {
140  this->m_block[this->m_blockByteIndex++] = octet;
141  ++this->m_byteCount;
142  if (m_blockByteIndex == block_bytes)
143  {
144  this->m_blockByteIndex = 0;
145  process_block();
146  }
147  }
148 
149  void process_block(void const * const start, void const * const end)
150  {
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)
154  {
155  process_byte(*begin);
156  begin++;
157  }
158  }
159 
160  void process_bytes(void const * const data, size_t const len)
161  {
162  const uint8_t* block = static_cast<const uint8_t*>(data);
163  process_block(block, block + len);
164  }
165 
166  uint32_t const * get_digest(digest32_t digest)
167  {
168  size_t const bitCount = this->m_byteCount * 8;
169  process_byte(0x80);
170  if (this->m_blockByteIndex > 56) {
171  while (m_blockByteIndex != 0) {
172  process_byte(0);
173  }
174  while (m_blockByteIndex < 56) {
175  process_byte(0);
176  }
177  }
178  else {
179  while (m_blockByteIndex < 56) {
180  process_byte(0);
181  }
182  }
183  process_byte(0);
184  process_byte(0);
185  process_byte(0);
186  process_byte(0);
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));
191 
192  memcpy(digest, m_digest, 5 * sizeof(uint32_t));
193  return digest;
194  }
195 
196  uint8_t const * get_digest_bytes(digest8_t digest)
197  {
198  digest32_t d32;
199  get_digest(d32);
200  size_t di = 0;
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);
205 
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);
210 
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);
215 
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);
220 
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);
225 
226  return digest;
227  }
228 
229  private:
230  void process_block()
231  {
232  uint32_t w[80];
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]);
238  }
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);
241  }
242 
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];
248 
249  for (std::size_t i = 0; i < 80; ++i)
250  {
251  uint32_t f = 0;
252  uint32_t k = 0;
253 
254  if (i < 20) {
255  f = (b & c) | (~b & d);
256  k = 0x5A827999;
257  }
258  else if (i < 40) {
259  f = b ^ c ^ d;
260  k = 0x6ED9EBA1;
261  }
262  else if (i < 60) {
263  f = (b & c) | (b & d) | (c & d);
264  k = 0x8F1BBCDC;
265  }
266  else {
267  f = b ^ c ^ d;
268  k = 0xCA62C1D6;
269  }
270  uint32_t temp = left_rotate(a, 5) + f + e + k + w[i];
271  e = d;
272  d = c;
273  c = left_rotate(b, 30);
274  b = a;
275  a = temp;
276  }
277 
278  m_digest[0] += a;
279  m_digest[1] += b;
280  m_digest[2] += c;
281  m_digest[3] += d;
282  m_digest[4] += e;
283  }
284 
285  private:
286  digest32_t m_digest;
287  uint8_t m_block[64];
288  size_t m_blockByteIndex;
289  size_t m_byteCount;
290  };
291 
292  template <typename CharT>
293  inline constexpr CharT empty_guid[37] = "00000000-0000-0000-0000-000000000000";
294 
295  template <>
296  inline constexpr wchar_t empty_guid<wchar_t>[37] = L"00000000-0000-0000-0000-000000000000";
297 
298  template <typename CharT>
299  inline constexpr CharT guid_encoder[17] = "0123456789abcdef";
300 
301  template <>
302  inline constexpr wchar_t guid_encoder<wchar_t>[17] = L"0123456789abcdef";
303  }
304 
305  // --------------------------------------------------------------------------------------------------------------------------
306  // UUID format https://tools.ietf.org/html/rfc4122
307  // --------------------------------------------------------------------------------------------------------------------------
308 
309  // --------------------------------------------------------------------------------------------------------------------------
310  // Field NDR Data Type Octet # Note
311  // --------------------------------------------------------------------------------------------------------------------------
312  // time_low unsigned long 0 - 3 The low field of the timestamp.
313  // time_mid unsigned short 4 - 5 The middle field of the timestamp.
314  // time_hi_and_version unsigned short 6 - 7 The high field of the timestamp multiplexed with the version number.
315  // clock_seq_hi_and_reserved unsigned small 8 The high field of the clock sequence multiplexed with the variant.
316  // clock_seq_low unsigned small 9 The low field of the clock sequence.
317  // node character 10 - 15 The spatially unique node identifier.
318  // --------------------------------------------------------------------------------------------------------------------------
319  // 0 1 2 3
320  // 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
321  // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
322  // | time_low |
323  // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
324  // | time_mid | time_hi_and_version |
325  // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
326  // |clk_seq_hi_res | clk_seq_low | node (0-1) |
327  // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
328  // | node (2-5) |
329  // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
330 
331  // --------------------------------------------------------------------------------------------------------------------------
332  // enumerations
333  // --------------------------------------------------------------------------------------------------------------------------
334 
335  // indicated by a bit pattern in octet 8, marked with N in xxxxxxxx-xxxx-xxxx-Nxxx-xxxxxxxxxxxx
336  enum class uuid_variant
337  {
338  // NCS backward compatibility (with the obsolete Apollo Network Computing System 1.5 UUID format)
339  // N bit pattern: 0xxx
340  // > 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);
341  // > the next 2 octets are reserved;
342  // > the next octet is the "address family";
343  // > the final 7 octets are a 56-bit host ID in the form specified by the address family
344  ncs,
345 
346  // RFC 4122/DCE 1.1
347  // N bit pattern: 10xx
348  // > big-endian byte order
349  rfc,
350 
351  // Microsoft Corporation backward compatibility
352  // N bit pattern: 110x
353  // > little endian byte order
354  // > formely used in the Component Object Model (COM) library
355  microsoft,
356 
357  // reserved for possible future definition
358  // N bit pattern: 111x
359  reserved
360  };
361 
362  // indicated by a bit pattern in octet 6, marked with M in xxxxxxxx-xxxx-Mxxx-xxxx-xxxxxxxxxxxx
363  enum class uuid_version
364  {
365  none = 0, // only possible for nil or invalid uuids
366  time_based = 1, // The time-based version specified in RFC 4122
367  dce_security = 2, // DCE Security version, with embedded POSIX UIDs.
368  name_based_md5 = 3, // The name-based version specified in RFS 4122 with MD5 hashing
369  random_number_based = 4, // The randomly or pseudo-randomly generated version specified in RFS 4122
370  name_based_sha1 = 5 // The name-based version specified in RFS 4122 with SHA1 hashing
371  };
372 
373  // Forward declare uuid & to_string so that we can declare to_string as a friend later.
374  class uuid;
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);
379 
380  // --------------------------------------------------------------------------------------------------------------------------
381  // uuid class
382  // --------------------------------------------------------------------------------------------------------------------------
383  class uuid
384  {
385  public:
386  using value_type = uint8_t;
387 
388  constexpr uuid() noexcept = default;
389 
390  uuid(value_type(&arr)[16]) noexcept
391  {
392  std::copy(std::cbegin(arr), std::cend(arr), std::begin(data));
393  }
394 
395  constexpr uuid(std::array<value_type, 16> const & arr) noexcept : data{arr} {}
396 
397  explicit uuid(span<value_type, 16> bytes)
398  {
399  std::copy(std::cbegin(bytes), std::cend(bytes), std::begin(data));
400  }
401 
402  template<typename ForwardIterator>
403  explicit uuid(ForwardIterator first, ForwardIterator last)
404  {
405  if (std::distance(first, last) == 16)
406  std::copy(first, last, std::begin(data));
407  }
408 
409  [[nodiscard]] constexpr uuid_variant variant() const noexcept
410  {
411  if ((data[8] & 0x80) == 0x00)
412  return uuid_variant::ncs;
413  else if ((data[8] & 0xC0) == 0x80)
414  return uuid_variant::rfc;
415  else if ((data[8] & 0xE0) == 0xC0)
417  else
418  return uuid_variant::reserved;
419  }
420 
421  [[nodiscard]] constexpr uuid_version version() const noexcept
422  {
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)
433  else
434  return uuid_version::none;
435  }
436 
437  [[nodiscard]] constexpr bool is_nil() const noexcept
438  {
439  for (size_t i = 0; i < data.size(); ++i) if (data[i] != 0) return false;
440  return true;
441  }
442 
443  void swap(uuid & other) noexcept
444  {
445  data.swap(other.data);
446  }
447 
448  [[nodiscard]] inline span<std::byte const, 16> as_bytes() const
449  {
450  return span<std::byte const, 16>(reinterpret_cast<std::byte const*>(data.data()), 16);
451  }
452 
453  template <typename StringType>
454  [[nodiscard]] constexpr static bool is_valid_uuid(StringType const & in_str) noexcept
455  {
456  auto str = detail::to_string_view(in_str);
457  bool firstDigit = true;
458  size_t hasBraces = 0;
459  size_t index = 0;
460 
461  if (str.empty())
462  return false;
463 
464  if (str.front() == '{')
465  hasBraces = 1;
466  if (hasBraces && str.back() != '}')
467  return false;
468 
469  for (size_t i = hasBraces; i < str.size() - hasBraces; ++i)
470  {
471  if (str[i] == '-') continue;
472 
473  if (index >= 16 || !detail::is_hex(str[i]))
474  {
475  return false;
476  }
477 
478  if (firstDigit)
479  {
480  firstDigit = false;
481  }
482  else
483  {
484  index++;
485  firstDigit = true;
486  }
487  }
488 
489  if (index < 16)
490  {
491  return false;
492  }
493 
494  return true;
495  }
496 
497  template <typename StringType>
498  [[nodiscard]] constexpr static std::optional<uuid> from_string(StringType const & in_str) noexcept
499  {
500  auto str = detail::to_string_view(in_str);
501  bool firstDigit = true;
502  size_t hasBraces = 0;
503  size_t index = 0;
504 
505  std::array<uint8_t, 16> data{ { 0 } };
506 
507  if (str.empty()) return {};
508 
509  if (str.front() == '{')
510  hasBraces = 1;
511  if (hasBraces && str.back() != '}')
512  return {};
513 
514  for (size_t i = hasBraces; i < str.size() - hasBraces; ++i)
515  {
516  if (str[i] == '-') continue;
517 
518  if (index >= 16 || !detail::is_hex(str[i]))
519  {
520  return {};
521  }
522 
523  if (firstDigit)
524  {
525  data[index] = static_cast<uint8_t>(detail::hex2char(str[i]) << 4);
526  firstDigit = false;
527  }
528  else
529  {
530  data[index] = static_cast<uint8_t>(data[index] | detail::hex2char(str[i]));
531  index++;
532  firstDigit = true;
533  }
534  }
535 
536  if (index < 16)
537  {
538  return {};
539  }
540 
541  return uuid{ data };
542  }
543 
544  private:
545  std::array<value_type, 16> data{ { 0 } };
546 
547  friend bool operator==(uuid const & lhs, uuid const & rhs) noexcept;
548  friend bool operator<(uuid const & lhs, uuid const & rhs) noexcept;
549 
550  template <class Elem, class Traits>
551  friend std::basic_ostream<Elem, Traits> & operator<<(std::basic_ostream<Elem, Traits> &s, uuid const & id);
552 
553  template<class CharT, class Traits, class Allocator>
554  friend std::basic_string<CharT, Traits, Allocator> to_string(uuid const& id);
555 
556  friend std::hash<uuid>;
557  };
558 
559  // --------------------------------------------------------------------------------------------------------------------------
560  // operators and non-member functions
561  // --------------------------------------------------------------------------------------------------------------------------
562 
563  [[nodiscard]] inline bool operator== (uuid const& lhs, uuid const& rhs) noexcept
564  {
565  return lhs.data == rhs.data;
566  }
567 
568  [[nodiscard]] inline bool operator!= (uuid const& lhs, uuid const& rhs) noexcept
569  {
570  return !(lhs == rhs);
571  }
572 
573  [[nodiscard]] inline bool operator< (uuid const& lhs, uuid const& rhs) noexcept
574  {
575  return lhs.data < rhs.data;
576  }
577 
578  template <class CharT,
579  class Traits,
580  class Allocator>
581  [[nodiscard]] inline std::basic_string<CharT, Traits, Allocator> to_string(uuid const & id)
582  {
583  std::basic_string<CharT, Traits, Allocator> uustr{detail::empty_guid<CharT>};
584 
585  for (size_t i = 0, index = 0; i < 36; ++i)
586  {
587  if (i == 8 || i == 13 || i == 18 || i == 23)
588  {
589  continue;
590  }
591  uustr[i] = detail::guid_encoder<CharT>[id.data[index] >> 4 & 0x0f];
592  uustr[++i] = detail::guid_encoder<CharT>[id.data[index] & 0x0f];
593  index++;
594  }
595 
596  return uustr;
597  }
598 
599  template <class Elem, class Traits>
600  std::basic_ostream<Elem, Traits>& operator<<(std::basic_ostream<Elem, Traits>& s, uuid const& id)
601  {
602  s << to_string(id);
603  return s;
604  }
605 
606  inline void swap(uuids::uuid & lhs, uuids::uuid & rhs) noexcept
607  {
608  lhs.swap(rhs);
609  }
610 
611  // --------------------------------------------------------------------------------------------------------------------------
612  // namespace IDs that could be used for generating name-based uuids
613  // --------------------------------------------------------------------------------------------------------------------------
614 
615  // Name string is a fully-qualified domain name
616  static uuid uuid_namespace_dns{ {0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8} };
617 
618  // Name string is a URL
619  static uuid uuid_namespace_url{ {0x6b, 0xa7, 0xb8, 0x11, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8} };
620 
621  // Name string is an ISO OID (See https://oidref.com/, https://en.wikipedia.org/wiki/Object_identifier)
622  static uuid uuid_namespace_oid{ {0x6b, 0xa7, 0xb8, 0x12, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8} };
623 
624  // 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)
625  static uuid uuid_namespace_x500{ {0x6b, 0xa7, 0xb8, 0x14, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8} };
626 
627  // --------------------------------------------------------------------------------------------------------------------------
628  // uuid generators
629  // --------------------------------------------------------------------------------------------------------------------------
630 
631 #ifdef UUID_SYSTEM_GENERATOR
632  class uuid_system_generator
633  {
634  public:
635  using result_type = uuid;
636 
637  uuid operator()()
638  {
639 #ifdef _WIN32
640 
641  GUID newId;
642  HRESULT hr = ::CoCreateGuid(&newId);
643 
644  if (FAILED(hr))
645  {
646  throw std::system_error(hr, std::system_category(), "CoCreateGuid failed");
647  }
648 
649  std::array<uint8_t, 16> bytes =
650  { {
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),
655 
656  (unsigned char)((newId.Data2 >> 8) & 0xFF),
657  (unsigned char)((newId.Data2) & 0xFF),
658 
659  (unsigned char)((newId.Data3 >> 8) & 0xFF),
660  (unsigned char)((newId.Data3) & 0xFF),
661 
662  newId.Data4[0],
663  newId.Data4[1],
664  newId.Data4[2],
665  newId.Data4[3],
666  newId.Data4[4],
667  newId.Data4[5],
668  newId.Data4[6],
669  newId.Data4[7]
670  } };
671 
672  return uuid{ std::begin(bytes), std::end(bytes) };
673 
674 #elif defined(__linux__) || defined(__unix__)
675 
676  uuid_t id;
677  uuid_generate(id);
678 
679  std::array<uint8_t, 16> bytes =
680  { {
681  id[0],
682  id[1],
683  id[2],
684  id[3],
685  id[4],
686  id[5],
687  id[6],
688  id[7],
689  id[8],
690  id[9],
691  id[10],
692  id[11],
693  id[12],
694  id[13],
695  id[14],
696  id[15]
697  } };
698 
699  return uuid{ std::begin(bytes), std::end(bytes) };
700 
701 #elif defined(__APPLE__)
702  auto newId = CFUUIDCreate(NULL);
703  auto bytes = CFUUIDGetUUIDBytes(newId);
704  CFRelease(newId);
705 
706  std::array<uint8_t, 16> arrbytes =
707  { {
708  bytes.byte0,
709  bytes.byte1,
710  bytes.byte2,
711  bytes.byte3,
712  bytes.byte4,
713  bytes.byte5,
714  bytes.byte6,
715  bytes.byte7,
716  bytes.byte8,
717  bytes.byte9,
718  bytes.byte10,
719  bytes.byte11,
720  bytes.byte12,
721  bytes.byte13,
722  bytes.byte14,
723  bytes.byte15
724  } };
725  return uuid{ std::begin(arrbytes), std::end(arrbytes) };
726 #else
727  return uuid{};
728 #endif
729  }
730  };
731 #endif
732 
733  template <typename UniformRandomNumberGenerator>
735  {
736  public:
737  using engine_type = UniformRandomNumberGenerator;
738 
740  generator(&gen, [](auto) {}) {}
742  generator(gen, [](auto) {}) {}
743 
744  [[nodiscard]] uuid operator()()
745  {
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);
749 
750  // variant must be 10xxxxxx
751  bytes[8] &= 0xBF;
752  bytes[8] |= 0x80;
753 
754  // version must be 0100xxxx
755  bytes[6] &= 0x4F;
756  bytes[6] |= 0x40;
757 
758  return uuid{std::begin(bytes), std::end(bytes)};
759  }
760 
761  private:
762  std::uniform_int_distribution<uint32_t> distribution;
763  std::shared_ptr<UniformRandomNumberGenerator> generator;
764  };
765 
767 
769  {
770  public:
771  explicit uuid_name_generator(uuid const& namespace_uuid) noexcept
772  : nsuuid(namespace_uuid)
773  {}
774 
775  template <typename StringType>
776  [[nodiscard]] uuid operator()(StringType const & name)
777  {
778  reset();
779  process_characters(detail::to_string_view(name));
780  return make_uuid();
781  }
782 
783  private:
784  void reset()
785  {
786  hasher.reset();
787  std::byte bytes[16];
788  auto nsbytes = nsuuid.as_bytes();
789  std::copy(std::cbegin(nsbytes), std::cend(nsbytes), bytes);
790  hasher.process_bytes(bytes, 16);
791  }
792 
793  template <typename CharT, typename Traits>
794  void process_characters(std::basic_string_view<CharT, Traits> const str)
795  {
796  for (uint32_t c : str)
797  {
798  hasher.process_byte(static_cast<uint8_t>(c & 0xFF));
799  if constexpr (!std::is_same_v<CharT, char>)
800  {
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));
804  }
805  }
806  }
807 
808  [[nodiscard]] uuid make_uuid()
809  {
811  hasher.get_digest_bytes(digest);
812 
813  // variant must be 0b10xxxxxx
814  digest[8] &= 0xBF;
815  digest[8] |= 0x80;
816 
817  // version must be 0b0101xxxx
818  digest[6] &= 0x5F;
819  digest[6] |= 0x50;
820 
821  return uuid{ digest, digest + 16 };
822  }
823 
824  private:
825  uuid nsuuid;
826  detail::sha1 hasher;
827  };
828 
829 #ifdef UUID_TIME_GENERATOR
830  // !!! DO NOT USE THIS IN PRODUCTION
831  // this implementation is unreliable for good uuids
832  class uuid_time_generator
833  {
834  using mac_address = std::array<unsigned char, 6>;
835 
836  std::optional<mac_address> device_address;
837 
838  [[nodiscard]] bool get_mac_address()
839  {
840  if (device_address.has_value())
841  {
842  return true;
843  }
844 
845 #ifdef _WIN32
846  DWORD len = 0;
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;
853  mac_address addr;
854  std::copy(pips->Address, pips->Address + 6, std::begin(addr));
855  device_address = addr;
856 #endif
857 
858  return device_address.has_value();
859  }
860 
861  [[nodiscard]] long long get_time_intervals()
862  {
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();
866  return ns / 100;
867  }
868 
869  [[nodiscard]] static unsigned short get_clock_sequence()
870  {
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++;
875  }
876 
877  public:
878  [[nodiscard]] uuid operator()()
879  {
880  if (get_mac_address())
881  {
882  std::array<uuids::uuid::value_type, 16> data;
883 
884  auto tm = get_time_intervals();
885 
886  auto clock_seq = get_clock_sequence();
887 
888  auto ptm = reinterpret_cast<uuids::uuid::value_type*>(&tm);
889 
890  memcpy(&data[0], ptm + 4, 4);
891  memcpy(&data[4], ptm + 2, 2);
892  memcpy(&data[6], ptm, 2);
893 
894  memcpy(&data[8], &clock_seq, 2);
895 
896  // variant must be 0b10xxxxxx
897  data[8] &= 0xBF;
898  data[8] |= 0x80;
899 
900  // version must be 0b0001xxxx
901  data[6] &= 0x1F;
902  data[6] |= 0x10;
903 
904  memcpy(&data[10], &device_address.value()[0], 6);
905 
906  return uuids::uuid{std::cbegin(data), std::cend(data)};
907  }
908 
909  return {};
910  }
911  };
912 #endif
913 }
914 
915 namespace std
916 {
917  template <>
918  struct hash<uuids::uuid>
919  {
921  using result_type = std::size_t;
922 
923  [[nodiscard]] result_type operator()(argument_type const &uuid) const
924  {
925 #ifdef UUID_HASH_STRING_BASED
926  std::hash<std::string> hasher;
927  return static_cast<result_type>(hasher(uuids::to_string(uuid)));
928 #else
929  uint64_t l =
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]);
938  uint64_t h =
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]);
947 
948  if constexpr (sizeof(result_type) > 4)
949  {
950  return result_type(l ^ h);
951  }
952  else
953  {
954  uint64_t hash64 = l ^ h;
955  return result_type(uint32_t(hash64 >> 32) ^ uint32_t(hash64));
956  }
957 #endif
958  }
959  };
960 }
961 
962 #endif /* STDUUID_H */
uuids::uuid::to_string
friend std::basic_string< CharT, Traits, Allocator > to_string(uuid const &id)
Definition: uuid.h:581
uuids::uuid::is_nil
constexpr bool is_nil() const noexcept
Definition: uuid.h:437
uuids::basic_uuid_random_generator::operator()
uuid operator()()
Definition: uuid.h:744
uuids::detail::sha1::digest32_t
uint32_t[5] digest32_t
Definition: uuid.h:115
uuids::detail::guid_encoder< wchar_t >
constexpr wchar_t guid_encoder< wchar_t >[17]
Definition: uuid.h:302
uuids::uuid::uuid
uuid(span< value_type, 16 > bytes)
Definition: uuid.h:397
uuids::detail::sha1::get_digest_bytes
const uint8_t * get_digest_bytes(digest8_t digest)
Definition: uuid.h:196
uuids::detail::empty_guid< wchar_t >
constexpr wchar_t empty_guid< wchar_t >[37]
Definition: uuid.h:296
uuids::operator<
bool operator<(uuid const &lhs, uuid const &rhs) noexcept
Definition: uuid.h:573
uuids::detail::sha1::block_bytes
static constexpr unsigned int block_bytes
Definition: uuid.h:118
uuids::uuid_version::none
@ none
uuids::detail::sha1
Definition: uuid.h:112
uuids::detail::empty_guid
constexpr CharT empty_guid[37]
Definition: uuid.h:293
uuids::uuid_version::time_based
@ time_based
uuids
Definition: uuid.h:62
uuids::detail::sha1::sha1
sha1()
Definition: uuid.h:125
uuids::uuid::operator==
friend bool operator==(uuid const &lhs, uuid const &rhs) noexcept
Definition: uuid.h:563
uuids::uuid_variant
uuid_variant
Definition: uuid.h:336
uuids::uuid_version::name_based_sha1
@ name_based_sha1
uuids::detail::to_string_view
constexpr std::basic_string_view< TChar > to_string_view(TChar const *str) noexcept
Definition: uuid.h:96
uuids::uuid::version
constexpr uuid_version version() const noexcept
Definition: uuid.h:421
uuids::uuid
Definition: uuid.h:383
uuids::uuid_variant::microsoft
@ microsoft
uuids::uuid::from_string
constexpr static std::optional< uuid > from_string(StringType const &in_str) noexcept
Definition: uuid.h:498
uuids::detail::sha1::get_digest
const uint32_t * get_digest(digest32_t digest)
Definition: uuid.h:166
uuids::basic_uuid_random_generator::engine_type
UniformRandomNumberGenerator engine_type
Definition: uuid.h:737
uuids::detail::sha1::process_bytes
void process_bytes(void const *const data, size_t const len)
Definition: uuid.h:160
uuids::uuid::as_bytes
span< std::byte const, 16 > as_bytes() const
Definition: uuid.h:448
uuids::detail::sha1::process_block
void process_block(void const *const start, void const *const end)
Definition: uuid.h:149
copy
Use of this software is granted under one of the following two to be chosen freely by the user Boost Software License Version Marcin Kalicinski Permission is hereby free of to any person or organization obtaining a copy of the software and accompanying documentation covered by this and transmit the and to prepare derivative works of the and to permit third parties to whom the Software is furnished to do all subject to the including the above license this restriction and the following must be included in all copies of the in whole or in and all derivative works of the unless such copies or derivative works are solely in the form of machine executable object code generated by a source language processor THE SOFTWARE IS PROVIDED AS WITHOUT WARRANTY OF ANY EXPRESS OR INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF FITNESS FOR A PARTICULAR TITLE AND NON INFRINGEMENT IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE FOR ANY DAMAGES OR OTHER WHETHER IN TORT OR ARISING OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE The MIT Marcin Kalicinski Permission is hereby free of to any person obtaining a copy of this software and associated documentation to deal in the Software without including without limitation the rights to copy
Definition: license.txt:39
byte
unsigned char byte
Definition: BlamColor.h:12
uuids::swap
void swap(uuids::uuid &lhs, uuids::uuid &rhs) noexcept
Definition: uuid.h:606
uuids::detail::hex2char
constexpr unsigned char hex2char(TChar const ch) noexcept
Definition: uuid.h:75
uuids::uuid::uuid
constexpr uuid(std::array< value_type, 16 > const &arr) noexcept
Definition: uuid.h:395
uuids::uuid::operator<
friend bool operator<(uuid const &lhs, uuid const &rhs) noexcept
Definition: uuid.h:573
uuids::detail::is_hex
constexpr bool is_hex(TChar const ch) noexcept
Definition: uuid.h:87
uuids::uuid_name_generator::uuid_name_generator
uuid_name_generator(uuid const &namespace_uuid) noexcept
Definition: uuid.h:771
uuids::detail::sha1::digest8_t
uint8_t[20] digest8_t
Definition: uuid.h:116
uuids::uuid_variant::rfc
@ rfc
uuids::uuid_version
uuid_version
Definition: uuid.h:363
uuids::operator!=
bool operator!=(uuid const &lhs, uuid const &rhs) noexcept
Definition: uuid.h:568
uuids::basic_uuid_random_generator::basic_uuid_random_generator
basic_uuid_random_generator(engine_type &gen)
Definition: uuid.h:739
uuids::detail::sha1::reset
void reset() noexcept
Definition: uuid.h:127
uuids::uuid_version::dce_security
@ dce_security
uuids::operator<<
std::basic_ostream< Elem, Traits > & operator<<(std::basic_ostream< Elem, Traits > &s, uuid const &id)
Definition: uuid.h:600
uuids::uuid_variant::reserved
@ reserved
uuids::uuid_name_generator::operator()
uuid operator()(StringType const &name)
Definition: uuid.h:776
uuids::uuid::operator<<
friend std::basic_ostream< Elem, Traits > & operator<<(std::basic_ostream< Elem, Traits > &s, uuid const &id)
Definition: uuid.h:600
uuids::to_string
std::basic_string< CharT, Traits, Allocator > to_string(uuid const &id)
Definition: uuid.h:581
std
Definition: uuid.h:915
uuids::uuid::uuid
uuid(ForwardIterator first, ForwardIterator last)
Definition: uuid.h:403
uuids::uuid_version::random_number_based
@ random_number_based
uuids::uuid_version::name_based_md5
@ name_based_md5
uuids::operator==
bool operator==(uuid const &lhs, uuid const &rhs) noexcept
Definition: uuid.h:563
uuids::span
gsl::span< ElementType, Extent > span
Definition: uuid.h:69
uuids::uuid_name_generator
Definition: uuid.h:768
e
void e()
Definition: BlamString.cpp:3
uuids::uuid::value_type
uint8_t value_type
Definition: uuid.h:386
uuids::basic_uuid_random_generator
Definition: uuid.h:734
uuids::uuid_variant::ncs
@ ncs
uuids::uuid::variant
constexpr uuid_variant variant() const noexcept
Definition: uuid.h:409
uuids::uuid::swap
void swap(uuid &other) noexcept
Definition: uuid.h:443
std::hash< uuids::uuid >::operator()
result_type operator()(argument_type const &uuid) const
Definition: uuid.h:923
std::hash< uuids::uuid >::result_type
std::size_t result_type
Definition: uuid.h:921
uuids::uuid::is_valid_uuid
constexpr static bool is_valid_uuid(StringType const &in_str) noexcept
Definition: uuid.h:454
uuids::detail::guid_encoder
constexpr CharT guid_encoder[17]
Definition: uuid.h:299
uuids::uuid::uuid
constexpr uuid() noexcept=default
uuids::detail::sha1::left_rotate
static uint32_t left_rotate(uint32_t value, size_t const count) noexcept
Definition: uuid.h:120
uuids::basic_uuid_random_generator::basic_uuid_random_generator
basic_uuid_random_generator(engine_type *gen)
Definition: uuid.h:741
uuids::detail::sha1::process_byte
void process_byte(uint8_t octet)
Definition: uuid.h:138