1
0
Fork 0

can create Timestamp UUIDs

This commit is contained in:
Kevin Matz 2021-08-02 16:29:18 -04:00
parent c01cd08b86
commit af8dcc92aa
2 changed files with 99 additions and 48 deletions

View File

@ -24,6 +24,7 @@
#include "uuid.h"
#include <algorithm>
#include <chrono>
#include <cstdlib>
#include <sstream>
#include <iomanip>
@ -42,7 +43,7 @@ uuid::uuid()
timestamp_ = 0;
clock_seq_ = 0;
node_ = 0;
setBytes();
setBytes_();
}
@ -58,7 +59,7 @@ uuid::uuid(const uuid& other)
timestamp_ = other.timestamp_;
clock_seq_ = other.clock_seq_;
node_ = other.node_;
setBytes();
setBytes_();
}
@ -77,9 +78,9 @@ uuid::~uuid()
*
* create this UUID from a byte array
*/
void uuid::fromArray(const uint8_t * bytes) {
void uuid::fromArray_(const uint8_t * bytes) {
std::memcpy(raw_, bytes, 16);
setFields();
setFields_();
}
@ -89,8 +90,8 @@ void uuid::fromArray(const uint8_t * bytes) {
*
* create this UUID from a C style char array
*/
void uuid::fromCstring(const char * cstr) {
fromString(std::string(cstr));
void uuid::fromCstring_(const char * cstr) {
fromString_(std::string(cstr));
}
@ -100,7 +101,7 @@ void uuid::fromCstring(const char * cstr) {
*
* create this UUID from a string representation
*/
void uuid::fromString(std::string str) {
void uuid::fromString_(std::string str) {
// remove formating
if (str.front() == '{' && str.back() == '}')
str = str.substr(1, str.size() - 2);
@ -111,7 +112,7 @@ void uuid::fromString(std::string str) {
for (unsigned int i = 0; i < sizeof(buf); i++)
buf[i] = std::strtoul(str.substr((i*2), 2).c_str(), NULL, 16);
// process buffer
fromArray(buf);
fromArray_(buf);
};
@ -162,17 +163,17 @@ std::string uuid::urn() const {
* @brief uuid::setBytes
* make the raw bytes match the field contents
*/
void uuid::setBytes()
void uuid::setBytes_()
{
switch (type_) {
case NIL:
std::memset(raw_, 0, 16);
break;
case NCS:
setNCSBytes();
setNCSBytes_();
break;
case RFC4122:
setRFC4122Bytes();
setRFC4122Bytes_();
break;
case MS:
break;
@ -185,7 +186,7 @@ void uuid::setBytes()
/**
* @brief uuid::setNCSBytes
*/
void uuid::setNCSBytes()
void uuid::setNCSBytes_()
{
NCSFields fields;
fields.time = timestamp_;
@ -201,7 +202,7 @@ void uuid::setNCSBytes()
* @brief uuid::setRFC4122Bytes
* TODO: Check endianness
*/
void uuid::setRFC4122Bytes()
void uuid::setRFC4122Bytes_()
{
RFC4122Fields fields;
fields.time_low = timestamp_;
@ -226,15 +227,15 @@ void uuid::setRFC4122Bytes()
/**
* @brief uuid::setFields
*/
void uuid::setFields()
void uuid::setFields_()
{
setType();
setType_();
switch (type_) {
case NCS:
setNCSFields();
setNCSFields_();
break;
case RFC4122:
setRFC4122Fields();
setRFC4122Fields_();
break;
default:
break;
@ -245,7 +246,7 @@ void uuid::setFields()
/**
* @brief uuid::setNCSFields
*/
void uuid::setNCSFields()
void uuid::setNCSFields_()
{
NCSFields fields;
std::memcpy(&fields, raw_, 16);
@ -259,7 +260,7 @@ void uuid::setNCSFields()
/**
* @brief uuid::setRFC4122Fields
*/
void uuid::setRFC4122Fields()
void uuid::setRFC4122Fields_()
{
RFC4122Fields fields;
std::memcpy(&fields, raw_, 16);
@ -301,7 +302,7 @@ void uuid::setRFC4122Fields()
*
* exctract the type from the raw bytes
*/
void uuid::setType() {
void uuid::setType_() {
if ((raw_[8] >> 7) == 0b0) {
type_ = NCS;
} else if ((raw_[8] >> 6) == 0b10) {
@ -323,7 +324,7 @@ uuid& uuid::operator=(const uuid& other)
{
if (this != &other) { // protect against invalid self-assignment
std::memcpy(raw_, other.raw_, 16);
setFields();
setFields_();
}
return *this;
}
@ -343,6 +344,27 @@ bool operator== (const uuid& a, const uuid& b)
}
/**
* @brief uuid::uuid1
* @param node
* @param clock_seq
* @return incrimented clock_sequence
*
* node ID and clock sequence tracking are the responsibility of the caller
*/
uint16_t uuid::uuid1(uint64_t node, uint16_t clock_seq)
{
type_ = RFC4122;
version_ = TIME;
timestamp_ = now_();
clock_seq_ = clock_seq + 1;
node_ = node;
setBytes_();
return clock_seq_;
}
/**
* @brief uuid::uuid4
*
@ -357,7 +379,26 @@ void uuid::uuid4() {
clock_seq_ = std::rand();
node_ = std::rand();
node_ |= (uint64_t)std::rand() << 32;
setBytes();
setBytes_();
}
/**
* @brief uuid::time_ 4.1.4. Timestamp
* @return
*
* The timestamp is a 60-bit value. For UUID version 1, this is represented
* by Coordinated Universal Time (UTC) as a count of 100-nanosecond intervals
* since 00:00:00.00, 15 October 1582 (the date of Gregorian reform to the
* Christian calendar).
*/
uint64_t uuid::now_()
{
auto now = std::chrono::high_resolution_clock::now();
std::chrono::duration<uint64_t, std::nano> since = now.time_since_epoch();
uint64_t periods = since.count() / 100;
periods += UUID_TICKS_BETWEEK_EPOCH;
return periods;
}
// const std::string NAMESPACE_DNS = "6ba7b810-9dad-11d1-80b4-00c04fd430c8";

View File

@ -91,6 +91,14 @@ struct RFC4122Fields {
}__attribute__((packed));
/**
* @brief UUID_TICKS_BETWEEK_EPOCH
* The number of 100 ns ticks between the Gregorian epoch `1582-10-15 00:00:00`
* and the Unix epoch `1970-01-01 00:00:00`.
*/
static const uint64_t UUID_TICKS_BETWEEK_EPOCH = 122192928000000000;
// extern const std::string NAMESPACE_DNS;
// extern const std::string NAMESPACE_URL;
// extern const std::string NAMESPACE_OID;
@ -103,27 +111,19 @@ struct RFC4122Fields {
class uuid {
public:
uuid();
uuid(const uuid& other);
uuid(const uint8_t * raw) : uuid() { fromArray(raw); };
uuid(const char * cstr) : uuid() { fromCstring(cstr); };
uuid(std::string str) : uuid() { fromString(str); };
uuid(const uuid&);
uuid(const uint8_t * raw) : uuid() { fromArray_(raw); };
uuid(const char * c_str) : uuid() { fromCstring_(c_str); };
uuid(std::string str) : uuid() { fromString_(str); };
~uuid();
// accessors
const uint8_t * bytes() const { return raw_; };
Type type() const { return type_; };
uint16_t version() const { return version_; };
uint64_t time() const { return timestamp_; };
uint16_t sequence() const { return clock_seq_; };
uint64_t node() const { return node_; };
const uint8_t* bytes() const { return raw_; };
// operator overloads
uuid& operator= (const uuid& other);
friend bool operator== (const uuid& a, const uuid& b);
// typecast overload
operator const uint8_t* () const { return raw_; };
operator const std::string () const { return string(); };
// output
std::string hex() const; // '12345678123456781234567812345678'
@ -131,11 +131,19 @@ public:
std::string urn() const; // 'urn:uuid:12345678-1234-5678-1234-567812345678'
// creators
// virtual void uuid1(uint64_t node, uint16_t clock_seq) {};
virtual uint16_t uuid1(uint64_t node, uint16_t clock_seq);
// virtual void uuid3(Namespace, std::string) {};
virtual void uuid4(); // very low quality of random
virtual void uuid4(); // very low quality of random
// virtual void uuid5(Namespace, std::string) {};
// operator overloads
uuid& operator= (const uuid& other);
friend bool operator== (const uuid&, const uuid&);
// typecast overload
operator const uint8_t * () const { return raw_; };
operator const std::string () const { return string(); };
private:
uint8_t* raw_;
Type type_;
@ -144,18 +152,20 @@ private:
uint16_t clock_seq_;
uint64_t node_;
void fromArray(const uint8_t *);
void fromCstring(const char *);
void fromString(std::string);
void fromArray_(const uint8_t *);
void fromCstring_(const char *);
void fromString_(std::string);
void setType();
void setBytes();
void setNCSBytes();
void setRFC4122Bytes();
void setType_();
void setBytes_();
void setNCSBytes_();
void setRFC4122Bytes_();
void setFields();
void setNCSFields();
void setRFC4122Fields();
void setFields_();
void setNCSFields_();
void setRFC4122Fields_();
uint64_t now_();
};
} // namespace UUID
@ -176,7 +186,7 @@ namespace std
*/
size_t operator()(UUID::uuid const& id) const noexcept
{
return hash<string>{}(id.hex());
return std::hash<std::string>{}(id.hex());
}
};
} // namespace std