File Coverage

Shared.xs
Criterion Covered Total %
statement 66 73 90.4
branch 1 2 50.0
condition n/a
subroutine n/a
pod n/a
total 67 75 89.3


line stmt bran cond sub pod time code
1             #define PERL_NO_GET_CONTEXT
2             #include "EXTERN.h"
3             #include "perl.h"
4             #include "XSUB.h"
5              
6             #include "ppport.h"
7              
8             #include "buf_i8.h"
9             #include "buf_u8.h"
10             #include "buf_i16.h"
11             #include "buf_u16.h"
12             #include "buf_i32.h"
13             #include "buf_u32.h"
14             #include "buf_i64.h"
15             #include "buf_u64.h"
16             #include "buf_f32.h"
17             #include "buf_f64.h"
18             #include "buf_str.h"
19              
20             #include "XSParseKeyword.h"
21              
22             /* ---- as_scalar magic: prevent use-after-free by preventing buffer DESTROY
23             * while the returned scalar ref is alive. We attach magic to the inner SV
24             * that holds a reference to the buffer object. When the inner SV is freed,
25             * the magic destructor releases the reference. ---- */
26              
27 5           static int buf_scalar_magic_free(pTHX_ SV *sv, MAGIC *mg) {
28             PERL_UNUSED_ARG(sv);
29 5 50         if (mg->mg_obj) SvREFCNT_dec(mg->mg_obj);
30 5           return 0;
31             }
32              
33             static const MGVTBL buf_scalar_magic_vtbl = {
34             NULL, NULL, NULL, NULL, buf_scalar_magic_free, NULL, NULL, NULL
35             };
36              
37             /* ---- Helper macros ---- */
38              
39             #define EXTRACT_BUF(classname, sv) \
40             if (!sv_isobject(sv) || !sv_derived_from(sv, classname)) \
41             croak("Expected a %s object", classname); \
42             BufHandle* h = INT2PTR(BufHandle*, SvIV(SvRV(sv))); \
43             if (!h) croak("Attempted to use a destroyed %s object", classname)
44              
45             /* ---- Generic keyword build functions ---- */
46              
47 5           static int build_kw_1arg(pTHX_ OP **out, XSParseKeywordPiece *args[], size_t nargs, void *hookdata) {
48             (void)nargs;
49 5           const char *func = (const char *)hookdata;
50 5           OP *map_op = args[0]->op;
51 5           OP *cvref = newCVREF(0, newGVOP(OP_GV, 0, gv_fetchpv(func, GV_ADD, SVt_PVCV)));
52 5           OP *arglist = op_append_elem(OP_LIST, map_op, cvref);
53 5           *out = op_convert_list(OP_ENTERSUB, OPf_STACKED, arglist);
54 5           return KEYWORD_PLUGIN_EXPR;
55             }
56              
57 9           static int build_kw_2arg(pTHX_ OP **out, XSParseKeywordPiece *args[], size_t nargs, void *hookdata) {
58             (void)nargs;
59 9           const char *func = (const char *)hookdata;
60 9           OP *map_op = args[0]->op;
61 9           OP *key_op = args[1]->op;
62 9           OP *cvref = newCVREF(0, newGVOP(OP_GV, 0, gv_fetchpv(func, GV_ADD, SVt_PVCV)));
63 9           OP *arglist = op_append_elem(OP_LIST, map_op, key_op);
64 9           arglist = op_append_elem(OP_LIST, arglist, cvref);
65 9           *out = op_convert_list(OP_ENTERSUB, OPf_STACKED, arglist);
66 9           return KEYWORD_PLUGIN_EXPR;
67             }
68              
69 12           static int build_kw_3arg(pTHX_ OP **out, XSParseKeywordPiece *args[], size_t nargs, void *hookdata) {
70             (void)nargs;
71 12           const char *func = (const char *)hookdata;
72 12           OP *map_op = args[0]->op;
73 12           OP *key_op = args[1]->op;
74 12           OP *val_op = args[2]->op;
75 12           OP *cvref = newCVREF(0, newGVOP(OP_GV, 0, gv_fetchpv(func, GV_ADD, SVt_PVCV)));
76 12           OP *arglist = op_append_elem(OP_LIST, map_op, key_op);
77 12           arglist = op_append_elem(OP_LIST, arglist, val_op);
78 12           arglist = op_append_elem(OP_LIST, arglist, cvref);
79 12           *out = op_convert_list(OP_ENTERSUB, OPf_STACKED, arglist);
80 12           return KEYWORD_PLUGIN_EXPR;
81             }
82              
83 4           static int build_kw_4arg(pTHX_ OP **out, XSParseKeywordPiece *args[], size_t nargs, void *hookdata) {
84             (void)nargs;
85 4           const char *func = (const char *)hookdata;
86 4           OP *map_op = args[0]->op;
87 4           OP *a1 = args[1]->op;
88 4           OP *a2 = args[2]->op;
89 4           OP *a3 = args[3]->op;
90 4           OP *cvref = newCVREF(0, newGVOP(OP_GV, 0, gv_fetchpv(func, GV_ADD, SVt_PVCV)));
91 4           OP *arglist = op_append_elem(OP_LIST, map_op, a1);
92 4           arglist = op_append_elem(OP_LIST, arglist, a2);
93 4           arglist = op_append_elem(OP_LIST, arglist, a3);
94 4           arglist = op_append_elem(OP_LIST, arglist, cvref);
95 4           *out = op_convert_list(OP_ENTERSUB, OPf_STACKED, arglist);
96 4           return KEYWORD_PLUGIN_EXPR;
97             }
98              
99 0           static int build_kw_1arg_list(pTHX_ OP **out, XSParseKeywordPiece *args[], size_t nargs, void *hookdata) {
100             (void)nargs;
101 0           const char *func = (const char *)hookdata;
102 0           OP *map_op = args[0]->op;
103 0           OP *cvref = newCVREF(0, newGVOP(OP_GV, 0, gv_fetchpv(func, GV_ADD, SVt_PVCV)));
104 0           OP *arglist = op_append_elem(OP_LIST, map_op, cvref);
105 0           *out = op_convert_list(OP_ENTERSUB, OPf_STACKED | OPf_WANT_LIST, arglist);
106 0           return KEYWORD_PLUGIN_EXPR;
107             }
108              
109 2           static int build_kw_3arg_list(pTHX_ OP **out, XSParseKeywordPiece *args[], size_t nargs, void *hookdata) {
110             (void)nargs;
111 2           const char *func = (const char *)hookdata;
112 2           OP *map_op = args[0]->op;
113 2           OP *a1 = args[1]->op;
114 2           OP *a2 = args[2]->op;
115 2           OP *cvref = newCVREF(0, newGVOP(OP_GV, 0, gv_fetchpv(func, GV_ADD, SVt_PVCV)));
116 2           OP *arglist = op_append_elem(OP_LIST, map_op, a1);
117 2           arglist = op_append_elem(OP_LIST, arglist, a2);
118 2           arglist = op_append_elem(OP_LIST, arglist, cvref);
119 2           *out = op_convert_list(OP_ENTERSUB, OPf_STACKED | OPf_WANT_LIST, arglist);
120 2           return KEYWORD_PLUGIN_EXPR;
121             }
122              
123             /* ---- Keyword pieces ---- */
124              
125             static const struct XSParseKeywordPieceType pieces_1expr[] = {
126             XPK_TERMEXPR, {0}
127             };
128              
129             static const struct XSParseKeywordPieceType pieces_2expr[] = {
130             XPK_TERMEXPR, XPK_COMMA, XPK_TERMEXPR, {0}
131             };
132              
133             static const struct XSParseKeywordPieceType pieces_3expr[] = {
134             XPK_TERMEXPR, XPK_COMMA, XPK_TERMEXPR, XPK_COMMA, XPK_TERMEXPR, {0}
135             };
136              
137             static const struct XSParseKeywordPieceType pieces_4expr[] = {
138             XPK_TERMEXPR, XPK_COMMA, XPK_TERMEXPR, XPK_COMMA, XPK_TERMEXPR, XPK_COMMA, XPK_TERMEXPR, {0}
139             };
140              
141             /* ---- Keyword hook definitions ---- */
142              
143             #define DEFINE_KW_HOOK(variant, PKG, kw, nargs, builder) \
144             static const struct XSParseKeywordHooks hooks_buf_##variant##_##kw = { \
145             .flags = XPK_FLAG_EXPR, \
146             .permit_hintkey = "Data::Buffer::Shared::" PKG "/buf_" #variant "_" #kw, \
147             .pieces = pieces_##nargs##expr, \
148             .build = builder, \
149             };
150              
151             #define REGISTER_KW(variant, kw, funcname) \
152             register_xs_parse_keyword("buf_" #variant "_" #kw, \
153             &hooks_buf_##variant##_##kw, (void*)(funcname))
154              
155             /* Integer variant keywords (set_slice is method-only due to variadic args) */
156             #define DEFINE_INT_KW_HOOKS(variant, PKG) \
157             DEFINE_KW_HOOK(variant, PKG, get, 2, build_kw_2arg) \
158             DEFINE_KW_HOOK(variant, PKG, set, 3, build_kw_3arg) \
159             DEFINE_KW_HOOK(variant, PKG, slice, 3, build_kw_3arg_list) \
160             DEFINE_KW_HOOK(variant, PKG, fill, 2, build_kw_2arg) \
161             DEFINE_KW_HOOK(variant, PKG, incr, 2, build_kw_2arg) \
162             DEFINE_KW_HOOK(variant, PKG, decr, 2, build_kw_2arg) \
163             DEFINE_KW_HOOK(variant, PKG, add, 3, build_kw_3arg) \
164             DEFINE_KW_HOOK(variant, PKG, cas, 4, build_kw_4arg) \
165             DEFINE_KW_HOOK(variant, PKG, capacity, 1, build_kw_1arg) \
166             DEFINE_KW_HOOK(variant, PKG, mmap_size, 1, build_kw_1arg) \
167             DEFINE_KW_HOOK(variant, PKG, elem_size, 1, build_kw_1arg) \
168             DEFINE_KW_HOOK(variant, PKG, lock_wr, 1, build_kw_1arg) \
169             DEFINE_KW_HOOK(variant, PKG, unlock_wr, 1, build_kw_1arg) \
170             DEFINE_KW_HOOK(variant, PKG, lock_rd, 1, build_kw_1arg) \
171             DEFINE_KW_HOOK(variant, PKG, unlock_rd, 1, build_kw_1arg) \
172             DEFINE_KW_HOOK(variant, PKG, ptr, 1, build_kw_1arg) \
173             DEFINE_KW_HOOK(variant, PKG, ptr_at, 2, build_kw_2arg) \
174             DEFINE_KW_HOOK(variant, PKG, clear, 1, build_kw_1arg) \
175             DEFINE_KW_HOOK(variant, PKG, get_raw, 3, build_kw_3arg) \
176             DEFINE_KW_HOOK(variant, PKG, set_raw, 3, build_kw_3arg) \
177             DEFINE_KW_HOOK(variant, PKG, cmpxchg, 4, build_kw_4arg) \
178             DEFINE_KW_HOOK(variant, PKG, atomic_and, 3, build_kw_3arg) \
179             DEFINE_KW_HOOK(variant, PKG, atomic_or, 3, build_kw_3arg) \
180             DEFINE_KW_HOOK(variant, PKG, atomic_xor, 3, build_kw_3arg)
181              
182             /* Float variants: no incr/decr/add/cas/cmpxchg/bitwise */
183             #define DEFINE_FLOAT_KW_HOOKS(variant, PKG) \
184             DEFINE_KW_HOOK(variant, PKG, get, 2, build_kw_2arg) \
185             DEFINE_KW_HOOK(variant, PKG, set, 3, build_kw_3arg) \
186             DEFINE_KW_HOOK(variant, PKG, slice, 3, build_kw_3arg_list) \
187             DEFINE_KW_HOOK(variant, PKG, fill, 2, build_kw_2arg) \
188             DEFINE_KW_HOOK(variant, PKG, capacity, 1, build_kw_1arg) \
189             DEFINE_KW_HOOK(variant, PKG, mmap_size, 1, build_kw_1arg) \
190             DEFINE_KW_HOOK(variant, PKG, elem_size, 1, build_kw_1arg) \
191             DEFINE_KW_HOOK(variant, PKG, lock_wr, 1, build_kw_1arg) \
192             DEFINE_KW_HOOK(variant, PKG, unlock_wr, 1, build_kw_1arg) \
193             DEFINE_KW_HOOK(variant, PKG, lock_rd, 1, build_kw_1arg) \
194             DEFINE_KW_HOOK(variant, PKG, unlock_rd, 1, build_kw_1arg) \
195             DEFINE_KW_HOOK(variant, PKG, ptr, 1, build_kw_1arg) \
196             DEFINE_KW_HOOK(variant, PKG, ptr_at, 2, build_kw_2arg) \
197             DEFINE_KW_HOOK(variant, PKG, clear, 1, build_kw_1arg) \
198             DEFINE_KW_HOOK(variant, PKG, get_raw, 3, build_kw_3arg) \
199             DEFINE_KW_HOOK(variant, PKG, set_raw, 3, build_kw_3arg)
200              
201             DEFINE_INT_KW_HOOKS(i8, "I8")
202             DEFINE_INT_KW_HOOKS(u8, "U8")
203             DEFINE_INT_KW_HOOKS(i16, "I16")
204             DEFINE_INT_KW_HOOKS(u16, "U16")
205             DEFINE_INT_KW_HOOKS(i32, "I32")
206             DEFINE_INT_KW_HOOKS(u32, "U32")
207             DEFINE_INT_KW_HOOKS(i64, "I64")
208             DEFINE_INT_KW_HOOKS(u64, "U64")
209              
210             DEFINE_FLOAT_KW_HOOKS(f32, "F32")
211             DEFINE_FLOAT_KW_HOOKS(f64, "F64")
212              
213             /* Str variant: same as float (no counters) but set takes string */
214             DEFINE_FLOAT_KW_HOOKS(str, "Str")
215              
216             /* ---- Registration macros ---- */
217              
218             #define REGISTER_INT_KWS(variant, PKG) \
219             REGISTER_KW(variant, get, PKG "::get"); \
220             REGISTER_KW(variant, set, PKG "::set"); \
221             REGISTER_KW(variant, slice, PKG "::slice"); \
222             REGISTER_KW(variant, fill, PKG "::fill"); \
223             REGISTER_KW(variant, incr, PKG "::incr"); \
224             REGISTER_KW(variant, decr, PKG "::decr"); \
225             REGISTER_KW(variant, add, PKG "::add"); \
226             REGISTER_KW(variant, cas, PKG "::cas"); \
227             REGISTER_KW(variant, capacity, PKG "::capacity"); \
228             REGISTER_KW(variant, mmap_size, PKG "::mmap_size"); \
229             REGISTER_KW(variant, elem_size, PKG "::elem_size"); \
230             REGISTER_KW(variant, lock_wr, PKG "::lock_wr"); \
231             REGISTER_KW(variant, unlock_wr, PKG "::unlock_wr"); \
232             REGISTER_KW(variant, lock_rd, PKG "::lock_rd"); \
233             REGISTER_KW(variant, unlock_rd, PKG "::unlock_rd"); \
234             REGISTER_KW(variant, ptr, PKG "::ptr"); \
235             REGISTER_KW(variant, ptr_at, PKG "::ptr_at"); \
236             REGISTER_KW(variant, clear, PKG "::clear"); \
237             REGISTER_KW(variant, get_raw, PKG "::get_raw"); \
238             REGISTER_KW(variant, set_raw, PKG "::set_raw"); \
239             REGISTER_KW(variant, cmpxchg, PKG "::cmpxchg"); \
240             REGISTER_KW(variant, atomic_and, PKG "::atomic_and"); \
241             REGISTER_KW(variant, atomic_or, PKG "::atomic_or"); \
242             REGISTER_KW(variant, atomic_xor, PKG "::atomic_xor");
243              
244             #define REGISTER_FLOAT_KWS(variant, PKG) \
245             REGISTER_KW(variant, get, PKG "::get"); \
246             REGISTER_KW(variant, set, PKG "::set"); \
247             REGISTER_KW(variant, slice, PKG "::slice"); \
248             REGISTER_KW(variant, fill, PKG "::fill"); \
249             REGISTER_KW(variant, capacity, PKG "::capacity"); \
250             REGISTER_KW(variant, mmap_size, PKG "::mmap_size"); \
251             REGISTER_KW(variant, elem_size, PKG "::elem_size"); \
252             REGISTER_KW(variant, lock_wr, PKG "::lock_wr"); \
253             REGISTER_KW(variant, unlock_wr, PKG "::unlock_wr"); \
254             REGISTER_KW(variant, lock_rd, PKG "::lock_rd"); \
255             REGISTER_KW(variant, unlock_rd, PKG "::unlock_rd"); \
256             REGISTER_KW(variant, ptr, PKG "::ptr"); \
257             REGISTER_KW(variant, ptr_at, PKG "::ptr_at"); \
258             REGISTER_KW(variant, clear, PKG "::clear"); \
259             REGISTER_KW(variant, get_raw, PKG "::get_raw"); \
260             REGISTER_KW(variant, set_raw, PKG "::set_raw");
261              
262             MODULE = Data::Buffer::Shared PACKAGE = Data::Buffer::Shared::I8
263             PROTOTYPES: DISABLE
264              
265             BOOT:
266 12           boot_xs_parse_keyword(0.40);
267 12           REGISTER_INT_KWS(i8, "Data::Buffer::Shared::I8")
268 12           REGISTER_INT_KWS(u8, "Data::Buffer::Shared::U8")
269 12           REGISTER_INT_KWS(i16, "Data::Buffer::Shared::I16")
270 12           REGISTER_INT_KWS(u16, "Data::Buffer::Shared::U16")
271 12           REGISTER_INT_KWS(i32, "Data::Buffer::Shared::I32")
272 12           REGISTER_INT_KWS(u32, "Data::Buffer::Shared::U32")
273 12           REGISTER_INT_KWS(i64, "Data::Buffer::Shared::I64")
274 12           REGISTER_INT_KWS(u64, "Data::Buffer::Shared::U64")
275 12           REGISTER_FLOAT_KWS(f32, "Data::Buffer::Shared::F32")
276 12           REGISTER_FLOAT_KWS(f64, "Data::Buffer::Shared::F64")
277 12           REGISTER_FLOAT_KWS(str, "Data::Buffer::Shared::Str")
278              
279             INCLUDE: xs/i8.xs
280             INCLUDE: xs/u8.xs
281             INCLUDE: xs/i16.xs
282             INCLUDE: xs/u16.xs
283             INCLUDE: xs/i32.xs
284             INCLUDE: xs/u32.xs
285             INCLUDE: xs/i64.xs
286             INCLUDE: xs/u64.xs
287             INCLUDE: xs/f32.xs
288             INCLUDE: xs/f64.xs
289             INCLUDE: xs/str.xs