Make it easier to simple xs hashref readers using prehashed keys.
Florian Ragwitz [Wed, 11 Mar 2009 04:20:04 +0000 (05:20 +0100)]
mop.c
mop.h
xs/Attribute.xs
xs/MOP.xs
xs/Method.xs
xs/Package.xs

diff --git a/mop.c b/mop.c
index 08e5349..25358f8 100644 (file)
--- a/mop.c
+++ b/mop.c
@@ -242,3 +242,41 @@ mop_prehash_keys ()
         PERL_HASH(prehashed_keys[i].hash, value, strlen(value));
     }
 }
+
+SV *
+mop_simple_reader (SV *self, mop_prehashed_key_t key)
+{
+    register HE *he;
+
+    if (!SvROK(self)) {
+        croak("can't call %s as a class method", prehashed_keys[key].name);
+    }
+
+    if (SvTYPE(SvRV(self)) != SVt_PVHV) {
+        croak("object is not a hashref");
+    }
+
+    if (!(he = hv_fetch_ent((HV *)SvRV(self), prehashed_keys[key].key, 0, prehashed_keys[key].hash))) {
+        return &PL_sv_undef;
+    }
+
+    return SvREFCNT_inc(HeVAL(he));
+}
+
+XS(mop_xs_simple_reader)
+{
+#ifdef dVAR
+    dVAR; dXSARGS;
+#else
+    dXSARGS;
+#endif
+
+    if (items != 1) {
+        croak("expected exactly one argument");
+    }
+
+    ST(0) = mop_simple_reader (ST(0), CvXSUBANY(cv).any_i32);
+    sv_2mortal(ST(0));
+    XSRETURN(1);
+}
+
diff --git a/mop.h b/mop.h
index 444f8ac..afa9358 100644 (file)
--- a/mop.h
+++ b/mop.h
@@ -40,6 +40,21 @@ void mop_prehash_keys (void);
 inline SV *mop_prehashed_key_for (mop_prehashed_key_t key);
 inline U32 mop_prehashed_hash_for (mop_prehashed_key_t key);
 
+#define INSTALL_SIMPLE_READER(klass, name) \
+    { \
+        CV *cv = newXS("Class::MOP::" #klass "::" #name, mop_xs_simple_reader, __FILE__); \
+        CvXSUBANY(cv).any_i32 = KEY_ ##name; \
+    }
+
+#define INSTALL_SIMPLE_READER_WITH_KEY(klass, name, key) \
+    { \
+        CV *cv = newXS("Class::MOP::" #klass "::" #name, mop_xs_simple_reader, __FILE__); \
+        CvXSUBANY(cv).any_i32 = KEY_ ##key; \
+    }
+
+SV *mop_simple_reader (SV *self, mop_prehashed_key_t key);
+XS(mop_xs_simple_reader);
+
 extern SV *mop_method_metaclass;
 extern SV *mop_associated_metaclass;
 extern SV *mop_wrap;
index 150fd05..0375cb4 100644 (file)
@@ -4,17 +4,5 @@ MODULE = Class::MOP::Attribute   PACKAGE = Class::MOP::Attribute
 
 PROTOTYPES: DISABLE
 
-void
-name(self)
-    SV *self
-    PREINIT:
-        register HE *he;
-    PPCODE:
-        if ( ! SvROK(self) ) {
-            die("Cannot call name as a class method");
-        }
-
-        if ( (he = hv_fetch_ent((HV *)SvRV(self), KEY_FOR(name), 0, HASH_FOR(name))) )
-            XPUSHs(HeVAL(he));
-        else
-            ST(0) = &PL_sv_undef;
+BOOT:
+    INSTALL_SIMPLE_READER(Attribute, name);
index f3a6384..60c006c 100644 (file)
--- a/xs/MOP.xs
+++ b/xs/MOP.xs
@@ -1,5 +1,9 @@
 #include "mop.h"
 
+SV *mop_method_metaclass;
+SV *mop_associated_metaclass;
+SV *mop_wrap;
+
 static bool
 find_method (const char *key, STRLEN keylen, SV *val, void *ud)
 {
@@ -8,10 +12,6 @@ find_method (const char *key, STRLEN keylen, SV *val, void *ud)
     return FALSE;
 }
 
-SV *mop_method_metaclass;
-SV *mop_associated_metaclass;
-SV *mop_wrap;
-
 MODULE = Class::MOP   PACKAGE = Class::MOP
 
 PROTOTYPES: DISABLE
index ba2c850..590cd06 100644 (file)
@@ -4,47 +4,7 @@ MODULE = Class::MOP::Method   PACKAGE = Class::MOP::Method
 
 PROTOTYPES: DISABLE
 
-void
-name(self)
-    SV *self
-    PREINIT:
-        register HE *he;
-    PPCODE:
-        if ( ! SvROK(self) ) {
-            die("Cannot call name as a class method");
-        }
-
-        if ( (he = hv_fetch_ent((HV *)SvRV(self), KEY_FOR(name), 0, HASH_FOR(name))) )
-            XPUSHs(HeVAL(he));
-        else
-            ST(0) = &PL_sv_undef;
-
-void
-package_name(self)
-    SV *self
-    PREINIT:
-        register HE *he;
-    PPCODE:
-        if ( ! SvROK(self) ) {
-            die("Cannot call package_name as a class method");
-        }
-
-        if ( (he = hv_fetch_ent((HV *)SvRV(self), KEY_FOR(package_name), 0, HASH_FOR(package_name))) )
-            XPUSHs(HeVAL(he));
-        else
-            ST(0) = &PL_sv_undef;
-
-void
-body(self)
-    SV *self
-    PREINIT:
-        register HE *he;
-    PPCODE:
-        if ( ! SvROK(self) ) {
-            die("Cannot call body as a class method");
-        }
-
-        if ( (he = hv_fetch_ent((HV *)SvRV(self), KEY_FOR(body), 0, HASH_FOR(body))) )
-            XPUSHs(HeVAL(he));
-        else
-            ST(0) = &PL_sv_undef;
+BOOT:
+    INSTALL_SIMPLE_READER(Method, name);
+    INSTALL_SIMPLE_READER(Method, package_name);
+    INSTALL_SIMPLE_READER(Method, body);
index eaac489..ce8d390 100644 (file)
@@ -35,17 +35,5 @@ get_all_package_symbols(self, filter=TYPE_FILTER_NONE)
         symbols = mop_get_all_package_symbols(stash, filter);
         PUSHs(sv_2mortal(newRV_noinc((SV *)symbols)));
 
-void
-name(self)
-    SV *self
-    PREINIT:
-        register HE *he;
-    PPCODE:
-        if ( ! SvROK(self) ) {
-            die("Cannot call name as a class method");
-        }
-
-        if ( (he = hv_fetch_ent((HV *)SvRV(self), KEY_FOR(package), 0, HASH_FOR(package))) )
-            XPUSHs(HeVAL(he));
-        else
-            ST(0) = &PL_sv_undef;
+BOOT:
+    INSTALL_SIMPLE_READER_WITH_KEY(Package, name, package);