1 #pragma once
2 
3 #include <iostream>
4 #include <string>
5 #include <cstring>
6 #include <limits>
7 #include <random>
8 #include <chrono>
9 
10 namespace tf {
11 
12 // Class: UUID
13 //
14 // A universally unique identifier (UUID) is an identifier standard used in software
15 // construction. A UUID is simply a 128-bit value. The meaning of each bit is defined
16 // by any of several variants.
17 // For human-readable display, many systems use a canonical format using hexadecimal
18 // text with inserted hyphen characters.
19 //
20 // For example: 123e4567-e89b-12d3-a456-426655440000
21 //
22 // The intent of UUIDs is to enable distributed systems to uniquely identify information
23 // without significant central coordination.
24 //
25 //   Copyright 2006 Andy Tompkins.
26 //   Distributed under the Boost Software License, Version 1.0. (See
27 //   accompanying file LICENSE_1_0.txt or copy at
28 //   http://www.boost.org/LICENSE_1_0.txt)
29 //
30 struct UUID {
31 
32   using value_type      = uint8_t;
33   using reference       = uint8_t&;
34   using const_reference = const uint8_t&;
35   using iterator        = uint8_t*;
36   using const_iterator  = const uint8_t*;
37   using size_type       = size_t;
38   using difference_type = ptrdiff_t;
39 
40   inline UUID();
41 
42   UUID(const UUID&) = default;
43   UUID(UUID&&) = default;
44 
45   UUID& operator = (const UUID&) = default;
46   UUID& operator = (UUID&&) = default;
47 
48   inline static size_type size();
49   inline iterator begin();
50   inline const_iterator begin() const;
51   inline iterator end();
52   inline const_iterator end() const;
53 
54   inline bool is_nil() const;
55   inline void swap(UUID& rhs);
56   inline size_t hash_value() const;
57 
58   inline bool operator == (const UUID&) const;
59   inline bool operator <  (const UUID&) const;
60   inline bool operator >  (const UUID&) const;
61   inline bool operator != (const UUID&) const;
62   inline bool operator >= (const UUID&) const;
63   inline bool operator <= (const UUID&) const;
64 
65   uint8_t data[16] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
66 
67   inline std::string to_string() const;
68 };
69 
70 // Constructor
UUID()71 inline UUID::UUID() {
72 
73   static thread_local std::default_random_engine engine {
74     std::random_device{}()
75   };
76 
77   std::uniform_int_distribution<unsigned long> distribution(
78     (std::numeric_limits<unsigned long>::min)(),
79     (std::numeric_limits<unsigned long>::max)()
80   );
81 
82   int i = 0;
83   auto random_value = distribution(engine);
84   for (auto it=begin(); it!=end(); ++it, ++i) {
85     if (i == sizeof(unsigned long)) {
86       random_value = distribution(engine);
87       i = 0;
88     }
89     *it = static_cast<UUID::value_type>((random_value >> (i*8)) & 0xFF);
90   }
91 
92   // set variant: must be 0b10xxxxxx
93   *(begin()+8) &= 0xBF;
94   *(begin()+8) |= 0x80;
95 
96   // set version: must be 0b0100xxxx
97   *(begin()+6) &= 0x4F; //0b01001111
98   *(begin()+6) |= 0x40; //0b01000000
99 }
100 
101 // Function: size
size()102 inline typename UUID::size_type UUID::size() {
103   return 16;
104 }
105 
106 // Function: begin
begin()107 inline typename UUID::iterator UUID::begin() {
108   return data;
109 }
110 
111 // Function: begin
begin() const112 inline typename UUID::const_iterator UUID::begin() const {
113   return data;
114 }
115 
116 // Function: end
end()117 inline typename UUID::iterator UUID::end() {
118   return data+size();
119 }
120 
121 // Function: end
end() const122 inline typename UUID::const_iterator UUID::end() const {
123   return data+size();
124 }
125 
126 // Function: is_nil
is_nil() const127 inline bool UUID::is_nil() const {
128   for (std::size_t i = 0; i < sizeof(this->data); ++i) {
129     if (this->data[i] != 0U) {
130       return false;
131     }
132   }
133   return true;
134 }
135 
136 // Procedure: swap
swap(UUID & rhs)137 inline void UUID::swap(UUID& rhs) {
138   UUID tmp = *this;
139   *this = rhs;
140   rhs = tmp;
141 }
142 
143 // Function: hash_value
hash_value() const144 inline size_t UUID::hash_value() const {
145   size_t seed = 0;
146   for(auto i=begin(); i != end(); ++i) {
147     seed ^= static_cast<size_t>(*i) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
148   }
149   return seed;
150 }
151 
152 // Operator: ==
operator ==(const UUID & rhs) const153 inline bool UUID::operator == (const UUID& rhs) const {
154   return std::memcmp(data, rhs.data, sizeof(data)) == 0;
155 }
156 
157 // Operator: !=
operator !=(const UUID & rhs) const158 inline bool UUID::operator != (const UUID& rhs) const {
159   return std::memcmp(data, rhs.data, sizeof(data)) != 0;
160 }
161 
162 // Operator: <
operator <(const UUID & rhs) const163 inline bool UUID::operator < (const UUID& rhs) const {
164   return std::memcmp(data, rhs.data, sizeof(data)) < 0;
165 }
166 
167 // Operator: >
operator >(const UUID & rhs) const168 inline bool UUID::operator > (const UUID& rhs) const {
169   return std::memcmp(data, rhs.data, sizeof(data)) > 0;
170 }
171 
172 // Operator: <=
operator <=(const UUID & rhs) const173 inline bool UUID::operator <= (const UUID& rhs) const {
174   return std::memcmp(data, rhs.data, sizeof(data)) <= 0;
175 }
176 
177 // Operator: >=
operator >=(const UUID & rhs) const178 inline bool UUID::operator >= (const UUID& rhs) const {
179   return std::memcmp(data, rhs.data, sizeof(data)) >= 0;
180 }
181 
182 // Function: to_string
to_string() const183 inline std::string UUID::to_string() const {
184 
185   auto to_char = [](size_t i) {
186     if (i <= 9) return static_cast<char>('0' + i);
187     return static_cast<char>('a' + (i-10));
188   };
189 
190   std::string result;
191   result.reserve(36);
192 
193   std::size_t i=0;
194   for (auto it = begin(); it!=end(); ++it, ++i) {
195 
196     const size_t hi = ((*it) >> 4) & 0x0F;
197     result += to_char(hi);
198 
199     const size_t lo = (*it) & 0x0F;
200     result += to_char(lo);
201 
202     if (i == 3 || i == 5 || i == 7 || i == 9) {
203       result += '-';
204     }
205   }
206   return result;
207 }
208 
209 // Procedure: swap
swap(UUID & lhs,UUID & rhs)210 inline void swap(UUID& lhs, UUID& rhs) {
211   lhs.swap(rhs);
212 }
213 
214 // ostream
operator <<(std::ostream & os,const UUID & rhs)215 inline std::ostream& operator << (std::ostream& os, const UUID& rhs) {
216   os << rhs.to_string();
217   return os;
218 }
219 
220 }  // End of namespace tf. ----------------------------------------------------
221 
222 //-----------------------------------------------------------------------------
223 
224 
225 namespace std {
226 
227 // Partial specialization: hash<tf::UUID>
228 template <>
229 struct hash<tf::UUID> {
operator ()std::hash230   size_t operator()(const tf::UUID& rhs) const { return rhs.hash_value(); }
231 };
232 
233 
234 }  // End of namespace std. ---------------------------------------------------
235 
236 
237