summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2012-04-07 09:25:07 -0700
committerKaz Kylheku <kaz@kylheku.com>2012-04-07 09:25:07 -0700
commitec19948f35d876f5c64814a2905760b2f8763bb4 (patch)
tree14c5a24be8cec4f2fee10cda36d3f9379dd17851
parent10d60eea8cf8c3b60d9df1d2fc7621833a2ee79c (diff)
downloadtxr-ec19948f35d876f5c64814a2905760b2f8763bb4.tar.gz
txr-ec19948f35d876f5c64814a2905760b2f8763bb4.tar.bz2
txr-ec19948f35d876f5c64814a2905760b2f8763bb4.zip
Rounding out hash table functionality with lazy lists that
can walk table content in different ways. * eval.c (op_dohash): Follow interface change of hash_next. (eval_init): hash-keys, hash-values, hash-pairs and hash-alist intrinsics introduced. * filter.c (trie_compress): Follow interface change of hash_next. * hash.c (hash_next): Silly interface which takes a pointer to the iterator has changed to just take the iterator. The function unambiguously returns nil when the iteration ends, so there is no need to set the iterator variable to nil. (maphash): Follows interface change of hash_next. (hash_keys_lazy, hash_values_lazy, hash_pairs_lazy, hash_alist_lazy): New static functions. (hash_keys, hash_values, hash_pairs, hash_alist): New functions. * hash.h (hash_next): Declaration updated. (hash_keys, hash_values, hash_pairs, hash_alist): Declared. * lib.c (make_half_lazy_cons): New way of constructing lazy cons, with the car field specified. It simplifies situations when the previous cons computes the car of the next one. Why hadn't I thought of this before? * lib.h (make_half_lazy_cons): Declared. * txr.1: Doc stubs for new hash functions. * txr.vim: Highlighting for new hash functions.
-rw-r--r--ChangeLog34
-rw-r--r--eval.c6
-rw-r--r--filter.c4
-rw-r--r--hash.c78
-rw-r--r--hash.h6
-rw-r--r--lib.c10
-rw-r--r--lib.h1
-rw-r--r--txr.12
-rw-r--r--txr.vim8
9 files changed, 138 insertions, 11 deletions
diff --git a/ChangeLog b/ChangeLog
index 06302f34..325a6edb 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,37 @@
+2012-04-07 Kaz Kylheku <kaz@kylheku.com>
+
+ Rounding out hash table functionality with lazy lists that
+ can walk table content in different ways.
+
+ * eval.c (op_dohash): Follow interface change of hash_next.
+ (eval_init): hash-keys, hash-values, hash-pairs and hash-alist
+ intrinsics introduced.
+
+ * filter.c (trie_compress): Follow interface change of hash_next.
+
+ * hash.c (hash_next): Silly interface which takes a pointer to
+ the iterator has changed to just take the iterator. The function
+ unambiguously returns nil when the iteration ends, so there
+ is no need to set the iterator variable to nil.
+ (maphash): Follows interface change of hash_next.
+ (hash_keys_lazy, hash_values_lazy, hash_pairs_lazy, hash_alist_lazy):
+ New static functions.
+ (hash_keys, hash_values, hash_pairs, hash_alist): New functions.
+
+ * hash.h (hash_next): Declaration updated.
+ (hash_keys, hash_values, hash_pairs, hash_alist): Declared.
+
+ * lib.c (make_half_lazy_cons): New way of constructing lazy cons,
+ with the car field specified. It simplifies situations when the
+ previous cons computes the car of the next one. Why hadn't I thought of
+ this before?
+
+ * lib.h (make_half_lazy_cons): Declared.
+
+ * txr.1: Doc stubs for new hash functions.
+
+ * txr.vim: Highlighting for new hash functions.
+
2012-04-05 Kaz Kylheku <kaz@kylheku.com>
Version 64
diff --git a/eval.c b/eval.c
index 32be8f2f..a97aa819 100644
--- a/eval.c
+++ b/eval.c
@@ -1035,7 +1035,7 @@ static val op_dohash(val form, val env)
uw_block_begin (nil, result);
- while ((cell = hash_next(&iter)) != nil) {
+ while ((cell = hash_next(iter)) != nil) {
/* These assignments are gc-safe, because keyvar and valvar
are newer objects than existing entries in the hash,
unless the body mutates hash by inserting newer objects,
@@ -2241,6 +2241,10 @@ void eval_init(void)
reg_fun(intern(lit("maphash"), user_package), func_n2(maphash));
reg_fun(intern(lit("hash-eql"), user_package), func_n1(hash_eql));
reg_fun(intern(lit("hash-equal"), user_package), func_n1(hash_equal));
+ reg_fun(intern(lit("hash-keys"), user_package), func_n1(hash_keys));
+ reg_fun(intern(lit("hash-values"), user_package), func_n1(hash_values));
+ reg_fun(intern(lit("hash-pairs"), user_package), func_n1(hash_pairs));
+ reg_fun(intern(lit("hash-alist"), user_package), func_n1(hash_alist));
reg_fun(intern(lit("eval"), user_package), func_n2o(eval_intrinsic, 1));
diff --git a/filter.c b/filter.c
index 0498ced2..9bbe5f1a 100644
--- a/filter.c
+++ b/filter.c
@@ -93,13 +93,13 @@ static void trie_compress(val *ptrie)
set(*ptrie, value);
} else if (eq(count, one) && nullp(value)) {
val iter = hash_begin(trie);
- val cell = hash_next(&iter);
+ val cell = hash_next(iter);
set(*ptrie, cons(car(cell), cdr(cell)));
trie_compress(cdr_l(*ptrie));
} else {
val cell, iter = hash_begin(trie);
- for (cell = hash_next(&iter); iter; cell = hash_next(&iter))
+ for (cell = hash_next(iter); cell; cell = hash_next(iter))
trie_compress(cdr_l(cell));
}
} else if (consp(trie)) {
diff --git a/hash.c b/hash.c
index d0bd4ac5..03967967 100644
--- a/hash.c
+++ b/hash.c
@@ -490,18 +490,16 @@ val hash_begin(val hash)
return hi_obj;
}
-val hash_next(val *iter)
+val hash_next(val iter)
{
- struct hash_iter *hi = (struct hash_iter *) cobj_handle(*iter, hash_iter_s);
+ struct hash_iter *hi = (struct hash_iter *) cobj_handle(iter, hash_iter_s);
val hash = hi->hash;
struct hash *h = (struct hash *) hash->co.handle;
if (hi->cons)
hi->cons = cdr(hi->cons);
while (nullp(hi->cons)) {
- if (++hi->chain >= h->modulus) {
- *iter = nil;
+ if (++hi->chain >= h->modulus)
return nil;
- }
set(hi->cons, vecref(h->table, num(hi->chain)));
}
return car(hi->cons);
@@ -511,7 +509,7 @@ val maphash(val fun, val hash)
{
val iter = hash_begin(hash);
val cell;
- while ((cell = hash_next(&iter)) != nil)
+ while ((cell = hash_next(iter)) != nil)
funcall2(fun, car(cell), cdr(cell));
return nil;
}
@@ -640,6 +638,74 @@ val hash_construct(val hashv_args, val pairs)
return hash;
}
+static val hash_keys_lazy(val iter, val lcons)
+{
+ val cell = hash_next(iter);
+ set(lcons->lc.cdr, if2(cell, make_half_lazy_cons(lcons->lc.func, car(cell))));
+ return nil;
+}
+
+val hash_keys(val hash)
+{
+ val iter = hash_begin(hash);
+ val cell = hash_next(iter);
+ if (!cell)
+ return nil;
+ return make_half_lazy_cons(func_f1(iter, hash_keys_lazy), car(cell));
+}
+
+static val hash_values_lazy(val iter, val lcons)
+{
+ val cell = hash_next(iter);
+ set(lcons->lc.cdr, if2(cell, make_half_lazy_cons(lcons->lc.func, cdr(cell))));
+ return nil;
+}
+
+val hash_values(val hash)
+{
+ val iter = hash_begin(hash);
+ val cell = hash_next(iter);
+ if (!cell)
+ return nil;
+ return make_half_lazy_cons(func_f1(iter, hash_values_lazy), cdr(cell));
+}
+
+static val hash_pairs_lazy(val iter, val lcons)
+{
+ val cell = hash_next(iter);
+ set(lcons->lc.cdr, if2(cell, make_half_lazy_cons(lcons->lc.func,
+ cons(car(cell),
+ cons(cdr(cell),
+ nil)))));
+ return nil;
+}
+
+val hash_pairs(val hash)
+{
+ val iter = hash_begin(hash);
+ val cell = hash_next(iter);
+ if (!cell)
+ return nil;
+ return make_half_lazy_cons(func_f1(iter, hash_pairs_lazy),
+ cons(car(cell), cons(cdr(cell), nil)));
+}
+
+static val hash_alist_lazy(val iter, val lcons)
+{
+ val cell = hash_next(iter);
+ set(lcons->lc.cdr, if2(cell, make_half_lazy_cons(lcons->lc.func, cell)));
+ return nil;
+}
+
+val hash_alist(val hash)
+{
+ val iter = hash_begin(hash);
+ val cell = hash_next(iter);
+ if (!cell)
+ return nil;
+ return make_half_lazy_cons(func_f1(iter, hash_alist_lazy), cell);
+}
+
void hash_init(void)
{
weak_keys_k = intern(lit("weak-keys"), keyword_package);
diff --git a/hash.h b/hash.h
index 3796882b..f6f804b5 100644
--- a/hash.h
+++ b/hash.h
@@ -40,11 +40,15 @@ val set_hash_userdata(val hash, val data);
val hashp(val obj);
val maphash(val func, val hash);
val hash_begin(val hash);
-val hash_next(val *iter);
+val hash_next(val iter);
val hash_eql(val obj);
val hash_equal(val obj);
val hashv(val args);
val hash_construct(val hashv_args, val pairs);
+val hash_keys(val hash);
+val hash_values(val hash);
+val hash_pairs(val hash);
+val hash_alist(val hash);
void hash_process_weak(void);
diff --git a/lib.c b/lib.c
index 52197df1..51c584b0 100644
--- a/lib.c
+++ b/lib.c
@@ -1002,6 +1002,16 @@ val make_lazy_cons(val func)
return obj;
}
+val make_half_lazy_cons(val func, val car)
+{
+ val obj = make_obj();
+ obj->lc.type = LCONS;
+ obj->lc.car = car;
+ obj->lc.cdr = nil;
+ obj->lc.func = func;
+ return obj;
+}
+
val lcons_fun(val lcons)
{
type_check(lcons, LCONS);
diff --git a/lib.h b/lib.h
index 1f8360c1..672f2fcf 100644
--- a/lib.h
+++ b/lib.h
@@ -397,6 +397,7 @@ int in_malloc_range(mem_t *);
wchar_t *chk_strdup(const wchar_t *str);
val cons(val car, val cdr);
val make_lazy_cons(val func);
+val make_half_lazy_cons(val func, val car);
val lcons_fun(val lcons);
val list(val first, ...); /* terminated by nao */
val consp(val obj);
diff --git a/txr.1 b/txr.1
index fcf30689..b3277021 100644
--- a/txr.1
+++ b/txr.1
@@ -7222,6 +7222,8 @@ followed by a period, e or E.
.SS Functions hash-eql and hash-equal
+.SS Functions hash_keys hash_values hash_pairs and hash_alist
+
.SS Function eval
.SS Function chain
diff --git a/txr.vim b/txr.vim
index b96801c3..7cb0efd2 100644
--- a/txr.vim
+++ b/txr.vim
@@ -51,7 +51,13 @@ syn keyword txl_keyword contained zerop evenp oddp > < >= <= = max min
syn keyword txl_keyword contained search-regex match-regex regsub
syn keyword txl_keyword contained make-hash hash hash-construct gethash sethash pushhash remhash
syn keyword txl_keyword contained hash-count get-hash-userdata set-hash-userdata hashp maphash
-syn keyword txl_keyword contained hash-eql hash-equal eval chain andf orf iff
+syn keyword txl_keyword contained hash-eql hash-equal
+syn keyword txl_keyword contained hash_keys hash_values hash_pairs hash_alist
+syn keyword txl_keyword contained *stdout* *stdin* *stddebug*
+syn keyword txl_keyword contained *stderr* format print pprint tostring tostringp
+syn keyword txl_keyword contained make-string-input-stream
+syn keyword txl_keyword contained make-string-byte-input-stream make-string-output-stream
+eval chain andf orf iff
syn keyword txl_keyword contained *stdout* *stdin* *stddebug*
syn keyword txl_keyword contained *stderr* format print pprint tostring tostringp
syn keyword txl_keyword contained make-string-input-stream