summaryrefslogtreecommitdiffstats
path: root/server/src/trace.cpp
blob: f2935a9c4057a8aa4702ea10cf770a94c230c7a8 (about) (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
module;

// Might as well since we're using OpenSSL
#include <openssl/err.h>
#include <openssl/rand.h>

module routemon:trace$impl;

import :trace;

namespace routemon::trace {

class psrng
{
  mutable std::default_random_engine e_ = {};
  mutable std::uniform_int_distribution<std::uint64_t> distr_ = {};
  mutable std::mutex mut_ = {};

public:
  auto next() const -> std::uint64_t
  {
    auto lock = std::lock_guard{mut_};
    return distr_(e_);
  }

  static auto instance() -> psrng const&
  {
    static auto const inst = psrng{};
    return inst;
  }
};

uuid7::uuid7()
{
  namespace chrono = std::chrono;
  auto const unix_time_ms_signed = static_cast<std::int64_t>(
      chrono::duration_cast<chrono::milliseconds>(
          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<std::uint64_t>(unix_time_ms_signed);
  if (std::countl_zero(unix_time_ms) < 16)
    throw std::runtime_error{"system time too great"};

  auto const& rng = psrng::instance();
  auto const rand1 = rng.next();
  auto const rand2 = rng.next();

  auto version = std::uint64_t{0b0111};
  auto variant = std::uint64_t{0b10};

  hi_ = unix_time_ms << 16;
  hi_ |= version << 12;
  hi_ |= rand1 & 0x0000'0000'0000'0fff;
  lo_ = variant << 62;
  lo_ |= rand2 >> 2;
}

auto uuid7::format(std::span<char, 37> target) -> void
{
  auto hexnibs =
      []<std::size_t n>(std::uint64_t v, std::span<char, n> s) -> void
  {
    for (auto i = 0uz; i < n; i++)
    {
      static char const hextab[16] = {
        '0', '1', '2', '3', '4', '5', '6', '7',
        '8', '9', 'a', 'b', 'c', 'd', 'e', 'f',
      };
      s[i] = hextab[(v >> 4 * (n - 1 - i)) & 0xf];
    }
  };

  auto p____hi_hi = (hi_ & 0xffff'ffff'0000'0000) >> 32;
  auto p_hi_lo_hi = (hi_ & 0x0000'0000'ffff'0000) >> 16;
  auto p_lo_lo_hi = (hi_ & 0x0000'0000'0000'ffff) >> 0;
  auto p____hi_lo = (lo_ & 0xffff'0000'0000'0000) >> 48;
  auto p____lo_lo = (lo_ & 0x0000'ffff'ffff'ffff) >> 0;

  hexnibs(p____hi_hi, target.subspan<0, 8>());
  target[8] = '-';
  hexnibs(p_hi_lo_hi, target.subspan<9, 4>());
  target[13] = '-';
  hexnibs(p_lo_lo_hi, target.subspan<14, 4>());
  target[18] = '-';
  hexnibs(p____hi_lo, target.subspan<19, 4>());
  target[23] = '-';
  hexnibs(p____lo_lo, target.subspan<24, 12>());
  target[36] = '\0';
}

id::id() { uuid7{}.format(chars_); }

auto id::as_string() const -> util::zstring_view
{
  return util::zstring_view{chars_.data(), chars_.size() - 1};
}

} // namespace routemon::trace