File Coverage

xs/sa.xsi
Criterion Covered Total %
statement 115 254 45.2
branch 157 618 25.4
condition n/a
subroutine n/a
pod n/a
total 272 872 31.1


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