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