UuidKey.hpp
1 #pragma once
2 #include <score/serialization/VisitorInterface.hpp>
3 
4 #include <QString>
5 
6 #include <score_lib_base_export.h>
7 
8 #include <cstdint>
9 #include <stdexcept>
10 #include <string>
11 
12 // Yay for windows defining uuid_t macro
13 #if defined(uuid_t)
14 #undef uuid_t
15 #endif
16 
17 class JSONObject;
18 namespace score
19 {
20 namespace uuids
21 {
22 // Taken from boost.uuid
23 struct uuid
24 {
25 public:
26  typedef uint8_t value_type;
27  typedef uint8_t& reference;
28  typedef uint8_t const& const_reference;
29  typedef uint8_t* iterator;
30  typedef uint8_t const* const_iterator;
31  typedef std::size_t size_type;
32  typedef std::ptrdiff_t difference_type;
33 
34  static constexpr size_type static_size() noexcept { return 16; }
35 
36 public:
37  constexpr uuid() noexcept
38  : data{{}}
39  {
40  }
41 
42  constexpr uuid(const uuid& other) noexcept
43  : data{other.data[0], other.data[1], other.data[2], other.data[3],
44  other.data[4], other.data[5], other.data[6], other.data[7],
45  other.data[8], other.data[9], other.data[10], other.data[11],
46  other.data[12], other.data[13], other.data[14], other.data[15]}
47  {
48  }
49 
50  constexpr uuid& operator=(const uuid& other) noexcept
51  {
52  for(int i = 0; i < 16; i++)
53  data[i] = other.data[i];
54  return *this;
55  }
56 
57  constexpr uuid(uint8_t (&other)[16]) noexcept
58  : data{other[0], other[1], other[2], other[3], other[4], other[5],
59  other[6], other[7], other[8], other[9], other[10], other[11],
60  other[12], other[13], other[14], other[15]}
61  {
62  }
63 
64  constexpr auto begin() noexcept { return &data[0]; }
65  constexpr auto end() noexcept { return &data[0] + 16; }
66 
67  constexpr auto begin() const noexcept { return &data[0]; }
68  constexpr auto end() const noexcept { return &data[0] + 16; }
69 
70  constexpr size_type size() const noexcept { return static_size(); }
71 
72  constexpr bool is_nil() const noexcept
73  {
74  for(std::size_t i = 0; i < sizeof(data); ++i)
75  {
76  if(data[i] != 0U)
77  return false;
78  }
79  return true;
80  }
81 
82  enum variant_type
83  {
84  variant_ncs, // NCS backward compatibility
85  variant_rfc_4122, // defined in RFC 4122 document
86  variant_microsoft, // Microsoft Corporation backward compatibility
87  variant_future // future definition
88  };
89  variant_type variant() const noexcept
90  {
91  // variant is stored in octet 7
92  // which is index 8, since indexes count backwards
93  unsigned char octet7 = data[8]; // octet 7 is array index 8
94  if((octet7 & 0x80) == 0x00)
95  { // 0b0xxxxxxx
96  return variant_ncs;
97  }
98  else if((octet7 & 0xC0) == 0x80)
99  { // 0b10xxxxxx
100  return variant_rfc_4122;
101  }
102  else if((octet7 & 0xE0) == 0xC0)
103  { // 0b110xxxxx
104  return variant_microsoft;
105  }
106  else
107  {
108  // assert( (octet7 & 0xE0) == 0xE0 ) // 0b111xxxx
109  return variant_future;
110  }
111  }
112 
113  enum version_type
114  {
115  version_unknown = -1,
116  version_time_based = 1,
117  version_dce_security = 2,
118  version_name_based_md5 = 3,
119  version_random_number_based = 4,
120  version_name_based_sha1 = 5
121  };
122  version_type version() const noexcept
123  {
124  // version is stored in octet 9
125  // which is index 6, since indexes count backwards
126  uint8_t octet9 = data[6];
127  if((octet9 & 0xF0) == 0x10)
128  {
129  return version_time_based;
130  }
131  else if((octet9 & 0xF0) == 0x20)
132  {
133  return version_dce_security;
134  }
135  else if((octet9 & 0xF0) == 0x30)
136  {
137  return version_name_based_md5;
138  }
139  else if((octet9 & 0xF0) == 0x40)
140  {
141  return version_random_number_based;
142  }
143  else if((octet9 & 0xF0) == 0x50)
144  {
145  return version_name_based_sha1;
146  }
147  else
148  {
149  return version_unknown;
150  }
151  }
152 
153 public:
154  // or should it be array<uint8_t, 16>
155  uint8_t data[16];
156 };
157 
158 constexpr inline bool operator==(uuid const& lhs, uuid const& rhs) noexcept
159 {
160  for(std::size_t i = 0; i < uuid::static_size(); ++i)
161  {
162  if(lhs.data[i] != rhs.data[i])
163  return false;
164  }
165  return true;
166 }
167 
168 constexpr inline bool operator!=(uuid const& lhs, uuid const& rhs) noexcept
169 {
170  return !(lhs == rhs);
171 }
172 
173 #if __cpp_lib_constexpr_algorithms >= 201806L
174 #define constexpr_algorithm constexpr
175 #else
176 #define constexpr_algorithm
177 #endif
178 
179 constexpr_algorithm inline bool operator<(uuid const& lhs, uuid const& rhs) noexcept
180 {
181  return std::lexicographical_compare(
182  lhs.data, lhs.data + uuid::static_size(), rhs.data,
183  rhs.data + uuid::static_size());
184 }
185 
186 constexpr_algorithm inline bool operator>(uuid const& lhs, uuid const& rhs) noexcept
187 {
188  return rhs < lhs;
189 }
190 
191 constexpr_algorithm inline bool operator<=(uuid const& lhs, uuid const& rhs) noexcept
192 {
193  return !(rhs < lhs);
194 }
195 
196 constexpr_algorithm inline bool operator>=(uuid const& lhs, uuid const& rhs) noexcept
197 {
198  return !(lhs < rhs);
199 }
200 
201 // This is equivalent to boost::hash_range(u.begin(), u.end());
202 constexpr inline std::size_t hash_value(uuid const& u) noexcept
203 {
204  std::size_t seed = 0;
205  for(uuid::const_iterator i = u.begin(), e = u.end(); i != e; ++i)
206  {
207  seed ^= static_cast<std::size_t>(*i) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
208  }
209 
210  return seed;
211 }
212 
214 {
215  typedef uuid result_type;
216 
217  template <int N>
218  static constexpr uuid compute(const char (&s)[N])
219  {
220  static_assert(N == 37, "Invalid uuid");
221  return compute(s, s + N);
222  }
223 
224  template <typename CharIterator>
225  static constexpr uuid compute(CharIterator begin, CharIterator end)
226  {
227  // check open brace
228  auto c = *begin++;
229 
230  bool has_dashes = false;
231 
232  uint8_t u[16]{};
233  int i = 0;
234  for(auto it_byte = u; it_byte != u + 16; ++it_byte, ++i)
235  {
236  if(it_byte != u)
237  {
238  c = *begin++;
239  }
240 
241  if(i == 4)
242  {
243  has_dashes = is_dash(c);
244  if(has_dashes)
245  {
246  c = *begin++;
247  }
248  }
249 
250  if(has_dashes)
251  {
252  if(i == 6 || i == 8 || i == 10)
253  {
254  if(is_dash(c))
255  {
256  c = *begin++;
257  }
258  else
259  {
260  throw std::runtime_error{"Invalid uuid"};
261  }
262  }
263  }
264  auto res = get_value(c);
265  c = *begin++;
266  res <<= 4;
267  res |= get_value(c);
268  *it_byte = res;
269  }
270 
271  return u;
272  }
273 
274 private:
275  static constexpr unsigned char get_value(char c)
276  {
277  switch(c)
278  {
279  case '0':
280  return 0;
281  case '1':
282  return 1;
283  case '2':
284  return 2;
285  case '3':
286  return 3;
287  case '4':
288  return 4;
289  case '5':
290  return 5;
291  case '6':
292  return 6;
293  case '7':
294  return 7;
295  case '8':
296  return 8;
297  case '9':
298  return 9;
299  case 'a':
300  case 'A':
301  return 10;
302  case 'b':
303  case 'B':
304  return 11;
305  case 'c':
306  case 'C':
307  return 12;
308  case 'd':
309  case 'D':
310  return 13;
311  case 'e':
312  case 'E':
313  return 14;
314  case 'f':
315  case 'F':
316  return 15;
317  default:
318  throw std::runtime_error{"Invalid uuid"};
319  }
320  }
321 
322  static constexpr unsigned char get_value(QChar c) { return get_value(c.toLatin1()); }
323 
324  static constexpr bool is_dash(char c) { return c == '-'; }
325  static constexpr bool is_dash(QChar c) { return c.toLatin1() == '-'; }
326 };
327 
328 SCORE_LIB_BASE_EXPORT QByteArray toByteArray(score::uuids::uuid const& u);
329 
330 }
331 using uuid_t = uuids::uuid;
332 }
333 
334 #define return_uuid(text) \
335  do \
336  { \
337  constexpr const auto t = score::uuids::string_generator::compute((text)); \
338  return t; \
339  } while(0)
340 
341 template <typename Tag>
343 {
344  using this_type = UuidKey<Tag>;
345 
346  friend struct std::hash<this_type>;
347  // friend struct boost::hash<this_type>;
348  // friend struct boost::hash<const this_type>;
349  friend constexpr bool operator==(const this_type& lhs, const this_type& rhs)
350  {
351  return static_cast<const score::uuid_t&>(lhs)
352  == static_cast<const score::uuid_t&>(rhs);
353  }
354  friend constexpr bool operator!=(const this_type& lhs, const this_type& rhs)
355  {
356  return static_cast<const score::uuid_t&>(lhs)
357  != static_cast<const score::uuid_t&>(rhs);
358  }
359  friend constexpr bool operator<(const this_type& lhs, const this_type& rhs)
360  {
361  return static_cast<const score::uuid_t&>(lhs)
362  < static_cast<const score::uuid_t&>(rhs);
363  }
364 
365 public:
366  constexpr UuidKey() noexcept = default;
367  constexpr UuidKey(const UuidKey& other) noexcept = default;
368  constexpr UuidKey(UuidKey&& other) noexcept = default;
369  constexpr UuidKey& operator=(const UuidKey& other) noexcept = default;
370  constexpr UuidKey& operator=(UuidKey&& other) noexcept = default;
371 
372  constexpr UuidKey(score::uuid_t other) noexcept
373  : score::uuid_t(other)
374  {
375  }
376 
377  template <int N>
378  explicit constexpr UuidKey(const char (&txt)[N])
379  : score::uuid_t(score::uuids::string_generator::compute<N>(txt))
380  {
381  }
382 
383  template <typename Iterator>
384  constexpr UuidKey(Iterator beg_it, Iterator end_it)
385  : score::uuid_t(score::uuids::string_generator::compute(beg_it, end_it))
386  {
387  }
388 
389  constexpr static UuidKey fromString(const std::string& str)
390  {
391  return UuidKey{str.begin(), str.end()};
392  }
393 
394  constexpr static UuidKey fromString(const QString& str)
395  {
396  return UuidKey{str.begin(), str.end()};
397  }
398 
399  constexpr const score::uuid_t& impl() const { return *this; }
400  constexpr score::uuid_t& impl() { return *this; }
401 };
402 
403 namespace std
404 {
405 template <typename T>
406 struct hash<UuidKey<T>>
407 {
408  constexpr std::size_t operator()(const UuidKey<T>& kagi) const noexcept
409  {
410  return score::uuids::hash_value(kagi.impl());
411  }
412 };
413 }
414 
415 #include <score/serialization/VisitorInterface.hpp>
416 template <>
417 struct is_custom_serialized<score::uuid_t> : std::true_type
418 {
419 };
420 
421 template <>
422 struct SCORE_LIB_BASE_EXPORT TSerializer<JSONObject, score::uuid_t>
423 {
424  using type = score::uuid_t;
425  static void readFrom(JSONObject::Serializer& s, const type& obj);
426  static void writeTo(JSONObject::Deserializer& s, type& obj);
427 };
428 
429 template <typename U>
431 {
432  static void readFrom(JSONObject::Serializer& s, const UuidKey<U>& uid)
433  {
435  }
436 
437  static void writeTo(JSONObject::Deserializer& s, UuidKey<U>& uid)
438  {
440  }
441 };
442 
443 template <>
444 struct SCORE_LIB_BASE_EXPORT TSerializer<DataStream, score::uuid_t>
445 {
446  static void readFrom(DataStream::Serializer& s, const score::uuid_t& obj);
447  static void writeTo(DataStream::Deserializer& s, score::uuid_t& obj);
448 };
449 
450 template <typename U>
452 {
453  static void readFrom(DataStream::Serializer& s, const UuidKey<U>& uid)
454  {
456  }
457 
458  static void writeTo(DataStream::Deserializer& s, UuidKey<U>& uid)
459  {
461  }
462 };
Definition: VisitorInterface.hpp:53
Definition: DataStreamVisitor.hpp:27
Definition: DataStreamVisitor.hpp:202
Definition: VisitorInterface.hpp:61
Definition: JSONVisitor.hpp:52
Definition: JSONVisitor.hpp:423
Definition: UuidKey.hpp:343
Base toolkit upon which the software is built.
Definition: Application.cpp:90
Definition: lv2_atom_helpers.hpp:99
Definition: VisitorInterface.hpp:13
Definition: UuidKey.hpp:214
Definition: UuidKey.hpp:24