File Coverage

xs/i32a.xsi
Criterion Covered Total %
statement 75 213 35.2
branch 120 582 20.6
condition n/a
subroutine n/a
pod n/a
total 195 795 24.5


line stmt bran cond sub pod time code
1             MODULE = Data::HashMap PACKAGE = Data::HashMap::I32A
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           HashMapI32A* map = hashmap_i32a_create(_max_size, _ttl, _lru_skip);
9 16 50         if (!map) croak("Failed to create HashMap::I32A");
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(HashMapI32A, stash_i32a, "Data::HashMap::I32A", self_sv);
    50          
    50          
    50          
19 16           hashmap_i32a_destroy(self);
20 16           sv_setiv(SvRV(self_sv), 0);
21              
22             bool
23             put(SV* self_sv, int32_t key, SV* value)
24             CODE:
25 50128 50         EXTRACT_MAP(HashMapI32A, stash_i32a, "Data::HashMap::I32A", self_sv);
    50          
    50          
    50          
26 50128           SvREFCNT_inc(value);
27 50128           RETVAL = hashmap_i32a_put(self, key, (void*)value, 0);
28 50128 100         if (!RETVAL) SvREFCNT_dec(value);
29             OUTPUT:
30             RETVAL
31              
32             SV*
33             get(SV* self_sv, int32_t key)
34             CODE:
35 50016 50         EXTRACT_MAP(HashMapI32A, stash_i32a, "Data::HashMap::I32A", self_sv);
    50          
    50          
    50          
36             void* val;
37 50016 100         if (!hashmap_i32a_get(self, key, &val)) XSRETURN_UNDEF;
38 50012           RETVAL = SvREFCNT_inc((SV*)val);
39             OUTPUT:
40             RETVAL
41              
42             bool
43             remove(SV* self_sv, int32_t key)
44             CODE:
45 50005 50         EXTRACT_MAP(HashMapI32A, stash_i32a, "Data::HashMap::I32A", self_sv);
    50          
    50          
    50          
46 50005           RETVAL = hashmap_i32a_remove(self, key);
47             OUTPUT:
48             RETVAL
49              
50             SV*
51             take(SV* self_sv, int32_t key)
52             CODE:
53 1 50         EXTRACT_MAP(HashMapI32A, stash_i32a, "Data::HashMap::I32A", self_sv);
    50          
    50          
    50          
54             void* val;
55 1 50         if (!hashmap_i32a_take(self, key, &val)) XSRETURN_UNDEF;
56 1           RETVAL = (SV*)val;
57             OUTPUT:
58             RETVAL
59              
60             bool
61             exists(SV* self_sv, int32_t key)
62             CODE:
63 3 50         EXTRACT_MAP(HashMapI32A, stash_i32a, "Data::HashMap::I32A", self_sv);
    50          
    50          
    50          
64 3           RETVAL = hashmap_i32a_exists(self, key);
65             OUTPUT:
66             RETVAL
67              
68             size_t
69             size(SV* self_sv)
70             CODE:
71 9 50         EXTRACT_MAP(HashMapI32A, stash_i32a, "Data::HashMap::I32A", 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(HashMapI32A, stash_i32a, "Data::HashMap::I32A", 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(HashMapI32A, stash_i32a, "Data::HashMap::I32A", 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(HashMapI32A, stash_i32a, "Data::HashMap::I32A", 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(HashMapI32A, stash_i32a, "Data::HashMap::I32A", 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 (I32A_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(HashMapI32A, stash_i32a, "Data::HashMap::I32A", 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 (I32A_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(HashMapI32A, stash_i32a, "Data::HashMap::I32A", 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 (I32A_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(HashMapI32A, stash_i32a, "Data::HashMap::I32A", 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 (I32A_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(HashMapI32A, stash_i32a, "Data::HashMap::I32A", 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(HashMapI32A, stash_i32a, "Data::HashMap::I32A", 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 (I32A_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_i32a_lru_unlink(self, (uint32_t)i);
182 0           hashmap_i32a_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         HM_MAYBE_COMPACT_XS(self, hashmap_i32a_compact);
    0          
    0          
188              
189             void
190             pop(SV* self_sv)
191             PPCODE:
192 0 0         EXTRACT_MAP(HashMapI32A, stash_i32a, "Data::HashMap::I32A", self_sv);
    0          
    0          
    0          
193 0 0         uint32_t now = self->expires_at ? (uint32_t)time(NULL) : 0;
194 0 0         if (self->lru_prev) {
195 0 0         while (self->lru_tail != HM_LRU_NONE) {
196 0           uint32_t idx = self->lru_tail;
197 0 0         if (HM_UNLIKELY(HM_TTL_SKIP_EXPIRED(self, idx, now))) {
    0          
    0          
    0          
198 0           hashmap_i32a_expire_at(self, idx, true); continue;
199             }
200 0 0         EXTEND(SP, 2);
201 0 0         mXPUSHi(self->nodes[idx].key);
202 0 0         if (self->nodes[idx].value) {
203 0 0         mXPUSHs((SV*)self->nodes[idx].value);
204 0 0         } else { XPUSHs(&PL_sv_undef); }
205 0           self->nodes[idx].value = NULL;
206 0           hashmap_i32a_lru_unlink(self, idx);
207 0           hashmap_i32a_tombstone_at(self, idx);
208 0 0         HM_MAYBE_COMPACT_XS(self, hashmap_i32a_compact);
    0          
    0          
209 0           XSRETURN(2);
210             }
211 0           XSRETURN_EMPTY;
212             } else {
213 0 0         while (self->iter_pos < self->capacity) {
214 0           size_t i = self->iter_pos++;
215 0 0         if (I32A_NODE_LIVE(self->nodes[i]) && !HM_TTL_SKIP_EXPIRED(self, i, now)) {
    0          
    0          
    0          
    0          
216 0 0         EXTEND(SP, 2);
217 0 0         mXPUSHi(self->nodes[i].key);
218 0 0         if (self->nodes[i].value) {
219 0 0         mXPUSHs((SV*)self->nodes[i].value);
220 0 0         } else { XPUSHs(&PL_sv_undef); }
221 0           self->nodes[i].value = NULL;
222 0           hashmap_i32a_tombstone_at(self, i);
223 0 0         HM_MAYBE_COMPACT_XS(self, hashmap_i32a_compact);
    0          
    0          
224 0           XSRETURN(2);
225             }
226             }
227 0           self->iter_pos = 0;
228 0           XSRETURN_EMPTY;
229             }
230              
231             void
232             shift(SV* self_sv)
233             PPCODE:
234 0 0         EXTRACT_MAP(HashMapI32A, stash_i32a, "Data::HashMap::I32A", self_sv);
    0          
    0          
    0          
235 0 0         uint32_t now = self->expires_at ? (uint32_t)time(NULL) : 0;
236 0 0         if (self->lru_prev) {
237 0 0         while (self->lru_head != HM_LRU_NONE) {
238 0           uint32_t idx = self->lru_head;
239 0 0         if (HM_UNLIKELY(HM_TTL_SKIP_EXPIRED(self, idx, now))) {
    0          
    0          
    0          
240 0           hashmap_i32a_expire_at(self, idx, true); continue;
241             }
242 0 0         EXTEND(SP, 2);
243 0 0         mXPUSHi(self->nodes[idx].key);
244 0 0         if (self->nodes[idx].value) {
245 0 0         mXPUSHs((SV*)self->nodes[idx].value);
246 0 0         } else { XPUSHs(&PL_sv_undef); }
247 0           self->nodes[idx].value = NULL;
248 0           hashmap_i32a_lru_unlink(self, idx);
249 0           hashmap_i32a_tombstone_at(self, idx);
250 0 0         HM_MAYBE_COMPACT_XS(self, hashmap_i32a_compact);
    0          
    0          
251 0           XSRETURN(2);
252             }
253 0           XSRETURN_EMPTY;
254             } else {
255 0 0         if (self->iter_pos == 0) self->iter_pos = self->capacity;
256 0 0         while (self->iter_pos > 0) {
257 0           size_t i = --self->iter_pos;
258 0 0         if (I32A_NODE_LIVE(self->nodes[i]) && !HM_TTL_SKIP_EXPIRED(self, i, now)) {
    0          
    0          
    0          
    0          
259 0 0         EXTEND(SP, 2);
260 0 0         mXPUSHi(self->nodes[i].key);
261 0 0         if (self->nodes[i].value) {
262 0 0         mXPUSHs((SV*)self->nodes[i].value);
263 0 0         } else { XPUSHs(&PL_sv_undef); }
264 0           self->nodes[i].value = NULL;
265 0           hashmap_i32a_tombstone_at(self, i);
266 0 0         HM_MAYBE_COMPACT_XS(self, hashmap_i32a_compact);
    0          
    0          
267 0           XSRETURN(2);
268             }
269             }
270 0           XSRETURN_EMPTY;
271             }
272              
273              
274             void
275             clear(SV* self_sv)
276             CODE:
277 3 50         EXTRACT_MAP(HashMapI32A, stash_i32a, "Data::HashMap::I32A", self_sv);
    50          
    50          
    50          
278 3           hashmap_i32a_clear(self);
279              
280             void
281             reserve(SV* self_sv, UV count)
282             CODE:
283 0 0         EXTRACT_MAP(HashMapI32A, stash_i32a, "Data::HashMap::I32A", self_sv);
    0          
    0          
    0          
284 0 0         if (!hashmap_i32a_reserve(self, (size_t)count))
285 0           croak("Failed to reserve capacity");
286              
287             void
288             purge(SV* self_sv)
289             CODE:
290 0 0         EXTRACT_MAP(HashMapI32A, stash_i32a, "Data::HashMap::I32A", self_sv);
    0          
    0          
    0          
291 0           hashmap_i32a_purge(self);
292              
293             SV*
294             freeze(SV* self_sv)
295             CODE:
296 0           croak("freeze not supported for SV* variants; use to_hash + Storable");
297             RETVAL = &PL_sv_undef;
298             OUTPUT:
299             RETVAL
300              
301              
302             UV
303             capacity(SV* self_sv)
304             CODE:
305 0 0         EXTRACT_MAP(HashMapI32A, stash_i32a, "Data::HashMap::I32A", self_sv);
    0          
    0          
    0          
306 0 0         RETVAL = (UV)self->capacity;
307             OUTPUT:
308             RETVAL
309              
310             bool
311             persist(SV* self_sv, int32_t key)
312             CODE:
313 0 0         EXTRACT_MAP(HashMapI32A, stash_i32a, "Data::HashMap::I32A", self_sv);
    0          
    0          
    0          
314 0           RETVAL = hashmap_i32a_persist(self, key);
315             OUTPUT:
316             RETVAL
317              
318             SV*
319             swap(SV* self_sv, int32_t key, SV* new_val)
320             CODE:
321 0 0         EXTRACT_MAP(HashMapI32A, stash_i32a, "Data::HashMap::I32A", self_sv);
    0          
    0          
    0          
322             void* old;
323 0           SvREFCNT_inc(new_val);
324 0 0         if (!hashmap_i32a_swap(self, key, (void*)new_val, &old)) { SvREFCNT_dec(new_val); XSRETURN_UNDEF; }
325 0           RETVAL = (SV*)old;
326             OUTPUT:
327             RETVAL
328              
329              
330             SV*
331             clone(SV* self_sv)
332             CODE:
333 0 0         EXTRACT_MAP(HashMapI32A, stash_i32a, "Data::HashMap::I32A", self_sv);
    0          
    0          
    0          
334 0           HashMapI32A* clone = hashmap_i32a_clone(self);
335 0 0         if (!clone) croak("Failed to clone");
336 0 0         { size_t _i; for (_i = 0; _i < clone->capacity; _i++) {
337 0 0         if (I32A_NODE_LIVE(clone->nodes[_i]) && clone->nodes[_i].value)
    0          
    0          
338 0           SvREFCNT_inc((SV*)clone->nodes[_i].value);
339             } }
340 0 0         RETVAL = sv_setref_pv(newSV(0), HvNAME(SvSTASH(SvRV(self_sv))), (void*)clone);
    0          
    0          
    0          
    0          
    0          
341             OUTPUT:
342             RETVAL
343              
344             void
345             from_hash(SV* self_sv, SV* href)
346             CODE:
347 0 0         EXTRACT_MAP(HashMapI32A, stash_i32a, "Data::HashMap::I32A", self_sv);
    0          
    0          
    0          
348 0 0         if (!SvROK(href) || SvTYPE(SvRV(href)) != SVt_PVHV)
    0          
349 0           croak("from_hash requires a hashref");
350 0           HV* hv = (HV*)SvRV(href);
351 0 0         hashmap_i32a_reserve(self, (size_t)HvUSEDKEYS(hv));
352 0           hv_iterinit(hv);
353             HE* he;
354 0 0         while ((he = hv_iternext(hv))) {
355 0           SV* ksv = hv_iterkeysv(he);
356 0           int32_t key = (int32_t)SvIV(ksv);
357 0           SV* val = HeVAL(he);
358 0           SvREFCNT_inc(val);
359 0 0         if (!hashmap_i32a_put(self, key, (void*)val, 0)) SvREFCNT_dec(val);
360             }
361              
362             void
363             merge(SV* self_sv, SV* other_sv)
364             CODE:
365 0 0         EXTRACT_MAP(HashMapI32A, stash_i32a, "Data::HashMap::I32A", self_sv);
    0          
    0          
    0          
366 0 0         if (!SvROK(other_sv) || !SvOBJECT(SvRV(other_sv)) || SvSTASH(SvRV(other_sv)) != stash_i32a)
    0          
    0          
367 0           croak("Expected a Data::HashMap::I32A object");
368 0           HashMapI32A* other = INT2PTR(HashMapI32A*, SvIV(SvRV(other_sv)));
369 0           hashmap_i32a_reserve(self, self->size + other->size);
370 0 0         uint32_t now = other->expires_at ? (uint32_t)time(NULL) : 0;
371             size_t i;
372 0 0         for (i = 0; i < other->capacity; i++) {
373 0 0         if (I32A_NODE_LIVE(other->nodes[i]) && !HM_TTL_SKIP_EXPIRED(other, i, now)) {
    0          
    0          
    0          
    0          
374 0           SvREFCNT_inc((SV*)other->nodes[i].value);
375 0 0         if (!hashmap_i32a_put(self, other->nodes[i].key, (void*)other->nodes[i].value, 0)) SvREFCNT_dec((SV*)other->nodes[i].value);
376             }
377             }
378              
379              
380             SV*
381             to_hash(SV* self_sv)
382             CODE:
383 1 50         EXTRACT_MAP(HashMapI32A, stash_i32a, "Data::HashMap::I32A", self_sv);
    50          
    50          
    50          
384 1           HV* hv = newHV();
385 1 50         uint32_t now = self->expires_at ? (uint32_t)time(NULL) : 0;
386             size_t i;
387 17 100         for (i = 0; i < self->capacity; i++) {
388 16 100         if (I32A_NODE_LIVE(self->nodes[i]) && !HM_TTL_SKIP_EXPIRED(self, i, now)) {
    50          
    50          
    0          
    0          
389 1 50         SV* val = self->nodes[i].value ? SvREFCNT_inc((SV*)self->nodes[i].value) : &PL_sv_undef;
390             char kbuf[24];
391 1           int klen = my_snprintf(kbuf, sizeof(kbuf), "%" IVdf, (IV)self->nodes[i].key);
392 1           (void)hv_store(hv, kbuf, klen, val, 0);
393             }
394             }
395 1           RETVAL = newRV_noinc((SV*)hv);
396             OUTPUT:
397             RETVAL
398              
399             bool
400             put_ttl(SV* self_sv, int32_t key, SV* value, UV ttl)
401             CODE:
402 0 0         EXTRACT_MAP(HashMapI32A, stash_i32a, "Data::HashMap::I32A", self_sv);
    0          
    0          
    0          
403 0           SvREFCNT_inc(value);
404 0           RETVAL = hashmap_i32a_put(self, key, (void*)value, (uint32_t)ttl);
405 0 0         if (!RETVAL) SvREFCNT_dec(value);
406             OUTPUT:
407             RETVAL
408              
409             SV*
410             get_or_set(SV* self_sv, int32_t key, SV* default_value)
411             CODE:
412 2 50         EXTRACT_MAP(HashMapI32A, stash_i32a, "Data::HashMap::I32A", self_sv);
    50          
    50          
    50          
413             bool was_found;
414 2           SvREFCNT_inc(default_value);
415 2           size_t idx = hashmap_i32a_get_or_set(self, key, (void*)default_value, 0, &was_found);
416 2 50         if (idx >= self->capacity) {
417 0           SvREFCNT_dec(default_value);
418 0           XSRETURN_UNDEF;
419             }
420 2 50         if (was_found) SvREFCNT_dec(default_value);
421 2           RETVAL = SvREFCNT_inc((SV*)self->nodes[idx].value);
422             OUTPUT:
423             RETVAL
424              
425              
426