Add *.bs to MANIFEST.SKIP
[gitmo/Mouse.git] / mro_compat.h
CommitLineData
f028039d 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
13Usage:
14 #include "mro_compat.h"
15
16Functions:
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)
56static AV* my_mro_get_linear_isa(pTHX_ HV* const stash);
57static
58#else
59extern 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 */
66AV*
67my_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 */