di 0.1.0
Loading...
Searching...
No Matches
uuid.h
Go to the documentation of this file.
1#pragma once
2
4#include "di/format/prelude.h"
5#include "di/parser/prelude.h"
7#include "di/random/prelude.h"
8#include "di/types/prelude.h"
9#include "di/util/bit_cast.h"
12
13namespace di::util {
14namespace detail {
15 struct GenerateUUIDFunction;
16}
17
18class UUID {
19private:
20 using ByteArray = di::Array<di::Byte, 16>;
21
22 enum class Variant : u8 {
23 LittleEndian = 0b110,
24 };
25
26 enum class Version : u8 {
27 Time = 0b0001,
28 DCESecurity = 0b0010,
29 NameMD5 = 0b0011,
30 Random = 0b0100,
31 NameSHA1 = 0b0101,
32 };
33
34public:
35 using IsAtom = void;
36
37 UUID() = default;
38
39 constexpr explicit UUID(ByteArray bytes) { *this = util::bit_cast<UUID>(bytes); }
40
41 constexpr auto null() const -> bool { return *this == UUID(); }
42 constexpr void clear() { *this = UUID(); }
43
44private:
45 friend struct detail::GenerateUUIDFunction;
46
47 constexpr friend auto operator==(UUID a, UUID b) -> bool {
48 return util::bit_cast<ByteArray>(a) == util::bit_cast<ByteArray>(b);
49 }
50 constexpr friend auto operator<=>(UUID a, UUID b) -> strong_ordering {
51 return util::bit_cast<ByteArray>(a) <=> util::bit_cast<ByteArray>(b);
52 }
53
54 constexpr auto variant() const -> Variant { return Variant(m_clock_seq_hi_and_res >> 5); }
55 constexpr auto version() const -> Version { return Version(m_time_hi_and_version >> 4); }
56
57 constexpr void set_to_standard_variant() {
58 m_clock_seq_hi_and_res &= 0b11000000;
59 m_clock_seq_hi_and_res |= 0b10000000;
60 }
61
62 constexpr void set_version(Version type) {
63 m_time_hi_and_version &= 0b00001111;
64 m_time_hi_and_version |= util::to_underlying(type) << 4;
65 }
66
67 constexpr auto is_little_endian() const -> bool { return variant() == Variant::LittleEndian; }
68
69 template<concepts::Encoding Enc>
71 FormatParseContext<Enc>& parse_context, bool debug) {
73 [](concepts::CopyConstructible auto formatter) {
74 return [=](concepts::FormatContext auto& context, UUID uuid) {
75#if DI_GCC
76#pragma GCC diagnostic push
77#pragma GCC diagnostic ignored "-Wstringop-overflow"
78#endif
79 auto buffer = di::Array<char, 36> {};
80 usize index = 0;
81
82 auto output_digit = [&](u8 digit) {
83 if (digit >= 10) {
84 buffer[index++] = char(digit - 10 + 'a');
85 } else {
86 buffer[index++] = char(digit + '0');
87 }
88 };
89
90 auto output_byte = [&](auto byte) {
91 output_digit(byte >> 4);
92 output_digit(byte & 0xF);
93 };
94
95 auto output = [&](auto value, auto bytes) {
96 u64 mask = 0xFF << 8 * (bytes - 1);
97 for (; bytes > 0; bytes--) {
98 u8 byte = (value & mask) >> 8 * (bytes - 1);
99 mask >>= 8;
100
101 output_byte(byte);
102 }
103 };
104
105 if (uuid.is_little_endian()) {
106 output(little_endian_to_host(uuid.m_time_low), 4);
107 } else {
108 output(big_endian_to_host(uuid.m_time_low), 4);
109 }
110 buffer[index++] = '-';
111 if (uuid.is_little_endian()) {
112 output(little_endian_to_host(uuid.m_time_mid), 2);
113 } else {
114 output(big_endian_to_host(uuid.m_time_mid), 2);
115 }
116 buffer[index++] = '-';
117 if (uuid.is_little_endian()) {
118 output(little_endian_to_host(uuid.m_time_hi_and_version), 2);
119 } else {
120 output(big_endian_to_host(uuid.m_time_hi_and_version), 2);
121 }
122 buffer[index++] = '-';
123 output_byte(uuid.m_clock_seq_hi_and_res);
124 output_byte(uuid.m_clock_seq_low);
125 buffer[index++] = '-';
126 output_byte(util::to_underlying(uuid.m_node[0]));
127 output_byte(util::to_underlying(uuid.m_node[1]));
128 output_byte(util::to_underlying(uuid.m_node[2]));
129 output_byte(util::to_underlying(uuid.m_node[3]));
130 output_byte(util::to_underlying(uuid.m_node[4]));
131 output_byte(util::to_underlying(uuid.m_node[5]));
132#if DI_GCC
133#pragma GCC diagnostic pop
134#endif
135
136 return formatter(context, container::TransparentStringView(buffer.begin(), buffer.end()));
137 };
138 };
139 }
140
142 auto valid_hex = ('0'_m - '9'_m || 'a'_m - 'f'_m || 'A'_m - 'F'_m);
143 auto minus = '-'_m;
144
145 return (parser::match_exactly(valid_hex, 8) >> ~parser::match_one(minus) >>
146 parser::match_exactly(valid_hex, 4) >> ~parser::match_one(minus) >>
147 parser::match_exactly(valid_hex, 4) >> ~parser::match_one(minus) >>
148 parser::match_exactly(valid_hex, 4) >> ~parser::match_one(minus) >>
149 parser::match_exactly(valid_hex, 12))
150 << []<typename Context>(
151 Context& context,
153 using Enc = meta::Encoding<Context>;
154 auto encoding = context.encoding();
155
156 auto [a, b, c, d, e] = results;
159 container::string::StringViewImpl<Enc> { encoding::unicode_code_point_unwrap(encoding, a.begin()),
160 encoding::unicode_code_point_unwrap(encoding, a.end()) });
163 container::string::StringViewImpl<Enc> { encoding::unicode_code_point_unwrap(encoding, b.begin()),
164 encoding::unicode_code_point_unwrap(encoding, b.end()) });
167 container::string::StringViewImpl<Enc> { encoding::unicode_code_point_unwrap(encoding, c.begin()),
168 encoding::unicode_code_point_unwrap(encoding, c.end()) });
171 container::string::StringViewImpl<Enc> { encoding::unicode_code_point_unwrap(encoding, d.begin()),
172 encoding::unicode_code_point_unwrap(encoding, d.end()) });
175 container::string::StringViewImpl<Enc> { encoding::unicode_code_point_unwrap(encoding, e.begin()),
176 encoding::unicode_code_point_unwrap(encoding, e.end()) });
177
178 auto result = UUID {};
179 result.m_time_low = m_time_low;
180 result.m_time_mid = m_time_mid;
181 result.m_time_hi_and_version = time_hi;
182 result.m_clock_seq_hi_and_res = clock_seq >> 8;
183 result.m_clock_seq_low = clock_seq & 0xFF;
184 result.m_node[0] = Byte((m_node & 0x0000FF0000000000) >> 40);
185 result.m_node[1] = Byte((m_node & 0x000000FF00000000) >> 32);
186 result.m_node[2] = Byte((m_node & 0x00000000FF000000) >> 24);
187 result.m_node[3] = Byte((m_node & 0x0000000000FF0000) >> 16);
188 result.m_node[4] = Byte((m_node & 0x000000000000FF00) >> 8);
189 result.m_node[5] = Byte((m_node & 0x00000000000000FF) >> 0);
190
191 if (result.is_little_endian()) {
192 result.m_time_low = host_to_little_endian(result.m_time_low);
193 result.m_time_mid = host_to_little_endian(result.m_time_mid);
194 result.m_time_hi_and_version = host_to_little_endian(result.m_time_hi_and_version);
195 } else {
196 result.m_time_low = host_to_big_endian(result.m_time_low);
197 result.m_time_mid = host_to_big_endian(result.m_time_mid);
198 result.m_time_hi_and_version = host_to_big_endian(result.m_time_hi_and_version);
199 }
200 return result;
201 };
202 }
203
204 u32 m_time_low { 0 };
205 u16 m_time_mid { 0 };
206 u16 m_time_hi_and_version { 0 };
207 u8 m_clock_seq_hi_and_res { 0 };
208 u8 m_clock_seq_low { 0 };
209 di::Array<di::Byte, 6> m_node { { di::Byte(0), di::Byte(0), di::Byte(0), di::Byte(0), di::Byte(0), di::Byte(0) } };
210};
211
212namespace detail {
213 struct GenerateUUIDFunction {
214 template<concepts::UniformRandomBitGenerator RNG>
215 constexpr auto operator()(RNG&& rng) const -> UUID {
216 auto distribution = random::UniformIntDistribution(0, 255);
217 auto bytes = UUID::ByteArray {};
218 for (auto& byte : bytes) {
219 byte = Byte(distribution(rng));
220 }
221
222 auto result = UUID(bytes);
223 result.set_version(UUID::Version::Random);
224 result.set_to_standard_variant();
225 return result;
226 }
227 };
228}
229
230constexpr inline auto generate_uuid = detail::GenerateUUIDFunction {};
231}
232
233namespace di {
234inline namespace literals {
235 inline namespace uuid_literals {
236 consteval auto operator""_uuid(char const* data, usize size) -> util::UUID {
237 auto view = di::TransparentStringView { data, size };
239 }
240 }
241}
242}
243
244namespace di {
246using util::UUID;
247}
248
249#if !defined(DI_NO_GLOBALS) && !defined(DI_NO_GLOBAL_UUID_LITERALS)
250using namespace di::literals::uuid_literals;
251#endif
Definition string_view_impl.h:19
Definition format_parse_context.h:14
Definition uuid.h:18
void IsAtom
Definition uuid.h:35
constexpr void clear()
Definition uuid.h:42
constexpr friend auto operator<=>(UUID a, UUID b) -> strong_ordering
Definition uuid.h:50
constexpr friend auto tag_invoke(types::Tag< parser::create_parser_in_place >, InPlaceType< UUID >)
Definition uuid.h:141
constexpr friend auto tag_invoke(types::Tag< format::formatter_in_place >, InPlaceType< UUID >, FormatParseContext< Enc > &parse_context, bool debug)
Definition uuid.h:70
constexpr UUID(ByteArray bytes)
Definition uuid.h:39
constexpr friend auto operator==(UUID a, UUID b) -> bool
Definition uuid.h:47
constexpr auto null() const -> bool
Definition uuid.h:41
UUID()=default
Definition variant.h:30
Definition operations.h:34
Definition format_context.h:9
string::StringViewImpl< string::TransparentEncoding > TransparentStringView
Definition string_view.h:13
constexpr auto formatter(FormatParseContext< Enc > &parse_context, bool debug=false)
Definition formatter.h:27
Definition uuid.h:235
vocab::Expected< T, meta::ParserContextError< Context > > ParserContextResult
Definition parser_context_result.h:8
meta::RemoveCVRef< T >::Encoding Encoding
Definition encoding.h:230
constexpr auto match_one
Definition match_one.h:27
constexpr auto run_parser_unchecked
Definition run_parser_unchecked.h:16
constexpr auto integer
Definition integer.h:212
constexpr auto parse_unchecked
Definition parse_unchecked.h:25
constexpr auto match_exactly
Definition match_exactly.h:56
std::byte byte
Definition byte.h:64
std::byte Byte
Definition byte.h:63
size_t usize
Definition integers.h:33
__UINT64_TYPE__ u64
Definition integers.h:12
__UINT8_TYPE__ u8
Definition integers.h:9
__UINT32_TYPE__ u32
Definition integers.h:11
di::meta::Decay< decltype(T)> Tag
Definition tag_invoke.h:28
__UINT16_TYPE__ u16
Definition integers.h:10
Definition vocab.h:96
constexpr auto to_underlying
Definition to_underlying.h:15
constexpr auto generate_uuid
Definition uuid.h:230
Definition any_storable.h:9
constexpr auto host_to_big_endian
Definition big_endian.h:21
constexpr auto little_endian_to_host
Definition little_endian.h:22
constexpr auto size
Definition size.h:62
constexpr auto data
Definition data.h:51
constexpr auto minus
Definition minus.h:15
constexpr auto big_endian_to_host
Definition big_endian.h:22
constexpr auto host_to_little_endian
Definition little_endian.h:21
Definition in_place_type.h:5
Definition array.h:27