Helios Engine
A modular ECS based data-oriented C++23 game engine framework
Loading...
Searching...
No Matches
uuid.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <uuid.h>
4
5#include <algorithm>
6#include <array>
7#include <cstddef>
8#include <random>
9#include <span>
10#include <string>
11#include <string_view>
12
13namespace helios {
14
15/// @brief A class representing a universally unique identifier (UUID).
16class Uuid {
17public:
18 /// @brief Default constructor creates an invalid UUID (all zeros).
19 constexpr Uuid() noexcept = default;
20
21 /**
22 * @brief Construct a UUID from a span of bytes.
23 * @details The span must be exactly 16 bytes long; otherwise, the resulting
24 * UUID will be invalid.
25 * @param bytes A span of bytes representing the UUID
26 */
27 explicit constexpr Uuid(std::span<uint8_t, 16> bytes) : uuid_(bytes) {}
28
29 /**
30 * @brief Construct a UUID from a span of bytes.
31 * @details The span must be exactly 16 bytes long; otherwise, the resulting
32 * UUID will be invalid.
33 * @param bytes A span of bytes representing the UUID
34 */
35 explicit constexpr Uuid(std::span<const std::byte, 16> bytes);
36
37 /**
38 * @brief Construct a UUID from a string representation.
39 * @details If the string is not a valid UUID, the resulting UUID will be
40 * invalid.
41 * @param str The string representation of the UUID
42 */
43 explicit constexpr Uuid(std::string_view str);
44
45 constexpr Uuid(const Uuid& other) noexcept = default;
46 constexpr Uuid(Uuid&& other) noexcept = default;
47 constexpr ~Uuid() noexcept = default;
48
49 constexpr Uuid& operator=(const Uuid& other) noexcept = default;
50 constexpr Uuid& operator=(Uuid&& other) noexcept = default;
51
52 /**
53 * @brief Generate a new random UUID.
54 * @details Uses a thread_local generator for thread-safety without locks.
55 * Each thread maintains its own generator state for optimal performance.
56 * @return A new random UUID
57 */
58 [[nodiscard]] static constexpr Uuid Generate();
59
60 /**
61 * @brief Convert the UUID to its string representation.
62 * @return The string representation of the UUID, or an empty string if the
63 * UUID is invalid
64 */
65 [[nodiscard]] std::string ToString() const;
66
67 /**
68 * @brief Get the UUID as a span of bytes.
69 * @return A span of bytes representing the UUID, or an empty span if the UUID
70 * is invalid
71 */
72 [[nodiscard]] auto AsBytes() const noexcept -> std::span<const std::byte, 16>;
73
74 [[nodiscard]] constexpr bool operator==(const Uuid& other) const noexcept =
75 default;
76 [[nodiscard]] constexpr bool operator!=(const Uuid& other) const noexcept =
77 default;
78
79 [[nodiscard]] constexpr bool operator<(const Uuid& other) const noexcept {
80 return uuid_ < other.uuid_;
81 }
82
83 /**
84 * @brief Check if the UUID is valid (not all zeros).
85 * @return True if the UUID is valid, false otherwise
86 */
87 [[nodiscard]] constexpr bool Valid() const noexcept {
88 return !uuid_.is_nil();
89 }
90
91 /**
92 * @brief Compute a hash value for the UUID.
93 * @return A hash value for the UUID
94 */
95 [[nodiscard]] constexpr size_t Hash() const noexcept {
96 return std::hash<uuids::uuid>{}(uuid_);
97 }
98
99 /**
100 * @brief Swap two UUIDs.
101 * @param lhs The first UUID
102 * @param rhs The second UUID
103 */
104 friend constexpr void swap(Uuid& lhs, Uuid& rhs) noexcept;
105
106private:
107 uuids::uuid uuid_;
108
109 friend class UuidGenerator;
110};
111
112constexpr Uuid::Uuid(std::span<const std::byte, 16> bytes) {
113 std::array<uint8_t, 16> byte_array = {};
114 std::ranges::transform(bytes, byte_array.begin(), [](std::byte byte) {
115 return static_cast<uint8_t>(byte);
116 });
117 uuid_ = uuids::uuid(byte_array);
118}
119
120constexpr Uuid::Uuid(std::string_view str) {
121 if (str.empty()) [[unlikely]] {
122 return;
123 }
124
125 auto result = uuids::uuid::from_string(str.data());
126 if (result.has_value()) {
127 uuid_ = *result;
128 }
129}
130
131constexpr Uuid Uuid::Generate() {
132 // Create a thread-local engine and pass it (as an lvalue) to the generator.
133 // This avoids binding a temporary to a non-const reference.
134 static thread_local std::random_device rd;
135 static thread_local std::array<std::random_device::result_type,
136 std::mt19937::state_size>
137 seed_data = []() {
138 std::array<std::random_device::result_type, std::mt19937::state_size>
139 data = {};
140 std::ranges::generate(data, std::ref(rd));
141 return data;
142 }();
143 static thread_local std::seed_seq seq(seed_data.begin(), seed_data.end());
144 static thread_local std::mt19937 engine(seq);
145 static thread_local uuids::uuid_random_generator gen(engine);
146
147 Uuid result;
148 result.uuid_ = gen();
149 return result;
150}
151
152inline std::string Uuid::ToString() const {
153 if (!Valid()) {
154 return {};
155 }
156 return uuids::to_string(uuid_);
157}
158
159inline auto Uuid::AsBytes() const noexcept -> std::span<const std::byte, 16> {
160 return uuid_.as_bytes();
161}
162
163constexpr void swap(Uuid& lhs, Uuid& rhs) noexcept {
164 using std::swap;
165 swap(lhs.uuid_, rhs.uuid_);
166}
167
168/// @brief A class for generating random UUIDs using a specified random number
169/// generator.
171public:
172 /// @brief Default constructor initializes the generator with a random seed.
173 UuidGenerator() : generator_(std::random_device{}()) {}
174
175 /**
176 * @brief Construct a `UuidGenerator` with a custom random engine.
177 * @tparam RandomEngine The type of the random engine
178 * @param engine An instance of the random engine
179 */
180 template <typename RandomEngine>
181 requires(!std::same_as<std::decay_t<RandomEngine>, UuidGenerator>)
182 explicit UuidGenerator(RandomEngine&& engine)
183 : generator_(std::forward<RandomEngine>(engine)) {}
184 UuidGenerator(const UuidGenerator&) = delete;
185 UuidGenerator(UuidGenerator&&) noexcept = default;
186 ~UuidGenerator() = default;
187
188 UuidGenerator& operator=(const UuidGenerator&) = delete;
189 UuidGenerator& operator=(UuidGenerator&&) noexcept = default;
190
191 [[nodiscard]] Uuid Generate();
192
193private:
194 std::mt19937_64 generator_;
195};
196
198 uuids::basic_uuid_random_generator<std::mt19937_64> gen(&generator_);
199 Uuid result;
200 result.uuid_ = gen();
201 return result;
202}
203
204#undef constexpr
205
206} // namespace helios
207
208namespace std {
209
210template <>
211struct hash<helios::Uuid> {
212 constexpr size_t operator()(const helios::Uuid& uuid) const noexcept {
213 return uuid.Hash();
214 }
215};
216
217} // namespace std
A class for generating random UUIDs using a specified random number generator.
Definition uuid.hpp:170
UuidGenerator(const UuidGenerator &)=delete
UuidGenerator()
Default constructor initializes the generator with a random seed.
Definition uuid.hpp:173
UuidGenerator(RandomEngine &&engine)
Construct a UuidGenerator with a custom random engine.
Definition uuid.hpp:182
UuidGenerator(UuidGenerator &&) noexcept=default
A class representing a universally unique identifier (UUID).
Definition uuid.hpp:16
constexpr ~Uuid() noexcept=default
auto AsBytes() const noexcept -> std::span< const std::byte, 16 >
Get the UUID as a span of bytes.
Definition uuid.hpp:159
constexpr Uuid() noexcept=default
Default constructor creates an invalid UUID (all zeros).
constexpr Uuid(Uuid &&other) noexcept=default
static constexpr Uuid Generate()
Generate a new random UUID.
Definition uuid.hpp:131
friend class UuidGenerator
Definition uuid.hpp:109
std::string ToString() const
Convert the UUID to its string representation.
Definition uuid.hpp:152
constexpr size_t Hash() const noexcept
Compute a hash value for the UUID.
Definition uuid.hpp:95
friend constexpr void swap(Uuid &lhs, Uuid &rhs) noexcept
Swap two UUIDs.
Definition uuid.hpp:163
constexpr bool Valid() const noexcept
Check if the UUID is valid (not all zeros).
Definition uuid.hpp:87
constexpr Uuid(const Uuid &other) noexcept=default
constexpr void swap(Uuid &lhs, Uuid &rhs) noexcept
Definition uuid.hpp:163
STL namespace.
constexpr size_t operator()(const helios::Uuid &uuid) const noexcept
Definition uuid.hpp:212