ulid-transform 1.2.1__cp313-cp313-win32.whl → 1.5.2__cp313-cp313-win32.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ulid_transform/__init__.py +1 -1
- ulid_transform/_py_ulid_impl.py +6 -3
- ulid_transform/_ulid_impl.cp313-win32.pyd +0 -0
- ulid_transform/ulid_struct.hh +185 -618
- ulid_transform/ulid_uint128.hh +211 -420
- ulid_transform/ulid_wrapper.cpp +67 -54
- ulid_transform/ulid_wrapper.h +1 -1
- {ulid_transform-1.2.1.dist-info → ulid_transform-1.5.2.dist-info}/METADATA +6 -5
- ulid_transform-1.5.2.dist-info/RECORD +14 -0
- {ulid_transform-1.2.1.dist-info → ulid_transform-1.5.2.dist-info}/WHEEL +1 -1
- ulid_transform/ulid.hh +0 -17
- ulid_transform-1.2.1.dist-info/RECORD +0 -15
- {ulid_transform-1.2.1.dist-info → ulid_transform-1.5.2.dist-info/licenses}/LICENSE +0 -0
ulid_transform/ulid_struct.hh
CHANGED
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
#ifndef ULID_STRUCT_HH
|
|
2
2
|
#define ULID_STRUCT_HH
|
|
3
3
|
|
|
4
|
+
#include <array>
|
|
4
5
|
#include <chrono>
|
|
5
6
|
#include <cstdlib>
|
|
6
7
|
#include <ctime>
|
|
7
8
|
#include <functional>
|
|
8
9
|
#include <random>
|
|
10
|
+
#include <thread>
|
|
9
11
|
#include <vector>
|
|
10
12
|
|
|
11
13
|
#if _MSC_VER > 0
|
|
12
14
|
typedef uint32_t rand_t;
|
|
13
|
-
#
|
|
15
|
+
#else
|
|
14
16
|
typedef uint8_t rand_t;
|
|
15
17
|
#endif
|
|
16
18
|
|
|
@@ -20,362 +22,69 @@ namespace ulid {
|
|
|
20
22
|
* ULID is a 16 byte Universally Unique Lexicographically Sortable Identifier
|
|
21
23
|
* */
|
|
22
24
|
struct ULID {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
ULID() {
|
|
26
|
-
// for (int i = 0 ; i < 16 ; i++) {
|
|
27
|
-
// data[i] = 0;
|
|
28
|
-
// }
|
|
29
|
-
|
|
30
|
-
// unrolled loop
|
|
31
|
-
data[0] = 0;
|
|
32
|
-
data[1] = 0;
|
|
33
|
-
data[2] = 0;
|
|
34
|
-
data[3] = 0;
|
|
35
|
-
data[4] = 0;
|
|
36
|
-
data[5] = 0;
|
|
37
|
-
data[6] = 0;
|
|
38
|
-
data[7] = 0;
|
|
39
|
-
data[8] = 0;
|
|
40
|
-
data[9] = 0;
|
|
41
|
-
data[10] = 0;
|
|
42
|
-
data[11] = 0;
|
|
43
|
-
data[12] = 0;
|
|
44
|
-
data[13] = 0;
|
|
45
|
-
data[14] = 0;
|
|
46
|
-
data[15] = 0;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
ULID(uint64_t val) {
|
|
50
|
-
// for (int i = 0 ; i < 16 ; i++) {
|
|
51
|
-
// data[15 - i] = static_cast<uint8_t>(val);
|
|
52
|
-
// val >>= 8;
|
|
53
|
-
// }
|
|
54
|
-
|
|
55
|
-
// unrolled loop
|
|
56
|
-
data[15] = static_cast<uint8_t>(val);
|
|
57
|
-
|
|
58
|
-
val >>= 8;
|
|
59
|
-
data[14] = static_cast<uint8_t>(val);
|
|
60
|
-
|
|
61
|
-
val >>= 8;
|
|
62
|
-
data[13] = static_cast<uint8_t>(val);
|
|
63
|
-
|
|
64
|
-
val >>= 8;
|
|
65
|
-
data[12] = static_cast<uint8_t>(val);
|
|
66
|
-
|
|
67
|
-
val >>= 8;
|
|
68
|
-
data[11] = static_cast<uint8_t>(val);
|
|
69
|
-
|
|
70
|
-
val >>= 8;
|
|
71
|
-
data[10] = static_cast<uint8_t>(val);
|
|
72
|
-
|
|
73
|
-
val >>= 8;
|
|
74
|
-
data[9] = static_cast<uint8_t>(val);
|
|
75
|
-
|
|
76
|
-
val >>= 8;
|
|
77
|
-
data[8] = static_cast<uint8_t>(val);
|
|
78
|
-
|
|
79
|
-
data[7] = 0;
|
|
80
|
-
data[6] = 0;
|
|
81
|
-
data[5] = 0;
|
|
82
|
-
data[4] = 0;
|
|
83
|
-
data[3] = 0;
|
|
84
|
-
data[2] = 0;
|
|
85
|
-
data[1] = 0;
|
|
86
|
-
data[0] = 0;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
ULID(const ULID& other) {
|
|
90
|
-
// for (int i = 0 ; i < 16 ; i++) {
|
|
91
|
-
// data[i] = other.data[i];
|
|
92
|
-
// }
|
|
93
|
-
|
|
94
|
-
// unrolled loop
|
|
95
|
-
data[0] = other.data[0];
|
|
96
|
-
data[1] = other.data[1];
|
|
97
|
-
data[2] = other.data[2];
|
|
98
|
-
data[3] = other.data[3];
|
|
99
|
-
data[4] = other.data[4];
|
|
100
|
-
data[5] = other.data[5];
|
|
101
|
-
data[6] = other.data[6];
|
|
102
|
-
data[7] = other.data[7];
|
|
103
|
-
data[8] = other.data[8];
|
|
104
|
-
data[9] = other.data[9];
|
|
105
|
-
data[10] = other.data[10];
|
|
106
|
-
data[11] = other.data[11];
|
|
107
|
-
data[12] = other.data[12];
|
|
108
|
-
data[13] = other.data[13];
|
|
109
|
-
data[14] = other.data[14];
|
|
110
|
-
data[15] = other.data[15];
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
ULID& operator=(const ULID& other) {
|
|
114
|
-
// for (int i = 0 ; i < 16 ; i++) {
|
|
115
|
-
// data[i] = other.data[i];
|
|
116
|
-
// }
|
|
117
|
-
|
|
118
|
-
// unrolled loop
|
|
119
|
-
data[0] = other.data[0];
|
|
120
|
-
data[1] = other.data[1];
|
|
121
|
-
data[2] = other.data[2];
|
|
122
|
-
data[3] = other.data[3];
|
|
123
|
-
data[4] = other.data[4];
|
|
124
|
-
data[5] = other.data[5];
|
|
125
|
-
data[6] = other.data[6];
|
|
126
|
-
data[7] = other.data[7];
|
|
127
|
-
data[8] = other.data[8];
|
|
128
|
-
data[9] = other.data[9];
|
|
129
|
-
data[10] = other.data[10];
|
|
130
|
-
data[11] = other.data[11];
|
|
131
|
-
data[12] = other.data[12];
|
|
132
|
-
data[13] = other.data[13];
|
|
133
|
-
data[14] = other.data[14];
|
|
134
|
-
data[15] = other.data[15];
|
|
135
|
-
|
|
136
|
-
return *this;
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
ULID(ULID&& other) {
|
|
140
|
-
// for (int i = 0 ; i < 16 ; i++) {
|
|
141
|
-
// data[i] = other.data[i];
|
|
142
|
-
// other.data[i] = 0;
|
|
143
|
-
// }
|
|
144
|
-
|
|
145
|
-
// unrolled loop
|
|
146
|
-
data[0] = other.data[0];
|
|
147
|
-
other.data[0] = 0;
|
|
148
|
-
|
|
149
|
-
data[1] = other.data[1];
|
|
150
|
-
other.data[1] = 0;
|
|
151
|
-
|
|
152
|
-
data[2] = other.data[2];
|
|
153
|
-
other.data[2] = 0;
|
|
154
|
-
|
|
155
|
-
data[3] = other.data[3];
|
|
156
|
-
other.data[3] = 0;
|
|
157
|
-
|
|
158
|
-
data[4] = other.data[4];
|
|
159
|
-
other.data[4] = 0;
|
|
160
|
-
|
|
161
|
-
data[5] = other.data[5];
|
|
162
|
-
other.data[5] = 0;
|
|
163
|
-
|
|
164
|
-
data[6] = other.data[6];
|
|
165
|
-
other.data[6] = 0;
|
|
166
|
-
|
|
167
|
-
data[7] = other.data[7];
|
|
168
|
-
other.data[7] = 0;
|
|
169
|
-
|
|
170
|
-
data[8] = other.data[8];
|
|
171
|
-
other.data[8] = 0;
|
|
172
|
-
|
|
173
|
-
data[9] = other.data[9];
|
|
174
|
-
other.data[9] = 0;
|
|
175
|
-
|
|
176
|
-
data[10] = other.data[10];
|
|
177
|
-
other.data[10] = 0;
|
|
178
|
-
|
|
179
|
-
data[11] = other.data[11];
|
|
180
|
-
other.data[11] = 0;
|
|
181
|
-
|
|
182
|
-
data[12] = other.data[12];
|
|
183
|
-
other.data[12] = 0;
|
|
184
|
-
|
|
185
|
-
data[13] = other.data[13];
|
|
186
|
-
other.data[13] = 0;
|
|
187
|
-
|
|
188
|
-
data[14] = other.data[14];
|
|
189
|
-
other.data[14] = 0;
|
|
190
|
-
|
|
191
|
-
data[15] = other.data[15];
|
|
192
|
-
other.data[15] = 0;
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
ULID& operator=(ULID&& other) {
|
|
196
|
-
// for (int i = 0 ; i < 16 ; i++) {
|
|
197
|
-
// data[i] = other.data[i];
|
|
198
|
-
// other.data[i] = 0;
|
|
199
|
-
// }
|
|
200
|
-
|
|
201
|
-
// unrolled loop
|
|
202
|
-
data[0] = other.data[0];
|
|
203
|
-
other.data[0] = 0;
|
|
204
|
-
|
|
205
|
-
data[1] = other.data[1];
|
|
206
|
-
other.data[1] = 0;
|
|
207
|
-
|
|
208
|
-
data[2] = other.data[2];
|
|
209
|
-
other.data[2] = 0;
|
|
210
|
-
|
|
211
|
-
data[3] = other.data[3];
|
|
212
|
-
other.data[3] = 0;
|
|
213
|
-
|
|
214
|
-
data[4] = other.data[4];
|
|
215
|
-
other.data[4] = 0;
|
|
216
|
-
|
|
217
|
-
data[5] = other.data[5];
|
|
218
|
-
other.data[5] = 0;
|
|
219
|
-
|
|
220
|
-
data[6] = other.data[6];
|
|
221
|
-
other.data[6] = 0;
|
|
222
|
-
|
|
223
|
-
data[7] = other.data[7];
|
|
224
|
-
other.data[7] = 0;
|
|
225
|
-
|
|
226
|
-
data[8] = other.data[8];
|
|
227
|
-
other.data[8] = 0;
|
|
228
|
-
|
|
229
|
-
data[9] = other.data[9];
|
|
230
|
-
other.data[9] = 0;
|
|
231
|
-
|
|
232
|
-
data[10] = other.data[10];
|
|
233
|
-
other.data[10] = 0;
|
|
234
|
-
|
|
235
|
-
data[11] = other.data[11];
|
|
236
|
-
other.data[11] = 0;
|
|
237
|
-
|
|
238
|
-
data[12] = other.data[12];
|
|
239
|
-
other.data[12] = 0;
|
|
240
|
-
|
|
241
|
-
data[13] = other.data[13];
|
|
242
|
-
other.data[13] = 0;
|
|
243
|
-
|
|
244
|
-
data[14] = other.data[14];
|
|
245
|
-
other.data[14] = 0;
|
|
246
|
-
|
|
247
|
-
data[15] = other.data[15];
|
|
248
|
-
other.data[15] = 0;
|
|
249
|
-
|
|
250
|
-
return *this;
|
|
251
|
-
}
|
|
25
|
+
uint8_t data[16];
|
|
252
26
|
};
|
|
253
27
|
|
|
254
28
|
/**
|
|
255
29
|
* EncodeTimestamp will encode the int64_t timestamp to the passed ulid
|
|
256
30
|
* */
|
|
257
|
-
inline void EncodeTimestamp(int64_t timestamp, ULID& ulid)
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
31
|
+
inline void EncodeTimestamp(int64_t timestamp, ULID& ulid)
|
|
32
|
+
{
|
|
33
|
+
ulid.data[0] = static_cast<uint8_t>(timestamp >> 40);
|
|
34
|
+
ulid.data[1] = static_cast<uint8_t>(timestamp >> 32);
|
|
35
|
+
ulid.data[2] = static_cast<uint8_t>(timestamp >> 24);
|
|
36
|
+
ulid.data[3] = static_cast<uint8_t>(timestamp >> 16);
|
|
37
|
+
ulid.data[4] = static_cast<uint8_t>(timestamp >> 8);
|
|
38
|
+
ulid.data[5] = static_cast<uint8_t>(timestamp);
|
|
264
39
|
}
|
|
265
40
|
|
|
266
41
|
/**
|
|
267
42
|
* EncodeTime will encode the time point to the passed ulid
|
|
268
43
|
* */
|
|
269
|
-
inline void EncodeTime(std::chrono::time_point<std::chrono::system_clock> time_point, ULID& ulid)
|
|
270
|
-
|
|
271
|
-
|
|
44
|
+
inline void EncodeTime(std::chrono::time_point<std::chrono::system_clock> time_point, ULID& ulid)
|
|
45
|
+
{
|
|
46
|
+
auto time_ms = std::chrono::time_point_cast<std::chrono::milliseconds>(time_point);
|
|
47
|
+
int64_t timestamp = time_ms.time_since_epoch().count();
|
|
272
48
|
EncodeTimestamp(timestamp, ulid);
|
|
273
49
|
}
|
|
274
50
|
|
|
275
|
-
/**
|
|
276
|
-
* EncodeTimeNow will encode a ULID using the time obtained using std::time(nullptr)
|
|
277
|
-
* */
|
|
278
|
-
inline void EncodeTimeNow(ULID& ulid) {
|
|
279
|
-
auto time_now = std::chrono::system_clock::from_time_t(time(nullptr));
|
|
280
|
-
EncodeTime(time_now, ulid);
|
|
281
|
-
}
|
|
282
|
-
|
|
283
51
|
/**
|
|
284
52
|
* EncodeTimeSystemClockNow will encode a ULID using the time obtained using
|
|
285
53
|
* std::chrono::system_clock::now() by taking the timestamp in milliseconds.
|
|
286
54
|
* */
|
|
287
|
-
inline void EncodeTimeSystemClockNow(ULID& ulid)
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
/**
|
|
292
|
-
* EncodeEntropy will encode the last 10 bytes of the passed uint8_t array with
|
|
293
|
-
* the values generated using the passed random number generator.
|
|
294
|
-
* */
|
|
295
|
-
inline void EncodeEntropy(const std::function<uint8_t()>& rng, ULID& ulid) {
|
|
296
|
-
ulid.data[6] = rng();
|
|
297
|
-
ulid.data[7] = rng();
|
|
298
|
-
ulid.data[8] = rng();
|
|
299
|
-
ulid.data[9] = rng();
|
|
300
|
-
ulid.data[10] = rng();
|
|
301
|
-
ulid.data[11] = rng();
|
|
302
|
-
ulid.data[12] = rng();
|
|
303
|
-
ulid.data[13] = rng();
|
|
304
|
-
ulid.data[14] = rng();
|
|
305
|
-
ulid.data[15] = rng();
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
/**
|
|
309
|
-
* EncodeEntropyRand will encode a ulid using std::rand
|
|
310
|
-
*
|
|
311
|
-
* std::rand returns values in [0, RAND_MAX]
|
|
312
|
-
* */
|
|
313
|
-
inline void EncodeEntropyRand(ULID& ulid) {
|
|
314
|
-
ulid.data[6] = static_cast<uint8_t>((std::rand() * 255ull) / RAND_MAX);
|
|
315
|
-
ulid.data[7] = static_cast<uint8_t>((std::rand() * 255ull) / RAND_MAX);
|
|
316
|
-
ulid.data[8] = static_cast<uint8_t>((std::rand() * 255ull) / RAND_MAX);
|
|
317
|
-
ulid.data[9] = static_cast<uint8_t>((std::rand() * 255ull) / RAND_MAX);
|
|
318
|
-
ulid.data[10] = static_cast<uint8_t>((std::rand() * 255ull) / RAND_MAX);
|
|
319
|
-
ulid.data[11] = static_cast<uint8_t>((std::rand() * 255ull) / RAND_MAX);
|
|
320
|
-
ulid.data[12] = static_cast<uint8_t>((std::rand() * 255ull) / RAND_MAX);
|
|
321
|
-
ulid.data[13] = static_cast<uint8_t>((std::rand() * 255ull) / RAND_MAX);
|
|
322
|
-
ulid.data[14] = static_cast<uint8_t>((std::rand() * 255ull) / RAND_MAX);
|
|
323
|
-
ulid.data[15] = static_cast<uint8_t>((std::rand() * 255ull) / RAND_MAX);
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
static std::uniform_int_distribution<rand_t> Distribution_0_255(0, 255);
|
|
327
|
-
|
|
328
|
-
/**
|
|
329
|
-
* EncodeEntropyMt19937 will encode a ulid using std::mt19937
|
|
330
|
-
*
|
|
331
|
-
* It also creates a std::uniform_int_distribution to generate values in [0, 255]
|
|
332
|
-
* */
|
|
333
|
-
inline void EncodeEntropyMt19937(std::mt19937& generator, ULID& ulid) {
|
|
334
|
-
ulid.data[6] = Distribution_0_255(generator);
|
|
335
|
-
ulid.data[7] = Distribution_0_255(generator);
|
|
336
|
-
ulid.data[8] = Distribution_0_255(generator);
|
|
337
|
-
ulid.data[9] = Distribution_0_255(generator);
|
|
338
|
-
ulid.data[10] = Distribution_0_255(generator);
|
|
339
|
-
ulid.data[11] = Distribution_0_255(generator);
|
|
340
|
-
ulid.data[12] = Distribution_0_255(generator);
|
|
341
|
-
ulid.data[13] = Distribution_0_255(generator);
|
|
342
|
-
ulid.data[14] = Distribution_0_255(generator);
|
|
343
|
-
ulid.data[15] = Distribution_0_255(generator);
|
|
344
|
-
}
|
|
345
|
-
|
|
346
|
-
/**
|
|
347
|
-
* Encode will create an encoded ULID with a timestamp and a generator.
|
|
348
|
-
* */
|
|
349
|
-
inline void Encode(std::chrono::time_point<std::chrono::system_clock> timestamp, const std::function<uint8_t()>& rng, ULID& ulid) {
|
|
350
|
-
EncodeTime(timestamp, ulid);
|
|
351
|
-
EncodeEntropy(rng, ulid);
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
/**
|
|
355
|
-
* EncodeNowRand = EncodeTimeNow + EncodeEntropyRand.
|
|
356
|
-
* */
|
|
357
|
-
inline void EncodeNowRand(ULID& ulid) {
|
|
358
|
-
EncodeTimeNow(ulid);
|
|
359
|
-
EncodeEntropyRand(ulid);
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
/**
|
|
363
|
-
* Create will create a ULID with a timestamp and a generator.
|
|
364
|
-
* */
|
|
365
|
-
inline ULID Create(std::chrono::time_point<std::chrono::system_clock> timestamp, const std::function<uint8_t()>& rng) {
|
|
366
|
-
ULID ulid;
|
|
367
|
-
Encode(timestamp, rng, ulid);
|
|
368
|
-
return ulid;
|
|
55
|
+
inline void EncodeTimeSystemClockNow(ULID& ulid)
|
|
56
|
+
{
|
|
57
|
+
EncodeTime(std::chrono::system_clock::now(), ulid);
|
|
369
58
|
}
|
|
370
59
|
|
|
371
|
-
|
|
372
60
|
/**
|
|
373
|
-
*
|
|
61
|
+
* EncodeEntropyMt19937Fast will encode using std::mt19937
|
|
62
|
+
* with only 3 generated values.
|
|
374
63
|
* */
|
|
375
|
-
inline ULID
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
64
|
+
inline void EncodeEntropyMt19937Fast(ULID& ulid)
|
|
65
|
+
{
|
|
66
|
+
static thread_local std::mt19937 gen([]() {
|
|
67
|
+
// Use multiple entropy sources for seeding
|
|
68
|
+
std::array<uint32_t, 3> seed_data = {
|
|
69
|
+
static_cast<uint32_t>(std::chrono::high_resolution_clock::now().time_since_epoch().count()),
|
|
70
|
+
static_cast<uint32_t>(std::random_device {}()),
|
|
71
|
+
static_cast<uint32_t>(std::hash<std::thread::id> {}(std::this_thread::get_id()))
|
|
72
|
+
};
|
|
73
|
+
std::seed_seq seed_seq(seed_data.begin(), seed_data.end());
|
|
74
|
+
return std::mt19937(seed_seq);
|
|
75
|
+
}());
|
|
76
|
+
uint64_t high = (static_cast<uint64_t>(gen()) << 32) | gen();
|
|
77
|
+
uint32_t low = gen();
|
|
78
|
+
ulid.data[6] = (high >> 40) & 0xFF;
|
|
79
|
+
ulid.data[7] = (high >> 32) & 0xFF;
|
|
80
|
+
ulid.data[8] = (high >> 24) & 0xFF;
|
|
81
|
+
ulid.data[9] = (high >> 16) & 0xFF;
|
|
82
|
+
ulid.data[10] = (high >> 8) & 0xFF;
|
|
83
|
+
ulid.data[11] = high & 0xFF;
|
|
84
|
+
ulid.data[12] = (low >> 24) & 0xFF;
|
|
85
|
+
ulid.data[13] = (low >> 16) & 0xFF;
|
|
86
|
+
ulid.data[14] = (low >> 8) & 0xFF;
|
|
87
|
+
ulid.data[15] = low & 0xFF;
|
|
379
88
|
}
|
|
380
89
|
|
|
381
90
|
/**
|
|
@@ -404,80 +113,63 @@ static const char Encoding[33] = "0123456789ABCDEFGHJKMNPQRSTVWXYZ";
|
|
|
404
113
|
* entropy:
|
|
405
114
|
* follows similarly, except now all components are set to 5 bits.
|
|
406
115
|
* */
|
|
407
|
-
inline void MarshalTo(const ULID& ulid, char dst[26])
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
/**
|
|
440
|
-
* Marshal will marshal a ULID to a std::string.
|
|
441
|
-
* */
|
|
442
|
-
inline std::string Marshal(const ULID& ulid) {
|
|
443
|
-
char data[27];
|
|
444
|
-
data[26] = '\0';
|
|
445
|
-
MarshalTo(ulid, data);
|
|
446
|
-
return std::string(data);
|
|
116
|
+
inline void MarshalTo(const ULID& ulid, char dst[26])
|
|
117
|
+
{
|
|
118
|
+
// 10 byte timestamp
|
|
119
|
+
dst[0] = Encoding[(ulid.data[0] & 224) >> 5];
|
|
120
|
+
dst[1] = Encoding[ulid.data[0] & 31];
|
|
121
|
+
dst[2] = Encoding[(ulid.data[1] & 248) >> 3];
|
|
122
|
+
dst[3] = Encoding[((ulid.data[1] & 7) << 2) | ((ulid.data[2] & 192) >> 6)];
|
|
123
|
+
dst[4] = Encoding[(ulid.data[2] & 62) >> 1];
|
|
124
|
+
dst[5] = Encoding[((ulid.data[2] & 1) << 4) | ((ulid.data[3] & 240) >> 4)];
|
|
125
|
+
dst[6] = Encoding[((ulid.data[3] & 15) << 1) | ((ulid.data[4] & 128) >> 7)];
|
|
126
|
+
dst[7] = Encoding[(ulid.data[4] & 124) >> 2];
|
|
127
|
+
dst[8] = Encoding[((ulid.data[4] & 3) << 3) | ((ulid.data[5] & 224) >> 5)];
|
|
128
|
+
dst[9] = Encoding[ulid.data[5] & 31];
|
|
129
|
+
|
|
130
|
+
// 16 bytes of entropy
|
|
131
|
+
dst[10] = Encoding[(ulid.data[6] & 248) >> 3];
|
|
132
|
+
dst[11] = Encoding[((ulid.data[6] & 7) << 2) | ((ulid.data[7] & 192) >> 6)];
|
|
133
|
+
dst[12] = Encoding[(ulid.data[7] & 62) >> 1];
|
|
134
|
+
dst[13] = Encoding[((ulid.data[7] & 1) << 4) | ((ulid.data[8] & 240) >> 4)];
|
|
135
|
+
dst[14] = Encoding[((ulid.data[8] & 15) << 1) | ((ulid.data[9] & 128) >> 7)];
|
|
136
|
+
dst[15] = Encoding[(ulid.data[9] & 124) >> 2];
|
|
137
|
+
dst[16] = Encoding[((ulid.data[9] & 3) << 3) | ((ulid.data[10] & 224) >> 5)];
|
|
138
|
+
dst[17] = Encoding[ulid.data[10] & 31];
|
|
139
|
+
dst[18] = Encoding[(ulid.data[11] & 248) >> 3];
|
|
140
|
+
dst[19] = Encoding[((ulid.data[11] & 7) << 2) | ((ulid.data[12] & 192) >> 6)];
|
|
141
|
+
dst[20] = Encoding[(ulid.data[12] & 62) >> 1];
|
|
142
|
+
dst[21] = Encoding[((ulid.data[12] & 1) << 4) | ((ulid.data[13] & 240) >> 4)];
|
|
143
|
+
dst[22] = Encoding[((ulid.data[13] & 15) << 1) | ((ulid.data[14] & 128) >> 7)];
|
|
144
|
+
dst[23] = Encoding[(ulid.data[14] & 124) >> 2];
|
|
145
|
+
dst[24] = Encoding[((ulid.data[14] & 3) << 3) | ((ulid.data[15] & 224) >> 5)];
|
|
146
|
+
dst[25] = Encoding[ulid.data[15] & 31];
|
|
447
147
|
}
|
|
448
148
|
|
|
449
149
|
/**
|
|
450
150
|
* MarshalBinaryTo will Marshal a ULID to the passed byte array
|
|
451
151
|
* */
|
|
452
|
-
inline void MarshalBinaryTo(const ULID& ulid, uint8_t dst[16])
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
/**
|
|
475
|
-
* MarshalBinary will Marshal a ULID to a byte vector.
|
|
476
|
-
* */
|
|
477
|
-
inline std::vector<uint8_t> MarshalBinary(const ULID& ulid) {
|
|
478
|
-
std::vector<uint8_t> dst(16);
|
|
479
|
-
MarshalBinaryTo(ulid, dst.data());
|
|
480
|
-
return dst;
|
|
152
|
+
inline void MarshalBinaryTo(const ULID& ulid, uint8_t dst[16])
|
|
153
|
+
{
|
|
154
|
+
// timestamp
|
|
155
|
+
dst[0] = ulid.data[0];
|
|
156
|
+
dst[1] = ulid.data[1];
|
|
157
|
+
dst[2] = ulid.data[2];
|
|
158
|
+
dst[3] = ulid.data[3];
|
|
159
|
+
dst[4] = ulid.data[4];
|
|
160
|
+
dst[5] = ulid.data[5];
|
|
161
|
+
|
|
162
|
+
// entropy
|
|
163
|
+
dst[6] = ulid.data[6];
|
|
164
|
+
dst[7] = ulid.data[7];
|
|
165
|
+
dst[8] = ulid.data[8];
|
|
166
|
+
dst[9] = ulid.data[9];
|
|
167
|
+
dst[10] = ulid.data[10];
|
|
168
|
+
dst[11] = ulid.data[11];
|
|
169
|
+
dst[12] = ulid.data[12];
|
|
170
|
+
dst[13] = ulid.data[13];
|
|
171
|
+
dst[14] = ulid.data[14];
|
|
172
|
+
dst[15] = ulid.data[15];
|
|
481
173
|
}
|
|
482
174
|
|
|
483
175
|
/**
|
|
@@ -487,230 +179,105 @@ inline std::vector<uint8_t> MarshalBinary(const ULID& ulid) {
|
|
|
487
179
|
* 65-90 are capital alphabets.
|
|
488
180
|
* */
|
|
489
181
|
static const uint8_t dec[256] = {
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
182
|
+
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
183
|
+
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
184
|
+
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
185
|
+
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
186
|
+
|
|
187
|
+
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
188
|
+
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
189
|
+
/* 0 1 2 3 4 5 6 7 */
|
|
190
|
+
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
|
191
|
+
/* 8 9 */
|
|
192
|
+
0x08, 0x09, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
193
|
+
|
|
194
|
+
/* 10(A) 11(B) 12(C) 13(D) 14(E) 15(F) 16(G) */
|
|
195
|
+
0xFF, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10,
|
|
196
|
+
/*17(H) 18(J) 19(K) 20(M) 21(N) */
|
|
197
|
+
0x11, 0xFF, 0x12, 0x13, 0xFF, 0x14, 0x15, 0xFF,
|
|
198
|
+
/*22(P)23(Q)24(R) 25(S) 26(T) 27(V) 28(W) */
|
|
199
|
+
0x16, 0x17, 0x18, 0x19, 0x1A, 0xFF, 0x1B, 0x1C,
|
|
200
|
+
/*29(X)30(Y)31(Z) */
|
|
201
|
+
0x1D, 0x1E, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
202
|
+
|
|
203
|
+
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
204
|
+
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
205
|
+
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
206
|
+
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
207
|
+
|
|
208
|
+
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
209
|
+
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
210
|
+
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
211
|
+
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
212
|
+
|
|
213
|
+
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
214
|
+
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
215
|
+
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
216
|
+
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
217
|
+
|
|
218
|
+
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
219
|
+
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
220
|
+
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
221
|
+
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
222
|
+
|
|
223
|
+
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
224
|
+
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
225
|
+
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
|
226
|
+
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
|
|
535
227
|
};
|
|
536
228
|
|
|
537
229
|
/**
|
|
538
230
|
* UnmarshalFrom will unmarshal a ULID from the passed character array.
|
|
539
231
|
* */
|
|
540
|
-
inline void UnmarshalFrom(const char str[26], ULID& ulid)
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
/**
|
|
563
|
-
* Unmarshal will create a new ULID by unmarshaling the passed string.
|
|
564
|
-
* */
|
|
565
|
-
inline ULID Unmarshal(const std::string& str) {
|
|
566
|
-
ULID ulid;
|
|
567
|
-
UnmarshalFrom(str.c_str(), ulid);
|
|
568
|
-
return ulid;
|
|
232
|
+
inline void UnmarshalFrom(const char str[26], ULID& ulid)
|
|
233
|
+
{
|
|
234
|
+
// timestamp
|
|
235
|
+
ulid.data[0] = (dec[int(str[0])] << 5) | dec[int(str[1])];
|
|
236
|
+
ulid.data[1] = (dec[int(str[2])] << 3) | (dec[int(str[3])] >> 2);
|
|
237
|
+
ulid.data[2] = (dec[int(str[3])] << 6) | (dec[int(str[4])] << 1) | (dec[int(str[5])] >> 4);
|
|
238
|
+
ulid.data[3] = (dec[int(str[5])] << 4) | (dec[int(str[6])] >> 1);
|
|
239
|
+
ulid.data[4] = (dec[int(str[6])] << 7) | (dec[int(str[7])] << 2) | (dec[int(str[8])] >> 3);
|
|
240
|
+
ulid.data[5] = (dec[int(str[8])] << 5) | dec[int(str[9])];
|
|
241
|
+
|
|
242
|
+
// entropy
|
|
243
|
+
ulid.data[6] = (dec[int(str[10])] << 3) | (dec[int(str[11])] >> 2);
|
|
244
|
+
ulid.data[7] = (dec[int(str[11])] << 6) | (dec[int(str[12])] << 1) | (dec[int(str[13])] >> 4);
|
|
245
|
+
ulid.data[8] = (dec[int(str[13])] << 4) | (dec[int(str[14])] >> 1);
|
|
246
|
+
ulid.data[9] = (dec[int(str[14])] << 7) | (dec[int(str[15])] << 2) | (dec[int(str[16])] >> 3);
|
|
247
|
+
ulid.data[10] = (dec[int(str[16])] << 5) | dec[int(str[17])];
|
|
248
|
+
ulid.data[11] = (dec[int(str[18])] << 3) | (dec[int(str[19])] >> 2);
|
|
249
|
+
ulid.data[12] = (dec[int(str[19])] << 6) | (dec[int(str[20])] << 1) | (dec[int(str[21])] >> 4);
|
|
250
|
+
ulid.data[13] = (dec[int(str[21])] << 4) | (dec[int(str[22])] >> 1);
|
|
251
|
+
ulid.data[14] = (dec[int(str[22])] << 7) | (dec[int(str[23])] << 2) | (dec[int(str[24])] >> 3);
|
|
252
|
+
ulid.data[15] = (dec[int(str[24])] << 5) | dec[int(str[25])];
|
|
569
253
|
}
|
|
570
254
|
|
|
571
255
|
/**
|
|
572
256
|
* UnmarshalBinaryFrom will unmarshal a ULID from the passed byte array.
|
|
573
257
|
* */
|
|
574
|
-
inline void UnmarshalBinaryFrom(const uint8_t b[16], ULID& ulid)
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
/**
|
|
597
|
-
* Unmarshal will create a new ULID by unmarshaling the passed byte vector.
|
|
598
|
-
* */
|
|
599
|
-
inline ULID UnmarshalBinary(const std::vector<uint8_t>& b) {
|
|
600
|
-
ULID ulid;
|
|
601
|
-
UnmarshalBinaryFrom(b.data(), ulid);
|
|
602
|
-
return ulid;
|
|
603
|
-
}
|
|
604
|
-
|
|
605
|
-
/**
|
|
606
|
-
* CompareULIDs will compare two ULIDs.
|
|
607
|
-
* returns:
|
|
608
|
-
* -1 if ulid1 is Lexicographically before ulid2
|
|
609
|
-
* 1 if ulid1 is Lexicographically after ulid2
|
|
610
|
-
* 0 if ulid1 is same as ulid2
|
|
611
|
-
* */
|
|
612
|
-
inline int CompareULIDs(const ULID& ulid1, const ULID& ulid2) {
|
|
613
|
-
// for (int i = 0 ; i < 16 ; i++) {
|
|
614
|
-
// if (ulid1.data[i] != ulid2.data[i]) {
|
|
615
|
-
// return (ulid1.data[i] < ulid2.data[i]) * -2 + 1;
|
|
616
|
-
// }
|
|
617
|
-
// }
|
|
618
|
-
|
|
619
|
-
// unrolled loop
|
|
620
|
-
|
|
621
|
-
if (ulid1.data[0] != ulid2.data[0]) {
|
|
622
|
-
return (ulid1.data[0] < ulid2.data[0]) * -2 + 1;
|
|
623
|
-
}
|
|
624
|
-
|
|
625
|
-
if (ulid1.data[1] != ulid2.data[1]) {
|
|
626
|
-
return (ulid1.data[1] < ulid2.data[1]) * -2 + 1;
|
|
627
|
-
}
|
|
628
|
-
|
|
629
|
-
if (ulid1.data[2] != ulid2.data[2]) {
|
|
630
|
-
return (ulid1.data[2] < ulid2.data[2]) * -2 + 1;
|
|
631
|
-
}
|
|
632
|
-
|
|
633
|
-
if (ulid1.data[3] != ulid2.data[3]) {
|
|
634
|
-
return (ulid1.data[3] < ulid2.data[3]) * -2 + 1;
|
|
635
|
-
}
|
|
636
|
-
|
|
637
|
-
if (ulid1.data[4] != ulid2.data[4]) {
|
|
638
|
-
return (ulid1.data[4] < ulid2.data[4]) * -2 + 1;
|
|
639
|
-
}
|
|
640
|
-
|
|
641
|
-
if (ulid1.data[5] != ulid2.data[5]) {
|
|
642
|
-
return (ulid1.data[5] < ulid2.data[5]) * -2 + 1;
|
|
643
|
-
}
|
|
644
|
-
|
|
645
|
-
if (ulid1.data[6] != ulid2.data[6]) {
|
|
646
|
-
return (ulid1.data[6] < ulid2.data[6]) * -2 + 1;
|
|
647
|
-
}
|
|
648
|
-
|
|
649
|
-
if (ulid1.data[7] != ulid2.data[7]) {
|
|
650
|
-
return (ulid1.data[7] < ulid2.data[7]) * -2 + 1;
|
|
651
|
-
}
|
|
652
|
-
|
|
653
|
-
if (ulid1.data[8] != ulid2.data[8]) {
|
|
654
|
-
return (ulid1.data[8] < ulid2.data[8]) * -2 + 1;
|
|
655
|
-
}
|
|
656
|
-
|
|
657
|
-
if (ulid1.data[9] != ulid2.data[9]) {
|
|
658
|
-
return (ulid1.data[9] < ulid2.data[9]) * -2 + 1;
|
|
659
|
-
}
|
|
660
|
-
|
|
661
|
-
if (ulid1.data[10] != ulid2.data[10]) {
|
|
662
|
-
return (ulid1.data[10] < ulid2.data[10]) * -2 + 1;
|
|
663
|
-
}
|
|
664
|
-
|
|
665
|
-
if (ulid1.data[11] != ulid2.data[11]) {
|
|
666
|
-
return (ulid1.data[11] < ulid2.data[11]) * -2 + 1;
|
|
667
|
-
}
|
|
668
|
-
|
|
669
|
-
if (ulid1.data[12] != ulid2.data[12]) {
|
|
670
|
-
return (ulid1.data[12] < ulid2.data[12]) * -2 + 1;
|
|
671
|
-
}
|
|
672
|
-
|
|
673
|
-
if (ulid1.data[13] != ulid2.data[13]) {
|
|
674
|
-
return (ulid1.data[13] < ulid2.data[13]) * -2 + 1;
|
|
675
|
-
}
|
|
676
|
-
|
|
677
|
-
if (ulid1.data[14] != ulid2.data[14]) {
|
|
678
|
-
return (ulid1.data[14] < ulid2.data[14]) * -2 + 1;
|
|
679
|
-
}
|
|
680
|
-
|
|
681
|
-
if (ulid1.data[15] != ulid2.data[15]) {
|
|
682
|
-
return (ulid1.data[15] < ulid2.data[15]) * -2 + 1;
|
|
683
|
-
}
|
|
684
|
-
|
|
685
|
-
return 0;
|
|
686
|
-
}
|
|
687
|
-
|
|
688
|
-
/**
|
|
689
|
-
* Time will extract the timestamp used to generate a ULID
|
|
690
|
-
* */
|
|
691
|
-
inline std::chrono::time_point<std::chrono::system_clock> Time(const ULID& ulid) {
|
|
692
|
-
int64_t ans = 0;
|
|
693
|
-
|
|
694
|
-
ans |= ulid.data[0];
|
|
695
|
-
|
|
696
|
-
ans <<= 8;
|
|
697
|
-
ans |= ulid.data[1];
|
|
698
|
-
|
|
699
|
-
ans <<= 8;
|
|
700
|
-
ans |= ulid.data[2];
|
|
701
|
-
|
|
702
|
-
ans <<= 8;
|
|
703
|
-
ans |= ulid.data[3];
|
|
704
|
-
|
|
705
|
-
ans <<= 8;
|
|
706
|
-
ans |= ulid.data[4];
|
|
707
|
-
|
|
708
|
-
ans <<= 8;
|
|
709
|
-
ans |= ulid.data[5];
|
|
710
|
-
|
|
711
|
-
return std::chrono::time_point<std::chrono::system_clock>(std::chrono::milliseconds{ans});
|
|
258
|
+
inline void UnmarshalBinaryFrom(const uint8_t b[16], ULID& ulid)
|
|
259
|
+
{
|
|
260
|
+
// timestamp
|
|
261
|
+
ulid.data[0] = b[0];
|
|
262
|
+
ulid.data[1] = b[1];
|
|
263
|
+
ulid.data[2] = b[2];
|
|
264
|
+
ulid.data[3] = b[3];
|
|
265
|
+
ulid.data[4] = b[4];
|
|
266
|
+
ulid.data[5] = b[5];
|
|
267
|
+
|
|
268
|
+
// entropy
|
|
269
|
+
ulid.data[6] = b[6];
|
|
270
|
+
ulid.data[7] = b[7];
|
|
271
|
+
ulid.data[8] = b[8];
|
|
272
|
+
ulid.data[9] = b[9];
|
|
273
|
+
ulid.data[10] = b[10];
|
|
274
|
+
ulid.data[11] = b[11];
|
|
275
|
+
ulid.data[12] = b[12];
|
|
276
|
+
ulid.data[13] = b[13];
|
|
277
|
+
ulid.data[14] = b[14];
|
|
278
|
+
ulid.data[15] = b[15];
|
|
712
279
|
}
|
|
713
280
|
|
|
714
|
-
};
|
|
281
|
+
}; // namespace ulid
|
|
715
282
|
|
|
716
283
|
#endif // ULID_STRUCT_HH
|