Add mouse_get_xa()
gfx [Sun, 15 Nov 2009 07:13:51 +0000 (16:13 +0900)]
mouse.h
xs-src/Mouse.xs
xs-src/MouseAccessor.xs
xs-src/MouseAttribute.xs
xs-src/MouseUtil.xs

diff --git a/mouse.h b/mouse.h
index fdca9bc..a359b14 100644 (file)
--- a/mouse.h
+++ b/mouse.h
@@ -70,15 +70,20 @@ bool mouse_is_class_loaded(pTHX_ SV*);
 #define IsHashRef(sv)  (SvROK(sv) && !SvOBJECT(SvRV(sv)) && SvTYPE(SvRV(sv)) == SVt_PVHV)
 #define IsCodeRef(sv)  (SvROK(sv) && !SvOBJECT(SvRV(sv)) && SvTYPE(SvRV(sv)) == SVt_PVCV)
 
-#define mcall0(invocant, m)        mouse_call0(aTHX_ (invocant), (m))
-#define mcall1(invocant, m, arg1)  mouse_call1(aTHX_ (invocant), (m), (arg1))
-#define mcall0s(invocant, m)       mcall0((invocant), sv_2mortal(newSVpvs_share(m)))
-#define mcall1s(invocant, m, arg1) mcall1((invocant), sv_2mortal(newSVpvs_share(m)), (arg1))
+#define mcall0(invocant, m)          mouse_call0(aTHX_ (invocant), (m))
+#define mcall1(invocant, m, arg1)    mouse_call1(aTHX_ (invocant), (m), (arg1))
+#define predicate_call(invocant, m)  mouse_predicate_call(aTHX_ (invocant), (m))
+
+#define mcall0s(invocant, m)          mcall0((invocant), sv_2mortal(newSVpvs_share(m)))
+#define mcall1s(invocant, m, arg1)    mcall1((invocant), sv_2mortal(newSVpvs_share(m)), (arg1))
+#define predicate_calls(invocant, m)  predicate_call((invocant), sv_2mortal(newSVpvs_share(m)))
+
 
 #define get_metaclass(name) mouse_get_metaclass(aTHX_ name)
 
 SV* mouse_call0(pTHX_ SV *const self, SV *const method);
 SV* mouse_call1(pTHX_ SV *const self, SV *const method, SV* const arg1);
+int mouse_predicate_call(pTHX_ SV* const self, SV* const method);
 
 SV* mouse_get_metaclass(pTHX_ SV* metaclass_name);
 
@@ -182,5 +187,53 @@ int mouse_is_an_instance_of(pTHX_ HV* const stash, SV* const instance);
 
 XS(XS_Mouse_constraint_check);
 
+/* Mouse XS Attribute object */
+
+AV* mouse_get_xa(pTHX_ SV* const attr);
+
+enum mouse_xa_ix_t{
+    MOUSE_XA_SLOT,      /* for constructors, sync to mg_obj */
+    MOUSE_XA_FLAGS,     /* for constructors, sync to mg_private */
+    MOUSE_XA_ATTRIBUTE,
+    MOUSE_XA_TC,
+    MOUSE_XA_TC_CODE,
+
+    MOUSE_XA_last
+};
+
+#define MOUSE_xa_slot(m)      MOUSE_av_at(m, MOUSE_XA_SLOT)
+#define MOUSE_xa_flags(m)     MOUSE_av_at(m, MOUSE_XA_FLAGS)
+#define MOUSE_xa_attribute(m) MOUSE_av_at(m, MOUSE_XA_ATTRIBUTE)
+#define MOUSE_xa_tc(m)        MOUSE_av_at(m, MOUSE_XA_TC)
+#define MOUSE_xa_tc_code(m)   MOUSE_av_at(m, MOUSE_XA_TC_CODE)
+
+
+enum mouse_xa_flags_t{
+    MOUSEf_ATTR_HAS_TC          = 0x0001,
+    MOUSEf_ATTR_HAS_DEFAULT     = 0x0002,
+    MOUSEf_ATTR_HAS_BUILDER     = 0x0004,
+    MOUSEf_ATTR_HAS_INITIALIZER = 0x0008,
+    MOUSEf_ATTR_HAS_TRIGGER     = 0x0010,
+
+    MOUSEf_ATTR_IS_LAZY         = 0x0020,
+    MOUSEf_ATTR_IS_WEAK_REF     = 0x0040,
+    MOUSEf_ATTR_IS_REQUIRED     = 0x0080,
+
+    MOUSEf_ATTR_SHOULD_COERCE   = 0x0100,
+
+    MOUSEf_ATTR_SHOULD_AUTO_DEREF
+                                = 0x0200,
+    MOUSEf_TC_IS_ARRAYREF       = 0x0400,
+    MOUSEf_TC_IS_HASHREF        = 0x0800,
+
+    MOUSEf_OTHER1               = 0x1000,
+    MOUSEf_OTHER2               = 0x2000,
+    MOUSEf_OTHER3               = 0x4000,
+    MOUSEf_OTHER4               = 0x8000,
+
+    MOUSEf_MOUSE_MASK           = 0xFFFF /* not used */
+};
+
+
 #endif /* !MOUSE_H */
 
index ee14df3..bec3c7d 100644 (file)
@@ -72,10 +72,8 @@ mouse_class_has_custom_buildargs(pTHX_ HV* const stash) {
     XS(XS_Mouse__Object_BUILDARGS); /* prototype */
 
     GV* const buildargs = gv_fetchmeth_autoload(stash, "BUILDARGS", sizeof("BUILDARGS")-1, 0);
-    CV* const cv        = GvCV(buildargs);
 
-    assert(cv);
-    return CvXSUB(cv) == XS_Mouse__Object_BUILDARGS;
+    return buildargs && CvXSUB(GvCV(buildargs)) == XS_Mouse__Object_BUILDARGS;
 }
 
 static void
@@ -192,14 +190,8 @@ mouse_get_xc(pTHX_ SV* const metaclass) {
     return xc;
 }
 
-AV*
-mouse_get_all_attributes(pTHX_ SV* const metaclass) {
-    AV* const xc = mouse_get_xc(aTHX_ metaclass);
-    return MOUSE_xc_attrall(xc);
-}
-
 HV*
-mouse_build_args(aTHX_ SV* metaclass, SV* const klass, I32 const start, I32 const items, I32 const ax) {
+mouse_build_args(pTHX_ SV* metaclass, SV* const klass, I32 const start, I32 const items, I32 const ax) {
     HV* args;
     if((items - start) == 1){
         SV* const args_ref = ST(start);
@@ -234,9 +226,10 @@ mouse_class_initialize_object(pTHX_ SV* const meta, SV* const object, HV* const
     AV* const attrs = MOUSE_xc_attrall(xc);
     I32 const len   = AvFILLp(attrs) + 1;
     I32 i;
-    AV* const triggers_queue = (invoke_triggers ? newAV_mortal() : NULL);
+    AV* const triggers_queue = (ignore_triggers ? NULL : newAV_mortal());
+
     for(i = 0; i < len; i++){
-        AV* const = mouse_get_xa(aTHX_ AvARRAY(attrs)[i]);
+        AV* const xa = mouse_get_xa(aTHX_ AvARRAY(attrs)[i]);
     }
 }
 
@@ -363,7 +356,8 @@ void
 get_all_attributes(SV* self)
 PPCODE:
 {
-    AV* const all_attrs = mouse_get_all_attributes(aTHX_ self);
+    AV* const xc        = mouse_get_xc(aTHX_ self);
+    AV* const all_attrs =  MOUSE_xc_attrall(xc);
     I32 const len       = AvFILLp(all_attrs) + 1;
     I32 i;
 
index aa87df3..86b0b9f 100644 (file)
@@ -6,49 +6,9 @@
         }                                                             \
     } STMT_END
 
-/* Mouse XS Attribute object */
-enum mouse_xa_ix_t{
-    MOUSE_XA_SLOT,      /* for constructors, sync to mg_obj */
-    MOUSE_XA_FLAGS,     /* for constructors, sync to mg_private */
-    MOUSE_XA_ATTRIBUTE,
-    MOUSE_XA_TC,
-    MOUSE_XA_TC_CODE,
-
-    MOUSE_XA_last
-};
-
-#define MOUSE_xa_attribute(m) MOUSE_av_at(m, MOUSE_XA_ATTRIBUTE)
-#define MOUSE_xa_tc(m)        MOUSE_av_at(m, MOUSE_XA_TC)
-#define MOUSE_xa_tc_code(m)   MOUSE_av_at(m, MOUSE_XA_TC_CODE)
 
 #define MOUSE_mg_attribute(mg) MOUSE_xa_attribute(MOUSE_mg_xa(mg))
 
-enum mouse_xa_flags_t{
-    MOUSEf_ATTR_HAS_TC          = 0x0001,
-    MOUSEf_ATTR_HAS_DEFAULT     = 0x0002,
-    MOUSEf_ATTR_HAS_BUILDER     = 0x0004,
-    MOUSEf_ATTR_HAS_INITIALIZER = 0x0008,
-    MOUSEf_ATTR_HAS_TRIGGER     = 0x0010,
-
-    MOUSEf_ATTR_IS_LAZY         = 0x0020,
-    MOUSEf_ATTR_IS_WEAK_REF     = 0x0040,
-    MOUSEf_ATTR_IS_REQUIRED     = 0x0080,
-
-    MOUSEf_ATTR_SHOULD_COERCE   = 0x0100,
-
-    MOUSEf_ATTR_SHOULD_AUTO_DEREF
-                                = 0x0200,
-    MOUSEf_TC_IS_ARRAYREF       = 0x0400,
-    MOUSEf_TC_IS_HASHREF        = 0x0800,
-
-    MOUSEf_OTHER1               = 0x1000,
-    MOUSEf_OTHER2               = 0x2000,
-    MOUSEf_OTHER3               = 0x4000,
-    MOUSEf_OTHER4               = 0x8000,
-
-    MOUSEf_MOUSE_MASK           = 0xFFFF /* not used */
-};
-
 static MGVTBL mouse_accessor_vtbl; /* MAGIC identity */
 
 
@@ -68,89 +28,22 @@ mouse_accessor_get_self(pTHX_ I32 const ax, I32 const items, CV* const cv) {
 
 CV*
 mouse_instantiate_xs_accessor(pTHX_ SV* const attr, XSUBADDR_t const accessor_impl){
-    SV* const slot = mcall0(attr,  mouse_name);
-    AV* const xa = newAV();
+    AV* const xa = mouse_get_xa(aTHX_ attr);
     CV* xsub;
     MAGIC* mg;
-    U16 flags = 0;
-
-    sv_2mortal((SV*)xa);
 
     xsub = newXS(NULL, accessor_impl, __FILE__);
     sv_2mortal((SV*)xsub);
 
-    mg = sv_magicext((SV*)xsub, slot, PERL_MAGIC_ext, &mouse_accessor_vtbl, (char*)xa, HEf_SVKEY);
+    mg = sv_magicext((SV*)xsub, MOUSE_xa_slot(xa), PERL_MAGIC_ext, &mouse_accessor_vtbl, (char*)xa, HEf_SVKEY);
+
+    MOUSE_mg_flags(mg) = (U16)SvUV(MOUSE_xa_flags(xa));
 
     /* NOTE:
      * although we use MAGIC for gc, we also store mg to CvXSUBANY for efficiency (gfx)
      */
     CvXSUBANY(xsub).any_ptr = (void*)mg;
 
-    av_extend(xa, MOUSE_XA_last - 1);
-
-    av_store(xa, MOUSE_XA_ATTRIBUTE, newSVsv(attr));
-
-    /* prepare attribute status */
-    /* XXX: making it lazy is a good way? */
-
-    if(SvTRUEx(mcall0s(attr, "has_type_constraint"))){
-        SV* tc;
-        flags |= MOUSEf_ATTR_HAS_TC;
-
-        ENTER;
-        SAVETMPS;
-
-        tc = mcall0s(attr, "type_constraint");
-        av_store(xa, MOUSE_XA_TC, newSVsv(tc));
-
-        if(SvTRUEx(mcall0s(attr, "should_auto_deref"))){
-            flags |= MOUSEf_ATTR_SHOULD_AUTO_DEREF;
-            if( SvTRUEx(mcall1s(tc, "is_a_type_of", newSVpvs_flags("ArrayRef", SVs_TEMP))) ){
-                flags |= MOUSEf_TC_IS_ARRAYREF;
-            }
-            else if( SvTRUEx(mcall1s(tc, "is_a_type_of", newSVpvs_flags("HashRef", SVs_TEMP))) ){
-                flags |= MOUSEf_TC_IS_HASHREF;
-            }
-            else{
-                mouse_throw_error(attr, tc,
-                    "Can not auto de-reference the type constraint '%"SVf"'",
-                        mcall0(tc, mouse_name));
-            }
-        }
-
-        if(SvTRUEx(mcall0s(attr, "should_coerce"))){
-            flags |= MOUSEf_ATTR_SHOULD_COERCE;
-        }
-
-        FREETMPS;
-        LEAVE;
-    }
-
-    if(SvTRUEx(mcall0s(attr, "has_trigger"))){
-        flags |= MOUSEf_ATTR_HAS_TRIGGER;
-    }
-
-    if(SvTRUEx(mcall0s(attr, "is_lazy"))){
-        flags |= MOUSEf_ATTR_IS_LAZY;
-
-        if(SvTRUEx(mcall0s(attr, "has_builder"))){
-            flags |= MOUSEf_ATTR_HAS_BUILDER;
-        }
-        else if(SvTRUEx(mcall0s(attr, "has_default"))){
-            flags |= MOUSEf_ATTR_HAS_DEFAULT;
-        }
-    }
-
-    if(SvTRUEx(mcall0s(attr, "is_weak_ref"))){
-        flags |= MOUSEf_ATTR_IS_WEAK_REF;
-    }
-
-    if(SvTRUEx(mcall0s(attr, "is_required"))){
-        flags |= MOUSEf_ATTR_IS_REQUIRED;
-    }
-
-    MOUSE_mg_flags(mg) = flags;
-
     return xsub;
 }
 
index f4d4ea4..9bda4c6 100644 (file)
@@ -1,6 +1,110 @@
-#define  NEED_newSVpvn_flags_GLOBAL
 #include "mouse.h"
 
+
+AV*
+mouse_get_xa(pTHX_ SV* const attr) {
+    static MGVTBL mouse_xa_vtbl; /* identity */
+
+    AV* xa;
+    MAGIC* mg;
+
+    if(!IsObject(attr)){
+        croak("Not a Mouse meta attribute");
+    }
+
+    mg = mouse_mg_find(aTHX_ SvRV(attr), &mouse_xa_vtbl, 0x00);
+    if(!mg){
+        SV* slot;
+        STRLEN len;
+        const char* pv;
+        U16 flags = 0x00;
+
+        ENTER;
+        SAVETMPS;
+
+        xa    = newAV();
+
+        mg = sv_magicext(SvRV(attr), (SV*)xa, PERL_MAGIC_ext, &mouse_xa_vtbl,NULL, 0);
+        SvREFCNT_dec(xa); /* refcnt++ in sv_magicext */
+
+        av_extend(xa, MOUSE_XA_last - 1);
+
+        slot = mcall0(attr, mouse_name);
+        pv = SvPV_const(slot, len);
+        av_store(xa, MOUSE_XA_SLOT, newSVpvn_share(pv, len, 0U));
+
+        av_store(xa, MOUSE_XA_ATTRIBUTE, newSVsv(attr));
+
+        if(predicate_calls(attr, "has_type_constraint")){
+            SV* tc;
+            flags |= MOUSEf_ATTR_HAS_TC;
+
+            tc = mcall0s(attr, "type_constraint");
+            av_store(xa, MOUSE_XA_TC, newSVsv(tc));
+
+            if(predicate_calls(attr, "should_auto_deref")){
+                SV* const is_a_type_of = sv_2mortal(newSVpvs_share("is_a_type_of"));
+
+                flags |= MOUSEf_ATTR_SHOULD_AUTO_DEREF;
+                if( SvTRUEx(mcall1(tc, is_a_type_of, newSVpvs_flags("ArrayRef", SVs_TEMP))) ){
+                    flags |= MOUSEf_TC_IS_ARRAYREF;
+                }
+                else if( SvTRUEx(mcall1(tc, is_a_type_of, newSVpvs_flags("HashRef", SVs_TEMP))) ){
+                    flags |= MOUSEf_TC_IS_HASHREF;
+                }
+                else{
+                    mouse_throw_error(attr, tc,
+                        "Can not auto de-reference the type constraint '%"SVf"'",
+                            mcall0(tc, mouse_name));
+                }
+            }
+
+            if(predicate_calls(attr, "should_coerce")){
+                flags |= MOUSEf_ATTR_SHOULD_COERCE;
+            }
+
+        }
+
+        if(predicate_calls(attr, "has_trigger")){
+            flags |= MOUSEf_ATTR_HAS_TRIGGER;
+        }
+
+        if(predicate_calls(attr, "is_lazy")){
+            flags |= MOUSEf_ATTR_IS_LAZY;
+
+            if(predicate_calls(attr, "has_builder")){
+                flags |= MOUSEf_ATTR_HAS_BUILDER;
+            }
+            else if(predicate_calls(attr, "has_default")){
+                flags |= MOUSEf_ATTR_HAS_DEFAULT;
+            }
+        }
+
+        if(predicate_calls(attr, "is_weak_ref")){
+            flags |= MOUSEf_ATTR_IS_WEAK_REF;
+        }
+
+        if(predicate_calls(attr, "is_required")){
+            flags |= MOUSEf_ATTR_IS_REQUIRED;
+        }
+
+        av_store(xa, MOUSE_XA_FLAGS, newSVuv(flags));
+        MOUSE_mg_flags(mg) = flags;
+
+        FREETMPS;
+        LEAVE;
+    }
+    else{
+        xa    = (AV*)MOUSE_mg_obj(mg);
+
+        assert(xa);
+        assert(SvTYPE(xa) == SVt_PVAV);
+    }
+
+    return xa;
+}
+
+
 MODULE = Mouse::Meta::Attribute  PACKAGE = Mouse::Meta::Attribute
 
 PROTOTYPES: DISABLE
index c1d4d91..f99c6f6 100644 (file)
@@ -156,9 +156,8 @@ mouse_is_class_loaded(pTHX_ SV * const klass){
 }
 
 
-SV *
-mouse_call0 (pTHX_ SV *const self, SV *const method)
-{
+SV*
+mouse_call0 (pTHX_ SV* const self, SV* const method) {
     dSP;
     SV *ret;
 
@@ -175,9 +174,8 @@ mouse_call0 (pTHX_ SV *const self, SV *const method)
     return ret;
 }
 
-SV *
-mouse_call1 (pTHX_ SV *const self, SV *const method, SV* const arg1)
-{
+SV*
+mouse_call1 (pTHX_ SV* const self, SV* const method, SV* const arg1) {
     dSP;
     SV *ret;
 
@@ -196,6 +194,12 @@ mouse_call1 (pTHX_ SV *const self, SV *const method, SV* const arg1)
     return ret;
 }
 
+int
+mouse_predicate_call(pTHX_ SV* const self, SV* const method) {
+    SV* const value = mcall0(self, method);
+    return SvTRUE(value);
+}
+
 SV*
 mouse_get_metaclass(pTHX_ SV* metaclass_name){
     CV* const get_metaclass  = get_cvs("Mouse::Util::get_metaclass_by_name", TRUE);