17d8dd8d9SRob Norris // SPDX-License-Identifier: MIT
2d99a0153SChris Williamson /*
3d99a0153SChris Williamson ** $Id: lstring.c,v 2.26.1.1 2013/04/12 18:48:47 roberto Exp $
4d99a0153SChris Williamson ** String table (keeps all strings handled by Lua)
5d99a0153SChris Williamson ** See Copyright Notice in lua.h
6d99a0153SChris Williamson */
7d99a0153SChris Williamson
8d99a0153SChris Williamson
9d99a0153SChris Williamson #define lstring_c
10d99a0153SChris Williamson #define LUA_CORE
11d99a0153SChris Williamson
12d99a0153SChris Williamson #include <sys/lua/lua.h>
13d99a0153SChris Williamson
14d99a0153SChris Williamson #include "lmem.h"
15d99a0153SChris Williamson #include "lobject.h"
16d99a0153SChris Williamson #include "lstate.h"
17d99a0153SChris Williamson #include "lstring.h"
18d99a0153SChris Williamson
19d99a0153SChris Williamson
20d99a0153SChris Williamson /*
21d99a0153SChris Williamson ** Lua will use at most ~(2^LUAI_HASHLIMIT) bytes from a string to
22d99a0153SChris Williamson ** compute its hash
23d99a0153SChris Williamson */
24d99a0153SChris Williamson #if !defined(LUAI_HASHLIMIT)
25d99a0153SChris Williamson #define LUAI_HASHLIMIT 5
26d99a0153SChris Williamson #endif
27d99a0153SChris Williamson
28d99a0153SChris Williamson
29d99a0153SChris Williamson /*
30d99a0153SChris Williamson ** equality for long strings
31d99a0153SChris Williamson */
luaS_eqlngstr(TString * a,TString * b)32d99a0153SChris Williamson int luaS_eqlngstr (TString *a, TString *b) {
33d99a0153SChris Williamson size_t len = a->tsv.len;
34d99a0153SChris Williamson lua_assert(a->tsv.tt == LUA_TLNGSTR && b->tsv.tt == LUA_TLNGSTR);
35d99a0153SChris Williamson return (a == b) || /* same instance or... */
36d99a0153SChris Williamson ((len == b->tsv.len) && /* equal length and ... */
37d99a0153SChris Williamson (memcmp(getstr(a), getstr(b), len) == 0)); /* equal contents */
38d99a0153SChris Williamson }
39d99a0153SChris Williamson
40d99a0153SChris Williamson
41d99a0153SChris Williamson /*
42d99a0153SChris Williamson ** equality for strings
43d99a0153SChris Williamson */
luaS_eqstr(TString * a,TString * b)44d99a0153SChris Williamson int luaS_eqstr (TString *a, TString *b) {
45d99a0153SChris Williamson return (a->tsv.tt == b->tsv.tt) &&
46d99a0153SChris Williamson (a->tsv.tt == LUA_TSHRSTR ? eqshrstr(a, b) : luaS_eqlngstr(a, b));
47d99a0153SChris Williamson }
48d99a0153SChris Williamson
49d99a0153SChris Williamson
luaS_hash(const char * str,size_t l,unsigned int seed)50d99a0153SChris Williamson unsigned int luaS_hash (const char *str, size_t l, unsigned int seed) {
51d99a0153SChris Williamson unsigned int h = seed ^ cast(unsigned int, l);
52d99a0153SChris Williamson size_t l1;
53d99a0153SChris Williamson size_t step = (l >> LUAI_HASHLIMIT) + 1;
54d99a0153SChris Williamson for (l1 = l; l1 >= step; l1 -= step)
55d99a0153SChris Williamson h = h ^ ((h<<5) + (h>>2) + cast_byte(str[l1 - 1]));
56d99a0153SChris Williamson return h;
57d99a0153SChris Williamson }
58d99a0153SChris Williamson
59d99a0153SChris Williamson
60d99a0153SChris Williamson /*
61d99a0153SChris Williamson ** resizes the string table
62d99a0153SChris Williamson */
luaS_resize(lua_State * L,int newsize)63d99a0153SChris Williamson void luaS_resize (lua_State *L, int newsize) {
64d99a0153SChris Williamson int i;
65d99a0153SChris Williamson stringtable *tb = &G(L)->strt;
66d99a0153SChris Williamson /* cannot resize while GC is traversing strings */
67d99a0153SChris Williamson luaC_runtilstate(L, ~bitmask(GCSsweepstring));
68d99a0153SChris Williamson if (newsize > tb->size) {
69d99a0153SChris Williamson luaM_reallocvector(L, tb->hash, tb->size, newsize, GCObject *);
70d99a0153SChris Williamson for (i = tb->size; i < newsize; i++) tb->hash[i] = NULL;
71d99a0153SChris Williamson }
72d99a0153SChris Williamson /* rehash */
73d99a0153SChris Williamson for (i=0; i<tb->size; i++) {
74d99a0153SChris Williamson GCObject *p = tb->hash[i];
75d99a0153SChris Williamson tb->hash[i] = NULL;
76d99a0153SChris Williamson while (p) { /* for each node in the list */
77d99a0153SChris Williamson GCObject *next = gch(p)->next; /* save next */
78d99a0153SChris Williamson unsigned int h = lmod(gco2ts(p)->hash, newsize); /* new position */
79d99a0153SChris Williamson gch(p)->next = tb->hash[h]; /* chain it */
80d99a0153SChris Williamson tb->hash[h] = p;
81d99a0153SChris Williamson resetoldbit(p); /* see MOVE OLD rule */
82d99a0153SChris Williamson p = next;
83d99a0153SChris Williamson }
84d99a0153SChris Williamson }
85d99a0153SChris Williamson if (newsize < tb->size) {
86d99a0153SChris Williamson /* shrinking slice must be empty */
87d99a0153SChris Williamson lua_assert(tb->hash[newsize] == NULL && tb->hash[tb->size - 1] == NULL);
88d99a0153SChris Williamson luaM_reallocvector(L, tb->hash, tb->size, newsize, GCObject *);
89d99a0153SChris Williamson }
90d99a0153SChris Williamson tb->size = newsize;
91d99a0153SChris Williamson }
92d99a0153SChris Williamson
93d99a0153SChris Williamson
94d99a0153SChris Williamson /*
95d99a0153SChris Williamson ** creates a new string object
96d99a0153SChris Williamson */
createstrobj(lua_State * L,const char * str,size_t l,int tag,unsigned int h,GCObject ** list)97d99a0153SChris Williamson static TString *createstrobj (lua_State *L, const char *str, size_t l,
98d99a0153SChris Williamson int tag, unsigned int h, GCObject **list) {
99d99a0153SChris Williamson TString *ts;
100cbce5813SDon Brady char *sbuf;
101d99a0153SChris Williamson size_t totalsize; /* total size of TString object */
102d99a0153SChris Williamson totalsize = sizeof(TString) + ((l + 1) * sizeof(char));
103d99a0153SChris Williamson ts = &luaC_newobj(L, tag, totalsize, list, 0)->ts;
104d99a0153SChris Williamson ts->tsv.len = l;
105d99a0153SChris Williamson ts->tsv.hash = h;
106d99a0153SChris Williamson ts->tsv.extra = 0;
107c84a37aeSRob Norris sbuf = ts->contents;
108cbce5813SDon Brady memcpy(sbuf, str, l*sizeof(char));
109cbce5813SDon Brady sbuf[l] = '\0'; /* ending 0 */
110d99a0153SChris Williamson return ts;
111d99a0153SChris Williamson }
112d99a0153SChris Williamson
113d99a0153SChris Williamson
114d99a0153SChris Williamson /*
115d99a0153SChris Williamson ** creates a new short string, inserting it into string table
116d99a0153SChris Williamson */
newshrstr(lua_State * L,const char * str,size_t l,unsigned int h)117d99a0153SChris Williamson static TString *newshrstr (lua_State *L, const char *str, size_t l,
118d99a0153SChris Williamson unsigned int h) {
119d99a0153SChris Williamson GCObject **list; /* (pointer to) list where it will be inserted */
120d99a0153SChris Williamson stringtable *tb = &G(L)->strt;
121d99a0153SChris Williamson TString *s;
122d99a0153SChris Williamson if (tb->nuse >= cast(lu_int32, tb->size) && tb->size <= MAX_INT/2)
123d99a0153SChris Williamson luaS_resize(L, tb->size*2); /* too crowded */
124d99a0153SChris Williamson list = &tb->hash[lmod(h, tb->size)];
125d99a0153SChris Williamson s = createstrobj(L, str, l, LUA_TSHRSTR, h, list);
126d99a0153SChris Williamson tb->nuse++;
127d99a0153SChris Williamson return s;
128d99a0153SChris Williamson }
129d99a0153SChris Williamson
130d99a0153SChris Williamson
131d99a0153SChris Williamson /*
132d99a0153SChris Williamson ** checks whether short string exists and reuses it or creates a new one
133d99a0153SChris Williamson */
internshrstr(lua_State * L,const char * str,size_t l)134d99a0153SChris Williamson static TString *internshrstr (lua_State *L, const char *str, size_t l) {
135d99a0153SChris Williamson GCObject *o;
136d99a0153SChris Williamson global_State *g = G(L);
137d99a0153SChris Williamson unsigned int h = luaS_hash(str, l, g->seed);
138d99a0153SChris Williamson for (o = g->strt.hash[lmod(h, g->strt.size)];
139d99a0153SChris Williamson o != NULL;
140d99a0153SChris Williamson o = gch(o)->next) {
141d99a0153SChris Williamson TString *ts = rawgco2ts(o);
142d99a0153SChris Williamson if (h == ts->tsv.hash &&
143d99a0153SChris Williamson l == ts->tsv.len &&
144d99a0153SChris Williamson (memcmp(str, getstr(ts), l * sizeof(char)) == 0)) {
145d99a0153SChris Williamson if (isdead(G(L), o)) /* string is dead (but was not collected yet)? */
146d99a0153SChris Williamson changewhite(o); /* resurrect it */
147d99a0153SChris Williamson return ts;
148d99a0153SChris Williamson }
149d99a0153SChris Williamson }
150d99a0153SChris Williamson return newshrstr(L, str, l, h); /* not found; create a new string */
151d99a0153SChris Williamson }
152d99a0153SChris Williamson
153d99a0153SChris Williamson
154d99a0153SChris Williamson /*
155d99a0153SChris Williamson ** new string (with explicit length)
156d99a0153SChris Williamson */
luaS_newlstr(lua_State * L,const char * str,size_t l)157d99a0153SChris Williamson TString *luaS_newlstr (lua_State *L, const char *str, size_t l) {
158d99a0153SChris Williamson if (l <= LUAI_MAXSHORTLEN) /* short string? */
159d99a0153SChris Williamson return internshrstr(L, str, l);
160d99a0153SChris Williamson else {
161d99a0153SChris Williamson if (l + 1 > (MAX_SIZET - sizeof(TString))/sizeof(char))
162d99a0153SChris Williamson luaM_toobig(L);
163d99a0153SChris Williamson return createstrobj(L, str, l, LUA_TLNGSTR, G(L)->seed, NULL);
164d99a0153SChris Williamson }
165d99a0153SChris Williamson }
166d99a0153SChris Williamson
167d99a0153SChris Williamson
168d99a0153SChris Williamson /*
169d99a0153SChris Williamson ** new zero-terminated string
170d99a0153SChris Williamson */
luaS_new(lua_State * L,const char * str)171d99a0153SChris Williamson TString *luaS_new (lua_State *L, const char *str) {
172d99a0153SChris Williamson return luaS_newlstr(L, str, strlen(str));
173d99a0153SChris Williamson }
174d99a0153SChris Williamson
175d99a0153SChris Williamson
luaS_newudata(lua_State * L,size_t s,Table * e)176d99a0153SChris Williamson Udata *luaS_newudata (lua_State *L, size_t s, Table *e) {
177d99a0153SChris Williamson Udata *u;
178d99a0153SChris Williamson if (s > MAX_SIZET - sizeof(Udata))
179d99a0153SChris Williamson luaM_toobig(L);
180d99a0153SChris Williamson u = &luaC_newobj(L, LUA_TUSERDATA, sizeof(Udata) + s, NULL, 0)->u;
181d99a0153SChris Williamson u->uv.len = s;
182d99a0153SChris Williamson u->uv.metatable = NULL;
183d99a0153SChris Williamson u->uv.env = e;
184d99a0153SChris Williamson return u;
185d99a0153SChris Williamson }
186