3 ** Copyright (C) 2005-2023 Mike Pall. See Copyright Notice in luajit.h
15 #include "lj_strfmt.h"
17 /* -- Buffer management --------------------------------------------------- */
19 static void buf_grow(SBuf
*sb
, MSize sz
)
21 MSize osz
= sbufsz(sb
), len
= sbuflen(sb
), nsz
= osz
;
24 if (nsz
< LJ_MIN_SBUF
) nsz
= LJ_MIN_SBUF
;
25 while (nsz
< sz
) nsz
+= nsz
;
27 if ((flag
& SBUF_FLAG_COW
)) { /* Copy-on-write semantics. */
28 lj_assertG_(G(sbufL(sb
)), sb
->w
== sb
->e
, "bad SBuf COW");
29 b
= (char *)lj_mem_new(sbufL(sb
), nsz
);
30 setsbufflag(sb
, flag
& ~(GCSize
)SBUF_FLAG_COW
);
31 setgcrefnull(sbufX(sb
)->cowref
);
32 memcpy(b
, sb
->b
, osz
);
34 b
= (char *)lj_mem_realloc(sbufL(sb
), sb
->b
, osz
, nsz
);
36 if ((flag
& SBUF_FLAG_EXT
)) {
37 sbufX(sb
)->r
= sbufX(sb
)->r
- sb
->b
+ b
; /* Adjust read pointer, too. */
39 /* Adjust buffer pointers. */
43 if ((flag
& SBUF_FLAG_BORROW
)) { /* Adjust borrowed buffer pointers. */
44 SBuf
*bsb
= mref(sbufX(sb
)->bsb
, SBuf
);
51 LJ_NOINLINE
char *LJ_FASTCALL
lj_buf_need2(SBuf
*sb
, MSize sz
)
53 lj_assertG_(G(sbufL(sb
)), sz
> sbufsz(sb
), "SBuf overflow");
54 if (LJ_UNLIKELY(sz
> LJ_MAX_BUF
))
55 lj_err_mem(sbufL(sb
));
60 LJ_NOINLINE
char *LJ_FASTCALL
lj_buf_more2(SBuf
*sb
, MSize sz
)
63 SBufExt
*sbx
= (SBufExt
*)sb
;
64 MSize len
= sbufxlen(sbx
);
65 if (LJ_UNLIKELY(sz
> LJ_MAX_BUF
|| len
+ sz
> LJ_MAX_BUF
))
66 lj_err_mem(sbufL(sbx
));
67 if (len
+ sz
> sbufsz(sbx
)) { /* Must grow. */
68 buf_grow((SBuf
*)sbx
, len
+ sz
);
69 } else if (sbufiscow(sb
) || sbufxslack(sbx
) < (sbufsz(sbx
) >> 3)) {
70 /* Also grow to avoid excessive compactions, if slack < size/8. */
71 buf_grow((SBuf
*)sbx
, sbuflen(sbx
) + sz
); /* Not sbufxlen! */
74 if (sbx
->r
!= sbx
->b
) { /* Compact by moving down. */
75 memmove(sbx
->b
, sbx
->r
, len
);
77 sbx
->w
= sbx
->b
+ len
;
78 lj_assertG_(G(sbufL(sbx
)), len
+ sz
<= sbufsz(sbx
), "bad SBuf compact");
81 MSize len
= sbuflen(sb
);
82 lj_assertG_(G(sbufL(sb
)), sz
> sbufleft(sb
), "SBuf overflow");
83 if (LJ_UNLIKELY(sz
> LJ_MAX_BUF
|| len
+ sz
> LJ_MAX_BUF
))
84 lj_err_mem(sbufL(sb
));
85 buf_grow(sb
, len
+ sz
);
90 void LJ_FASTCALL
lj_buf_shrink(lua_State
*L
, SBuf
*sb
)
93 MSize osz
= (MSize
)(sb
->e
- b
);
94 if (osz
> 2*LJ_MIN_SBUF
) {
95 MSize n
= (MSize
)(sb
->w
- b
);
96 b
= lj_mem_realloc(L
, b
, osz
, (osz
>> 1));
99 sb
->e
= b
+ (osz
>> 1);
101 lj_assertG_(G(sbufL(sb
)), !sbufisext(sb
), "YAGNI shrink SBufExt");
104 char * LJ_FASTCALL
lj_buf_tmp(lua_State
*L
, MSize sz
)
106 SBuf
*sb
= &G(L
)->tmpbuf
;
108 return lj_buf_need(sb
, sz
);
111 #if LJ_HASBUFFER && LJ_HASJIT
112 void lj_bufx_set(SBufExt
*sbx
, const char *p
, MSize len
, GCobj
*ref
)
114 lua_State
*L
= sbufL(sbx
);
115 lj_bufx_free(L
, sbx
);
116 lj_bufx_set_cow(L
, sbx
, p
, len
);
117 setgcref(sbx
->cowref
, ref
);
118 lj_gc_objbarrier(L
, (GCudata
*)sbx
- 1, ref
);
122 MSize LJ_FASTCALL
lj_bufx_more(SBufExt
*sbx
, MSize sz
)
124 lj_buf_more((SBuf
*)sbx
, sz
);
125 return sbufleft(sbx
);
130 /* -- Low-level buffer put operations ------------------------------------- */
132 SBuf
*lj_buf_putmem(SBuf
*sb
, const void *q
, MSize len
)
134 char *w
= lj_buf_more(sb
, len
);
135 w
= lj_buf_wmem(w
, q
, len
);
140 #if LJ_HASJIT || LJ_HASFFI
141 static LJ_NOINLINE SBuf
* LJ_FASTCALL
lj_buf_putchar2(SBuf
*sb
, int c
)
143 char *w
= lj_buf_more2(sb
, 1);
149 SBuf
* LJ_FASTCALL
lj_buf_putchar(SBuf
*sb
, int c
)
152 if (LJ_LIKELY(w
< sb
->e
)) {
157 return lj_buf_putchar2(sb
, c
);
161 SBuf
* LJ_FASTCALL
lj_buf_putstr(SBuf
*sb
, GCstr
*s
)
164 char *w
= lj_buf_more(sb
, len
);
165 w
= lj_buf_wmem(w
, strdata(s
), len
);
170 /* -- High-level buffer put operations ------------------------------------ */
172 SBuf
* LJ_FASTCALL
lj_buf_putstr_reverse(SBuf
*sb
, GCstr
*s
)
175 char *w
= lj_buf_more(sb
, len
), *e
= w
+len
;
176 const char *q
= strdata(s
)+len
-1;
183 SBuf
* LJ_FASTCALL
lj_buf_putstr_lower(SBuf
*sb
, GCstr
*s
)
186 char *w
= lj_buf_more(sb
, len
), *e
= w
+len
;
187 const char *q
= strdata(s
);
188 for (; w
< e
; w
++, q
++) {
189 uint32_t c
= *(unsigned char *)q
;
191 *w
= c
+ ((c
>= 'A' && c
<= 'Z') << 5);
193 if (c
>= 'A' && c
<= 'Z') c
+= 0x20;
201 SBuf
* LJ_FASTCALL
lj_buf_putstr_upper(SBuf
*sb
, GCstr
*s
)
204 char *w
= lj_buf_more(sb
, len
), *e
= w
+len
;
205 const char *q
= strdata(s
);
206 for (; w
< e
; w
++, q
++) {
207 uint32_t c
= *(unsigned char *)q
;
209 *w
= c
- ((c
>= 'a' && c
<= 'z') << 5);
211 if (c
>= 'a' && c
<= 'z') c
-= 0x20;
219 SBuf
*lj_buf_putstr_rep(SBuf
*sb
, GCstr
*s
, int32_t rep
)
222 if (rep
> 0 && len
) {
223 uint64_t tlen
= (uint64_t)rep
* len
;
225 if (LJ_UNLIKELY(tlen
> LJ_MAX_STR
))
226 lj_err_mem(sbufL(sb
));
227 w
= lj_buf_more(sb
, (MSize
)tlen
);
228 if (len
== 1) { /* Optimize a common case. */
229 uint32_t c
= strdata(s
)[0];
230 do { *w
++ = c
; } while (--rep
> 0);
232 const char *e
= strdata(s
) + len
;
234 const char *q
= strdata(s
);
235 do { *w
++ = *q
++; } while (q
< e
);
243 SBuf
*lj_buf_puttab(SBuf
*sb
, GCtab
*t
, GCstr
*sep
, int32_t i
, int32_t e
)
245 MSize seplen
= sep
? sep
->len
: 0;
248 cTValue
*o
= lj_tab_getint(t
, i
);
251 badtype
: /* Error: bad element type. */
252 sb
->w
= (char *)(intptr_t)i
; /* Store failing index. */
254 } else if (tvisstr(o
)) {
255 MSize len
= strV(o
)->len
;
256 w
= lj_buf_wmem(lj_buf_more(sb
, len
+ seplen
), strVdata(o
), len
);
257 } else if (tvisint(o
)) {
258 w
= lj_strfmt_wint(lj_buf_more(sb
, STRFMT_MAXBUF_INT
+seplen
), intV(o
));
259 } else if (tvisnum(o
)) {
260 w
= lj_buf_more(lj_strfmt_putfnum(sb
, STRFMT_G14
, numV(o
)), seplen
);
268 if (seplen
) w
= lj_buf_wmem(w
, strdata(sep
), seplen
);
275 /* -- Miscellaneous buffer operations ------------------------------------- */
277 GCstr
* LJ_FASTCALL
lj_buf_tostr(SBuf
*sb
)
279 return lj_str_new(sbufL(sb
), sb
->b
, sbuflen(sb
));
282 /* Concatenate two strings. */
283 GCstr
*lj_buf_cat2str(lua_State
*L
, GCstr
*s1
, GCstr
*s2
)
285 MSize len1
= s1
->len
, len2
= s2
->len
;
286 char *buf
= lj_buf_tmp(L
, len1
+ len2
);
287 memcpy(buf
, strdata(s1
), len1
);
288 memcpy(buf
+len1
, strdata(s2
), len2
);
289 return lj_str_new(L
, buf
, len1
+ len2
);
292 /* Read ULEB128 from buffer. */
293 uint32_t LJ_FASTCALL
lj_buf_ruleb128(const char **pp
)
295 const uint8_t *w
= (const uint8_t *)*pp
;
297 if (LJ_UNLIKELY(v
>= 0x80)) {
300 do { v
|= ((*w
& 0x7f) << (sh
+= 7)); } while (*w
++ >= 0x80);
302 *pp
= (const char *)w
;