Refactor generate_isa_predicate_for-related stuff
gfx [Sat, 31 Oct 2009 05:45:29 +0000 (14:45 +0900)]
mouse.h
xs-src/Mouse.xs
xs-src/MouseTypeConstraints.xs
xs-src/MouseUtil.xs

diff --git a/mouse.h b/mouse.h
index 98f7f31..dc5858e 100644 (file)
--- a/mouse.h
+++ b/mouse.h
@@ -176,10 +176,9 @@ int mouse_tc_GlobRef   (pTHX_ SV* const sv);
 int mouse_tc_FileHandle(pTHX_ SV* const sv);
 int mouse_tc_Object    (pTHX_ SV* const sv);
 
-const char* mouse_canonicalize_package_name(const char* name);
+CV* generate_isa_predicate_for(pTHX_ SV* const klass, const char* const predicate_name);
 
-XS(XS_isa_check);
-XS(XS_isa_check_for_universal);
+XS(XS_Mouse_parameterized_check);
 
 #endif /* !MOUSE_H */
 
index 8d0f3a8..993c1c7 100644 (file)
@@ -120,6 +120,7 @@ PPCODE:
     }
 }
 
+
 MODULE = Mouse  PACKAGE = Mouse::Meta::Role
 
 BOOT:
index ffae815..60fa4c4 100644 (file)
@@ -275,7 +275,7 @@ START_MY_CXT
 #define MG_klass_pv(mg)    ((mg)->mg_ptr)
 #define MG_klass_len(mg)   ((mg)->mg_len)
 
-const char*
+static const char*
 mouse_canonicalize_package_name(const char* name){
 
     /* "::Foo" -> "Foo" */
@@ -292,7 +292,7 @@ mouse_canonicalize_package_name(const char* name){
 }
 
 static int
-lookup_isa(pTHX_ HV* const instance_stash, const char* const klass_pv){
+mouse_lookup_isa(pTHX_ HV* const instance_stash, const char* const klass_pv){
     AV*  const linearized_isa = mro_get_linear_isa(instance_stash);
     SV**       svp            = AvARRAY(linearized_isa);
     SV** const end            = svp + AvFILLp(linearized_isa) + 1;
@@ -307,90 +307,110 @@ lookup_isa(pTHX_ HV* const instance_stash, const char* const klass_pv){
     return FALSE;
 }
 
-static int
-instance_isa(pTHX_ SV* const instance, const MAGIC* const mg){
-    dMY_CXT;
-    HV* const instance_stash = SvSTASH(SvRV(instance));
-    GV* const instance_isa   = gv_fetchmeth_autoload(instance_stash, "isa", sizeof("isa")-1, 0);
-
-    /* the instance has no own isa method */
-    if(instance_isa == NULL || GvCV(instance_isa) == GvCV(MY_CXT.universal_isa)){
-        return MG_klass_stash(mg) == instance_stash
-            || lookup_isa(aTHX_ instance_stash, MG_klass_pv(mg));
-    }
-    /* the instance has its own isa method */
-    else {
-        int retval;
-        dSP;
+int
+mouse_is_an_instance_of(pTHX_ HV* const stash, SV* const instance){
+    assert(stash);
+    assert(SvTYPE(stash) == SVt_PVHV);
+
+    if(SvROK(instance) && SvOBJECT(SvRV(instance))){
+        dMY_CXT;
+        HV* const instance_stash = SvSTASH(SvRV(instance));
+        GV* const instance_isa   = gv_fetchmeth_autoload(instance_stash, "isa", sizeof("isa")-1, 0);
+
+        /* the instance has no own isa method */
+        if(instance_isa == NULL || GvCV(instance_isa) == GvCV(MY_CXT.universal_isa)){
+            return stash == instance_stash
+                || mouse_lookup_isa(aTHX_ instance_stash, HvNAME_get(stash));
+        }
+        /* the instance has its own isa method */
+        else {
+            int retval;
+            dSP;
 
-        ENTER;
-        SAVETMPS;
+            ENTER;
+            SAVETMPS;
 
-        PUSHMARK(SP);
-        EXTEND(SP, 2);
-        PUSHs(instance);
-        mPUSHp(MG_klass_pv(mg), MG_klass_len(mg));
-        PUTBACK;
+            PUSHMARK(SP);
+            EXTEND(SP, 2);
+            PUSHs(instance);
+            mPUSHp(HvNAME_get(stash), HvNAMELEN_get(stash));
+            PUTBACK;
 
-        call_sv((SV*)instance_isa, G_SCALAR);
+            call_sv((SV*)instance_isa, G_SCALAR);
 
-        SPAGAIN;
+            SPAGAIN;
 
-        retval = SvTRUEx(POPs);
+            retval = SvTRUEx(POPs);
 
-        PUTBACK;
+            PUTBACK;
 
-        FREETMPS;
-        LEAVE;
+            FREETMPS;
+            LEAVE;
 
-        return retval;
+            return retval;
+        }
     }
+    return FALSE;
 }
 
+static int
+mouse_is_an_instance_of_universal(pTHX_ SV* const data, SV* const sv){
+    PERL_UNUSED_ARG(data);
+    return SvROK(sv) && SvOBJECT(SvRV(sv));
+}
 
-XS(XS_isa_check){
-    dVAR;
-    dXSARGS;
-    SV* sv;
+static MGVTBL mouse_util_type_constraints_vtbl; /* not used, only for identity */
 
-    assert(XSANY.any_ptr != NULL);
+CV*
+generate_isa_predicate_for(pTHX_ SV* const klass, const char* const predicate_name){
+    STRLEN klass_len;
+    const char* klass_pv = SvPV_const(klass, klass_len);
+    CV* xsub;
+    SV*   mg_obj;
+    void* mg_ptr;
 
-    if(items != 1){
-        if(items < 1){
-            croak("Not enough arguments for is-a predicate");
-        }
-        else{
-            croak("Too many arguments for is-a predicate");
-        }
+    klass_pv = mouse_canonicalize_package_name(klass_pv);
+
+    if(strNE(klass_pv, "UNIVERSAL")){
+        mg_obj = (SV*)gv_stashpvn(klass_pv, klass_len, GV_ADD);
+        mg_ptr = (void*)mouse_is_an_instance_of;
+
+    }
+    else{
+        mg_obj = NULL;
+        mg_ptr = (void*)mouse_is_an_instance_of_universal;
     }
 
-    sv = ST(0);
-    SvGETMAGIC(sv);
+    xsub = newXS(predicate_name, XS_Mouse_parameterized_check, __FILE__);
 
-    ST(0) = boolSV( SvROK(sv) && SvOBJECT(SvRV(sv)) && instance_isa(aTHX_ sv, (MAGIC*)XSANY.any_ptr) );
-    XSRETURN(1);
-}
+    CvXSUBANY(xsub).any_ptr = sv_magicext(
+        (SV*)xsub,
+        mg_obj,
+        PERL_MAGIC_ext,
+        &mouse_util_type_constraints_vtbl,
+        mg_ptr,
+        0   /* indicates static data */
+    );
 
+    if(!predicate_name){
+        sv_2mortal((SV*)xsub);
+    }
 
-XS(XS_isa_check_for_universal){
+    return xsub;
+}
+
+XS(XS_Mouse_parameterized_check) {
     dVAR;
     dXSARGS;
-    SV* sv;
-    PERL_UNUSED_VAR(cv);
+    MAGIC* const mg = (MAGIC*)XSANY.any_ptr;
+    typedef int (*check_fptr_t)(pTHX_ SV* const data, SV* const sv);
 
-    if(items != 1){
-        if(items < 1){
-            croak("Not enough arguments for is-a predicate");
-        }
-        else{
-            croak("Too many arguments for is-a predicate");
-        }
+    if(items < 1){
+        croak("Too few arguments for parameterized check functions");
     }
 
-    sv = ST(0);
-    SvGETMAGIC(sv);
-
-    ST(0) = boolSV( SvROK(sv) && SvOBJECT(SvRV(sv)) );
+    SvGETMAGIC( ST(0) );
+    ST(0) = boolSV( CALL_FPTR((check_fptr_t)mg->mg_ptr)(aTHX_ mg->mg_obj, ST(0)) );
     XSRETURN(1);
 }
 
index 0e2ae3b..b1b4f05 100644 (file)
@@ -312,40 +312,28 @@ OUTPUT:
     RETVAL
 
 void
-generate_isa_predicate_for(SV* klass, const char* predicate_name = NULL)
+generate_isa_predicate_for(SV* klass, SV* predicate_name = NULL)
 PPCODE:
 {
-    STRLEN klass_len;
-    const char* klass_pv;
-    HV* stash;
+    const char* name_pv = NULL;
     CV* xsub;
 
+    SvGETMAGIC(klass);
+
     if(!SvOK(klass)){
-        croak("You must define a class name for generate_for");
+        croak("You must define a class name");
     }
-    klass_pv = SvPV_const(klass, klass_len);
-    klass_pv = mouse_canonicalize_package_name(klass_pv);
-
-    if(strNE(klass_pv, "UNIVERSAL")){
-        static MGVTBL mouse_util_type_constraints_vtbl; /* not used, only for identity */
-
-        xsub = newXS(predicate_name, XS_isa_check, __FILE__);
-
-        stash = gv_stashpvn(klass_pv, klass_len, GV_ADD);
 
-        CvXSUBANY(xsub).any_ptr = sv_magicext(
-            (SV*)xsub,
-            (SV*)stash, /* mg_obj */
-            PERL_MAGIC_ext,
-            &mouse_util_type_constraints_vtbl,
-            klass_pv,   /* mg_ptr */
-            klass_len   /* mg_len */
-        );
-    }
-    else{
-        xsub = newXS(predicate_name, XS_isa_check_for_universal, __FILE__);
+    if(predicate_name){
+        SvGETMAGIC(predicate_name);
+        if(!SvOK(predicate_name)){
+            croak("You must define a predicate_name");
+        }
+        name_pv = SvPV_nolen_const(predicate_name);
     }
 
+    xsub = generate_isa_predicate_for(aTHX_ klass, name_pv);
+
     if(predicate_name == NULL){ /* anonymous predicate */
         XPUSHs( newRV_noinc((SV*)xsub) );
     }