Prefix all exported symbols with "mop_"
[gitmo/Class-MOP.git] / xs / Class.xs
CommitLineData
d846ade3 1#include "mop.h"
2
3NEEDS_KEY(name);
4NEEDS_KEY(body);
5NEEDS_KEY(methods);
6NEEDS_KEY(package);
7NEEDS_KEY(package_name);
8NEEDS_KEY(package_cache_flag);
9
10static void
11mop_update_method_map(pTHX_ SV *const self, SV *const class_name, HV *const stash, HV *const map)
12{
13 const char *const class_name_pv = HvNAME(stash); /* must be HvNAME(stash), not SvPV_nolen_const(class_name) */
14 SV *method_metaclass_name;
15 char *method_name;
16 I32 method_name_len;
17 SV *coderef;
18 HV *symbols;
19 dSP;
20
e1f52a8a 21 symbols = mop_get_all_package_symbols(stash, TYPE_FILTER_CODE);
d846ade3 22
23 (void)hv_iterinit(symbols);
24 while ( (coderef = hv_iternextsv(symbols, &method_name, &method_name_len)) ) {
25 CV *cv = (CV *)SvRV(coderef);
26 char *cvpkg_name;
27 char *cv_name;
28 SV *method_slot;
29 SV *method_object;
30
e1f52a8a 31 if (!mop_get_code_info(coderef, &cvpkg_name, &cv_name)) {
d846ade3 32 continue;
33 }
34
35 /* this checks to see that the subroutine is actually from our package */
36 if ( !(strEQ(cvpkg_name, "constant") && strEQ(cv_name, "__ANON__")) ) {
37 if ( strNE(cvpkg_name, class_name_pv) ) {
38 continue;
39 }
40 }
41
42 method_slot = *hv_fetch(map, method_name, method_name_len, TRUE);
43 if ( SvOK(method_slot) ) {
44 SV *const body = mop_call0(aTHX_ method_slot, key_body); /* $method_object->body() */
45 if ( SvROK(body) && ((CV *) SvRV(body)) == cv ) {
46 continue;
47 }
48 }
49
e1f52a8a 50 method_metaclass_name = mop_call0(aTHX_ self, mop_method_metaclass); /* $self->method_metaclass() */
d846ade3 51
52 /*
53 $method_object = $method_metaclass->wrap(
54 $cv,
55 associated_metaclass => $self,
56 package_name => $class_name,
57 name => $method_name
58 );
59 */
60 ENTER;
61 SAVETMPS;
62
63 PUSHMARK(SP);
64 EXTEND(SP, 8);
65 PUSHs(method_metaclass_name); /* invocant */
66 mPUSHs(newRV_inc((SV *)cv));
e1f52a8a 67 PUSHs(mop_associated_metaclass);
d846ade3 68 PUSHs(self);
69 PUSHs(key_package_name);
70 PUSHs(class_name);
71 PUSHs(key_name);
72 mPUSHs(newSVpv(method_name, method_name_len));
73 PUTBACK;
74
e1f52a8a 75 call_sv(mop_wrap, G_SCALAR | G_METHOD);
d846ade3 76 SPAGAIN;
77 method_object = POPs;
78 PUTBACK;
79 /* $map->{$method_name} = $method_object */
80 sv_setsv(method_slot, method_object);
81
82 FREETMPS;
83 LEAVE;
84 }
85}
86
87MODULE = Class::MOP::Class PACKAGE = Class::MOP::Class
88
89PROTOTYPES: DISABLE
90
91void
92get_method_map(self)
93 SV *self
94 PREINIT:
95 HV *const obj = (HV *)SvRV(self);
96 SV *const class_name = HeVAL( hv_fetch_ent(obj, key_package, 0, hash_package) );
97 HV *const stash = gv_stashsv(class_name, 0);
98 UV const current = mop_check_package_cache_flag(aTHX_ stash);
99 SV *const cache_flag = HeVAL( hv_fetch_ent(obj, key_package_cache_flag, TRUE, hash_package_cache_flag));
100 SV *const map_ref = HeVAL( hv_fetch_ent(obj, key_methods, TRUE, hash_methods));
101 PPCODE:
102 /* in $self->{methods} does not yet exist (or got deleted) */
103 if ( !SvROK(map_ref) || SvTYPE(SvRV(map_ref)) != SVt_PVHV ) {
104 SV *new_map_ref = newRV_noinc((SV *)newHV());
105 sv_2mortal(new_map_ref);
106 sv_setsv(map_ref, new_map_ref);
107 }
108
109 if ( !SvOK(cache_flag) || SvUV(cache_flag) != current ) {
110 mop_update_method_map(aTHX_ self, class_name, stash, (HV *)SvRV(map_ref));
111 sv_setuv(cache_flag, mop_check_package_cache_flag(aTHX_ stash)); /* update_cache_flag() */
112 }
113
114 XPUSHs(map_ref);