// file : libbutl/uuid.ixx -*- C++ -*- // copyright : Copyright (c) 2014-2019 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 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; } }