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