2008-09-06 18:19:51 -04:00
|
|
|
#include <sys/types.h>
|
2019-08-09 12:00:17 -04:00
|
|
|
|
|
|
|
#include <assert.h>
|
2010-05-02 14:17:47 -04:00
|
|
|
#include <setjmp.h>
|
2019-08-09 12:00:17 -04:00
|
|
|
#include <stdarg.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
#include "dtypes.h"
|
|
|
|
#include "utils.h"
|
|
|
|
#include "utf8.h"
|
|
|
|
#include "ios.h"
|
|
|
|
#include "socket.h"
|
|
|
|
#include "timefuncs.h"
|
|
|
|
#include "hashing.h"
|
|
|
|
#include "htable.h"
|
|
|
|
#include "htableh_inc.h"
|
|
|
|
#include "bitvector.h"
|
|
|
|
#include "dirpath.h"
|
|
|
|
#include "random.h"
|
2008-09-06 18:19:51 -04:00
|
|
|
#include "llt.h"
|
2019-08-09 12:00:17 -04:00
|
|
|
|
2008-09-06 18:19:51 -04:00
|
|
|
#include "flisp.h"
|
2008-12-21 00:55:00 -05:00
|
|
|
#include "equalhash.h"
|
2008-09-06 18:19:51 -04:00
|
|
|
|
2008-12-20 01:16:00 -05:00
|
|
|
static value_t tablesym;
|
|
|
|
static fltype_t *tabletype;
|
|
|
|
|
2019-08-09 12:26:20 -04:00
|
|
|
void print_htable(value_t v, struct ios *f)
|
2008-09-06 18:19:51 -04:00
|
|
|
{
|
2019-08-09 12:26:09 -04:00
|
|
|
struct htable *h = (struct htable *)cv_data((cvalue_t *)ptr(v));
|
2008-12-20 01:16:00 -05:00
|
|
|
size_t i;
|
2019-08-09 07:02:02 -04:00
|
|
|
int first = 1;
|
2008-12-20 01:16:00 -05:00
|
|
|
fl_print_str("#table(", f);
|
2019-08-09 07:02:02 -04:00
|
|
|
for (i = 0; i < h->size; i += 2) {
|
|
|
|
if (h->table[i + 1] != HT_NOTFOUND) {
|
|
|
|
if (!first)
|
|
|
|
fl_print_str(" ", f);
|
2009-05-05 00:01:06 -04:00
|
|
|
fl_print_child(f, (value_t)h->table[i]);
|
2008-12-20 01:16:00 -05:00
|
|
|
fl_print_chr(' ', f);
|
2019-08-09 07:02:02 -04:00
|
|
|
fl_print_child(f, (value_t)h->table[i + 1]);
|
2008-12-20 01:16:00 -05:00
|
|
|
first = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
fl_print_chr(')', f);
|
2008-09-06 18:19:51 -04:00
|
|
|
}
|
|
|
|
|
2008-12-21 00:55:00 -05:00
|
|
|
void print_traverse_htable(value_t self)
|
|
|
|
{
|
2019-08-09 12:26:09 -04:00
|
|
|
struct htable *h = (struct htable *)cv_data((cvalue_t *)ptr(self));
|
2008-12-21 00:55:00 -05:00
|
|
|
size_t i;
|
2019-08-09 07:02:02 -04:00
|
|
|
for (i = 0; i < h->size; i += 2) {
|
|
|
|
if (h->table[i + 1] != HT_NOTFOUND) {
|
2008-12-21 00:55:00 -05:00
|
|
|
print_traverse((value_t)h->table[i]);
|
2019-08-09 07:02:02 -04:00
|
|
|
print_traverse((value_t)h->table[i + 1]);
|
2008-12-21 00:55:00 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-09-06 18:19:51 -04:00
|
|
|
void free_htable(value_t self)
|
|
|
|
{
|
2019-08-09 12:26:09 -04:00
|
|
|
struct htable *h = (struct htable *)cv_data((cvalue_t *)ptr(self));
|
2008-12-22 01:36:50 -05:00
|
|
|
htable_free(h);
|
2008-09-06 18:19:51 -04:00
|
|
|
}
|
|
|
|
|
2008-11-28 16:44:59 -05:00
|
|
|
void relocate_htable(value_t oldv, value_t newv)
|
2008-09-06 18:19:51 -04:00
|
|
|
{
|
2019-08-09 12:26:09 -04:00
|
|
|
struct htable *oldh = (struct htable *)cv_data((cvalue_t *)ptr(oldv));
|
|
|
|
struct htable *h = (struct htable *)cv_data((cvalue_t *)ptr(newv));
|
2008-12-22 01:36:50 -05:00
|
|
|
if (oldh->table == &oldh->_space[0])
|
|
|
|
h->table = &h->_space[0];
|
2008-09-06 18:19:51 -04:00
|
|
|
size_t i;
|
2019-08-09 07:02:02 -04:00
|
|
|
for (i = 0; i < h->size; i++) {
|
2008-11-23 02:12:37 -05:00
|
|
|
if (h->table[i] != HT_NOTFOUND)
|
2019-08-09 07:02:02 -04:00
|
|
|
h->table[i] = (void *)relocate_lispvalue((value_t)h->table[i]);
|
2008-09-06 18:19:51 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-12-21 00:55:00 -05:00
|
|
|
cvtable_t table_vtable = { print_htable, relocate_htable, free_htable,
|
|
|
|
print_traverse_htable };
|
2008-09-06 18:19:51 -04:00
|
|
|
|
|
|
|
int ishashtable(value_t v)
|
|
|
|
{
|
2019-08-09 07:02:02 -04:00
|
|
|
return iscvalue(v) && cv_class((cvalue_t *)ptr(v)) == tabletype;
|
2008-09-06 18:19:51 -04:00
|
|
|
}
|
|
|
|
|
2008-12-22 01:36:50 -05:00
|
|
|
value_t fl_tablep(value_t *args, uint32_t nargs)
|
2008-09-06 18:19:51 -04:00
|
|
|
{
|
switching to scheme #t, #f, and () values
porting code to sort out which NILs are false and which are
empty lists
switching to scheme-style special forms. however you feel about
scheme names vs. CL names, using both is silly.
mostly switching to scheme predicate names, with compatibility
aliases for now. adding set-constant! to make this efficient.
adding null?, eqv?, assq, assv, assoc, memq, memv, member
adding 2-argument form of if
allowing else as final cond condition
looking for init file in same directory as executable, so flisp
can be started from anywhere
renaming T to FL_T, since exporting a 1-character symbol is
not very nice
adding opaque type boilerplate example file
adding correctness checking for the pattern-lambda benchmark
bugfix in int2str
2009-01-28 20:04:23 -05:00
|
|
|
argcount("table?", nargs, 1);
|
|
|
|
return ishashtable(args[0]) ? FL_T : FL_F;
|
2008-09-06 18:19:51 -04:00
|
|
|
}
|
|
|
|
|
2019-08-09 12:26:09 -04:00
|
|
|
static struct htable *totable(value_t v, char *fname)
|
2008-12-21 00:55:00 -05:00
|
|
|
{
|
2009-01-04 21:45:21 -05:00
|
|
|
if (!ishashtable(v))
|
|
|
|
type_error(fname, "table", v);
|
2019-08-09 12:26:09 -04:00
|
|
|
return (struct htable *)cv_data((cvalue_t *)ptr(v));
|
2008-12-21 00:55:00 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
value_t fl_table(value_t *args, uint32_t nargs)
|
2008-09-06 18:19:51 -04:00
|
|
|
{
|
2009-03-26 23:06:55 -04:00
|
|
|
size_t cnt = (size_t)nargs;
|
|
|
|
if (cnt & 1)
|
2008-12-20 01:16:00 -05:00
|
|
|
lerror(ArgError, "table: arguments must come in pairs");
|
2008-12-22 01:36:50 -05:00
|
|
|
value_t nt;
|
|
|
|
// prevent small tables from being added to finalizer list
|
2009-03-26 23:06:55 -04:00
|
|
|
if (cnt <= HT_N_INLINE) {
|
2008-12-22 01:36:50 -05:00
|
|
|
tabletype->vtable->finalize = NULL;
|
2019-08-09 12:26:09 -04:00
|
|
|
nt = cvalue(tabletype, sizeof(struct htable));
|
2008-12-22 01:36:50 -05:00
|
|
|
tabletype->vtable->finalize = free_htable;
|
2019-08-09 07:02:02 -04:00
|
|
|
} else {
|
|
|
|
nt = cvalue(tabletype, 2 * sizeof(void *));
|
2008-12-22 01:36:50 -05:00
|
|
|
}
|
2019-08-09 12:26:09 -04:00
|
|
|
struct htable *h = (struct htable *)cv_data((cvalue_t *)ptr(nt));
|
2019-08-09 07:02:02 -04:00
|
|
|
htable_new(h, cnt / 2);
|
2008-12-21 00:55:00 -05:00
|
|
|
uint32_t i;
|
2019-08-09 07:02:02 -04:00
|
|
|
value_t k = FL_NIL, arg = FL_NIL;
|
|
|
|
FOR_ARGS(i, 0, arg, args)
|
|
|
|
{
|
|
|
|
if (i & 1)
|
|
|
|
equalhash_put(h, (void *)k, (void *)arg);
|
2009-03-26 23:06:55 -04:00
|
|
|
else
|
|
|
|
k = arg;
|
|
|
|
}
|
2008-12-20 01:16:00 -05:00
|
|
|
return nt;
|
2008-09-06 18:19:51 -04:00
|
|
|
}
|
|
|
|
|
2009-01-31 20:53:58 -05:00
|
|
|
// (put! table key value)
|
2008-12-21 00:55:00 -05:00
|
|
|
value_t fl_table_put(value_t *args, uint32_t nargs)
|
2008-09-06 18:19:51 -04:00
|
|
|
{
|
2009-01-31 20:53:58 -05:00
|
|
|
argcount("put!", nargs, 3);
|
2019-08-09 12:26:09 -04:00
|
|
|
struct htable *h = totable(args[0], "put!");
|
2008-12-22 01:36:50 -05:00
|
|
|
void **table0 = h->table;
|
2019-08-09 07:02:02 -04:00
|
|
|
equalhash_put(h, (void *)args[1], (void *)args[2]);
|
2008-12-22 01:36:50 -05:00
|
|
|
// register finalizer if we outgrew inline space
|
|
|
|
if (table0 == &h->_space[0] && h->table != &h->_space[0]) {
|
2019-08-09 07:02:02 -04:00
|
|
|
cvalue_t *cv = (cvalue_t *)ptr(args[0]);
|
2008-12-22 01:36:50 -05:00
|
|
|
add_finalizer(cv);
|
2019-08-09 07:02:02 -04:00
|
|
|
cv->len = 2 * sizeof(void *);
|
2008-12-22 01:36:50 -05:00
|
|
|
}
|
2008-12-21 00:55:00 -05:00
|
|
|
return args[0];
|
2008-09-06 18:19:51 -04:00
|
|
|
}
|
|
|
|
|
2009-03-23 16:44:19 -04:00
|
|
|
static void key_error(char *fname, value_t key)
|
|
|
|
{
|
2010-04-29 14:01:26 -04:00
|
|
|
lerrorf(fl_list2(KeyError, key), "%s: key not found", fname);
|
2009-03-23 16:44:19 -04:00
|
|
|
}
|
|
|
|
|
2008-12-20 01:16:00 -05:00
|
|
|
// (get table key [default])
|
2008-12-21 00:55:00 -05:00
|
|
|
value_t fl_table_get(value_t *args, uint32_t nargs)
|
2008-09-06 18:19:51 -04:00
|
|
|
{
|
2008-12-21 00:55:00 -05:00
|
|
|
if (nargs != 3)
|
|
|
|
argcount("get", nargs, 2);
|
2019-08-09 12:26:09 -04:00
|
|
|
struct htable *h = totable(args[0], "get");
|
2019-08-09 07:02:02 -04:00
|
|
|
value_t v = (value_t)equalhash_get(h, (void *)args[1]);
|
2008-12-21 00:55:00 -05:00
|
|
|
if (v == (value_t)HT_NOTFOUND) {
|
|
|
|
if (nargs == 3)
|
|
|
|
return args[2];
|
2009-03-23 16:44:19 -04:00
|
|
|
key_error("get", args[1]);
|
2008-12-21 00:55:00 -05:00
|
|
|
}
|
|
|
|
return v;
|
2008-09-06 18:19:51 -04:00
|
|
|
}
|
|
|
|
|
2009-03-21 22:05:26 -04:00
|
|
|
// (has? table key)
|
2008-12-21 00:55:00 -05:00
|
|
|
value_t fl_table_has(value_t *args, uint32_t nargs)
|
2008-09-06 18:19:51 -04:00
|
|
|
{
|
2008-11-05 23:04:04 -05:00
|
|
|
argcount("has", nargs, 2);
|
2019-08-09 12:26:09 -04:00
|
|
|
struct htable *h = totable(args[0], "has");
|
2019-08-09 07:02:02 -04:00
|
|
|
return equalhash_has(h, (void *)args[1]) ? FL_T : FL_F;
|
2008-09-06 18:19:51 -04:00
|
|
|
}
|
|
|
|
|
2009-01-31 20:53:58 -05:00
|
|
|
// (del! table key)
|
2008-12-21 00:55:00 -05:00
|
|
|
value_t fl_table_del(value_t *args, uint32_t nargs)
|
2008-09-06 18:19:51 -04:00
|
|
|
{
|
2009-01-31 20:53:58 -05:00
|
|
|
argcount("del!", nargs, 2);
|
2019-08-09 12:26:09 -04:00
|
|
|
struct htable *h = totable(args[0], "del!");
|
2019-08-09 07:02:02 -04:00
|
|
|
if (!equalhash_remove(h, (void *)args[1]))
|
2009-03-23 16:44:19 -04:00
|
|
|
key_error("del!", args[1]);
|
2008-12-21 00:55:00 -05:00
|
|
|
return args[0];
|
|
|
|
}
|
|
|
|
|
|
|
|
value_t fl_table_foldl(value_t *args, uint32_t nargs)
|
|
|
|
{
|
|
|
|
argcount("table.foldl", nargs, 3);
|
2019-08-09 07:02:02 -04:00
|
|
|
value_t f = args[0], zero = args[1], t = args[2];
|
2019-08-09 12:26:09 -04:00
|
|
|
struct htable *h = totable(t, "table.foldl");
|
2008-12-22 01:36:50 -05:00
|
|
|
size_t i, n = h->size;
|
|
|
|
void **table = h->table;
|
2009-07-03 14:43:15 -04:00
|
|
|
fl_gc_handle(&f);
|
|
|
|
fl_gc_handle(&zero);
|
|
|
|
fl_gc_handle(&t);
|
2019-08-09 07:02:02 -04:00
|
|
|
for (i = 0; i < n; i += 2) {
|
|
|
|
if (table[i + 1] != HT_NOTFOUND) {
|
|
|
|
zero =
|
|
|
|
fl_applyn(3, f, (value_t)table[i], (value_t)table[i + 1], zero);
|
2008-12-21 00:55:00 -05:00
|
|
|
// reload pointer
|
2019-08-09 12:26:09 -04:00
|
|
|
h = (struct htable *)cv_data((cvalue_t *)ptr(t));
|
2009-03-21 22:05:26 -04:00
|
|
|
if (h->size != n)
|
|
|
|
lerror(EnumerationError, "table.foldl: table modified");
|
|
|
|
table = h->table;
|
2008-12-21 00:55:00 -05:00
|
|
|
}
|
|
|
|
}
|
2009-07-03 14:43:15 -04:00
|
|
|
fl_free_gc_handles(3);
|
|
|
|
return zero;
|
2008-09-06 18:19:51 -04:00
|
|
|
}
|
2008-12-20 01:16:00 -05:00
|
|
|
|
2019-08-09 07:02:02 -04:00
|
|
|
static builtinspec_t tablefunc_info[] = { { "table", fl_table },
|
|
|
|
{ "table?", fl_tablep },
|
|
|
|
{ "put!", fl_table_put },
|
|
|
|
{ "get", fl_table_get },
|
|
|
|
{ "has?", fl_table_has },
|
|
|
|
{ "del!", fl_table_del },
|
|
|
|
{ "table.foldl", fl_table_foldl },
|
|
|
|
{ NULL, NULL } };
|
2008-12-20 01:16:00 -05:00
|
|
|
|
2013-06-08 19:29:15 -04:00
|
|
|
void table_init(void)
|
2008-12-20 01:16:00 -05:00
|
|
|
{
|
|
|
|
tablesym = symbol("table");
|
2019-08-09 07:02:02 -04:00
|
|
|
tabletype =
|
2019-08-09 12:26:09 -04:00
|
|
|
define_opaque_type(tablesym, sizeof(struct htable), &table_vtable, NULL);
|
2008-12-20 01:16:00 -05:00
|
|
|
assign_global_builtins(tablefunc_info);
|
|
|
|
}
|