what is this even for
[gitmo/Moose.git] / xs / HasMethods.xs
1 #include "mop.h"
2
3 SV *mop_method_metaclass;
4 SV *mop_associated_metaclass;
5 SV *mop_wrap;
6
7 static void
8 mop_update_method_map(pTHX_ HV *const stash, HV *const map)
9 {
10     char *method_name;
11     I32   method_name_len;
12     SV   *method;
13     HV   *symbols;
14
15     symbols = mop_get_all_package_symbols(stash, TYPE_FILTER_CODE);
16     sv_2mortal((SV*)symbols);
17
18     (void)hv_iterinit(map);
19     while ((method = hv_iternextsv(map, &method_name, &method_name_len))) {
20         SV *body;
21         SV *stash_slot;
22
23         if (!SvROK(method)) {
24             continue;
25         }
26
27         if (sv_isobject(method)) {
28             /* $method_object->body() */
29             body = mop_call0(aTHX_ method, KEY_FOR(body));
30         }
31         else {
32             body = method;
33         }
34
35         stash_slot = *hv_fetch(symbols, method_name, method_name_len, TRUE);
36         if (SvROK(stash_slot) && ((CV*)SvRV(body)) == ((CV*)SvRV(stash_slot))) {
37             continue;
38         }
39
40         /* delete $map->{$method_name} */
41         (void)hv_delete(map, method_name, method_name_len, G_DISCARD);
42     }
43 }
44
45 MODULE = Class::MOP::Mixin::HasMethods   PACKAGE = Class::MOP::Mixin::HasMethods
46
47 PROTOTYPES: DISABLE
48
49 void
50 _method_map(self)
51     SV *self
52     PREINIT:
53         HV *const obj        = (HV *)SvRV(self);
54         SV *const class_name = HeVAL( hv_fetch_ent(obj, KEY_FOR(package), 0, HASH_FOR(package)) );
55         HV *const stash      = gv_stashsv(class_name, 0);
56         UV current;
57         SV *cache_flag;
58         SV *map_ref;
59     PPCODE:
60         if (!stash) {
61              mXPUSHs(newRV_noinc((SV *)newHV()));
62              return;
63         }
64
65         current    = mop_check_package_cache_flag(aTHX_ stash);
66         cache_flag = HeVAL( hv_fetch_ent(obj, KEY_FOR(package_cache_flag), TRUE, HASH_FOR(package_cache_flag)));
67         map_ref    = HeVAL( hv_fetch_ent(obj, KEY_FOR(methods), TRUE, HASH_FOR(methods)));
68
69         /* $self->{methods} does not yet exist (or got deleted) */
70         if ( !SvROK(map_ref) || SvTYPE(SvRV(map_ref)) != SVt_PVHV ) {
71             SV *new_map_ref = newRV_noinc((SV *)newHV());
72             sv_2mortal(new_map_ref);
73             sv_setsv(map_ref, new_map_ref);
74         }
75
76         if ( !SvOK(cache_flag) || SvUV(cache_flag) != current ) {
77             mop_update_method_map(aTHX_ stash, (HV *)SvRV(map_ref));
78             sv_setuv(cache_flag, mop_check_package_cache_flag(aTHX_ stash)); /* update_cache_flag() */
79         }
80
81         XPUSHs(map_ref);
82
83 BOOT:
84     mop_method_metaclass     = newSVpvs("method_metaclass");
85     mop_associated_metaclass = newSVpvs("associated_metaclass");
86     mop_wrap                 = newSVpvs("wrap");
87     INSTALL_SIMPLE_READER(Mixin::HasMethods, method_metaclass);
88     INSTALL_SIMPLE_READER(Mixin::HasMethods, wrapped_method_metaclass);