STATIC const char vmg_wrongargnum[] = "Wrong number of arguments";
STATIC const char vmg_argstorefailed[] = "Error while storing arguments";
-/* --- Signatures ---------------------------------------------------------- */
+/* --- Context-safe global data -------------------------------------------- */
-#define SIG_WZO ((U16) (0x3891))
-#define SIG_WIZ ((U16) (0x3892))
+#define MY_CXT_KEY __PACKAGE__ "::_guts" XS_VERSION
+
+typedef struct {
+ HV *b__op_stashes[OPc_MAX];
+} my_cxt_t;
+
+START_MY_CXT
/* --- <vmg_vtable> structure ---------------------------------------------- */
#endif /* VMG_THREADSAFE */
-/* --- Context-safe global data -------------------------------------------- */
+#define vmg_wizard_id(W) PTR2IV(vmg_vtable_vtbl((W)->vtable))
-#define MY_CXT_KEY __PACKAGE__ "::_guts" XS_VERSION
+/* --- Wizard SV objects --------------------------------------------------- */
-typedef struct {
- HV *b__op_stashes[OPc_MAX];
-} my_cxt_t;
+STATIC int vmg_wizard_sv_free(pTHX_ SV *sv, MAGIC *mg) {
+ if (PL_dirty) /* During global destruction, the context is already freed */
+ return 0;
-START_MY_CXT
+ vmg_wizard_free((vmg_wizard *) mg->mg_ptr);
-/* --- Wizard SV objects --------------------------------------------------- */
+ return 0;
+}
-STATIC int vmg_wizard_sv_free(pTHX_ SV *sv, MAGIC *mg);
#if VMG_THREADSAFE
-STATIC int vmg_wizard_sv_dup(pTHX_ MAGIC *mg, CLONE_PARAMS *params);
-#endif
+
+STATIC int vmg_wizard_sv_dup(pTHX_ MAGIC *mg, CLONE_PARAMS *params) {
+ mg->mg_ptr = (char *) vmg_wizard_dup((const vmg_wizard *) mg->mg_ptr, params);
+
+ return 0;
+}
+
+#endif /* VMG_THREADSAFE */
STATIC MGVTBL vmg_wizard_sv_vtbl = {
NULL, /* get */
if (w) {
MAGIC *mg = sv_magicext(wiz, NULL, PERL_MAGIC_ext, &vmg_wizard_sv_vtbl,
(const char *) w, 0);
- mg->mg_private = SIG_WZO;
+ mg->mg_private = 0;
#if VMG_THREADSAFE
mg->mg_flags |= MGf_DUP;
#endif
return wiz;
}
-STATIC const SV *vmg_wizard_sv_validate(pTHX_ const SV *wiz) {
-#define vmg_wizard_sv_validate(W) vmg_wizard_sv_validate(aTHX_ (W))
- if (SvROK(wiz)) {
- wiz = SvRV_const(wiz);
#if VMG_THREADSAFE
- if (SvTYPE(wiz) >= SVt_PVMG && SvMAGIC(wiz))
-#else
- if (SvIOK(wiz))
-#endif
- return wiz;
- }
- croak(vmg_invalid_wiz);
- /* Not reached */
- return NULL;
-}
+#define vmg_sv_has_wizard_type(S) (SvTYPE(S) >= SVt_PVMG)
-#if VMG_THREADSAFE
-
-STATIC const vmg_wizard *vmg_wizard_from_sv(const SV *wiz) {
+STATIC const vmg_wizard *vmg_wizard_from_sv_nocheck(const SV *wiz) {
MAGIC *mg;
for (mg = SvMAGIC(wiz); mg; mg = mg->mg_moremagic) {
return NULL;
}
-#define vmg_wizard_from_sv(W) vmg_wizard_from_sv((const SV *) (W))
-
-#define vmg_wizard_sv_id(W) PTR2IV(vmg_vtable_vtbl(vmg_wizard_from_sv(W)->vtable))
-
-#else
-
-#define vmg_wizard_sv_id(W) SvIVX((const SV *) (W))
-
-#define vmg_wizard_from_sv(W) INT2PTR(const vmg_wizard *, vmg_wizard_sv_id(W))
+#else /* VMG_THREADSAFE */
-#endif
+#define vmg_sv_has_wizard_type(S) SvIOK(S)
-STATIC int vmg_wizard_sv_free(pTHX_ SV *sv, MAGIC *mg) {
- if (PL_dirty) /* During global destruction, the context is already freed */
- return 0;
+#define vmg_wizard_from_sv_nocheck(W) INT2PTR(const vmg_wizard *, SvIVX(W))
- vmg_wizard_free((vmg_wizard *) mg->mg_ptr);
+#endif /* !VMG_THREADSAFE */
- return 0;
-}
+#define vmg_wizard_from_sv(W) (vmg_sv_has_wizard_type(W) ? vmg_wizard_from_sv_nocheck(W) : NULL)
-#if VMG_THREADSAFE
+STATIC const vmg_wizard *vmg_wizard_from_mg(const MAGIC *mg) {
+ if (mg->mg_type == PERL_MAGIC_ext && mg->mg_len == HEf_SVKEY) {
+ SV *sv = (SV *) mg->mg_ptr;
-STATIC int vmg_wizard_sv_dup(pTHX_ MAGIC *mg, CLONE_PARAMS *params) {
- mg->mg_ptr = (char *) vmg_wizard_dup((const vmg_wizard *) mg->mg_ptr, params);
+ if (vmg_sv_has_wizard_type(sv))
+ return vmg_wizard_from_sv_nocheck(sv);
+ }
- return 0;
+ return NULL;
}
-#endif /* VMG_THREADSAFE */
+#define vmg_wizard_from_mg_nocheck(M) vmg_wizard_from_sv_nocheck((const SV *) (M)->mg_ptr)
/* --- User-level functions implementation --------------------------------- */
-STATIC const MAGIC *vmg_find(const SV *sv, const SV *wiz) {
- const MAGIC *mg, *moremagic;
+STATIC const MAGIC *vmg_find(const SV *sv, const vmg_wizard *w) {
+ const MAGIC *mg;
IV wid;
if (SvTYPE(sv) < SVt_PVMG)
return NULL;
- wid = vmg_wizard_sv_id(wiz);
- for (mg = SvMAGIC(sv); mg; mg = moremagic) {
- moremagic = mg->mg_moremagic;
- if (mg->mg_type == PERL_MAGIC_ext && mg->mg_private == SIG_WIZ) {
- IV zid = vmg_wizard_sv_id(mg->mg_ptr);
- if (zid == wid)
- return mg;
- }
+ wid = vmg_wizard_id(w);
+
+ for (mg = SvMAGIC(sv); mg; mg = mg->mg_moremagic) {
+ const vmg_wizard *z = vmg_wizard_from_mg(mg);
+
+ if (z && vmg_wizard_id(z) == wid)
+ return mg;
}
return NULL;
return nsv;
}
-STATIC SV *vmg_data_get(pTHX_ SV *sv, const SV *wiz) {
+STATIC SV *vmg_data_get(pTHX_ SV *sv, const vmg_wizard *w) {
#define vmg_data_get(S, W) vmg_data_get(aTHX_ (S), (W))
- const MAGIC *mg = vmg_find(sv, wiz);
+ const MAGIC *mg = vmg_find(sv, w);
+
return mg ? mg->mg_obj : NULL;
}
}
#endif /* VMG_UVAR */
-STATIC UV vmg_cast(pTHX_ SV *sv, const SV *wiz, SV **args, I32 items) {
-#define vmg_cast(S, W, A, I) vmg_cast(aTHX_ (S), (W), (A), (I))
- const vmg_wizard *w;
- MAGIC *mg;
- SV *data;
- U32 oldgmg;
+STATIC UV vmg_cast(pTHX_ SV *sv, const vmg_wizard *w, const SV *wiz, SV **args, I32 items) {
+#define vmg_cast(S, W, WIZ, A, I) vmg_cast(aTHX_ (S), (W), (WIZ), (A), (I))
+ MAGIC *mg;
+ MGVTBL *t;
+ SV *data;
+ U32 oldgmg;
- if (vmg_find(sv, wiz))
+ if (vmg_find(sv, w))
return 1;
- w = vmg_wizard_from_sv(wiz);
oldgmg = SvGMAGICAL(sv);
data = (w->cb_data) ? vmg_data_new(w->cb_data, sv, args, items) : NULL;
+
+ t = vmg_vtable_vtbl(w->vtable);
+ mg = sv_magicext(sv, data, PERL_MAGIC_ext, t, (const char *) wiz, HEf_SVKEY);
+ mg->mg_private = 0;
+
/* sv_magicext() calls mg_magical and increments data's refcount */
- mg = sv_magicext(sv, data, PERL_MAGIC_ext, vmg_vtable_vtbl(w->vtable),
- (const char *) wiz, HEf_SVKEY);
SvREFCNT_dec(data);
- mg->mg_private = SIG_WIZ;
- if (w->cb_copy)
+
+ if (t->svt_copy)
mg->mg_flags |= MGf_COPY;
#if 0
- if (w->cb_dup)
+ if (t->svt_dup)
mg->mg_flags |= MGf_DUP;
#endif
#if MGf_LOCAL
- if (w->cb_local)
+ if (t->svt_local)
mg->mg_flags |= MGf_LOCAL;
#endif /* MGf_LOCAL */
return 1;
}
-STATIC UV vmg_dispell(pTHX_ SV *sv, const SV *wiz) {
+STATIC UV vmg_dispell(pTHX_ SV *sv, const vmg_wizard *w) {
#define vmg_dispell(S, W) vmg_dispell(aTHX_ (S), (W))
#if VMG_UVAR
U32 uvars = 0;
#endif /* VMG_UVAR */
MAGIC *mg, *prevmagic, *moremagic = NULL;
- IV wid = vmg_wizard_sv_id(wiz);
+ IV wid = vmg_wizard_id(w);
if (SvTYPE(sv) < SVt_PVMG)
return 0;
for (prevmagic = NULL, mg = SvMAGIC(sv); mg; prevmagic = mg, mg = moremagic) {
+ const vmg_wizard *z;
+
moremagic = mg->mg_moremagic;
- if (mg->mg_type == PERL_MAGIC_ext && mg->mg_private == SIG_WIZ) {
+
+ z = vmg_wizard_from_mg(mg);
+ if (z) {
+ IV zid = vmg_wizard_id(z);
+
#if VMG_UVAR
- const vmg_wizard *z = vmg_wizard_from_sv(mg->mg_ptr);
-#endif /* VMG_UVAR */
- IV zid = vmg_wizard_sv_id(mg->mg_ptr);
if (zid == wid) {
-#if VMG_UVAR
/* If the current has no uvar, short-circuit uvar deletion. */
uvars = z->uvar ? (uvars + 1) : 0;
-#endif /* VMG_UVAR */
break;
-#if VMG_UVAR
} else if (z->uvar) {
++uvars;
/* We can't break here since we need to find the ext magic to delete. */
-#endif /* VMG_UVAR */
}
+#else /* VMG_UVAR */
+ if (zid == wid)
+ break;
+#endif /* !VMG_UVAR */
}
}
if (!mg)
/* mg was the first ext magic in the chain that had uvar */
for (mg = moremagic; mg; mg = mg->mg_moremagic) {
- if (mg->mg_type == PERL_MAGIC_ext && mg->mg_private == SIG_WIZ) {
- const vmg_wizard *z = vmg_wizard_from_sv(mg->mg_ptr);
- if (z->uvar) {
- ++uvars;
- break;
- }
+ const vmg_wizard *z = vmg_wizard_from_mg(mg);
+
+ if (z && z->uvar) {
+ ++uvars;
+ break;
}
}
vmg_cb_call(aTHX_ (I), VMG_CB_FLAGS((OI), 3), (S), (A1), (A2), (A3))
STATIC int vmg_svt_get(pTHX_ SV *sv, MAGIC *mg) {
- const vmg_wizard *w = vmg_wizard_from_sv(mg->mg_ptr);
+ const vmg_wizard *w = vmg_wizard_from_mg_nocheck(mg);
+
return vmg_cb_call1(w->cb_get, w->opinfo, sv, mg->mg_obj);
}
STATIC int vmg_svt_set(pTHX_ SV *sv, MAGIC *mg) {
- const vmg_wizard *w = vmg_wizard_from_sv(mg->mg_ptr);
+ const vmg_wizard *w = vmg_wizard_from_mg_nocheck(mg);
+
return vmg_cb_call1(w->cb_set, w->opinfo, sv, mg->mg_obj);
}
STATIC U32 vmg_svt_len(pTHX_ SV *sv, MAGIC *mg) {
- const vmg_wizard *w = vmg_wizard_from_sv(mg->mg_ptr);
+ const vmg_wizard *w = vmg_wizard_from_mg_nocheck(mg);
unsigned int opinfo = w->opinfo;
U32 len, ret;
SV *svr;
}
STATIC int vmg_svt_clear(pTHX_ SV *sv, MAGIC *mg) {
- const vmg_wizard *w = vmg_wizard_from_sv(mg->mg_ptr);
+ const vmg_wizard *w = vmg_wizard_from_mg_nocheck(mg);
+
return vmg_cb_call1(w->cb_clear, w->opinfo, sv, mg->mg_obj);
}
if (PL_dirty)
return 0;
- w = vmg_wizard_from_sv(mg->mg_ptr);
+ w = vmg_wizard_from_mg_nocheck(mg);
/* So that it survives the temp cleanup below */
SvREFCNT_inc_simple_void(sv);
int keylen
# endif
) {
- const vmg_wizard *w = vmg_wizard_from_sv(mg->mg_ptr);
+ const vmg_wizard *w = vmg_wizard_from_mg_nocheck(mg);
SV *keysv;
int ret;
#if MGf_LOCAL
STATIC int vmg_svt_local(pTHX_ SV *nsv, MAGIC *mg) {
- const vmg_wizard *w = vmg_wizard_from_sv(mg->mg_ptr);
+ const vmg_wizard *w = vmg_wizard_from_mg_nocheck(mg);
+
return vmg_cb_call1(w->cb_local, w->opinfo, nsv, mg->mg_obj);
}
#endif /* MGf_LOCAL */
default:
continue;
}
- if (mg->mg_private != SIG_WIZ) continue;
- w = vmg_wizard_from_sv(mg->mg_ptr);
+ w = vmg_wizard_from_mg(mg);
+ if (!w) continue;
switch (w->uvar) {
case 0:
continue;
SV *cast(SV *sv, SV *wiz, ...)
PROTOTYPE: \[$@%&*]$@
PREINIT:
+ const vmg_wizard *w = NULL;
SV **args = NULL;
+ UV ret;
I32 i = 0;
CODE:
if (items > 2) {
i = items - 2;
args = &ST(2);
}
- RETVAL = newSVuv(vmg_cast(SvRV(sv), vmg_wizard_sv_validate(wiz), args, i));
+ if (SvROK(wiz)) {
+ wiz = SvRV_const(wiz);
+ w = vmg_wizard_from_sv(wiz);
+ }
+ if (!w)
+ croak(vmg_invalid_wiz);
+ RETVAL = newSVuv(vmg_cast(SvRV(sv), w, wiz, args, i));
OUTPUT:
RETVAL
getdata(SV *sv, SV *wiz)
PROTOTYPE: \[$@%&*]$
PREINIT:
+ const vmg_wizard *w = NULL;
SV *data;
PPCODE:
- data = vmg_data_get(SvRV(sv), vmg_wizard_sv_validate(wiz));
+ if (SvROK(wiz))
+ w = vmg_wizard_from_sv(SvRV_const(wiz));
+ if (!w)
+ croak(vmg_invalid_wiz);
+ data = vmg_data_get(SvRV(sv), w);
if (!data)
XSRETURN_EMPTY;
ST(0) = data;
SV *dispell(SV *sv, SV *wiz)
PROTOTYPE: \[$@%&*]$
+PREINIT:
+ const vmg_wizard *w = NULL;
CODE:
- RETVAL = newSVuv(vmg_dispell(SvRV(sv), vmg_wizard_sv_validate(wiz)));
+ if (SvROK(wiz))
+ w = vmg_wizard_from_sv(SvRV_const(wiz));
+ if (!w)
+ croak(vmg_invalid_wiz);
+ RETVAL = newSVuv(vmg_dispell(SvRV(sv), w));
OUTPUT:
RETVAL