Skip to content

Commit 1f2e709

Browse files
committed
Add UUIDv7; make UUIDv4 API compat with UUIDv7
1 parent 2e9d224 commit 1f2e709

File tree

3 files changed

+284
-54
lines changed

3 files changed

+284
-54
lines changed

README.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,8 @@ own ECL bundle. Please see
4848
* [ScopeContentsAsTempSuperFile.ecl](ScopeContentsAsTempSuperFile.ecl)
4949
* [Sets.ecl](Sets.ecl)
5050
* [Str.ecl](Str.ecl)
51-
* [UUID.ecl](UUID.ecl)
51+
* [UUIDv4.ecl](UUIDv4.ecl)
52+
* [UUIDv7.ecl](UUIDv7.ecl)
5253
* [VersionStringCompare.ecl](VersionStringCompare.ecl)
5354
* [VerticalSlice.ecl](VerticalSlice.ecl)
5455
* [WholeUpdate.ecl](WholeUpdate.ecl)

UUID.ecl UUIDv4.ecl

+53-53
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,12 @@
3030
* NullValueStr()
3131
* IsNullValueBin(CONST UUIDBin_t uuid)
3232
* IsNullValueStr(CONST UUIDStr_t uuid)
33-
* AsString(CONST UUIDBin_t uuid)
34-
* AsBinary(CONST UUIDStr_t uuid)
33+
* AsStr(CONST UUIDBin_t uuid)
34+
* AsBin(CONST UUIDStr_t uuid)
3535
*
3636
* Origin: https://github.com/hpccsystems-solutions-lab/Useful_ECL
3737
*/
38-
EXPORT UUID := MODULE
38+
EXPORT UUIDv4 := MODULE
3939

4040
/**
4141
* Exported Data Types
@@ -62,6 +62,56 @@ EXPORT UUID := MODULE
6262
memcpy(__result, newValue, sizeof(uuid_t));
6363
ENDEMBED;
6464

65+
/**
66+
* Convert a binary UUID value to its human-readable string version.
67+
*
68+
* @param uuid The binary UUID value to convert.
69+
*
70+
* @return A new UUIDStr_t value.
71+
*
72+
* @see AsBin
73+
*/
74+
EXPORT UUIDStr_t AsStr(CONST UUIDBin_t uuid) := EMBED(c++)
75+
#option library uuid
76+
#option pure;
77+
#include <uuid/uuid.h>
78+
79+
#body
80+
81+
char buffer[37];
82+
83+
uuid_unparse(static_cast<const unsigned char*>(uuid), buffer);
84+
memcpy(__result, buffer, 36);
85+
ENDEMBED;
86+
87+
/**
88+
* Convert a string UUID value to its compact binary version.
89+
*
90+
* @param uuid The string UUID value to convert.
91+
*
92+
* @return A new UUIDBin_t value. If the argument is not a valid UUID
93+
* then a (binary null UUID will be returned.
94+
*
95+
* @see AsStr
96+
*/
97+
EXPORT UUIDBin_t AsBin(CONST UUIDStr_t uuid) := EMBED(c++)
98+
#option library uuid
99+
#option pure;
100+
#include <uuid/uuid.h>
101+
102+
#body
103+
104+
char buffer[37];
105+
uuid_t parsedValue;
106+
107+
memcpy(buffer, uuid, 36);
108+
buffer[36] = 0;
109+
if (uuid_parse(buffer, parsedValue) != 0)
110+
uuid_clear(parsedValue);
111+
112+
memcpy(__result, parsedValue, 16);
113+
ENDEMBED;
114+
65115
/**
66116
* Create a new UUID value in human-readable string form.
67117
*
@@ -171,54 +221,4 @@ EXPORT UUID := MODULE
171221
return uuid_is_null(parsedValue) == 1;
172222
ENDEMBED;
173223

174-
/**
175-
* Convert a binary UUID value to its human-readable string version.
176-
*
177-
* @param uuid The binary UUID value to convert.
178-
*
179-
* @return A new UUIDStr_t value.
180-
*
181-
* @see AsBinary
182-
*/
183-
EXPORT UUIDStr_t AsString(CONST UUIDBin_t uuid) := EMBED(c++)
184-
#option library uuid
185-
#option pure;
186-
#include <uuid/uuid.h>
187-
188-
#body
189-
190-
char buffer[37];
191-
192-
uuid_unparse(static_cast<const unsigned char*>(uuid), buffer);
193-
memcpy(__result, buffer, 36);
194-
ENDEMBED;
195-
196-
/**
197-
* Convert a string UUID value to its compact binary version.
198-
*
199-
* @param uuid The string UUID value to convert.
200-
*
201-
* @return A new UUIDBin_t value. If the argument is not a valid UUID
202-
* then a (binary null UUID will be returned.
203-
*
204-
* @see AsString
205-
*/
206-
EXPORT UUIDBin_t AsBinary(CONST UUIDStr_t uuid) := EMBED(c++)
207-
#option library uuid
208-
#option pure;
209-
#include <uuid/uuid.h>
210-
211-
#body
212-
213-
char buffer[37];
214-
uuid_t parsedValue;
215-
216-
memcpy(buffer, uuid, 36);
217-
buffer[36] = 0;
218-
if (uuid_parse(buffer, parsedValue) != 0)
219-
uuid_clear(parsedValue);
220-
221-
memcpy(__result, parsedValue, 16);
222-
ENDEMBED;
223-
224224
END;

UUIDv7.ecl

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

0 commit comments

Comments
 (0)