Ancient
view release on metacpan or search on metacpan
xs/slot/slot.c view on Meta::CPAN
IV idx = SvIV(*svp);
OP *newop = newOP(OP_CUSTOM, 0);
newop->op_ppaddr = pp_slot_clear;
newop->op_targ = idx;
op_free(entersubop);
return newop;
}
}
}
return entersubop;
}
/* ============================================
XS Accessor - fallback for dynamic calls
============================================ */
static XS(xs_slot_accessor) {
dXSARGS;
IV idx = CvXSUBANY(cv).any_iv;
SV **slot = &g_slots[idx];
if (items) {
SV *old = *slot;
SV *new_val = ST(0);
*slot = SvREFCNT_inc_simple_NN(new_val);
SvREFCNT_dec_NN(old);
if (g_has_watchers[idx]) fire_watchers(aTHX_ idx, new_val);
ST(0) = new_val;
XSRETURN(1);
}
ST(0) = *slot;
XSRETURN(1);
}
/* ============================================
Watchers
============================================ */
static void fire_watchers(pTHX_ IV idx, SV *new_val) {
char key[32];
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;
xs/slot/slot.c view on Meta::CPAN
ST(0) = g_slots[idx];
XSRETURN(1);
}
XSRETURN_EMPTY;
}
static XS(xs_get) {
dXSARGS;
if (items < 1) XSRETURN_UNDEF;
STRLEN name_len;
const char *name = SvPV(ST(0), name_len);
SV **svp = hv_fetch(g_slot_index, name, name_len, 0);
if (svp) {
ST(0) = g_slots[SvIV(*svp)];
XSRETURN(1);
}
XSRETURN_UNDEF;
}
static XS(xs_set) {
dXSARGS;
if (items < 2) XSRETURN_EMPTY;
STRLEN name_len;
const char *name = SvPV(ST(0), name_len);
SV **svp = hv_fetch(g_slot_index, name, name_len, 0);
if (svp) {
IV idx = SvIV(*svp);
SV *old = g_slots[idx];
g_slots[idx] = SvREFCNT_inc(ST(1));
SvREFCNT_dec(old);
ST(0) = g_slots[idx];
XSRETURN(1);
}
XSRETURN_EMPTY;
}
/* slot::add - create slot(s) without installing accessors (fastest path) */
static XS(xs_add) {
dXSARGS;
int i;
for (i = 0; i < items; i++) {
STRLEN name_len;
const char *name = SvPV(ST(i), name_len);
/* Only create if doesn't exist */
if (!hv_fetch(g_slot_index, name, name_len, 0)) {
create_slot(aTHX_ name, name_len);
}
}
XSRETURN_EMPTY;
}
static XS(xs_slots) {
dXSARGS;
HE *entry;
PERL_UNUSED_VAR(items);
SP -= items;
hv_iterinit(g_slot_index);
while ((entry = hv_iternext(g_slot_index))) {
XPUSHs(hv_iterkeysv(entry));
}
PUTBACK;
return;
}
/* slot::exists - check if slot is defined */
static XS(xs_exists) {
dXSARGS;
STRLEN name_len;
const char *name;
if (items != 1) croak("Usage: slot::exists($name)");
name = SvPV(ST(0), name_len);
if (hv_exists(g_slot_index, name, name_len)) {
XSRETURN_YES;
}
XSRETURN_NO;
}
/* slot::clear - reset slot value to undef and clear watchers */
static XS(xs_clear) {
dXSARGS;
int i;
for (i = 0; i < items; i++) {
STRLEN name_len;
const char *name = SvPV(ST(i), name_len);
SV **svp = hv_fetch(g_slot_index, name, name_len, 0);
if (svp) {
IV idx = SvIV(*svp);
SV *old = g_slots[idx];
/* Reset to undef */
g_slots[idx] = &PL_sv_undef;
SvREFCNT_dec(old);
/* Clear watchers */
hv_delete(g_watchers, name, name_len, G_DISCARD);
g_has_watchers[idx] = 0;
}
}
XSRETURN_EMPTY;
}
/* slot::clear_by_idx - reset slot value to undef and clear watchers by index */
static XS(xs_clear_by_idx) {
dXSARGS;
int i;
for (i = 0; i < items; i++) {
IV idx = SvIV(ST(i));
if (idx >= 0 && idx < g_slots_count) {
SV *old = g_slots[idx];
char key[32];
int klen;
SV **name_sv;
/* Reset to undef */
g_slots[idx] = &PL_sv_undef;
SvREFCNT_dec(old);
/* Clear watchers - need to look up name from idx */
klen = snprintf(key, sizeof(key), "%ld", (long)idx);
name_sv = hv_fetch(g_slot_names, key, klen, 0);
if (name_sv && SvOK(*name_sv)) {
STRLEN name_len;
const char *name = SvPV(*name_sv, name_len);
( run in 0.628 second using v1.01-cache-2.11-cpan-800906f7e73 )