xref: /src/sys/contrib/openzfs/module/lua/lstring.c (revision 61145dc2b94f12f6a47344fb9aac702321880e43)
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