File Coverage

xs/i16.xs
Criterion Covered Total %
statement 82 290 28.2
branch 105 570 18.4
condition n/a
subroutine n/a
pod n/a
total 187 860 21.7


line stmt bran cond sub pod time code
1             MODULE = Data::HashMap::Shared PACKAGE = Data::HashMap::Shared::I16
2             PROTOTYPES: DISABLE
3              
4             SV*
5             new(char* class, char* path, UV max_entries, UV lru_max = 0, UV ttl_default = 0, UV lru_skip = 0)
6             CODE:
7 4           char errbuf[SHM_ERR_BUFLEN]; ShmHandle* map = shm_i16_create(path, (uint32_t)max_entries, (uint32_t)lru_max, (uint32_t)ttl_default, (uint32_t)lru_skip, errbuf);
8 4 50         if (!map) croak("HashMap::Shared::I16: %s", errbuf[0] ? errbuf : "unknown error");
    0          
9 4           RETVAL = sv_setref_pv(newSV(0), class, (void*)map);
10             OUTPUT:
11             RETVAL
12              
13             SV*
14             new_sharded(char* class, char* path_prefix, UV num_shards, UV max_entries, UV lru_max = 0, UV ttl_default = 0, UV lru_skip = 0)
15             CODE:
16 0           char errbuf[SHM_ERR_BUFLEN]; ShmHandle* map = shm_i16_create_sharded(path_prefix, (uint32_t)num_shards, (uint32_t)max_entries, (uint32_t)lru_max, (uint32_t)ttl_default, (uint32_t)lru_skip, errbuf);
17 0 0         if (!map) croak("HashMap::Shared::I16: %s", errbuf[0] ? errbuf : "unknown error");
    0          
18 0           RETVAL = sv_setref_pv(newSV(0), class, (void*)map);
19             OUTPUT:
20             RETVAL
21              
22             void
23             DESTROY(SV* self_sv)
24             CODE:
25 4 50         if (!SvROK(self_sv)) return;
26 4           ShmHandle* h = INT2PTR(ShmHandle*, SvIV(SvRV(self_sv)));
27 4 50         if (!h) return;
28 4           shm_close_map(h);
29 4           sv_setiv(SvRV(self_sv), 0);
30              
31             bool
32             put(SV* self_sv, int16_t key, int16_t value)
33             CODE:
34 12 50         EXTRACT_MAP("Data::HashMap::Shared::I16", self_sv);
    50          
    50          
35 12 50         RETVAL = shm_i16_put(h, key, value);
36             OUTPUT:
37             RETVAL
38              
39             SV*
40             get(SV* self_sv, int16_t key)
41             CODE:
42 9 50         EXTRACT_MAP("Data::HashMap::Shared::I16", self_sv);
    50          
    50          
43             int16_t value;
44 9 100         if (!shm_i16_get(h, key, &value)) XSRETURN_UNDEF;
45 8           RETVAL = newSViv(value);
46             OUTPUT:
47             RETVAL
48              
49             bool
50             remove(SV* self_sv, int16_t key)
51             CODE:
52 1 50         EXTRACT_MAP("Data::HashMap::Shared::I16", self_sv);
    50          
    50          
53 1 50         RETVAL = shm_i16_remove(h, key);
54             OUTPUT:
55             RETVAL
56              
57             bool
58             exists(SV* self_sv, int16_t key)
59             CODE:
60 2 50         EXTRACT_MAP("Data::HashMap::Shared::I16", self_sv);
    50          
    50          
61 2 100         RETVAL = shm_i16_exists(h, key);
62             OUTPUT:
63             RETVAL
64              
65             SV*
66             incr(SV* self_sv, int16_t key)
67             CODE:
68 2 50         EXTRACT_MAP("Data::HashMap::Shared::I16", self_sv);
    50          
    50          
69             int ok;
70 2           int16_t val = shm_i16_incr_by(h, key, 1, &ok);
71 2 50         if (!ok) croak("HashMap::Shared::I16: increment failed");
72 2           RETVAL = newSViv(val);
73             OUTPUT:
74             RETVAL
75              
76             SV*
77             decr(SV* self_sv, int16_t key)
78             CODE:
79 1 50         EXTRACT_MAP("Data::HashMap::Shared::I16", self_sv);
    50          
    50          
80             int ok;
81 1           int16_t val = shm_i16_incr_by(h, key, -1, &ok);
82 1 50         if (!ok) croak("HashMap::Shared::I16: decrement failed");
83 1           RETVAL = newSViv(val);
84             OUTPUT:
85             RETVAL
86              
87             SV*
88             incr_by(SV* self_sv, int16_t key, int16_t delta)
89             CODE:
90 1 50         EXTRACT_MAP("Data::HashMap::Shared::I16", self_sv);
    50          
    50          
91             int ok;
92 1           int16_t val = shm_i16_incr_by(h, key, delta, &ok);
93 1 50         if (!ok) croak("HashMap::Shared::I16: incr_by failed");
94 1           RETVAL = newSViv(val);
95             OUTPUT:
96             RETVAL
97              
98             UV
99             size(SV* self_sv)
100             CODE:
101 1 50         EXTRACT_MAP("Data::HashMap::Shared::I16", self_sv);
    50          
    50          
102 1 50         RETVAL = (UV)shm_i16_size(h);
103             OUTPUT:
104             RETVAL
105              
106             UV
107             max_entries(SV* self_sv)
108             CODE:
109 0 0         EXTRACT_MAP("Data::HashMap::Shared::I16", self_sv);
    0          
    0          
110 0 0         RETVAL = (UV)shm_i16_max_entries(h);
111             OUTPUT:
112             RETVAL
113              
114             void
115             keys(SV* self_sv)
116             PPCODE:
117 1 50         EXTRACT_MAP("Data::HashMap::Shared::I16", self_sv);
    50          
    50          
118 1 50         uint32_t ns = h->shard_handles ? h->num_shards : 1;
119 2 100         for (uint32_t si = 0; si < ns; si++) {
120 1 50         ShmHandle *sh = h->shard_handles ? h->shard_handles[si] : h;
121 1           ShmHeader *hdr = sh->hdr;
122 1           ShmNodeI16 *nodes = (ShmNodeI16 *)sh->nodes;
123 1 50         uint32_t now = sh->expires_at ? shm_now() : 0;
124 1           RDLOCK_GUARD(hdr);
125 1 50         EXTEND(SP, hdr->size);
126 17 100         for (uint32_t i = 0; i < hdr->table_cap; i++) {
127 16 100         if (SHM_IS_LIVE(sh->states[i]) && !SHM_IS_EXPIRED(sh, i, now))
    50          
    0          
    0          
128 5 50         mXPUSHi(nodes[i].key);
129             }
130             }
131              
132             void
133             values(SV* self_sv)
134             PPCODE:
135 0 0         EXTRACT_MAP("Data::HashMap::Shared::I16", self_sv);
    0          
    0          
136 0 0         uint32_t ns = h->shard_handles ? h->num_shards : 1;
137 0 0         for (uint32_t si = 0; si < ns; si++) {
138 0 0         ShmHandle *sh = h->shard_handles ? h->shard_handles[si] : h;
139 0           ShmHeader *hdr = sh->hdr;
140 0           ShmNodeI16 *nodes = (ShmNodeI16 *)sh->nodes;
141 0 0         uint32_t now = sh->expires_at ? shm_now() : 0;
142 0           RDLOCK_GUARD(hdr);
143 0 0         EXTEND(SP, hdr->size);
144 0 0         for (uint32_t i = 0; i < hdr->table_cap; i++) {
145 0 0         if (SHM_IS_LIVE(sh->states[i]) && !SHM_IS_EXPIRED(sh, i, now))
    0          
    0          
    0          
146 0 0         mXPUSHi(nodes[i].value);
147             }
148             }
149            
150              
151             void
152             items(SV* self_sv)
153             PPCODE:
154 0 0         EXTRACT_MAP("Data::HashMap::Shared::I16", self_sv);
    0          
    0          
155 0 0         uint32_t ns = h->shard_handles ? h->num_shards : 1;
156 0 0         for (uint32_t si = 0; si < ns; si++) {
157 0 0         ShmHandle *sh = h->shard_handles ? h->shard_handles[si] : h;
158 0           ShmHeader *hdr = sh->hdr;
159 0           ShmNodeI16 *nodes = (ShmNodeI16 *)sh->nodes;
160 0 0         uint32_t now = sh->expires_at ? shm_now() : 0;
161 0           RDLOCK_GUARD(hdr);
162 0 0         EXTEND(SP, hdr->size * 2);
163 0 0         for (uint32_t i = 0; i < hdr->table_cap; i++) {
164 0 0         if (SHM_IS_LIVE(sh->states[i]) && !SHM_IS_EXPIRED(sh, i, now)) {
    0          
    0          
    0          
165 0 0         mXPUSHi(nodes[i].key);
166 0 0         mXPUSHi(nodes[i].value);
167             }
168             }
169             }
170            
171              
172             void
173             each(SV* self_sv)
174             PPCODE:
175 0 0         EXTRACT_MAP("Data::HashMap::Shared::I16", self_sv);
    0          
    0          
176             int16_t out_key, out_value;
177 0 0         if (shm_i16_each(h, &out_key, &out_value)) {
178 0 0         EXTEND(SP, 2);
179 0 0         mXPUSHi(out_key);
180 0 0         mXPUSHi(out_value);
181 0           XSRETURN(2);
182             }
183 0           shm_i16_flush_deferred(h);
184 0           XSRETURN_EMPTY;
185              
186             void
187             iter_reset(SV* self_sv)
188             CODE:
189 0 0         EXTRACT_MAP("Data::HashMap::Shared::I16", self_sv);
    0          
    0          
190 0           shm_i16_iter_reset(h);
191 0           shm_i16_flush_deferred(h);
192              
193             void
194             clear(SV* self_sv)
195             CODE:
196 1 50         EXTRACT_MAP("Data::HashMap::Shared::I16", self_sv);
    50          
    50          
197 1           shm_i16_clear(h);
198              
199             SV*
200             to_hash(SV* self_sv)
201             CODE:
202 1 50         EXTRACT_MAP("Data::HashMap::Shared::I16", self_sv);
    50          
    50          
203 1           HV* hv = newHV();
204 1 50         uint32_t ns = h->shard_handles ? h->num_shards : 1;
205 2 100         for (uint32_t si = 0; si < ns; si++) {
206 1 50         ShmHandle *sh = h->shard_handles ? h->shard_handles[si] : h;
207 1           ShmHeader *hdr = sh->hdr;
208 1           ShmNodeI16 *nodes = (ShmNodeI16 *)sh->nodes;
209 1 50         uint32_t now = sh->expires_at ? shm_now() : 0;
210 1           RDLOCK_GUARD(hdr);
211 17 100         for (uint32_t i = 0; i < hdr->table_cap; i++) {
212 16 100         if (SHM_IS_LIVE(sh->states[i]) && !SHM_IS_EXPIRED(sh, i, now)) {
    50          
    0          
    0          
213 5           SV* val = newSViv(nodes[i].value);
214             char kbuf[24];
215 5           int klen = my_snprintf(kbuf, sizeof(kbuf), "%" IVdf, (IV)nodes[i].key);
216 5 50         if (!hv_store(hv, kbuf, klen, val, 0)) SvREFCNT_dec(val);
217             }
218             }
219             }
220            
221 1           RETVAL = newRV_noinc((SV*)hv);
222             OUTPUT:
223             RETVAL
224              
225             SV*
226             get_or_set(SV* self_sv, int16_t key, int16_t default_value)
227             CODE:
228 2 50         EXTRACT_MAP("Data::HashMap::Shared::I16", self_sv);
    50          
    50          
229             int16_t out;
230 2           int rc = shm_i16_get_or_set(h, key, default_value, &out);
231 2 50         if (!rc) XSRETURN_UNDEF;
232 2           RETVAL = newSViv(out);
233             OUTPUT:
234             RETVAL
235              
236             bool
237             put_ttl(SV* self_sv, int16_t key, int16_t value, UV ttl_sec)
238             CODE:
239 0 0         EXTRACT_MAP("Data::HashMap::Shared::I16", self_sv);
    0          
    0          
240 0 0         REQUIRE_TTL(h);
    0          
241 0 0         RETVAL = shm_i16_put_ttl(h, key, value, (uint32_t)ttl_sec);
242             OUTPUT:
243             RETVAL
244              
245             UV
246             max_size(SV* self_sv)
247             CODE:
248 0 0         EXTRACT_MAP("Data::HashMap::Shared::I16", self_sv);
    0          
    0          
249 0 0         RETVAL = (UV)shm_i16_max_size(h);
250             OUTPUT:
251             RETVAL
252              
253             UV
254             ttl(SV* self_sv)
255             CODE:
256 0 0         EXTRACT_MAP("Data::HashMap::Shared::I16", self_sv);
    0          
    0          
257 0 0         RETVAL = (UV)shm_i16_ttl(h);
258             OUTPUT:
259             RETVAL
260              
261             SV*
262             take(SV* self_sv, int16_t key)
263             CODE:
264 0 0         EXTRACT_MAP("Data::HashMap::Shared::I16", self_sv);
    0          
    0          
265             int16_t out_value;
266 0 0         if (!shm_i16_take(h, key, &out_value)) XSRETURN_UNDEF;
267 0           RETVAL = newSViv(out_value);
268             OUTPUT:
269             RETVAL
270              
271             void
272             pop(SV* self_sv)
273             PPCODE:
274 0 0         EXTRACT_MAP("Data::HashMap::Shared::I16", self_sv);
    0          
    0          
275             int16_t out_key;
276             int16_t out_val;
277 0 0         if (!shm_i16_pop(h, &out_key, &out_val)) XSRETURN_EMPTY;
278 0 0         EXTEND(SP, 2);
279 0           mPUSHi(out_key);
280 0           mPUSHi(out_val);
281              
282             void
283             shift(SV* self_sv)
284             PPCODE:
285 0 0         EXTRACT_MAP("Data::HashMap::Shared::I16", self_sv);
    0          
    0          
286             int16_t out_key;
287             int16_t out_val;
288 0 0         if (!shm_i16_shift(h, &out_key, &out_val)) XSRETURN_EMPTY;
289 0 0         EXTEND(SP, 2);
290 0           mPUSHi(out_key);
291 0           mPUSHi(out_val);
292              
293             void
294             drain(SV* self_sv, UV limit)
295             PPCODE:
296 0 0         EXTRACT_MAP("Data::HashMap::Shared::I16", self_sv);
    0          
    0          
297 0 0         if (limit == 0) XSRETURN_EMPTY;
298             shm_i16_drain_entry *entries;
299 0 0         Newxz(entries, limit, shm_i16_drain_entry);
300            
301 0           SAVEFREEPV(entries);
302 0           char *buf = NULL; uint32_t buf_cap = 0;
303 0           uint32_t n = shm_i16_drain(h, (uint32_t)limit, entries, &buf, &buf_cap);
304            
305 0 0         EXTEND(SP, n * 2);
306 0 0         for (uint32_t i = 0; i < n; i++) {
307 0           mPUSHi(entries[i].key);
308 0           mPUSHi(entries[i].value);
309             }
310 0 0         if (buf) free(buf);
311            
312              
313             UV
314             flush_expired(SV* self_sv)
315             CODE:
316 0 0         EXTRACT_MAP("Data::HashMap::Shared::I16", self_sv);
    0          
    0          
317 0 0         RETVAL = (UV)shm_i16_flush_expired(h);
318             OUTPUT:
319             RETVAL
320              
321             void
322             flush_expired_partial(SV* self_sv, UV limit)
323             PPCODE:
324 0 0         EXTRACT_MAP("Data::HashMap::Shared::I16", self_sv);
    0          
    0          
325 0           int done = 0;
326 0           uint32_t flushed = shm_i16_flush_expired_partial(h, (uint32_t)limit, &done);
327 0 0         EXTEND(SP, 2);
328 0           mPUSHu(flushed);
329 0           mPUSHi(done);
330              
331             UV
332             mmap_size(SV* self_sv)
333             CODE:
334 0 0         EXTRACT_MAP("Data::HashMap::Shared::I16", self_sv);
    0          
    0          
335 0           RETVAL = (UV)shm_i16_mmap_size(h);
336             OUTPUT:
337             RETVAL
338              
339             bool
340             touch(SV* self_sv, int16_t key)
341             CODE:
342 0 0         EXTRACT_MAP("Data::HashMap::Shared::I16", self_sv);
    0          
    0          
343 0 0         RETVAL = shm_i16_touch(h, key);
344             OUTPUT:
345             RETVAL
346              
347             bool
348             reserve(SV* self_sv, UV target)
349             CODE:
350 0 0         EXTRACT_MAP("Data::HashMap::Shared::I16", self_sv);
    0          
    0          
351 0 0         RETVAL = shm_i16_reserve(h, (uint32_t)target);
352             OUTPUT:
353             RETVAL
354              
355             UV
356             stat_evictions(SV* self_sv)
357             CODE:
358 0 0         EXTRACT_MAP("Data::HashMap::Shared::I16", self_sv);
    0          
    0          
359 0           RETVAL = (UV)shm_i16_stat_evictions(h);
360             OUTPUT:
361             RETVAL
362              
363             UV
364             stat_expired(SV* self_sv)
365             CODE:
366 0 0         EXTRACT_MAP("Data::HashMap::Shared::I16", self_sv);
    0          
    0          
367 0           RETVAL = (UV)shm_i16_stat_expired(h);
368             OUTPUT:
369             RETVAL
370              
371             UV
372             stat_recoveries(SV* self_sv)
373             CODE:
374 0 0         EXTRACT_MAP("Data::HashMap::Shared::I16", self_sv);
    0          
    0          
375 0 0         RETVAL = (UV)shm_i16_stat_recoveries(h);
376             OUTPUT:
377             RETVAL
378              
379             UV
380             arena_used(SV* self_sv)
381             CODE:
382 0 0         EXTRACT_MAP("Data::HashMap::Shared::I16", self_sv);
    0          
    0          
383 0           RETVAL = (UV)shm_i16_arena_used(h);
384             OUTPUT:
385             RETVAL
386              
387             UV
388             arena_cap(SV* self_sv)
389             CODE:
390 0 0         EXTRACT_MAP("Data::HashMap::Shared::I16", self_sv);
    0          
    0          
391 0           RETVAL = (UV)shm_i16_arena_cap(h);
392             OUTPUT:
393             RETVAL
394              
395             bool
396             add(SV* self_sv, int16_t key, int16_t value)
397             CODE:
398 2 50         EXTRACT_MAP("Data::HashMap::Shared::I16", self_sv);
    50          
    50          
399 2 100         RETVAL = shm_i16_add(h, key, value);
400             OUTPUT:
401             RETVAL
402              
403             bool
404             update(SV* self_sv, int16_t key, int16_t value)
405             CODE:
406 2 50         EXTRACT_MAP("Data::HashMap::Shared::I16", self_sv);
    50          
    50          
407 2 100         RETVAL = shm_i16_update(h, key, value);
408             OUTPUT:
409             RETVAL
410              
411             SV*
412             swap(SV* self_sv, int16_t key, int16_t value)
413             CODE:
414 2 50         EXTRACT_MAP("Data::HashMap::Shared::I16", self_sv);
    50          
    50          
415             int16_t out_value;
416 2           int rc = shm_i16_swap(h, key, value, &out_value);
417 2 100         if (rc != 1) XSRETURN_UNDEF;
418 1           RETVAL = newSViv(out_value);
419             OUTPUT:
420             RETVAL
421              
422             bool
423             cas(SV* self_sv, int16_t key, int16_t expected, int16_t desired)
424             CODE:
425 2 50         EXTRACT_MAP("Data::HashMap::Shared::I16", self_sv);
    50          
    50          
426 2 100         RETVAL = shm_i16_cas(h, key, expected, desired);
427             OUTPUT:
428             RETVAL
429              
430             bool
431             persist(SV* self_sv, int16_t key)
432             CODE:
433 1 50         EXTRACT_MAP("Data::HashMap::Shared::I16", self_sv);
    50          
    50          
434 1 50         RETVAL = shm_i16_persist(h, key);
435             OUTPUT:
436             RETVAL
437              
438             bool
439             set_ttl(SV* self_sv, int16_t key, UV ttl_sec)
440             CODE:
441 1 50         EXTRACT_MAP("Data::HashMap::Shared::I16", self_sv);
    50          
    50          
442 1 50         RETVAL = shm_i16_set_ttl(h, key, (uint32_t)ttl_sec);
443             OUTPUT:
444             RETVAL
445              
446             void
447             get_multi(SV* self_sv, ...)
448             PPCODE:
449 0 0         EXTRACT_MAP("Data::HashMap::Shared::I16", self_sv);
    0          
    0          
450 0           int nkeys = items - 1;
451 0 0         if (nkeys == 0) XSRETURN_EMPTY;
452 0 0         EXTEND(SP, nkeys);
    0          
453 0 0         if (h->shard_handles) {
454 0 0         for (int i = 0; i < nkeys; i++) {
455 0           int16_t key = (int16_t)SvIV(ST(i + 1));
456             int16_t val;
457 0 0         if (shm_i16_get(h, key, &val))
458 0           mPUSHi(val);
459             else
460 0           PUSHs(&PL_sv_undef);
461             }
462             } else {
463 0           ShmHeader *hdr = h->hdr;
464 0           ShmNodeI16 *nodes = (ShmNodeI16 *)h->nodes;
465 0           uint8_t *states = h->states;
466 0 0         uint32_t now = h->expires_at ? shm_now() : 0;
467             /* Phase 1: compute hashes and prefetch first probe positions */
468 0           uint32_t *hashes = NULL;
469 0           Newx(hashes, nkeys, uint32_t);
470 0           SAVEFREEPV(hashes);
471 0           RDLOCK_GUARD(hdr);
472 0           uint32_t mask = hdr->table_cap - 1;
473 0 0         for (int i = 0; i < nkeys; i++) {
474 0           hashes[i] = shm_hash_int64((int64_t)(int16_t)SvIV(ST(i + 1)));
475 0           __builtin_prefetch(&states[hashes[i] & mask], 0, 0);
476 0           __builtin_prefetch(&nodes[hashes[i] & mask], 0, 0);
477             }
478             /* Phase 2: probe each key */
479 0 0         for (int i = 0; i < nkeys; i++) {
480 0           int16_t key = (int16_t)SvIV(ST(i + 1));
481 0           uint32_t hash = hashes[i];
482 0           uint32_t pos = hash & mask;
483 0           uint8_t tag = SHM_MAKE_TAG(hash);
484 0           int found = 0;
485 0           int16_t val = 0;
486 0 0         for (uint32_t j = 0; j <= mask; j++) {
487 0           uint32_t idx = (pos + j) & mask;
488 0           uint8_t st = states[idx];
489 0 0         if (st == SHM_EMPTY) break;
490 0 0         if (st != tag) continue;
491 0 0         if (nodes[idx].key == key) {
492 0 0         if (h->expires_at && h->expires_at[idx] && now >= h->expires_at[idx]) break;
    0          
    0          
493 0           val = nodes[idx].value;
494 0           found = 1;
495 0           break;
496             }
497             }
498 0 0         if (found) mPUSHi(val);
499 0           else PUSHs(&PL_sv_undef);
500             /* Prefetch next key's probe position */
501 0 0         if (i + 1 < nkeys) {
502 0           uint32_t npos = hashes[i + 1] & mask;
503 0           __builtin_prefetch(&states[npos], 0, 0);
504 0           __builtin_prefetch(&nodes[npos], 0, 0);
505             }
506             }
507             }
508              
509             SV*
510             stats(SV* self_sv)
511             CODE:
512 0 0         EXTRACT_MAP("Data::HashMap::Shared::I16", self_sv);
    0          
    0          
513 0           HV *hv = newHV();
514 0           hv_store(hv, "size", 4, newSVuv(shm_i16_size(h)), 0);
515 0           hv_store(hv, "capacity", 8, newSVuv(shm_i16_capacity(h)), 0);
516 0           hv_store(hv, "max_entries", 11, newSVuv(shm_i16_max_entries(h)), 0);
517 0           hv_store(hv, "tombstones", 10, newSVuv(shm_i16_tombstones(h)), 0);
518 0           hv_store(hv, "mmap_size", 9, newSVuv(shm_i16_mmap_size(h)), 0);
519 0           hv_store(hv, "arena_used", 10, newSVuv(shm_i16_arena_used(h)), 0);
520 0           hv_store(hv, "arena_cap", 9, newSVuv(shm_i16_arena_cap(h)), 0);
521 0           hv_store(hv, "evictions", 9, newSVuv(shm_i16_stat_evictions(h)), 0);
522 0           hv_store(hv, "expired", 7, newSVuv(shm_i16_stat_expired(h)), 0);
523 0           hv_store(hv, "recoveries", 10, newSVuv(shm_i16_stat_recoveries(h)), 0);
524 0           hv_store(hv, "max_size", 8, newSVuv(shm_i16_max_size(h)), 0);
525 0           hv_store(hv, "ttl", 3, newSVuv(shm_i16_ttl(h)), 0);
526 0           RETVAL = newRV_noinc((SV*)hv);
527             OUTPUT:
528             RETVAL
529              
530             UV
531             set_multi(SV* self_sv, ...)
532             CODE:
533 0 0         EXTRACT_MAP("Data::HashMap::Shared::I16", self_sv);
    0          
    0          
534 0 0         if ((items - 1) % 2 != 0) croak("set_multi requires even number of arguments (key, value pairs)");
535 0           uint32_t count = 0;
536 0 0         if (h->shard_handles) {
537 0 0         for (int i = 1; i < items; i += 2)
538 0           count += shm_i16_put(h, (int16_t)SvIV(ST(i)), (int16_t)SvIV(ST(i + 1)));
539             } else {
540 0           ShmHeader *hdr = h->hdr;
541 0           shm_rwlock_wrlock(hdr);
542 0           shm_seqlock_write_begin(&hdr->seq);
543 0 0         for (int i = 1; i < items; i += 2)
544 0           count += shm_i16_put_inner(h, (int16_t)SvIV(ST(i)), (int16_t)SvIV(ST(i + 1)), SHM_TTL_USE_DEFAULT);
545 0           shm_seqlock_write_end(&hdr->seq);
546 0           shm_rwlock_wrunlock(hdr);
547             }
548 0 0         RETVAL = count;
549             OUTPUT:
550             RETVAL
551              
552             SV*
553             path(SV* self_sv)
554             CODE:
555 0 0         EXTRACT_MAP("Data::HashMap::Shared::I16", self_sv);
    0          
    0          
556 0           RETVAL = newSVpv(h->path, 0);
557             OUTPUT:
558             RETVAL
559              
560             bool
561             unlink(SV* self_or_class, ...)
562             CODE:
563             const char *p;
564 0 0         if (SvROK(self_or_class) && SvOBJECT(SvRV(self_or_class))) {
    0          
565 0           ShmHandle* h = INT2PTR(ShmHandle*, SvIV(SvRV(self_or_class)));
566 0 0         if (!h) croak("Attempted to use a destroyed Data::HashMap::Shared::I16 object");
567 0           p = h->path;
568             } else {
569 0 0         if (items < 2) croak("Usage: Data::HashMap::Shared::I16->unlink($path)");
570 0           p = SvPV_nolen(ST(1));
571             }
572 0 0         RETVAL = (SvROK(self_or_class) && SvOBJECT(SvRV(self_or_class))) ?
    0          
573 0 0         shm_unlink_sharded(INT2PTR(ShmHandle*, SvIV(SvRV(self_or_class)))) :
574 0           shm_unlink_path(p);
575             OUTPUT:
576             RETVAL
577              
578             SV*
579             ttl_remaining(SV* self_sv, int16_t key)
580             CODE:
581 3 50         EXTRACT_MAP("Data::HashMap::Shared::I16", self_sv);
    50          
    50          
582 3           int64_t remaining = shm_i16_ttl_remaining(h, key);
583 3 50         if (remaining < 0) XSRETURN_UNDEF;
584 3           RETVAL = newSViv(remaining);
585             OUTPUT:
586             RETVAL
587              
588             UV
589             capacity(SV* self_sv)
590             CODE:
591 0 0         EXTRACT_MAP("Data::HashMap::Shared::I16", self_sv);
    0          
    0          
592 0 0         RETVAL = (UV)shm_i16_capacity(h);
593             OUTPUT:
594             RETVAL
595              
596             UV
597             tombstones(SV* self_sv)
598             CODE:
599 0 0         EXTRACT_MAP("Data::HashMap::Shared::I16", self_sv);
    0          
    0          
600 0 0         RETVAL = (UV)shm_i16_tombstones(h);
601             OUTPUT:
602             RETVAL
603              
604             SV*
605             cursor(SV* self_sv)
606             CODE:
607 0 0         EXTRACT_MAP("Data::HashMap::Shared::I16", self_sv);
    0          
    0          
608 0           ShmCursor* c = shm_cursor_create(h);
609 0 0         if (!c) croak("Failed to allocate cursor");
610 0           RETVAL = sv_setref_pv(newSV(0), "Data::HashMap::Shared::I16::Cursor", (void*)c);
611             OUTPUT:
612             RETVAL
613              
614             MODULE = Data::HashMap::Shared PACKAGE = Data::HashMap::Shared::I16::Cursor
615             PROTOTYPES: DISABLE
616              
617             void
618             DESTROY(SV* self_sv)
619             CODE:
620 0 0         if (!SvROK(self_sv)) return;
621 0           ShmCursor* c = INT2PTR(ShmCursor*, SvIV(SvRV(self_sv)));
622 0 0         if (!c) return;
623 0           ShmHandle* h = c->current;
624 0           shm_cursor_destroy(c);
625 0 0         if (h) shm_i16_flush_deferred(h);
626 0           sv_setiv(SvRV(self_sv), 0);
627              
628             void
629             next(SV* self_sv)
630             PPCODE:
631 0 0         EXTRACT_CURSOR("Data::HashMap::Shared::I16::Cursor", self_sv);
    0          
    0          
632             int16_t out_key, out_value;
633 0 0         if (shm_i16_cursor_next(c, &out_key, &out_value)) {
634 0 0         EXTEND(SP, 2);
635 0 0         mXPUSHi(out_key);
636 0 0         mXPUSHi(out_value);
637 0           XSRETURN(2);
638             }
639 0           XSRETURN_EMPTY;
640              
641             void
642             reset(SV* self_sv)
643             CODE:
644 0 0         EXTRACT_CURSOR("Data::HashMap::Shared::I16::Cursor", self_sv);
    0          
    0          
645 0           shm_i16_cursor_reset(c);
646              
647             bool
648             seek(SV* self_sv, int16_t key)
649             CODE:
650 0 0         EXTRACT_CURSOR("Data::HashMap::Shared::I16::Cursor", self_sv);
    0          
    0          
651 0 0         RETVAL = shm_i16_cursor_seek(c, key);
652             OUTPUT:
653             RETVAL
654