26#ifndef SCRU128_H_AVJRBJQI
27#define SCRU128_H_AVJRBJQI
34#define SCRU128_LEN (16)
40#define SCRU128_STR_LEN (26)
52#define SCRU128_GENERATOR_STATUS_NEW_TIMESTAMP (1)
58#define SCRU128_GENERATOR_STATUS_COUNTER_LO_INC (2)
64#define SCRU128_GENERATOR_STATUS_COUNTER_HI_INC (3)
70#define SCRU128_GENERATOR_STATUS_TIMESTAMP_INC (4)
77#define SCRU128_GENERATOR_STATUS_ROLLBACK_RESET (5)
80#define SCRU128_GENERATOR_STATUS_ERROR (-1)
86#define SCRU128_GENERATOR_STATUS_ROLLBACK_ABORT (-2)
101 uint32_t _counter_hi;
104 uint32_t _counter_lo;
111 uint64_t _ts_counter_hi;
115static const uint64_t SCRU128_MAX_TIMESTAMP = 0xffffffffffff;
118static const uint32_t SCRU128_MAX_COUNTER_HI = 0xffffff;
121static const uint32_t SCRU128_MAX_COUNTER_LO = 0xffffff;
148 uint32_t counter_hi, uint32_t counter_lo,
150 if (timestamp > SCRU128_MAX_TIMESTAMP ||
151 counter_hi > SCRU128_MAX_COUNTER_HI ||
152 counter_lo > SCRU128_MAX_COUNTER_LO) {
156 id_out[0] = timestamp >> 40;
157 id_out[1] = timestamp >> 32;
158 id_out[2] = timestamp >> 24;
159 id_out[3] = timestamp >> 16;
160 id_out[4] = timestamp >> 8;
161 id_out[5] = timestamp;
162 id_out[6] = counter_hi >> 16;
163 id_out[7] = counter_hi >> 8;
164 id_out[8] = counter_hi;
165 id_out[9] = counter_lo >> 16;
166 id_out[10] = counter_lo >> 8;
167 id_out[11] = counter_lo;
168 id_out[12] = entropy >> 24;
169 id_out[13] = entropy >> 16;
170 id_out[14] = entropy >> 8;
171 id_out[15] = entropy;
181static inline void scru128_copy(uint8_t *id_dst,
const uint8_t *id_src) {
183 id_dst[i] = id_src[i];
198 for (int_fast8_t i = 0; i < 25; i++) {
201 src[i] = ( c ==
'0' ? 0 : c ==
'1' ? 1 : c ==
'2' ? 2 : c ==
'3' ? 3
202 : c ==
'4' ? 4 : c ==
'5' ? 5 : c ==
'6' ? 6 : c ==
'7' ? 7
203 : c ==
'8' ? 8 : c ==
'9' ? 9 : c ==
'A' ? 10 : c ==
'B' ? 11
204 : c ==
'C' ? 12 : c ==
'D' ? 13 : c ==
'E' ? 14 : c ==
'F' ? 15
205 : c ==
'G' ? 16 : c ==
'H' ? 17 : c ==
'I' ? 18 : c ==
'J' ? 19
206 : c ==
'K' ? 20 : c ==
'L' ? 21 : c ==
'M' ? 22 : c ==
'N' ? 23
207 : c ==
'O' ? 24 : c ==
'P' ? 25 : c ==
'Q' ? 26 : c ==
'R' ? 27
208 : c ==
'S' ? 28 : c ==
'T' ? 29 : c ==
'U' ? 30 : c ==
'V' ? 31
209 : c ==
'W' ? 32 : c ==
'X' ? 33 : c ==
'Y' ? 34 : c ==
'Z' ? 35
210 : c ==
'a' ? 10 : c ==
'b' ? 11 : c ==
'c' ? 12 : c ==
'd' ? 13
211 : c ==
'e' ? 14 : c ==
'f' ? 15 : c ==
'g' ? 16 : c ==
'h' ? 17
212 : c ==
'i' ? 18 : c ==
'j' ? 19 : c ==
'k' ? 20 : c ==
'l' ? 21
213 : c ==
'm' ? 22 : c ==
'n' ? 23 : c ==
'o' ? 24 : c ==
'p' ? 25
214 : c ==
'q' ? 26 : c ==
'r' ? 27 : c ==
's' ? 28 : c ==
't' ? 29
215 : c ==
'u' ? 30 : c ==
'v' ? 31 : c ==
'w' ? 32 : c ==
'x' ? 33
216 : c ==
'y' ? 34 : c ==
'z' ? 35 : 0xff);
218 if (src[i] == 0xff) {
230 int_fast8_t min_index = 99;
231 for (int_fast8_t i = -5; i < 25; i += 10) {
234 for (int_fast8_t j = i < 0 ? 0 : i; j < i + 10; j++) {
235 carry = (carry * 36) + src[j];
241 for (; carry > 0 || j > min_index; j--) {
245 carry += (uint64_t)id_out[j] * 3656158440062976;
246 id_out[j] = (uint8_t)carry;
260 return (uint64_t)
id[0] << 40 | (uint64_t)
id[1] << 32 | (uint64_t)
id[2] << 24 |
261 (uint64_t)
id[3] << 16 | (uint64_t)
id[4] << 8 | (uint64_t)
id[5];
270 return (uint32_t)
id[6] << 16 | (uint32_t)
id[7] << 8 | (uint32_t)
id[8];
279 return (uint32_t)
id[9] << 16 | (uint32_t)
id[10] << 8 | (uint32_t)
id[11];
288 return (uint32_t)
id[12] << 24 | (uint32_t)
id[13] << 16 |
289 (uint32_t)
id[14] << 8 | (uint32_t)
id[15];
301 static const char DIGITS[] =
"0123456789abcdefghijklmnopqrstuvwxyz";
304 for (int_fast8_t i = 0; i < 26; i++) {
308 int_fast8_t min_index = 99;
309 for (int_fast8_t i = -5; i <
SCRU128_LEN; i += 7) {
312 for (int_fast8_t j = i < 0 ? 0 : i; j < i + 7; j++) {
313 carry = (carry << 8) |
id[j];
319 for (; carry > 0 || j > min_index; j--) {
320 carry += (uint64_t)str_out[j] << 56;
321 str_out[j] = carry % 36;
327 for (int_fast8_t i = 0; i < 25; i++) {
328 str_out[i] = DIGITS[(
unsigned char)str_out[i]];
340 const uint8_t *id_rgt) {
342 if (id_lft[i] != id_rgt[i]) {
343 return id_lft[i] < id_rgt[i] ? -1 : 1;
362 g->_ts_counter_hi = 0;
393 uint64_t timestamp, uint32_t (*arc4random)(
void),
394 uint64_t rollback_allowance) {
395 if (timestamp == 0 || timestamp > SCRU128_MAX_TIMESTAMP) {
397 }
else if (rollback_allowance > SCRU128_MAX_TIMESTAMP) {
402 if (timestamp > g->_timestamp) {
403 g->_timestamp = timestamp;
404 g->_counter_lo = (*arc4random)() & SCRU128_MAX_COUNTER_LO;
405 }
else if (timestamp + rollback_allowance >= g->_timestamp) {
409 if (g->_counter_lo > SCRU128_MAX_COUNTER_LO) {
413 if (g->_counter_hi > SCRU128_MAX_COUNTER_HI) {
417 g->_counter_lo = (*arc4random)() & SCRU128_MAX_COUNTER_LO;
426 if (g->_timestamp - g->_ts_counter_hi >= 1000 || g->_ts_counter_hi == 0) {
427 g->_ts_counter_hi = g->_timestamp;
428 g->_counter_hi = (*arc4random)() & SCRU128_MAX_COUNTER_HI;
432 (*arc4random)()) == 0) {
468 uint64_t timestamp, uint32_t (*arc4random)(
void),
469 uint64_t rollback_allowance) {
471 g, id_out, timestamp, arc4random, rollback_allowance);
475 g->_ts_counter_hi = 0;
int scru128_generate(Scru128Generator *g, uint8_t *id_out)
Generates a new SCRU128 ID from the current timestamp.
static int scru128_from_fields(uint8_t *id_out, uint64_t timestamp, uint32_t counter_hi, uint32_t counter_lo, uint32_t entropy)
Creates a SCRU128 ID from field values.
Definition scru128.h:147
#define SCRU128_GENERATOR_STATUS_ROLLBACK_ABORT
Indicates that the previous generation was aborted because the latest timestamp was significantly sma...
Definition scru128.h:86
static uint32_t scru128_entropy(const uint8_t *id)
Returns the 32-bit entropy field value of a SCRU128 ID.
Definition scru128.h:287
static int8_t scru128_generate_or_reset_core(Scru128Generator *g, uint8_t *id_out, uint64_t timestamp, uint32_t(*arc4random)(void), uint64_t rollback_allowance)
Generates a new SCRU128 ID with the given timestamp and random number generator, or resets the genera...
Definition scru128.h:467
static int scru128_compare(const uint8_t *id_lft, const uint8_t *id_rgt)
Returns a negative integer, zero, or positive integer if id_lft is less than, equal to,...
Definition scru128.h:339
#define SCRU128_GENERATOR_STATUS_TIMESTAMP_INC
Indicates that the previous timestamp was incremented because counter_hi reached its maximum value.
Definition scru128.h:70
static uint32_t scru128_counter_hi(const uint8_t *id)
Returns the 24-bit counter_hi field value of a SCRU128 ID.
Definition scru128.h:269
#define SCRU128_GENERATOR_STATUS_ROLLBACK_RESET
Indicates that the generator was reinitialized and the monotonic order of generated IDs was broken be...
Definition scru128.h:77
static void scru128_copy(uint8_t *id_dst, const uint8_t *id_src)
Copies a SCRU128 ID from id_src to id_dst.
Definition scru128.h:181
#define SCRU128_GENERATOR_STATUS_COUNTER_LO_INC
Indicates that counter_lo was incremented because the latest timestamp was no greater than the previo...
Definition scru128.h:58
#define SCRU128_GENERATOR_STATUS_ERROR
Indicates that the previous generation failed.
Definition scru128.h:80
#define SCRU128_LEN
The size in bytes of a SCRU128 ID in the binary representation (16 bytes).
Definition scru128.h:34
static int scru128_generate_string(Scru128Generator *g, char *str_out)
Generates a new SCRU128 ID encoded in the 25-digit canonical string representation.
Definition scru128.h:523
#define SCRU128_GENERATOR_STATUS_COUNTER_HI_INC
Indicates that counter_hi was incremented because counter_lo reached its maximum value.
Definition scru128.h:64
static int scru128_from_str(uint8_t *id_out, const char *str)
Creates a SCRU128 ID from a 25-digit string representation.
Definition scru128.h:196
static uint32_t scru128_counter_lo(const uint8_t *id)
Returns the 24-bit counter_lo field value of a SCRU128 ID.
Definition scru128.h:278
static void scru128_to_str(const uint8_t *id, char *str_out)
Returns the 25-digit canonical string representation of a SCRU128 ID.
Definition scru128.h:300
static uint64_t scru128_timestamp(const uint8_t *id)
Returns the 48-bit timestamp field value of a SCRU128 ID.
Definition scru128.h:259
#define SCRU128_GENERATOR_STATUS_NEW_TIMESTAMP
Indicates that the latest timestamp was used because it was greater than the previous one.
Definition scru128.h:52
static void scru128_generator_init(Scru128Generator *g)
Initializes a generator struct g.
Definition scru128.h:358
static int8_t scru128_generate_or_abort_core(Scru128Generator *g, uint8_t *id_out, uint64_t timestamp, uint32_t(*arc4random)(void), uint64_t rollback_allowance)
Generates a new SCRU128 ID with the given timestamp and random number generator, or returns an error ...
Definition scru128.h:392
Represents a SCRU128 ID generator that encapsulates the monotonic counter and other internal states.
Definition scru128.h:96