File Coverage

Shared.xs
Criterion Covered Total %
statement 66 66 100.0
branch 1 2 50.0
condition n/a
subroutine n/a
pod n/a
total 67 68 98.5


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 12           static int build_kw_2arg(pTHX_ OP **out, XSParseKeywordPiece *args[], size_t nargs, void *hookdata) {
58             (void)nargs;
59 12           const char *func = (const char *)hookdata;
60 12           OP *map_op = args[0]->op;
61 12           OP *key_op = args[1]->op;
62 12           OP *cvref = newCVREF(0, newGVOP(OP_GV, 0, gv_fetchpv(func, GV_ADD, SVt_PVCV)));
63 12           OP *arglist = op_append_elem(OP_LIST, map_op, key_op);
64 12           arglist = op_append_elem(OP_LIST, arglist, cvref);
65 12           *out = op_convert_list(OP_ENTERSUB, OPf_STACKED, arglist);
66 12           return KEYWORD_PLUGIN_EXPR;
67             }
68              
69 14           static int build_kw_3arg(pTHX_ OP **out, XSParseKeywordPiece *args[], size_t nargs, void *hookdata) {
70             (void)nargs;
71 14           const char *func = (const char *)hookdata;
72 14           OP *map_op = args[0]->op;
73 14           OP *key_op = args[1]->op;
74 14           OP *val_op = args[2]->op;
75 14           OP *cvref = newCVREF(0, newGVOP(OP_GV, 0, gv_fetchpv(func, GV_ADD, SVt_PVCV)));
76 14           OP *arglist = op_append_elem(OP_LIST, map_op, key_op);
77 14           arglist = op_append_elem(OP_LIST, arglist, val_op);
78 14           arglist = op_append_elem(OP_LIST, arglist, cvref);
79 14           *out = op_convert_list(OP_ENTERSUB, OPf_STACKED, arglist);
80 14           return KEYWORD_PLUGIN_EXPR;
81             }
82              
83 5           static int build_kw_4arg(pTHX_ OP **out, XSParseKeywordPiece *args[], size_t nargs, void *hookdata) {
84             (void)nargs;
85 5           const char *func = (const char *)hookdata;
86 5           OP *map_op = args[0]->op;
87 5           OP *a1 = args[1]->op;
88 5           OP *a2 = args[2]->op;
89 5           OP *a3 = args[3]->op;
90 5           OP *cvref = newCVREF(0, newGVOP(OP_GV, 0, gv_fetchpv(func, GV_ADD, SVt_PVCV)));
91 5           OP *arglist = op_append_elem(OP_LIST, map_op, a1);
92 5           arglist = op_append_elem(OP_LIST, arglist, a2);
93 5           arglist = op_append_elem(OP_LIST, arglist, a3);
94 5           arglist = op_append_elem(OP_LIST, arglist, cvref);
95 5           *out = op_convert_list(OP_ENTERSUB, OPf_STACKED, arglist);
96 5           return KEYWORD_PLUGIN_EXPR;
97             }
98              
99 2           static int build_kw_3arg_list(pTHX_ OP **out, XSParseKeywordPiece *args[], size_t nargs, void *hookdata) {
100             (void)nargs;
101 2           const char *func = (const char *)hookdata;
102 2           OP *map_op = args[0]->op;
103 2           OP *a1 = args[1]->op;
104 2           OP *a2 = args[2]->op;
105 2           OP *cvref = newCVREF(0, newGVOP(OP_GV, 0, gv_fetchpv(func, GV_ADD, SVt_PVCV)));
106 2           OP *arglist = op_append_elem(OP_LIST, map_op, a1);
107 2           arglist = op_append_elem(OP_LIST, arglist, a2);
108 2           arglist = op_append_elem(OP_LIST, arglist, cvref);
109 2           *out = op_convert_list(OP_ENTERSUB, OPf_STACKED | OPf_WANT_LIST, arglist);
110 2           return KEYWORD_PLUGIN_EXPR;
111             }
112              
113             /* ---- Keyword pieces ---- */
114              
115             static const struct XSParseKeywordPieceType pieces_1expr[] = {
116             XPK_TERMEXPR, {0}
117             };
118              
119             static const struct XSParseKeywordPieceType pieces_2expr[] = {
120             XPK_TERMEXPR, XPK_COMMA, XPK_TERMEXPR, {0}
121             };
122              
123             static const struct XSParseKeywordPieceType pieces_3expr[] = {
124             XPK_TERMEXPR, XPK_COMMA, XPK_TERMEXPR, XPK_COMMA, XPK_TERMEXPR, {0}
125             };
126              
127             static const struct XSParseKeywordPieceType pieces_4expr[] = {
128             XPK_TERMEXPR, XPK_COMMA, XPK_TERMEXPR, XPK_COMMA, XPK_TERMEXPR, XPK_COMMA, XPK_TERMEXPR, {0}
129             };
130              
131             /* ---- Keyword hook definitions ---- */
132              
133             #define DEFINE_KW_HOOK(variant, PKG, kw, nargs, builder) \
134             static const struct XSParseKeywordHooks hooks_buf_##variant##_##kw = { \
135             .flags = XPK_FLAG_EXPR, \
136             .permit_hintkey = "Data::Buffer::Shared::" PKG "/buf_" #variant "_" #kw, \
137             .pieces = pieces_##nargs##expr, \
138             .build = builder, \
139             };
140              
141             #define REGISTER_KW(variant, kw, funcname) \
142             register_xs_parse_keyword("buf_" #variant "_" #kw, \
143             &hooks_buf_##variant##_##kw, (void*)(funcname))
144              
145             /* Integer variant keywords (set_slice is method-only due to variadic args) */
146             #define DEFINE_INT_KW_HOOKS(variant, PKG) \
147             DEFINE_KW_HOOK(variant, PKG, get, 2, build_kw_2arg) \
148             DEFINE_KW_HOOK(variant, PKG, set, 3, build_kw_3arg) \
149             DEFINE_KW_HOOK(variant, PKG, slice, 3, build_kw_3arg_list) \
150             DEFINE_KW_HOOK(variant, PKG, fill, 2, build_kw_2arg) \
151             DEFINE_KW_HOOK(variant, PKG, incr, 2, build_kw_2arg) \
152             DEFINE_KW_HOOK(variant, PKG, decr, 2, build_kw_2arg) \
153             DEFINE_KW_HOOK(variant, PKG, add, 3, build_kw_3arg) \
154             DEFINE_KW_HOOK(variant, PKG, cas, 4, build_kw_4arg) \
155             DEFINE_KW_HOOK(variant, PKG, capacity, 1, build_kw_1arg) \
156             DEFINE_KW_HOOK(variant, PKG, mmap_size, 1, build_kw_1arg) \
157             DEFINE_KW_HOOK(variant, PKG, elem_size, 1, build_kw_1arg) \
158             DEFINE_KW_HOOK(variant, PKG, lock_wr, 1, build_kw_1arg) \
159             DEFINE_KW_HOOK(variant, PKG, unlock_wr, 1, build_kw_1arg) \
160             DEFINE_KW_HOOK(variant, PKG, lock_rd, 1, build_kw_1arg) \
161             DEFINE_KW_HOOK(variant, PKG, unlock_rd, 1, build_kw_1arg) \
162             DEFINE_KW_HOOK(variant, PKG, ptr, 1, build_kw_1arg) \
163             DEFINE_KW_HOOK(variant, PKG, ptr_at, 2, build_kw_2arg) \
164             DEFINE_KW_HOOK(variant, PKG, clear, 1, build_kw_1arg) \
165             DEFINE_KW_HOOK(variant, PKG, get_raw, 3, build_kw_3arg) \
166             DEFINE_KW_HOOK(variant, PKG, set_raw, 3, build_kw_3arg) \
167             DEFINE_KW_HOOK(variant, PKG, cmpxchg, 4, build_kw_4arg) \
168             DEFINE_KW_HOOK(variant, PKG, atomic_and, 3, build_kw_3arg) \
169             DEFINE_KW_HOOK(variant, PKG, atomic_or, 3, build_kw_3arg) \
170             DEFINE_KW_HOOK(variant, PKG, atomic_xor, 3, build_kw_3arg)
171              
172             /* Float variants: no incr/decr/add/cas/cmpxchg/bitwise */
173             #define DEFINE_FLOAT_KW_HOOKS(variant, PKG) \
174             DEFINE_KW_HOOK(variant, PKG, get, 2, build_kw_2arg) \
175             DEFINE_KW_HOOK(variant, PKG, set, 3, build_kw_3arg) \
176             DEFINE_KW_HOOK(variant, PKG, slice, 3, build_kw_3arg_list) \
177             DEFINE_KW_HOOK(variant, PKG, fill, 2, build_kw_2arg) \
178             DEFINE_KW_HOOK(variant, PKG, capacity, 1, build_kw_1arg) \
179             DEFINE_KW_HOOK(variant, PKG, mmap_size, 1, build_kw_1arg) \
180             DEFINE_KW_HOOK(variant, PKG, elem_size, 1, build_kw_1arg) \
181             DEFINE_KW_HOOK(variant, PKG, lock_wr, 1, build_kw_1arg) \
182             DEFINE_KW_HOOK(variant, PKG, unlock_wr, 1, build_kw_1arg) \
183             DEFINE_KW_HOOK(variant, PKG, lock_rd, 1, build_kw_1arg) \
184             DEFINE_KW_HOOK(variant, PKG, unlock_rd, 1, build_kw_1arg) \
185             DEFINE_KW_HOOK(variant, PKG, ptr, 1, build_kw_1arg) \
186             DEFINE_KW_HOOK(variant, PKG, ptr_at, 2, build_kw_2arg) \
187             DEFINE_KW_HOOK(variant, PKG, clear, 1, build_kw_1arg) \
188             DEFINE_KW_HOOK(variant, PKG, get_raw, 3, build_kw_3arg) \
189             DEFINE_KW_HOOK(variant, PKG, set_raw, 3, build_kw_3arg)
190              
191             DEFINE_INT_KW_HOOKS(i8, "I8")
192             DEFINE_INT_KW_HOOKS(u8, "U8")
193             DEFINE_INT_KW_HOOKS(i16, "I16")
194             DEFINE_INT_KW_HOOKS(u16, "U16")
195             DEFINE_INT_KW_HOOKS(i32, "I32")
196             DEFINE_INT_KW_HOOKS(u32, "U32")
197             DEFINE_INT_KW_HOOKS(i64, "I64")
198             DEFINE_INT_KW_HOOKS(u64, "U64")
199              
200             DEFINE_FLOAT_KW_HOOKS(f32, "F32")
201             DEFINE_FLOAT_KW_HOOKS(f64, "F64")
202              
203             /* Str variant: same as float (no counters) but set takes string */
204             DEFINE_FLOAT_KW_HOOKS(str, "Str")
205              
206             /* ---- Registration macros ---- */
207              
208             #define REGISTER_INT_KWS(variant, PKG) \
209             REGISTER_KW(variant, get, PKG "::get"); \
210             REGISTER_KW(variant, set, PKG "::set"); \
211             REGISTER_KW(variant, slice, PKG "::slice"); \
212             REGISTER_KW(variant, fill, PKG "::fill"); \
213             REGISTER_KW(variant, incr, PKG "::incr"); \
214             REGISTER_KW(variant, decr, PKG "::decr"); \
215             REGISTER_KW(variant, add, PKG "::add"); \
216             REGISTER_KW(variant, cas, PKG "::cas"); \
217             REGISTER_KW(variant, capacity, PKG "::capacity"); \
218             REGISTER_KW(variant, mmap_size, PKG "::mmap_size"); \
219             REGISTER_KW(variant, elem_size, PKG "::elem_size"); \
220             REGISTER_KW(variant, lock_wr, PKG "::lock_wr"); \
221             REGISTER_KW(variant, unlock_wr, PKG "::unlock_wr"); \
222             REGISTER_KW(variant, lock_rd, PKG "::lock_rd"); \
223             REGISTER_KW(variant, unlock_rd, PKG "::unlock_rd"); \
224             REGISTER_KW(variant, ptr, PKG "::ptr"); \
225             REGISTER_KW(variant, ptr_at, PKG "::ptr_at"); \
226             REGISTER_KW(variant, clear, PKG "::clear"); \
227             REGISTER_KW(variant, get_raw, PKG "::get_raw"); \
228             REGISTER_KW(variant, set_raw, PKG "::set_raw"); \
229             REGISTER_KW(variant, cmpxchg, PKG "::cmpxchg"); \
230             REGISTER_KW(variant, atomic_and, PKG "::atomic_and"); \
231             REGISTER_KW(variant, atomic_or, PKG "::atomic_or"); \
232             REGISTER_KW(variant, atomic_xor, PKG "::atomic_xor");
233              
234             #define REGISTER_FLOAT_KWS(variant, PKG) \
235             REGISTER_KW(variant, get, PKG "::get"); \
236             REGISTER_KW(variant, set, PKG "::set"); \
237             REGISTER_KW(variant, slice, PKG "::slice"); \
238             REGISTER_KW(variant, fill, PKG "::fill"); \
239             REGISTER_KW(variant, capacity, PKG "::capacity"); \
240             REGISTER_KW(variant, mmap_size, PKG "::mmap_size"); \
241             REGISTER_KW(variant, elem_size, PKG "::elem_size"); \
242             REGISTER_KW(variant, lock_wr, PKG "::lock_wr"); \
243             REGISTER_KW(variant, unlock_wr, PKG "::unlock_wr"); \
244             REGISTER_KW(variant, lock_rd, PKG "::lock_rd"); \
245             REGISTER_KW(variant, unlock_rd, PKG "::unlock_rd"); \
246             REGISTER_KW(variant, ptr, PKG "::ptr"); \
247             REGISTER_KW(variant, ptr_at, PKG "::ptr_at"); \
248             REGISTER_KW(variant, clear, PKG "::clear"); \
249             REGISTER_KW(variant, get_raw, PKG "::get_raw"); \
250             REGISTER_KW(variant, set_raw, PKG "::set_raw");
251              
252             MODULE = Data::Buffer::Shared PACKAGE = Data::Buffer::Shared::I8
253             PROTOTYPES: DISABLE
254              
255             BOOT:
256 15           boot_xs_parse_keyword(0.40);
257 15           REGISTER_INT_KWS(i8, "Data::Buffer::Shared::I8")
258 15           REGISTER_INT_KWS(u8, "Data::Buffer::Shared::U8")
259 15           REGISTER_INT_KWS(i16, "Data::Buffer::Shared::I16")
260 15           REGISTER_INT_KWS(u16, "Data::Buffer::Shared::U16")
261 15           REGISTER_INT_KWS(i32, "Data::Buffer::Shared::I32")
262 15           REGISTER_INT_KWS(u32, "Data::Buffer::Shared::U32")
263 15           REGISTER_INT_KWS(i64, "Data::Buffer::Shared::I64")
264 15           REGISTER_INT_KWS(u64, "Data::Buffer::Shared::U64")
265 15           REGISTER_FLOAT_KWS(f32, "Data::Buffer::Shared::F32")
266 15           REGISTER_FLOAT_KWS(f64, "Data::Buffer::Shared::F64")
267 15           REGISTER_FLOAT_KWS(str, "Data::Buffer::Shared::Str")
268              
269             INCLUDE: xs/i8.xs
270             INCLUDE: xs/u8.xs
271             INCLUDE: xs/i16.xs
272             INCLUDE: xs/u16.xs
273             INCLUDE: xs/i32.xs
274             INCLUDE: xs/u32.xs
275             INCLUDE: xs/i64.xs
276             INCLUDE: xs/u64.xs
277             INCLUDE: xs/f32.xs
278             INCLUDE: xs/f64.xs
279             INCLUDE: xs/str.xs