sandbox
Loading...
Searching...
No Matches
uuid.hpp
1#ifndef LIBSBX_MATH_UUID_HPP_
2#define LIBSBX_MATH_UUID_HPP_
3
4#if defined(SBX_MATH_UUID_USE_V4)
5
6#include <cinttypes>
7#include <exception>
8#include <charconv>
9
10#include <fmt/format.h>
11
12#include <range/v3/all.hpp>
13
15
16#include <libsbx/math/random.hpp>
17
18namespace sbx::math {
19
20struct invalid_uuid_exception : std::runtime_error {
21
22 invalid_uuid_exception(std::string_view uuid)
23 : std::runtime_error{fmt::format("String '{}' is not a valid uuid", uuid)} { }
24
25}; // struct invalid_uuid_exception
26
27class uuid {
28
29 friend struct fmt::formatter<sbx::math::uuid>;
30 friend struct std::hash<sbx::math::uuid>;
31
32 struct null_uui_tag { };
33
34public:
35
36 // static const uuid null;
37
38 using value_type = std::uint64_t;
39
40 uuid()
41 : _value{random::next<value_type>()} {
42 // Taken from https://www.cryptosys.net/pki/uuid-rfc4122.html
43
44 // // 1. Generate 16 random bytes (=128 bits)
45 // for (auto& byte : _bytes) {
46 // byte = random::next<std::uint8_t>();
47 // }
48
49 // 2. Adjust certain bits according to RFC 4122 section 4.4 as follows:
50 // (a) set the four most significant bits of the 7th byte to 0100'B, so the high nibble is "4"
51 // (b) set the two most significant bits of the 9th byte to 10'B, so the high nibble will be one of "8", "9", "A" or "B"
52 // _bytes[6] = 0x40 | (_bytes[6] & 0xf);
53 // _bytes[8] = 0x80 | (_bytes[8] & 0x3f);
54 }
55
56 // uuid(std::string_view string) {
57 // if (string.size() != 36u) {
58 // throw invalid_uuid_exception{string};
59 // }
60
61 // for (auto i = 0u, offset = 0u; i < _bytes.size(); ++i) {
62
63 // if (i == 4u || i == 6u || i == 8u || i == 10u) {
64 // ++offset;
65 // }
66
67 // auto substr = string.substr(i * 2u + offset, 2u);
68 // const auto [itr, error] = std::from_chars(substr.data(), substr.data() + 2u, _bytes[i], 16);
69
70 // if (error == std::errc::invalid_argument || error == std::errc::result_out_of_range) {
71 // throw invalid_uuid_exception{string};
72 // }
73 // }
74
75 // }
76
77 ~uuid() = default;
78
79 static auto null() -> uuid {
80 return uuid{null_uui_tag{}};
81 }
82
83 auto operator==(const uuid& other) const noexcept -> bool {
84 return _value == other._value;
85 }
86
87 // operator std::string() const {
88 // return fmt::format(
89 // "{:02x}{:02x}{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}",
90 // _bytes[0], _bytes[1], _bytes[2], _bytes[3], _bytes[4], _bytes[5], _bytes[6], _bytes[7],
91 // _bytes[8], _bytes[9], _bytes[10], _bytes[11], _bytes[12], _bytes[13], _bytes[14], _bytes[15]
92 // );
93 // }
94
95 operator value_type() const {
96 return _value;
97 }
98
99private:
100
101 uuid(null_uui_tag)
102 : _value{0} { }
103
104 // std::array<std::uint8_t, 16u> _bytes;
105 value_type _value;
106
107}; // class uuid
108
109} // namespace sbx::math
110
111template<>
112struct fmt::formatter<sbx::math::uuid> {
113
114 template<typename ParseContext>
115 constexpr auto parse(ParseContext& context) -> decltype(context.begin()) {
116 return context.begin();
117 }
118
119 template<typename FormatContext>
120 auto format(const sbx::math::uuid& uuid, FormatContext& context) -> decltype(context.out()) {
121 return fmt::format_to(context.out(), "{}", static_cast<sbx::math::uuid::value_type>(uuid));
122 }
123}; // struct fmt::formatter<sbx::math::uuid>
124
125// template<>
126// struct YAML::convert<sbx::math::uuid> {
127
128// static auto encode(const sbx::math::uuid& rhs) -> YAML::Node {
129// return Node{std::string{rhs}};
130// }
131
132// static auto decode(const YAML::Node& node, sbx::math::uuid& rhs) -> bool {
133// rhs = sbx::math::uuid{node.as<std::string>()};
134
135// return true;
136// }
137
138// }; // struct YAML::convert<sbx::math::uuid>
139
140template<>
141struct std::hash<sbx::math::uuid> {
142 auto operator()(const sbx::math::uuid& uuid) const noexcept -> std::size_t {
143 return static_cast<sbx::math::uuid::value_type>(uuid);
144 }
145}; // struct std::hash<sbx::math::uuid>
146
147#else // SBX_MATH_UUID_USE_V4
148
149#include <cinttypes>
150#include <concepts>
151
152#include <fmt/format.h>
153
154#include <libsbx/math/random.hpp>
155
156namespace sbx::math {
157
158template<std::unsigned_integral Type>
160
161 friend struct fmt::formatter<sbx::math::basic_uuid<Type>>;
162 friend struct std::hash<sbx::math::basic_uuid<Type>>;
163
164public:
165
166 using value_type = Type;
167
168 basic_uuid()
169 : _value{random::next<value_type>()} { }
170
171 static constexpr auto null() -> basic_uuid {
172 return basic_uuid{0u};
173 }
174
175 constexpr auto operator==(const basic_uuid& other) const noexcept -> bool {
176 return _value == other._value;
177 }
178
179 constexpr auto operator<(const basic_uuid& other) const noexcept -> bool {
180 return _value < other._value;
181 }
182
183 constexpr auto value() const noexcept -> value_type {
184 return _value;
185 }
186
187private:
188
189 basic_uuid(const value_type value)
190 : _value{value} { }
191
192 value_type _value;
193
194}; // class uuid
195
197
198} // namespace sbx::math
199
200template<std::unsigned_integral Type>
201struct fmt::formatter<sbx::math::basic_uuid<Type>> {
202
203 template<typename ParseContext>
204 constexpr auto parse(ParseContext& context) -> decltype(context.begin()) {
205 return context.begin();
206 }
207
208 template<typename FormatContext>
209 auto format(const sbx::math::basic_uuid<Type>& uuid, FormatContext& context) -> decltype(context.out()) {
210 return fmt::format_to(context.out(), "{}", uuid._value);
211 }
212}; // struct fmt::formatter<sbx::math::uuid>
213
214
215template<std::unsigned_integral Type>
216struct std::hash<sbx::math::basic_uuid<Type>> {
217 auto operator()(const sbx::math::basic_uuid<Type>& uuid) const noexcept -> std::size_t {
218 return uuid._value;
219 }
220}; // struct std::hash<sbx::math::uuid>
221
222#endif // SBX_MATH_UUID_USE_V4
223
224#endif // LIBSBX_MATH_UUID_HPP_
225
Definition: uuid.hpp:159