module; // Might as well since we're using OpenSSL #include #include export module routemon:trace; import std; import :util; namespace routemon::trace { class uuid7 { std::uint64_t high_ = 0; std::uint64_t low_ = 0; public: uuid7() { namespace chrono = std::chrono; auto const unix_time_ms_signed = static_cast(chrono::duration_cast(chrono::system_clock::now().time_since_epoch()).count()); if (unix_time_ms_signed < 0) throw std::runtime_error{"system time before UNIX epoch"}; auto const unix_time_ms = static_cast(unix_time_ms_signed); if (std::countl_zero(unix_time_ms) < 16) throw std::runtime_error{"system time too great"}; auto rand = std::array{}; int s = RAND_bytes(rand.data(), static_cast(rand.size())); if (s != 1) { unsigned long e = ERR_get_error(); throw std::runtime_error{std::format("failed to generate UUID(v7): {} ({}, code {})", ERR_reason_error_string(e), ERR_lib_error_string(e), e)}; } auto version = std::uint64_t{0b0111}; auto variant = std::uint64_t{0b10}; high_ |= unix_time_ms << 16; high_ |= version << 12; high_ |= std::uint64_t{rand[0]} << 4; high_ |= std::uint64_t{rand[1]}; low_ |= variant << 62; low_ |= std::uint64_t{rand[2]} << 54; low_ |= std::uint64_t{rand[3]} << 48; low_ |= std::uint64_t{rand[4]} << 40; low_ |= std::uint64_t{rand[5]} << 32; low_ |= std::uint64_t{rand[6]} << 24; low_ |= std::uint64_t{rand[7]} << 16; low_ |= std::uint64_t{rand[8]} << 8; low_ |= std::uint64_t{rand[9]}; } auto format(std::array& target) -> void { auto high_high = (high_ & 0xffff'ffff'0000'0000) >> 32; auto high_low_high = (high_ & 0x0000'0000'ffff'0000) >> 16; auto low_low_high = (high_ & 0x0000'0000'0000'ffff) >> 0; auto high_low = (low_ & 0xffff'0000'0000'0000) >> 48; auto low_low = (low_ & 0x0000'ffff'ffff'ffff) >> 0; std::format_to(target.begin(), "{:0>8x}-{:0>4x}-{:0>4x}-{:0>4x}-{:0>12x}", high_high, high_low_high, low_low_high, high_low, low_low); target.back() = '\0'; } }; export class id { std::array chars_; public: id() { uuid7{}.format(chars_); } auto as_string() const -> util::zstring_view { return util::zstring_view{chars_.data(), chars_.size() - 1}; } }; } // namespace routemon::trace