3 ** Copyright (C) 2005-2023 Mike Pall. See Copyright Notice in luajit.h
28 #include "lj_strfmt.h"
29 #include "lj_serialize.h"
32 /* -- Helper functions ---------------------------------------------------- */
34 /* Check that the first argument is a string buffer. */
35 static SBufExt
*buffer_tobuf(lua_State
*L
)
37 if (!(L
->base
< L
->top
&& tvisbuf(L
->base
)))
38 lj_err_argtype(L
, 1, "buffer");
42 /* Ditto, but for writers. */
43 static LJ_AINLINE SBufExt
*buffer_tobufw(lua_State
*L
)
45 SBufExt
*sbx
= buffer_tobuf(L
);
50 #define buffer_toudata(sbx) ((GCudata *)(sbx)-1)
52 /* -- Buffer methods ------------------------------------------------------ */
54 #define LJLIB_MODULE_buffer_method
56 LJLIB_CF(buffer_method_free
)
58 SBufExt
*sbx
= buffer_tobuf(L
);
60 L
->top
= L
->base
+1; /* Chain buffer object. */
64 LJLIB_CF(buffer_method_reset
) LJLIB_REC(.)
66 SBufExt
*sbx
= buffer_tobuf(L
);
68 L
->top
= L
->base
+1; /* Chain buffer object. */
72 LJLIB_CF(buffer_method_skip
) LJLIB_REC(.)
74 SBufExt
*sbx
= buffer_tobuf(L
);
75 MSize n
= (MSize
)lj_lib_checkintrange(L
, 2, 0, LJ_MAX_BUF
);
76 MSize len
= sbufxlen(sbx
);
79 } else if (sbufiscow(sbx
)) {
82 sbx
->r
= sbx
->w
= sbx
->b
;
84 L
->top
= L
->base
+1; /* Chain buffer object. */
88 LJLIB_CF(buffer_method_set
) LJLIB_REC(.)
90 SBufExt
*sbx
= buffer_tobuf(L
);
95 if (tviscdata(L
->base
+1)) {
96 CTState
*cts
= ctype_cts(L
);
97 lj_cconv_ct_tv(cts
, ctype_get(cts
, CTID_P_CVOID
), (uint8_t *)&p
,
98 L
->base
+1, CCF_ARG(2));
99 len
= (MSize
)lj_lib_checkintrange(L
, 3, 0, LJ_MAX_BUF
);
103 GCstr
*str
= lj_lib_checkstrx(L
, 2);
107 lj_bufx_free(L
, sbx
);
108 lj_bufx_set_cow(L
, sbx
, p
, len
);
109 ref
= gcV(L
->base
+1);
110 setgcref(sbx
->cowref
, ref
);
111 lj_gc_objbarrier(L
, buffer_toudata(sbx
), ref
);
112 L
->top
= L
->base
+1; /* Chain buffer object. */
116 LJLIB_CF(buffer_method_put
) LJLIB_REC(.)
118 SBufExt
*sbx
= buffer_tobufw(L
);
119 ptrdiff_t arg
, narg
= L
->top
- L
->base
;
120 for (arg
= 1; arg
< narg
; arg
++) {
121 cTValue
*o
= &L
->base
[arg
], *mo
= NULL
;
124 lj_buf_putstr((SBuf
*)sbx
, strV(o
));
125 } else if (tvisint(o
)) {
126 lj_strfmt_putint((SBuf
*)sbx
, intV(o
));
127 } else if (tvisnum(o
)) {
128 lj_strfmt_putfnum((SBuf
*)sbx
, STRFMT_G14
, numV(o
));
129 } else if (tvisbuf(o
)) {
130 SBufExt
*sbx2
= bufV(o
);
131 if (sbx2
== sbx
) lj_err_arg(L
, (int)(arg
+1), LJ_ERR_BUFFER_SELF
);
132 lj_buf_putmem((SBuf
*)sbx
, sbx2
->r
, sbufxlen(sbx2
));
133 } else if (!mo
&& !tvisnil(mo
= lj_meta_lookup(L
, o
, MM_tostring
))) {
134 /* Call __tostring metamethod inline. */
135 copyTV(L
, L
->top
++, mo
);
136 copyTV(L
, L
->top
++, o
);
138 o
= &L
->base
[arg
]; /* The stack may have been reallocated. */
139 copyTV(L
, &L
->base
[arg
], L
->top
-1);
140 L
->top
= L
->base
+ narg
;
141 goto retry
; /* Retry with the result. */
143 lj_err_argtype(L
, (int)(arg
+1), "string/number/__tostring");
145 /* Probably not useful to inline other __tostring MMs, e.g. FFI numbers. */
147 L
->top
= L
->base
+1; /* Chain buffer object. */
152 LJLIB_CF(buffer_method_putf
) LJLIB_REC(.)
154 SBufExt
*sbx
= buffer_tobufw(L
);
155 lj_strfmt_putarg(L
, (SBuf
*)sbx
, 2, 2);
156 L
->top
= L
->base
+1; /* Chain buffer object. */
161 LJLIB_CF(buffer_method_get
) LJLIB_REC(.)
163 SBufExt
*sbx
= buffer_tobuf(L
);
164 ptrdiff_t arg
, narg
= L
->top
- L
->base
;
167 setnilV(L
->top
++); /* get() is the same as get(nil). */
169 for (arg
= 1; arg
< narg
; arg
++) {
170 TValue
*o
= &L
->base
[arg
];
171 MSize n
= tvisnil(o
) ? LJ_MAX_BUF
:
172 (MSize
) lj_lib_checkintrange(L
, (int)(arg
+1), 0, LJ_MAX_BUF
);
173 MSize len
= sbufxlen(sbx
);
174 if (n
> len
) n
= len
;
175 setstrV(L
, o
, lj_str_new(L
, sbx
->r
, n
));
178 if (sbx
->r
== sbx
->w
&& !sbufiscow(sbx
)) sbx
->r
= sbx
->w
= sbx
->b
;
180 return (int)(narg
-1);
184 LJLIB_CF(buffer_method_putcdata
) LJLIB_REC(.)
186 SBufExt
*sbx
= buffer_tobufw(L
);
189 if (tviscdata(L
->base
+1)) {
190 CTState
*cts
= ctype_cts(L
);
191 lj_cconv_ct_tv(cts
, ctype_get(cts
, CTID_P_CVOID
), (uint8_t *)&p
,
192 L
->base
+1, CCF_ARG(2));
194 lj_err_argtype(L
, 2, "cdata");
196 len
= (MSize
)lj_lib_checkintrange(L
, 3, 0, LJ_MAX_BUF
);
197 lj_buf_putmem((SBuf
*)sbx
, p
, len
);
198 L
->top
= L
->base
+1; /* Chain buffer object. */
202 LJLIB_CF(buffer_method_reserve
) LJLIB_REC(.)
204 SBufExt
*sbx
= buffer_tobufw(L
);
205 MSize sz
= (MSize
)lj_lib_checkintrange(L
, 2, 0, LJ_MAX_BUF
);
207 lj_buf_more((SBuf
*)sbx
, sz
);
209 cd
= lj_cdata_new_(L
, CTID_P_UINT8
, CTSIZE_PTR
);
210 *(void **)cdataptr(cd
) = sbx
->w
;
211 setcdataV(L
, L
->top
++, cd
);
212 setintV(L
->top
++, sbufleft(sbx
));
216 LJLIB_CF(buffer_method_commit
) LJLIB_REC(.)
218 SBufExt
*sbx
= buffer_tobuf(L
);
219 MSize len
= (MSize
)lj_lib_checkintrange(L
, 2, 0, LJ_MAX_BUF
);
220 if (len
> sbufleft(sbx
)) lj_err_arg(L
, 2, LJ_ERR_NUMRNG
);
222 L
->top
= L
->base
+1; /* Chain buffer object. */
226 LJLIB_CF(buffer_method_ref
) LJLIB_REC(.)
228 SBufExt
*sbx
= buffer_tobuf(L
);
231 cd
= lj_cdata_new_(L
, CTID_P_UINT8
, CTSIZE_PTR
);
232 *(void **)cdataptr(cd
) = sbx
->r
;
233 setcdataV(L
, L
->top
++, cd
);
234 setintV(L
->top
++, sbufxlen(sbx
));
239 LJLIB_CF(buffer_method_encode
) LJLIB_REC(.)
241 SBufExt
*sbx
= buffer_tobufw(L
);
242 cTValue
*o
= lj_lib_checkany(L
, 2);
243 lj_serialize_put(sbx
, o
);
245 L
->top
= L
->base
+1; /* Chain buffer object. */
249 LJLIB_CF(buffer_method_decode
) LJLIB_REC(.)
251 SBufExt
*sbx
= buffer_tobufw(L
);
253 sbx
->r
= lj_serialize_get(sbx
, L
->top
-1);
258 LJLIB_CF(buffer_method___gc
)
260 SBufExt
*sbx
= buffer_tobuf(L
);
261 lj_bufx_free(L
, sbx
);
265 LJLIB_CF(buffer_method___tostring
) LJLIB_REC(.)
267 SBufExt
*sbx
= buffer_tobuf(L
);
268 setstrV(L
, L
->top
-1, lj_str_new(L
, sbx
->r
, sbufxlen(sbx
)));
273 LJLIB_CF(buffer_method___len
) LJLIB_REC(.)
275 SBufExt
*sbx
= buffer_tobuf(L
);
276 setintV(L
->top
-1, (int32_t)sbufxlen(sbx
));
280 LJLIB_PUSH("buffer") LJLIB_SET(__metatable
)
281 LJLIB_PUSH(top
-1) LJLIB_SET(__index
)
283 /* -- Buffer library functions -------------------------------------------- */
285 #define LJLIB_MODULE_buffer
287 LJLIB_PUSH(top
-2) LJLIB_SET(!) /* Set environment. */
293 GCtab
*env
, *dict_str
= NULL
, *dict_mt
= NULL
;
296 if (L
->base
< L
->top
&& !tvistab(L
->base
)) {
298 if (!tvisnil(L
->base
))
299 sz
= (MSize
)lj_lib_checkintrange(L
, 1, 0, LJ_MAX_BUF
);
301 if (L
->base
+targ
-1 < L
->top
) {
302 GCtab
*options
= lj_lib_checktab(L
, targ
);
303 cTValue
*opt_dict
, *opt_mt
;
304 opt_dict
= lj_tab_getstr(options
, lj_str_newlit(L
, "dict"));
305 if (opt_dict
&& tvistab(opt_dict
)) {
306 dict_str
= tabV(opt_dict
);
307 lj_serialize_dict_prep_str(L
, dict_str
);
309 opt_mt
= lj_tab_getstr(options
, lj_str_newlit(L
, "metatable"));
310 if (opt_mt
&& tvistab(opt_mt
)) {
311 dict_mt
= tabV(opt_mt
);
312 lj_serialize_dict_prep_mt(L
, dict_mt
);
315 env
= tabref(curr_func(L
)->c
.env
);
316 ud
= lj_udata_new(L
, sizeof(SBufExt
), env
);
317 ud
->udtype
= UDTYPE_BUFFER
;
318 /* NOBARRIER: The GCudata is new (marked white). */
319 setgcref(ud
->metatable
, obj2gco(env
));
320 setudataV(L
, L
->top
++, ud
);
321 sbx
= (SBufExt
*)uddata(ud
);
322 lj_bufx_init(L
, sbx
);
323 setgcref(sbx
->dict_str
, obj2gco(dict_str
));
324 setgcref(sbx
->dict_mt
, obj2gco(dict_mt
));
325 if (sz
> 0) lj_buf_need2((SBuf
*)sbx
, sz
);
330 LJLIB_CF(buffer_encode
) LJLIB_REC(.)
332 cTValue
*o
= lj_lib_checkany(L
, 1);
333 setstrV(L
, L
->top
++, lj_serialize_encode(L
, o
));
338 LJLIB_CF(buffer_decode
) LJLIB_REC(.)
340 GCstr
*str
= lj_lib_checkstrx(L
, 1);
342 lj_serialize_decode(L
, L
->top
-1, str
);
347 /* ------------------------------------------------------------------------ */
349 #include "lj_libdef.h"
351 int luaopen_string_buffer(lua_State
*L
)
353 LJ_LIB_REG(L
, NULL
, buffer_method
);
354 lua_getfield(L
, -1, "__tostring");
355 lua_setfield(L
, -2, "tostring");
356 LJ_LIB_REG(L
, NULL
, buffer
);