From: Vincent Pit Date: Sun, 29 Jun 2008 16:24:29 +0000 (+0200) Subject: Importing Variable-Magic-0.07_02.tar.gz X-Git-Tag: v0.07_02^0 X-Git-Url: http://git.vpit.fr/?p=perl%2Fmodules%2FVariable-Magic.git;a=commitdiff_plain;h=6f35a291f0c453d34b617ee9eb03d2a68c410614 Importing Variable-Magic-0.07_02.tar.gz --- diff --git a/MANIFEST b/MANIFEST index 559408b..90a639c 100644 --- a/MANIFEST +++ b/MANIFEST @@ -6,6 +6,7 @@ Makefile.PL README lib/Variable/Magic.pm samples/magic.pl +samples/uvar.pl t/00-load.t t/01-import.t t/10-simple.t diff --git a/META.yml b/META.yml index c4bb419..166ea1d 100644 --- a/META.yml +++ b/META.yml @@ -1,14 +1,17 @@ -# http://module-build.sourceforge.net/META-spec.html -#XXXXXXX This is a prototype!!! It will change in the future!!! XXXXX# -name: Variable-Magic -version: 0.07_01 -version_from: lib/Variable/Magic.pm -installdirs: site -requires: +--- #YAML:1.0 +name: Variable-Magic +version: 0.07_02 +abstract: Associate user-defined magic to variables from Perl. +license: perl +author: + - Vincent Pit +generated_by: ExtUtils::MakeMaker version 6.42 +distribution_type: module +requires: Carp: 0 Exporter: 0 Test::More: 0 XSLoader: 0 - -distribution_type: module -generated_by: ExtUtils::MakeMaker version 6.30 +meta-spec: + url: http://module-build.sourceforge.net/META-spec-v1.3.html + version: 1.3 diff --git a/Magic.xs b/Magic.xs index fd22ffa..87139f6 100644 --- a/Magic.xs +++ b/Magic.xs @@ -49,55 +49,6 @@ # define MGf_LOCAL 0 #endif /* !MGf_LOCAL */ -/* --- Our sv_magicext ----------------------------------------------------- */ - -#ifdef sv_magicext -STATIC MAGIC *vmg_sv_magicext(pTHX_ SV *sv, SV *obj, MGVTBL *vtbl, SV *obj2, I32 flag) { - return sv_magicext(sv, obj, PERL_MAGIC_ext, vtbl, (const char *) obj2, flag); -} -#else /* Stub inspired from 5.7.3's sv_magicext */ -STATIC MAGIC *vmg_sv_magicext(pTHX_ SV *sv, SV *obj, MGVTBL *vtbl, SV *obj2, I32 flag) { - MAGIC* mg; - - if (SvTYPE(sv) < SVt_PVMG) { - SvUPGRADE(sv, SVt_PVMG); - } - Newx(mg, 1, MAGIC); - mg->mg_moremagic = SvMAGIC(sv); - SvMAGIC_set(sv, mg); - - if (!obj || obj == sv || - (SvTYPE(obj) == SVt_PVGV && - (GvSV(obj) == sv || GvHV(obj) == (HV *) sv || GvAV(obj) == (AV *) sv || - GvCV(obj) == (CV *) sv || GvIOp(obj) == (IO *) sv || - GvFORM(obj) == (CV *) sv))) { - mg->mg_obj = obj; - } else { - mg->mg_obj = SvREFCNT_inc(obj); - mg->mg_flags |= MGf_REFCOUNTED; - } - - mg->mg_type = PERL_MAGIC_ext; - mg->mg_len = flag; - if (obj2) { - if (flag == HEf_SVKEY) { - mg->mg_ptr = (char *) SvREFCNT_inc((SV *) obj2); - } else { - mg->mg_ptr = (char *) obj2; - } - } - mg->mg_virtual = vtbl; - - mg_magical(sv); - if (SvGMAGICAL(sv)) { - SvFLAGS(sv) &= ~(SVf_IOK | SVf_NOK | SVf_POK); - } - - return mg; -} -#endif -#define vmg_sv_magicext(S, O, V, OO, F) vmg_sv_magicext(aTHX_ (S), (O), (V), (OO), (F)) - /* --- Context-safe global data -------------------------------------------- */ #define MY_CXT_KEY __PACKAGE__ "::_guts" XS_VERSION @@ -136,6 +87,8 @@ STATIC U16 vmg_gensig(pTHX) { typedef struct { MGVTBL *vtbl; U16 sig; + int uvar; + SV *cb_data; SV *cb_get, *cb_set, *cb_len, *cb_clear, *cb_free; #if MGf_COPY SV *cb_copy; @@ -146,7 +99,7 @@ typedef struct { #if MGf_LOCAL SV *cb_local; #endif /* MGf_LOCAL */ - SV *cb_data; + SV *cb_fetch, *cb_store, *cb_exists, *cb_delete; } MGWIZ; #define MGWIZ2SV(W) (newSVuv(PTR2UV(W))) @@ -209,24 +162,36 @@ STATIC SV *vmg_data_get(SV *sv, U16 sig) { /* ... Magic cast/dispell .................................................. */ +STATIC I32 vmg_uf_val(pTHX_ IV idx, SV *sv); + STATIC UV vmg_cast(pTHX_ SV *sv, SV *wiz, AV *args) { #define vmg_cast(S, W, A) vmg_cast(aTHX_ (S), (W), (A)) + int has_uvar = 0; MAGIC *mg = NULL, *moremagic = NULL; MGWIZ *w; SV *data; w = SV2MGWIZ(wiz); - if (SvTYPE(sv) >= SVt_PVMG) { - for (mg = SvMAGIC(sv); mg; mg = moremagic) { - moremagic = mg->mg_moremagic; - if ((mg->mg_type == PERL_MAGIC_ext) && (mg->mg_private == w->sig)) { break; } - } + if ((SvTYPE(sv) >= SVt_PVMG) && (mg = SvMAGIC(sv))) { + if (mg->mg_type == PERL_MAGIC_uvar) { has_uvar = 1; } + do { + if ((mg->mg_type == PERL_MAGIC_ext) && (mg->mg_private == w->sig)) { break;} + mg = mg->mg_moremagic; + } while (mg); if (mg) { return 1; } } + if (w->uvar && (SvTYPE(sv) >= SVt_PVHV) && !has_uvar) { + struct ufuncs uf; + uf.uf_val = vmg_uf_val; + uf.uf_set = NULL; + uf.uf_index = 0; + sv_magicext(sv, NULL, PERL_MAGIC_uvar, &PL_vtbl_uvar, (char *) &uf, sizeof(uf)); + } + data = (w->cb_data) ? vmg_data_new(w->cb_data, sv, args) : NULL; - mg = vmg_sv_magicext(sv, data, w->vtbl, wiz, HEf_SVKEY); + mg = sv_magicext(sv, data, PERL_MAGIC_ext, w->vtbl, (char *) wiz, HEf_SVKEY); mg->mg_private = w->sig; mg->mg_flags = mg->mg_flags #if MGf_COPY @@ -302,6 +267,37 @@ STATIC int vmg_cb_call(pTHX_ SV *cb, SV *sv, SV *data) { return ret; } +STATIC int vmg_cb_call2(pTHX_ SV *cb, SV *sv, SV *data, SV *extra) { +#define vmg_cb_call2(I, S, D, E) vmg_cb_call2(aTHX_ (I), (S), (D), (E)) + int ret; + + dSP; + int count; + + ENTER; + SAVETMPS; + + PUSHMARK(SP); + XPUSHs(sv_2mortal(newRV_inc(sv))); + XPUSHs(data ? data : &PL_sv_undef); + if (extra) { XPUSHs(extra); } + PUTBACK; + + count = call_sv(cb, G_SCALAR); + + SPAGAIN; + + if (count != 1) { croak("Callback needs to return 1 scalar\n"); } + ret = POPi; + + PUTBACK; + + FREETMPS; + LEAVE; + + return ret; +} + STATIC int vmg_svt_get(pTHX_ SV *sv, MAGIC *mg) { return vmg_cb_call(SV2MGWIZ(mg->mg_ptr)->cb_get, sv, mg->mg_obj); } @@ -356,33 +352,7 @@ STATIC int vmg_svt_free(pTHX_ SV *sv, MAGIC *mg) { #if MGf_COPY STATIC int vmg_svt_copy(pTHX_ SV *sv, MAGIC *mg, SV *nsv, const char *name, int namelen) { - int ret; - - dSP; - int count; - - ENTER; - SAVETMPS; - - PUSHMARK(SP); - XPUSHs(sv_2mortal(newRV_inc(sv))); - XPUSHs((mg->mg_obj) ? (mg->mg_obj) : &PL_sv_undef); - XPUSHs(sv_mortalcopy(nsv)); - PUTBACK; - - count = call_sv(SV2MGWIZ(mg->mg_ptr)->cb_copy, G_SCALAR); - - SPAGAIN; - - if (count != 1) { croak("Callback needs to return 1 scalar\n"); } - ret = POPi; - - PUTBACK; - - FREETMPS; - LEAVE; - - return ret; + return vmg_cb_call2(SV2MGWIZ(mg->mg_ptr)->cb_copy, sv, mg->mg_obj, nsv); } #endif /* MGf_COPY */ @@ -398,6 +368,39 @@ STATIC int vmg_svt_local(pTHX_ SV *nsv, MAGIC *mg) { } #endif /* MGf_LOCAL */ +STATIC I32 vmg_uf_val(pTHX_ IV idx, SV *sv) { + MAGIC *mg; + SV *key; + for (mg = SvMAGIC(sv); mg; mg = mg->mg_moremagic) { + if (mg->mg_type == PERL_MAGIC_uvar) { key = mg->mg_obj; break; } + } + if (!key) { return 0; } + for (mg = SvMAGIC(sv); mg; mg = mg->mg_moremagic) { + MGWIZ *w; + if ((mg->mg_type != PERL_MAGIC_ext) || + (mg->mg_private < SIG_MIN) || (mg->mg_private > SIG_MAX)) { continue; } + w = SV2MGWIZ(mg->mg_ptr); + if (!w->uvar) { continue; } + switch (idx & (HV_FETCH_ISSTORE|HV_FETCH_ISEXISTS|HV_FETCH_LVALUE|HV_DELETE)){ + case 0: + if (w->cb_fetch) { return vmg_cb_call2(w->cb_fetch, sv, mg->mg_obj, key); } + break; + case HV_FETCH_ISSTORE: + case HV_FETCH_LVALUE: + case (HV_FETCH_ISSTORE|HV_FETCH_LVALUE): + if (w->cb_store) { return vmg_cb_call2(w->cb_store, sv, mg->mg_obj, key); } + break; + case HV_FETCH_ISEXISTS: + if (w->cb_exists) { return vmg_cb_call2(w->cb_exists, sv, mg->mg_obj, key);} + break; + case HV_DELETE: + if (w->cb_delete) { return vmg_cb_call2(w->cb_delete, sv, mg->mg_obj, key);} + break; + } + } + return 0; +} + /* ... Wizard destructor ................................................... */ STATIC int vmg_wizard_free(pTHX_ SV *wiz, MAGIC *mg) { @@ -415,6 +418,7 @@ STATIC int vmg_wizard_free(pTHX_ SV *wiz, MAGIC *mg) { --MY_CXT.count; } + if (w->cb_data != NULL) { SvREFCNT_dec(SvRV(w->cb_data)); } if (w->cb_get != NULL) { SvREFCNT_dec(SvRV(w->cb_get)); } if (w->cb_set != NULL) { SvREFCNT_dec(SvRV(w->cb_set)); } if (w->cb_len != NULL) { SvREFCNT_dec(SvRV(w->cb_len)); } @@ -429,7 +433,10 @@ STATIC int vmg_wizard_free(pTHX_ SV *wiz, MAGIC *mg) { #if MGf_LOCAL if (w->cb_local != NULL) { SvREFCNT_dec(SvRV(w->cb_local)); } #endif /* MGf_LOCAL */ - if (w->cb_data != NULL) { SvREFCNT_dec(SvRV(w->cb_data)); } + if (w->cb_fetch != NULL) { SvREFCNT_dec(SvRV(w->cb_fetch)); } + if (w->cb_store != NULL) { SvREFCNT_dec(SvRV(w->cb_store)); } + if (w->cb_exists != NULL) { SvREFCNT_dec(SvRV(w->cb_exists)); } + if (w->cb_delete != NULL) { SvREFCNT_dec(SvRV(w->cb_delete)); } Safefree(w->vtbl); Safefree(w); @@ -481,7 +488,11 @@ STATIC U16 vmg_sv2sig(pTHX_ SV *sv) { return sig; } -#define VMG_SET_CB(T, V, M, CB) \ +#define VMG_SET_CB(T, M, CB) \ + cb = (CB); \ + (M)->cb_##T = (SvROK(cb)) ? newRV_inc(SvRV(cb)) : NULL; + +#define VMG_SET_CB_SVT(T, V, M, CB) \ cb = (CB); \ if (SvROK(cb)) { \ (V)->svt_##T = vmg_svt_##T; (M)->cb_##T = newRV_inc(SvRV(cb)); \ @@ -523,17 +534,7 @@ PREINIT: CODE: dMY_CXT; - if (items != 7 -#if MGf_COPY - + 1 -#endif /* MGf_COPY */ -#if MGf_DUP - + 1 -#endif /* MGf_DUP */ -#if MGf_LOCAL - + 1 -#endif /* MGf_LOCAL */ - ) { croak(vmg__wizard_args); } + if (items != 14) { croak(vmg__wizard_args); } if (SvOK(svsig)) { SV **old; @@ -552,24 +553,30 @@ CODE: w->vtbl = t; w->sig = sig; - cb = ST(1); w->cb_data = SvROK(cb) ? newRV_inc(SvRV(cb)) : NULL; - VMG_SET_CB(get, t, w, ST(2)); - VMG_SET_CB(set, t, w, ST(3)); - VMG_SET_CB(len, t, w, ST(4)); - VMG_SET_CB(clear, t, w, ST(5)); - VMG_SET_CB(free, t, w, ST(6)); + VMG_SET_CB(data, w, ST(1)); + VMG_SET_CB_SVT(get, t, w, ST(2)); + VMG_SET_CB_SVT(set, t, w, ST(3)); + VMG_SET_CB_SVT(len, t, w, ST(4)); + VMG_SET_CB_SVT(clear, t, w, ST(5)); + VMG_SET_CB_SVT(free, t, w, ST(6)); #if MGf_COPY - VMG_SET_CB(copy, t, w, ST(7)); + VMG_SET_CB_SVT(copy, t, w, ST(7)); #endif /* MGf_COPY */ #if MGf_DUP - VMG_SET_CB(dup, t, w, ST(8)); + VMG_SET_CB_SVT(dup, t, w, ST(8)); #endif /* MGf_DUP */ #if MGf_LOCAL - VMG_SET_CB(local, t, w, ST(9)); + VMG_SET_CB_SVT(local, t, w, ST(9)); #endif /* MGf_LOCAL */ + VMG_SET_CB(fetch, w, ST(10)); + VMG_SET_CB(store, w, ST(11)); + VMG_SET_CB(exists, w, ST(12)); + VMG_SET_CB(delete, w, ST(13)); + + w->uvar = (w->cb_fetch || w->cb_store || w->cb_exists || w->cb_delete); sv = MGWIZ2SV(w); - mg = vmg_sv_magicext(sv, NULL, &vmg_wizard_vtbl, NULL, -1); + mg = sv_magicext(sv, NULL, PERL_MAGIC_ext, &vmg_wizard_vtbl, NULL, -1); mg->mg_private = SIG_WIZ; #if MGf_COPY if (t->svt_copy) { mg->mg_flags |= MGf_COPY; } diff --git a/README b/README index a626da0..98e8dfe 100644 --- a/README +++ b/README @@ -2,7 +2,7 @@ NAME Variable::Magic - Associate user-defined magic to variables from Perl. VERSION - Version 0.07_01 + Version 0.07_02 SYNOPSIS use Variable::Magic qw/wizard cast dispell/; diff --git a/lib/Variable/Magic.pm b/lib/Variable/Magic.pm index f605649..11a26a8 100644 --- a/lib/Variable/Magic.pm +++ b/lib/Variable/Magic.pm @@ -13,14 +13,14 @@ Variable::Magic - Associate user-defined magic to variables from Perl. =head1 VERSION -Version 0.07_01 +Version 0.07_02 =cut use vars qw/$VERSION/; BEGIN { - $VERSION = '0.07_01'; + $VERSION = '0.07_02'; } =head1 SYNOPSIS @@ -155,12 +155,7 @@ sub wizard { croak 'Wrong number of arguments for wizard()' if @_ % 2; my %opts = @_; my $sig = $opts{sig}; - my @types = qw/data get set len clear free/; - push @types, 'copy' if MGf_COPY; - push @types, 'dup' if MGf_DUP; - delete $opts{dup}; # don't use it for now - push @types, 'local' if MGf_LOCAL; - return _wizard($sig, map { $opts{$_} } @types); + return _wizard($sig, map { $opts{$_} } qw/data get set len clear free copy dup local fetch store exists delete/); } =head2 C diff --git a/samples/uvar.pl b/samples/uvar.pl new file mode 100755 index 0000000..6620aec --- /dev/null +++ b/samples/uvar.pl @@ -0,0 +1,18 @@ +#!/usr/bin/env perl + +use lib qw{blib/arch blib/lib}; + +use strict; +use warnings; + +use Variable::Magic qw/wizard cast/; + +my $w = wizard map { + my $s = $_; $s => sub { print STDERR "$s $_[2]!\n" } +} qw/fetch store exists delete/; +my %h; +cast %h, $w; +$h{'foo'} = 1; +print STDERR "#", $h{'foo'}, "#\n"; +my $y = exists $h{'foo'}; +delete $h{'foo'};