diff options
| author | Mike Pall <mike> | 2021-06-01 05:16:32 +0200 |
|---|---|---|
| committer | Mike Pall <mike> | 2021-06-01 05:16:32 +0200 |
| commit | a119497becdf2894fb7fa737f106464309dd7947 (patch) | |
| tree | 95c7f88198ba3f12eff52fd5646207ffb31da2d5 /src/lib_buffer.c | |
| parent | edd5cbadc5cdc7b5b66d5340ee97c5abe5a3892a (diff) | |
| download | luajit-a119497becdf2894fb7fa737f106464309dd7947.tar.gz luajit-a119497becdf2894fb7fa737f106464309dd7947.tar.bz2 luajit-a119497becdf2894fb7fa737f106464309dd7947.zip | |
String buffers, part 2d: basic string buffer methods.
Sponsored by fmad.io.
Diffstat (limited to 'src/lib_buffer.c')
| -rw-r--r-- | src/lib_buffer.c | 278 |
1 files changed, 277 insertions, 1 deletions
diff --git a/src/lib_buffer.c b/src/lib_buffer.c index c9ef9510e..78c4eeb94 100644 --- a/src/lib_buffer.c +++ b/src/lib_buffer.c | |||
| @@ -14,14 +14,286 @@ | |||
| 14 | 14 | ||
| 15 | #if LJ_HASBUFFER | 15 | #if LJ_HASBUFFER |
| 16 | #include "lj_gc.h" | 16 | #include "lj_gc.h" |
| 17 | #include "lj_err.h" | ||
| 17 | #include "lj_buf.h" | 18 | #include "lj_buf.h" |
| 19 | #include "lj_str.h" | ||
| 20 | #include "lj_tab.h" | ||
| 21 | #include "lj_udata.h" | ||
| 22 | #include "lj_meta.h" | ||
| 23 | #if LJ_HASFFI | ||
| 24 | #include "lj_ctype.h" | ||
| 25 | #include "lj_cdata.h" | ||
| 26 | #include "lj_cconv.h" | ||
| 27 | #endif | ||
| 28 | #include "lj_strfmt.h" | ||
| 18 | #include "lj_serialize.h" | 29 | #include "lj_serialize.h" |
| 19 | #include "lj_lib.h" | 30 | #include "lj_lib.h" |
| 20 | 31 | ||
| 21 | /* ------------------------------------------------------------------------ */ | 32 | /* ------------------------------------------------------------------------ */ |
| 22 | 33 | ||
| 34 | #define LJLIB_MODULE_buffer_method | ||
| 35 | |||
| 36 | /* Check that the first argument is a string buffer. */ | ||
| 37 | static SBufExt *buffer_tobuf(lua_State *L) | ||
| 38 | { | ||
| 39 | if (!(L->base < L->top && tvisbuf(L->base))) | ||
| 40 | lj_err_argtype(L, 1, "buffer"); | ||
| 41 | return bufV(L->base); | ||
| 42 | } | ||
| 43 | |||
| 44 | /* Ditto, but for writers. */ | ||
| 45 | static LJ_AINLINE SBufExt *buffer_tobufw(lua_State *L) | ||
| 46 | { | ||
| 47 | SBufExt *sbx = buffer_tobuf(L); | ||
| 48 | setsbufXL_(sbx, L); | ||
| 49 | return sbx; | ||
| 50 | } | ||
| 51 | |||
| 52 | LJLIB_CF(buffer_method_free) | ||
| 53 | { | ||
| 54 | SBufExt *sbx = buffer_tobuf(L); | ||
| 55 | lj_bufx_free(G(L), sbx); | ||
| 56 | lj_bufx_init(L, sbx); | ||
| 57 | L->top = L->base+1; /* Chain buffer object. */ | ||
| 58 | return 1; | ||
| 59 | } | ||
| 60 | |||
| 61 | LJLIB_CF(buffer_method_reset) | ||
| 62 | { | ||
| 63 | SBufExt *sbx = buffer_tobuf(L); | ||
| 64 | lj_bufx_reset(sbx); | ||
| 65 | L->top = L->base+1; /* Chain buffer object. */ | ||
| 66 | return 1; | ||
| 67 | } | ||
| 68 | |||
| 69 | LJLIB_CF(buffer_method_skip) | ||
| 70 | { | ||
| 71 | SBufExt *sbx = buffer_tobuf(L); | ||
| 72 | MSize n = (MSize)lj_lib_checkintrange(L, 2, 0, LJ_MAX_BUF); | ||
| 73 | MSize len = sbufxlen(sbx); | ||
| 74 | if (n < len) { | ||
| 75 | sbx->r += n; | ||
| 76 | } else { | ||
| 77 | sbx->r = sbx->w = sbx->b; | ||
| 78 | } | ||
| 79 | L->top = L->base+1; /* Chain buffer object. */ | ||
| 80 | return 1; | ||
| 81 | } | ||
| 82 | |||
| 83 | LJLIB_CF(buffer_method_set) | ||
| 84 | { | ||
| 85 | SBufExt *sbx = buffer_tobuf(L); | ||
| 86 | const char *p; | ||
| 87 | MSize len; | ||
| 88 | #if LJ_HASFFI | ||
| 89 | if (tviscdata(L->base+1)) { | ||
| 90 | CTState *cts = ctype_cts(L); | ||
| 91 | lj_cconv_ct_tv(cts, ctype_get(cts, CTID_P_CVOID), (uint8_t *)&p, | ||
| 92 | L->base+1, CCF_ARG(2)); | ||
| 93 | len = (MSize)lj_lib_checkintrange(L, 3, 0, LJ_MAX_BUF); | ||
| 94 | } else | ||
| 95 | #endif | ||
| 96 | { | ||
| 97 | GCstr *str = lj_lib_checkstrx(L, 2); | ||
| 98 | p = strdata(str); | ||
| 99 | len = str->len; | ||
| 100 | } | ||
| 101 | lj_bufx_free(G(L), sbx); | ||
| 102 | lj_bufx_init_cow(L, sbx, p, len); | ||
| 103 | setgcref(sbx->cowref, gcV(L->base+1)); | ||
| 104 | L->top = L->base+1; /* Chain buffer object. */ | ||
| 105 | return 1; | ||
| 106 | } | ||
| 107 | |||
| 108 | LJLIB_CF(buffer_method_put) | ||
| 109 | { | ||
| 110 | SBufExt *sbx = buffer_tobufw(L); | ||
| 111 | ptrdiff_t arg, narg = L->top - L->base; | ||
| 112 | for (arg = 1; arg < narg; arg++) { | ||
| 113 | cTValue *o = &L->base[arg], *mo = NULL; | ||
| 114 | retry: | ||
| 115 | if (tvisstr(o)) { | ||
| 116 | lj_buf_putstr((SBuf *)sbx, strV(o)); | ||
| 117 | } else if (tvisint(o)) { | ||
| 118 | lj_strfmt_putint((SBuf *)sbx, intV(o)); | ||
| 119 | } else if (tvisnum(o)) { | ||
| 120 | lj_strfmt_putfnum((SBuf *)sbx, STRFMT_G14, numV(o)); | ||
| 121 | } else if (tvisbuf(o)) { | ||
| 122 | SBufExt *sbx2 = bufV(o); | ||
| 123 | lj_buf_putmem((SBuf *)sbx, sbx2->r, sbufxlen(sbx2)); | ||
| 124 | } else if (!mo && !tvisnil(mo = lj_meta_lookup(L, o, MM_tostring))) { | ||
| 125 | /* Call __tostring metamethod inline. */ | ||
| 126 | copyTV(L, L->top++, mo); | ||
| 127 | copyTV(L, L->top++, o); | ||
| 128 | lua_call(L, 1, 1); | ||
| 129 | o = &L->base[arg]; /* The stack may have been reallocated. */ | ||
| 130 | copyTV(L, &L->base[arg], L->top-1); | ||
| 131 | L->top = L->base + narg; | ||
| 132 | goto retry; /* Retry with the result. */ | ||
| 133 | } else { | ||
| 134 | lj_err_argtype(L, arg+1, "string/number/__tostring"); | ||
| 135 | } | ||
| 136 | /* Probably not useful to inline other __tostring MMs, e.g. FFI numbers. */ | ||
| 137 | } | ||
| 138 | L->top = L->base+1; /* Chain buffer object. */ | ||
| 139 | lj_gc_check(L); | ||
| 140 | return 1; | ||
| 141 | } | ||
| 142 | |||
| 143 | LJLIB_CF(buffer_method_putf) | ||
| 144 | { | ||
| 145 | SBufExt *sbx = buffer_tobufw(L); | ||
| 146 | lj_strfmt_putarg(L, (SBuf *)sbx, 2, 2); | ||
| 147 | L->top = L->base+1; /* Chain buffer object. */ | ||
| 148 | lj_gc_check(L); | ||
| 149 | return 1; | ||
| 150 | } | ||
| 151 | |||
| 152 | LJLIB_CF(buffer_method_get) | ||
| 153 | { | ||
| 154 | SBufExt *sbx = buffer_tobuf(L); | ||
| 155 | ptrdiff_t arg, narg = L->top - L->base; | ||
| 156 | if (narg == 1) { | ||
| 157 | narg++; | ||
| 158 | setnilV(L->top++); /* get() is the same as get(nil). */ | ||
| 159 | } | ||
| 160 | for (arg = 1; arg < narg; arg++) { | ||
| 161 | TValue *o = &L->base[arg]; | ||
| 162 | MSize n = tvisnil(o) ? LJ_MAX_BUF : | ||
| 163 | (MSize) lj_lib_checkintrange(L, arg+1, 0, LJ_MAX_BUF); | ||
| 164 | MSize len = sbufxlen(sbx); | ||
| 165 | if (n > len) n = len; | ||
| 166 | setstrV(L, o, lj_str_new(L, sbx->r, n)); | ||
| 167 | sbx->r += n; | ||
| 168 | } | ||
| 169 | if (sbx->r == sbx->w) sbx->r = sbx->w = sbx->b; | ||
| 170 | lj_gc_check(L); | ||
| 171 | return narg-1; | ||
| 172 | } | ||
| 173 | |||
| 174 | #if LJ_HASFFI | ||
| 175 | LJLIB_CF(buffer_method_putcdata) | ||
| 176 | { | ||
| 177 | SBufExt *sbx = buffer_tobufw(L); | ||
| 178 | const char *p; | ||
| 179 | MSize len; | ||
| 180 | if (tviscdata(L->base+1)) { | ||
| 181 | CTState *cts = ctype_cts(L); | ||
| 182 | lj_cconv_ct_tv(cts, ctype_get(cts, CTID_P_CVOID), (uint8_t *)&p, | ||
| 183 | L->base+1, CCF_ARG(2)); | ||
| 184 | } else { | ||
| 185 | lj_err_argtype(L, 2, "cdata"); | ||
| 186 | } | ||
| 187 | len = (MSize)lj_lib_checkintrange(L, 3, 0, LJ_MAX_BUF); | ||
| 188 | lj_buf_putmem((SBuf *)sbx, p, len); | ||
| 189 | L->top = L->base+1; /* Chain buffer object. */ | ||
| 190 | return 1; | ||
| 191 | } | ||
| 192 | |||
| 193 | LJLIB_CF(buffer_method_reserve) | ||
| 194 | { | ||
| 195 | SBufExt *sbx = buffer_tobufw(L); | ||
| 196 | MSize len = (MSize)lj_lib_checkintrange(L, 2, 0, LJ_MAX_BUF); | ||
| 197 | GCcdata *cd; | ||
| 198 | lj_buf_more((SBuf *)sbx, len); | ||
| 199 | ctype_loadffi(L); | ||
| 200 | cd = lj_cdata_new_(L, CTID_P_UINT8, CTSIZE_PTR); | ||
| 201 | *(void **)cdataptr(cd) = sbx->w; | ||
| 202 | setcdataV(L, L->top++, cd); | ||
| 203 | setintV(L->top++, sbufleft(sbx)); | ||
| 204 | return 2; | ||
| 205 | } | ||
| 206 | |||
| 207 | LJLIB_CF(buffer_method_commit) | ||
| 208 | { | ||
| 209 | SBufExt *sbx = buffer_tobuf(L); | ||
| 210 | MSize len = (MSize)lj_lib_checkintrange(L, 2, 0, LJ_MAX_BUF); | ||
| 211 | if (len > sbufleft(sbx)) lj_err_arg(L, 2, LJ_ERR_NUMRNG); | ||
| 212 | sbx->w += len; | ||
| 213 | L->top = L->base+1; /* Chain buffer object. */ | ||
| 214 | return 1; | ||
| 215 | } | ||
| 216 | |||
| 217 | LJLIB_CF(buffer_method_ref) | ||
| 218 | { | ||
| 219 | SBufExt *sbx = buffer_tobuf(L); | ||
| 220 | GCcdata *cd; | ||
| 221 | ctype_loadffi(L); | ||
| 222 | cd = lj_cdata_new_(L, CTID_P_UINT8, CTSIZE_PTR); | ||
| 223 | *(void **)cdataptr(cd) = sbx->r; | ||
| 224 | setcdataV(L, L->top++, cd); | ||
| 225 | setintV(L->top++, sbufxlen(sbx)); | ||
| 226 | return 2; | ||
| 227 | } | ||
| 228 | #endif | ||
| 229 | |||
| 230 | LJLIB_CF(buffer_method_encode) | ||
| 231 | { | ||
| 232 | SBufExt *sbx = buffer_tobufw(L); | ||
| 233 | cTValue *o = lj_lib_checkany(L, 2); | ||
| 234 | lj_serialize_put(sbx, o); | ||
| 235 | lj_gc_check(L); | ||
| 236 | L->top = L->base+1; /* Chain buffer object. */ | ||
| 237 | return 1; | ||
| 238 | } | ||
| 239 | |||
| 240 | LJLIB_CF(buffer_method_decode) | ||
| 241 | { | ||
| 242 | SBufExt *sbx = buffer_tobufw(L); | ||
| 243 | setnilV(L->top++); | ||
| 244 | lj_serialize_get(sbx, L->top-1); | ||
| 245 | lj_gc_check(L); | ||
| 246 | return 1; | ||
| 247 | } | ||
| 248 | |||
| 249 | LJLIB_CF(buffer_method___gc) | ||
| 250 | { | ||
| 251 | SBufExt *sbx = buffer_tobuf(L); | ||
| 252 | lj_bufx_free(G(L), sbx); | ||
| 253 | lj_bufx_init(L, sbx); | ||
| 254 | return 0; | ||
| 255 | } | ||
| 256 | |||
| 257 | LJLIB_CF(buffer_method___tostring) | ||
| 258 | { | ||
| 259 | SBufExt *sbx = buffer_tobuf(L); | ||
| 260 | setstrV(L, L->top-1, lj_str_new(L, sbx->r, sbufxlen(sbx))); | ||
| 261 | lj_gc_check(L); | ||
| 262 | return 1; | ||
| 263 | } | ||
| 264 | |||
| 265 | LJLIB_CF(buffer_method___len) | ||
| 266 | { | ||
| 267 | SBufExt *sbx = buffer_tobuf(L); | ||
| 268 | setintV(L->top-1, (int32_t)sbufxlen(sbx)); | ||
| 269 | return 1; | ||
| 270 | } | ||
| 271 | |||
| 272 | LJLIB_PUSH("buffer") LJLIB_SET(__metatable) | ||
| 273 | LJLIB_PUSH(top-1) LJLIB_SET(__index) | ||
| 274 | |||
| 275 | /* ------------------------------------------------------------------------ */ | ||
| 276 | |||
| 23 | #define LJLIB_MODULE_buffer | 277 | #define LJLIB_MODULE_buffer |
| 24 | 278 | ||
| 279 | LJLIB_PUSH(top-2) LJLIB_SET(!) /* Set environment. */ | ||
| 280 | |||
| 281 | LJLIB_CF(buffer_new) | ||
| 282 | { | ||
| 283 | MSize sz = L->base == L->top ? 0u : | ||
| 284 | (MSize)lj_lib_checkintrange(L, 1, 0, LJ_MAX_BUF); | ||
| 285 | GCtab *env = tabref(curr_func(L)->c.env); | ||
| 286 | GCudata *ud = lj_udata_new(L, sizeof(SBufExt), env); | ||
| 287 | SBufExt *sbx = (SBufExt *)uddata(ud); | ||
| 288 | ud->udtype = UDTYPE_BUFFER; | ||
| 289 | /* NOBARRIER: The GCudata is new (marked white). */ | ||
| 290 | setgcref(ud->metatable, obj2gco(env)); | ||
| 291 | setudataV(L, L->top++, ud); | ||
| 292 | lj_bufx_init(L, sbx); | ||
| 293 | if (sz > 0) lj_buf_need2((SBuf *)sbx, sz); | ||
| 294 | return 1; | ||
| 295 | } | ||
| 296 | |||
| 25 | LJLIB_CF(buffer_encode) | 297 | LJLIB_CF(buffer_encode) |
| 26 | { | 298 | { |
| 27 | cTValue *o = lj_lib_checkany(L, 1); | 299 | cTValue *o = lj_lib_checkany(L, 1); |
| @@ -35,13 +307,14 @@ LJLIB_CF(buffer_encode) | |||
| 35 | 307 | ||
| 36 | LJLIB_CF(buffer_decode) | 308 | LJLIB_CF(buffer_decode) |
| 37 | { | 309 | { |
| 38 | GCstr *str = lj_lib_checkstr(L, 1); | 310 | GCstr *str = lj_lib_checkstrx(L, 1); |
| 39 | SBufExt sbx; | 311 | SBufExt sbx; |
| 40 | lj_bufx_init_cow(L, &sbx, strdata(str), str->len); | 312 | lj_bufx_init_cow(L, &sbx, strdata(str), str->len); |
| 41 | /* No need to set sbx.cowref here. */ | 313 | /* No need to set sbx.cowref here. */ |
| 42 | setnilV(L->top++); | 314 | setnilV(L->top++); |
| 43 | lj_serialize_get(&sbx, L->top-1); | 315 | lj_serialize_get(&sbx, L->top-1); |
| 44 | lj_gc_check(L); | 316 | lj_gc_check(L); |
| 317 | if (sbx.r != sbx.w) lj_err_caller(L, LJ_ERR_BUFFER_LEFTOV); | ||
| 45 | return 1; | 318 | return 1; |
| 46 | } | 319 | } |
| 47 | 320 | ||
| @@ -51,6 +324,9 @@ LJLIB_CF(buffer_decode) | |||
| 51 | 324 | ||
| 52 | int luaopen_string_buffer(lua_State *L) | 325 | int luaopen_string_buffer(lua_State *L) |
| 53 | { | 326 | { |
| 327 | LJ_LIB_REG(L, NULL, buffer_method); | ||
| 328 | lua_getfield(L, -1, "__tostring"); | ||
| 329 | lua_setfield(L, -2, "tostring"); | ||
| 54 | LJ_LIB_REG(L, NULL, buffer); | 330 | LJ_LIB_REG(L, NULL, buffer); |
| 55 | return 1; | 331 | return 1; |
| 56 | } | 332 | } |
