File Coverage

XS.xs
Criterion Covered Total %
statement 85 89 95.5
branch 23 38 60.5
condition n/a
subroutine n/a
pod n/a
total 108 127 85.0


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