more efficient representation for small tables

adding tablep and table.clone

fixing bug with filename string in load
This commit is contained in:
JeffBezanson 2008-12-22 06:36:50 +00:00
parent dfacb4d897
commit 8e4ba69a7b
9 changed files with 92 additions and 64 deletions

View File

@ -45,7 +45,7 @@ static size_t nfinalizers=0;
static size_t maxfinalizers=0;
static size_t malloc_pressure = 0;
static void add_finalizer(cvalue_t *cv)
void add_finalizer(cvalue_t *cv)
{
if (nfinalizers == maxfinalizers) {
size_t nn = (maxfinalizers==0 ? 256 : maxfinalizers*2);
@ -87,6 +87,10 @@ static void sweep_finalizers()
} while ((n < l-ndel) && SWAP_sf(lst[n],lst[n+ndel]));
nfinalizers -= ndel;
#ifdef VERBOSEGC
if (ndel > 0)
printf("GC: finalized %d objects\n", ndel);
#endif
malloc_pressure = 0;
}

View File

@ -462,7 +462,7 @@ void gc(int mustgrow)
sweep_finalizers();
#ifdef VERBOSEGC
printf("gc found %d/%d live conses\n",
printf("GC: found %d/%d live conses\n",
(curheap-tospace)/sizeof(cons_t), heapsize/sizeof(cons_t));
#endif
temp = tospace;
@ -1460,6 +1460,7 @@ value_t load_file(char *fname)
value_t volatile e, v=NIL;
ios_t fi;
ios_t * volatile f;
fname = strdup(fname);
f = &fi; f = ios_file(f, fname, 0, 0);
if (f == NULL) lerror(IOError, "file \"%s\" not found", fname);
FL_TRY {
@ -1476,8 +1477,10 @@ value_t load_file(char *fname)
snprintf(&lerrorbuf[msglen], sizeof(lerrorbuf)-msglen,
"\nin file \"%s\"", fname);
lerrorbuf[sizeof(lerrorbuf)-1] = '\0';
free(fname);
raise(lasterror);
}
free(fname);
ios_close(f);
return v;
}

View File

@ -241,6 +241,7 @@ extern fltype_t *stringtype, *wcstringtype;
extern fltype_t *builtintype;
value_t cvalue(fltype_t *type, size_t sz);
void add_finalizer(cvalue_t *cv);
size_t ctype_sizeof(value_t type, int *palign);
value_t cvalue_copy(value_t v);
value_t cvalue_from_data(fltype_t *type, void *data, size_t sz);

View File

@ -278,11 +278,9 @@
(defmacro dotimes (var . body)
(let ((v (car var))
(cnt (cadr var))
(lim (gensym)))
`(let ((,lim (- ,cnt 1)))
(for 0 ,lim
(lambda (,v) ,(f-body body))))))
(cnt (cadr var)))
`(for 0 (- ,cnt 1)
(lambda (,v) ,(f-body body)))))
(defun map-int (f n)
(if (<= n 0)
@ -421,10 +419,10 @@
l))
(defun self-evaluating-p (x)
(or (eq x nil)
(eq x T)
(and (atom x)
(not (symbolp x)))))
(or (and (atom x)
(not (symbolp x)))
(and (constantp x)
(eq x (eval x)))))
; backquote
(defmacro backquote (x) (bq-process x))
@ -503,3 +501,8 @@
(defun table.values (t)
(table.foldl (lambda (k v z) (cons v z))
() t))
(defun table.clone (t)
(let ((nt (table)))
(table.foldl (lambda (k v z) (put nt k v))
() t)
nt))

View File

@ -11,22 +11,9 @@
static value_t tablesym;
static fltype_t *tabletype;
typedef struct {
void *(*get)(void *t, void *key);
void (*remove)(void *t, void *key);
void **(*bp)(void *t, void *key);
} table_interface_t;
typedef struct {
table_interface_t *ti;
ulong_t nkeys;
htable_t ht;
} fltable_t;
void print_htable(value_t v, ios_t *f, int princ)
{
fltable_t *pt = (fltable_t*)cv_data((cvalue_t*)ptr(v));
htable_t *h = &pt->ht;
htable_t *h = (htable_t*)cv_data((cvalue_t*)ptr(v));
size_t i;
int first=1;
fl_print_str("#table(", f);
@ -44,8 +31,7 @@ void print_htable(value_t v, ios_t *f, int princ)
void print_traverse_htable(value_t self)
{
fltable_t *pt = (fltable_t*)cv_data((cvalue_t*)ptr(self));
htable_t *h = &pt->ht;
htable_t *h = (htable_t*)cv_data((cvalue_t*)ptr(self));
size_t i;
for(i=0; i < h->size; i+=2) {
if (h->table[i+1] != HT_NOTFOUND) {
@ -57,15 +43,16 @@ void print_traverse_htable(value_t self)
void free_htable(value_t self)
{
fltable_t *pt = (fltable_t*)cv_data((cvalue_t*)ptr(self));
htable_free(&pt->ht);
htable_t *h = (htable_t*)cv_data((cvalue_t*)ptr(self));
htable_free(h);
}
void relocate_htable(value_t oldv, value_t newv)
{
(void)oldv;
fltable_t *pt = (fltable_t*)cv_data((cvalue_t*)ptr(newv));
htable_t *h = &pt->ht;
htable_t *oldh = (htable_t*)cv_data((cvalue_t*)ptr(oldv));
htable_t *h = (htable_t*)cv_data((cvalue_t*)ptr(newv));
if (oldh->table == &oldh->_space[0])
h->table = &h->_space[0];
size_t i;
for(i=0; i < h->size; i++) {
if (h->table[i] != HT_NOTFOUND)
@ -81,16 +68,16 @@ int ishashtable(value_t v)
return iscvalue(v) && cv_class((cvalue_t*)ptr(v)) == tabletype;
}
value_t fl_hashtablep(value_t *args, uint32_t nargs)
value_t fl_tablep(value_t *args, uint32_t nargs)
{
argcount("hashtablep", nargs, 1);
argcount("tablep", nargs, 1);
return ishashtable(args[0]) ? T : NIL;
}
static fltable_t *totable(value_t v, char *fname)
static htable_t *totable(value_t v, char *fname)
{
if (ishashtable(v))
return (fltable_t*)cv_data((cvalue_t*)ptr(v));
return (htable_t*)cv_data((cvalue_t*)ptr(v));
type_error(fname, "table", v);
return NULL;
}
@ -99,12 +86,21 @@ value_t fl_table(value_t *args, uint32_t nargs)
{
if (nargs & 1)
lerror(ArgError, "table: arguments must come in pairs");
value_t nt = cvalue(tabletype, sizeof(fltable_t));
fltable_t *h = (fltable_t*)cv_data((cvalue_t*)ptr(nt));
htable_new(&h->ht, 8);
value_t nt;
// prevent small tables from being added to finalizer list
if (nargs <= HT_N_INLINE) {
tabletype->vtable->finalize = NULL;
nt = cvalue(tabletype, sizeof(htable_t));
tabletype->vtable->finalize = free_htable;
}
else {
nt = cvalue(tabletype, 2*sizeof(void*));
}
htable_t *h = (htable_t*)cv_data((cvalue_t*)ptr(nt));
htable_new(h, nargs/2);
uint32_t i;
for(i=0; i < nargs; i+=2)
equalhash_put(&h->ht, (void*)args[i], (void*)args[i+1]);
equalhash_put(h, (void*)args[i], (void*)args[i+1]);
return nt;
}
@ -112,8 +108,15 @@ value_t fl_table(value_t *args, uint32_t nargs)
value_t fl_table_put(value_t *args, uint32_t nargs)
{
argcount("put", nargs, 3);
fltable_t *pt = totable(args[0], "put");
equalhash_put(&pt->ht, (void*)args[1], (void*)args[2]);
htable_t *h = totable(args[0], "put");
void **table0 = h->table;
equalhash_put(h, (void*)args[1], (void*)args[2]);
// register finalizer if we outgrew inline space
if (table0 == &h->_space[0] && h->table != &h->_space[0]) {
cvalue_t *cv = (cvalue_t*)ptr(args[0]);
add_finalizer(cv);
cv->len = 2*sizeof(void*);
}
return args[0];
}
@ -122,8 +125,8 @@ value_t fl_table_get(value_t *args, uint32_t nargs)
{
if (nargs != 3)
argcount("get", nargs, 2);
fltable_t *pt = totable(args[0], "get");
value_t v = (value_t)equalhash_get(&pt->ht, (void*)args[1]);
htable_t *h = totable(args[0], "get");
value_t v = (value_t)equalhash_get(h, (void*)args[1]);
if (v == (value_t)HT_NOTFOUND) {
if (nargs == 3)
return args[2];
@ -136,16 +139,16 @@ value_t fl_table_get(value_t *args, uint32_t nargs)
value_t fl_table_has(value_t *args, uint32_t nargs)
{
argcount("has", nargs, 2);
fltable_t *pt = totable(args[0], "has");
return equalhash_has(&pt->ht, (void*)args[1]) ? T : NIL;
htable_t *h = totable(args[0], "has");
return equalhash_has(h, (void*)args[1]) ? T : NIL;
}
// (del table key)
value_t fl_table_del(value_t *args, uint32_t nargs)
{
argcount("del", nargs, 2);
fltable_t *pt = totable(args[0], "del");
if (!equalhash_remove(&pt->ht, (void*)args[1]))
htable_t *h = totable(args[0], "del");
if (!equalhash_remove(h, (void*)args[1]))
lerror(KeyError, "del: key not found");
return args[0];
}
@ -154,9 +157,9 @@ value_t fl_table_foldl(value_t *args, uint32_t nargs)
{
argcount("table.foldl", nargs, 3);
PUSH(listn(3, NIL, NIL, NIL));
fltable_t *pt = totable(args[2], "table.foldl");
size_t i, n = pt->ht.size;
void **table = pt->ht.table;
htable_t *h = totable(args[2], "table.foldl");
size_t i, n = h->size;
void **table = h->table;
value_t c;
for(i=0; i < n; i+=2) {
if (table[i+1] != HT_NOTFOUND) {
@ -166,7 +169,7 @@ value_t fl_table_foldl(value_t *args, uint32_t nargs)
car_(cdr_(cdr_(c))) = args[1];
args[1] = apply(args[0], c);
// reload pointer
table = ((fltable_t*)cv_data((cvalue_t*)ptr(args[2])))->ht.table;
table = ((htable_t*)cv_data((cvalue_t*)ptr(args[2])))->table;
}
}
(void)POP();
@ -175,6 +178,7 @@ value_t fl_table_foldl(value_t *args, uint32_t nargs)
static builtinspec_t tablefunc_info[] = {
{ "table", fl_table },
{ "tablep", fl_tablep },
{ "put", fl_table_put },
{ "get", fl_table_get },
{ "has", fl_table_has },
@ -186,7 +190,7 @@ static builtinspec_t tablefunc_info[] = {
void table_init()
{
tablesym = symbol("table");
tabletype = define_opaque_type(tablesym, sizeof(fltable_t),
tabletype = define_opaque_type(tablesym, sizeof(htable_t),
&table_vtable, NULL);
assign_global_builtins(tablefunc_info);
}

View File

@ -925,8 +925,7 @@ consolidated todo list as of 8/30:
* new cvalues, types representation
- use the unused tag for TAG_PRIM, add smaller prim representation
* finalizers in gc
- hashtable
- special representation for small tables w/o finalizer
* hashtable
- expose io stream object
- enable print-shared for cvalues' types

View File

@ -14,11 +14,17 @@
htable_t *htable_new(htable_t *h, size_t size)
{
size = nextipow2(size);
size *= 2; // 2 pointers per key/value pair
size *= 2; // aim for 50% occupancy
h->size = size;
h->table = (void**)malloc(size*sizeof(void*));
if (size <= HT_N_INLINE/2) {
h->size = size = HT_N_INLINE;
h->table = &h->_space[0];
}
else {
size = nextipow2(size);
size *= 2; // 2 pointers per key/value pair
size *= 2; // aim for 50% occupancy
h->size = size;
h->table = (void**)malloc(size*sizeof(void*));
}
if (h->table == NULL) return NULL;
size_t i;
for(i=0; i < size; i++)
@ -28,13 +34,15 @@ htable_t *htable_new(htable_t *h, size_t size)
void htable_free(htable_t *h)
{
free(h->table);
if (h->table != &h->_space[0])
free(h->table);
}
// empty and reduce size
void htable_reset(htable_t *h, size_t sz)
{
if (h->size > sz*4) {
sz = nextipow2(sz);
if (h->size > sz*4 && h->size > HT_N_INLINE) {
size_t newsz = sz*4;
void **newtab = (void**)realloc(h->table, newsz*sizeof(void*));
if (newtab == NULL)

View File

@ -1,9 +1,12 @@
#ifndef __HTABLE_H_
#define __HTABLE_H_
#define HT_N_INLINE 16
typedef struct {
size_t size;
void **table;
void *_space[HT_N_INLINE];
} htable_t;
// define this to be an invalid key/value

View File

@ -7,7 +7,7 @@
#define hash_size(h) ((h)->size/2)
// compute empirical max-probe for a given size
#define max_probe(size) ((size)>>5)
#define max_probe(size) ((size)<=HT_N_INLINE/2 ? HT_N_INLINE/2 : (size)>>5)
#define HTIMPL(HTNAME, HFUNC, EQFUNC) \
static void **HTNAME##_lookup_bp(htable_t *h, void *key) \
@ -49,6 +49,8 @@ static void **HTNAME##_lookup_bp(htable_t *h, void *key) \
ol = h->table; \
if (sz >= (1<<19)) \
newsz = sz<<1; \
else if (sz <= HT_N_INLINE) \
newsz = 32; \
else \
newsz = sz<<2; \
/*printf("trying to allocate %d words.\n", newsz); fflush(stdout);*/ \
@ -64,7 +66,8 @@ static void **HTNAME##_lookup_bp(htable_t *h, void *key) \
(*HTNAME##_lookup_bp(h, ol[i])) = ol[i+1]; \
} \
} \
free(ol); \
if (ol != &h->_space[0]) \
free(ol); \
\
sz = hash_size(h); \
maxprobe = max_probe(sz); \