Data-SortedSet-Shared
view release on metacpan or search on metacpan
char errbuf[SS_ERR_BUFLEN];
CODE:
if (max_entries > UINT32_MAX) croak("Data::SortedSet::Shared->new_memfd: max_entries exceeds 2^32");
SsHandle *h = ss_create_memfd(name, (uint32_t)max_entries, errbuf);
if (!h) croak("Data::SortedSet::Shared->new_memfd: %s", errbuf);
MAKE_OBJ(class, h);
OUTPUT:
RETVAL
SV *
new_from_fd(class, fd)
const char *class
int fd
PREINIT:
char errbuf[SS_ERR_BUFLEN];
CODE:
SsHandle *h = ss_open_fd(fd, errbuf);
if (!h) croak("Data::SortedSet::Shared->new_from_fd: %s", errbuf);
MAKE_OBJ(class, h);
OUTPUT:
RETVAL
void
DESTROY(self)
SV *self
CODE:
if (sv_isobject(self) && sv_derived_from(self, "Data::SortedSet::Shared")) {
SsHandle *h = INT2PTR(SsHandle*, SvIV(SvRV(self)));
if (h) { sv_setiv(SvRV(self), 0); ss_destroy(h); } /* null first: activates EXTRACT's use-after-destroy croak + makes a double DESTROY a no-op */
}
UV
count(self)
SV *self
PREINIT:
EXTRACT(self);
CODE:
ss_rwlock_rdlock(h);
RETVAL = h->hdr->count;
ss_rwlock_rdunlock(h);
OUTPUT:
RETVAL
UV
max_entries(self)
SV *self
PREINIT:
EXTRACT(self);
CODE:
RETVAL = h->hdr->max_entries;
OUTPUT:
RETVAL
void
clear(self)
SV *self
PREINIT:
EXTRACT(self);
CODE:
ss_rwlock_wrlock(h);
ss_clear_locked(h);
ss_rwlock_wrunlock(h);
SV *
add(self, member, score)
SV *self
IV member
NV score
PREINIT:
EXTRACT(self);
int rc;
CODE:
if (score != score) croak("add: score must not be NaN");
ss_rwlock_wrlock(h);
rc = ss_add_locked(h, (int64_t)member, (double)score);
__atomic_fetch_add(&h->hdr->stat_ops, 1, __ATOMIC_RELAXED);
ss_rwlock_wrunlock(h);
RETVAL = (rc < 0) ? &PL_sv_undef : newSViv(rc);
OUTPUT:
RETVAL
SV *
score(self, member)
SV *self
IV member
PREINIT:
EXTRACT(self);
double sc;
CODE:
ss_rwlock_rdlock(h);
int found = ss_idx_get(h, (int64_t)member, &sc);
ss_rwlock_rdunlock(h);
RETVAL = found ? newSVnv(sc) : &PL_sv_undef;
OUTPUT:
RETVAL
bool
exists(self, member)
SV *self
IV member
PREINIT:
EXTRACT(self);
double sc;
CODE:
ss_rwlock_rdlock(h);
RETVAL = ss_idx_get(h, (int64_t)member, &sc);
ss_rwlock_rdunlock(h);
OUTPUT:
RETVAL
bool
remove(self, member)
SV *self
IV member
PREINIT:
EXTRACT(self);
CODE:
ss_rwlock_wrlock(h);
RETVAL = ss_remove_locked(h, (int64_t)member);
__atomic_fetch_add(&h->hdr->stat_ops, 1, __ATOMIC_RELAXED);
ss_rwlock_wrunlock(h);
OUTPUT:
RETVAL
NV
incr(self, member, delta)
SV *self
IV member
NV delta
PREINIT:
EXTRACT(self);
double out;
int rc;
CODE:
if (delta != delta) croak("incr: delta must not be NaN");
ss_rwlock_wrlock(h);
rc = ss_incr_locked(h, (int64_t)member, (double)delta, &out);
__atomic_fetch_add(&h->hdr->stat_ops, 1, __ATOMIC_RELAXED);
ss_rwlock_wrunlock(h);
if (rc == -1) croak("incr: max_entries exhausted");
if (rc == -2) croak("incr: result is NaN");
RETVAL = out;
OUTPUT:
RETVAL
void
pop_min(self)
SV *self
PREINIT:
EXTRACT(self);
PPCODE:
{
int64_t m; double s; int ok;
ss_rwlock_wrlock(h);
ok = ss_pop_locked(h, 0, &m, &s);
if (ok) __atomic_fetch_add(&h->hdr->stat_ops, 1, __ATOMIC_RELAXED);
ss_rwlock_wrunlock(h);
if (ok) { EXTEND(SP, 2); PUSHs(sv_2mortal(newSViv((IV)m))); PUSHs(sv_2mortal(newSVnv(s))); }
}
void
pop_max(self)
SV *self
PREINIT:
EXTRACT(self);
PPCODE:
{
int64_t m; double s; int ok;
ss_rwlock_wrlock(h);
ok = ss_pop_locked(h, 1, &m, &s);
if (ok) __atomic_fetch_add(&h->hdr->stat_ops, 1, __ATOMIC_RELAXED);
ss_rwlock_wrunlock(h);
if (ok) { EXTEND(SP, 2); PUSHs(sv_2mortal(newSViv((IV)m))); PUSHs(sv_2mortal(newSVnv(s))); }
}
bool
_validate(self)
SV *self
PREINIT:
EXTRACT(self);
CODE:
ss_rwlock_rdlock(h);
RETVAL = ss_validate_tree(h);
ss_rwlock_rdunlock(h);
OUTPUT:
RETVAL
SV *
rank(self, member)
SV *self
IV member
PREINIT:
EXTRACT(self);
double sc;
CODE:
ss_rwlock_rdlock(h);
RETVAL = ss_idx_get(h, (int64_t)member, &sc)
? newSVuv(ss_rank_of(h, sc, (int64_t)member)) : &PL_sv_undef;
ss_rwlock_rdunlock(h);
OUTPUT:
RETVAL
SV *
rev_rank(self, member)
SV *self
IV member
PREINIT:
EXTRACT(self);
double sc;
CODE:
ss_rwlock_rdlock(h);
RETVAL = ss_idx_get(h, (int64_t)member, &sc)
? newSVuv(h->hdr->count - 1 - ss_rank_of(h, sc, (int64_t)member)) : &PL_sv_undef;
ss_rwlock_rdunlock(h);
OUTPUT:
RETVAL
SV *
at_rank(self, rank)
SV *self
IV rank
PREINIT:
EXTRACT(self);
CODE:
ss_rwlock_rdlock(h);
{
uint32_t cnt = h->hdr->count;
IV r = rank; if (r < 0) r += (IV)cnt;
if (r >= 0 && (uint64_t)r < cnt) { /* compare in 64-bit; large r must not truncate to an in-range index */
int pos; uint32_t leaf = ss_at_rank(h, (uint32_t)r, &pos);
if (RETVAL < 0) croak("eventfd: %s", strerror(errno));
OUTPUT:
RETVAL
int
fileno(self)
SV *self
PREINIT:
EXTRACT(self);
CODE:
RETVAL = h->notify_fd;
OUTPUT:
RETVAL
bool
notify(self)
SV *self
PREINIT:
EXTRACT(self);
CODE:
RETVAL = ss_notify(h);
OUTPUT:
RETVAL
SV *
eventfd_consume(self)
SV *self
PREINIT:
EXTRACT(self);
CODE:
{
int64_t v = ss_eventfd_consume(h);
RETVAL = (v < 0) ? &PL_sv_undef : newSVuv((UV)v);
}
OUTPUT:
RETVAL
IV
add_many(self, rows)
SV *self
SV *rows
PREINIT:
EXTRACT(self);
int added = 0;
CODE:
if (!SvROK(rows) || SvTYPE(SvRV(rows)) != SVt_PVAV)
croak("add_many: expected an arrayref of [member, score] rows");
{
AV *av = (AV *)SvRV(rows);
SSize_t nr = av_len(av) + 1;
ss_rwlock_wrlock(h);
for (SSize_t i = 0; i < nr; i++) {
SV **rv = av_fetch(av, i, 0);
if (!rv || !SvROK(*rv) || SvTYPE(SvRV(*rv)) != SVt_PVAV) continue; /* skip malformed */
AV *row = (AV *)SvRV(*rv);
if (av_len(row) + 1 < 2) continue;
SV **ms = av_fetch(row, 0, 0), **sv = av_fetch(row, 1, 0);
if (!ms || !sv) continue;
double score = SvNV(*sv);
if (score != score) continue; /* skip NaN */
int rc = ss_add_locked(h, (int64_t)SvIV(*ms), score);
if (rc == 1) added++;
else if (rc == -1) break; /* pool full */
}
__atomic_fetch_add(&h->hdr->stat_ops, 1, __ATOMIC_RELAXED);
ss_rwlock_wrunlock(h);
}
RETVAL = added;
OUTPUT:
RETVAL
SV *
stats(self)
SV *self
PREINIT:
EXTRACT(self);
CODE:
{
HV *hv = newHV();
ss_rwlock_rdlock(h);
SsHeader *hd = h->hdr;
uint32_t nfree = 0, f = hd->node_free_head;
while (f != SS_NONE) { nfree++; f = h->nodes[f].parent; }
uint32_t iload = hd->count; /* backward-shift delete leaves no tombstones: occupied slots == count */
hv_stores(hv, "count", newSVuv(hd->count));
hv_stores(hv, "max_entries", newSVuv(hd->max_entries));
hv_stores(hv, "height", newSVuv(hd->height));
hv_stores(hv, "node_capacity", newSVuv(hd->node_capacity));
hv_stores(hv, "nodes_used", newSVuv(hd->node_capacity - nfree));
hv_stores(hv, "index_slots", newSVuv(hd->index_slots));
hv_stores(hv, "index_load", newSVnv((double)iload / (double)hd->index_slots));
hv_stores(hv, "ops", newSVuv(hd->stat_ops));
hv_stores(hv, "mmap_size", newSVuv((UV)h->mmap_size));
ss_rwlock_rdunlock(h);
RETVAL = newRV_noinc((SV *)hv);
}
OUTPUT:
RETVAL
( run in 0.750 second using v1.01-cache-2.11-cpan-bbe5e583499 )