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 1.483 second using v1.01-cache-2.11-cpan-d80b1682f3f )