Przeglądaj źródła

tables can become full of "emptys" slots, and keep growing without limits.

Roberto Ierusalimschy 27 lat temu
rodzic
commit
6cdf0d8768
3 zmienionych plików z 47 dodań i 26 usunięć
  1. 5 1
      bugs
  2. 25 8
      lstring.c
  3. 17 17
      ltable.c

+ 5 - 1
bugs

@@ -21,7 +21,7 @@ Mon Jan 19 18:17:18 EDT 1998
 
 ** lstrlib.c
 Tue Jan 27 15:27:49 EDT 1998
->> formats like "%020d" were considered too big (3 algarithms); moreover,
+>> formats like "%020d" were considered too big (3 digits); moreover,
 >> some sistems limit printf to at most 500 chars, so we can limit sizes
 >> to 2 digits (99).
 
@@ -29,3 +29,7 @@ Tue Jan 27 15:27:49 EDT 1998
 Tue Jan 27 17:12:36 EDT 1998
 >> "lua_getstring" may create a new string, so should check GC
 
+** lstring.c / ltable.c
+Wed Jan 28 14:48:12 EDT 1998
+>> tables can become full of "emptys" slots, and keep growing without limits.
+

+ 25 - 8
lstring.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lstring.c,v 1.9 1997/12/30 19:15:52 roberto Exp roberto $
+** $Id: lstring.c,v 1.10 1998/01/13 18:06:27 roberto Exp roberto $
 ** String table (keeps all strings handled by Lua)
 ** See Copyright Notice in lua.h
 */
@@ -50,26 +50,43 @@ static unsigned long hash (char *s, int tag)
 }
 
 
+static int newsize (stringtable *tb)
+{
+  int size = tb->size;
+  int realuse = 0;
+  int i;
+  /* count how many entries are really in use */
+  for (i=0; i<size; i++)
+    if (tb->hash[i] != NULL && tb->hash[i] != &EMPTY)
+      realuse++;
+  if (2*(realuse+1) <= size)  /* +1 is the new element */
+    return size;  /* don't need to grow, just rehash to clear EMPTYs */
+  else
+    return luaO_redimension(size);
+}
+
+
 static void grow (stringtable *tb)
 {
-  int newsize = luaO_redimension(tb->size);
-  TaggedString **newhash = luaM_newvector(newsize, TaggedString *);
+  
+  int ns = newsize(tb);
+  TaggedString **newhash = luaM_newvector(ns, TaggedString *);
   int i;
-  for (i=0; i<newsize; i++)
+  for (i=0; i<ns; i++)
     newhash[i] = NULL;
   /* rehash */
   tb->nuse = 0;
   for (i=0; i<tb->size; i++) {
     if (tb->hash[i] != NULL && tb->hash[i] != &EMPTY) {
-      int h = tb->hash[i]->hash%newsize;
+      int h = tb->hash[i]->hash%ns;
       while (newhash[h])
-        h = (h+1)%newsize;
+        h = (h+1)%ns;
       newhash[h] = tb->hash[i];
       tb->nuse++;
     }
   }
   luaM_free(tb->hash);
-  tb->size = newsize;
+  tb->size = ns;
   tb->hash = newhash;
 }
 
@@ -86,7 +103,7 @@ static TaggedString *newone (char *buff, int tag, unsigned long h)
     L->nblocks += gcsizestring(l);
   }
   else {
-    ts = (TaggedString *)luaM_malloc(sizeof(TaggedString));
+    ts = luaM_new(TaggedString);
     ts->u.d.v = buff;
     ts->u.d.tag = tag == LUA_ANYTAG ? 0 : tag;
     ts->constindex = -1;  /* tag -> this is a userdata */

+ 17 - 17
ltable.c

@@ -1,5 +1,5 @@
 /*
-** $Id: ltable.c,v 1.10 1998/01/09 14:44:55 roberto Exp roberto $
+** $Id: ltable.c,v 1.11 1998/01/13 18:06:27 roberto Exp roberto $
 ** Lua tables (hash)
 ** See Copyright Notice in lua.h
 */
@@ -121,36 +121,36 @@ Hash *luaH_new (int nhash)
 }
 
 
-/*
-** Rehash:
-** Check if table has deleted slots. It it has, it does not need to
-** grow, since rehash will reuse them.
-*/
-static int emptyslots (Hash *t)
+static int newsize (Hash *t)
 {
+  Node *v = t->node;
+  int size = nhash(t);
+  int realuse = 0;
   int i;
-  for (i=nhash(t)-1; i>=0; i--) {
-    Node *n = node(t, i);
-    if (ttype(ref(n)) != LUA_T_NIL && ttype(val(n)) == LUA_T_NIL)
-      return 1;
+  for (i=0; i<size; i++) {
+    if (ttype(ref(v+i)) != LUA_T_NIL && ttype(val(v+i)) != LUA_T_NIL)
+      realuse++;
   }
-  return 0;
+  if (2*(realuse+1) <= size)  /* +1 is the new element */
+    return size;  /* don't need to grow, just rehash */
+  else
+    return luaO_redimension(size);
 }
 
 static void rehash (Hash *t)
 {
-  int   nold = nhash(t);
+  int nold = nhash(t);
   Node *vold = nodevector(t);
+  int nnew = newsize(t);
   int i;
-  if (!emptyslots(t))
-    nhash(t) = luaO_redimension(nhash(t));
-  nodevector(t) = hashnodecreate(nhash(t));
+  nodevector(t) = hashnodecreate(nnew);
+  nhash(t) = nnew;
   for (i=0; i<nold; i++) {
     Node *n = vold+i;
     if (ttype(ref(n)) != LUA_T_NIL && ttype(val(n)) != LUA_T_NIL)
       *node(t, present(t, ref(n))) = *n;  /* copy old node to luaM_new hash */
   }
-  L->nblocks += gcsize(t->nhash)-gcsize(nold);
+  L->nblocks += gcsize(nnew)-gcsize(nold);
   luaM_free(vold);
 }