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