File Coverage

xs/i16a.xsi
Criterion Covered Total %
statement 66 223 29.6
branch 108 578 18.6
condition n/a
subroutine n/a
pod n/a
total 174 801 21.7


line stmt bran cond sub pod time code
1             MODULE = Data::HashMap PACKAGE = Data::HashMap::I16A
2             PROTOTYPES: DISABLE
3              
4             SV*
5             new(char* class, ...)
6             CODE:
7 16 100         EXTRACT_NEW_ARGS(_max_size, _ttl, _lru_skip);
    100          
    50          
8 16           HashMapI16A* map = hashmap_i16a_create(_max_size, _ttl, _lru_skip);
9 16 50         if (!map) croak("Failed to create HashMap::I16A");
10 16           map->free_value_fn = hm_sv_free;
11 16           RETVAL = sv_setref_pv(newSV(0), class, (void*)map);
12             OUTPUT:
13             RETVAL
14              
15             void
16             DESTROY(SV* self_sv)
17             CODE:
18 16 50         EXTRACT_MAP(HashMapI16A, stash_i16a, "Data::HashMap::I16A", self_sv);
    50          
    50          
    50          
19 16           hashmap_i16a_destroy(self);
20 16           sv_setiv(SvRV(self_sv), 0);
21              
22             bool
23             put(SV* self_sv, int16_t key, SV* value)
24             CODE:
25 30068 50         EXTRACT_MAP(HashMapI16A, stash_i16a, "Data::HashMap::I16A", self_sv);
    50          
    50          
    50          
26 30068           SvREFCNT_inc(value);
27 30068           RETVAL = hashmap_i16a_put(self, key, (void*)value, 0);
28 30068 100         if (!RETVAL) SvREFCNT_dec(value);
29             OUTPUT:
30             RETVAL
31              
32             SV*
33             get(SV* self_sv, int16_t key)
34             CODE:
35 30016 50         EXTRACT_MAP(HashMapI16A, stash_i16a, "Data::HashMap::I16A", self_sv);
    50          
    50          
    50          
36             void* val;
37 30016 100         if (!hashmap_i16a_get(self, key, &val)) XSRETURN_UNDEF;
38 30012           RETVAL = SvREFCNT_inc((SV*)val);
39             OUTPUT:
40             RETVAL
41              
42             bool
43             remove(SV* self_sv, int16_t key)
44             CODE:
45 30005 50         EXTRACT_MAP(HashMapI16A, stash_i16a, "Data::HashMap::I16A", self_sv);
    50          
    50          
    50          
46 30005           RETVAL = hashmap_i16a_remove(self, key);
47             OUTPUT:
48             RETVAL
49              
50             SV*
51             take(SV* self_sv, int16_t key)
52             CODE:
53 1 50         EXTRACT_MAP(HashMapI16A, stash_i16a, "Data::HashMap::I16A", self_sv);
    50          
    50          
    50          
54             void* val;
55 1 50         if (!hashmap_i16a_take(self, key, &val)) XSRETURN_UNDEF;
56 1           RETVAL = (SV*)val;
57             OUTPUT:
58             RETVAL
59              
60             bool
61             exists(SV* self_sv, int16_t key)
62             CODE:
63 3 50         EXTRACT_MAP(HashMapI16A, stash_i16a, "Data::HashMap::I16A", self_sv);
    50          
    50          
    50          
64 3           RETVAL = hashmap_i16a_exists(self, key);
65             OUTPUT:
66             RETVAL
67              
68             size_t
69             size(SV* self_sv)
70             CODE:
71 9 50         EXTRACT_MAP(HashMapI16A, stash_i16a, "Data::HashMap::I16A", self_sv);
    50          
    50          
    50          
72 9 50         RETVAL = self->size;
73             OUTPUT:
74             RETVAL
75              
76             size_t
77             max_size(SV* self_sv)
78             CODE:
79 0 0         EXTRACT_MAP(HashMapI16A, stash_i16a, "Data::HashMap::I16A", self_sv);
    0          
    0          
    0          
80 0 0         RETVAL = self->max_size;
81             OUTPUT:
82             RETVAL
83              
84             UV
85             ttl(SV* self_sv)
86             CODE:
87 0 0         EXTRACT_MAP(HashMapI16A, stash_i16a, "Data::HashMap::I16A", self_sv);
    0          
    0          
    0          
88 0 0         RETVAL = (UV)self->default_ttl;
89             OUTPUT:
90             RETVAL
91              
92             UV
93             lru_skip(SV* self_sv)
94             CODE:
95 0 0         EXTRACT_MAP(HashMapI16A, stash_i16a, "Data::HashMap::I16A", self_sv);
    0          
    0          
    0          
96 0 0         RETVAL = (UV)self->lru_skip;
97             OUTPUT:
98             RETVAL
99              
100             void
101             keys(SV* self_sv)
102             PPCODE:
103 1 50         EXTRACT_MAP(HashMapI16A, stash_i16a, "Data::HashMap::I16A", self_sv);
    50          
    50          
    50          
104 1 50         uint32_t now = self->expires_at ? (uint32_t)time(NULL) : 0;
105 1 50         EXTEND(SP, self->size);
106             size_t i;
107 17 100         for (i = 0; i < self->capacity; i++) {
108 16 100         if (I16A_NODE_LIVE(self->nodes[i]) && !HM_TTL_SKIP_EXPIRED(self, i, now))
    50          
    50          
    0          
    0          
109 2 50         mXPUSHi(self->nodes[i].key);
110             }
111              
112             void
113             values(SV* self_sv)
114             PPCODE:
115 1 50         EXTRACT_MAP(HashMapI16A, stash_i16a, "Data::HashMap::I16A", self_sv);
    50          
    50          
    50          
116 1 50         uint32_t now = self->expires_at ? (uint32_t)time(NULL) : 0;
117 1 50         EXTEND(SP, self->size);
118             size_t i;
119 17 100         for (i = 0; i < self->capacity; i++) {
120 16 100         if (I16A_NODE_LIVE(self->nodes[i]) && !HM_TTL_SKIP_EXPIRED(self, i, now)) {
    50          
    50          
    0          
    0          
121 2 50         SV* sv = self->nodes[i].value ? SvREFCNT_inc((SV*)self->nodes[i].value) : &PL_sv_undef;
122 2 50         mXPUSHs(sv);
123             }
124             }
125              
126             void
127             items(SV* self_sv)
128             PPCODE:
129 1 50         EXTRACT_MAP(HashMapI16A, stash_i16a, "Data::HashMap::I16A", self_sv);
    50          
    50          
    50          
130 1 50         uint32_t now = self->expires_at ? (uint32_t)time(NULL) : 0;
131 1 50         EXTEND(SP, self->size * 2);
132             size_t i;
133 17 100         for (i = 0; i < self->capacity; i++) {
134 16 100         if (I16A_NODE_LIVE(self->nodes[i]) && !HM_TTL_SKIP_EXPIRED(self, i, now)) {
    50          
    50          
    0          
    0          
135 2 50         mXPUSHi(self->nodes[i].key);
136 2 50         SV* sv = self->nodes[i].value ? SvREFCNT_inc((SV*)self->nodes[i].value) : &PL_sv_undef;
137 2 50         mXPUSHs(sv);
138             }
139             }
140              
141             void
142             each(SV* self_sv)
143             PPCODE:
144 6 50         EXTRACT_MAP(HashMapI16A, stash_i16a, "Data::HashMap::I16A", self_sv);
    50          
    50          
    50          
145 6 50         uint32_t now = self->expires_at ? (uint32_t)time(NULL) : 0;
146 34 100         while (self->iter_pos < self->capacity) {
147 32           size_t i = self->iter_pos++;
148 32 100         if (I16A_NODE_LIVE(self->nodes[i]) && !HM_TTL_SKIP_EXPIRED(self, i, now)) {
    50          
    50          
    0          
    0          
149 4 50         EXTEND(SP, 2);
150 4 50         mXPUSHi(self->nodes[i].key);
151 4 50         if (GIMME_V == G_SCALAR) XSRETURN(1);
152 4 50         SV* sv = self->nodes[i].value ? SvREFCNT_inc((SV*)self->nodes[i].value) : &PL_sv_undef;
153 4 50         mXPUSHs(sv);
154 4           XSRETURN(2);
155             }
156             }
157 2           self->iter_pos = 0;
158 2           XSRETURN_EMPTY;
159              
160             void
161             iter_reset(SV* self_sv)
162             CODE:
163 0 0         EXTRACT_MAP(HashMapI16A, stash_i16a, "Data::HashMap::I16A", self_sv);
    0          
    0          
    0          
164 0           self->iter_pos = 0;
165              
166             void
167             drain(SV* self_sv, UV count)
168             PPCODE:
169 0 0         EXTRACT_MAP(HashMapI16A, stash_i16a, "Data::HashMap::I16A", self_sv);
    0          
    0          
    0          
170 0 0         uint32_t now = self->expires_at ? (uint32_t)time(NULL) : 0;
171 0           UV n = 0;
172 0 0         EXTEND(SP, (count < self->size ? count : self->size) * 2);
173 0 0         while (self->iter_pos < self->capacity && n < count) {
    0          
174 0           size_t i = self->iter_pos++;
175 0 0         if (I16A_NODE_LIVE(self->nodes[i]) && !HM_TTL_SKIP_EXPIRED(self, i, now)) {
    0          
    0          
    0          
    0          
176 0 0         mXPUSHi(self->nodes[i].key);
177 0 0         if (self->nodes[i].value) {
178 0 0         mXPUSHs((SV*)self->nodes[i].value);
179 0 0         } else { XPUSHs(&PL_sv_undef); }
180 0           self->nodes[i].value = NULL;
181 0 0         if (HM_UNLIKELY(self->lru_prev)) hashmap_i16a_lru_unlink(self, (uint32_t)i);
182 0           hashmap_i16a_tombstone_at(self, i);
183 0           n++;
184             }
185             }
186 0 0         if (self->iter_pos >= self->capacity) self->iter_pos = 0;
187 0 0         if (self->tombstones > self->capacity / 4 ||
188 0 0         (self->size > 0 && self->tombstones > self->size))
    0          
189 0           hashmap_i16a_compact(self);
190              
191             void
192             pop(SV* self_sv)
193             PPCODE:
194 0 0         EXTRACT_MAP(HashMapI16A, stash_i16a, "Data::HashMap::I16A", self_sv);
    0          
    0          
    0          
195 0 0         uint32_t now = self->expires_at ? (uint32_t)time(NULL) : 0;
196 0 0         if (self->lru_prev) {
197 0 0         while (self->lru_tail != HM_LRU_NONE) {
198 0           uint32_t idx = self->lru_tail;
199 0 0         if (HM_UNLIKELY(self->expires_at && self->expires_at[idx]) && now >= self->expires_at[idx]) {
    0          
    0          
200 0           hashmap_i16a_expire_at(self, idx, true); continue;
201             }
202 0 0         EXTEND(SP, 2);
203 0 0         mXPUSHi(self->nodes[idx].key);
204 0 0         if (self->nodes[idx].value) {
205 0 0         mXPUSHs((SV*)self->nodes[idx].value);
206 0 0         } else { XPUSHs(&PL_sv_undef); }
207 0           self->nodes[idx].value = NULL;
208 0           hashmap_i16a_lru_unlink(self, idx);
209 0           hashmap_i16a_tombstone_at(self, idx);
210 0 0         if (self->tombstones > self->capacity / 4 ||
211 0 0         (self->size > 0 && self->tombstones > self->size))
    0          
212 0           hashmap_i16a_compact(self);
213 0           XSRETURN(2);
214             }
215 0           XSRETURN_EMPTY;
216             } else {
217 0 0         while (self->iter_pos < self->capacity) {
218 0           size_t i = self->iter_pos++;
219 0 0         if (I16A_NODE_LIVE(self->nodes[i]) && !HM_TTL_SKIP_EXPIRED(self, i, now)) {
    0          
    0          
    0          
    0          
220 0 0         EXTEND(SP, 2);
221 0 0         mXPUSHi(self->nodes[i].key);
222 0 0         if (self->nodes[i].value) {
223 0 0         mXPUSHs((SV*)self->nodes[i].value);
224 0 0         } else { XPUSHs(&PL_sv_undef); }
225 0           self->nodes[i].value = NULL;
226 0           hashmap_i16a_tombstone_at(self, i);
227 0 0         if (self->tombstones > self->capacity / 4 ||
228 0 0         (self->size > 0 && self->tombstones > self->size))
    0          
229 0           hashmap_i16a_compact(self);
230 0           XSRETURN(2);
231             }
232             }
233 0           self->iter_pos = 0;
234 0           XSRETURN_EMPTY;
235             }
236              
237             void
238             shift(SV* self_sv)
239             PPCODE:
240 0 0         EXTRACT_MAP(HashMapI16A, stash_i16a, "Data::HashMap::I16A", self_sv);
    0          
    0          
    0          
241 0 0         uint32_t now = self->expires_at ? (uint32_t)time(NULL) : 0;
242 0 0         if (self->lru_prev) {
243 0 0         while (self->lru_head != HM_LRU_NONE) {
244 0           uint32_t idx = self->lru_head;
245 0 0         if (HM_UNLIKELY(self->expires_at && self->expires_at[idx]) && now >= self->expires_at[idx]) {
    0          
    0          
246 0           hashmap_i16a_expire_at(self, idx, true); continue;
247             }
248 0 0         EXTEND(SP, 2);
249 0 0         mXPUSHi(self->nodes[idx].key);
250 0 0         if (self->nodes[idx].value) {
251 0 0         mXPUSHs((SV*)self->nodes[idx].value);
252 0 0         } else { XPUSHs(&PL_sv_undef); }
253 0           self->nodes[idx].value = NULL;
254 0           hashmap_i16a_lru_unlink(self, idx);
255 0           hashmap_i16a_tombstone_at(self, idx);
256 0 0         if (self->tombstones > self->capacity / 4 ||
257 0 0         (self->size > 0 && self->tombstones > self->size))
    0          
258 0           hashmap_i16a_compact(self);
259 0           XSRETURN(2);
260             }
261 0           XSRETURN_EMPTY;
262             } else {
263 0 0         if (self->iter_pos == 0) self->iter_pos = self->capacity;
264 0 0         while (self->iter_pos > 0) {
265 0           size_t i = --self->iter_pos;
266 0 0         if (I16A_NODE_LIVE(self->nodes[i]) && !HM_TTL_SKIP_EXPIRED(self, i, now)) {
    0          
    0          
    0          
    0          
267 0 0         EXTEND(SP, 2);
268 0 0         mXPUSHi(self->nodes[i].key);
269 0 0         if (self->nodes[i].value) {
270 0 0         mXPUSHs((SV*)self->nodes[i].value);
271 0 0         } else { XPUSHs(&PL_sv_undef); }
272 0           self->nodes[i].value = NULL;
273 0           hashmap_i16a_tombstone_at(self, i);
274 0 0         if (self->tombstones > self->capacity / 4 ||
275 0 0         (self->size > 0 && self->tombstones > self->size))
    0          
276 0           hashmap_i16a_compact(self);
277 0           XSRETURN(2);
278             }
279             }
280 0           XSRETURN_EMPTY;
281             }
282              
283              
284             void
285             clear(SV* self_sv)
286             CODE:
287 3 50         EXTRACT_MAP(HashMapI16A, stash_i16a, "Data::HashMap::I16A", self_sv);
    50          
    50          
    50          
288 3           hashmap_i16a_clear(self);
289              
290             void
291             reserve(SV* self_sv, UV count)
292             CODE:
293 0 0         EXTRACT_MAP(HashMapI16A, stash_i16a, "Data::HashMap::I16A", self_sv);
    0          
    0          
    0          
294 0 0         if (!hashmap_i16a_reserve(self, (size_t)count))
295 0           croak("Failed to reserve capacity");
296              
297             void
298             purge(SV* self_sv)
299             CODE:
300 0 0         EXTRACT_MAP(HashMapI16A, stash_i16a, "Data::HashMap::I16A", self_sv);
    0          
    0          
    0          
301 0           hashmap_i16a_purge(self);
302              
303             SV*
304             freeze(SV* self_sv)
305             CODE:
306 0           croak("freeze not supported for SV* variants; use to_hash + Storable");
307             RETVAL = &PL_sv_undef;
308             OUTPUT:
309             RETVAL
310              
311              
312             UV
313             capacity(SV* self_sv)
314             CODE:
315 0 0         EXTRACT_MAP(HashMapI16A, stash_i16a, "Data::HashMap::I16A", self_sv);
    0          
    0          
    0          
316 0 0         RETVAL = (UV)self->capacity;
317             OUTPUT:
318             RETVAL
319              
320             bool
321             persist(SV* self_sv, int16_t key)
322             CODE:
323 0 0         EXTRACT_MAP(HashMapI16A, stash_i16a, "Data::HashMap::I16A", self_sv);
    0          
    0          
    0          
324 0           RETVAL = hashmap_i16a_persist(self, key);
325             OUTPUT:
326             RETVAL
327              
328             SV*
329             swap(SV* self_sv, int16_t key, SV* new_val)
330             CODE:
331 0 0         EXTRACT_MAP(HashMapI16A, stash_i16a, "Data::HashMap::I16A", self_sv);
    0          
    0          
    0          
332             void* old;
333 0           SvREFCNT_inc(new_val);
334 0 0         if (!hashmap_i16a_swap(self, key, (void*)new_val, &old)) { SvREFCNT_dec(new_val); XSRETURN_UNDEF; }
335 0           RETVAL = (SV*)old;
336             OUTPUT:
337             RETVAL
338              
339              
340             SV*
341             clone(SV* self_sv)
342             CODE:
343 0 0         EXTRACT_MAP(HashMapI16A, stash_i16a, "Data::HashMap::I16A", self_sv);
    0          
    0          
    0          
344 0           HashMapI16A* clone = hashmap_i16a_clone(self);
345 0 0         if (!clone) croak("Failed to clone");
346 0 0         { size_t _i; for (_i = 0; _i < clone->capacity; _i++) {
347 0 0         if (I16A_NODE_LIVE(clone->nodes[_i]) && clone->nodes[_i].value)
    0          
    0          
348 0           SvREFCNT_inc((SV*)clone->nodes[_i].value);
349             } }
350 0 0         RETVAL = sv_setref_pv(newSV(0), HvNAME(SvSTASH(SvRV(self_sv))), (void*)clone);
    0          
    0          
    0          
    0          
    0          
351             OUTPUT:
352             RETVAL
353              
354             void
355             from_hash(SV* self_sv, SV* href)
356             CODE:
357 0 0         EXTRACT_MAP(HashMapI16A, stash_i16a, "Data::HashMap::I16A", self_sv);
    0          
    0          
    0          
358 0 0         if (!SvROK(href) || SvTYPE(SvRV(href)) != SVt_PVHV)
    0          
359 0           croak("from_hash requires a hashref");
360 0           HV* hv = (HV*)SvRV(href);
361 0 0         hashmap_i16a_reserve(self, (size_t)HvUSEDKEYS(hv));
362 0           hv_iterinit(hv);
363             HE* he;
364 0 0         while ((he = hv_iternext(hv))) {
365 0           SV* ksv = hv_iterkeysv(he);
366 0           int16_t key = (int16_t)SvIV(ksv);
367 0           SV* val = HeVAL(he);
368 0           SvREFCNT_inc(val);
369 0 0         if (!hashmap_i16a_put(self, key, (void*)val, 0)) SvREFCNT_dec(val);
370             }
371              
372             void
373             merge(SV* self_sv, SV* other_sv)
374             CODE:
375 0 0         EXTRACT_MAP(HashMapI16A, stash_i16a, "Data::HashMap::I16A", self_sv);
    0          
    0          
    0          
376 0 0         if (!SvROK(other_sv) || !SvOBJECT(SvRV(other_sv)) || SvSTASH(SvRV(other_sv)) != stash_i16a)
    0          
    0          
377 0           croak("Expected a Data::HashMap::I16A object");
378 0           HashMapI16A* other = INT2PTR(HashMapI16A*, SvIV(SvRV(other_sv)));
379 0           hashmap_i16a_reserve(self, self->size + other->size);
380 0 0         uint32_t now = other->expires_at ? (uint32_t)time(NULL) : 0;
381             size_t i;
382 0 0         for (i = 0; i < other->capacity; i++) {
383 0 0         if (I16A_NODE_LIVE(other->nodes[i]) && !HM_TTL_SKIP_EXPIRED(other, i, now)) {
    0          
    0          
    0          
    0          
384 0           SvREFCNT_inc((SV*)other->nodes[i].value);
385 0 0         if (!hashmap_i16a_put(self, other->nodes[i].key, (void*)other->nodes[i].value, 0)) SvREFCNT_dec((SV*)other->nodes[i].value);
386             }
387             }
388              
389              
390             SV*
391             to_hash(SV* self_sv)
392             CODE:
393 0 0         EXTRACT_MAP(HashMapI16A, stash_i16a, "Data::HashMap::I16A", self_sv);
    0          
    0          
    0          
394 0           HV* hv = newHV();
395 0 0         uint32_t now = self->expires_at ? (uint32_t)time(NULL) : 0;
396             size_t i;
397 0 0         for (i = 0; i < self->capacity; i++) {
398 0 0         if (I16A_NODE_LIVE(self->nodes[i]) && !HM_TTL_SKIP_EXPIRED(self, i, now)) {
    0          
    0          
    0          
    0          
399 0 0         SV* val = self->nodes[i].value ? SvREFCNT_inc((SV*)self->nodes[i].value) : &PL_sv_undef;
400             char kbuf[24];
401 0           int klen = my_snprintf(kbuf, sizeof(kbuf), "%" IVdf, (IV)self->nodes[i].key);
402 0           (void)hv_store(hv, kbuf, klen, val, 0);
403             }
404             }
405 0           RETVAL = newRV_noinc((SV*)hv);
406             OUTPUT:
407             RETVAL
408              
409             bool
410             put_ttl(SV* self_sv, int16_t key, SV* value, UV ttl)
411             CODE:
412 0 0         EXTRACT_MAP(HashMapI16A, stash_i16a, "Data::HashMap::I16A", self_sv);
    0          
    0          
    0          
413 0           SvREFCNT_inc(value);
414 0           RETVAL = hashmap_i16a_put(self, key, (void*)value, (uint32_t)ttl);
415 0 0         if (!RETVAL) SvREFCNT_dec(value);
416             OUTPUT:
417             RETVAL
418              
419             SV*
420             get_or_set(SV* self_sv, int16_t key, SV* default_value)
421             CODE:
422 2 50         EXTRACT_MAP(HashMapI16A, stash_i16a, "Data::HashMap::I16A", self_sv);
    50          
    50          
    50          
423             bool was_found;
424 2           SvREFCNT_inc(default_value);
425 2           size_t idx = hashmap_i16a_get_or_set(self, key, (void*)default_value, 0, &was_found);
426 2 50         if (idx >= self->capacity) {
427 0           SvREFCNT_dec(default_value);
428 0           XSRETURN_UNDEF;
429             }
430 2 50         if (was_found) SvREFCNT_dec(default_value);
431 2           RETVAL = SvREFCNT_inc((SV*)self->nodes[idx].value);
432             OUTPUT:
433             RETVAL
434              
435              
436