_get_code_ref() and get_linear_isa() in XS
[gitmo/Mouse.git] / xs-src / mouse_util.xs
CommitLineData
df6dd016 1#include "mouse.h"
2
cccb83de 3#define ISA_CACHE "::LINEALIZED_ISA_CACHE::"
4
5#ifndef no_mro_get_linear_isa
6AV*
7mouse_mro_get_linear_isa(pTHX_ HV* const stash){
8 GV* const cachegv = *(GV**)hv_fetchs(stash, ISA_CACHE, TRUE);
9 AV* isa;
10 SV* gen;
11 CV* get_linear_isa;
12
13 if(!isGV(cachegv))
14 gv_init(cachegv, stash, ISA_CACHE, sizeof(ISA_CACHE)-1, TRUE);
15
16 isa = GvAVn(cachegv);
17 gen = GvSVn(cachegv);
18
19
20 if(SvIOK(gen) && SvIVX(gen) == (IV)mro_get_pkg_gen(stash)){
21 return isa; /* returns the cache if available */
22 }
23 else{
24 SvREADONLY_off(isa);
25 av_clear(isa);
26 }
27
28 get_linear_isa = get_cv("Mouse::Util::get_linear_isa", TRUE);
29
30 {
31 SV* avref;
32 dSP;
33
34 ENTER;
35 SAVETMPS;
36
37 PUSHMARK(SP);
38 mXPUSHp(HvNAME_get(stash), HvNAMELEN_get(stash));
39 PUTBACK;
40
41 call_sv((SV*)get_linear_isa, G_SCALAR);
42
43 SPAGAIN;
44 avref = POPs;
45 PUTBACK;
46
47 if(SvROK(avref) && SvTYPE(SvRV(avref)) == SVt_PVAV){
48 AV* const av = (AV*)SvRV(avref);
49 I32 const len = AvFILLp(av) + 1;
50 I32 i;
51
52 for(i = 0; i < len; i++){
53 HV* const stash = gv_stashsv(AvARRAY(av)[i], FALSE);
54 if(stash)
55 av_push(isa, newSVpv(HvNAME(stash), 0));
56 }
57 SvREADONLY_on(isa);
58 }
59 else{
60 Perl_croak(aTHX_ "Mouse:Util::get_linear_isa() didn't return an ARRAY reference");
61 }
62
63 FREETMPS;
64 LEAVE;
65 }
66
67 sv_setiv(gen, (IV)mro_get_pkg_gen(stash));
68 return GvAV(cachegv);
69}
70#endif /* !no_mor_get_linear_isa */
71
72
df6dd016 73/* equivalent to "blessed($x) && $x->isa($klass)" */
74bool
75mouse_is_instance_of(pTHX_ SV* const sv, SV* const klass){
76 assert(sv);
77 assert(klass);
78
79 if(IsObject(sv) && SvOK(klass)){
80 bool ok;
81
82 ENTER;
83 SAVETMPS;
84
85 ok = SvTRUEx(mcall1s(sv, "isa", klass));
86
87 FREETMPS;
88 LEAVE;
89
90 return ok;
91 }
92
93 return FALSE;
94}
95
96
97bool
98mouse_is_class_loaded(pTHX_ SV * const klass){
99 HV *stash;
100 GV** gvp;
101 HE* he;
102
103 if (!(SvPOKp(klass) && SvCUR(klass))) { /* XXX: SvPOK does not work with magical scalars */
104 return FALSE;
105 }
106
107 stash = gv_stashsv(klass, FALSE);
108 if (!stash) {
109 return FALSE;
110 }
111
112 if (( gvp = (GV**)hv_fetchs(stash, "VERSION", FALSE) )) {
113 if(isGV(*gvp) && GvSV(*gvp) && SvOK(GvSV(*gvp))){
114 return TRUE;
115 }
116 }
117
118 if (( gvp = (GV**)hv_fetchs(stash, "ISA", FALSE) )) {
119 if(isGV(*gvp) && GvAV(*gvp) && av_len(GvAV(*gvp)) != -1){
120 return TRUE;
121 }
122 }
123
124 hv_iterinit(stash);
125 while(( he = hv_iternext(stash) )){
126 GV* const gv = (GV*)HeVAL(he);
127
128 if(isGV(gv)){
129 if(GvCVu(gv)){
130 return TRUE;
131 }
132 }
133 else if(SvOK(gv)){
134 return TRUE;
135 }
136 }
137 return FALSE;
138}
139
140
141SV *
142mouse_call0 (pTHX_ SV *const self, SV *const method)
143{
144 dSP;
145 SV *ret;
146
147 PUSHMARK(SP);
148 XPUSHs(self);
149 PUTBACK;
150
151 call_sv(method, G_SCALAR | G_METHOD);
152
153 SPAGAIN;
154 ret = POPs;
155 PUTBACK;
156
157 return ret;
158}
159
160SV *
161mouse_call1 (pTHX_ SV *const self, SV *const method, SV* const arg1)
162{
163 dSP;
164 SV *ret;
165
166 PUSHMARK(SP);
167 EXTEND(SP, 2);
168 PUSHs(self);
169 PUSHs(arg1);
170 PUTBACK;
171
172 call_sv(method, G_SCALAR | G_METHOD);
173
174 SPAGAIN;
175 ret = POPs;
176 PUTBACK;
177
178 return ret;
179}
180
43165725 181MAGIC*
182mouse_mg_find(pTHX_ SV* const sv, const MGVTBL* const vtbl, I32 const flags){
183 MAGIC* mg;
184
185 assert(sv != NULL);
186 for(mg = SvMAGIC(sv); mg; mg = mg->mg_moremagic){
187 if(mg->mg_virtual == vtbl){
188 return mg;
189 }
190 }
191
192 if(flags & MOUSEf_DIE_ON_FAIL){
193 croak("mouse_mg_find: no MAGIC found for %"SVf, sv_2mortal(newRV_inc(sv)));
194 }
195 return NULL;
196}