Stroika Library 3.0d25
 
Loading...
Searching...
No Matches
GUID.h
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2026. All rights reserved
3 */
4#ifndef _Stroika_Foundation_Common_GUID_h_
5#define _Stroika_Foundation_Common_GUID_h_ 1
6
7#include "Stroika/Foundation/StroikaPreComp.h"
8
9#include <compare>
10
11#if qStroika_Platform_MacOS
12#include <uuid/uuid.h>
13#elif qStroika_Platform_Windows
14#include <guiddef.h>
15#endif
16
19#include "Stroika/Foundation/Common/Common.h"
20#include "Stroika/Foundation/Common/Concepts.h"
21
22/**
23 */
24
25namespace Stroika::Foundation::Memory {
26 class BLOB; // Forward declare to avoid mutual include issues
27}
28
30
31 /**
32 * A very common 16-byte opaque ID structure.
33 *
34 * \note Satisfies Concepts:
35 * o sizeof (GUID) == 16
36 * o ranges::range<GUID>
37 * o regular<GUID>
38 * o totally_ordered<GUID>
39 *
40 * \note <a href="Design-Overview.md#Comparisons">Comparisons</a>:
41 * o static_assert (totally_ordered<GUID>);
42 * o by field - Data1, then Data2, Data3 and Data4's bytes - so in the same order as its text (As<String> (), which
43 * writes it in lower case) and its RFC 9562 bytes (AsRFC9562Bytes ()); NOT necessarily as its in-memory bytes (As<Memory::BLOB> ()).
44 *
45 * \note Byte order: its 16 bytes come in two orders, and each API taking or giving them says which:
46 * o RFC 9562's - network byte order, the order its text is written in. As a uuid_t (<uuid/uuid.h>) holds them, and as
47 * RFC 9562's algorithms (a name-based UUID's, say) take them: FromRFC9562Bytes (), AsRFC9562Bytes ().
48 * o this struct's own, in memory - Windows' GUID layout: its first three fields (Data1, Data2, Data3 - its first 8
49 * bytes) in the machine's byte order, its last 8 as written. The Memory::BLOB and array<> constructors, As<Memory::BLOB> ()
50 * and As<array<>> (), begin ()/end ()/data () - so too a GUID serialized as a BLOB. On a little-endian machine (as
51 * all those Stroika is tested on are, as of v3.0d25) its first 8 bytes differ from RFC 9562's; on a big-endian one
52 * the two orders would be the same.
53 */
54 struct GUID {
55 private:
56 static GUID mk_ (const string& src);
57
58 public:
59 /**
60 * \note - when converting from a string, GUID allows the leading/trailing {} to be optionally provided.
61 * - format's supported {61e4d49d-8c26-3480-f5c8-564e155c67a6}
62 * or 61e4d49d-8c26-3480-f5c8-564e155c67a6
63 * no argument CTOR, creates an all-zero GUID.
64 *
65 * \see GUID::GenerateNew () to create a new random GUID.
66 *
67 * \note The Memory::BLOB and array<> constructors take the 16 bytes in this struct's in-memory layout; for them in the
68 * order the text is written in (RFC 9562's - as a uuid_t holds them), @see FromRFC9562Bytes () - and GUID's note
69 * on byte order.
70 *
71 * @todo maybe support more input formats, such as https://stackoverflow.com/questions/7775439/is-the-format-of-guid-always-the-same
72 */
73 constexpr GUID () noexcept = default;
74#if qStroika_Platform_MacOS
75 GUID (const uuid_t& src) noexcept; ///< \brief from a uuid_t (<uuid/uuid.h>) - its bytes in RFC 9562's order (@see FromRFC9562Bytes)
76#elif qStroika_Platform_Windows
77 constexpr GUID (const ::GUID& src) noexcept;
78#endif
79 template <Characters::IConvertibleToString STRISH_TYPE>
81 GUID (const Memory::BLOB& src);
82 GUID (const array<byte, 16>& src) noexcept;
83 GUID (const array<uint8_t, 16>& src) noexcept;
84
85 public:
86 /**
87 * Like Windows UuidCreate, or CoCreateGuid - create a random GUID (but portably): an RFC 9562 version 4 UUID, random
88 * but for its version and variant bits. (Before Stroika v3.0d25 all 128 bits were random - unique just the same, but
89 * not marked as version 4.)
90 *
91 * \alias CreateNew(), CTOR
92 *
93 * \par Example Usage
94 * \code
95 * String newUUIDAsString = GUID::GenerateNew ().As<String> ();
96 * \endcode
97 */
98 static GUID GenerateNew () noexcept;
99
100 public:
101 /**
102 * \brief From its 16 bytes in RFC 9562's order: network byte order, the order its text is written in - as a uuid_t
103 * (<uuid/uuid.h>) holds them, and as RFC 9562's algorithms (a name-based UUID's, say) take them.
104 *
105 * \note Not the Memory::BLOB and array<> constructors, which take the bytes in this struct's in-memory layout (@see
106 * GUID's note on byte order).
107 *
108 * \par Example Usage
109 * \code
110 * array<byte, 16> b{}; // 00 01 02 ... 0f
111 * for (size_t i = 0; i < b.size (); ++i) {
112 * b[i] = static_cast<byte> (i);
113 * }
114 * Assert (GUID::FromRFC9562Bytes (b).As<String> () == "00010203-0405-0607-0809-0a0b0c0d0e0f");
115 * \endcode
116 */
117 static constexpr GUID FromRFC9562Bytes (span<const byte, 16> bytes) noexcept;
118
119 public:
120 /**
121 * \brief Its 16 bytes in RFC 9562's order - the order its text is written in (@see FromRFC9562Bytes).
122 *
123 * \note Not As<Memory::BLOB> () or As<array<>> (), which give them in this struct's in-memory layout.
124 */
125 constexpr array<byte, 16> AsRFC9562Bytes () const noexcept;
126
127 public:
128 uint32_t Data1{};
129 uint16_t Data2{};
130 uint16_t Data3{};
131 uint8_t Data4[8]{};
132
133 public:
134 using value_type = byte;
135
136 public:
137 /**
138 * Its bytes in this struct's in-memory layout (@see GUID's note on byte order).
139 *
140 * \nb: Stroika v2.1 allowed iterating and modifying in place of the GUID as a sequence of bytes, but no more
141 */
142 nonvirtual const byte* begin () const noexcept;
143
144 public:
145 /**
146 * \nb: Stroika v2.1 allowed iterating and modifying in place of the GUID as a sequence of bytes, but no more
147 */
148 nonvirtual const byte* end () const noexcept; ///< \brief @see begin ()
149
150 public:
151 /**
152 */
153 constexpr size_t size () const noexcept;
154
155 public:
156 /**
157 * Its bytes in this struct's in-memory layout - as As<Memory::BLOB> () (@see GUID's note on byte order).
158 */
159 nonvirtual explicit operator Memory::BLOB () const;
160
161 public:
162 /**
163 * By field - so in the same order as its text, and its RFC 9562 bytes; NOT as its in-memory bytes (@see GUID's note on
164 * comparisons).
165 */
166 nonvirtual strong_ordering operator<=> (const GUID&) const noexcept = default;
167
168 public:
169 /**
170 * Its bytes in this struct's in-memory layout (@see GUID's note on byte order).
171 */
172 nonvirtual const uint8_t* data () const noexcept;
173
174 public:
175 /**
176 * For now, only supported formats are
177 * o String -- format: 61e4d49d-8c26-3480-f5c8-564e155c67a6
178 * o string -- same
179 * o BLOB
180 * o array<uint8_t, 16> or array<byte, 16>
181 *
182 * \note As<Memory::BLOB> () and As<array<>> () give the 16 bytes in this struct's in-memory layout - Windows' GUID layout,
183 * whose first three fields are in the machine's byte order. For them in the order the text is written in (RFC 9562's
184 * - as a uuid_t holds them), @see AsRFC9562Bytes () - and GUID's note on byte order.
185 */
186 template <IAnyOf<Characters::String, std::string, Memory::BLOB, array<byte, 16>, array<uint8_t, 16>> T>
187 nonvirtual T As () const;
188
189 public:
190 /**
191 * @see Characters::ToString ()
192 */
193 nonvirtual Characters::String ToString () const;
194 };
195 static_assert (sizeof (GUID) == 16);
199
200}
201
202/*
203 * Already default-implemented in ToString() code, but this implementation is better (because by default
204 * 'range version' used) and this takes precedence.
205 */
206template <>
207struct qStroika_Foundation_Characters_FMT_PREFIX_::formatter<Stroika::Foundation::Common::GUID, wchar_t>
208 : qStroika_Foundation_Characters_FMT_PREFIX_::formatter<std::wstring, wchar_t> {
209 using inherited = qStroika_Foundation_Characters_FMT_PREFIX_::formatter<std::wstring, wchar_t>;
210 template <class FmtContext>
211 typename FmtContext::iterator format (const Stroika::Foundation::Common::GUID& s, FmtContext& ctx) const;
212};
213template <>
214struct qStroika_Foundation_Characters_FMT_PREFIX_::formatter<Stroika::Foundation::Common::GUID, char>
215 : qStroika_Foundation_Characters_FMT_PREFIX_::formatter<std::string, char> {
216 using inherited = qStroika_Foundation_Characters_FMT_PREFIX_::formatter<std::string, char>;
217 template <class FmtContext>
218 typename FmtContext::iterator format (const Stroika::Foundation::Common::GUID& s, FmtContext& ctx) const;
219};
220
222 template <typename T>
223 struct DefaultSerializer; // Forward declare to avoid mutual include issues
224 template <>
225 struct DefaultSerializer<Stroika::Foundation::Common::GUID> {
226 Memory::BLOB operator() (const Stroika::Foundation::Common::GUID& arg) const;
227 };
228}
229
230/*
231 ********************************************************************************
232 ***************************** Implementation Details ***************************
233 ********************************************************************************
234 */
235#include "GUID.inl"
236
237#endif /*_Stroika_Foundation_Common_GUID_h_*/
String is like std::u32string, except it is much easier to use, often much more space efficient,...
Definition String.h:201
Concept: trivial shorthand for variadic same_as A or same_as B, or ...
Definition Concepts.h:122
STL namespace.
constexpr array< byte, 16 > AsRFC9562Bytes() const noexcept
Its 16 bytes in RFC 9562's order - the order its text is written in (.
Definition GUID.inl:41
static GUID GenerateNew() noexcept
Definition GUID.cpp:76
constexpr GUID() noexcept=default
static constexpr GUID FromRFC9562Bytes(span< const byte, 16 > bytes) noexcept
From its 16 bytes in RFC 9562's order: network byte order, the order its text is written in - as a uu...
Definition GUID.inl:28
nonvirtual const byte * end() const noexcept
Definition GUID.inl:85
nonvirtual operator Memory::BLOB() const
Definition GUID.cpp:70
nonvirtual const byte * begin() const noexcept
Definition GUID.inl:81
nonvirtual Characters::String ToString() const
Definition GUID.cpp:64
nonvirtual const uint8_t * data() const noexcept
Definition GUID.inl:93