119 lines
2.8 KiB
C++
119 lines
2.8 KiB
C++
#include <cpputils/datetime.h>
|
|
#include <cpputils/uuid.h>
|
|
#include <cstddef>
|
|
#include <cstdint>
|
|
#include <cstdio>
|
|
#include <string>
|
|
|
|
using cpputils::uuid::V4;
|
|
using cpputils::uuid::V7;
|
|
|
|
std::string cpputils::uuid::uuidToString(
|
|
std::array<uint8_t, 16> const& uuid) noexcept {
|
|
static constexpr char hex[] = "0123456789abcdef";
|
|
|
|
std::string out(36, '\0');
|
|
size_t p = 0;
|
|
|
|
auto w = [&](size_t i) {
|
|
uint8_t b = uuid[i];
|
|
out[p++] = hex[b >> 4];
|
|
out[p++] = hex[b & 0xF];
|
|
};
|
|
|
|
w(0);
|
|
w(1);
|
|
w(2);
|
|
w(3);
|
|
out[p++] = '-';
|
|
w(4);
|
|
w(5);
|
|
out[p++] = '-';
|
|
w(6);
|
|
w(7);
|
|
out[p++] = '-';
|
|
w(8);
|
|
w(9);
|
|
out[p++] = '-';
|
|
w(10);
|
|
w(11);
|
|
w(12);
|
|
w(13);
|
|
w(14);
|
|
w(15);
|
|
|
|
return out;
|
|
}
|
|
|
|
std::array<uint8_t, 16> V4::generate() {
|
|
std::array<uint8_t, 16> uuid{};
|
|
uint64_t rand_a = random64();
|
|
uint64_t rand_b = random64();
|
|
uint64_t rand_c = random64();
|
|
// First 48 bits
|
|
uuid[0] = (rand_a >> 40) & 0xFF; // 0-7
|
|
uuid[1] = (rand_a >> 32) & 0xFF; // 8-15
|
|
uuid[2] = (rand_a >> 24) & 0xFF; // 16-23
|
|
uuid[3] = (rand_a >> 16) & 0xFF; // 24-31
|
|
uuid[4] = (rand_a >> 8) & 0xFF; // 32-39
|
|
uuid[5] = rand_a & 0xFF; // 40-47
|
|
|
|
uuid[6] = (rand_b) & 0x0F; // fill lower 4 bits with random
|
|
uuid[6] |= 0x40; // set top 4 bits to 0100
|
|
uuid[7] = (rand_b >> 8) & 0xFF;
|
|
|
|
uuid[8] = (rand_b >> 16) & 0xFF;
|
|
uuid[8] |= (0b10 << 6);
|
|
|
|
uuid[9] = (rand_c) & 0xFF;
|
|
uuid[10] = (rand_c >> 8) & 0xFF;
|
|
uuid[11] = (rand_c >> 16) & 0xFF;
|
|
uuid[12] = (rand_c >> 24) & 0xFF;
|
|
uuid[13] = (rand_c >> 32) & 0xFF;
|
|
uuid[14] = (rand_c >> 40) & 0xFF;
|
|
uuid[15] = (rand_c >> 48) & 0xFF;
|
|
|
|
return uuid;
|
|
}
|
|
|
|
uint8_t V7::next_sequence(int64_t current_timestamp) {
|
|
uint64_t prev_timestamp = last_timestamp.load(std::memory_order_relaxed);
|
|
|
|
if (current_timestamp > prev_timestamp) {
|
|
last_timestamp.store(current_timestamp, std::memory_order_relaxed);
|
|
sequence.store(0, std::memory_order_relaxed);
|
|
return 0;
|
|
} else {
|
|
return sequence.fetch_add(1, std::memory_order_relaxed) & 0xFF;
|
|
}
|
|
}
|
|
|
|
std::array<uint8_t, 16> V7::generate(int64_t timestamp) {
|
|
std::array<uint8_t, 16> uuid{};
|
|
uint8_t seq = next_sequence(timestamp);
|
|
uint64_t rand_a = random64();
|
|
uint64_t rand_b = random64();
|
|
|
|
// Encode timestamp (big-endian)
|
|
uuid[0] = (timestamp >> 40) & 0xFF;
|
|
uuid[1] = (timestamp >> 32) & 0xFF;
|
|
uuid[2] = (timestamp >> 24) & 0xFF;
|
|
uuid[3] = (timestamp >> 16) & 0xFF;
|
|
uuid[4] = (timestamp >> 8) & 0xFF;
|
|
uuid[5] = timestamp & 0xFF;
|
|
|
|
// Version 7 (UUIDv7)
|
|
uuid[6] = ((timestamp >> 4) & 0x0F) | 0x70;
|
|
uuid[7] = ((timestamp << 4) & 0xF0) | ((seq >> 8) & 0x0F);
|
|
|
|
// Variant 1 (RFC 4122 standard)
|
|
uuid[8] = (seq & 0xFF) | 0x80;
|
|
|
|
// Fill remaining bytes with randomness
|
|
for (size_t i = 9; i < 16; i++) {
|
|
uuid[i] = (rand_b >> ((15 - i) * 8)) & 0xFF;
|
|
}
|
|
|
|
return uuid;
|
|
}
|