Data-SortedSet-Shared

 view release on metacpan or  search on metacpan

sortedset.h  view on Meta::CPAN

}

/* delete (score,member) from subtree nidx (known present); decrement counts;
   return 1 if nidx now underflows (num < SS_MIN) */
static int ss_delete_rec(SsHandle *h, uint32_t nidx, double score, int64_t member) {
    SsNode *nd = &h->nodes[nidx];
    if (nd->is_leaf) {
        int pos = 0;
        while (pos < nd->num && ss_key_cmp(nd->scores[pos], nd->members[pos], score, member) != 0) pos++;
        for (int i = pos; i+1 < nd->num; i++) { nd->scores[i] = nd->scores[i+1]; nd->members[i] = nd->members[i+1]; }
        nd->num--;
        return nd->num < SS_MIN;
    }
    int c = ss_child_index(nd, score, member);
    int under = ss_delete_rec(h, nd->children[c], score, member);
    nd->counts[c]--;
    if (under) ss_fix_underflow(h, nidx, c);
    return nd->num < SS_MIN;
}

static void ss_tree_del(SsHandle *h, double score, int64_t member) {
    SsHeader *hdr = h->hdr;
    ss_delete_rec(h, hdr->root, score, member);
    SsNode *root = &h->nodes[hdr->root];
    if (root->is_leaf) {
        if (root->num == 0) {
            ss_node_free(h, hdr->root);
            hdr->root = SS_NONE; hdr->leftmost = SS_NONE; hdr->rightmost = SS_NONE; hdr->height = 0;
        }
    } else if (root->num == 1) {
        uint32_t child = root->children[0];
        ss_node_free(h, hdr->root);
        hdr->root = child; h->nodes[child].parent = SS_NONE; hdr->height--;
    }
    hdr->count--;
}

/* add: 1 (new), 0 (existing -- score updated if changed), -1 (full) */
static int ss_add_locked(SsHandle *h, int64_t member, double score) {
    double old;
    if (ss_idx_get(h, member, &old)) {
        if (old != score) { ss_tree_del(h, old, member); ss_tree_add(h, score, member); ss_idx_set(h, member, score); }
        return 0;
    }
    if (h->hdr->count >= h->hdr->max_entries) return -1;
    ss_tree_add(h, score, member);
    ss_idx_set(h, member, score);
    return 1;
}

/* remove: 1 if removed, 0 if absent */
static int ss_remove_locked(SsHandle *h, int64_t member) {
    double old;
    if (!ss_idx_get(h, member, &old)) return 0;
    ss_tree_del(h, old, member);
    ss_idx_del(h, member);
    return 1;
}

/* incr by delta. *out = new score. returns 1 (created), 0 (updated), -1 (full),
   -2 (result is NaN) */
static int ss_incr_locked(SsHandle *h, int64_t member, double delta, double *out) {
    double old;
    if (ss_idx_get(h, member, &old)) {
        double ns = old + delta; *out = ns;
        if (ns != ns) return -2;
        if (ns != old) { ss_tree_del(h, old, member); ss_tree_add(h, ns, member); ss_idx_set(h, member, ns); }
        return 0;
    }
    if (h->hdr->count >= h->hdr->max_entries) return -1;
    *out = delta;
    if (delta != delta) return -2;
    ss_tree_add(h, delta, member); ss_idx_set(h, member, delta);
    return 1;
}

/* node indices stored in the mmap (children[], leftmost,
 * rightmost, leaf next/prev, free-list links) are attacker-controlled -- a
 * local peer can write the backing file. Bound every such index against the
 * node pool before using it to dereference h->nodes[]. A predictable
 * never-taken branch for valid data; on a bad index the caller stops/skips
 * instead of trapping. */
static inline int ss_node_ok(const SsHandle *h, uint32_t idx) {
    return idx < h->hdr->node_capacity;
}

/* pop the min (max=0) or max (max=1): 0 if empty, else 1 with *m,*s */
static int ss_pop_locked(SsHandle *h, int max, int64_t *m, double *s) {
    if (h->hdr->root == SS_NONE) return 0;
    uint32_t li = max ? h->hdr->rightmost : h->hdr->leftmost;
    if (!ss_node_ok(h, li)) return 0;                 /* corrupt leftmost/rightmost */
    SsNode *nd = &h->nodes[li];
    int pos = max ? nd->num - 1 : 0;
    *m = nd->members[pos]; *s = nd->scores[pos];
    ss_tree_del(h, *s, *m);
    ss_idx_del(h, *m);
    return 1;
}

/* ---- structural validator (debug / tests) ---- */
static long ss_check_rec(SsHandle *h, uint32_t nidx, int depth, int is_root,
                         double *ps, int64_t *pm, int *hp, int *leaf_depth) {
    if (!ss_node_ok(h, nidx)) return -1;              /* corrupt child index */
    SsNode *nd = &h->nodes[nidx];
    if (nd->num < 1 || nd->num > SS_ORDER) return -1;
    if (!is_root && nd->num < SS_MIN) return -1;
    if (nd->is_leaf) {
        if (*leaf_depth < 0) *leaf_depth = depth;
        else if (*leaf_depth != depth) return -1;
        for (int i = 0; i < nd->num; i++) {
            if (*hp && ss_key_cmp(*ps, *pm, nd->scores[i], nd->members[i]) >= 0) return -1;
            *ps = nd->scores[i]; *pm = nd->members[i]; *hp = 1;
        }
        return nd->num;
    }
    long total = 0;
    for (int i = 0; i < nd->num; i++) {
        long c = ss_check_rec(h, nd->children[i], depth + 1, 0, ps, pm, hp, leaf_depth);
        if (c < 0 || (uint32_t)c != nd->counts[i]) return -1;
        total += c;
    }



( run in 0.760 second using v1.01-cache-2.11-cpan-9581c071862 )