Add *.bs to MANIFEST.SKIP
[gitmo/Mouse.git] / mro_compat.h
1 /*
2 ----------------------------------------------------------------------------
3
4     Devel::MRO/mro_compat.h - Provides mro functions for XS modules
5
6     Copyright (c) 2008-2009, Goro Fuji (gfx) <gfuji(at)cpan.org>.
7
8     This program is free software; you can redistribute it and/or
9     modify it under the same terms as Perl itself.
10
11 ----------------------------------------------------------------------------
12
13 Usage:
14         #include "mro_compat.h"
15
16 Functions:
17         AV*  mro_get_linear_isa(HV* stash)
18         UV   mro_get_pkg_gen(HV* stash)
19         void mro_method_changed_in(HV* stash)
20
21
22     See "perldoc Devel::MRO" for details.
23  */
24
25
26 #ifdef mro_get_linear_isa /* >= 5.10.0 */
27
28 /* NOTE:
29         Because ActivePerl 5.10.0 does not provide Perl_mro_meta_init(), 
30         which is used in HvMROMETA() macro, this mro_get_pkg_gen() refers
31         to xhv_mro_meta directly.
32 */
33 /* compatible with &mro::get_pkg_gen() */
34 #ifndef mro_get_pkg_gen
35 #define mro_get_pkg_gen(stash) (HvAUX(stash) ? HvAUX(stash)->xhv_mro_meta->pkg_gen : (U32)0)
36 #endif
37
38 #ifndef mro_get_cache_gen
39 #define mro_get_cache_gen(stash) (HvAUX(stash) ? HvAUX(stash)->xhv_mro_meta->cache_gen : (U32)0)
40 #endif
41
42 #ifndef mro_get_gen
43 #define mro_get_gen(stash) (HvAUX(stash) ? (HvAUX(stash)->xhv_mro_meta->pkg_gen + HvAUX(stash)->xhv_mro_meta->cache_gen) : (U32)0)
44 #endif
45
46 #else /* < 5.10.0  */
47 #define mro_get_linear_isa(stash) my_mro_get_linear_isa(aTHX_ stash)
48
49 #define mro_method_changed_in(stash) ((void)stash, (void)PL_sub_generation++)
50 #define mro_get_pkg_gen(stash)   ((void)stash, PL_sub_generation)
51 #define mro_get_cache_gen(stash) ((void)stash, (U32)0)
52 #define mro_get_gen(stash)       ((void)stash, PL_sub_generation)
53
54
55 #if defined(NEED_mro_get_linear_isa) && !defined(NEED_mro_get_linear_isa_GLOBAL)
56 static AV* my_mro_get_linear_isa(pTHX_ HV* const stash);
57 static
58 #else
59 extern AV* my_mro_get_linear_isa(pTHX_ HV* const stash);
60 #endif /* !NEED_mro_get_linear_isa */
61
62 #if defined(NEED_mro_get_linear_isa) || defined(NEED_mro_get_linear_isa_GLOBAL)
63 #define ISA_CACHE "::LINEALIZED_ISA_CACHE::"
64
65 /* call &mro::get_linear_isa, which is actually &MRO::Compat::__get_linear_isa */
66 AV*
67 my_mro_get_linear_isa(pTHX_ HV* const stash){
68         GV* cachegv;
69         AV* isa;  /* linearized ISA cache */
70         SV* gen;  /* package generation */
71         CV* get_linear_isa;
72
73         assert(stash != NULL);
74         assert(SvTYPE(stash) == SVt_PVHV);
75
76         cachegv = *(GV**)hv_fetchs(stash, ISA_CACHE, TRUE);
77         if(!isGV(cachegv))
78                 gv_init(cachegv, stash, ISA_CACHE, sizeof(ISA_CACHE)-1, GV_ADD);
79
80         isa = GvAVn(cachegv);
81 #ifdef GvSVn
82         gen = GvSVn(cachegv);
83 #else
84         gen = GvSV(cachegv);
85 #endif
86
87         if(SvIOK(gen) && SvIVX(gen) == (IV)mro_get_pkg_gen(stash)){
88                 return isa; /* returns the cache if available */
89         }
90         else{
91                 SvREADONLY_off(isa);
92                 av_clear(isa);
93         }
94
95         get_linear_isa = get_cv("mro::get_linear_isa", FALSE);
96         if(!get_linear_isa){
97                 ENTER;
98                 SAVETMPS;
99
100                 Perl_load_module(aTHX_ PERL_LOADMOD_NOIMPORT, newSVpvs("MRO::Compat"), NULL, NULL);
101                 get_linear_isa = get_cv("mro::get_linear_isa", TRUE);
102
103                 FREETMPS;
104                 LEAVE;
105         }
106
107         {
108                 SV* avref;
109                 dSP;
110
111                 ENTER;
112                 SAVETMPS;
113
114                 PUSHMARK(SP);
115                 mXPUSHp(HvNAME(stash), strlen(HvNAME(stash)));
116                 PUTBACK;
117
118                 call_sv((SV*)get_linear_isa, G_SCALAR);
119
120                 SPAGAIN;
121                 avref = POPs;
122                 PUTBACK;
123
124                 if(SvROK(avref) && SvTYPE(SvRV(avref)) == SVt_PVAV){
125                         AV* const av  = (AV*)SvRV(avref);
126                         I32 const len = AvFILLp(av) + 1;
127                         I32 i;
128
129                         for(i = 0; i < len; i++){
130                                 HV* const st = gv_stashsv(AvARRAY(av)[i], FALSE);
131                                 if(st)
132                                         av_push(isa, newSVpv(HvNAME(st), 0));
133                         }
134                         SvREADONLY_on(isa);
135                 }
136                 else{
137                         Perl_croak(aTHX_ "panic: mro::get_linear_isa() didn't return an ARRAY reference");
138                 }
139
140                 FREETMPS;
141                 LEAVE;
142         }
143
144         sv_setiv(gen, (IV)mro_get_pkg_gen(stash));
145         return isa;
146 }
147 #undef ISA_CACHE
148
149 #endif /* !(defined(NEED_mro_get_linear_isa) || defined(NEED_mro_get_linear_isa_GLOBAL)) */
150
151 #endif /* end of the file */