String buffers, part 2d: basic string buffer methods.

Sponsored by fmad.io.
This commit is contained in:
Mike Pall
2021-06-01 05:16:32 +02:00
parent edd5cbadc5
commit a119497bec
18 changed files with 816 additions and 85 deletions

View File

@@ -2,17 +2,18 @@ lib_aux.o: lib_aux.c lua.h luaconf.h lauxlib.h lj_obj.h lj_def.h \
lj_arch.h lj_err.h lj_errmsg.h lj_state.h lj_trace.h lj_jit.h lj_ir.h \
lj_dispatch.h lj_bc.h lj_traceerr.h lj_lib.h
lib_base.o: lib_base.c lua.h luaconf.h lauxlib.h lualib.h lj_obj.h \
lj_def.h lj_arch.h lj_gc.h lj_err.h lj_errmsg.h lj_debug.h lj_str.h \
lj_tab.h lj_meta.h lj_state.h lj_frame.h lj_bc.h lj_ctype.h lj_cconv.h \
lj_ff.h lj_ffdef.h lj_dispatch.h lj_jit.h lj_ir.h lj_char.h lj_strscan.h \
lj_strfmt.h lj_lib.h lj_libdef.h
lj_def.h lj_arch.h lj_gc.h lj_err.h lj_errmsg.h lj_debug.h lj_buf.h \
lj_str.h lj_tab.h lj_meta.h lj_state.h lj_frame.h lj_bc.h lj_ctype.h \
lj_cconv.h lj_ff.h lj_ffdef.h lj_dispatch.h lj_jit.h lj_ir.h lj_char.h \
lj_strscan.h lj_strfmt.h lj_lib.h lj_libdef.h
lib_bit.o: lib_bit.c lua.h luaconf.h lauxlib.h lualib.h lj_obj.h lj_def.h \
lj_arch.h lj_err.h lj_errmsg.h lj_buf.h lj_gc.h lj_str.h lj_strscan.h \
lj_strfmt.h lj_ctype.h lj_cdata.h lj_cconv.h lj_carith.h lj_ff.h \
lj_ffdef.h lj_lib.h lj_libdef.h
lib_buffer.o: lib_buffer.c lua.h luaconf.h lauxlib.h lualib.h lj_obj.h \
lj_def.h lj_arch.h lj_gc.h lj_buf.h lj_str.h lj_serialize.h lj_lib.h \
lj_libdef.h
lj_def.h lj_arch.h lj_gc.h lj_err.h lj_errmsg.h lj_buf.h lj_str.h \
lj_tab.h lj_udata.h lj_meta.h lj_ctype.h lj_cdata.h lj_cconv.h \
lj_strfmt.h lj_serialize.h lj_lib.h lj_libdef.h
lib_debug.o: lib_debug.c lua.h luaconf.h lauxlib.h lualib.h lj_obj.h \
lj_def.h lj_arch.h lj_gc.h lj_err.h lj_errmsg.h lj_debug.h lj_lib.h \
lj_libdef.h
@@ -51,10 +52,10 @@ lj_api.o: lj_api.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_gc.h \
lj_meta.h lj_state.h lj_bc.h lj_frame.h lj_trace.h lj_jit.h lj_ir.h \
lj_dispatch.h lj_traceerr.h lj_vm.h lj_strscan.h lj_strfmt.h
lj_asm.o: lj_asm.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_gc.h \
lj_str.h lj_tab.h lj_frame.h lj_bc.h lj_ctype.h lj_ir.h lj_jit.h \
lj_ircall.h lj_iropt.h lj_mcode.h lj_trace.h lj_dispatch.h lj_traceerr.h \
lj_snap.h lj_asm.h lj_vm.h lj_target.h lj_target_*.h lj_emit_*.h \
lj_asm_*.h
lj_buf.h lj_str.h lj_tab.h lj_frame.h lj_bc.h lj_ctype.h lj_ir.h \
lj_jit.h lj_ircall.h lj_iropt.h lj_mcode.h lj_trace.h lj_dispatch.h \
lj_traceerr.h lj_snap.h lj_asm.h lj_vm.h lj_target.h lj_target_*.h \
lj_emit_*.h lj_asm_*.h
lj_assert.o: lj_assert.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h
lj_bc.o: lj_bc.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_bc.h \
lj_bcdef.h
@@ -80,8 +81,8 @@ lj_ccallback.o: lj_ccallback.c lj_obj.h lua.h luaconf.h lj_def.h \
lj_target_*.h lj_mcode.h lj_jit.h lj_ir.h lj_trace.h lj_dispatch.h \
lj_traceerr.h lj_vm.h
lj_cconv.o: lj_cconv.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
lj_err.h lj_errmsg.h lj_tab.h lj_ctype.h lj_gc.h lj_cdata.h lj_cconv.h \
lj_ccallback.h
lj_err.h lj_errmsg.h lj_buf.h lj_gc.h lj_str.h lj_tab.h lj_ctype.h \
lj_cdata.h lj_cconv.h lj_ccallback.h
lj_cdata.o: lj_cdata.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h \
lj_gc.h lj_err.h lj_errmsg.h lj_tab.h lj_ctype.h lj_cconv.h lj_cdata.h
lj_char.o: lj_char.c lj_char.h lj_def.h lua.h luaconf.h
@@ -137,8 +138,8 @@ lj_lex.o: lj_lex.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_gc.h \
lj_strfmt.h
lj_lib.o: lj_lib.c lauxlib.h lua.h luaconf.h lj_obj.h lj_def.h lj_arch.h \
lj_gc.h lj_err.h lj_errmsg.h lj_str.h lj_tab.h lj_func.h lj_bc.h \
lj_dispatch.h lj_jit.h lj_ir.h lj_vm.h lj_strscan.h lj_strfmt.h lj_lex.h \
lj_bcdump.h lj_lib.h
lj_dispatch.h lj_jit.h lj_ir.h lj_ctype.h lj_vm.h lj_strscan.h \
lj_strfmt.h lj_lex.h lj_bcdump.h lj_lib.h
lj_load.o: lj_load.c lua.h luaconf.h lauxlib.h lj_obj.h lj_def.h \
lj_arch.h lj_gc.h lj_err.h lj_errmsg.h lj_buf.h lj_str.h lj_func.h \
lj_frame.h lj_bc.h lj_vm.h lj_lex.h lj_bcdump.h lj_parse.h

View File

@@ -19,6 +19,7 @@
#include "lj_gc.h"
#include "lj_err.h"
#include "lj_debug.h"
#include "lj_buf.h"
#include "lj_str.h"
#include "lj_tab.h"
#include "lj_meta.h"
@@ -406,10 +407,22 @@ LJLIB_CF(load)
GCstr *name = lj_lib_optstr(L, 2);
GCstr *mode = lj_lib_optstr(L, 3);
int status;
if (L->base < L->top && (tvisstr(L->base) || tvisnumber(L->base))) {
GCstr *s = lj_lib_checkstr(L, 1);
if (L->base < L->top &&
(tvisstr(L->base) || tvisnumber(L->base) || tvisbuf(L->base))) {
const char *s;
MSize len;
if (tvisbuf(L->base)) {
SBufExt *sbx = bufV(L->base);
s = sbx->r;
len = sbufxlen(sbx);
if (!name) name = &G(L)->strempty; /* Buffers are not NUL-terminated. */
} else {
GCstr *str = lj_lib_checkstr(L, 1);
s = strdata(str);
len = str->len;
}
lua_settop(L, 4); /* Ensure env arg exists. */
status = luaL_loadbufferx(L, strdata(s), s->len, strdata(name ? name : s),
status = luaL_loadbufferx(L, s, len, name ? strdata(name) : s,
mode ? strdata(mode) : NULL);
} else {
lj_lib_checkfunc(L, 1);

View File

@@ -14,14 +14,286 @@
#if LJ_HASBUFFER
#include "lj_gc.h"
#include "lj_err.h"
#include "lj_buf.h"
#include "lj_str.h"
#include "lj_tab.h"
#include "lj_udata.h"
#include "lj_meta.h"
#if LJ_HASFFI
#include "lj_ctype.h"
#include "lj_cdata.h"
#include "lj_cconv.h"
#endif
#include "lj_strfmt.h"
#include "lj_serialize.h"
#include "lj_lib.h"
/* ------------------------------------------------------------------------ */
#define LJLIB_MODULE_buffer_method
/* Check that the first argument is a string buffer. */
static SBufExt *buffer_tobuf(lua_State *L)
{
if (!(L->base < L->top && tvisbuf(L->base)))
lj_err_argtype(L, 1, "buffer");
return bufV(L->base);
}
/* Ditto, but for writers. */
static LJ_AINLINE SBufExt *buffer_tobufw(lua_State *L)
{
SBufExt *sbx = buffer_tobuf(L);
setsbufXL_(sbx, L);
return sbx;
}
LJLIB_CF(buffer_method_free)
{
SBufExt *sbx = buffer_tobuf(L);
lj_bufx_free(G(L), sbx);
lj_bufx_init(L, sbx);
L->top = L->base+1; /* Chain buffer object. */
return 1;
}
LJLIB_CF(buffer_method_reset)
{
SBufExt *sbx = buffer_tobuf(L);
lj_bufx_reset(sbx);
L->top = L->base+1; /* Chain buffer object. */
return 1;
}
LJLIB_CF(buffer_method_skip)
{
SBufExt *sbx = buffer_tobuf(L);
MSize n = (MSize)lj_lib_checkintrange(L, 2, 0, LJ_MAX_BUF);
MSize len = sbufxlen(sbx);
if (n < len) {
sbx->r += n;
} else {
sbx->r = sbx->w = sbx->b;
}
L->top = L->base+1; /* Chain buffer object. */
return 1;
}
LJLIB_CF(buffer_method_set)
{
SBufExt *sbx = buffer_tobuf(L);
const char *p;
MSize len;
#if LJ_HASFFI
if (tviscdata(L->base+1)) {
CTState *cts = ctype_cts(L);
lj_cconv_ct_tv(cts, ctype_get(cts, CTID_P_CVOID), (uint8_t *)&p,
L->base+1, CCF_ARG(2));
len = (MSize)lj_lib_checkintrange(L, 3, 0, LJ_MAX_BUF);
} else
#endif
{
GCstr *str = lj_lib_checkstrx(L, 2);
p = strdata(str);
len = str->len;
}
lj_bufx_free(G(L), sbx);
lj_bufx_init_cow(L, sbx, p, len);
setgcref(sbx->cowref, gcV(L->base+1));
L->top = L->base+1; /* Chain buffer object. */
return 1;
}
LJLIB_CF(buffer_method_put)
{
SBufExt *sbx = buffer_tobufw(L);
ptrdiff_t arg, narg = L->top - L->base;
for (arg = 1; arg < narg; arg++) {
cTValue *o = &L->base[arg], *mo = NULL;
retry:
if (tvisstr(o)) {
lj_buf_putstr((SBuf *)sbx, strV(o));
} else if (tvisint(o)) {
lj_strfmt_putint((SBuf *)sbx, intV(o));
} else if (tvisnum(o)) {
lj_strfmt_putfnum((SBuf *)sbx, STRFMT_G14, numV(o));
} else if (tvisbuf(o)) {
SBufExt *sbx2 = bufV(o);
lj_buf_putmem((SBuf *)sbx, sbx2->r, sbufxlen(sbx2));
} else if (!mo && !tvisnil(mo = lj_meta_lookup(L, o, MM_tostring))) {
/* Call __tostring metamethod inline. */
copyTV(L, L->top++, mo);
copyTV(L, L->top++, o);
lua_call(L, 1, 1);
o = &L->base[arg]; /* The stack may have been reallocated. */
copyTV(L, &L->base[arg], L->top-1);
L->top = L->base + narg;
goto retry; /* Retry with the result. */
} else {
lj_err_argtype(L, arg+1, "string/number/__tostring");
}
/* Probably not useful to inline other __tostring MMs, e.g. FFI numbers. */
}
L->top = L->base+1; /* Chain buffer object. */
lj_gc_check(L);
return 1;
}
LJLIB_CF(buffer_method_putf)
{
SBufExt *sbx = buffer_tobufw(L);
lj_strfmt_putarg(L, (SBuf *)sbx, 2, 2);
L->top = L->base+1; /* Chain buffer object. */
lj_gc_check(L);
return 1;
}
LJLIB_CF(buffer_method_get)
{
SBufExt *sbx = buffer_tobuf(L);
ptrdiff_t arg, narg = L->top - L->base;
if (narg == 1) {
narg++;
setnilV(L->top++); /* get() is the same as get(nil). */
}
for (arg = 1; arg < narg; arg++) {
TValue *o = &L->base[arg];
MSize n = tvisnil(o) ? LJ_MAX_BUF :
(MSize) lj_lib_checkintrange(L, arg+1, 0, LJ_MAX_BUF);
MSize len = sbufxlen(sbx);
if (n > len) n = len;
setstrV(L, o, lj_str_new(L, sbx->r, n));
sbx->r += n;
}
if (sbx->r == sbx->w) sbx->r = sbx->w = sbx->b;
lj_gc_check(L);
return narg-1;
}
#if LJ_HASFFI
LJLIB_CF(buffer_method_putcdata)
{
SBufExt *sbx = buffer_tobufw(L);
const char *p;
MSize len;
if (tviscdata(L->base+1)) {
CTState *cts = ctype_cts(L);
lj_cconv_ct_tv(cts, ctype_get(cts, CTID_P_CVOID), (uint8_t *)&p,
L->base+1, CCF_ARG(2));
} else {
lj_err_argtype(L, 2, "cdata");
}
len = (MSize)lj_lib_checkintrange(L, 3, 0, LJ_MAX_BUF);
lj_buf_putmem((SBuf *)sbx, p, len);
L->top = L->base+1; /* Chain buffer object. */
return 1;
}
LJLIB_CF(buffer_method_reserve)
{
SBufExt *sbx = buffer_tobufw(L);
MSize len = (MSize)lj_lib_checkintrange(L, 2, 0, LJ_MAX_BUF);
GCcdata *cd;
lj_buf_more((SBuf *)sbx, len);
ctype_loadffi(L);
cd = lj_cdata_new_(L, CTID_P_UINT8, CTSIZE_PTR);
*(void **)cdataptr(cd) = sbx->w;
setcdataV(L, L->top++, cd);
setintV(L->top++, sbufleft(sbx));
return 2;
}
LJLIB_CF(buffer_method_commit)
{
SBufExt *sbx = buffer_tobuf(L);
MSize len = (MSize)lj_lib_checkintrange(L, 2, 0, LJ_MAX_BUF);
if (len > sbufleft(sbx)) lj_err_arg(L, 2, LJ_ERR_NUMRNG);
sbx->w += len;
L->top = L->base+1; /* Chain buffer object. */
return 1;
}
LJLIB_CF(buffer_method_ref)
{
SBufExt *sbx = buffer_tobuf(L);
GCcdata *cd;
ctype_loadffi(L);
cd = lj_cdata_new_(L, CTID_P_UINT8, CTSIZE_PTR);
*(void **)cdataptr(cd) = sbx->r;
setcdataV(L, L->top++, cd);
setintV(L->top++, sbufxlen(sbx));
return 2;
}
#endif
LJLIB_CF(buffer_method_encode)
{
SBufExt *sbx = buffer_tobufw(L);
cTValue *o = lj_lib_checkany(L, 2);
lj_serialize_put(sbx, o);
lj_gc_check(L);
L->top = L->base+1; /* Chain buffer object. */
return 1;
}
LJLIB_CF(buffer_method_decode)
{
SBufExt *sbx = buffer_tobufw(L);
setnilV(L->top++);
lj_serialize_get(sbx, L->top-1);
lj_gc_check(L);
return 1;
}
LJLIB_CF(buffer_method___gc)
{
SBufExt *sbx = buffer_tobuf(L);
lj_bufx_free(G(L), sbx);
lj_bufx_init(L, sbx);
return 0;
}
LJLIB_CF(buffer_method___tostring)
{
SBufExt *sbx = buffer_tobuf(L);
setstrV(L, L->top-1, lj_str_new(L, sbx->r, sbufxlen(sbx)));
lj_gc_check(L);
return 1;
}
LJLIB_CF(buffer_method___len)
{
SBufExt *sbx = buffer_tobuf(L);
setintV(L->top-1, (int32_t)sbufxlen(sbx));
return 1;
}
LJLIB_PUSH("buffer") LJLIB_SET(__metatable)
LJLIB_PUSH(top-1) LJLIB_SET(__index)
/* ------------------------------------------------------------------------ */
#define LJLIB_MODULE_buffer
LJLIB_PUSH(top-2) LJLIB_SET(!) /* Set environment. */
LJLIB_CF(buffer_new)
{
MSize sz = L->base == L->top ? 0u :
(MSize)lj_lib_checkintrange(L, 1, 0, LJ_MAX_BUF);
GCtab *env = tabref(curr_func(L)->c.env);
GCudata *ud = lj_udata_new(L, sizeof(SBufExt), env);
SBufExt *sbx = (SBufExt *)uddata(ud);
ud->udtype = UDTYPE_BUFFER;
/* NOBARRIER: The GCudata is new (marked white). */
setgcref(ud->metatable, obj2gco(env));
setudataV(L, L->top++, ud);
lj_bufx_init(L, sbx);
if (sz > 0) lj_buf_need2((SBuf *)sbx, sz);
return 1;
}
LJLIB_CF(buffer_encode)
{
cTValue *o = lj_lib_checkany(L, 1);
@@ -35,13 +307,14 @@ LJLIB_CF(buffer_encode)
LJLIB_CF(buffer_decode)
{
GCstr *str = lj_lib_checkstr(L, 1);
GCstr *str = lj_lib_checkstrx(L, 1);
SBufExt sbx;
lj_bufx_init_cow(L, &sbx, strdata(str), str->len);
/* No need to set sbx.cowref here. */
setnilV(L->top++);
lj_serialize_get(&sbx, L->top-1);
lj_gc_check(L);
if (sbx.r != sbx.w) lj_err_caller(L, LJ_ERR_BUFFER_LEFTOV);
return 1;
}
@@ -51,6 +324,9 @@ LJLIB_CF(buffer_decode)
int luaopen_string_buffer(lua_State *L)
{
LJ_LIB_REG(L, NULL, buffer_method);
lua_getfield(L, -1, "__tostring");
lua_setfield(L, -2, "tostring");
LJ_LIB_REG(L, NULL, buffer);
return 1;
}

View File

@@ -11,6 +11,7 @@
#if LJ_HASJIT
#include "lj_gc.h"
#include "lj_buf.h"
#include "lj_str.h"
#include "lj_tab.h"
#include "lj_frame.h"

View File

@@ -58,6 +58,10 @@ typedef struct SBufExt {
(lj_assertG_(G(sbufL(sb)), sbufisext(sb), "not an SBufExt"), (SBufExt *)(sb))
#define setsbufflag(sb, flag) (setmrefu((sb)->L, (flag)))
#define tvisbuf(o) \
(LJ_HASBUFFER && tvisudata(o) && udataV(o)->udtype == UDTYPE_BUFFER)
#define bufV(o) check_exp(tvisbuf(o), ((SBufExt *)uddata(udataV(o))))
/* Buffer management */
LJ_FUNC char *LJ_FASTCALL lj_buf_need2(SBuf *sb, MSize sz);
LJ_FUNC char *LJ_FASTCALL lj_buf_more2(SBuf *sb, MSize sz);

View File

@@ -8,6 +8,7 @@
#if LJ_HASFFI
#include "lj_err.h"
#include "lj_buf.h"
#include "lj_tab.h"
#include "lj_ctype.h"
#include "lj_cdata.h"
@@ -621,6 +622,8 @@ void lj_cconv_ct_tv(CTState *cts, CType *d,
tmpptr = uddata(ud);
if (ud->udtype == UDTYPE_IO_FILE)
tmpptr = *(void **)tmpptr;
else if (ud->udtype == UDTYPE_BUFFER)
tmpptr = ((SBufExt *)tmpptr)->r;
} else if (tvislightud(o)) {
tmpptr = lightudV(cts->g, o);
} else if (tvisfunc(o)) {

View File

@@ -616,10 +616,12 @@ static TRef crec_ct_tv(jit_State *J, CType *d, TRef dp, TRef sp, cTValue *sval)
sp = lj_ir_kptr(J, NULL);
} else if (tref_isudata(sp)) {
GCudata *ud = udataV(sval);
if (ud->udtype == UDTYPE_IO_FILE) {
if (ud->udtype == UDTYPE_IO_FILE || ud->udtype == UDTYPE_BUFFER) {
TRef tr = emitir(IRT(IR_FLOAD, IRT_U8), sp, IRFL_UDATA_UDTYPE);
emitir(IRTGI(IR_EQ), tr, lj_ir_kint(J, UDTYPE_IO_FILE));
sp = emitir(IRT(IR_FLOAD, IRT_PTR), sp, IRFL_UDATA_FILE);
emitir(IRTGI(IR_EQ), tr, lj_ir_kint(J, ud->udtype));
sp = emitir(IRT(IR_FLOAD, IRT_PTR), sp,
ud->udtype == UDTYPE_IO_FILE ? IRFL_UDATA_FILE :
IRFL_UDATA_BUF_R);
} else {
sp = emitir(IRT(IR_ADD, IRT_PTR), sp, lj_ir_kintp(J, sizeof(GCudata)));
}

View File

@@ -298,6 +298,7 @@ typedef struct CTState {
_(P_VOID, CTSIZE_PTR, CT_PTR, CTALIGN_PTR|CTID_VOID) \
_(P_CVOID, CTSIZE_PTR, CT_PTR, CTALIGN_PTR|CTID_CVOID) \
_(P_CCHAR, CTSIZE_PTR, CT_PTR, CTALIGN_PTR|CTID_CCHAR) \
_(P_UINT8, CTSIZE_PTR, CT_PTR, CTALIGN_PTR|CTID_UINT8) \
_(A_CCHAR, -1, CT_ARRAY, CTF_CONST|CTALIGN(0)|CTID_CCHAR) \
_(CTYPEID, 4, CT_ENUM, CTALIGN(2)|CTID_INT32) \
CTTYDEFP(_) \

View File

@@ -67,6 +67,7 @@ ERRDEF(PROTMT, "cannot change a protected metatable")
ERRDEF(UNPACK, "too many results to unpack")
ERRDEF(RDRSTR, "reader function must return a string")
ERRDEF(PRTOSTR, LUA_QL("tostring") " must return a string to " LUA_QL("print"))
ERRDEF(NUMRNG, "number out of range")
ERRDEF(IDXRNG, "index out of range")
ERRDEF(BASERNG, "base out of range")
ERRDEF(LVLRNG, "level out of range")

View File

@@ -65,6 +65,12 @@ static void gc_mark(global_State *g, GCobj *o)
gray2black(o); /* Userdata are never gray. */
if (mt) gc_markobj(g, mt);
gc_markobj(g, tabref(gco2ud(o)->env));
if (LJ_HASBUFFER && gco2ud(o)->udtype == UDTYPE_BUFFER) {
SBufExt *sbx = (SBufExt *)uddata(gco2ud(o));
if (sbufiscow(sbx) && gcref(sbx->cowref) != NULL) {
gc_markobj(g, gcref(sbx->cowref));
}
}
} else if (LJ_UNLIKELY(gct == ~LJ_TUPVAL)) {
GCupval *uv = gco2uv(o);
gc_marktv(g, uvval(uv));

View File

@@ -204,6 +204,7 @@ IRFPMDEF(FPMENUM)
_(UDATA_META, offsetof(GCudata, metatable)) \
_(UDATA_UDTYPE, offsetof(GCudata, udtype)) \
_(UDATA_FILE, sizeof(GCudata)) \
_(UDATA_BUF_R, sizeof(GCudata) + offsetof(SBufExt, r)) \
_(CDATA_CTYPEID, offsetof(GCcdata, ctypeid)) \
_(CDATA_PTR, sizeof(GCcdata)) \
_(CDATA_INT, sizeof(GCcdata)) \

View File

@@ -16,6 +16,9 @@
#include "lj_func.h"
#include "lj_bc.h"
#include "lj_dispatch.h"
#if LJ_HASFFI
#include "lj_ctype.h"
#endif
#include "lj_vm.h"
#include "lj_strscan.h"
#include "lj_strfmt.h"
@@ -301,3 +304,54 @@ int lj_lib_checkopt(lua_State *L, int narg, int def, const char *lst)
return def;
}
/* -- Strict type checks -------------------------------------------------- */
/* The following type checks do not coerce between strings and numbers.
** And they handle plain int64_t/uint64_t FFI numbers, too.
*/
#if LJ_HASBUFFER
GCstr *lj_lib_checkstrx(lua_State *L, int narg)
{
TValue *o = L->base + narg-1;
if (!(o < L->top && tvisstr(o))) lj_err_argt(L, narg, LUA_TSTRING);
return strV(o);
}
int32_t lj_lib_checkintrange(lua_State *L, int narg, int32_t a, int32_t b)
{
TValue *o = L->base + narg-1;
lj_assertL(b >= 0, "expected range must be non-negative");
if (o < L->top) {
if (LJ_LIKELY(tvisint(o))) {
int32_t i = intV(o);
if (i >= a && i <= b) return i;
} else if (LJ_LIKELY(tvisnum(o))) {
/* For performance reasons, this doesn't check for integerness or
** integer overflow. Overflow detection still works, since all FPUs
** return either MININT or MAXINT, which is then out of range.
*/
int32_t i = (int32_t)numV(o);
if (i >= a && i <= b) return i;
#if LJ_HASFFI
} else if (tviscdata(o)) {
GCcdata *cd = cdataV(o);
if (cd->ctypeid == CTID_INT64) {
int64_t i = *(int64_t *)cdataptr(cd);
if (i >= (int64_t)a && i <= (int64_t)b) return (int32_t)i;
} else if (cd->ctypeid == CTID_UINT64) {
uint64_t i = *(uint64_t *)cdataptr(cd);
if ((a < 0 || i >= (uint64_t)a) && i <= (uint64_t)b) return (int32_t)i;
}
#endif
} else {
goto badtype;
}
lj_err_arg(L, narg, LJ_ERR_NUMRNG);
}
badtype:
lj_err_argt(L, narg, LUA_TNUMBER);
return 0; /* unreachable */
}
#endif

View File

@@ -46,6 +46,12 @@ LJ_FUNC GCtab *lj_lib_checktab(lua_State *L, int narg);
LJ_FUNC GCtab *lj_lib_checktabornil(lua_State *L, int narg);
LJ_FUNC int lj_lib_checkopt(lua_State *L, int narg, int def, const char *lst);
#if LJ_HASBUFFER
LJ_FUNC GCstr *lj_lib_checkstrx(lua_State *L, int narg);
LJ_FUNC int32_t lj_lib_checkintrange(lua_State *L, int narg,
int32_t a, int32_t b);
#endif
/* Avoid including lj_frame.h. */
#if LJ_GC64
#define lj_lib_upvalue(L, n) \

View File

@@ -240,8 +240,8 @@ TValue *lj_meta_cat(lua_State *L, TValue *top, int left)
int fromc = 0;
if (left < 0) { left = -left; fromc = 1; }
do {
if (!(tvisstr(top) || tvisnumber(top)) ||
!(tvisstr(top-1) || tvisnumber(top-1))) {
if (!(tvisstr(top) || tvisnumber(top) || tvisbuf(top)) ||
!(tvisstr(top-1) || tvisnumber(top-1) || tvisbuf(top-1))) {
cTValue *mo = lj_meta_lookup(L, top-1, MM_concat);
if (tvisnil(mo)) {
mo = lj_meta_lookup(L, top, MM_concat);
@@ -277,10 +277,12 @@ TValue *lj_meta_cat(lua_State *L, TValue *top, int left)
** next step: [...][CAT stack ............]
*/
TValue *e, *o = top;
uint64_t tlen = tvisstr(o) ? strV(o)->len : STRFMT_MAXBUF_NUM;
uint64_t tlen = tvisstr(o) ? strV(o)->len :
tvisbuf(o) ? sbufxlen(bufV(o)) : STRFMT_MAXBUF_NUM;
SBuf *sb;
do {
o--; tlen += tvisstr(o) ? strV(o)->len : STRFMT_MAXBUF_NUM;
o--; tlen += tvisstr(o) ? strV(o)->len :
tvisbuf(o) ? sbufxlen(bufV(o)) : STRFMT_MAXBUF_NUM;
} while (--left > 0 && (tvisstr(o-1) || tvisnumber(o-1)));
if (tlen >= LJ_MAX_STR) lj_err_msg(L, LJ_ERR_STROV);
sb = lj_buf_tmp_(L);
@@ -290,6 +292,9 @@ TValue *lj_meta_cat(lua_State *L, TValue *top, int left)
GCstr *s = strV(o);
MSize len = s->len;
lj_buf_putmem(sb, strdata(s), len);
} else if (tvisbuf(o)) {
SBufExt *sbx = bufV(o);
lj_buf_putmem(sb, sbx->r, sbufxlen(sbx));
} else if (tvisint(o)) {
lj_strfmt_putint(sb, intV(o));
} else {

View File

@@ -332,6 +332,7 @@ enum {
UDTYPE_USERDATA, /* Regular userdata. */
UDTYPE_IO_FILE, /* I/O library FILE. */
UDTYPE_FFI_CLIB, /* FFI C library namespace. */
UDTYPE_BUFFER, /* String buffer. */
UDTYPE__MAX
};

View File

@@ -346,10 +346,7 @@ SBufExt * LJ_FASTCALL lj_serialize_put(SBufExt *sbx, cTValue *o)
SBufExt * LJ_FASTCALL lj_serialize_get(SBufExt *sbx, TValue *o)
{
char *r = serialize_get(sbx->r, sbx, o);
if (r != sbx->w)
lj_err_caller(sbufL(sbx), LJ_ERR_BUFFER_LEFTOV);
sbx->r = r;
sbx->r = serialize_get(sbx->r, sbx, o);
return sbx;
}

View File

@@ -164,6 +164,10 @@ const char *lj_strfmt_wstrnum(lua_State *L, cTValue *o, MSize *lenp)
if (tvisstr(o)) {
*lenp = strV(o)->len;
return strVdata(o);
} else if (tvisbuf(o)) {
SBufExt *sbx = bufV(o);
*lenp = sbufxlen(sbx);
return sbx->r;
} else if (tvisint(o)) {
sb = lj_strfmt_putint(lj_buf_tmp_(L), intV(o));
} else if (tvisnum(o)) {
@@ -421,6 +425,10 @@ int lj_strfmt_putarg(lua_State *L, SBuf *sb, int arg, int retry)
if (LJ_LIKELY(tvisstr(o))) {
len = strV(o)->len;
s = strVdata(o);
} else if (tvisbuf(o)) {
SBufExt *sbx = bufV(o);
len = sbufxlen(sbx);
s = sbx->r;
} else {
GCstr *str = lj_strfmt_obj(L, o);
len = str->len;