Iros
 
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 {
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 UUID() = default;
36
37 constexpr explicit UUID(ByteArray bytes) { *this = util::bit_cast<UUID>(bytes); }
38
39 constexpr auto null() const -> bool { return *this == UUID(); }
40 constexpr void clear() { *this = UUID(); }
41
42private:
44
45 constexpr friend auto operator==(UUID a, UUID b) -> bool {
46 return util::bit_cast<ByteArray>(a) == util::bit_cast<ByteArray>(b);
47 }
48 constexpr friend auto operator<=>(UUID a, UUID b) -> strong_ordering {
49 return util::bit_cast<ByteArray>(a) <=> util::bit_cast<ByteArray>(b);
50 }
51
52 constexpr auto variant() const -> Variant { return Variant(m_clock_seq_hi_and_res >> 5); }
53 constexpr auto version() const -> Version { return Version(m_time_hi_and_version >> 4); }
54
55 constexpr void set_to_standard_variant() {
56 m_clock_seq_hi_and_res &= 0b11000000;
57 m_clock_seq_hi_and_res |= 0b10000000;
58 }
59
60 constexpr void set_version(Version type) {
61 m_time_hi_and_version &= 0b00001111;
62 m_time_hi_and_version |= util::to_underlying(type) << 4;
63 }
64
65 constexpr auto is_little_endian() const -> bool { return variant() == Variant::LittleEndian; }
66
67 template<concepts::Encoding Enc>
69 FormatParseContext<Enc>& parse_context, bool debug) {
71 [](concepts::CopyConstructible auto formatter) {
72 return [=](concepts::FormatContext auto& context, UUID uuid) {
73#if DI_GCC
74#pragma GCC diagnostic push
75#pragma GCC diagnostic ignored "-Wstringop-overflow"
76#endif
77 auto buffer = di::Array<char, 36> {};
78 usize index = 0;
79
80 auto output_digit = [&](u8 digit) {
81 if (digit >= 10) {
82 buffer[index++] = char(digit - 10 + 'a');
83 } else {
84 buffer[index++] = char(digit + '0');
85 }
86 };
87
88 auto output_byte = [&](auto byte) {
89 output_digit(byte >> 4);
90 output_digit(byte & 0xF);
91 };
92
93 auto output = [&](auto value, auto bytes) {
94 u64 mask = 0xFF << 8 * (bytes - 1);
95 for (; bytes > 0; bytes--) {
96 u8 byte = (value & mask) >> 8 * (bytes - 1);
97 mask >>= 8;
98
99 output_byte(byte);
100 }
101 };
102
103 if (uuid.is_little_endian()) {
104 output(little_endian_to_host(uuid.m_time_low), 4);
105 } else {
106 output(big_endian_to_host(uuid.m_time_low), 4);
107 }
108 buffer[index++] = '-';
109 if (uuid.is_little_endian()) {
110 output(little_endian_to_host(uuid.m_time_mid), 2);
111 } else {
112 output(big_endian_to_host(uuid.m_time_mid), 2);
113 }
114 buffer[index++] = '-';
115 if (uuid.is_little_endian()) {
116 output(little_endian_to_host(uuid.m_time_hi_and_version), 2);
117 } else {
118 output(big_endian_to_host(uuid.m_time_hi_and_version), 2);
119 }
120 buffer[index++] = '-';
121 output_byte(uuid.m_clock_seq_hi_and_res);
122 output_byte(uuid.m_clock_seq_low);
123 buffer[index++] = '-';
124 output_byte(util::to_underlying(uuid.m_node[0]));
125 output_byte(util::to_underlying(uuid.m_node[1]));
126 output_byte(util::to_underlying(uuid.m_node[2]));
127 output_byte(util::to_underlying(uuid.m_node[3]));
128 output_byte(util::to_underlying(uuid.m_node[4]));
129 output_byte(util::to_underlying(uuid.m_node[5]));
130#if DI_GCC
131#pragma GCC diagnostic pop
132#endif
133
134 return formatter(context, container::TransparentStringView(buffer.begin(), buffer.end()));
135 };
136 };
137 }
138
140 auto valid_hex = ('0'_m - '9'_m || 'a'_m - 'f'_m || 'A'_m - 'F'_m);
141 auto minus = '-'_m;
142
143 return (parser::match_exactly(valid_hex, 8) >> ~parser::match_one(minus) >>
144 parser::match_exactly(valid_hex, 4) >> ~parser::match_one(minus) >>
145 parser::match_exactly(valid_hex, 4) >> ~parser::match_one(minus) >>
146 parser::match_exactly(valid_hex, 4) >> ~parser::match_one(minus) >>
147 parser::match_exactly(valid_hex, 12))
148 << []<typename Context>(
149 Context& context,
151 using Enc = meta::Encoding<Context>;
152 auto encoding = context.encoding();
153
154 auto [a, b, c, d, e] = results;
157 container::string::StringViewImpl<Enc> { encoding::unicode_code_point_unwrap(encoding, a.begin()),
158 encoding::unicode_code_point_unwrap(encoding, a.end()) });
161 container::string::StringViewImpl<Enc> { encoding::unicode_code_point_unwrap(encoding, b.begin()),
162 encoding::unicode_code_point_unwrap(encoding, b.end()) });
165 container::string::StringViewImpl<Enc> { encoding::unicode_code_point_unwrap(encoding, c.begin()),
166 encoding::unicode_code_point_unwrap(encoding, c.end()) });
169 container::string::StringViewImpl<Enc> { encoding::unicode_code_point_unwrap(encoding, d.begin()),
170 encoding::unicode_code_point_unwrap(encoding, d.end()) });
173 container::string::StringViewImpl<Enc> { encoding::unicode_code_point_unwrap(encoding, e.begin()),
174 encoding::unicode_code_point_unwrap(encoding, e.end()) });
175
176 auto result = UUID {};
177 result.m_time_low = m_time_low;
178 result.m_time_mid = m_time_mid;
179 result.m_time_hi_and_version = time_hi;
180 result.m_clock_seq_hi_and_res = clock_seq >> 8;
181 result.m_clock_seq_low = clock_seq & 0xFF;
182 result.m_node[0] = Byte((m_node & 0x0000FF0000000000) >> 40);
183 result.m_node[1] = Byte((m_node & 0x000000FF00000000) >> 32);
184 result.m_node[2] = Byte((m_node & 0x00000000FF000000) >> 24);
185 result.m_node[3] = Byte((m_node & 0x0000000000FF0000) >> 16);
186 result.m_node[4] = Byte((m_node & 0x000000000000FF00) >> 8);
187 result.m_node[5] = Byte((m_node & 0x00000000000000FF) >> 0);
188
189 if (result.is_little_endian()) {
190 result.m_time_low = host_to_little_endian(result.m_time_low);
191 result.m_time_mid = host_to_little_endian(result.m_time_mid);
192 result.m_time_hi_and_version = host_to_little_endian(result.m_time_hi_and_version);
193 } else {
194 result.m_time_low = host_to_big_endian(result.m_time_low);
195 result.m_time_mid = host_to_big_endian(result.m_time_mid);
196 result.m_time_hi_and_version = host_to_big_endian(result.m_time_hi_and_version);
197 }
198 return result;
199 };
200 }
201
202 u32 m_time_low { 0 };
203 u16 m_time_mid { 0 };
204 u16 m_time_hi_and_version { 0 };
205 u8 m_clock_seq_hi_and_res { 0 };
206 u8 m_clock_seq_low { 0 };
207 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) } };
208};
209
210namespace detail {
212 template<concepts::UniformRandomBitGenerator RNG>
213 constexpr auto operator()(RNG&& rng) const -> UUID {
214 auto distribution = random::UniformIntDistribution(0, 255);
215 auto bytes = UUID::ByteArray {};
216 for (auto& byte : bytes) {
217 byte = Byte(distribution(rng));
218 }
219
220 auto result = UUID(bytes);
221 result.set_version(UUID::Version::Random);
222 result.set_to_standard_variant();
223 return result;
224 }
225 };
226}
227
229}
230
231namespace di {
232inline namespace literals {
233 inline namespace uuid_literals {
234 consteval auto operator""_uuid(char const* data, usize size) -> util::UUID {
235 auto view = di::TransparentStringView { data, size };
237 }
238 }
239}
240}
241
242namespace di {
244using util::UUID;
245}
246
247#if !defined(DI_NO_GLOBALS) && !defined(DI_NO_GLOBAL_UUID_LITERALS)
248using namespace di::literals::uuid_literals;
249#endif
Definition string_view_impl_forward_declaration.h:7
Definition format_parse_context.h:14
Definition uniform_int_distribution.h:10
Definition uuid.h:18
constexpr void clear()
Definition uuid.h:40
constexpr friend auto operator<=>(UUID a, UUID b) -> strong_ordering
Definition uuid.h:48
constexpr friend auto tag_invoke(types::Tag< parser::create_parser_in_place >, InPlaceType< UUID >)
Definition uuid.h:139
constexpr friend auto tag_invoke(types::Tag< format::formatter_in_place >, InPlaceType< UUID >, FormatParseContext< Enc > &parse_context, bool debug)
Definition uuid.h:68
constexpr UUID(ByteArray bytes)
Definition uuid.h:37
constexpr friend auto operator==(UUID a, UUID b) -> bool
Definition uuid.h:45
constexpr auto null() const -> bool
Definition uuid.h:39
UUID()=default
Definition variant_forward_declaration.h:6
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:233
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 clamp.h:9
Definition vocab.h:96
constexpr auto to_underlying
Definition to_underlying.h:15
constexpr auto generate_uuid
Definition uuid.h:228
Definition zstring_parser.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:54
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
constexpr auto operator()(RNG &&rng) const -> UUID
Definition uuid.h:213
Definition span_fixed_size.h:37