File Coverage

xs/sa.xsi
Criterion Covered Total %
statement 114 244 46.7
branch 158 622 25.4
condition n/a
subroutine n/a
pod n/a
total 272 866 31.4


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 47 100         EXTRACT_NEW_ARGS(_max_size, _ttl, _lru_skip);
    100          
    50          
8 47           HashMapSA* map = hashmap_sa_create(_max_size, _ttl, _lru_skip);
9 47 50         if (!map) croak("Failed to create HashMap::SA");
10 47           map->free_value_fn = hm_sv_free;
11 47           RETVAL = sv_setref_pv(newSV(0), class, (void*)map);
12             OUTPUT:
13             RETVAL
14              
15             void
16             DESTROY(SV* self_sv)
17             CODE:
18 47 50         EXTRACT_MAP(HashMapSA, stash_sa, "Data::HashMap::SA", self_sv);
    50          
    50          
    50          
19 47           hashmap_sa_destroy(self);
20 47           sv_setiv(SvRV(self_sv), 0);
21              
22             bool
23             put(SV* self_sv, SV* key_sv, SV* value)
24             CODE:
25 81583 50         EXTRACT_MAP(HashMapSA, stash_sa, "Data::HashMap::SA", self_sv);
    50          
    50          
    50          
26 81583 50         EXTRACT_STR_KEY(key_sv);
27 81583           SvREFCNT_inc(value);
28 81583           RETVAL = hashmap_sa_put(self, _kstr, (uint32_t)_klen, _khash, _kutf8, (void*)value, 0);
29 81583 50         if (!RETVAL) SvREFCNT_dec(value);
30             OUTPUT:
31             RETVAL
32              
33             SV*
34             get(SV* self_sv, SV* key_sv)
35             CODE:
36 50026 50         EXTRACT_MAP(HashMapSA, stash_sa, "Data::HashMap::SA", self_sv);
    50          
    50          
    50          
37 50026 50         EXTRACT_STR_KEY(key_sv);
38             void* val;
39 50026 100         if (!hashmap_sa_get(self, _kstr, (uint32_t)_klen, _khash, &val))
40 5           XSRETURN_UNDEF;
41 50021           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);
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, &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);
71             OUTPUT:
72             RETVAL
73              
74             size_t
75             size(SV* self_sv)
76             CODE:
77 14 50         EXTRACT_MAP(HashMapSA, stash_sa, "Data::HashMap::SA", self_sv);
    50          
    50          
    50          
78 14 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         HM_MAYBE_COMPACT_XS(self, hashmap_sa_compact);
    0          
    0          
210              
211             void
212             pop(SV* self_sv)
213             PPCODE:
214 0 0         EXTRACT_MAP(HashMapSA, stash_sa, "Data::HashMap::SA", self_sv);
    0          
    0          
    0          
215 0 0         uint32_t now = self->expires_at ? (uint32_t)time(NULL) : 0;
216 0 0         if (self->lru_prev) {
217 0 0         while (self->lru_tail != HM_LRU_NONE) {
218 0           uint32_t idx = self->lru_tail;
219 0 0         if (HM_UNLIKELY(HM_TTL_SKIP_EXPIRED(self, idx, now))) {
    0          
    0          
    0          
220 0           hashmap_sa_expire_at(self, idx, true); continue;
221             }
222 0 0         EXTEND(SP, 2);
223             {
224 0           SV* ksv = newSVpvn(self->nodes[idx].key, HM_UNPACK_LEN(self->nodes[idx].key_len));
225 0 0         if (HM_UNPACK_UTF8(self->nodes[idx].key_len)) SvUTF8_on(ksv);
226 0 0         mXPUSHs(ksv);
227             }
228 0 0         if (self->nodes[idx].value) {
229 0 0         mXPUSHs((SV*)self->nodes[idx].value);
230 0 0         } else { XPUSHs(&PL_sv_undef); }
231 0           self->nodes[idx].value = NULL;
232 0           hashmap_sa_lru_unlink(self, idx);
233 0           hashmap_sa_tombstone_at(self, idx);
234 0 0         HM_MAYBE_COMPACT_XS(self, hashmap_sa_compact);
    0          
    0          
235 0           XSRETURN(2);
236             }
237 0           XSRETURN_EMPTY;
238             } else {
239 0 0         while (self->iter_pos < self->capacity) {
240 0           size_t i = self->iter_pos++;
241 0 0         if (SA_NODE_LIVE(self->nodes[i]) && !HM_TTL_SKIP_EXPIRED(self, i, now)) {
    0          
    0          
    0          
    0          
242 0 0         EXTEND(SP, 2);
243             {
244 0           SV* ksv = newSVpvn(self->nodes[i].key, HM_UNPACK_LEN(self->nodes[i].key_len));
245 0 0         if (HM_UNPACK_UTF8(self->nodes[i].key_len)) SvUTF8_on(ksv);
246 0 0         mXPUSHs(ksv);
247             }
248 0 0         if (self->nodes[i].value) {
249 0 0         mXPUSHs((SV*)self->nodes[i].value);
250 0 0         } else { XPUSHs(&PL_sv_undef); }
251 0           self->nodes[i].value = NULL;
252 0           hashmap_sa_tombstone_at(self, i);
253 0 0         HM_MAYBE_COMPACT_XS(self, hashmap_sa_compact);
    0          
    0          
254 0           XSRETURN(2);
255             }
256             }
257 0           self->iter_pos = 0;
258 0           XSRETURN_EMPTY;
259             }
260              
261             void
262             shift(SV* self_sv)
263             PPCODE:
264 1 50         EXTRACT_MAP(HashMapSA, stash_sa, "Data::HashMap::SA", self_sv);
    50          
    50          
    50          
265 1 50         uint32_t now = self->expires_at ? (uint32_t)time(NULL) : 0;
266 1 50         if (self->lru_prev) {
267 1 50         while (self->lru_head != HM_LRU_NONE) {
268 1           uint32_t idx = self->lru_head;
269 1 50         if (HM_UNLIKELY(HM_TTL_SKIP_EXPIRED(self, idx, now))) {
    0          
    50          
    0          
270 0           hashmap_sa_expire_at(self, idx, true); continue;
271             }
272 1 50         EXTEND(SP, 2);
273             {
274 1           SV* ksv = newSVpvn(self->nodes[idx].key, HM_UNPACK_LEN(self->nodes[idx].key_len));
275 1 50         if (HM_UNPACK_UTF8(self->nodes[idx].key_len)) SvUTF8_on(ksv);
276 1 50         mXPUSHs(ksv);
277             }
278 1 50         if (self->nodes[idx].value) {
279 1 50         mXPUSHs((SV*)self->nodes[idx].value);
280 0 0         } else { XPUSHs(&PL_sv_undef); }
281 1           self->nodes[idx].value = NULL;
282 1           hashmap_sa_lru_unlink(self, idx);
283 1           hashmap_sa_tombstone_at(self, idx);
284 1 50         HM_MAYBE_COMPACT_XS(self, hashmap_sa_compact);
    50          
    0          
285 1           XSRETURN(2);
286             }
287 0           XSRETURN_EMPTY;
288             } else {
289 0 0         if (self->iter_pos == 0) self->iter_pos = self->capacity;
290 0 0         while (self->iter_pos > 0) {
291 0           size_t i = --self->iter_pos;
292 0 0         if (SA_NODE_LIVE(self->nodes[i]) && !HM_TTL_SKIP_EXPIRED(self, i, now)) {
    0          
    0          
    0          
    0          
293 0 0         EXTEND(SP, 2);
294             {
295 0           SV* ksv = newSVpvn(self->nodes[i].key, HM_UNPACK_LEN(self->nodes[i].key_len));
296 0 0         if (HM_UNPACK_UTF8(self->nodes[i].key_len)) SvUTF8_on(ksv);
297 0 0         mXPUSHs(ksv);
298             }
299 0 0         if (self->nodes[i].value) {
300 0 0         mXPUSHs((SV*)self->nodes[i].value);
301 0 0         } else { XPUSHs(&PL_sv_undef); }
302 0           self->nodes[i].value = NULL;
303 0           hashmap_sa_tombstone_at(self, i);
304 0 0         HM_MAYBE_COMPACT_XS(self, hashmap_sa_compact);
    0          
    0          
305 0           XSRETURN(2);
306             }
307             }
308 0           XSRETURN_EMPTY;
309             }
310              
311              
312             void
313             clear(SV* self_sv)
314             CODE:
315 3 50         EXTRACT_MAP(HashMapSA, stash_sa, "Data::HashMap::SA", self_sv);
    50          
    50          
    50          
316 3           hashmap_sa_clear(self);
317              
318             void
319             reserve(SV* self_sv, UV count)
320             CODE:
321 0 0         EXTRACT_MAP(HashMapSA, stash_sa, "Data::HashMap::SA", self_sv);
    0          
    0          
    0          
322 0 0         if (!hashmap_sa_reserve(self, (size_t)count))
323 0           croak("Failed to reserve capacity");
324              
325             void
326             purge(SV* self_sv)
327             CODE:
328 0 0         EXTRACT_MAP(HashMapSA, stash_sa, "Data::HashMap::SA", self_sv);
    0          
    0          
    0          
329 0           hashmap_sa_purge(self);
330              
331             SV*
332             freeze(SV* self_sv)
333             CODE:
334 0           croak("freeze not supported for SV* variants; use to_hash + Storable");
335             RETVAL = &PL_sv_undef;
336             OUTPUT:
337             RETVAL
338              
339              
340             UV
341             capacity(SV* self_sv)
342             CODE:
343 0 0         EXTRACT_MAP(HashMapSA, stash_sa, "Data::HashMap::SA", self_sv);
    0          
    0          
    0          
344 0 0         RETVAL = (UV)self->capacity;
345             OUTPUT:
346             RETVAL
347              
348             bool
349             persist(SV* self_sv, SV* key_sv)
350             CODE:
351 0 0         EXTRACT_MAP(HashMapSA, stash_sa, "Data::HashMap::SA", self_sv);
    0          
    0          
    0          
352 0 0         EXTRACT_STR_KEY(key_sv);
353 0           RETVAL = hashmap_sa_persist(self, _kstr, (uint32_t)_klen, _khash);
354             OUTPUT:
355             RETVAL
356              
357             SV*
358             swap(SV* self_sv, SV* key_sv, SV* new_val)
359             CODE:
360 0 0         EXTRACT_MAP(HashMapSA, stash_sa, "Data::HashMap::SA", self_sv);
    0          
    0          
    0          
361 0 0         EXTRACT_STR_KEY(key_sv);
362             void* old;
363 0           SvREFCNT_inc(new_val);
364 0 0         if (!hashmap_sa_swap(self, _kstr, (uint32_t)_klen, _khash, (void*)new_val, &old)) { SvREFCNT_dec(new_val); XSRETURN_UNDEF; }
365 0           RETVAL = (SV*)old;
366             OUTPUT:
367             RETVAL
368              
369              
370             SV*
371             clone(SV* self_sv)
372             CODE:
373 0 0         EXTRACT_MAP(HashMapSA, stash_sa, "Data::HashMap::SA", self_sv);
    0          
    0          
    0          
374 0           HashMapSA* clone = hashmap_sa_clone(self);
375 0 0         if (!clone) croak("Failed to clone");
376 0 0         { size_t _i; for (_i = 0; _i < clone->capacity; _i++) {
377 0 0         if (SA_NODE_LIVE(clone->nodes[_i]) && clone->nodes[_i].value)
    0          
    0          
378 0           SvREFCNT_inc((SV*)clone->nodes[_i].value);
379             } }
380 0 0         RETVAL = sv_setref_pv(newSV(0), HvNAME(SvSTASH(SvRV(self_sv))), (void*)clone);
    0          
    0          
    0          
    0          
    0          
381             OUTPUT:
382             RETVAL
383              
384             void
385             from_hash(SV* self_sv, SV* href)
386             CODE:
387 0 0         EXTRACT_MAP(HashMapSA, stash_sa, "Data::HashMap::SA", self_sv);
    0          
    0          
    0          
388 0 0         if (!SvROK(href) || SvTYPE(SvRV(href)) != SVt_PVHV)
    0          
389 0           croak("from_hash requires a hashref");
390 0           HV* hv = (HV*)SvRV(href);
391 0 0         hashmap_sa_reserve(self, (size_t)HvUSEDKEYS(hv));
392 0           hv_iterinit(hv);
393             HE* he;
394 0 0         while ((he = hv_iternext(hv))) {
395 0 0         STRLEN klen; const char* kstr = HePV(he, klen);
396 0 0         bool kutf8 = HeUTF8(he) ? true : false;
397 0           uint32_t khash = hm_hash_string(kstr, (uint32_t)klen);
398 0           SV* val = HeVAL(he);
399 0           SvREFCNT_inc(val);
400 0 0         if (!hashmap_sa_put(self, kstr, (uint32_t)klen, khash, kutf8, (void*)val, 0)) SvREFCNT_dec(val);
401             }
402              
403             void
404             merge(SV* self_sv, SV* other_sv)
405             CODE:
406 0 0         EXTRACT_MAP(HashMapSA, stash_sa, "Data::HashMap::SA", self_sv);
    0          
    0          
    0          
407 0 0         if (!SvROK(other_sv) || !SvOBJECT(SvRV(other_sv)) || SvSTASH(SvRV(other_sv)) != stash_sa)
    0          
    0          
408 0           croak("Expected a Data::HashMap::SA object");
409 0           HashMapSA* other = INT2PTR(HashMapSA*, SvIV(SvRV(other_sv)));
410 0           hashmap_sa_reserve(self, self->size + other->size);
411 0 0         uint32_t now = other->expires_at ? (uint32_t)time(NULL) : 0;
412             size_t i;
413 0 0         for (i = 0; i < other->capacity; i++) {
414 0 0         if (SA_NODE_LIVE(other->nodes[i]) && !HM_TTL_SKIP_EXPIRED(other, i, now)) {
    0          
    0          
    0          
    0          
415 0           SvREFCNT_inc((SV*)other->nodes[i].value);
416 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);
417             }
418             }
419              
420              
421             SV*
422             to_hash(SV* self_sv)
423             CODE:
424 1 50         EXTRACT_MAP(HashMapSA, stash_sa, "Data::HashMap::SA", self_sv);
    50          
    50          
    50          
425 1           HV* hv = newHV();
426 1 50         uint32_t now = self->expires_at ? (uint32_t)time(NULL) : 0;
427             size_t i;
428 17 100         for (i = 0; i < self->capacity; i++) {
429 16 100         if (SA_NODE_LIVE(self->nodes[i]) && !HM_TTL_SKIP_EXPIRED(self, i, now)) {
    50          
    50          
    0          
    0          
430 1           uint32_t klen = HM_UNPACK_LEN(self->nodes[i].key_len);
431 1           bool kutf8 = HM_UNPACK_UTF8(self->nodes[i].key_len);
432 1 50         SV* val = self->nodes[i].value ? SvREFCNT_inc((SV*)self->nodes[i].value) : &PL_sv_undef;
433 1 50         (void)hv_store(hv, self->nodes[i].key, kutf8 ? -(I32)klen : (I32)klen, val, 0);
434             }
435             }
436 1           RETVAL = newRV_noinc((SV*)hv);
437             OUTPUT:
438             RETVAL
439              
440             bool
441             put_ttl(SV* self_sv, SV* key_sv, SV* value, UV ttl)
442             CODE:
443 1 50         EXTRACT_MAP(HashMapSA, stash_sa, "Data::HashMap::SA", self_sv);
    50          
    50          
    50          
444 1 50         EXTRACT_STR_KEY(key_sv);
445 1           SvREFCNT_inc(value);
446 1           RETVAL = hashmap_sa_put(self, _kstr, (uint32_t)_klen, _khash, _kutf8, (void*)value, (uint32_t)ttl);
447 1 50         if (!RETVAL) SvREFCNT_dec(value);
448             OUTPUT:
449             RETVAL
450              
451             SV*
452             get_or_set(SV* self_sv, SV* key_sv, SV* default_value)
453             CODE:
454 4 50         EXTRACT_MAP(HashMapSA, stash_sa, "Data::HashMap::SA", self_sv);
    50          
    50          
    50          
455 4 50         EXTRACT_STR_KEY(key_sv);
456             bool was_found;
457 4           SvREFCNT_inc(default_value);
458 4           size_t idx = hashmap_sa_get_or_set(self, _kstr, (uint32_t)_klen, _khash, _kutf8, (void*)default_value, 0, &was_found);
459 4 50         if (idx >= self->capacity) {
460 0           SvREFCNT_dec(default_value);
461 0           XSRETURN_UNDEF;
462             }
463 4 100         if (was_found) SvREFCNT_dec(default_value);
464 4           RETVAL = SvREFCNT_inc((SV*)self->nodes[idx].value);
465             OUTPUT:
466             RETVAL