]> git.vpit.fr Git - perl/modules/Variable-Magic.git/commitdiff
Importing Variable-Magic-0.07_02.tar.gz v0.07_02
authorVincent Pit <vince@profvince.com>
Sun, 29 Jun 2008 16:24:29 +0000 (18:24 +0200)
committerVincent Pit <vince@profvince.com>
Sun, 29 Jun 2008 16:24:29 +0000 (18:24 +0200)
MANIFEST
META.yml
Magic.xs
README
lib/Variable/Magic.pm
samples/uvar.pl [new file with mode: 0755]

index 559408b0c44459c573ddcc41ad32464132938995..90a639c3954378f600b2389d627c22bfd716c4ff 100644 (file)
--- 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
index c4bb41998d4390669adae27bb48d270f036a406c..166ea1d889c2ca260a85c2de5687310e2c284aa9 100644 (file)
--- 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 <perl@profvince.com>
+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
index fd22ffa81f9e9fc04e8804c043ee47f03a8efdb5..87139f6841c1f21d98204c635bc66a39c69ef287 100644 (file)
--- a/Magic.xs
+++ b/Magic.xs
 # 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 a626da01eb6c5a454204c4eb90abea31e75b80ca..98e8dfebbc8fef102fec657da75ada6cb5abdfdc 100644 (file)
--- 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/;
index f60564917e14c139d3bfd9a8ae0d925d7b5c2b59..11a26a8511362af310831fe5f72ec10008860e3e 100644 (file)
@@ -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<gensig>
diff --git a/samples/uvar.pl b/samples/uvar.pl
new file mode 100755 (executable)
index 0000000..6620aec
--- /dev/null
@@ -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'};