ulid_fast 0.1.0
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.
- checksums.yaml +7 -0
- data/ext/ulid_fast/extconf.rb +3 -0
- data/ext/ulid_fast/ulid-fast.c +88 -0
- data/ext/ulid_fast/ulid.c +294 -0
- data/ext/ulid_fast/ulid.h +59 -0
- data/lib/ulid_fast/version.rb +3 -0
- metadata +76 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 675e2d1ea39c7608d9bb84a96efeab8acdf7eef82c1dd294c300577db946f72e
|
4
|
+
data.tar.gz: a58b60f8ff7177465adb801d194d80e456cbcaa4f7b90ea9efdb7cda2d0666bb
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 2aa59ba886b3f1d00ade9e4f3aa5595d41ebf15ccc2ad0a841d4d88dc1e58b5c8954032a3a3403e3dba9f691e8bbdf2b79a130d3b454aec5f1ec34ec9154027e
|
7
|
+
data.tar.gz: 6805293e8c88cf1464cdebb3f157c5fc97749b85e53068bf29f4b22b3a370fc4f1bd1ebc92a08e7454f3e771b62acda7bed04b36d0d62ee6c37e96fffd46202c
|
@@ -0,0 +1,88 @@
|
|
1
|
+
#include <stdlib.h>
|
2
|
+
#include <ruby.h>
|
3
|
+
#include <ruby/encoding.h>
|
4
|
+
#include "ulid.h"
|
5
|
+
|
6
|
+
|
7
|
+
static VALUE m_ULID;
|
8
|
+
|
9
|
+
|
10
|
+
void
|
11
|
+
rb_ulid_generator_mark (void *_self)
|
12
|
+
{
|
13
|
+
/*
|
14
|
+
* This function is not needed becaue there is no malloc() or
|
15
|
+
* pointers to other VALUE objects.
|
16
|
+
* However, to help others understand how Ruby C extensions
|
17
|
+
* work I've left it here.
|
18
|
+
*
|
19
|
+
struct ulid_generator *ug;
|
20
|
+
|
21
|
+
TypedData_Get_Struct(self, struct ulid_generator, &UlidGeneratorType, ug);
|
22
|
+
|
23
|
+
rb_gc_mark(ug->thing);
|
24
|
+
rb_gc_mark(ug->other_thing);
|
25
|
+
*/
|
26
|
+
}
|
27
|
+
|
28
|
+
void
|
29
|
+
rb_ulid_generator_free (void *_self)
|
30
|
+
{
|
31
|
+
// Not needed. We do not malloc() here or in the ulid lib
|
32
|
+
// free(_self);
|
33
|
+
}
|
34
|
+
|
35
|
+
static const rb_data_type_t UlidGeneratorType = {
|
36
|
+
"UlidGenerator",
|
37
|
+
{ rb_ulid_generator_mark, rb_ulid_generator_free, NULL }
|
38
|
+
};
|
39
|
+
|
40
|
+
static VALUE
|
41
|
+
rb_ulid_generate(VALUE self)
|
42
|
+
{
|
43
|
+
struct ulid_generator *ug;
|
44
|
+
|
45
|
+
TypedData_Get_Struct(self, struct ulid_generator, &UlidGeneratorType, ug);
|
46
|
+
char ulid[27];
|
47
|
+
|
48
|
+
ulid_generate(ug, ulid);
|
49
|
+
|
50
|
+
return rb_utf8_str_new(ulid, 26);
|
51
|
+
}
|
52
|
+
|
53
|
+
static VALUE
|
54
|
+
rb_ulid_alloc(VALUE self)
|
55
|
+
{
|
56
|
+
struct ulid_generator *ug;
|
57
|
+
VALUE obj;
|
58
|
+
obj = TypedData_Make_Struct(self, struct ulid_generator, &UlidGeneratorType, ug);
|
59
|
+
|
60
|
+
int ret = ulid_generator_init(ug, ULID_SECURE);
|
61
|
+
|
62
|
+
if (ret != 0)
|
63
|
+
rb_raise(rb_eRuntimeError, "ulid_generator_init failure");
|
64
|
+
|
65
|
+
return obj;
|
66
|
+
}
|
67
|
+
|
68
|
+
// TODO ..
|
69
|
+
/*
|
70
|
+
static VALUE
|
71
|
+
rb_ulid_each(int argc, VALUE* argv, VALUE self)
|
72
|
+
{
|
73
|
+
// return rb_funcall(self, rb_intern("to_enum"), 2, rb_intern("generate"), self,);
|
74
|
+
|
75
|
+
return Qnil;
|
76
|
+
}
|
77
|
+
*/
|
78
|
+
|
79
|
+
void
|
80
|
+
Init_ulid_fast() {
|
81
|
+
m_ULID = rb_define_module("ULID");
|
82
|
+
|
83
|
+
VALUE cls = rb_define_class_under(m_ULID, "Generator", rb_cObject);
|
84
|
+
// rb_include_module(m_ULID, rb_mEnumerable);
|
85
|
+
rb_define_alloc_func(cls, rb_ulid_alloc);
|
86
|
+
rb_define_method(cls, "generate", rb_ulid_generate, 0);
|
87
|
+
//rb_define_method(cls, "each", rb_ulid_each, -1);
|
88
|
+
}
|
@@ -0,0 +1,294 @@
|
|
1
|
+
/* ULID generation and parsing library (implementation)
|
2
|
+
*
|
3
|
+
* This is free and unencumbered software released into the public domain.
|
4
|
+
*/
|
5
|
+
#ifdef _WIN32
|
6
|
+
# define WIN32_LEAN_AND_MEAN
|
7
|
+
# include <windows.h>
|
8
|
+
# pragma comment(lib, "advapi32.lib")
|
9
|
+
#elif __linux__
|
10
|
+
# define _GNU_SOURCE
|
11
|
+
# include <unistd.h>
|
12
|
+
# include <sys/time.h>
|
13
|
+
# include <sys/syscall.h>
|
14
|
+
#else
|
15
|
+
# define _POSIX_C_SOURCE 200112L
|
16
|
+
# include <sys/time.h>
|
17
|
+
#endif
|
18
|
+
#include <time.h>
|
19
|
+
#include <stdio.h>
|
20
|
+
#include <string.h>
|
21
|
+
#include "ulid.h"
|
22
|
+
|
23
|
+
/* Returns unix epoch microseconds.
|
24
|
+
*/
|
25
|
+
static unsigned long long
|
26
|
+
platform_utime(int coarse)
|
27
|
+
{
|
28
|
+
#ifdef _WIN32
|
29
|
+
FILETIME ft;
|
30
|
+
(void)coarse;
|
31
|
+
GetSystemTimeAsFileTime(&ft);
|
32
|
+
return ((unsigned long long)ft.dwHighDateTime << 32 |
|
33
|
+
(unsigned long long)ft.dwLowDateTime << 0)
|
34
|
+
/ 10 - 11644473600000000ULL;
|
35
|
+
#elif __linux__
|
36
|
+
/* CLOCK_REALTIME_COARSE has a resolution of 1ms, which is
|
37
|
+
* sufficient for this purpose. It's also _much_ faster.
|
38
|
+
*/
|
39
|
+
struct timespec tv[1];
|
40
|
+
clock_gettime(coarse ? CLOCK_REALTIME_COARSE : CLOCK_REALTIME, tv);
|
41
|
+
return tv->tv_sec * 1000000ULL + tv->tv_nsec / 1000ULL;
|
42
|
+
#else
|
43
|
+
struct timespec tv[1];
|
44
|
+
(void)coarse;
|
45
|
+
clock_gettime(CLOCK_REALTIME, tv);
|
46
|
+
return tv->tv_sec * 1000000ULL + tv->tv_nsec / 1000ULL;
|
47
|
+
#endif
|
48
|
+
}
|
49
|
+
|
50
|
+
/* Gather entropy from the operating system.
|
51
|
+
* Returns 0 on success.
|
52
|
+
*/
|
53
|
+
static int
|
54
|
+
platform_entropy(void *buf, int len)
|
55
|
+
{
|
56
|
+
#if _WIN32
|
57
|
+
BOOLEAN NTAPI SystemFunction036(PVOID, ULONG);
|
58
|
+
return !SystemFunction036(buf, len);
|
59
|
+
#elif __linux__
|
60
|
+
return syscall(SYS_getrandom, buf, len, 0) != len;
|
61
|
+
#else
|
62
|
+
int r = 0;
|
63
|
+
FILE *f = fopen("/dev/urandom", "rb");
|
64
|
+
if (f) {
|
65
|
+
r = fread(buf, len, 1, f);
|
66
|
+
fclose(f);
|
67
|
+
}
|
68
|
+
return !r;
|
69
|
+
#endif
|
70
|
+
}
|
71
|
+
|
72
|
+
int
|
73
|
+
ulid_generator_init(struct ulid_generator *g, int flags)
|
74
|
+
{
|
75
|
+
g->last_ts = 0;
|
76
|
+
g->flags = flags;
|
77
|
+
g->i = g->j = 0;
|
78
|
+
for (int i = 0; i < 256; i++)
|
79
|
+
g->s[i] = i;
|
80
|
+
|
81
|
+
/* RC4 is used to fill the random segment of ULIDs. It's tiny,
|
82
|
+
* simple, perfectly sufficient for the task (assuming it's seeded
|
83
|
+
* properly), and doesn't require fixed-width integers. It's not the
|
84
|
+
* fastest option, but it's plenty fast for the task.
|
85
|
+
*
|
86
|
+
* Besides, when we're in a serious hurry in normal operation (not
|
87
|
+
* in "relaxed" mode), we're incrementing the random field much more
|
88
|
+
* often than generating fresh random bytes.
|
89
|
+
*/
|
90
|
+
|
91
|
+
int initstyle = 1;
|
92
|
+
unsigned char key[256] = {0};
|
93
|
+
if (!platform_entropy(key, 256)) {
|
94
|
+
/* Mix entropy into the RC4 state. */
|
95
|
+
for (int i = 0, j = 0; i < 256; i++) {
|
96
|
+
j = (j + g->s[i] + key[i]) & 0xff;
|
97
|
+
int tmp = g->s[i];
|
98
|
+
g->s[i] = g->s[j];
|
99
|
+
g->s[j] = tmp;
|
100
|
+
}
|
101
|
+
initstyle = 0;
|
102
|
+
} else if (!(flags & ULID_SECURE)) {
|
103
|
+
/* Failed to read entropy from OS, so generate some. */
|
104
|
+
unsigned long n = 0;
|
105
|
+
unsigned long long now;
|
106
|
+
unsigned long long start = platform_utime(0);
|
107
|
+
do {
|
108
|
+
struct {
|
109
|
+
clock_t clk;
|
110
|
+
unsigned long long ts;
|
111
|
+
long n;
|
112
|
+
void *stackgap;
|
113
|
+
} noise;
|
114
|
+
noise.ts = now = platform_utime(0);
|
115
|
+
noise.clk = clock();
|
116
|
+
noise.stackgap = &noise;
|
117
|
+
noise.n = n;
|
118
|
+
unsigned char *k = (unsigned char *)&noise;
|
119
|
+
for (int i = 0, j = 0; i < 256; i++) {
|
120
|
+
j = (j + g->s[i] + k[i % sizeof(noise)]) & 0xff;
|
121
|
+
int tmp = g->s[i];
|
122
|
+
g->s[i] = g->s[j];
|
123
|
+
g->s[j] = tmp;
|
124
|
+
}
|
125
|
+
} while (n++ < 1UL << 16 || now - start < 500000ULL);
|
126
|
+
}
|
127
|
+
return initstyle;
|
128
|
+
}
|
129
|
+
|
130
|
+
void
|
131
|
+
ulid_encode(char str[27], const unsigned char ulid[16])
|
132
|
+
{
|
133
|
+
static const char set[256] = {
|
134
|
+
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
|
135
|
+
0x38, 0x39, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46,
|
136
|
+
0x47, 0x48, 0x4a, 0x4b, 0x4d, 0x4e, 0x50, 0x51,
|
137
|
+
0x52, 0x53, 0x54, 0x56, 0x57, 0x58, 0x59, 0x5a,
|
138
|
+
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
|
139
|
+
0x38, 0x39, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46,
|
140
|
+
0x47, 0x48, 0x4a, 0x4b, 0x4d, 0x4e, 0x50, 0x51,
|
141
|
+
0x52, 0x53, 0x54, 0x56, 0x57, 0x58, 0x59, 0x5a,
|
142
|
+
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
|
143
|
+
0x38, 0x39, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46,
|
144
|
+
0x47, 0x48, 0x4a, 0x4b, 0x4d, 0x4e, 0x50, 0x51,
|
145
|
+
0x52, 0x53, 0x54, 0x56, 0x57, 0x58, 0x59, 0x5a,
|
146
|
+
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
|
147
|
+
0x38, 0x39, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46,
|
148
|
+
0x47, 0x48, 0x4a, 0x4b, 0x4d, 0x4e, 0x50, 0x51,
|
149
|
+
0x52, 0x53, 0x54, 0x56, 0x57, 0x58, 0x59, 0x5a,
|
150
|
+
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
|
151
|
+
0x38, 0x39, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46,
|
152
|
+
0x47, 0x48, 0x4a, 0x4b, 0x4d, 0x4e, 0x50, 0x51,
|
153
|
+
0x52, 0x53, 0x54, 0x56, 0x57, 0x58, 0x59, 0x5a,
|
154
|
+
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
|
155
|
+
0x38, 0x39, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46,
|
156
|
+
0x47, 0x48, 0x4a, 0x4b, 0x4d, 0x4e, 0x50, 0x51,
|
157
|
+
0x52, 0x53, 0x54, 0x56, 0x57, 0x58, 0x59, 0x5a,
|
158
|
+
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
|
159
|
+
0x38, 0x39, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46,
|
160
|
+
0x47, 0x48, 0x4a, 0x4b, 0x4d, 0x4e, 0x50, 0x51,
|
161
|
+
0x52, 0x53, 0x54, 0x56, 0x57, 0x58, 0x59, 0x5a,
|
162
|
+
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
|
163
|
+
0x38, 0x39, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46,
|
164
|
+
0x47, 0x48, 0x4a, 0x4b, 0x4d, 0x4e, 0x50, 0x51,
|
165
|
+
0x52, 0x53, 0x54, 0x56, 0x57, 0x58, 0x59, 0x5a
|
166
|
+
};
|
167
|
+
str[ 0] = set[ ulid[ 0] >> 5];
|
168
|
+
str[ 1] = set[ ulid[ 0] >> 0];
|
169
|
+
str[ 2] = set[ ulid[ 1] >> 3];
|
170
|
+
str[ 3] = set[(ulid[ 1] << 2 | ulid[ 2] >> 6) & 0x1f];
|
171
|
+
str[ 4] = set[ ulid[ 2] >> 1];
|
172
|
+
str[ 5] = set[(ulid[ 2] << 4 | ulid[ 3] >> 4) & 0x1f];
|
173
|
+
str[ 6] = set[(ulid[ 3] << 1 | ulid[ 4] >> 7) & 0x1f];
|
174
|
+
str[ 7] = set[ ulid[ 4] >> 2];
|
175
|
+
str[ 8] = set[(ulid[ 4] << 3 | ulid[ 5] >> 5) & 0x1f];
|
176
|
+
str[ 9] = set[ ulid[ 5] >> 0];
|
177
|
+
str[10] = set[ ulid[ 6] >> 3];
|
178
|
+
str[11] = set[(ulid[ 6] << 2 | ulid[ 7] >> 6) & 0x1f];
|
179
|
+
str[12] = set[ ulid[ 7] >> 1];
|
180
|
+
str[13] = set[(ulid[ 7] << 4 | ulid[ 8] >> 4) & 0x1f];
|
181
|
+
str[14] = set[(ulid[ 8] << 1 | ulid[ 9] >> 7) & 0x1f];
|
182
|
+
str[15] = set[ ulid[ 9] >> 2];
|
183
|
+
str[16] = set[(ulid[ 9] << 3 | ulid[10] >> 5) & 0x1f];
|
184
|
+
str[17] = set[ ulid[10] >> 0];
|
185
|
+
str[18] = set[ ulid[11] >> 3];
|
186
|
+
str[19] = set[(ulid[11] << 2 | ulid[12] >> 6) & 0x1f];
|
187
|
+
str[20] = set[ ulid[12] >> 1];
|
188
|
+
str[21] = set[(ulid[12] << 4 | ulid[13] >> 4) & 0x1f];
|
189
|
+
str[22] = set[(ulid[13] << 1 | ulid[14] >> 7) & 0x1f];
|
190
|
+
str[23] = set[ ulid[14] >> 2];
|
191
|
+
str[24] = set[(ulid[14] << 3 | ulid[15] >> 5) & 0x1f];
|
192
|
+
str[25] = set[ ulid[15] >> 0];
|
193
|
+
str[26] = 0;
|
194
|
+
}
|
195
|
+
|
196
|
+
int
|
197
|
+
ulid_decode(unsigned char ulid[16], const char *s)
|
198
|
+
{
|
199
|
+
static const signed char v[] = {
|
200
|
+
-1, -1, -1, -1, -1, -1, -1, -1,
|
201
|
+
-1, -1, -1, -1, -1, -1, -1, -1,
|
202
|
+
-1, -1, -1, -1, -1, -1, -1, -1,
|
203
|
+
-1, -1, -1, -1, -1, -1, -1, -1,
|
204
|
+
-1, -1, -1, -1, -1, -1, -1, -1,
|
205
|
+
-1, -1, -1, -1, -1, -1, -1, -1,
|
206
|
+
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
207
|
+
0x08, 0x09, -1, -1, -1, -1, -1, -1,
|
208
|
+
-1, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
|
209
|
+
0x11, 0x01, 0x12, 0x13, 0x01, 0x14, 0x15, 0x00,
|
210
|
+
0x16, 0x17, 0x18, 0x19, 0x1a, -1, 0x1b, 0x1c,
|
211
|
+
0x1d, 0x1e, 0x1f, -1, -1, -1, -1, -1,
|
212
|
+
-1, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
|
213
|
+
0x11, 0x01, 0x12, 0x13, 0x01, 0x14, 0x15, 0x00,
|
214
|
+
0x16, 0x17, 0x18, 0x19, 0x1a, -1, 0x1b, 0x1c,
|
215
|
+
0x1d, 0x1e, 0x1f, -1, -1, -1, -1, -1,
|
216
|
+
-1, -1, -1, -1, -1, -1, -1, -1,
|
217
|
+
-1, -1, -1, -1, -1, -1, -1, -1,
|
218
|
+
-1, -1, -1, -1, -1, -1, -1, -1,
|
219
|
+
-1, -1, -1, -1, -1, -1, -1, -1,
|
220
|
+
-1, -1, -1, -1, -1, -1, -1, -1,
|
221
|
+
-1, -1, -1, -1, -1, -1, -1, -1,
|
222
|
+
-1, -1, -1, -1, -1, -1, -1, -1,
|
223
|
+
-1, -1, -1, -1, -1, -1, -1, -1,
|
224
|
+
-1, -1, -1, -1, -1, -1, -1, -1,
|
225
|
+
-1, -1, -1, -1, -1, -1, -1, -1,
|
226
|
+
-1, -1, -1, -1, -1, -1, -1, -1,
|
227
|
+
-1, -1, -1, -1, -1, -1, -1, -1,
|
228
|
+
-1, -1, -1, -1, -1, -1, -1, -1,
|
229
|
+
-1, -1, -1, -1, -1, -1, -1, -1,
|
230
|
+
-1, -1, -1, -1, -1, -1, -1, -1,
|
231
|
+
-1, -1, -1, -1, -1, -1, -1, -1
|
232
|
+
};
|
233
|
+
if (v[(int)s[0]] > 7)
|
234
|
+
return 1;
|
235
|
+
for (int i = 0; i < 26; i++)
|
236
|
+
if (v[(int)s[i]] == -1)
|
237
|
+
return 2;
|
238
|
+
ulid[ 0] = v[(int)s[ 0]] << 5 | v[(int)s[ 1]] >> 0;
|
239
|
+
ulid[ 1] = v[(int)s[ 2]] << 3 | v[(int)s[ 3]] >> 2;
|
240
|
+
ulid[ 2] = v[(int)s[ 3]] << 6 | v[(int)s[ 4]] << 1 | v[(int)s[ 5]] >> 4;
|
241
|
+
ulid[ 3] = v[(int)s[ 5]] << 4 | v[(int)s[ 6]] >> 1;
|
242
|
+
ulid[ 4] = v[(int)s[ 6]] << 7 | v[(int)s[ 7]] << 2 | v[(int)s[ 8]] >> 3;
|
243
|
+
ulid[ 5] = v[(int)s[ 8]] << 5 | v[(int)s[ 9]] >> 0;
|
244
|
+
ulid[ 6] = v[(int)s[10]] << 3 | v[(int)s[11]] >> 2;
|
245
|
+
ulid[ 7] = v[(int)s[11]] << 6 | v[(int)s[12]] << 1 | v[(int)s[13]] >> 4;
|
246
|
+
ulid[ 8] = v[(int)s[13]] << 4 | v[(int)s[14]] >> 1;
|
247
|
+
ulid[ 9] = v[(int)s[14]] << 7 | v[(int)s[15]] << 2 | v[(int)s[16]] >> 3;
|
248
|
+
ulid[10] = v[(int)s[16]] << 5 | v[(int)s[17]] >> 0;
|
249
|
+
ulid[11] = v[(int)s[18]] << 3 | v[(int)s[19]] >> 2;
|
250
|
+
ulid[12] = v[(int)s[19]] << 6 | v[(int)s[20]] << 1 | v[(int)s[21]] >> 4;
|
251
|
+
ulid[13] = v[(int)s[21]] << 4 | v[(int)s[22]] >> 1;
|
252
|
+
ulid[14] = v[(int)s[22]] << 7 | v[(int)s[23]] << 2 | v[(int)s[24]] >> 3;
|
253
|
+
ulid[15] = v[(int)s[24]] << 5 | v[(int)s[25]] >> 0;
|
254
|
+
return 0;
|
255
|
+
}
|
256
|
+
|
257
|
+
void
|
258
|
+
ulid_generate(struct ulid_generator *g, char str[27])
|
259
|
+
{
|
260
|
+
unsigned long long ts = platform_utime(1) / 1000;
|
261
|
+
|
262
|
+
if (!(g->flags & ULID_RELAXED) && g->last_ts == ts) {
|
263
|
+
/* Chance of 80-bit overflow is so small that it's not considered. */
|
264
|
+
for (int i = 15; i > 5; i--)
|
265
|
+
if (++g->last[i])
|
266
|
+
break;
|
267
|
+
ulid_encode(str, g->last);
|
268
|
+
return;
|
269
|
+
}
|
270
|
+
|
271
|
+
/* Fill out timestamp */
|
272
|
+
g->last_ts = ts;
|
273
|
+
g->last[0] = ts >> 40;
|
274
|
+
g->last[1] = ts >> 32;
|
275
|
+
g->last[2] = ts >> 24;
|
276
|
+
g->last[3] = ts >> 16;
|
277
|
+
g->last[4] = ts >> 8;
|
278
|
+
g->last[5] = ts >> 0;
|
279
|
+
|
280
|
+
/* Fill out random section */
|
281
|
+
for (int k = 0; k < 10; k++) {
|
282
|
+
g->i = (g->i + 1) & 0xff;
|
283
|
+
g->j = (g->j + g->s[g->i]) & 0xff;
|
284
|
+
int tmp = g->s[g->i];
|
285
|
+
g->s[g->i] = g->s[g->j];
|
286
|
+
g->s[g->j] = tmp;
|
287
|
+
g->last[6 + k] = g->s[(g->s[g->i] + g->s[g->j]) & 0xff];
|
288
|
+
}
|
289
|
+
if (g->flags & ULID_PARANOID)
|
290
|
+
g->last[6] &= 0x7f;
|
291
|
+
|
292
|
+
ulid_encode(str, g->last);
|
293
|
+
}
|
294
|
+
|
@@ -0,0 +1,59 @@
|
|
1
|
+
/* ULID generation and parsing library (API)
|
2
|
+
*
|
3
|
+
* This is free and unencumbered software released into the public domain.
|
4
|
+
*/
|
5
|
+
#ifndef ULID_H
|
6
|
+
#define ULID_H
|
7
|
+
|
8
|
+
/* Generator configuration flags */
|
9
|
+
#define ULID_RELAXED (1 << 0)
|
10
|
+
#define ULID_PARANOID (1 << 1)
|
11
|
+
#define ULID_SECURE (1 << 2)
|
12
|
+
|
13
|
+
struct ulid_generator {
|
14
|
+
unsigned char last[16];
|
15
|
+
unsigned long long last_ts;
|
16
|
+
int flags;
|
17
|
+
unsigned char i, j;
|
18
|
+
unsigned char s[256];
|
19
|
+
};
|
20
|
+
|
21
|
+
/* Initialize a new ULID generator instance.
|
22
|
+
*
|
23
|
+
* The ULID_RELAXED flag allows ULIDs generated within the same
|
24
|
+
* millisecond to be non-monotonic, e.g. the random section is generated
|
25
|
+
* fresh each time.
|
26
|
+
*
|
27
|
+
* The ULID_PARANOID flag causes the generator to clear the highest bit
|
28
|
+
* of the random field, which guarantees that overflow cannot occur.
|
29
|
+
* Normally the chance of overflow is non-zero, but negligible. This
|
30
|
+
* makes it zero. It doesn't make sense to use this flag in conjunction
|
31
|
+
* with ULID_RELAX.
|
32
|
+
*
|
33
|
+
* The ULID_SECURE flag doesn't fall back on userspace initialization if
|
34
|
+
* system entropy could not be gathered. You _must_ check the return
|
35
|
+
* value if you use this flag, since it now indicates a hard error.
|
36
|
+
*
|
37
|
+
* Returns 0 if the generator was successfully initialized from secure
|
38
|
+
* system entropy. Returns 1 if this failed and instead derived entropy
|
39
|
+
* in userspace (or is uninitialized in the case of ULID_SECURE).
|
40
|
+
*/
|
41
|
+
int ulid_generator_init(struct ulid_generator *, int flags);
|
42
|
+
|
43
|
+
/* Generate a new ULID.
|
44
|
+
* A zero terminating byte is written to the output buffer.
|
45
|
+
*/
|
46
|
+
void ulid_generate(struct ulid_generator *, char [27]);
|
47
|
+
|
48
|
+
/* Encode a 128-bit binary ULID to its text format.
|
49
|
+
* A zero terminating byte is written to the output buffer.
|
50
|
+
*/
|
51
|
+
void ulid_encode(char [27], const unsigned char [16]);
|
52
|
+
|
53
|
+
/* Decode a text ULID to a 128-bit binary ULID.
|
54
|
+
* Returns non-zero if input was invalid.
|
55
|
+
*/
|
56
|
+
int ulid_decode(unsigned char [16], const char *);
|
57
|
+
|
58
|
+
#endif
|
59
|
+
|
metadata
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ulid_fast
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- James Cook
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2020-02-11 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rake-compiler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: minitest
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '5'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '5'
|
41
|
+
description:
|
42
|
+
email:
|
43
|
+
executables: []
|
44
|
+
extensions:
|
45
|
+
- ext/ulid_fast/extconf.rb
|
46
|
+
extra_rdoc_files: []
|
47
|
+
files:
|
48
|
+
- ext/ulid_fast/extconf.rb
|
49
|
+
- ext/ulid_fast/ulid-fast.c
|
50
|
+
- ext/ulid_fast/ulid.c
|
51
|
+
- ext/ulid_fast/ulid.h
|
52
|
+
- lib/ulid_fast/version.rb
|
53
|
+
homepage: https://github.com/jamescook/ulid_fast
|
54
|
+
licenses:
|
55
|
+
- MIT
|
56
|
+
metadata: {}
|
57
|
+
post_install_message:
|
58
|
+
rdoc_options: []
|
59
|
+
require_paths:
|
60
|
+
- lib
|
61
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
62
|
+
requirements:
|
63
|
+
- - ">"
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: '2.1'
|
66
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
67
|
+
requirements:
|
68
|
+
- - ">="
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
version: '0'
|
71
|
+
requirements: []
|
72
|
+
rubygems_version: 3.1.2
|
73
|
+
signing_key:
|
74
|
+
specification_version: 4
|
75
|
+
summary: ULID Ruby C Extension
|
76
|
+
test_files: []
|