Ancient

 view release on metacpan or  search on metacpan

xs/doubly/doubly.c  view on Meta::CPAN

#ifdef USE_ITHREADS
    owner_tid_sv = hv_fetch(hash, "_owner_tid", 10, 0);
    owner_tid = owner_tid_sv ? SvUV(*owner_tid_sv) : PTR2UV(PERL_GET_THX);
#endif

    list_incref(list_idx);

#ifdef USE_ITHREADS
    ST(0) = sv_2mortal(create_doubly_object(aTHX_ list_idx, new_node_id, owner_tid));
#else
    ST(0) = sv_2mortal(create_doubly_object(aTHX_ list_idx, new_node_id));
#endif
    XSRETURN(1);
}

static XS(xs_find) {
    dXSARGS;
    HV* hash;
    SV** id_sv;
    IV list_idx;
    SV* cb;
    DoublyListMeta* list;
    DoublyNodeSlot* node;
    IV node_idx;
    SV* node_data;
    int found;
    IV found_node_id;
    IV current_node_id;
#ifdef USE_ITHREADS
    SV** owner_tid_sv;
    UV owner_tid;
#endif

    if (items < 2) croak("Usage: doubly::find(self, callback)");

    hash = (HV*)SvRV(ST(0));
    id_sv = hv_fetch(hash, "_id", 3, 0);
    list_idx = id_sv ? SvIV(*id_sv) : -1;
    cb = ST(1);

    found = 0;
    found_node_id = 0;

    DOUBLY_LOCK();
    list = get_list(list_idx);
    if (list && !list->destroyed && list->length > 0) {
        node_idx = list->head_idx;
        while (node_idx >= 0 && !found) {
            node = get_node(node_idx);
            if (!node) break;

            current_node_id = node->node_id;
            node_data = node->data ? newSVsv(node->data) : &PL_sv_undef;

            DOUBLY_UNLOCK();

            {
                dSP;
                PUSHMARK(SP);
                XPUSHs(sv_2mortal(node_data));
                PUTBACK;
                call_sv(cb, G_SCALAR);
                SPAGAIN;
                if (SvTRUE(*PL_stack_sp)) {
                    found = 1;
                    found_node_id = current_node_id;
                }
                POPs;
            }

            DOUBLY_LOCK();
            list = get_list(list_idx);
            if (!list || list->destroyed) break;

            if (!found) {
                /* Re-find node by ID since list may have changed during callback */
                node_idx = find_node_by_id(list, current_node_id);
                if (node_idx >= 0) {
                    node = get_node(node_idx);
                    if (node) {
                        node_idx = node->next_idx;
                    } else {
                        break;
                    }
                } else {
                    /* Node was removed during callback, try to continue from head */
                    break;
                }
            }
        }
    }
    DOUBLY_UNLOCK();

    if (found) {
#ifdef USE_ITHREADS
        owner_tid_sv = hv_fetch(hash, "_owner_tid", 10, 0);
        owner_tid = owner_tid_sv ? SvUV(*owner_tid_sv) : PTR2UV(PERL_GET_THX);
#endif
        list_incref(list_idx);
#ifdef USE_ITHREADS
        ST(0) = sv_2mortal(create_doubly_object(aTHX_ list_idx, found_node_id, owner_tid));
#else
        ST(0) = sv_2mortal(create_doubly_object(aTHX_ list_idx, found_node_id));
#endif
    } else {
        ST(0) = &PL_sv_undef;
    }
    XSRETURN(1);
}

static XS(xs_insert) {
    dXSARGS;
    HV* hash;
    SV** id_sv;
    IV list_idx;
    SV* cb;
    SV* data;
    DoublyListMeta* list;
    DoublyNodeSlot* node;
    IV node_idx;
    IV current_node_id;
    SV* node_data;
    int found;
    IV pos;

    if (items < 3 || !SvROK(ST(0)) || SvTYPE(SvRV(ST(0))) != SVt_PVHV)
        croak("Usage: doubly::insert(self, callback, data)");

    hash = (HV*)SvRV(ST(0));
    id_sv = hv_fetch(hash, "_id", 3, 0);
    list_idx = id_sv ? SvIV(*id_sv) : -1;
    cb = ST(1);
    data = ST(2);

    found = 0;
    pos = 0;

    DOUBLY_LOCK();
    list = get_list(list_idx);
    if (list && !list->destroyed && list->length > 0) {
        node_idx = list->head_idx;
        while (node_idx >= 0 && !found) {
            node = get_node(node_idx);
            if (!node) break;

            current_node_id = node->node_id;
            node_data = node->data ? newSVsv(node->data) : &PL_sv_undef;

            DOUBLY_UNLOCK();

            {
                dSP;
                PUSHMARK(SP);
                XPUSHs(sv_2mortal(node_data));
                PUTBACK;
                call_sv(cb, G_SCALAR);
                SPAGAIN;
                if (SvTRUE(*PL_stack_sp)) {
                    found = 1;
                }
                POPs;
            }

            DOUBLY_LOCK();
            list = get_list(list_idx);
            if (!list || list->destroyed) break;

            if (!found) {
                /* Re-find node by ID since list may have changed during callback */
                node_idx = find_node_by_id(list, current_node_id);
                if (node_idx >= 0) {
                    node = get_node(node_idx);
                    if (node) {
                        node_idx = node->next_idx;
                        pos++;
                    } else {
                        break;
                    }
                } else {
                    /* Node was removed during callback */
                    break;
                }
            }
        }
    }
    DOUBLY_UNLOCK();

    if (found) {
        list_insert_at_pos(aTHX_ list_idx, pos, data);
    } else {
        list_add(aTHX_ list_idx, data);
    }

    /* Return $self for chaining - no refcount increment needed */
    XSRETURN(1);
}

static XS(xs_destroy) {
    dXSARGS;
    HV* hash;
    SV** id_sv;
    IV list_idx;

    if (items < 1) croak("Usage: doubly::destroy(self)");

    hash = (HV*)SvRV(ST(0));
    id_sv = hv_fetch(hash, "_id", 3, 0);
    list_idx = id_sv ? SvIV(*id_sv) : -1;

    list_destroy(aTHX_ list_idx);
    XSRETURN_EMPTY;
}

static XS(xs_DESTROY) {
    dXSARGS;



( run in 0.453 second using v1.01-cache-2.11-cpan-13bb782fe5a )