From febb9c275b5247df596876e4eea7fa17b7ec45e7 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Wed, 22 Aug 2018 17:26:08 +0200 Subject: Add support for UUID generation --- libbutl/uuid.ixx | 291 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 291 insertions(+) create mode 100644 libbutl/uuid.ixx (limited to 'libbutl/uuid.ixx') 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 // mem*() +#include // 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 (t); t >>= 8; + r[2] = static_cast (t); t >>= 8; + r[1] = static_cast (t); t >>= 8; + r[0] = static_cast (t); + + t = time_mid; + r[5] = static_cast (t); t >>= 8; + r[4] = static_cast (t); + + t = time_hiv; + r[7] = static_cast (t); t >>= 8; + r[6] = static_cast (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 ((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:: + 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 d (u.binary ()); + + size_t h (static_cast (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 (16777619UL) + : (size_t) 1099511628211ULL; + } + + return h; + } +} -- cgit v1.1