File Coverage

xs/si32.xsi
Criterion Covered Total %
statement 136 293 46.4
branch 186 666 27.9
condition n/a
subroutine n/a
pod n/a
total 322 959 33.5


line stmt bran cond sub pod time code
1             MODULE = Data::HashMap PACKAGE = Data::HashMap::SI32
2             PROTOTYPES: DISABLE
3              
4             SV*
5             new(char* class, ...)
6             CODE:
7 17 100         EXTRACT_NEW_ARGS(_max_size, _ttl, _lru_skip);
    50          
    50          
8 17           HashMapSI32* map = hashmap_si32_create(_max_size, _ttl, _lru_skip);
9 17 50         if (!map) croak("Failed to create HashMap::SI32");
10 17           RETVAL = sv_setref_pv(newSV(0), class, (void*)map);
11             OUTPUT:
12             RETVAL
13              
14             void
15             DESTROY(SV* self_sv)
16             CODE:
17 17 50         EXTRACT_MAP(HashMapSI32, stash_si32, "Data::HashMap::SI32", self_sv);
    50          
    50          
    50          
18 17           hashmap_si32_destroy(self);
19 17           sv_setiv(SvRV(self_sv), 0);
20              
21             bool
22             put(SV* self_sv, SV* key_sv, int32_t value)
23             CODE:
24 80223 50         EXTRACT_MAP(HashMapSI32, stash_si32, "Data::HashMap::SI32", self_sv);
    50          
    50          
    50          
25 80223 50         EXTRACT_STR_KEY(key_sv);
26 80223           RETVAL = hashmap_si32_put(self, _kstr, (uint32_t)_klen, _khash, _kutf8, value, 0);
27             OUTPUT:
28             RETVAL
29              
30             SV*
31             get(SV* self_sv, SV* key_sv)
32             CODE:
33 50010 50         EXTRACT_MAP(HashMapSI32, stash_si32, "Data::HashMap::SI32", self_sv);
    50          
    50          
    50          
34 50010 50         EXTRACT_STR_KEY(key_sv);
35             int32_t value;
36 50010 100         if (!hashmap_si32_get(self, _kstr, (uint32_t)_klen, _khash, _kutf8, &value))
37 3           XSRETURN_UNDEF;
38 50007           RETVAL = newSViv(value);
39             OUTPUT:
40             RETVAL
41              
42             bool
43             remove(SV* self_sv, SV* key_sv)
44             CODE:
45 80005 50         EXTRACT_MAP(HashMapSI32, stash_si32, "Data::HashMap::SI32", self_sv);
    50          
    50          
    50          
46 80005 50         EXTRACT_STR_KEY(key_sv);
47 80005           RETVAL = hashmap_si32_remove(self, _kstr, (uint32_t)_klen, _khash, _kutf8);
48             OUTPUT:
49             RETVAL
50              
51             SV*
52             take(SV* self_sv, SV* key_sv)
53             CODE:
54 1 50         EXTRACT_MAP(HashMapSI32, stash_si32, "Data::HashMap::SI32", self_sv);
    50          
    50          
    50          
55 1 50         EXTRACT_STR_KEY(key_sv);
56             int32_t value;
57 1 50         if (!hashmap_si32_take(self, _kstr, (uint32_t)_klen, _khash, _kutf8, &value)) XSRETURN_UNDEF;
58 1           RETVAL = newSViv(value);
59             OUTPUT:
60             RETVAL
61              
62             bool
63             exists(SV* self_sv, SV* key_sv)
64             CODE:
65 2 50         EXTRACT_MAP(HashMapSI32, stash_si32, "Data::HashMap::SI32", self_sv);
    50          
    50          
    50          
66 2 50         EXTRACT_STR_KEY(key_sv);
67 2           RETVAL = hashmap_si32_exists(self, _kstr, (uint32_t)_klen, _khash, _kutf8);
68             OUTPUT:
69             RETVAL
70              
71             SV*
72             incr(SV* self_sv, SV* key_sv)
73             CODE:
74 12 50         EXTRACT_MAP(HashMapSI32, stash_si32, "Data::HashMap::SI32", self_sv);
    50          
    50          
    50          
75 12 50         EXTRACT_STR_KEY(key_sv);
76             int32_t val;
77 12 100         if (!hashmap_si32_increment(self, _kstr, (uint32_t)_klen, _khash, _kutf8, &val))
78 1           croak("HashMap::SI32: increment failed");
79 11           RETVAL = newSViv(val);
80             OUTPUT:
81             RETVAL
82              
83             SV*
84             decr(SV* self_sv, SV* key_sv)
85             CODE:
86 3 50         EXTRACT_MAP(HashMapSI32, stash_si32, "Data::HashMap::SI32", self_sv);
    50          
    50          
    50          
87 3 50         EXTRACT_STR_KEY(key_sv);
88             int32_t val;
89 3 100         if (!hashmap_si32_decrement(self, _kstr, (uint32_t)_klen, _khash, _kutf8, &val))
90 1           croak("HashMap::SI32: decrement failed");
91 2           RETVAL = newSViv(val);
92             OUTPUT:
93             RETVAL
94              
95             SV*
96             incr_by(SV* self_sv, SV* key_sv, int32_t delta)
97             CODE:
98 6 50         EXTRACT_MAP(HashMapSI32, stash_si32, "Data::HashMap::SI32", self_sv);
    50          
    50          
    50          
99 6 50         EXTRACT_STR_KEY(key_sv);
100             int32_t val;
101 6 100         if (!hashmap_si32_increment_by(self, _kstr, (uint32_t)_klen, _khash, _kutf8, delta, &val))
102 2           croak("HashMap::SI32: incr_by failed");
103 4           RETVAL = newSViv(val);
104             OUTPUT:
105             RETVAL
106              
107             size_t
108             size(SV* self_sv)
109             CODE:
110 5 50         EXTRACT_MAP(HashMapSI32, stash_si32, "Data::HashMap::SI32", self_sv);
    50          
    50          
    50          
111 5 50         RETVAL = self->size;
112             OUTPUT:
113             RETVAL
114              
115             size_t
116             max_size(SV* self_sv)
117             CODE:
118 0 0         EXTRACT_MAP(HashMapSI32, stash_si32, "Data::HashMap::SI32", self_sv);
    0          
    0          
    0          
119 0 0         RETVAL = self->max_size;
120             OUTPUT:
121             RETVAL
122              
123             UV
124             ttl(SV* self_sv)
125             CODE:
126 0 0         EXTRACT_MAP(HashMapSI32, stash_si32, "Data::HashMap::SI32", self_sv);
    0          
    0          
    0          
127 0 0         RETVAL = (UV)self->default_ttl;
128             OUTPUT:
129             RETVAL
130              
131             UV
132             lru_skip(SV* self_sv)
133             CODE:
134 0 0         EXTRACT_MAP(HashMapSI32, stash_si32, "Data::HashMap::SI32", self_sv);
    0          
    0          
    0          
135 0 0         RETVAL = (UV)self->lru_skip;
136             OUTPUT:
137             RETVAL
138              
139             void
140             keys(SV* self_sv)
141             PPCODE:
142 3 50         EXTRACT_MAP(HashMapSI32, stash_si32, "Data::HashMap::SI32", self_sv);
    50          
    50          
    50          
143 3 50         uint32_t now = self->expires_at ? (uint32_t)time(NULL) : 0;
144 3 50         EXTEND(SP, self->size);
145             size_t i;
146 51 100         for (i = 0; i < self->capacity; i++) {
147 48 100         if (SI32_NODE_LIVE(self->nodes[i]) && !HM_TTL_SKIP_EXPIRED(self, i, now)) {
    100          
    50          
    0          
    0          
148 7           uint32_t klen = HM_UNPACK_LEN(self->nodes[i].key_len);
149 7           SV* sv = newSVpvn(self->nodes[i].key, klen);
150 7 100         if (HM_UNPACK_UTF8(self->nodes[i].key_len)) SvUTF8_on(sv);
151 7 50         mXPUSHs(sv);
152             }
153             }
154              
155             void
156             values(SV* self_sv)
157             PPCODE:
158 1 50         EXTRACT_MAP(HashMapSI32, stash_si32, "Data::HashMap::SI32", self_sv);
    50          
    50          
    50          
159 1 50         uint32_t now = self->expires_at ? (uint32_t)time(NULL) : 0;
160 1 50         EXTEND(SP, self->size);
161             size_t i;
162 17 100         for (i = 0; i < self->capacity; i++) {
163 16 100         if (SI32_NODE_LIVE(self->nodes[i]) && !HM_TTL_SKIP_EXPIRED(self, i, now))
    50          
    50          
    0          
    0          
164 2 50         mXPUSHi(self->nodes[i].value);
165             }
166              
167             void
168             items(SV* self_sv)
169             PPCODE:
170 2 50         EXTRACT_MAP(HashMapSI32, stash_si32, "Data::HashMap::SI32", self_sv);
    50          
    50          
    50          
171 2 50         uint32_t now = self->expires_at ? (uint32_t)time(NULL) : 0;
172 2 50         EXTEND(SP, self->size * 2);
173             size_t i;
174 34 100         for (i = 0; i < self->capacity; i++) {
175 32 100         if (SI32_NODE_LIVE(self->nodes[i]) && !HM_TTL_SKIP_EXPIRED(self, i, now)) {
    100          
    50          
    0          
    0          
176 7           uint32_t klen = HM_UNPACK_LEN(self->nodes[i].key_len);
177 7           SV* sv = newSVpvn(self->nodes[i].key, klen);
178 7 100         if (HM_UNPACK_UTF8(self->nodes[i].key_len)) SvUTF8_on(sv);
179 7 50         mXPUSHs(sv);
180 7 50         mXPUSHi(self->nodes[i].value);
181             }
182             }
183              
184             void
185             each(SV* self_sv)
186             PPCODE:
187 3 50         EXTRACT_MAP(HashMapSI32, stash_si32, "Data::HashMap::SI32", self_sv);
    50          
    50          
    50          
188 3 50         uint32_t now = self->expires_at ? (uint32_t)time(NULL) : 0;
189 17 100         while (self->iter_pos < self->capacity) {
190 16           size_t i = self->iter_pos++;
191 16 100         if (SI32_NODE_LIVE(self->nodes[i]) && !HM_TTL_SKIP_EXPIRED(self, i, now)) {
    50          
    50          
    0          
    0          
192 2 50         EXTEND(SP, 2);
193             {
194 2           uint32_t klen = HM_UNPACK_LEN(self->nodes[i].key_len);
195 2           SV* ksv = newSVpvn(self->nodes[i].key, klen);
196 2 50         if (HM_UNPACK_UTF8(self->nodes[i].key_len)) SvUTF8_on(ksv);
197 2 50         mXPUSHs(ksv);
198             }
199 2 50         if (GIMME_V == G_SCALAR) XSRETURN(1);
200 2 50         mXPUSHi(self->nodes[i].value);
201 2           XSRETURN(2);
202             }
203             }
204 1           self->iter_pos = 0;
205 1           XSRETURN_EMPTY;
206              
207             void
208             iter_reset(SV* self_sv)
209             CODE:
210 0 0         EXTRACT_MAP(HashMapSI32, stash_si32, "Data::HashMap::SI32", self_sv);
    0          
    0          
    0          
211 0           self->iter_pos = 0;
212              
213             void
214             drain(SV* self_sv, UV count)
215             PPCODE:
216 1 50         EXTRACT_MAP(HashMapSI32, stash_si32, "Data::HashMap::SI32", self_sv);
    50          
    50          
    50          
217 1 50         uint32_t now = self->expires_at ? (uint32_t)time(NULL) : 0;
218 1           UV n = 0;
219 1 50         EXTEND(SP, (count < self->size ? count : self->size) * 2);
220 2 50         while (self->iter_pos < self->capacity && n < count) {
    100          
221 1           size_t i = self->iter_pos++;
222 1 50         if (SI32_NODE_LIVE(self->nodes[i]) && !HM_TTL_SKIP_EXPIRED(self, i, now)) {
    50          
    50          
    0          
    0          
223             {
224 1           SV* ksv = newSVpvn(self->nodes[i].key, HM_UNPACK_LEN(self->nodes[i].key_len));
225 1 50         if (HM_UNPACK_UTF8(self->nodes[i].key_len)) SvUTF8_on(ksv);
226 1 50         mXPUSHs(ksv);
227             }
228 1 50         mXPUSHi(self->nodes[i].value);
229 1 50         if (HM_UNLIKELY(self->lru_prev)) hashmap_si32_lru_unlink(self, (uint32_t)i);
230 1           hashmap_si32_tombstone_at(self, i);
231 1           n++;
232             }
233             }
234 1 50         if (self->iter_pos >= self->capacity) self->iter_pos = 0;
235 1 50         if (self->tombstones > self->capacity / 4 ||
236 1 50         (self->size > 0 && self->tombstones > self->size))
    50          
237 1           hashmap_si32_compact(self);
238              
239             void
240             pop(SV* self_sv)
241             PPCODE:
242 1 50         EXTRACT_MAP(HashMapSI32, stash_si32, "Data::HashMap::SI32", self_sv);
    50          
    50          
    50          
243 1 50         uint32_t now = self->expires_at ? (uint32_t)time(NULL) : 0;
244 1 50         if (self->lru_prev) {
245 1 50         while (self->lru_tail != HM_LRU_NONE) {
246 1           uint32_t idx = self->lru_tail;
247 1 50         if (HM_UNLIKELY(self->expires_at && self->expires_at[idx]) && now >= self->expires_at[idx]) {
    0          
    0          
248 0           hashmap_si32_expire_at(self, idx, true); continue;
249             }
250 1 50         EXTEND(SP, 2);
251             {
252 1           SV* ksv = newSVpvn(self->nodes[idx].key, HM_UNPACK_LEN(self->nodes[idx].key_len));
253 1 50         if (HM_UNPACK_UTF8(self->nodes[idx].key_len)) SvUTF8_on(ksv);
254 1 50         mXPUSHs(ksv);
255             }
256 1 50         mXPUSHi(self->nodes[idx].value);
257 1           hashmap_si32_lru_unlink(self, idx);
258 1           hashmap_si32_tombstone_at(self, idx);
259 1 50         if (self->tombstones > self->capacity / 4 ||
260 1 50         (self->size > 0 && self->tombstones > self->size))
    0          
261 0           hashmap_si32_compact(self);
262 1           XSRETURN(2);
263             }
264 0           XSRETURN_EMPTY;
265             } else {
266 0 0         while (self->iter_pos < self->capacity) {
267 0           size_t i = self->iter_pos++;
268 0 0         if (SI32_NODE_LIVE(self->nodes[i]) && !HM_TTL_SKIP_EXPIRED(self, i, now)) {
    0          
    0          
    0          
    0          
269 0 0         EXTEND(SP, 2);
270             {
271 0           SV* ksv = newSVpvn(self->nodes[i].key, HM_UNPACK_LEN(self->nodes[i].key_len));
272 0 0         if (HM_UNPACK_UTF8(self->nodes[i].key_len)) SvUTF8_on(ksv);
273 0 0         mXPUSHs(ksv);
274             }
275 0 0         mXPUSHi(self->nodes[i].value);
276 0           hashmap_si32_tombstone_at(self, i);
277 0 0         if (self->tombstones > self->capacity / 4 ||
278 0 0         (self->size > 0 && self->tombstones > self->size))
    0          
279 0           hashmap_si32_compact(self);
280 0           XSRETURN(2);
281             }
282             }
283 0           self->iter_pos = 0;
284 0           XSRETURN_EMPTY;
285             }
286              
287             void
288             shift(SV* self_sv)
289             PPCODE:
290 0 0         EXTRACT_MAP(HashMapSI32, stash_si32, "Data::HashMap::SI32", self_sv);
    0          
    0          
    0          
291 0 0         uint32_t now = self->expires_at ? (uint32_t)time(NULL) : 0;
292 0 0         if (self->lru_prev) {
293 0 0         while (self->lru_head != HM_LRU_NONE) {
294 0           uint32_t idx = self->lru_head;
295 0 0         if (HM_UNLIKELY(self->expires_at && self->expires_at[idx]) && now >= self->expires_at[idx]) {
    0          
    0          
296 0           hashmap_si32_expire_at(self, idx, true); continue;
297             }
298 0 0         EXTEND(SP, 2);
299             {
300 0           SV* ksv = newSVpvn(self->nodes[idx].key, HM_UNPACK_LEN(self->nodes[idx].key_len));
301 0 0         if (HM_UNPACK_UTF8(self->nodes[idx].key_len)) SvUTF8_on(ksv);
302 0 0         mXPUSHs(ksv);
303             }
304 0 0         mXPUSHi(self->nodes[idx].value);
305 0           hashmap_si32_lru_unlink(self, idx);
306 0           hashmap_si32_tombstone_at(self, idx);
307 0 0         if (self->tombstones > self->capacity / 4 ||
308 0 0         (self->size > 0 && self->tombstones > self->size))
    0          
309 0           hashmap_si32_compact(self);
310 0           XSRETURN(2);
311             }
312 0           XSRETURN_EMPTY;
313             } else {
314 0 0         if (self->iter_pos == 0) self->iter_pos = self->capacity;
315 0 0         while (self->iter_pos > 0) {
316 0           size_t i = --self->iter_pos;
317 0 0         if (SI32_NODE_LIVE(self->nodes[i]) && !HM_TTL_SKIP_EXPIRED(self, i, now)) {
    0          
    0          
    0          
    0          
318 0 0         EXTEND(SP, 2);
319             {
320 0           SV* ksv = newSVpvn(self->nodes[i].key, HM_UNPACK_LEN(self->nodes[i].key_len));
321 0 0         if (HM_UNPACK_UTF8(self->nodes[i].key_len)) SvUTF8_on(ksv);
322 0 0         mXPUSHs(ksv);
323             }
324 0 0         mXPUSHi(self->nodes[i].value);
325 0           hashmap_si32_tombstone_at(self, i);
326 0 0         if (self->tombstones > self->capacity / 4 ||
327 0 0         (self->size > 0 && self->tombstones > self->size))
    0          
328 0           hashmap_si32_compact(self);
329 0           XSRETURN(2);
330             }
331             }
332 0           XSRETURN_EMPTY;
333             }
334              
335              
336             void
337             clear(SV* self_sv)
338             CODE:
339 2 50         EXTRACT_MAP(HashMapSI32, stash_si32, "Data::HashMap::SI32", self_sv);
    50          
    50          
    50          
340 2           hashmap_si32_clear(self);
341              
342             void
343             reserve(SV* self_sv, UV count)
344             CODE:
345 0 0         EXTRACT_MAP(HashMapSI32, stash_si32, "Data::HashMap::SI32", self_sv);
    0          
    0          
    0          
346 0 0         if (!hashmap_si32_reserve(self, (size_t)count))
347 0           croak("Failed to reserve capacity");
348              
349             void
350             purge(SV* self_sv)
351             CODE:
352 0 0         EXTRACT_MAP(HashMapSI32, stash_si32, "Data::HashMap::SI32", self_sv);
    0          
    0          
    0          
353 0           hashmap_si32_purge(self);
354              
355             SV*
356             freeze(SV* self_sv)
357             CODE:
358 0 0         EXTRACT_MAP(HashMapSI32, stash_si32, "Data::HashMap::SI32", self_sv);
    0          
    0          
    0          
359 0 0         uint32_t now = self->expires_at ? (uint32_t)time(NULL) : 0;
360 0           SV* buf = newSV(22 + self->size * 32);
361 0           SvPOK_on(buf);
362 0           SvCUR_set(buf, 0);
363             /* Header: magic(4) + version(1) + variant_id(1) + count(4) + max_size(4) + ttl(4) + lru_skip(4) */
364 0           sv_catpvn(buf, "DHMP", 4);
365 0           { uint8_t ver = 1; sv_catpvn(buf, (const char*)&ver, 1); }
366 0           { uint8_t vid = 6; sv_catpvn(buf, (const char*)&vid, 1); }
367 0           STRLEN cnt_offset = SvCUR(buf);
368 0           { uint32_t cnt = 0; sv_catpvn(buf, (const char*)&cnt, 4); }
369 0           UV n_written = 0;
370 0           { uint32_t ms = (uint32_t)self->max_size; sv_catpvn(buf, (const char*)&ms, 4); }
371 0           { uint32_t dt = self->default_ttl; sv_catpvn(buf, (const char*)&dt, 4); }
372 0           { uint32_t ls = self->lru_skip; sv_catpvn(buf, (const char*)&ls, 4); }
373             { size_t i;
374 0 0         for (i = 0; i < self->capacity; i++) {
375 0 0         if (SI32_NODE_LIVE(self->nodes[i]) && !HM_TTL_SKIP_EXPIRED(self, i, now)) {
    0          
    0          
    0          
    0          
376 0           uint32_t kl = HM_UNPACK_LEN(self->nodes[i].key_len);
377 0           uint8_t ku = HM_UNPACK_UTF8(self->nodes[i].key_len) ? 1 : 0;
378 0           sv_catpvn(buf, (const char*)&kl, 4);
379 0           sv_catpvn(buf, (const char*)&ku, 1);
380 0           sv_catpvn(buf, self->nodes[i].key, kl);
381 0           sv_catpvn(buf, (const char*)&self->nodes[i].value, 4);
382             /* TTL: remaining seconds (0 = none) */
383 0           { uint32_t rem = 0;
384 0 0         if (self->expires_at && self->expires_at[i] && self->expires_at[i] > now)
    0          
    0          
385 0           rem = self->expires_at[i] - now;
386 0           sv_catpvn(buf, (const char*)&rem, 4);
387             }
388 0           n_written++;
389             }
390             }
391             }
392 0           { uint32_t actual = (uint32_t)n_written;
393 0           memcpy(SvPVX(buf) + cnt_offset, &actual, 4); }
394 0           RETVAL = buf;
395             OUTPUT:
396             RETVAL
397              
398             SV*
399             thaw(char* class, SV* data)
400             CODE:
401             STRLEN dlen;
402 0           const uint8_t* p = (const uint8_t*)SvPV(data, dlen);
403 0           const uint8_t* end = p + dlen;
404 0 0         if (dlen < 22 || memcmp(p, "DHMP", 4) != 0) croak("Invalid freeze data");
    0          
405 0           p += 4;
406 0 0         uint8_t ver = *p++; if (ver != 1) croak("Unsupported freeze version %d", ver);
407 0 0         uint8_t vid = *p++; if (vid != 6) croak("Variant mismatch: expected 6, got %d", vid);
408 0           uint32_t cnt; memcpy(&cnt, p, 4); p += 4;
409 0           uint32_t ms; memcpy(&ms, p, 4); p += 4;
410 0           uint32_t dt; memcpy(&dt, p, 4); p += 4;
411 0           uint32_t ls; memcpy(&ls, p, 4); p += 4;
412 0           HashMapSI32* map = hashmap_si32_create((size_t)ms, dt, ls);
413 0 0         if (!map) croak("Failed to create map for thaw");
414 0 0         if (cnt > 0) hashmap_si32_reserve(map, (size_t)cnt);
415             { uint32_t j;
416 0 0         for (j = 0; j < cnt; j++) {
417 0 0         if (p + 13 > end) { hashmap_si32_destroy(map); croak("Truncated freeze data"); }
418 0           uint32_t kl; memcpy(&kl, p, 4); p += 4;
419 0           uint8_t ku = *p++; bool kutf8 = ku ? true : false;
420 0 0         if (p + kl + 8 > end) { hashmap_si32_destroy(map); croak("Truncated freeze data"); }
421 0           const char* kstr = (const char*)p; p += kl;
422 0           uint32_t khash = hm_hash_string(kstr, kl);
423 0           int32_t val; memcpy(&val, p, 4); p += 4;
424 0           uint32_t ttl; memcpy(&ttl, p, 4); p += 4;
425 0           hashmap_si32_put(map, kstr, kl, khash, kutf8, val, ttl);
426             }
427             }
428 0 0         if (p > end) croak("Truncated freeze data");
429 0           RETVAL = sv_setref_pv(newSV(0), class, (void*)map);
430             OUTPUT:
431             RETVAL
432              
433              
434             UV
435             capacity(SV* self_sv)
436             CODE:
437 0 0         EXTRACT_MAP(HashMapSI32, stash_si32, "Data::HashMap::SI32", self_sv);
    0          
    0          
    0          
438 0 0         RETVAL = (UV)self->capacity;
439             OUTPUT:
440             RETVAL
441              
442             bool
443             persist(SV* self_sv, SV* key_sv)
444             CODE:
445 0 0         EXTRACT_MAP(HashMapSI32, stash_si32, "Data::HashMap::SI32", self_sv);
    0          
    0          
    0          
446 0 0         EXTRACT_STR_KEY(key_sv);
447 0           RETVAL = hashmap_si32_persist(self, _kstr, (uint32_t)_klen, _khash, _kutf8);
448             OUTPUT:
449             RETVAL
450              
451             SV*
452             swap(SV* self_sv, SV* key_sv, int32_t new_val)
453             CODE:
454 0 0         EXTRACT_MAP(HashMapSI32, stash_si32, "Data::HashMap::SI32", self_sv);
    0          
    0          
    0          
455 0 0         EXTRACT_STR_KEY(key_sv);
456             int32_t old;
457 0 0         if (!hashmap_si32_swap(self, _kstr, (uint32_t)_klen, _khash, _kutf8, new_val, &old)) XSRETURN_UNDEF;
458 0           RETVAL = newSViv(old);
459             OUTPUT:
460             RETVAL
461              
462             bool
463             cas(SV* self_sv, SV* key_sv, int32_t expected, int32_t new_val)
464             CODE:
465 0 0         EXTRACT_MAP(HashMapSI32, stash_si32, "Data::HashMap::SI32", self_sv);
    0          
    0          
    0          
466 0 0         EXTRACT_STR_KEY(key_sv);
467 0           RETVAL = hashmap_si32_cas(self, _kstr, (uint32_t)_klen, _khash, _kutf8, expected, new_val);
468             OUTPUT:
469             RETVAL
470              
471              
472             SV*
473             clone(SV* self_sv)
474             CODE:
475 0 0         EXTRACT_MAP(HashMapSI32, stash_si32, "Data::HashMap::SI32", self_sv);
    0          
    0          
    0          
476 0           HashMapSI32* clone = hashmap_si32_clone(self);
477 0 0         if (!clone) croak("Failed to clone");
478 0 0         RETVAL = sv_setref_pv(newSV(0), HvNAME(SvSTASH(SvRV(self_sv))), (void*)clone);
    0          
    0          
    0          
    0          
    0          
479             OUTPUT:
480             RETVAL
481              
482             void
483             from_hash(SV* self_sv, SV* href)
484             CODE:
485 0 0         EXTRACT_MAP(HashMapSI32, stash_si32, "Data::HashMap::SI32", self_sv);
    0          
    0          
    0          
486 0 0         if (!SvROK(href) || SvTYPE(SvRV(href)) != SVt_PVHV)
    0          
487 0           croak("from_hash requires a hashref");
488 0           HV* hv = (HV*)SvRV(href);
489 0 0         hashmap_si32_reserve(self, (size_t)HvUSEDKEYS(hv));
490 0           hv_iterinit(hv);
491             HE* he;
492 0 0         while ((he = hv_iternext(hv))) {
493 0 0         STRLEN klen; const char* kstr = HePV(he, klen);
494 0 0         bool kutf8 = HeUTF8(he) ? true : false;
495 0           uint32_t khash = hm_hash_string(kstr, (uint32_t)klen);
496 0           SV* val = HeVAL(he);
497 0           hashmap_si32_put(self, kstr, (uint32_t)klen, khash, kutf8, (int32_t)SvIV(val), 0);
498             }
499              
500             void
501             merge(SV* self_sv, SV* other_sv)
502             CODE:
503 0 0         EXTRACT_MAP(HashMapSI32, stash_si32, "Data::HashMap::SI32", self_sv);
    0          
    0          
    0          
504 0 0         if (!SvROK(other_sv) || !SvOBJECT(SvRV(other_sv)) || SvSTASH(SvRV(other_sv)) != stash_si32)
    0          
    0          
505 0           croak("Expected a Data::HashMap::SI32 object");
506 0           HashMapSI32* other = INT2PTR(HashMapSI32*, SvIV(SvRV(other_sv)));
507 0           hashmap_si32_reserve(self, self->size + other->size);
508 0 0         uint32_t now = other->expires_at ? (uint32_t)time(NULL) : 0;
509             size_t i;
510 0 0         for (i = 0; i < other->capacity; i++) {
511 0 0         if (SI32_NODE_LIVE(other->nodes[i]) && !HM_TTL_SKIP_EXPIRED(other, i, now))
    0          
    0          
    0          
    0          
512 0           hashmap_si32_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), other->nodes[i].value, 0);
513             }
514              
515              
516             SV*
517             to_hash(SV* self_sv)
518             CODE:
519 1 50         EXTRACT_MAP(HashMapSI32, stash_si32, "Data::HashMap::SI32", self_sv);
    50          
    50          
    50          
520 1           HV* hv = newHV();
521 1 50         uint32_t now = self->expires_at ? (uint32_t)time(NULL) : 0;
522             size_t i;
523 17 100         for (i = 0; i < self->capacity; i++) {
524 16 100         if (SI32_NODE_LIVE(self->nodes[i]) && !HM_TTL_SKIP_EXPIRED(self, i, now)) {
    50          
    50          
    0          
    0          
525 1           uint32_t klen = HM_UNPACK_LEN(self->nodes[i].key_len);
526 1           bool kutf8 = HM_UNPACK_UTF8(self->nodes[i].key_len);
527 1           SV* val = newSViv(self->nodes[i].value);
528 1 50         (void)hv_store(hv, self->nodes[i].key, kutf8 ? -(I32)klen : (I32)klen, val, 0);
529             }
530             }
531 1           RETVAL = newRV_noinc((SV*)hv);
532             OUTPUT:
533             RETVAL
534              
535             bool
536             put_ttl(SV* self_sv, SV* key_sv, int32_t value, UV ttl)
537             CODE:
538 1 50         EXTRACT_MAP(HashMapSI32, stash_si32, "Data::HashMap::SI32", self_sv);
    50          
    50          
    50          
539 1 50         EXTRACT_STR_KEY(key_sv);
540 1           RETVAL = hashmap_si32_put(self, _kstr, (uint32_t)_klen, _khash, _kutf8, value, (uint32_t)ttl);
541             OUTPUT:
542             RETVAL
543              
544             SV*
545             get_or_set(SV* self_sv, SV* key_sv, int32_t default_value)
546             CODE:
547 1 50         EXTRACT_MAP(HashMapSI32, stash_si32, "Data::HashMap::SI32", self_sv);
    50          
    50          
    50          
548 1 50         EXTRACT_STR_KEY(key_sv);
549             bool was_found;
550 1           size_t idx = hashmap_si32_get_or_set(self, _kstr, (uint32_t)_klen, _khash, _kutf8, default_value, 0, &was_found);
551             (void)was_found;
552 1 50         if (idx >= self->capacity) XSRETURN_UNDEF;
553 1           RETVAL = newSViv(self->nodes[idx].value);
554             OUTPUT:
555             RETVAL
556              
557              
558