ulid_fast 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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: []
|