line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
#include "EXTERN.h" |
2
|
|
|
|
|
|
|
#include "perl.h" |
3
|
|
|
|
|
|
|
#include "XSUB.h" |
4
|
|
|
|
|
|
|
|
5
|
|
|
|
|
|
|
#include "ppport.h" |
6
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
#define ULID_LEN 16 |
8
|
|
|
|
|
|
|
#define ULID_TIME_LEN 6 |
9
|
|
|
|
|
|
|
#define ULID_RAND_LEN 10 |
10
|
|
|
|
|
|
|
#define RESULT_LEN 26 |
11
|
|
|
|
|
|
|
|
12
|
20
|
|
|
|
|
|
SV* encode_ulid(SV *strsv) |
13
|
|
|
|
|
|
|
{ |
14
|
|
|
|
|
|
|
unsigned long len; |
15
|
20
|
50
|
|
|
|
|
char *str = SvPVbyte(strsv, len); |
16
|
20
|
50
|
|
|
|
|
if (len != ULID_LEN) croak("invalid string length in encode_ulid: %d", len); |
17
|
|
|
|
|
|
|
|
18
|
20
|
|
|
|
|
|
char base32[] = "0123456789ABCDEFGHJKMNPQRSTVWXYZ"; |
19
|
|
|
|
|
|
|
char result[RESULT_LEN]; |
20
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
// This part will be replaced with a pregenerated base32 encoding for |
22
|
|
|
|
|
|
|
// ULIDs, which runs significantly faster. See gen/gen_streamlined_ulid.pl |
23
|
|
|
|
|
|
|
// script for details. |
24
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
// autogenerated: |
26
|
20
|
|
|
|
|
|
result[0] = base32[((str[0] & 0xe0)>>5)]; |
27
|
20
|
|
|
|
|
|
result[1] = base32[((str[0] & 0x1f))]; |
28
|
20
|
|
|
|
|
|
result[2] = base32[((str[1] & 0xf8)>>3)]; |
29
|
20
|
|
|
|
|
|
result[3] = base32[((str[1] & 0x07)<<2) + ((str[2] & 0xc0)>>6)]; |
30
|
20
|
|
|
|
|
|
result[4] = base32[((str[2] & 0x3e)>>1)]; |
31
|
20
|
|
|
|
|
|
result[5] = base32[((str[2] & 0x01)<<4) + ((str[3] & 0xf0)>>4)]; |
32
|
20
|
|
|
|
|
|
result[6] = base32[((str[3] & 0x0f)<<1) + ((str[4] & 0x80)>>7)]; |
33
|
20
|
|
|
|
|
|
result[7] = base32[((str[4] & 0x7c)>>2)]; |
34
|
20
|
|
|
|
|
|
result[8] = base32[((str[4] & 0x03)<<3) + ((str[5] & 0xe0)>>5)]; |
35
|
20
|
|
|
|
|
|
result[9] = base32[((str[5] & 0x1f))]; |
36
|
|
|
|
|
|
|
|
37
|
20
|
|
|
|
|
|
result[10] = base32[((str[6] & 0xf8)>>3)]; |
38
|
20
|
|
|
|
|
|
result[11] = base32[((str[6] & 0x07)<<2) + ((str[7] & 0xc0)>>6)]; |
39
|
20
|
|
|
|
|
|
result[12] = base32[((str[7] & 0x3e)>>1)]; |
40
|
20
|
|
|
|
|
|
result[13] = base32[((str[7] & 0x01)<<4) + ((str[8] & 0xf0)>>4)]; |
41
|
20
|
|
|
|
|
|
result[14] = base32[((str[8] & 0x0f)<<1) + ((str[9] & 0x80)>>7)]; |
42
|
20
|
|
|
|
|
|
result[15] = base32[((str[9] & 0x7c)>>2)]; |
43
|
20
|
|
|
|
|
|
result[16] = base32[((str[9] & 0x03)<<3) + ((str[10] & 0xe0)>>5)]; |
44
|
20
|
|
|
|
|
|
result[17] = base32[((str[10] & 0x1f))]; |
45
|
20
|
|
|
|
|
|
result[18] = base32[((str[11] & 0xf8)>>3)]; |
46
|
20
|
|
|
|
|
|
result[19] = base32[((str[11] & 0x07)<<2) + ((str[12] & 0xc0)>>6)]; |
47
|
20
|
|
|
|
|
|
result[20] = base32[((str[12] & 0x3e)>>1)]; |
48
|
20
|
|
|
|
|
|
result[21] = base32[((str[12] & 0x01)<<4) + ((str[13] & 0xf0)>>4)]; |
49
|
20
|
|
|
|
|
|
result[22] = base32[((str[13] & 0x0f)<<1) + ((str[14] & 0x80)>>7)]; |
50
|
20
|
|
|
|
|
|
result[23] = base32[((str[14] & 0x7c)>>2)]; |
51
|
20
|
|
|
|
|
|
result[24] = base32[((str[14] & 0x03)<<3) + ((str[15] & 0xe0)>>5)]; |
52
|
20
|
|
|
|
|
|
result[25] = base32[((str[15] & 0x1f))]; |
53
|
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
|
55
|
20
|
|
|
|
|
|
return newSVpv(result, RESULT_LEN); |
56
|
|
|
|
|
|
|
} |
57
|
|
|
|
|
|
|
|
58
|
40
|
|
|
|
|
|
SV* build_binary_ulid (double time, SV *randomnesssv) |
59
|
|
|
|
|
|
|
{ |
60
|
|
|
|
|
|
|
unsigned long len; |
61
|
40
|
50
|
|
|
|
|
char *randomness = SvPVbyte(randomnesssv, len); |
62
|
40
|
50
|
|
|
|
|
if (len == 0) croak("no randomness was fetched for build_binary_ulid"); |
63
|
|
|
|
|
|
|
|
64
|
40
|
|
|
|
|
|
char result[ULID_LEN] = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; |
65
|
|
|
|
|
|
|
int i, j; |
66
|
|
|
|
|
|
|
|
67
|
40
|
|
|
|
|
|
unsigned long long microtime = time * 1000; |
68
|
|
|
|
|
|
|
|
69
|
|
|
|
|
|
|
// network byte order |
70
|
280
|
100
|
|
|
|
|
for (i = ULID_TIME_LEN - 1; i >= 0; --i) { |
71
|
240
|
|
|
|
|
|
result[i] = (char) (microtime & 0xff); |
72
|
240
|
|
|
|
|
|
microtime = microtime >> 8; |
73
|
|
|
|
|
|
|
} |
74
|
|
|
|
|
|
|
|
75
|
440
|
100
|
|
|
|
|
for (i = ULID_LEN - len, j = 0; i < ULID_LEN; ++i) { |
76
|
400
|
|
|
|
|
|
result[i] = randomness[j++]; |
77
|
|
|
|
|
|
|
} |
78
|
|
|
|
|
|
|
|
79
|
40
|
|
|
|
|
|
return newSVpv(result, ULID_LEN); |
80
|
|
|
|
|
|
|
} |
81
|
|
|
|
|
|
|
|
82
|
|
|
|
|
|
|
// proper XS Code starts here |
83
|
|
|
|
|
|
|
|
84
|
|
|
|
|
|
|
MODULE = Data::ULID::XS PACKAGE = Data::ULID::XS |
85
|
|
|
|
|
|
|
|
86
|
|
|
|
|
|
|
PROTOTYPES: DISABLE |
87
|
|
|
|
|
|
|
|
88
|
|
|
|
|
|
|
SV* |
89
|
|
|
|
|
|
|
ulid(...) |
90
|
|
|
|
|
|
|
CODE: |
91
|
40
|
|
|
|
|
|
dSP; |
92
|
|
|
|
|
|
|
|
93
|
40
|
50
|
|
|
|
|
PUSHMARK(SP); |
94
|
|
|
|
|
|
|
|
95
|
40
|
100
|
|
|
|
|
if (items == 0) { |
96
|
20
|
|
|
|
|
|
int count = call_pv("Data::ULID::XS::binary_ulid", G_SCALAR); |
97
|
|
|
|
|
|
|
|
98
|
20
|
|
|
|
|
|
SPAGAIN; |
99
|
|
|
|
|
|
|
|
100
|
20
|
50
|
|
|
|
|
if (count != 1) { |
101
|
0
|
|
|
|
|
|
croak("Calling Data::ULID::XS::binary_ulid went wrong in Data::ULID::XS::ulid"); |
102
|
|
|
|
|
|
|
} |
103
|
|
|
|
|
|
|
|
104
|
20
|
|
|
|
|
|
RETVAL = encode_ulid(POPs); |
105
|
|
|
|
|
|
|
} |
106
|
|
|
|
|
|
|
else { |
107
|
20
|
50
|
|
|
|
|
EXTEND(SP, 1); |
108
|
20
|
|
|
|
|
|
PUSHs(ST(0)); |
109
|
20
|
|
|
|
|
|
PUTBACK; |
110
|
|
|
|
|
|
|
|
111
|
20
|
|
|
|
|
|
int count = call_pv("Data::ULID::ulid", G_SCALAR); |
112
|
|
|
|
|
|
|
|
113
|
20
|
|
|
|
|
|
SPAGAIN; |
114
|
|
|
|
|
|
|
|
115
|
20
|
50
|
|
|
|
|
if (count != 1) { |
116
|
0
|
|
|
|
|
|
croak("Calling Data::ULID::ulid went wrong in Data::ULID::XS::ulid"); |
117
|
|
|
|
|
|
|
} |
118
|
|
|
|
|
|
|
|
119
|
20
|
|
|
|
|
|
SV *ret = POPs; |
120
|
20
|
|
|
|
|
|
SvREFCNT_inc(ret); |
121
|
20
|
|
|
|
|
|
RETVAL = ret; |
122
|
|
|
|
|
|
|
} |
123
|
|
|
|
|
|
|
|
124
|
40
|
|
|
|
|
|
PUTBACK; |
125
|
|
|
|
|
|
|
OUTPUT: |
126
|
|
|
|
|
|
|
RETVAL |
127
|
|
|
|
|
|
|
|
128
|
|
|
|
|
|
|
SV* |
129
|
|
|
|
|
|
|
binary_ulid(...) |
130
|
|
|
|
|
|
|
CODE: |
131
|
60
|
|
|
|
|
|
dSP; |
132
|
|
|
|
|
|
|
|
133
|
60
|
50
|
|
|
|
|
PUSHMARK(SP); |
134
|
|
|
|
|
|
|
|
135
|
60
|
100
|
|
|
|
|
if (items == 0) { |
136
|
40
|
|
|
|
|
|
SV *tmp = newSViv(10); |
137
|
|
|
|
|
|
|
|
138
|
40
|
50
|
|
|
|
|
EXTEND(SP, 2); |
139
|
40
|
|
|
|
|
|
PUSHs(get_sv("Data::ULID::XS::RNG", 0)); |
140
|
40
|
|
|
|
|
|
PUSHs(tmp); |
141
|
40
|
|
|
|
|
|
PUTBACK; |
142
|
|
|
|
|
|
|
|
143
|
40
|
|
|
|
|
|
int count = call_method("bytes", G_SCALAR); |
144
|
40
|
|
|
|
|
|
SvREFCNT_dec(tmp); |
145
|
|
|
|
|
|
|
|
146
|
40
|
|
|
|
|
|
SPAGAIN; |
147
|
|
|
|
|
|
|
|
148
|
40
|
50
|
|
|
|
|
if (count != 1) { |
149
|
0
|
|
|
|
|
|
croak("Calling method bytes on Crypt::PRNG::* went wrong in Data::ULID::XS::binary_ulid"); |
150
|
|
|
|
|
|
|
} |
151
|
|
|
|
|
|
|
|
152
|
40
|
|
|
|
|
|
SV **svp = hv_fetchs(PL_modglobal, "Time::NVtime", 0); |
153
|
40
|
50
|
|
|
|
|
if (!SvIOK(*svp)) croak("Time::NVtime isn't a function pointer"); |
154
|
40
|
50
|
|
|
|
|
NV (*nvtime)() = INT2PTR(NV(*)(), SvIV(*svp)); |
155
|
|
|
|
|
|
|
|
156
|
40
|
|
|
|
|
|
RETVAL = build_binary_ulid((*nvtime)(), POPs); |
157
|
|
|
|
|
|
|
} |
158
|
|
|
|
|
|
|
else { |
159
|
20
|
50
|
|
|
|
|
EXTEND(SP, 1); |
160
|
20
|
|
|
|
|
|
PUSHs(ST(0)); |
161
|
20
|
|
|
|
|
|
PUTBACK; |
162
|
|
|
|
|
|
|
|
163
|
20
|
|
|
|
|
|
int count = call_pv("Data::ULID::binary_ulid", G_SCALAR); |
164
|
|
|
|
|
|
|
|
165
|
20
|
|
|
|
|
|
SPAGAIN; |
166
|
|
|
|
|
|
|
|
167
|
20
|
50
|
|
|
|
|
if (count != 1) { |
168
|
0
|
|
|
|
|
|
croak("Calling Data::ULID::binary_ulid went wrong in Data::ULID::XS::binary_ulid"); |
169
|
|
|
|
|
|
|
} |
170
|
|
|
|
|
|
|
|
171
|
20
|
|
|
|
|
|
SV *ret = POPs; |
172
|
20
|
|
|
|
|
|
SvREFCNT_inc(ret); |
173
|
20
|
|
|
|
|
|
RETVAL = ret; |
174
|
|
|
|
|
|
|
} |
175
|
|
|
|
|
|
|
|
176
|
60
|
|
|
|
|
|
PUTBACK; |
177
|
|
|
|
|
|
|
OUTPUT: |
178
|
|
|
|
|
|
|
RETVAL |
179
|
|
|
|
|
|
|
|