Ancient

 view release on metacpan or  search on metacpan

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

    int klen = snprintf(key, sizeof(key), "%ld", (long)idx);
    SV **name_sv = hv_fetch(g_slot_names, key, klen, 0);

    if (!name_sv || !SvOK(*name_sv)) return;

    STRLEN name_len;
    const char *name = SvPV(*name_sv, name_len);
    SV **svp = hv_fetch(g_watchers, name, name_len, 0);

    if (svp && SvROK(*svp) && SvTYPE(SvRV(*svp)) == SVt_PVAV) {
        AV *callbacks = (AV*)SvRV(*svp);
        SSize_t i, len = av_len(callbacks);
        for (i = 0; i <= len; i++) {
            SV **cb = av_fetch(callbacks, i, 0);
            if (cb && SvROK(*cb)) {
                dSP;
                ENTER; SAVETMPS;
                PUSHMARK(SP);
                mXPUSHs(newSVpvn(name, name_len));
                XPUSHs(new_val);
                PUTBACK;
                call_sv(*cb, G_DISCARD);
                FREETMPS; LEAVE;
            }
        }
    }
}

/* ============================================
   Slot management
   ============================================ */

static void ensure_slot_capacity(IV needed) {
    if (needed >= g_slots_size) {
        IV new_size = g_slots_size ? g_slots_size * 2 : 16;
        IV i;
        while (new_size <= needed) new_size *= 2;
        Renew(g_slots, new_size, SV*);
        Renew(g_has_watchers, new_size, char);
        for (i = g_slots_size; i < new_size; i++) {
            g_slots[i] = &PL_sv_undef;
            g_has_watchers[i] = 0;
        }
        g_slots_size = new_size;
    }
}

static IV create_slot(pTHX_ const char *name, STRLEN name_len) {
    IV idx = g_slots_count++;
    char key[32];
    int klen;

    ensure_slot_capacity(idx);
    hv_store(g_slot_index, name, name_len, newSViv(idx), 0);
    klen = snprintf(key, sizeof(key), "%ld", (long)idx);
    hv_store(g_slot_names, key, klen, newSVpvn(name, name_len), 0);

    return idx;
}

static char* get_caller(pTHX) {
    return HvNAME((HV*)CopSTASH(PL_curcop));
}

static void install_accessor(pTHX_ const char *pkg, const char *name, IV idx) {
    char full[512];
    CV *cv;

    snprintf(full, sizeof(full), "%s::%s", pkg, name);
    cv = newXS(full, xs_slot_accessor, __FILE__);
    CvXSUBANY(cv).any_iv = idx;

    /* Install call checker for custom op optimization */
    cv_set_call_checker(cv, slot_call_checker, (SV*)cv);
}

static XS(xs_import) {
    dXSARGS;
    char *pkg = get_caller(aTHX);
    int i;

    for (i = 1; i < items; i++) {
        char *name = SvPV_nolen(ST(i));
        STRLEN name_len = SvCUR(ST(i));
        IV idx;
        SV **existing;

        existing = hv_fetch(g_slot_index, name, name_len, 0);
        if (existing) {
            idx = SvIV(*existing);
        } else {
            idx = create_slot(aTHX_ name, name_len);
        }
        install_accessor(aTHX_ pkg, name, idx);
    }
    XSRETURN_EMPTY;
}

/* ============================================
   Watch/unwatch API
   ============================================ */

static XS(xs_watch) {
    dXSARGS;
    if (items < 2) croak("Usage: slot::watch($name, $callback)");

    char *name = SvPV_nolen(ST(0));
    STRLEN name_len = SvCUR(ST(0));
    SV *callback = ST(1);
    SV **existing;
    AV *callbacks;
    SV **idx_sv;

    existing = hv_fetch(g_watchers, name, name_len, 0);
    if (existing && SvROK(*existing)) {
        callbacks = (AV*)SvRV(*existing);
    } else {
        callbacks = newAV();
        hv_store(g_watchers, name, name_len, newRV_noinc((SV*)callbacks), 0);
    }
    av_push(callbacks, SvREFCNT_inc(callback));

    /* Set the has_watchers flag for fast path */
    idx_sv = hv_fetch(g_slot_index, name, name_len, 0);
    if (idx_sv) {
        g_has_watchers[SvIV(*idx_sv)] = 1;
    }

    XSRETURN_EMPTY;
}

static XS(xs_unwatch) {
    dXSARGS;
    if (items < 1) croak("Usage: slot::unwatch($name, [$callback])");

    char *name = SvPV_nolen(ST(0));
    STRLEN name_len = SvCUR(ST(0));
    SV **idx_sv;
    int clear_flag = 0;



( run in 4.144 seconds using v1.01-cache-2.11-cpan-d80b1682f3f )