235 lines
5.6 KiB
C++
235 lines
5.6 KiB
C++
#pragma once
|
|
|
|
#include <iostream>
|
|
#include <string>
|
|
#include <cstring>
|
|
#include <limits>
|
|
#include <random>
|
|
#include <chrono>
|
|
|
|
namespace tf {
|
|
|
|
// Class: UUID
|
|
//
|
|
// A universally unique identifier (UUID) is an identifier standard used in software
|
|
// construction. A UUID is simply a 128-bit value. The meaning of each bit is defined
|
|
// by any of several variants.
|
|
// For human-readable display, many systems use a canonical format using hexadecimal
|
|
// text with inserted hyphen characters.
|
|
//
|
|
// For example: 123e4567-e89b-12d3-a456-426655440000
|
|
//
|
|
// The intent of UUIDs is to enable distributed systems to uniquely identify information
|
|
// without significant central coordination.
|
|
//
|
|
// Copyright 2006 Andy Tompkins.
|
|
// Distributed under the Boost Software License, Version 1.0. (See
|
|
// accompanying file LICENSE_1_0.txt or copy at
|
|
// http://www.boost.org/LICENSE_1_0.txt)
|
|
//
|
|
struct UUID {
|
|
|
|
using value_type = uint8_t;
|
|
using reference = uint8_t&;
|
|
using const_reference = const uint8_t&;
|
|
using iterator = uint8_t*;
|
|
using const_iterator = const uint8_t*;
|
|
using size_type = size_t;
|
|
using difference_type = ptrdiff_t;
|
|
|
|
inline UUID();
|
|
|
|
UUID(const UUID&) = default;
|
|
UUID(UUID&&) = default;
|
|
|
|
UUID& operator = (const UUID&) = default;
|
|
UUID& operator = (UUID&&) = default;
|
|
|
|
inline static size_type size();
|
|
inline iterator begin();
|
|
inline const_iterator begin() const;
|
|
inline iterator end();
|
|
inline const_iterator end() const;
|
|
|
|
inline bool is_nil() const;
|
|
inline void swap(UUID& rhs);
|
|
inline size_t hash_value() const;
|
|
|
|
inline bool operator == (const UUID&) const;
|
|
inline bool operator < (const UUID&) const;
|
|
inline bool operator > (const UUID&) const;
|
|
inline bool operator != (const UUID&) const;
|
|
inline bool operator >= (const UUID&) const;
|
|
inline bool operator <= (const UUID&) const;
|
|
|
|
uint8_t data[16] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
|
|
|
inline std::string to_string() const;
|
|
};
|
|
|
|
// Constructor
|
|
inline UUID::UUID() {
|
|
|
|
static thread_local std::default_random_engine engine {
|
|
std::random_device{}()
|
|
};
|
|
|
|
std::uniform_int_distribution<unsigned long> distribution(
|
|
(std::numeric_limits<unsigned long>::min)(),
|
|
(std::numeric_limits<unsigned long>::max)()
|
|
);
|
|
|
|
int i = 0;
|
|
auto random_value = distribution(engine);
|
|
for (auto it=begin(); it!=end(); ++it, ++i) {
|
|
if (i == sizeof(unsigned long)) {
|
|
random_value = distribution(engine);
|
|
i = 0;
|
|
}
|
|
*it = static_cast<UUID::value_type>((random_value >> (i*8)) & 0xFF);
|
|
}
|
|
|
|
// set variant: must be 0b10xxxxxx
|
|
*(begin()+8) &= 0xBF;
|
|
*(begin()+8) |= 0x80;
|
|
|
|
// set version: must be 0b0100xxxx
|
|
*(begin()+6) &= 0x4F; //0b01001111
|
|
*(begin()+6) |= 0x40; //0b01000000
|
|
}
|
|
|
|
// Function: size
|
|
inline typename UUID::size_type UUID::size() {
|
|
return 16;
|
|
}
|
|
|
|
// Function: begin
|
|
inline typename UUID::iterator UUID::begin() {
|
|
return data;
|
|
}
|
|
|
|
// Function: begin
|
|
inline typename UUID::const_iterator UUID::begin() const {
|
|
return data;
|
|
}
|
|
|
|
// Function: end
|
|
inline typename UUID::iterator UUID::end() {
|
|
return data+size();
|
|
}
|
|
|
|
// Function: end
|
|
inline typename UUID::const_iterator UUID::end() const {
|
|
return data+size();
|
|
}
|
|
|
|
// Function: is_nil
|
|
inline bool UUID::is_nil() const {
|
|
for (std::size_t i = 0; i < sizeof(this->data); ++i) {
|
|
if (this->data[i] != 0U) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// Procedure: swap
|
|
inline void UUID::swap(UUID& rhs) {
|
|
UUID tmp = *this;
|
|
*this = rhs;
|
|
rhs = tmp;
|
|
}
|
|
|
|
// Function: hash_value
|
|
inline size_t UUID::hash_value() const {
|
|
size_t seed = 0;
|
|
for(auto i=begin(); i != end(); ++i) {
|
|
seed ^= static_cast<size_t>(*i) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
|
|
}
|
|
return seed;
|
|
}
|
|
|
|
// Operator: ==
|
|
inline bool UUID::operator == (const UUID& rhs) const {
|
|
return std::memcmp(data, rhs.data, sizeof(data)) == 0;
|
|
}
|
|
|
|
// Operator: !=
|
|
inline bool UUID::operator != (const UUID& rhs) const {
|
|
return std::memcmp(data, rhs.data, sizeof(data)) != 0;
|
|
}
|
|
|
|
// Operator: <
|
|
inline bool UUID::operator < (const UUID& rhs) const {
|
|
return std::memcmp(data, rhs.data, sizeof(data)) < 0;
|
|
}
|
|
|
|
// Operator: >
|
|
inline bool UUID::operator > (const UUID& rhs) const {
|
|
return std::memcmp(data, rhs.data, sizeof(data)) > 0;
|
|
}
|
|
|
|
// Operator: <=
|
|
inline bool UUID::operator <= (const UUID& rhs) const {
|
|
return std::memcmp(data, rhs.data, sizeof(data)) <= 0;
|
|
}
|
|
|
|
// Operator: >=
|
|
inline bool UUID::operator >= (const UUID& rhs) const {
|
|
return std::memcmp(data, rhs.data, sizeof(data)) >= 0;
|
|
}
|
|
|
|
// Function: to_string
|
|
inline std::string UUID::to_string() const {
|
|
|
|
auto to_char = [](size_t i) {
|
|
if (i <= 9) return static_cast<char>('0' + i);
|
|
return static_cast<char>('a' + (i-10));
|
|
};
|
|
|
|
std::string result;
|
|
result.reserve(36);
|
|
|
|
std::size_t i=0;
|
|
for (auto it = begin(); it!=end(); ++it, ++i) {
|
|
|
|
const size_t hi = ((*it) >> 4) & 0x0F;
|
|
result += to_char(hi);
|
|
|
|
const size_t lo = (*it) & 0x0F;
|
|
result += to_char(lo);
|
|
|
|
if (i == 3 || i == 5 || i == 7 || i == 9) {
|
|
result += '-';
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
// Procedure: swap
|
|
inline void swap(UUID& lhs, UUID& rhs) {
|
|
lhs.swap(rhs);
|
|
}
|
|
|
|
// ostream
|
|
inline std::ostream& operator << (std::ostream& os, const UUID& rhs) {
|
|
os << rhs.to_string();
|
|
return os;
|
|
}
|
|
|
|
} // End of namespace tf. ----------------------------------------------------
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
namespace std {
|
|
|
|
// Partial specialization: hash<tf::UUID>
|
|
template <>
|
|
struct hash<tf::UUID> {
|
|
size_t operator()(const tf::UUID& rhs) const { return rhs.hash_value(); }
|
|
};
|
|
|
|
|
|
} // End of namespace std. ---------------------------------------------------
|
|
|
|
|