summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2014-02-12 20:25:27 -0800
committerKaz Kylheku <kaz@kylheku.com>2014-02-14 15:53:43 -0800
commit260968beacb1a2e1c6bdd652f75fe087f907ce0f (patch)
tree6f9da93f5136fc15dc0ad4c8fd1998edb8888081
parented290d6d0df5f4c694459f853983ab79929ea786 (diff)
downloadtxr-260968beacb1a2e1c6bdd652f75fe087f907ce0f.tar.gz
txr-260968beacb1a2e1c6bdd652f75fe087f907ce0f.tar.bz2
txr-260968beacb1a2e1c6bdd652f75fe087f907ce0f.zip
* eval.c (eval_init): Register hash_guni and hash_gisec as intrinsics.
* hash.c (hash_guni, hash_gisec): New functions. (hash_isec): Bugfix: since gethash was naively used, keys in hash2 associated with the value nil were erroneously omitted from the intersection. * hash.h (hash_guni, hash_gisec): Declared. * txr.1: Documented new functions.
-rw-r--r--ChangeLog13
-rw-r--r--eval.c2
-rw-r--r--hash.c61
-rw-r--r--hash.h2
-rw-r--r--txr.123
5 files changed, 95 insertions, 6 deletions
diff --git a/ChangeLog b/ChangeLog
index 90234c48..02a1b139 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -11,6 +11,19 @@
2014-02-12 Kaz Kylheku <kaz@kylheku.com>
+ * eval.c (eval_init): Register hash_guni and hash_gisec as intrinsics.
+
+ * hash.c (hash_guni, hash_gisec): New functions.
+ (hash_isec): Bugfix: since gethash was naively used, keys in hash2
+ associated with the value nil were erroneously omitted from the
+ intersection.
+
+ * hash.h (hash_guni, hash_gisec): Declared.
+
+ * txr.1: Documented new functions.
+
+2014-02-12 Kaz Kylheku <kaz@kylheku.com>
+
* parser.l: Disallow syntax like 1.0a, flagging it as
an invalid floating-point token. The problem is that 1a is allowed,
for compatibility with other Lisp dialects (it is a symbol) whereas
diff --git a/eval.c b/eval.c
index 5f88d61c..7a6fa19e 100644
--- a/eval.c
+++ b/eval.c
@@ -2509,8 +2509,10 @@ void eval_init(void)
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("hash-uni"), user_package), func_n2(hash_uni));
+ reg_fun(intern(lit("hash-guni"), user_package), func_n2(hash_guni));
reg_fun(intern(lit("hash-diff"), user_package), func_n2(hash_diff));
reg_fun(intern(lit("hash-isec"), user_package), func_n2(hash_isec));
+ reg_fun(intern(lit("hash-gisec"), user_package), func_n2(hash_gisec));
reg_fun(intern(lit("group-by"), user_package), func_n2v(group_by));
reg_fun(intern(lit("hash-update"), user_package), func_n2(hash_update));
diff --git a/hash.c b/hash.c
index f9548c3c..0941effb 100644
--- a/hash.c
+++ b/hash.c
@@ -952,6 +952,37 @@ val hash_uni(val hash1, val hash2)
}
}
+val hash_guni(val hash1, val hash2)
+{
+ struct hash *h1 = (struct hash *) cobj_handle(hash1, hash_s);
+ struct hash *h2 = (struct hash *) cobj_handle(hash2, hash_s);
+
+ if (h1->hash_fun != h2->hash_fun)
+ uw_throwf(error_s, lit("hash-guni: ~a and ~a are incompatible hashes"), hash1, hash2, nao);
+
+ {
+ val hout = make_similar_hash(hash1);
+ val hiter, entry;
+
+ for (hiter = hash_begin(hash1), entry = hash_next(hiter);
+ entry;
+ entry = hash_next(hiter))
+ {
+ sethash(hout, car(entry), cdr(entry));
+ }
+
+ for (hiter = hash_begin(hash2), entry = hash_next(hiter);
+ entry;
+ entry = hash_next(hiter))
+ {
+ val *loc = gethash_l(hout, car(entry), 0);
+ set(*loc, append2(*loc, cdr(entry)));
+ }
+
+ return hout;
+ }
+}
+
val hash_diff(val hash1, val hash2)
{
struct hash *h1 = (struct hash *) cobj_handle(hash1, hash_s);
@@ -991,7 +1022,9 @@ val hash_isec(val hash1, val hash2)
entry;
entry = hash_next(hiter))
{
- if (gethash(hash2, car(entry)))
+ val found;
+ gethash_f(hash2, car(entry), &found);
+ if (found)
sethash(hout, car(entry), cdr(entry));
}
@@ -999,6 +1032,32 @@ val hash_isec(val hash1, val hash2)
}
}
+val hash_gisec(val hash1, val hash2)
+{
+ struct hash *h1 = (struct hash *) cobj_handle(hash1, hash_s);
+ struct hash *h2 = (struct hash *) cobj_handle(hash2, hash_s);
+
+ if (h1->hash_fun != h2->hash_fun)
+ uw_throwf(error_s, lit("hash-uni: ~a and ~a are incompatible hashes"), hash1, hash2, nao);
+
+ {
+ val hout = make_similar_hash(hash1);
+ val hiter, entry;
+
+ for (hiter = hash_begin(hash1), entry = hash_next(hiter);
+ entry;
+ entry = hash_next(hiter))
+ {
+ val found;
+ val data2 = gethash_f(hash2, car(entry), &found);
+ if (found)
+ sethash(hout, car(entry), append2(cdr(entry), data2));
+ }
+
+ return hout;
+ }
+}
+
val hash_update(val hash, val fun)
{
val iter = hash_begin(hash);
diff --git a/hash.h b/hash.h
index 5afc9572..89048457 100644
--- a/hash.h
+++ b/hash.h
@@ -54,8 +54,10 @@ val hash_values(val hash);
val hash_pairs(val hash);
val hash_alist(val hash);
val hash_uni(val hash1, val hash2);
+val hash_guni(val hash1, val hash2);
val hash_diff(val hash1, val hash2);
val hash_isec(val hash1, val hash2);
+val hash_gisec(val hash1, val hash2);
val hash_update(val hash, val fun);
void hash_process_weak(void);
diff --git a/txr.1 b/txr.1
index b9a884ff..cc6d127e 100644
--- a/txr.1
+++ b/txr.1
@@ -10594,14 +10594,16 @@ The <result-form> and <body-form>-s are in the scope of an implicit anonymous
block, which means that it is possible to terminate the execution of
dohash early using (return) or (return <value>).
-.SS Functions hash-uni, hash-diff and hash-isec
+.SS Functions hash-uni, hash-guni, hash-diff, hash-isec and hash-gisec
.TP
Syntax:
(hash-uni <hash1> <hash2>)
+ (hash-guni <hash1> <hash2>)
(hash-diff <hash1> <hash2>)
(hash-isec <hash1> <hash2>)
+ (hash-gisec <hash1> <hash2>)
.TP
Description:
@@ -10616,10 +10618,16 @@ make-similar-hash operation. If <hash1> has userdata, the resulting hash table
has the same userdata. If <hash1> has weak keys, the resulting table has weak
keys, and so forth.
-The hash-uni function performs a set union. The resulting hash contains all of the
-keys from <hash1> and all of the keys from <hash2>, and their corresponding values.
-If a key occurs both in <hash1> and <hash2>, then it occurs only once in the
-resulting hash. The value for this common key is the one from <hash2>.
+The hash-uni function performs a set union. The resulting hash contains all of
+the keys from <hash1> and all of the keys from <hash2>, and their corresponding
+values. If a key occurs both in <hash1> and <hash2>, then it occurs only once
+in the resulting hash. The value for this common key is the one from <hash2>.
+The hash-guni function is similar, except that if a key occurs in both <hash1>
+and <hash2>, then the respective data items from <hash1> and <hash2> for that
+key appear appended together in the resulting hash as if by the append
+function, in that order. (The hash-guni name is a reference to the group-by
+function. A sequence of data items can be grouped in multiple ways, and then
+the hashes combined with hash-guni.)
The hash-diff function performs a set difference. First, a copy of <hash1> is
made as if by the copy-has function. Then from this copy, all keys which occur
@@ -10629,6 +10637,11 @@ The hash-isec function performs a set intersection. The resulting hash contains
only those keys which occur both in <hash1> and <hash2>. The values selected
for these common keys are those from <hash1>.
+The hash-gisec function performs a set intersection similarly to hash-isec.
+However, for each key placed in the resulting hash, the associated data is
+formed by appending together the data item from <hash1> and from <hash2>, in
+that order.
+
.SH PARTIAL EVALUATION AND COMBINATORS
.SS Operators op and do