2 ** $Id: lstring.c,v 1.13 1998/06/19 16:14:09 roberto Exp $
3 ** String table (keeps all strings handled by Lua)
4 ** See Copyright Notice in lua.h
20 #define gcsizestring(l) (1+(l/64)) /* "weight" for a string with length 'l' */
24 static TaggedString EMPTY
= {{NULL
, 2}, 0L, 0,
25 {{{LUA_T_NIL
, {NULL
}}, 0L}}, {0}};
31 L
->string_root
= luaM_newvector(NUM_HASHS
, stringtable
);
32 for (i
=0; i
<NUM_HASHS
; i
++) {
33 L
->string_root
[i
].size
= 0;
34 L
->string_root
[i
].nuse
= 0;
35 L
->string_root
[i
].hash
= NULL
;
40 static unsigned long hash_s (char *s
, long l
)
44 h
= ((h
<<5)-h
)^(unsigned char)*(s
++);
48 static int newsize (stringtable
*tb
)
53 /* count how many entries are really in use */
54 for (i
=0; i
<size
; i
++)
55 if (tb
->hash
[i
] != NULL
&& tb
->hash
[i
] != &EMPTY
)
57 if (2*(realuse
+1) <= size
) /* +1 is the new element */
58 return size
; /* don't need to grow, just rehash to clear EMPTYs */
60 return luaO_redimension(size
);
64 static void grow (stringtable
*tb
)
68 TaggedString
**newhash
= luaM_newvector(ns
, TaggedString
*);
74 for (i
=0; i
<tb
->size
; i
++) {
75 if (tb
->hash
[i
] != NULL
&& tb
->hash
[i
] != &EMPTY
) {
76 int h
= tb
->hash
[i
]->hash
%ns
;
79 newhash
[h
] = tb
->hash
[i
];
89 static TaggedString
*newone_s (char *str
, long l
, unsigned long h
)
91 TaggedString
*ts
= (TaggedString
*)luaM_malloc(sizeof(TaggedString
)+l
);
92 memcpy(ts
->str
, str
, l
);
93 ts
->str
[l
] = 0; /* ending 0 */
94 ts
->u
.s
.globalval
.ttype
= LUA_T_NIL
; /* initialize global value */
97 L
->nblocks
+= gcsizestring(l
);
99 ts
->head
.next
= (GCnode
*)ts
; /* signal it is in no list */
104 static TaggedString
*newone_u (char *buff
, int tag
, unsigned long h
)
106 TaggedString
*ts
= luaM_new(TaggedString
);
108 ts
->u
.d
.tag
= (tag
== LUA_ANYTAG
) ? 0 : tag
;
109 ts
->constindex
= -1; /* tag -> this is a userdata */
112 ts
->head
.next
= (GCnode
*)ts
; /* signal it is in no list */
117 static TaggedString
*insert_s (char *str
, long l
, stringtable
*tb
)
120 unsigned long h
= hash_s(str
, l
);
124 if ((long)tb
->nuse
*3 >= (long)size
*2) {
128 for (i
= h
%size
; (ts
= tb
->hash
[i
]) != NULL
; ) {
131 else if (ts
->constindex
>= 0 &&
133 (memcmp(str
, ts
->str
, l
) == 0))
135 if (++i
== size
) i
=0;
138 if (j
!= -1) /* is there an EMPTY space? */
142 ts
= tb
->hash
[i
] = newone_s(str
, l
, h
);
146 static TaggedString
*insert_u (void *buff
, int tag
, stringtable
*tb
)
149 unsigned long h
= (unsigned long)buff
;
153 if ((long)tb
->nuse
*3 >= (long)size
*2) {
157 for (i
= h
%size
; (ts
= tb
->hash
[i
]) != NULL
; ) {
160 else if (ts
->constindex
< 0 && /* is a udata? */
161 (tag
== ts
->u
.d
.tag
|| tag
== LUA_ANYTAG
) &&
164 if (++i
== size
) i
=0;
167 if (j
!= -1) /* is there an EMPTY space? */
171 ts
= tb
->hash
[i
] = newone_u(buff
, tag
, h
);
175 TaggedString
*luaS_createudata (void *udata
, int tag
)
177 return insert_u(udata
, tag
, &L
->string_root
[(unsigned)udata
%NUM_HASHS
]);
180 TaggedString
*luaS_newlstr (char *str
, long l
)
182 int i
= (l
==0)?0:(unsigned char)str
[0];
183 return insert_s(str
, l
, &L
->string_root
[i
%NUM_HASHS
]);
186 TaggedString
*luaS_new (char *str
)
188 return luaS_newlstr(str
, strlen(str
));
191 TaggedString
*luaS_newfixedstring (char *str
)
193 TaggedString
*ts
= luaS_new(str
);
194 if (ts
->head
.marked
== 0)
195 ts
->head
.marked
= 2; /* avoid GC */
200 void luaS_free (TaggedString
*l
)
203 TaggedString
*next
= (TaggedString
*)l
->head
.next
;
204 L
->nblocks
-= (l
->constindex
== -1) ? 1 : gcsizestring(l
->u
.s
.len
);
212 ** Garbage collection functions.
215 static void remove_from_list (GCnode
*l
)
218 GCnode
*next
= l
->next
;
219 while (next
&& !next
->marked
)
220 next
= l
->next
= next
->next
;
226 TaggedString
*luaS_collector (void)
228 TaggedString
*frees
= NULL
;
230 remove_from_list(&(L
->rootglobal
));
231 for (i
=0; i
<NUM_HASHS
; i
++) {
232 stringtable
*tb
= &L
->string_root
[i
];
234 for (j
=0; j
<tb
->size
; j
++) {
235 TaggedString
*t
= tb
->hash
[j
];
236 if (t
== NULL
) continue;
237 if (t
->head
.marked
== 1)
239 else if (!t
->head
.marked
) {
240 t
->head
.next
= (GCnode
*)frees
;
242 tb
->hash
[j
] = &EMPTY
;
250 TaggedString
*luaS_collectudata (void)
252 TaggedString
*frees
= NULL
;
254 L
->rootglobal
.next
= NULL
; /* empty list of globals */
255 for (i
=0; i
<NUM_HASHS
; i
++) {
256 stringtable
*tb
= &L
->string_root
[i
];
258 for (j
=0; j
<tb
->size
; j
++) {
259 TaggedString
*t
= tb
->hash
[j
];
260 if (t
== NULL
|| t
== &EMPTY
|| t
->constindex
!= -1)
261 continue; /* get only user data */
262 t
->head
.next
= (GCnode
*)frees
;
264 tb
->hash
[j
] = &EMPTY
;
271 void luaS_freeall (void)
274 for (i
=0; i
<NUM_HASHS
; i
++) {
275 stringtable
*tb
= &L
->string_root
[i
];
277 for (j
=0; j
<tb
->size
; j
++) {
278 TaggedString
*t
= tb
->hash
[j
];
279 if (t
== &EMPTY
) continue;
284 luaM_free(L
->string_root
);
288 void luaS_rawsetglobal (TaggedString
*ts
, TObject
*newval
)
290 ts
->u
.s
.globalval
= *newval
;
291 if (ts
->head
.next
== (GCnode
*)ts
) { /* is not in list? */
292 ts
->head
.next
= L
->rootglobal
.next
;
293 L
->rootglobal
.next
= (GCnode
*)ts
;
298 char *luaS_travsymbol (int (*fn
)(TObject
*))
301 for (g
=(TaggedString
*)L
->rootglobal
.next
; g
; g
=(TaggedString
*)g
->head
.next
)
302 if (fn(&g
->u
.s
.globalval
))
308 int luaS_globaldefined (char *name
)
310 TaggedString
*ts
= luaS_new(name
);
311 return ts
->u
.s
.globalval
.ttype
!= LUA_T_NIL
;