more efficient representation for small tables
adding tablep and table.clone fixing bug with filename string in load
This commit is contained in:
parent
dfacb4d897
commit
8e4ba69a7b
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
22
llt/htable.c
22
llt/htable.c
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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); \
|
||||
|
|
Loading…
Reference in New Issue