File Coverage

xs/ia.xsi
Criterion Covered Total %
statement 133 213 62.4
branch 202 582 34.7
condition n/a
subroutine n/a
pod n/a
total 335 795 42.1


line stmt bran cond sub pod time code
1             MODULE = Data::HashMap PACKAGE = Data::HashMap::IA
2             PROTOTYPES: DISABLE
3              
4             SV*
5             new(char* class, ...)
6             CODE:
7 55 100         EXTRACT_NEW_ARGS(_max_size, _ttl, _lru_skip);
    100          
    50          
8 55           HashMapIA* map = hashmap_ia_create(_max_size, _ttl, _lru_skip);
9 55 50         if (!map) croak("Failed to create HashMap::IA");
10 55           map->free_value_fn = hm_sv_free;
11 55           RETVAL = sv_setref_pv(newSV(0), class, (void*)map);
12             OUTPUT:
13             RETVAL
14              
15             void
16             DESTROY(SV* self_sv)
17             CODE:
18 56 50         EXTRACT_MAP(HashMapIA, stash_ia, "Data::HashMap::IA", self_sv);
    50          
    50          
    50          
19 56           hashmap_ia_destroy(self);
20 56           sv_setiv(SvRV(self_sv), 0);
21              
22             bool
23             put(SV* self_sv, int64_t key, SV* value)
24             CODE:
25 81926 50         EXTRACT_MAP(HashMapIA, stash_ia, "Data::HashMap::IA", self_sv);
    50          
    50          
    50          
26 81926           SvREFCNT_inc(value);
27 81926           RETVAL = hashmap_ia_put(self, key, (void*)value, 0);
28 81926 100         if (!RETVAL) SvREFCNT_dec(value);
29             OUTPUT:
30             RETVAL
31              
32             SV*
33             get(SV* self_sv, int64_t key)
34             CODE:
35 50026 50         EXTRACT_MAP(HashMapIA, stash_ia, "Data::HashMap::IA", self_sv);
    50          
    50          
    50          
36             void* val;
37 50026 100         if (!hashmap_ia_get(self, key, &val)) XSRETURN_UNDEF;
38 50019           RETVAL = SvREFCNT_inc((SV*)val);
39             OUTPUT:
40             RETVAL
41              
42             bool
43             remove(SV* self_sv, int64_t key)
44             CODE:
45 80505 50         EXTRACT_MAP(HashMapIA, stash_ia, "Data::HashMap::IA", self_sv);
    50          
    50          
    50          
46 80505           RETVAL = hashmap_ia_remove(self, key);
47             OUTPUT:
48             RETVAL
49              
50             SV*
51             take(SV* self_sv, int64_t key)
52             CODE:
53 2 50         EXTRACT_MAP(HashMapIA, stash_ia, "Data::HashMap::IA", self_sv);
    50          
    50          
    50          
54             void* val;
55 2 100         if (!hashmap_ia_take(self, key, &val)) XSRETURN_UNDEF;
56 1           RETVAL = (SV*)val;
57             OUTPUT:
58             RETVAL
59              
60             bool
61             exists(SV* self_sv, int64_t key)
62             CODE:
63 4 50         EXTRACT_MAP(HashMapIA, stash_ia, "Data::HashMap::IA", self_sv);
    50          
    50          
    50          
64 4           RETVAL = hashmap_ia_exists(self, key);
65             OUTPUT:
66             RETVAL
67              
68             size_t
69             size(SV* self_sv)
70             CODE:
71 16 50         EXTRACT_MAP(HashMapIA, stash_ia, "Data::HashMap::IA", self_sv);
    50          
    50          
    50          
72 16 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(HashMapIA, stash_ia, "Data::HashMap::IA", 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(HashMapIA, stash_ia, "Data::HashMap::IA", 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(HashMapIA, stash_ia, "Data::HashMap::IA", 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 5 50         EXTRACT_MAP(HashMapIA, stash_ia, "Data::HashMap::IA", self_sv);
    50          
    50          
    50          
104 5 100         uint32_t now = self->expires_at ? (uint32_t)time(NULL) : 0;
105 5 50         EXTEND(SP, self->size);
106             size_t i;
107 309 100         for (i = 0; i < self->capacity; i++) {
108 304 100         if (IA_NODE_LIVE(self->nodes[i]) && !HM_TTL_SKIP_EXPIRED(self, i, now))
    100          
    100          
    50          
    50          
109 100 50         mXPUSHi(self->nodes[i].key);
110             }
111              
112             void
113             values(SV* self_sv)
114             PPCODE:
115 3 50         EXTRACT_MAP(HashMapIA, stash_ia, "Data::HashMap::IA", self_sv);
    50          
    50          
    50          
116 3 50         uint32_t now = self->expires_at ? (uint32_t)time(NULL) : 0;
117 3 50         EXTEND(SP, self->size);
118             size_t i;
119 275 100         for (i = 0; i < self->capacity; i++) {
120 272 100         if (IA_NODE_LIVE(self->nodes[i]) && !HM_TTL_SKIP_EXPIRED(self, i, now)) {
    100          
    50          
    0          
    0          
121 100 50         SV* sv = self->nodes[i].value ? SvREFCNT_inc((SV*)self->nodes[i].value) : &PL_sv_undef;
122 100 50         mXPUSHs(sv);
123             }
124             }
125              
126             void
127             items(SV* self_sv)
128             PPCODE:
129 1 50         EXTRACT_MAP(HashMapIA, stash_ia, "Data::HashMap::IA", 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 (IA_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 48 50         EXTRACT_MAP(HashMapIA, stash_ia, "Data::HashMap::IA", self_sv);
    50          
    50          
    50          
145 48 50         uint32_t now = self->expires_at ? (uint32_t)time(NULL) : 0;
146 100 100         while (self->iter_pos < self->capacity) {
147 96           size_t i = self->iter_pos++;
148 96 100         if (IA_NODE_LIVE(self->nodes[i]) && !HM_TTL_SKIP_EXPIRED(self, i, now)) {
    50          
    50          
    0          
    0          
149 44 50         EXTEND(SP, 2);
150 44 50         mXPUSHi(self->nodes[i].key);
151 44 50         if (GIMME_V == G_SCALAR) XSRETURN(1);
152 44 50         SV* sv = self->nodes[i].value ? SvREFCNT_inc((SV*)self->nodes[i].value) : &PL_sv_undef;
153 44 50         mXPUSHs(sv);
154 44           XSRETURN(2);
155             }
156             }
157 4           self->iter_pos = 0;
158 4           XSRETURN_EMPTY;
159              
160             void
161             iter_reset(SV* self_sv)
162             CODE:
163 0 0         EXTRACT_MAP(HashMapIA, stash_ia, "Data::HashMap::IA", self_sv);
    0          
    0          
    0          
164 0           self->iter_pos = 0;
165              
166             void
167             drain(SV* self_sv, UV count)
168             PPCODE:
169 1 50         EXTRACT_MAP(HashMapIA, stash_ia, "Data::HashMap::IA", self_sv);
    50          
    50          
    50          
170 1 50         uint32_t now = self->expires_at ? (uint32_t)time(NULL) : 0;
171 1           UV n = 0;
172 1 50         EXTEND(SP, (count < self->size ? count : self->size) * 2);
173 15 50         while (self->iter_pos < self->capacity && n < count) {
    100          
174 14           size_t i = self->iter_pos++;
175 14 100         if (IA_NODE_LIVE(self->nodes[i]) && !HM_TTL_SKIP_EXPIRED(self, i, now)) {
    50          
    50          
    0          
    0          
176 2 50         mXPUSHi(self->nodes[i].key);
177 2 50         if (self->nodes[i].value) {
178 2 50         mXPUSHs((SV*)self->nodes[i].value);
179 0 0         } else { XPUSHs(&PL_sv_undef); }
180 2           self->nodes[i].value = NULL;
181 2 50         if (HM_UNLIKELY(self->lru_prev)) hashmap_ia_lru_unlink(self, (uint32_t)i);
182 2           hashmap_ia_tombstone_at(self, i);
183 2           n++;
184             }
185             }
186 1 50         if (self->iter_pos >= self->capacity) self->iter_pos = 0;
187 1 50         HM_MAYBE_COMPACT_XS(self, hashmap_ia_compact);
    50          
    50          
188              
189             void
190             pop(SV* self_sv)
191             PPCODE:
192 1 50         EXTRACT_MAP(HashMapIA, stash_ia, "Data::HashMap::IA", self_sv);
    50          
    50          
    50          
193 1 50         uint32_t now = self->expires_at ? (uint32_t)time(NULL) : 0;
194 1 50         if (self->lru_prev) {
195 1 50         while (self->lru_tail != HM_LRU_NONE) {
196 1           uint32_t idx = self->lru_tail;
197 1 50         if (HM_UNLIKELY(HM_TTL_SKIP_EXPIRED(self, idx, now))) {
    0          
    50          
    0          
198 0           hashmap_ia_expire_at(self, idx, true); continue;
199             }
200 1 50         EXTEND(SP, 2);
201 1 50         mXPUSHi(self->nodes[idx].key);
202 1 50         if (self->nodes[idx].value) {
203 1 50         mXPUSHs((SV*)self->nodes[idx].value);
204 0 0         } else { XPUSHs(&PL_sv_undef); }
205 1           self->nodes[idx].value = NULL;
206 1           hashmap_ia_lru_unlink(self, idx);
207 1           hashmap_ia_tombstone_at(self, idx);
208 1 50         HM_MAYBE_COMPACT_XS(self, hashmap_ia_compact);
    50          
    50          
209 1           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 (IA_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_ia_tombstone_at(self, i);
223 0 0         HM_MAYBE_COMPACT_XS(self, hashmap_ia_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(HashMapIA, stash_ia, "Data::HashMap::IA", 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_ia_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_ia_lru_unlink(self, idx);
249 0           hashmap_ia_tombstone_at(self, idx);
250 0 0         HM_MAYBE_COMPACT_XS(self, hashmap_ia_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 (IA_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_ia_tombstone_at(self, i);
266 0 0         HM_MAYBE_COMPACT_XS(self, hashmap_ia_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 7 50         EXTRACT_MAP(HashMapIA, stash_ia, "Data::HashMap::IA", self_sv);
    50          
    50          
    50          
278 7           hashmap_ia_clear(self);
279              
280             void
281             reserve(SV* self_sv, UV count)
282             CODE:
283 0 0         EXTRACT_MAP(HashMapIA, stash_ia, "Data::HashMap::IA", self_sv);
    0          
    0          
    0          
284 0 0         if (!hashmap_ia_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(HashMapIA, stash_ia, "Data::HashMap::IA", self_sv);
    0          
    0          
    0          
291 0           hashmap_ia_purge(self);
292              
293             SV*
294             freeze(SV* self_sv)
295             CODE:
296 1           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(HashMapIA, stash_ia, "Data::HashMap::IA", self_sv);
    0          
    0          
    0          
306 0 0         RETVAL = (UV)self->capacity;
307             OUTPUT:
308             RETVAL
309              
310             bool
311             persist(SV* self_sv, int64_t key)
312             CODE:
313 0 0         EXTRACT_MAP(HashMapIA, stash_ia, "Data::HashMap::IA", self_sv);
    0          
    0          
    0          
314 0           RETVAL = hashmap_ia_persist(self, key);
315             OUTPUT:
316             RETVAL
317              
318             SV*
319             swap(SV* self_sv, int64_t key, SV* new_val)
320             CODE:
321 2 50         EXTRACT_MAP(HashMapIA, stash_ia, "Data::HashMap::IA", self_sv);
    50          
    50          
    50          
322             void* old;
323 2           SvREFCNT_inc(new_val);
324 2 100         if (!hashmap_ia_swap(self, key, (void*)new_val, &old)) { SvREFCNT_dec(new_val); XSRETURN_UNDEF; }
325 1           RETVAL = (SV*)old;
326             OUTPUT:
327             RETVAL
328              
329              
330             SV*
331             clone(SV* self_sv)
332             CODE:
333 1 50         EXTRACT_MAP(HashMapIA, stash_ia, "Data::HashMap::IA", self_sv);
    50          
    50          
    50          
334 1           HashMapIA* clone = hashmap_ia_clone(self);
335 1 50         if (!clone) croak("Failed to clone");
336 17 100         { size_t _i; for (_i = 0; _i < clone->capacity; _i++) {
337 16 100         if (IA_NODE_LIVE(clone->nodes[_i]) && clone->nodes[_i].value)
    50          
    50          
338 1           SvREFCNT_inc((SV*)clone->nodes[_i].value);
339             } }
340 1 50         RETVAL = sv_setref_pv(newSV(0), HvNAME(SvSTASH(SvRV(self_sv))), (void*)clone);
    50          
    50          
    0          
    50          
    50          
341             OUTPUT:
342             RETVAL
343              
344             void
345             from_hash(SV* self_sv, SV* href)
346             CODE:
347 1 50         EXTRACT_MAP(HashMapIA, stash_ia, "Data::HashMap::IA", self_sv);
    50          
    50          
    50          
348 1 50         if (!SvROK(href) || SvTYPE(SvRV(href)) != SVt_PVHV)
    50          
349 0           croak("from_hash requires a hashref");
350 1           HV* hv = (HV*)SvRV(href);
351 1 50         hashmap_ia_reserve(self, (size_t)HvUSEDKEYS(hv));
352 1           hv_iterinit(hv);
353             HE* he;
354 4 100         while ((he = hv_iternext(hv))) {
355 2           SV* ksv = hv_iterkeysv(he);
356 2           int64_t key = (int64_t)SvIV(ksv);
357 2           SV* val = HeVAL(he);
358 2           SvREFCNT_inc(val);
359 2 50         if (!hashmap_ia_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(HashMapIA, stash_ia, "Data::HashMap::IA", self_sv);
    0          
    0          
    0          
366 0 0         if (!SvROK(other_sv) || !SvOBJECT(SvRV(other_sv)) || SvSTASH(SvRV(other_sv)) != stash_ia)
    0          
    0          
367 0           croak("Expected a Data::HashMap::IA object");
368 0           HashMapIA* other = INT2PTR(HashMapIA*, SvIV(SvRV(other_sv)));
369 0           hashmap_ia_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 (IA_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_ia_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 3 50         EXTRACT_MAP(HashMapIA, stash_ia, "Data::HashMap::IA", self_sv);
    50          
    50          
    50          
384 3           HV* hv = newHV();
385 3 50         uint32_t now = self->expires_at ? (uint32_t)time(NULL) : 0;
386             size_t i;
387 83 100         for (i = 0; i < self->capacity; i++) {
388 80 100         if (IA_NODE_LIVE(self->nodes[i]) && !HM_TTL_SKIP_EXPIRED(self, i, now)) {
    50          
    50          
    0          
    0          
389 41 50         SV* val = self->nodes[i].value ? SvREFCNT_inc((SV*)self->nodes[i].value) : &PL_sv_undef;
390             char kbuf[24];
391 41           int klen = my_snprintf(kbuf, sizeof(kbuf), "%" IVdf, (IV)self->nodes[i].key);
392 41           (void)hv_store(hv, kbuf, klen, val, 0);
393             }
394             }
395 3           RETVAL = newRV_noinc((SV*)hv);
396             OUTPUT:
397             RETVAL
398              
399             bool
400             put_ttl(SV* self_sv, int64_t key, SV* value, UV ttl)
401             CODE:
402 101 50         EXTRACT_MAP(HashMapIA, stash_ia, "Data::HashMap::IA", self_sv);
    50          
    50          
    50          
403 101           SvREFCNT_inc(value);
404 101           RETVAL = hashmap_ia_put(self, key, (void*)value, (uint32_t)ttl);
405 101 50         if (!RETVAL) SvREFCNT_dec(value);
406             OUTPUT:
407             RETVAL
408              
409             SV*
410             get_or_set(SV* self_sv, int64_t key, SV* default_value)
411             CODE:
412 4 50         EXTRACT_MAP(HashMapIA, stash_ia, "Data::HashMap::IA", self_sv);
    50          
    50          
    50          
413             bool was_found;
414 4           SvREFCNT_inc(default_value);
415 4           size_t idx = hashmap_ia_get_or_set(self, key, (void*)default_value, 0, &was_found);
416 4 50         if (idx >= self->capacity) {
417 0           SvREFCNT_dec(default_value);
418 0           XSRETURN_UNDEF;
419             }
420 4 100         if (was_found) SvREFCNT_dec(default_value);
421 4           RETVAL = SvREFCNT_inc((SV*)self->nodes[idx].value);
422             OUTPUT:
423             RETVAL
424              
425              
426