File Coverage

src/xs/export.cc
Criterion Covered Total %
statement 62 125 49.6
branch 73 228 32.0
condition n/a
subroutine n/a
pod n/a
total 135 353 38.2


line stmt bran cond sub pod time code
1             #include
2              
3             #define EX_CROAK_NOSUB(hvname,subname) croak("Panda::Export: can't export unexisting symbol '%s::%s'", hvname, subname)
4             #define EX_CROAK_EXISTS(hvname,subname) croak("Panda::Export: can't create constant '%s::%s' - symbol already exists", hvname, subname)
5             #define EX_CROAK_NONAME(hvname) croak("Panda::Export: can't define a constant with an empty name in '%s'", hvname)
6             #define EX_CROAK_BADNAME(hvname,subname) croak("Panda::Export: can't create constant '%s::%s' - name must be a valid string", hvname, subname)
7              
8             namespace xs { namespace exp {
9              
10             static thread_local HV* clists;
11              
12 6           AV* constants_list (pTHX_ HV* stash) {
13 6 100         if (!clists) clists = newHV();
14 6 50         SV* clist = *hv_fetch(clists, HvNAME(stash), HvNAMELEN(stash), 1);
    50          
    50          
    0          
    50          
    50          
    50          
    50          
    50          
    0          
    50          
    50          
15             AV* ret;
16 6 100         if (!SvOK(clist)) {
    50          
    50          
17 3 50         SvUPGRADE(clist, SVt_RV);
18 3           SvROK_on(clist);
19 3           ret = newAV();
20 3           SvRV_set(clist, (SV*) ret);
21             }
22 3           else ret = (AV*)SvRV(clist);
23 6           return ret;
24             }
25              
26 13           static SV* push_export (pTHX_ HV* stash, SV* name, AV* stash_constants_list = NULL, bool need_inc = false) {
27 13 50         if (!stash_constants_list) stash_constants_list = constants_list(aTHX_ stash);
28              
29 13 100         if (!SvPOK(name)) EX_CROAK_BADNAME(HvNAME(stash), SvPV_nolen(name));
    50          
    50          
    50          
    50          
    0          
    50          
    50          
30 12 50         if (!SvCUR(name)) EX_CROAK_NONAME(HvNAME(stash));
    0          
    0          
    0          
    0          
    0          
    0          
31              
32 12 50         if (need_inc) {
33 12 50         if (SvIsCOW_shared_hash(name)) SvREFCNT_inc(name);
    50          
34 12           else name = newSVpvn_share(SvPVX_const(name), SvCUR(name), 0);
35             }
36              
37 12           av_push(stash_constants_list, name);
38 12           return name;
39             }
40              
41 0           void register_export (pTHX_ HV* stash, CV* sub) {
42 0 0         HEK* hek = CvNAMED(sub) ? CvNAME_HEK(sub) : GvNAME_HEK(CvGV(sub));
43 0 0         if (!hek) EX_CROAK_NONAME(HvNAME(stash));
    0          
    0          
    0          
    0          
    0          
    0          
44              
45 0           SV* name = newSVhek(hek);
46             assert(SvIsCOW_shared_hash(name));
47              
48 0           push_export(aTHX_ stash, name);
49 0           }
50              
51 0           void register_export (pTHX_ HV* stash, SV* name) {
52 0           push_export(aTHX_ stash, name, NULL, true);
53 0           }
54              
55 0           void register_export (pTHX_ HV* stash, const char* name) {
56 0           SV* sv_name = newSVpvn_share(name, strlen(name), 0);
57 0           push_export(aTHX_ stash, sv_name);
58 0           }
59              
60 14           void create_constant (pTHX_ HV* stash, SV* name, SV* value, AV* stash_constants_list) {
61 14 50         if (!name) EX_CROAK_NONAME(HvNAME(stash));
    0          
    0          
    0          
    0          
    0          
    0          
62              
63             // check that we won't redefine any subroutine
64 14           HE* sym_he = hv_fetch_ent(stash, name, 0, 0);
65 14 100         if (sym_he && HeVAL(sym_he) && isGV(HeVAL(sym_he)) && GvCV(HeVAL(sym_he))) EX_CROAK_EXISTS(HvNAME(stash), SvPV_nolen(name));
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    0          
    50          
    50          
66              
67             /* gets name as a shared PV */
68 13           name = push_export(aTHX_ stash, name, stash_constants_list, true);
69              
70 12 50         if (value) SvREFCNT_inc(value);
71 0           else value = newSV(0);
72 12           SvREADONLY_on(value);
73 12           newCONSTSUB(stash, SvPVX_const(name), value);
74 12           }
75              
76 0           void create_constant (pTHX_ HV* stash, const char* name, const char* value, AV* stash_constants_list) {
77 0           SV* namesv = newSVpvn_share(name, strlen(name), 0);
78 0           SV* valuesv = newSVpv(value, 0);
79 0           create_constant(aTHX_ stash, namesv, valuesv, stash_constants_list);
80 0           SvREFCNT_dec_NN(namesv);
81 0           SvREFCNT_dec_NN(valuesv);
82 0           }
83              
84 0           void create_constant (pTHX_ HV* stash, const char* name, int64_t value, AV* stash_constants_list) {
85 0           SV* namesv = newSVpvn_share(name, strlen(name), 0);
86 0           SV* valuesv = newSViv(value);
87 0           create_constant(aTHX_ stash, namesv, valuesv, stash_constants_list);
88 0           SvREFCNT_dec_NN(namesv);
89 0           SvREFCNT_dec_NN(valuesv);
90 0           }
91              
92 0           void create_constant (pTHX_ HV* stash, constant_t constant, AV* stash_constants_list) {
93 0 0         if (constant.svalue) create_constant(aTHX_ stash, constant.name, constant.svalue, stash_constants_list);
94 0           else create_constant(aTHX_ stash, constant.name, constant.value, stash_constants_list);
95 0           }
96              
97 3           void create_constants (pTHX_ HV* stash, HV* constants) {
98 3           AV* clist = constants_list(aTHX_ stash);
99 45 50         XS_HV_ITER(constants, {
    50          
    100          
    100          
100             SV* name = newSVpvn_share(HeKEY(he), HeKLEN(he), HeHASH(he));
101             create_constant(aTHX_ stash, name, HeVAL(he), clist);
102             SvREFCNT_dec_NN(name);
103             });
104 2           }
105              
106 1           void create_constants (pTHX_ HV* stash, SV** list, size_t items) {
107 1 50         if (!list || !items) return;
    50          
108 1           AV* clist = constants_list(aTHX_ stash);
109 1 50         for (size_t i = 0; i < items - 1; i += 2) {
110 1           SV* name = *list++;
111 1           SV* value = *list++;
112 1           create_constant(aTHX_ stash, name, value, clist);
113             }
114             }
115              
116 0           void create_constants (pTHX_ HV* stash, constant_t* list, size_t items) {
117 0 0         if (!list || !items) return;
    0          
118 0           AV* clist = constants_list(aTHX_ stash);
119 0 0         while (items--) {
120 0           constant_t constant = *list++;
121 0 0         if (!constant.name) break;
122 0 0         SV* namesv = newSVpvn_share(constant.name, strlen(constant.name), 0);
123 0 0         SV* valuesv = constant.svalue ? newSVpv(constant.svalue, 0) : newSViv(constant.value);
    0          
    0          
124 0 0         create_constant(aTHX_ stash, namesv, valuesv, clist);
125 0 0         SvREFCNT_dec_NN(namesv);
126 0 0         SvREFCNT_dec_NN(valuesv);
127             }
128             }
129              
130 27           static inline void _export_sub (pTHX_ HV* from, HV* to, SV* name) {
131 27           HE* symentry_ent = hv_fetch_ent(from, name, 0, 0);
132 27 100         GV* symentry = symentry_ent ? (GV*)HeVAL(symentry_ent) : NULL;
133 27 100         if (!symentry || (isGV(symentry) && !GvCV(symentry))) EX_CROAK_NOSUB(HvNAME(from), SvPV_nolen(name));
    50          
    50          
    50          
    50          
    50          
    50          
    0          
    50          
    50          
134 26           SvREFCNT_inc_simple_void_NN((SV*)symentry);
135 26           hv_store_ent(to, name, (SV*)symentry, 0);
136 26           }
137              
138 0           static inline void _export_sub (pTHX_ HV* from, HV* to, const char* name) {
139 0           size_t namelen = strlen(name);
140 0           SV** symentry_ref = hv_fetch(from, name, namelen, 0);
141 0 0         GV* symentry = symentry_ref ? (GV*)(*symentry_ref) : NULL;
142 0 0         if (!symentry || (isGV(symentry) && !GvCV(symentry))) EX_CROAK_NOSUB(HvNAME(from), name);
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
143 0           SvREFCNT_inc_simple_void_NN((SV*)symentry);
144 0           hv_store(to, name, namelen, (SV*)symentry, 0);
145 0           }
146              
147 0           void export_sub (pTHX_ HV* from, HV* to, SV* name) { _export_sub(aTHX_ from, to, name); }
148 0           void export_sub (pTHX_ HV* from, HV* to, const char* name) { _export_sub(aTHX_ from, to, name); }
149              
150 1           void export_constants (pTHX_ HV* from, HV* to) {
151 1           AV* clist = constants_list(aTHX_ from);
152 1           export_subs(aTHX_ from, to, AvARRAY(clist), AvFILLp(clist)+1);
153 1           }
154              
155 6           void export_subs (pTHX_ HV* from, HV* to, SV** list, size_t items) {
156 33 100         while (items--) {
157 28           SV* name = *list++;
158 28 50         if (!name) continue;
159 28           const char* name_str = SvPVX_const(name);
160 28 100         if (name_str[0] == ':' && strEQ(name_str, ":const")) {
    50          
161 1           AV* clist = constants_list(aTHX_ from);
162             // this check prevents infinite loop if someone created constant with name ":const"
163 1 50         if (AvARRAY(clist) != list) export_subs(aTHX_ from, to, AvARRAY(clist), AvFILLp(clist)+1);
164 1           continue;
165             }
166 27           _export_sub(aTHX_ from, to, name);
167             }
168 5           }
169              
170 0           void export_subs (pTHX_ HV* from, HV* to, const char** list, size_t items) {
171 0 0         while (items--) {
172 0           const char* name = *list++;
173 0 0         if (!name) break;
174 0 0         if (name[0] == ':' && strEQ(name, ":const")) {
    0          
175 0           AV* clist = constants_list(aTHX_ from);
176 0           export_subs(aTHX_ from, to, AvARRAY(clist), AvFILLp(clist)+1);
177 0           continue;
178             }
179 0           _export_sub(aTHX_ from, to, name);
180             }
181 0           }
182              
183 8 50         }}
    50