Optimize is_class_loaded()
[gitmo/Class-MOP.git] / xs / MOP.xs
1 #include "mop.h"
2
3 SV *mop_method_metaclass;
4 SV *mop_associated_metaclass;
5 SV *mop_associated_attribute;
6 SV *mop_wrap;
7 SV *mop_methods;
8 SV *mop_name;
9 SV *mop_body;
10 SV *mop_package;
11 SV *mop_package_name;
12 SV *mop_package_cache_flag;
13 SV *mop_initialize;
14 SV *mop_isa;
15 SV *mop_can;
16 SV *mop_Class;
17 SV *mop_VERSION;
18 SV *mop_ISA;
19
20 /* equivalent to "blessed($x) && $x->isa($klass)" */
21 bool
22 mop_is_instance_of(pTHX_ SV* const sv, SV* const klass){
23     assert(sv);
24     assert(klass);
25
26     if(SvROK(sv) && SvOBJECT(SvRV(sv)) && SvOK(klass)){
27         bool ok;
28
29         ENTER;
30         SAVETMPS;
31
32         ok = SvTRUEx(mop_call1(aTHX_ sv, mop_isa, klass));
33
34         FREETMPS;
35         LEAVE;
36
37         return ok;
38     }
39
40     return FALSE;
41 }
42
43 static bool
44 find_method (const char *key, STRLEN keylen, SV *val, void *ud)
45 {
46     bool * const found_method = (bool *)ud;
47     PERL_UNUSED_ARG(key);
48     PERL_UNUSED_ARG(keylen);
49     PERL_UNUSED_ARG(val);
50     *found_method = TRUE;
51     return FALSE;
52 }
53
54
55 bool
56 mop_is_class_loaded(pTHX_ SV * const klass){
57     HV *stash;
58     HE* he;
59
60     if (!(SvPOKp(klass) && SvCUR(klass))) { /* XXX: SvPOK does not work with magical scalars */
61         return FALSE;
62     }
63
64     stash = gv_stashsv(klass, 0);
65     if (!stash) {
66         return FALSE;
67     }
68
69     if (( he = hv_fetch_ent (stash, mop_VERSION, FALSE, 0U) )) {
70         GV* const version_gv = (GV*)HeVAL(he);
71         if(isGV(version_gv) && GvSV(version_gv) && SvOK(GvSV(version_gv))){
72             return TRUE;
73         }
74     }
75
76     if (( he = hv_fetch_ent (stash, mop_ISA, FALSE, 0U) )) {
77         GV* const isa_gv = (GV*)HeVAL(he);
78         if(isGV(isa_gv) && GvAV(isa_gv) && av_len(GvAV(isa_gv)) != -1){
79             return TRUE;
80         }
81     }
82
83     {
84         bool found_method = FALSE;
85         mop_get_package_symbols(stash, TYPE_FILTER_CODE, find_method, &found_method);
86         return found_method;
87     }
88 }
89
90 MODULE = Class::MOP   PACKAGE = Class::MOP
91
92 PROTOTYPES: DISABLE
93
94 BOOT:
95     mop_method_metaclass     = MAKE_KEYSV(method_metaclass);
96     mop_associated_metaclass = MAKE_KEYSV(associated_metaclass);
97     mop_associated_attribute = MAKE_KEYSV(associated_attribute);
98     mop_wrap                 = MAKE_KEYSV(wrap);
99     mop_methods              = MAKE_KEYSV(methods);
100     mop_name                 = MAKE_KEYSV(name);
101     mop_body                 = MAKE_KEYSV(body);
102     mop_package              = MAKE_KEYSV(package);
103     mop_package_name         = MAKE_KEYSV(package_name);
104     mop_package_cache_flag   = MAKE_KEYSV(_package_cache_flag);
105     mop_initialize           = MAKE_KEYSV(initialize);
106     mop_Class                = MAKE_KEYSV(Class::MOP::Class);
107     mop_VERSION              = MAKE_KEYSV(VERSION);
108     mop_ISA                  = MAKE_KEYSV(ISA);
109     mop_isa                  = MAKE_KEYSV(isa);
110     mop_can                  = MAKE_KEYSV(can);
111
112     MOP_CALL_BOOT( Class__MOP__Package );
113     MOP_CALL_BOOT( Class__MOP__Class );
114     MOP_CALL_BOOT( Class__MOP__Attribute );
115     MOP_CALL_BOOT( Class__MOP__Instance );
116     MOP_CALL_BOOT( Class__MOP__Method );
117     MOP_CALL_BOOT( Class__MOP__Method__Accessor );
118     MOP_CALL_BOOT( Class__MOP__Method__Constructor );
119
120 # use prototype here to be compatible with get_code_info from Sub::Identify
121 void
122 get_code_info(coderef)
123     SV *coderef
124     PROTOTYPE: $
125     PREINIT:
126         char *pkg  = NULL;
127         char *name = NULL;
128     PPCODE:
129         SvGETMAGIC(coderef);
130         if (mop_get_code_info(coderef, &pkg, &name)) {
131             EXTEND(SP, 2);
132             mPUSHs(newSVpv(pkg, 0));
133             mPUSHs(newSVpv(name, 0));
134         }
135
136
137 bool
138 is_class_loaded(SV* klass = &PL_sv_undef)
139 INIT:
140     SvGETMAGIC(klass);
141
142
143
144 #bool
145 #is_instance_of(SV* sv, SV* klass)
146 #INIT:
147 #    SvGETMAGIC(sv);
148 #    SvGETMAGIC(klass);
149 #