-
Notifications
You must be signed in to change notification settings - Fork 5
/
UUIDv7.ecl
229 lines (198 loc) · 6.42 KB
/
UUIDv7.ecl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
/**
* Set of functions for creating and testing Universally Unique Identifier
* (UUID) values. More information on UUIDs can be found here:
*
* https://en.wikipedia.org/wiki/Universally_unique_identifier
*
* UUIDs can be represented in either a compact 16-byte form or a human-readable
* (and somewhat more portable) 36-character string. There are separate
* functions for creating and testing UUID values in binary or string forms,
* denoted by a 'Bin' or 'Str' suffix. A pair of functions for converting
* binary representations to string and vice-versa are also included.
*
* UUIDv7 is a 128-bit unique identifier like it's older siblings, such as
* the widely used UUIDv4. But unlike v4, UUIDv7 is time-sortable with 1 ms
* precision. By combining the timestamp and the random parts, UUIDv7 becomes
* an excellent choice for record identifiers in databases, including
* distributed ones.
*
* This module is API-compatible with Useful_ECL.UUIDv4.
*
* Exported data types:
*
* UUIDBin_t (DATA16)
* UUIDStr_t (STRING36)
*
* Exported functions:
*
* GenerateBin()
* GenerateStr()
* NullValueBin()
* NullValueStr()
* IsNullValueBin(CONST UUIDBin_t uuid)
* IsNullValueStr(CONST UUIDStr_t uuid)
* AsStr(CONST UUIDBin_t uuid)
* AsBin(CONST UUIDStr_t uuid)
*
* Origin: https://github.com/hpccsystems-solutions-lab/Useful_ECL
*/
EXPORT UUIDv7 := MODULE
/**
* Exported Data Types
*/
EXPORT UUIDBin_t := DATA16;
EXPORT UUIDStr_t := STRING36;
/**
* Create a new UUID value in compact binary form.
*
* @return A new UUIDBin_t value.
*
* @see GenerateStr
*/
EXPORT UUIDBin_t GenerateBin() VOLATILE := EMBED(c++)
#include <array>
#include <chrono>
#include <cstdint>
#include <cstdio>
#include <random>
#body
// random bytes
std::array<uint8_t, 16> value;
for (auto& elem : value)
elem = std::rand() % 256;
// current timestamp in ms
auto now = std::chrono::system_clock::now();
auto millis = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()).count();
// timestamp
value[0] = (millis >> 40) & 0xFF;
value[1] = (millis >> 32) & 0xFF;
value[2] = (millis >> 24) & 0xFF;
value[3] = (millis >> 16) & 0xFF;
value[4] = (millis >> 8) & 0xFF;
value[5] = millis & 0xFF;
// version and variant
value[6] = (value[6] & 0x0F) | 0x70;
value[8] = (value[8] & 0x3F) | 0x80;
memcpy(__result, value.data(), 16);
ENDEMBED;
/**
* Convert a binary UUID value to its human-readable string version.
*
* @param uuid The binary UUID value to convert.
*
* @return A new UUIDStr_t value.
*
* @see AsBin
*/
EXPORT UUIDStr_t AsStr(CONST UUIDBin_t uuid) := EMBED(c++)
#option pure;
#include <iostream>
#include <sstream>
#include <iomanip>
#include <string>
#include <vector>
#body
std::ostringstream oss;
const unsigned char* u = static_cast<const unsigned char*>(uuid);
for (size_t i = 0; i < 16; ++i)
{
if (i == 4 || i == 6 || i == 8 || i == 10)
oss << '-';
oss << std::hex << std::setw(2) << std::setfill('0') << static_cast<int>(u[i]);
}
memcpy(__result, oss.str().data(), 36);
ENDEMBED;
/**
* Convert a string UUID value to its compact binary version.
*
* @param uuid The string UUID value to convert.
*
* @return A new UUIDBin_t value. If the argument is not a valid UUID
* then a (binary null UUID will be returned.
*
* @see AsStr
*/
EXPORT UUIDBin_t AsBin(CONST UUIDStr_t uuid) := EMBED(c++)
#option pure;
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
#include <iomanip>
#include <stdexcept>
uint8_t hexCharToInt(char c)
{
if (c >= '0' && c <= '9') return c - '0';
if (c >= 'a' && c <= 'f') return c - 'a' + 10;
if (c >= 'A' && c <= 'F') return c - 'A' + 10;
throw std::invalid_argument("Invalid hexadecimal character");
}
#body
std::vector<uint8_t> binaryUUID;
binaryUUID.reserve(16);
for (size_t i = 0; i < uuidLen; ++i)
{
if (uuid[i] == '-') continue;
if (i % 2 == 0) {
// Convert two characters to one byte
uint8_t byte = (hexCharToInt(uuid[i]) << 4) | hexCharToInt(uuid[i + 1]);
binaryUUID.push_back(byte);
}
}
memcpy(__result, binaryUUID.data(), 16);
ENDEMBED;
/**
* Create a new UUID value in human-readable string form.
*
* @return A new UUIDStr_t value.
*
* @see GenerateBin
* @see AsString
*/
EXPORT UUIDStr_t GenerateStr() VOLATILE := AsStr(GenerateBin());
/**
* Return the standard "null UUID" value in compact binary form.
*
* @return A null UUIDBin_t value.
*
* @see NullValueStr
*/
EXPORT UUIDBin_t NullValueBin() := EMBED(c++)
#option pure;
#body
memset(__result, 0, 16);
ENDEMBED;
/**
* Return the standard "null UUID" value in human-readable string form.
*
* @return A null UUIDStr_t value.
*
* @see NullValueBin
*/
EXPORT UUIDStr_t NullValueStr() := '00000000-0000-0000-0000-000000000000';
/**
* Test if the given binary UUID value is NULL.
*
* @param uuid The binary UUID value to test.
*
* @return TRUE if the argument is a null UUID value, FALSE otherwise.
*
* @see IsNullValueStr
*/
EXPORT BOOLEAN IsNullValueBin(CONST UUIDBin_t uuid) := EMBED(c++)
#option pure;
#body
std::vector<uint8_t> zeroBlock(16, 0);
return memcmp(uuid, zeroBlock.data(), 16) == 0;
ENDEMBED;
/**
* Test if the given string UUID value is NULL.
*
* @param uuid The string UUID value to test.
*
* @return TRUE if the argument is a null UUID value, FALSE otherwise.
*
* @see IsNullValueBin
*/
EXPORT BOOLEAN IsNullValueStr(CONST UUIDStr_t uuid) := (uuid = NullValueStr());
END;