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 maxfinalizers=0;
|
||||||
static size_t malloc_pressure = 0;
|
static size_t malloc_pressure = 0;
|
||||||
|
|
||||||
static void add_finalizer(cvalue_t *cv)
|
void add_finalizer(cvalue_t *cv)
|
||||||
{
|
{
|
||||||
if (nfinalizers == maxfinalizers) {
|
if (nfinalizers == maxfinalizers) {
|
||||||
size_t nn = (maxfinalizers==0 ? 256 : maxfinalizers*2);
|
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]));
|
} while ((n < l-ndel) && SWAP_sf(lst[n],lst[n+ndel]));
|
||||||
|
|
||||||
nfinalizers -= ndel;
|
nfinalizers -= ndel;
|
||||||
|
#ifdef VERBOSEGC
|
||||||
|
if (ndel > 0)
|
||||||
|
printf("GC: finalized %d objects\n", ndel);
|
||||||
|
#endif
|
||||||
|
|
||||||
malloc_pressure = 0;
|
malloc_pressure = 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -462,7 +462,7 @@ void gc(int mustgrow)
|
||||||
sweep_finalizers();
|
sweep_finalizers();
|
||||||
|
|
||||||
#ifdef VERBOSEGC
|
#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));
|
(curheap-tospace)/sizeof(cons_t), heapsize/sizeof(cons_t));
|
||||||
#endif
|
#endif
|
||||||
temp = tospace;
|
temp = tospace;
|
||||||
|
@ -1460,6 +1460,7 @@ value_t load_file(char *fname)
|
||||||
value_t volatile e, v=NIL;
|
value_t volatile e, v=NIL;
|
||||||
ios_t fi;
|
ios_t fi;
|
||||||
ios_t * volatile f;
|
ios_t * volatile f;
|
||||||
|
fname = strdup(fname);
|
||||||
f = &fi; f = ios_file(f, fname, 0, 0);
|
f = &fi; f = ios_file(f, fname, 0, 0);
|
||||||
if (f == NULL) lerror(IOError, "file \"%s\" not found", fname);
|
if (f == NULL) lerror(IOError, "file \"%s\" not found", fname);
|
||||||
FL_TRY {
|
FL_TRY {
|
||||||
|
@ -1476,8 +1477,10 @@ value_t load_file(char *fname)
|
||||||
snprintf(&lerrorbuf[msglen], sizeof(lerrorbuf)-msglen,
|
snprintf(&lerrorbuf[msglen], sizeof(lerrorbuf)-msglen,
|
||||||
"\nin file \"%s\"", fname);
|
"\nin file \"%s\"", fname);
|
||||||
lerrorbuf[sizeof(lerrorbuf)-1] = '\0';
|
lerrorbuf[sizeof(lerrorbuf)-1] = '\0';
|
||||||
|
free(fname);
|
||||||
raise(lasterror);
|
raise(lasterror);
|
||||||
}
|
}
|
||||||
|
free(fname);
|
||||||
ios_close(f);
|
ios_close(f);
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
|
@ -241,6 +241,7 @@ extern fltype_t *stringtype, *wcstringtype;
|
||||||
extern fltype_t *builtintype;
|
extern fltype_t *builtintype;
|
||||||
|
|
||||||
value_t cvalue(fltype_t *type, size_t sz);
|
value_t cvalue(fltype_t *type, size_t sz);
|
||||||
|
void add_finalizer(cvalue_t *cv);
|
||||||
size_t ctype_sizeof(value_t type, int *palign);
|
size_t ctype_sizeof(value_t type, int *palign);
|
||||||
value_t cvalue_copy(value_t v);
|
value_t cvalue_copy(value_t v);
|
||||||
value_t cvalue_from_data(fltype_t *type, void *data, size_t sz);
|
value_t cvalue_from_data(fltype_t *type, void *data, size_t sz);
|
||||||
|
|
|
@ -278,11 +278,9 @@
|
||||||
|
|
||||||
(defmacro dotimes (var . body)
|
(defmacro dotimes (var . body)
|
||||||
(let ((v (car var))
|
(let ((v (car var))
|
||||||
(cnt (cadr var))
|
(cnt (cadr var)))
|
||||||
(lim (gensym)))
|
`(for 0 (- ,cnt 1)
|
||||||
`(let ((,lim (- ,cnt 1)))
|
(lambda (,v) ,(f-body body)))))
|
||||||
(for 0 ,lim
|
|
||||||
(lambda (,v) ,(f-body body))))))
|
|
||||||
|
|
||||||
(defun map-int (f n)
|
(defun map-int (f n)
|
||||||
(if (<= n 0)
|
(if (<= n 0)
|
||||||
|
@ -421,10 +419,10 @@
|
||||||
l))
|
l))
|
||||||
|
|
||||||
(defun self-evaluating-p (x)
|
(defun self-evaluating-p (x)
|
||||||
(or (eq x nil)
|
(or (and (atom x)
|
||||||
(eq x T)
|
(not (symbolp x)))
|
||||||
(and (atom x)
|
(and (constantp x)
|
||||||
(not (symbolp x)))))
|
(eq x (eval x)))))
|
||||||
|
|
||||||
; backquote
|
; backquote
|
||||||
(defmacro backquote (x) (bq-process x))
|
(defmacro backquote (x) (bq-process x))
|
||||||
|
@ -503,3 +501,8 @@
|
||||||
(defun table.values (t)
|
(defun table.values (t)
|
||||||
(table.foldl (lambda (k v z) (cons v z))
|
(table.foldl (lambda (k v z) (cons v z))
|
||||||
() t))
|
() 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 value_t tablesym;
|
||||||
static fltype_t *tabletype;
|
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)
|
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 = (htable_t*)cv_data((cvalue_t*)ptr(v));
|
||||||
htable_t *h = &pt->ht;
|
|
||||||
size_t i;
|
size_t i;
|
||||||
int first=1;
|
int first=1;
|
||||||
fl_print_str("#table(", f);
|
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)
|
void print_traverse_htable(value_t self)
|
||||||
{
|
{
|
||||||
fltable_t *pt = (fltable_t*)cv_data((cvalue_t*)ptr(self));
|
htable_t *h = (htable_t*)cv_data((cvalue_t*)ptr(self));
|
||||||
htable_t *h = &pt->ht;
|
|
||||||
size_t i;
|
size_t i;
|
||||||
for(i=0; i < h->size; i+=2) {
|
for(i=0; i < h->size; i+=2) {
|
||||||
if (h->table[i+1] != HT_NOTFOUND) {
|
if (h->table[i+1] != HT_NOTFOUND) {
|
||||||
|
@ -57,15 +43,16 @@ void print_traverse_htable(value_t self)
|
||||||
|
|
||||||
void free_htable(value_t self)
|
void free_htable(value_t self)
|
||||||
{
|
{
|
||||||
fltable_t *pt = (fltable_t*)cv_data((cvalue_t*)ptr(self));
|
htable_t *h = (htable_t*)cv_data((cvalue_t*)ptr(self));
|
||||||
htable_free(&pt->ht);
|
htable_free(h);
|
||||||
}
|
}
|
||||||
|
|
||||||
void relocate_htable(value_t oldv, value_t newv)
|
void relocate_htable(value_t oldv, value_t newv)
|
||||||
{
|
{
|
||||||
(void)oldv;
|
htable_t *oldh = (htable_t*)cv_data((cvalue_t*)ptr(oldv));
|
||||||
fltable_t *pt = (fltable_t*)cv_data((cvalue_t*)ptr(newv));
|
htable_t *h = (htable_t*)cv_data((cvalue_t*)ptr(newv));
|
||||||
htable_t *h = &pt->ht;
|
if (oldh->table == &oldh->_space[0])
|
||||||
|
h->table = &h->_space[0];
|
||||||
size_t i;
|
size_t i;
|
||||||
for(i=0; i < h->size; i++) {
|
for(i=0; i < h->size; i++) {
|
||||||
if (h->table[i] != HT_NOTFOUND)
|
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;
|
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;
|
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))
|
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);
|
type_error(fname, "table", v);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -99,12 +86,21 @@ value_t fl_table(value_t *args, uint32_t nargs)
|
||||||
{
|
{
|
||||||
if (nargs & 1)
|
if (nargs & 1)
|
||||||
lerror(ArgError, "table: arguments must come in pairs");
|
lerror(ArgError, "table: arguments must come in pairs");
|
||||||
value_t nt = cvalue(tabletype, sizeof(fltable_t));
|
value_t nt;
|
||||||
fltable_t *h = (fltable_t*)cv_data((cvalue_t*)ptr(nt));
|
// prevent small tables from being added to finalizer list
|
||||||
htable_new(&h->ht, 8);
|
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;
|
uint32_t i;
|
||||||
for(i=0; i < nargs; i+=2)
|
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;
|
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)
|
value_t fl_table_put(value_t *args, uint32_t nargs)
|
||||||
{
|
{
|
||||||
argcount("put", nargs, 3);
|
argcount("put", nargs, 3);
|
||||||
fltable_t *pt = totable(args[0], "put");
|
htable_t *h = totable(args[0], "put");
|
||||||
equalhash_put(&pt->ht, (void*)args[1], (void*)args[2]);
|
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];
|
return args[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -122,8 +125,8 @@ value_t fl_table_get(value_t *args, uint32_t nargs)
|
||||||
{
|
{
|
||||||
if (nargs != 3)
|
if (nargs != 3)
|
||||||
argcount("get", nargs, 2);
|
argcount("get", nargs, 2);
|
||||||
fltable_t *pt = totable(args[0], "get");
|
htable_t *h = totable(args[0], "get");
|
||||||
value_t v = (value_t)equalhash_get(&pt->ht, (void*)args[1]);
|
value_t v = (value_t)equalhash_get(h, (void*)args[1]);
|
||||||
if (v == (value_t)HT_NOTFOUND) {
|
if (v == (value_t)HT_NOTFOUND) {
|
||||||
if (nargs == 3)
|
if (nargs == 3)
|
||||||
return args[2];
|
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)
|
value_t fl_table_has(value_t *args, uint32_t nargs)
|
||||||
{
|
{
|
||||||
argcount("has", nargs, 2);
|
argcount("has", nargs, 2);
|
||||||
fltable_t *pt = totable(args[0], "has");
|
htable_t *h = totable(args[0], "has");
|
||||||
return equalhash_has(&pt->ht, (void*)args[1]) ? T : NIL;
|
return equalhash_has(h, (void*)args[1]) ? T : NIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// (del table key)
|
// (del table key)
|
||||||
value_t fl_table_del(value_t *args, uint32_t nargs)
|
value_t fl_table_del(value_t *args, uint32_t nargs)
|
||||||
{
|
{
|
||||||
argcount("del", nargs, 2);
|
argcount("del", nargs, 2);
|
||||||
fltable_t *pt = totable(args[0], "del");
|
htable_t *h = totable(args[0], "del");
|
||||||
if (!equalhash_remove(&pt->ht, (void*)args[1]))
|
if (!equalhash_remove(h, (void*)args[1]))
|
||||||
lerror(KeyError, "del: key not found");
|
lerror(KeyError, "del: key not found");
|
||||||
return args[0];
|
return args[0];
|
||||||
}
|
}
|
||||||
|
@ -154,9 +157,9 @@ value_t fl_table_foldl(value_t *args, uint32_t nargs)
|
||||||
{
|
{
|
||||||
argcount("table.foldl", nargs, 3);
|
argcount("table.foldl", nargs, 3);
|
||||||
PUSH(listn(3, NIL, NIL, NIL));
|
PUSH(listn(3, NIL, NIL, NIL));
|
||||||
fltable_t *pt = totable(args[2], "table.foldl");
|
htable_t *h = totable(args[2], "table.foldl");
|
||||||
size_t i, n = pt->ht.size;
|
size_t i, n = h->size;
|
||||||
void **table = pt->ht.table;
|
void **table = h->table;
|
||||||
value_t c;
|
value_t c;
|
||||||
for(i=0; i < n; i+=2) {
|
for(i=0; i < n; i+=2) {
|
||||||
if (table[i+1] != HT_NOTFOUND) {
|
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];
|
car_(cdr_(cdr_(c))) = args[1];
|
||||||
args[1] = apply(args[0], c);
|
args[1] = apply(args[0], c);
|
||||||
// reload pointer
|
// 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();
|
(void)POP();
|
||||||
|
@ -175,6 +178,7 @@ value_t fl_table_foldl(value_t *args, uint32_t nargs)
|
||||||
|
|
||||||
static builtinspec_t tablefunc_info[] = {
|
static builtinspec_t tablefunc_info[] = {
|
||||||
{ "table", fl_table },
|
{ "table", fl_table },
|
||||||
|
{ "tablep", fl_tablep },
|
||||||
{ "put", fl_table_put },
|
{ "put", fl_table_put },
|
||||||
{ "get", fl_table_get },
|
{ "get", fl_table_get },
|
||||||
{ "has", fl_table_has },
|
{ "has", fl_table_has },
|
||||||
|
@ -186,7 +190,7 @@ static builtinspec_t tablefunc_info[] = {
|
||||||
void table_init()
|
void table_init()
|
||||||
{
|
{
|
||||||
tablesym = symbol("table");
|
tablesym = symbol("table");
|
||||||
tabletype = define_opaque_type(tablesym, sizeof(fltable_t),
|
tabletype = define_opaque_type(tablesym, sizeof(htable_t),
|
||||||
&table_vtable, NULL);
|
&table_vtable, NULL);
|
||||||
assign_global_builtins(tablefunc_info);
|
assign_global_builtins(tablefunc_info);
|
||||||
}
|
}
|
||||||
|
|
|
@ -925,8 +925,7 @@ consolidated todo list as of 8/30:
|
||||||
* new cvalues, types representation
|
* new cvalues, types representation
|
||||||
- use the unused tag for TAG_PRIM, add smaller prim representation
|
- use the unused tag for TAG_PRIM, add smaller prim representation
|
||||||
* finalizers in gc
|
* finalizers in gc
|
||||||
- hashtable
|
* hashtable
|
||||||
- special representation for small tables w/o finalizer
|
|
||||||
- expose io stream object
|
- expose io stream object
|
||||||
|
|
||||||
- enable print-shared for cvalues' types
|
- enable print-shared for cvalues' types
|
||||||
|
|
10
llt/htable.c
10
llt/htable.c
|
@ -14,11 +14,17 @@
|
||||||
|
|
||||||
htable_t *htable_new(htable_t *h, size_t size)
|
htable_t *htable_new(htable_t *h, size_t size)
|
||||||
{
|
{
|
||||||
|
if (size <= HT_N_INLINE/2) {
|
||||||
|
h->size = size = HT_N_INLINE;
|
||||||
|
h->table = &h->_space[0];
|
||||||
|
}
|
||||||
|
else {
|
||||||
size = nextipow2(size);
|
size = nextipow2(size);
|
||||||
size *= 2; // 2 pointers per key/value pair
|
size *= 2; // 2 pointers per key/value pair
|
||||||
size *= 2; // aim for 50% occupancy
|
size *= 2; // aim for 50% occupancy
|
||||||
h->size = size;
|
h->size = size;
|
||||||
h->table = (void**)malloc(size*sizeof(void*));
|
h->table = (void**)malloc(size*sizeof(void*));
|
||||||
|
}
|
||||||
if (h->table == NULL) return NULL;
|
if (h->table == NULL) return NULL;
|
||||||
size_t i;
|
size_t i;
|
||||||
for(i=0; i < size; 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)
|
void htable_free(htable_t *h)
|
||||||
{
|
{
|
||||||
|
if (h->table != &h->_space[0])
|
||||||
free(h->table);
|
free(h->table);
|
||||||
}
|
}
|
||||||
|
|
||||||
// empty and reduce size
|
// empty and reduce size
|
||||||
void htable_reset(htable_t *h, size_t sz)
|
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;
|
size_t newsz = sz*4;
|
||||||
void **newtab = (void**)realloc(h->table, newsz*sizeof(void*));
|
void **newtab = (void**)realloc(h->table, newsz*sizeof(void*));
|
||||||
if (newtab == NULL)
|
if (newtab == NULL)
|
||||||
|
|
|
@ -1,9 +1,12 @@
|
||||||
#ifndef __HTABLE_H_
|
#ifndef __HTABLE_H_
|
||||||
#define __HTABLE_H_
|
#define __HTABLE_H_
|
||||||
|
|
||||||
|
#define HT_N_INLINE 16
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
size_t size;
|
size_t size;
|
||||||
void **table;
|
void **table;
|
||||||
|
void *_space[HT_N_INLINE];
|
||||||
} htable_t;
|
} htable_t;
|
||||||
|
|
||||||
// define this to be an invalid key/value
|
// define this to be an invalid key/value
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
#define hash_size(h) ((h)->size/2)
|
#define hash_size(h) ((h)->size/2)
|
||||||
|
|
||||||
// compute empirical max-probe for a given size
|
// 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) \
|
#define HTIMPL(HTNAME, HFUNC, EQFUNC) \
|
||||||
static void **HTNAME##_lookup_bp(htable_t *h, void *key) \
|
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; \
|
ol = h->table; \
|
||||||
if (sz >= (1<<19)) \
|
if (sz >= (1<<19)) \
|
||||||
newsz = sz<<1; \
|
newsz = sz<<1; \
|
||||||
|
else if (sz <= HT_N_INLINE) \
|
||||||
|
newsz = 32; \
|
||||||
else \
|
else \
|
||||||
newsz = sz<<2; \
|
newsz = sz<<2; \
|
||||||
/*printf("trying to allocate %d words.\n", newsz); fflush(stdout);*/ \
|
/*printf("trying to allocate %d words.\n", newsz); fflush(stdout);*/ \
|
||||||
|
@ -64,6 +66,7 @@ static void **HTNAME##_lookup_bp(htable_t *h, void *key) \
|
||||||
(*HTNAME##_lookup_bp(h, ol[i])) = ol[i+1]; \
|
(*HTNAME##_lookup_bp(h, ol[i])) = ol[i+1]; \
|
||||||
} \
|
} \
|
||||||
} \
|
} \
|
||||||
|
if (ol != &h->_space[0]) \
|
||||||
free(ol); \
|
free(ol); \
|
||||||
\
|
\
|
||||||
sz = hash_size(h); \
|
sz = hash_size(h); \
|
||||||
|
|
Loading…
Reference in New Issue