载入中...
搜索中...
未找到
Identity.cpp
浏览该文件的文档.
1#include "common/Identity.h"
2
3#include <utility>
4
5namespace eve {
6
7namespace {
8
9[[nodiscard]] bool isLogicalName(std::string_view value) noexcept {
10 if (value.empty()) return false;
11 for (const char character : value) {
12 const bool alpha = (character >= 'a' && character <= 'z') || (character >= 'A' && character <= 'Z');
13 const bool digit = character >= '0' && character <= '9';
14 if (!(alpha || digit || character == '_' || character == '-' || character == '.')) {
15 return false;
16 }
17 }
18 const char first = value.front();
19 return (first >= 'a' && first <= 'z') || (first >= 'A' && first <= 'Z') || (first >= '0' && first <= '9');
20}
21
22[[nodiscard]] bool isLogicalNamespace(std::string_view value) noexcept {
23 if (value.empty()) return false;
24 for (const char character : value) {
25 const bool lower = character >= 'a' && character <= 'z';
26 const bool digit = character >= '0' && character <= '9';
27 if (!(lower || digit || character == '_' || character == '-' || character == '.')) {
28 return false;
29 }
30 }
31 return value.front() >= 'a' && value.front() <= 'z';
32}
33
34} // namespace
35
36std::optional<LogicalId> LogicalId::parse(std::string_view text) {
37 const auto separator = text.find(':');
38 if (separator == std::string_view::npos || text.find(':', separator + 1) != std::string_view::npos) {
39 return std::nullopt;
40 }
41
42 const auto namespaceName = text.substr(0, separator);
43 const auto name = text.substr(separator + 1);
44 if (!isLogicalNamespace(namespaceName) || !isLogicalName(name)) return std::nullopt;
45 return LogicalId(std::string(text));
46}
47
48std::optional<LogicalId> LogicalId::fromParts(std::string_view namespaceName, std::string_view name) {
49 if (!isLogicalNamespace(namespaceName) || !isLogicalName(name)) return std::nullopt;
50 std::string value;
51 value.reserve(namespaceName.size() + name.size() + 1);
52 value.append(namespaceName);
53 value.push_back(':');
54 value.append(name);
55 return LogicalId(std::move(value));
56}
57
58std::string_view LogicalId::namespaceName() const noexcept {
59 const auto separator = value_.find(':');
60 return separator == std::string::npos ? std::string_view{} : std::string_view(value_).substr(0, separator);
61}
62
63std::string_view LogicalId::name() const noexcept {
64 const auto separator = value_.find(':');
65 return separator == std::string::npos ? std::string_view{} : std::string_view(value_).substr(separator + 1);
66}
67
68std::uint64_t LogicalId::hash() const noexcept {
69 std::uint64_t result = 14695981039346656037ull;
70 for (const auto character : value_) {
71 result ^= static_cast<std::uint8_t>(character);
72 result *= 1099511628211ull;
73 }
74 return result;
75}
76
78 : entropy_(std::move(entropy)), clock_(std::move(clock)) {}
79
80std::optional<PersistentId> UuidV7Generator::generate() const {
81 const auto timestamp = clock_ ? clock_() : std::chrono::system_clock::now();
82 return generate(timestamp);
83}
84
85std::optional<PersistentId> UuidV7Generator::generate(std::chrono::system_clock::time_point timestamp) const {
86 return generateUuidV7(timestamp, entropy_);
87}
88
89std::optional<PersistentId> generateUuidV7(std::chrono::system_clock::time_point timestamp,
90 const UuidEntropySource& entropy) {
91 if (!entropy) return std::nullopt;
92
93 if (timestamp.time_since_epoch() < std::chrono::system_clock::duration::zero()) return std::nullopt;
94 const auto milliseconds =
95 std::chrono::duration_cast<std::chrono::milliseconds>(timestamp.time_since_epoch()).count();
96 constexpr std::uint64_t maxTimestamp = (std::uint64_t{1} << 48u) - 1u;
97 if (milliseconds < 0 || static_cast<std::uint64_t>(milliseconds) > maxTimestamp) {
98 return std::nullopt;
99 }
100
102 if (!entropy(std::span<std::uint8_t>(bytes).subspan(6))) return std::nullopt;
103
104 auto timestampValue = static_cast<std::uint64_t>(milliseconds);
105 for (std::size_t index = 6; index > 0; --index) {
106 bytes[index - 1] = static_cast<std::uint8_t>(timestampValue & 0xffu);
107 timestampValue >>= 8u;
108 }
109
110 bytes[6] = static_cast<std::uint8_t>(0x70u | (bytes[6] & 0x0fu));
111 bytes[8] = static_cast<std::uint8_t>(0x80u | (bytes[8] & 0x3fu));
112 return PersistentId(bytes);
113}
114
115// ---- Tag-free UUID core ---------------------------------------------------
116//
117// One copy of each algorithm, shared by every eve::detail::Id128<Tag>
118// instantiation. The tagged methods are inline one-line forwards, so adding a
119// domain tag no longer duplicates the parser, the formatter or the derivation.
120
121namespace detail {
122
123namespace {
124
125[[nodiscard]] constexpr std::optional<std::uint8_t> hexValue(char value) noexcept {
126 if (value >= '0' && value <= '9') return static_cast<std::uint8_t>(value - '0');
127 if (value >= 'a' && value <= 'f') return static_cast<std::uint8_t>(value - 'a' + 10);
128 if (value >= 'A' && value <= 'F') return static_cast<std::uint8_t>(value - 'A' + 10);
129 return std::nullopt;
130}
131
132} // namespace
133
134std::optional<UuidBytes> parseUuidText(std::string_view text) noexcept {
135 if (text.size() != 36 || text[8] != '-' || text[13] != '-' || text[18] != '-' || text[23] != '-') {
136 return std::nullopt;
137 }
138
140 std::size_t byteIndex = 0;
141 for (std::size_t i = 0; i < text.size();) {
142 if (text[i] == '-') {
143 ++i;
144 continue;
145 }
146
147 if (i + 1 >= text.size()) return std::nullopt;
148 const auto high = hexValue(text[i]);
149 const auto low = hexValue(text[i + 1]);
150 if (!high || !low || byteIndex >= bytes.size()) {
151 return std::nullopt;
152 }
153 bytes[byteIndex++] = static_cast<std::uint8_t>((*high << 4u) | *low);
154 i += 2;
155 }
156 if (byteIndex != bytes.size()) return std::nullopt;
157 return bytes;
158}
159
160std::string formatUuidBytes(const UuidBytes& bytes) {
161 static constexpr char digits[] = "0123456789abcdef";
162 std::string result;
163 result.reserve(36);
164 for (std::size_t i = 0; i < bytes.size(); ++i) {
165 if (i == 4 || i == 6 || i == 8 || i == 10) result.push_back('-');
166 result.push_back(digits[(bytes[i] >> 4u) & 0x0fu]);
167 result.push_back(digits[bytes[i] & 0x0fu]);
168 }
169 return result;
170}
171
172UuidBytes childUuidBytes(const UuidBytes& parent, std::string_view role) noexcept {
173 UuidBytes result = parent;
174 std::uint64_t hash = 14695981039346656037ull;
175 for (const unsigned char byte : role) {
176 hash ^= byte;
177 hash *= 1099511628211ull;
178 }
179 for (std::size_t i = 0; i < sizeof(hash); ++i) {
180 result[8 + i] ^= static_cast<std::uint8_t>((hash >> (i * 8u)) & 0xffu);
181 }
182 // Preserve the UUID variant while retaining the parent's namespace.
183 result[8] = static_cast<std::uint8_t>((result[8] & 0x3fu) | 0x80u);
184 return result;
185}
186
187void UuidIdState::assign(std::string_view text) {
188 if (text.empty()) return;
189 if (const auto parsed = parseUuidText(text)) {
190 uuid = *parsed;
191 spelling = formatUuidBytes(*parsed);
192 canonical = true;
193 return;
194 }
195 spelling = text;
197 canonical = false;
198}
199
200UuidBytes UuidIdState::projectLegacy(std::string_view text) noexcept {
201 std::uint64_t first = 14695981039346656037ull;
202 std::uint64_t second = 1099511628211ull;
203 for (const unsigned char byte : text) {
204 first ^= byte;
205 first *= 1099511628211ull;
206 second ^= static_cast<std::uint8_t>(byte + 0x9du);
207 second *= 14029467366897019727ull;
208 }
209
211 for (std::size_t i = 0; i < sizeof(first); ++i) {
212 bytes[i] = static_cast<std::uint8_t>((first >> (i * 8u)) & 0xffu);
213 bytes[8 + i] = static_cast<std::uint8_t>((second >> (i * 8u)) & 0xffu);
214 }
215 // Mark the deterministic projection as UUIDv5-shaped and RFC variant.
216 bytes[6] = static_cast<std::uint8_t>((bytes[6] & 0x0fu) | 0x50u);
217 bytes[8] = static_cast<std::uint8_t>((bytes[8] & 0x3fu) | 0x80u);
218 return bytes;
219}
220
221} // namespace detail
222
223} // namespace eve
double value
std::array< std::uint8_t, 32 > hash
Definition Evpack.cpp:172
std::int32_t second
std::int32_t first
Strong identity values shared by persistence, content and logical-name APIs.
std::string text
std::int32_t parent
std::uint64_t bytes
std::string name
double & milliseconds
Definition OnnxGpgpu.cpp:19
int detail
uint32_t index
static std::optional< LogicalId > fromParts(std::string_view namespaceName, std::string_view name)
Builds a logical ID from separate namespace and name components.
Definition Identity.cpp:48
static std::optional< LogicalId > parse(std::string_view text)
Parses a scoped logical name.
Definition Identity.cpp:36
std::uint64_t hash() const noexcept
Returns a stable non-cryptographic hash for hash tables.
Definition Identity.cpp:68
std::string_view name() const noexcept
Returns the name component as a view into this object.
Definition Identity.cpp:63
std::string_view namespaceName() const noexcept
Returns the namespace component as a view into this object.
Definition Identity.cpp:58
LogicalId()=default
Constructs an empty, invalid logical ID.
std::optional< PersistentId > generate() const
Generates a UUIDv7 using the injected clock.
Definition Identity.cpp:80
UuidV7Generator(UuidEntropySource entropy, UuidClock clock={})
Creates a generator with an injected entropy source and optional clock.
Definition Identity.cpp:77
std::array< std::uint8_t, 16 > Bytes
Definition Identity.h:114
void assign(std::string_view text)
Assigns from canonical UUID text or from a legacy spelling.
Definition Identity.cpp:187
static UuidBytes projectLegacy(std::string_view text) noexcept
Builds the deterministic UUID projection of a legacy spelling.
Definition Identity.cpp:200
std::array< std::uint8_t, 16 > UuidBytes
Byte representation shared by every tagged 128-bit identity.
Definition Identity.h:54
std::string formatUuidBytes(const UuidBytes &bytes)
Formats UUID bytes as lower-case canonical 8-4-4-4-12 text.
Definition Identity.cpp:160
UuidBytes childUuidBytes(const UuidBytes &parent, std::string_view role) noexcept
Derives a deterministic child UUID from a parent and a role.
Definition Identity.cpp:172
std::optional< UuidBytes > parseUuidText(std::string_view text) noexcept
Parses canonical UUID text without knowing the domain tag.
Definition Identity.cpp:134
Build metadata (engine git commit, build time, third-party version).
Definition Build.cpp:16
StrongUuid< detail::PersistentIdTag > PersistentId
Stable instance identity for persistence, networking and process boundaries.
Definition Identity.h:254
std::function< std::chrono::system_clock::time_point()> UuidClock
Clock callback used by the injectable UUIDv7 generator.
Definition Identity.h:469
std::function< bool(std::span< std::uint8_t > bytes)> UuidEntropySource
Entropy callback used by UUIDv7 generation.
Definition Identity.h:466
std::optional< PersistentId > generateUuidV7(std::chrono::system_clock::time_point timestamp, const UuidEntropySource &entropy)
Constructs a UUIDv7 without owning a clock or generator object.
Definition Identity.cpp:89