aboutsummaryrefslogtreecommitdiff
path: root/libbutl/uuid.ixx
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2018-08-22 17:26:08 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2018-08-22 17:36:23 +0200
commitfebb9c275b5247df596876e4eea7fa17b7ec45e7 (patch)
tree214a192cc6b019fb25a659cfdb84601da74438bf /libbutl/uuid.ixx
parentf8fc81a5c9fcd986473797df9286c6c9fef683bf (diff)
Add support for UUID generation
Diffstat (limited to 'libbutl/uuid.ixx')
-rw-r--r--libbutl/uuid.ixx291
1 files changed, 291 insertions, 0 deletions
diff --git a/libbutl/uuid.ixx b/libbutl/uuid.ixx
new file mode 100644
index 0000000..0208221
--- /dev/null
+++ b/libbutl/uuid.ixx
@@ -0,0 +1,291 @@
+// file : libbutl/uuid.ixx -*- C++ -*-
+// copyright : Copyright (c) 2014-2018 Code Synthesis Ltd
+// license : MIT; see accompanying LICENSE file
+
+#include <cstring> // mem*()
+#include <utility> // swap()
+
+namespace butl
+{
+ // NOTE: the order of definitions is important to MinGW GCC (DLL linkage).
+
+ inline uuid::
+ uuid ()
+ : time_low (0), time_mid (0), time_hiv (0),
+ clock_seq_hir (0), clock_seq_low (0),
+ node {0, 0, 0, 0, 0, 0}
+ {
+ }
+
+ inline bool uuid::
+ nil () const
+ {
+ return
+ time_low == 0 &&
+ time_mid == 0 &&
+ time_hiv == 0 &&
+ clock_seq_hir == 0 &&
+ clock_seq_low == 0 &&
+ node[0] == 0 && node[1] == 0 && node[2] == 0 &&
+ node[3] == 0 && node[4] == 0 && node[5] == 0;
+ }
+
+ inline uuid::
+ operator bool () const
+ {
+ return !nil ();
+ }
+
+ inline void uuid::
+ swap (uuid& u)
+ {
+ std::swap (time_low, u.time_low);
+ std::swap (time_mid, u.time_mid);
+ std::swap (time_hiv, u.time_hiv);
+ std::swap (clock_seq_hir, u.clock_seq_hir);
+ std::swap (clock_seq_low, u.clock_seq_low);
+ std::swap (node, u.node);
+ }
+
+ inline uuid::
+ uuid (uuid&& u)
+ : uuid () // nil
+ {
+ swap (u);
+ }
+
+ inline uuid& uuid::
+ operator= (uuid&& u)
+ {
+ if (this != &u)
+ {
+ uuid n; // nil
+ swap (n);
+ swap (u);
+ }
+ return *this;
+ }
+
+ inline void
+ uuid_assign_impl (uuid& r, const std::uint8_t* p)
+ {
+ {
+ std::uint32_t t;
+
+ t = *p++;
+ t = (t << 8) | *p++;
+ t = (t << 8) | *p++;
+ t = (t << 8) | *p++;
+ r.time_low = t;
+ }
+
+ std::uint16_t t;
+
+ t = *p++;
+ t = (t << 8) | *p++;
+ r.time_mid = t;
+
+ t = *p++;
+ t = (t << 8) | *p++;
+ r.time_hiv = t;
+
+ r.clock_seq_hir = *p++;
+ r.clock_seq_low = *p++;
+
+ std::memcpy (r.node, p, 6);
+ }
+
+ inline void uuid::
+ assign (const binary_type& d)
+ {
+ uuid_assign_impl (*this, d.data ());
+ }
+
+ inline uuid::
+ uuid (const binary_type& d)
+ {
+ assign (d);
+ }
+
+ inline uuid::binary_type uuid::
+ binary () const noexcept
+ {
+ using u8 = std::uint8_t;
+
+ binary_type r;
+ std::uint32_t t;
+
+ t = time_low;
+ r[3] = static_cast<u8> (t); t >>= 8;
+ r[2] = static_cast<u8> (t); t >>= 8;
+ r[1] = static_cast<u8> (t); t >>= 8;
+ r[0] = static_cast<u8> (t);
+
+ t = time_mid;
+ r[5] = static_cast<u8> (t); t >>= 8;
+ r[4] = static_cast<u8> (t);
+
+ t = time_hiv;
+ r[7] = static_cast<u8> (t); t >>= 8;
+ r[6] = static_cast<u8> (t);
+
+ r[9] = clock_seq_low;
+ r[8] = clock_seq_hir;
+
+ std::memcpy(r.data () + 10, node, 6);
+
+ return r;
+ }
+
+ inline void uuid::
+ assign (const std::uint8_t (&d)[16])
+ {
+ uuid_assign_impl (*this, d);
+ }
+
+ inline uuid::
+ uuid (const std::uint8_t (&d)[16])
+ {
+ assign (d);
+ }
+
+#ifdef _WIN32
+ inline uuid::
+ uuid (const _GUID& g)
+ {
+ assign (g);
+ }
+#endif
+
+ inline void uuid::
+ assign (const std::string& s)
+ {
+ assign (s.c_str ());
+ }
+
+ inline uuid::
+ uuid (const std::string& s)
+ {
+ assign (s);
+ }
+
+ inline uuid::
+ uuid (const char* s)
+ {
+ assign (s);
+ }
+
+ inline std::string uuid::
+ string (bool upper) const
+ {
+ return c_string (upper).data ();
+ }
+
+ inline uuid::variant_type uuid::
+ variant () const
+ {
+ return nil ()
+ ? variant_type::dce
+ : ((clock_seq_hir & 0x80) == 0 ? variant_type::ncs :
+ (clock_seq_hir & 0x40) == 0 ? variant_type::dce :
+ (clock_seq_hir & 0x20) == 0 ? variant_type::microsoft :
+ /* */ variant_type::other);
+ }
+
+ inline uuid::version_type uuid::
+ version () const
+ {
+ return nil ()
+ ? version_type::random
+ : static_cast<version_type> ((time_hiv >> 12) & 0x0f);
+ }
+
+ inline int uuid::
+ compare (const uuid& y) const
+ {
+ int r;
+ auto neq = [&r] (auto a, auto b) -> bool
+ {
+ return (r = (a == b ? 0 : (a < b ? -1 : 1))) != 0;
+ };
+
+ return (neq (time_low, y.time_low) ? r :
+ neq (time_mid, y.time_mid) ? r :
+ neq (time_hiv, y.time_hiv) ? r :
+ neq (clock_seq_hir, y.clock_seq_hir) ? r :
+ neq (clock_seq_low, y.clock_seq_low) ? r :
+ std::memcmp (node, y.node, 6));
+ }
+
+ inline bool
+ operator== (const uuid& x, const uuid& y)
+ {
+ return x.compare (y) == 0;
+ }
+
+ inline bool
+ operator!= (const uuid& x, const uuid& y)
+ {
+ return x.compare (y) != 0;
+ }
+
+ inline bool
+ operator< (const uuid& x, const uuid& y)
+ {
+ return x.compare (y) < 0;
+ }
+
+ inline bool
+ operator> (const uuid& x, const uuid& y)
+ {
+ return x.compare (y) > 0;
+ }
+
+ inline bool
+ operator<= (const uuid& x, const uuid& y)
+ {
+ return x.compare (y) <= 0;
+ }
+
+ inline bool
+ operator>= (const uuid& x, const uuid& y)
+ {
+ return x.compare (y) >= 0;
+ }
+
+ inline uuid uuid::
+ generate (bool strong)
+ {
+ return system_generator.generate (strong);
+ }
+}
+
+namespace std
+{
+ inline size_t hash<butl::uuid>::
+ operator() (const butl::uuid& u) const noexcept
+ {
+ // To make sure hashes for the same UUID are the same on the same-width
+ // platforms we FNV-hash the portable binary prepresentation.
+ //
+ // Let's keep the implementation inline hoping the compiler will unroll
+ // the loop for us.
+ //
+ array<uint8_t, 16> d (u.binary ());
+
+ size_t h (static_cast<size_t> (2166136261UL));
+ for (uint8_t b: d)
+ {
+ h ^= b;
+
+ // We are using the C-style cast to suppress VC warnings for 32-bit
+ // targets (the value is compiled but not used).
+ //
+ h *= sizeof (size_t) == 4
+ ? static_cast<size_t> (16777619UL)
+ : (size_t) 1099511628211ULL;
+ }
+
+ return h;
+ }
+}