26#ifndef UUIDV7_H_BAEDKYFQ
27#define UUIDV7_H_BAEDKYFQ
42#define UUIDV7_STATUS_UNPRECEDENTED (0)
48#define UUIDV7_STATUS_NEW_TIMESTAMP (1)
54#define UUIDV7_STATUS_COUNTER_INC (2)
60#define UUIDV7_STATUS_TIMESTAMP_INC (3)
66#define UUIDV7_STATUS_CLOCK_ROLLBACK (4)
69#define UUIDV7_STATUS_ERR_TIMESTAMP (-1)
75#define UUIDV7_STATUS_ERR_TIMESTAMP_OVERFLOW (-2)
113 const uint8_t *rand_bytes,
114 const uint8_t *uuid_prev) {
115 static const uint64_t MAX_TIMESTAMP = ((uint64_t)1 << 48) - 1;
116 static const uint64_t MAX_COUNTER = ((uint64_t)1 << 42) - 1;
118 if (unix_ts_ms > MAX_TIMESTAMP) {
123 uint64_t timestamp = 0;
124 if (uuid_prev == NULL) {
126 timestamp = unix_ts_ms;
128 for (
int i = 0; i < 6; i++) {
129 timestamp = (timestamp << 8) | uuid_prev[i];
132 if (unix_ts_ms > timestamp) {
134 timestamp = unix_ts_ms;
135 }
else if (unix_ts_ms + 10000 < timestamp) {
138 timestamp = unix_ts_ms;
141 uint64_t counter = uuid_prev[6] & 0x0f;
142 counter = (counter << 8) | uuid_prev[7];
143 counter = (counter << 6) | (uuid_prev[8] & 0x3f);
144 counter = (counter << 8) | uuid_prev[9];
145 counter = (counter << 8) | uuid_prev[10];
146 counter = (counter << 8) | uuid_prev[11];
148 if (counter++ < MAX_COUNTER) {
150 uuid_out[6] = counter >> 38;
151 uuid_out[7] = counter >> 30;
152 uuid_out[8] = counter >> 24;
153 uuid_out[9] = counter >> 16;
154 uuid_out[10] = counter >> 8;
155 uuid_out[11] = counter;
160 if (timestamp > MAX_TIMESTAMP) {
167 uuid_out[0] = timestamp >> 40;
168 uuid_out[1] = timestamp >> 32;
169 uuid_out[2] = timestamp >> 24;
170 uuid_out[3] = timestamp >> 16;
171 uuid_out[4] = timestamp >> 8;
172 uuid_out[5] = timestamp;
175 uuid_out[i] = *rand_bytes++;
178 uuid_out[6] = 0x70 | (uuid_out[6] & 0x0f);
179 uuid_out[8] = 0x80 | (uuid_out[8] & 0x3f);
204 static const char DIGITS[] =
"0123456789abcdef";
205 for (
int i = 0; i < 16; i++) {
206 uint_fast8_t e = uuid[i];
207 *string_out++ = DIGITS[e >> 4];
208 *string_out++ = DIGITS[e & 15];
209 if (i == 3 || i == 5 || i == 7 || i == 9) {
225 for (
int i = 0; i < 32; i++) {
228 uint8_t x = c ==
'0' ? 0 : c ==
'1' ? 1 : c ==
'2' ? 2 : c ==
'3' ? 3
229 : c ==
'4' ? 4 : c ==
'5' ? 5 : c ==
'6' ? 6 : c ==
'7' ? 7
230 : c ==
'8' ? 8 : c ==
'9' ? 9 : c ==
'a' ? 10 : c ==
'b' ? 11
231 : c ==
'c' ? 12 : c ==
'd' ? 13 : c ==
'e' ? 14 : c ==
'f' ? 15
232 : c ==
'A' ? 10 : c ==
'B' ? 11 : c ==
'C' ? 12 : c ==
'D' ? 13
233 : c ==
'E' ? 14 : c ==
'F' ? 15 : 0xff;
240 uuid_out[i >> 1] = x << 4;
242 uuid_out[i >> 1] |= x;
245 if ((i == 7 || i == 11 || i == 15 || i == 19) && (*
string++ !=
'-')) {
249 if (*
string !=
'\0') {
#define UUIDV7_STATUS_ERR_TIMESTAMP
Indicates that an invalid unix_ts_ms is passed.
Definition uuidv7.h:69
static void uuidv7_to_string(const uint8_t *uuid, char *string_out)
Encodes a UUID in the 8-4-4-4-12 hexadecimal string representation.
Definition uuidv7.h:203
#define UUIDV7_STATUS_COUNTER_INC
Indicates that the counter was incremented because the unix_ts_ms passed was no greater than the prev...
Definition uuidv7.h:54
static int8_t uuidv7_generate(uint8_t *uuid_out, uint64_t unix_ts_ms, const uint8_t *rand_bytes, const uint8_t *uuid_prev)
Generates a new UUIDv7 from the given Unix time, random bytes, and previous UUID.
Definition uuidv7.h:112
#define UUIDV7_STATUS_TIMESTAMP_INC
Indicates that the previous unix_ts_ms was incremented because the counter reached its maximum value.
Definition uuidv7.h:60
#define UUIDV7_STATUS_CLOCK_ROLLBACK
Indicates that the monotonic order of generated UUIDs was broken because the unix_ts_ms passed was le...
Definition uuidv7.h:66
static int uuidv7_status_n_rand_consumed(int8_t status)
Determines the number of random bytes consumsed by uuidv7_generate() from the UUIDV7_STATUS_* code re...
Definition uuidv7.h:192
#define UUIDV7_STATUS_ERR_TIMESTAMP_OVERFLOW
Indicates that the attempt to increment the previous unix_ts_ms failed because it had reached its max...
Definition uuidv7.h:75
static int uuidv7_from_string(const char *string, uint8_t *uuid_out)
Decodes the 8-4-4-4-12 hexadecimal string representation of a UUID.
Definition uuidv7.h:224
#define UUIDV7_STATUS_NEW_TIMESTAMP
Indicates that the unix_ts_ms passed was used because it was greater than the previous one.
Definition uuidv7.h:48
#define UUIDV7_STATUS_UNPRECEDENTED
Indicates that the unix_ts_ms passed was used because no preceding UUID was specified.
Definition uuidv7.h:42
static int uuidv7_new_string(char *string_out)
Generates an 8-4-4-4-12 hexadecimal string representation of new UUIDv7.
Definition uuidv7.h:294
int uuidv7_new(uint8_t *uuid_out)
Generates a new UUIDv7 with the current Unix time.