summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2014-02-12 22:09:48 -0800
committerKaz Kylheku <kaz@kylheku.com>2014-02-14 15:53:43 -0800
commitb21d9c695dfb570a459129885063749e6efa561e (patch)
treec87a1f73d359c574e9d99591660e20af762413c0
parent260968beacb1a2e1c6bdd652f75fe087f907ce0f (diff)
downloadtxr-b21d9c695dfb570a459129885063749e6efa561e.tar.gz
txr-b21d9c695dfb570a459129885063749e6efa561e.tar.bz2
txr-b21d9c695dfb570a459129885063749e6efa561e.zip
Different approach: optional arguments on hash-isec and hash-uni allow
for more flexible joining of data from the hash tables. * eval.c (eval_init): Remove hash_guni and hash_gisec. Change registration for hash_uni and hash_isec to three arguments with one optional. * hash.c (hash_uni): Third parameter introduced, join_func. The default behavior changes: in the two argument case, clashing keys prefer the value from hash1 rather than hash2. For this reason, we now iterate over hash2 first, then hash1. (hash_guni): Removed. (hash_isec): Third parameter introduced, join_func. (hash_gisec): Removed. * hash.h (hash_uni, hash_isec): Declarations updated. (hash_guni, hash_gisec): Delarations removed. * txr.1: Documentation updated.
-rw-r--r--ChangeLog22
-rw-r--r--eval.c6
-rw-r--r--hash.c76
-rw-r--r--hash.h6
-rw-r--r--txr.130
5 files changed, 52 insertions, 88 deletions
diff --git a/ChangeLog b/ChangeLog
index 02a1b139..544d470c 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -11,6 +11,28 @@
2014-02-12 Kaz Kylheku <kaz@kylheku.com>
+ Different approach: optional arguments on hash-isec and hash-uni allow
+ for more flexible joining of data from the hash tables.
+
+ * eval.c (eval_init): Remove hash_guni and hash_gisec. Change
+ registration for hash_uni and hash_isec to three arguments with
+ one optional.
+
+ * hash.c (hash_uni): Third parameter introduced, join_func.
+ The default behavior changes: in the two argument case,
+ clashing keys prefer the value from hash1 rather than hash2.
+ For this reason, we now iterate over hash2 first, then hash1.
+ (hash_guni): Removed.
+ (hash_isec): Third parameter introduced, join_func.
+ (hash_gisec): Removed.
+
+ * hash.h (hash_uni, hash_isec): Declarations updated.
+ (hash_guni, hash_gisec): Delarations removed.
+
+ * txr.1: Documentation updated.
+
+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.
diff --git a/eval.c b/eval.c
index 7a6fa19e..e32ed23b 100644
--- a/eval.c
+++ b/eval.c
@@ -2508,11 +2508,9 @@ void eval_init(void)
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("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-uni"), user_package), func_n3o(hash_uni, 2));
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("hash-isec"), user_package), func_n3o(hash_isec, 2));
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 0941effb..0e98403c 100644
--- a/hash.c
+++ b/hash.c
@@ -922,7 +922,7 @@ val hash_alist(val hash)
return make_half_lazy_cons(func_f1(iter, hash_alist_lazy), cell);
}
-val hash_uni(val hash1, val hash2)
+val hash_uni(val hash1, val hash2, val join_func)
{
struct hash *h1 = (struct hash *) cobj_handle(hash1, hash_s);
struct hash *h2 = (struct hash *) cobj_handle(hash2, hash_s);
@@ -934,13 +934,6 @@ val hash_uni(val hash1, val hash2)
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))
@@ -948,35 +941,16 @@ val hash_uni(val hash1, val hash2)
sethash(hout, car(entry), cdr(entry));
}
- return hout;
- }
-}
-
-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)));
+ if (missingp(join_func)) {
+ sethash(hout, car(entry), cdr(entry));
+ } else {
+ val *loc = gethash_l(hout, car(entry), 0);
+ set(*loc, funcall2(join_func, cdr(entry), *loc));
+ }
}
return hout;
@@ -1006,33 +980,7 @@ val hash_diff(val hash1, val hash2)
}
}
-val hash_isec(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;
- gethash_f(hash2, car(entry), &found);
- if (found)
- sethash(hout, car(entry), cdr(entry));
- }
-
- return hout;
- }
-}
-
-val hash_gisec(val hash1, val hash2)
+val hash_isec(val hash1, val hash2, val join_func)
{
struct hash *h1 = (struct hash *) cobj_handle(hash1, hash_s);
struct hash *h2 = (struct hash *) cobj_handle(hash2, hash_s);
@@ -1050,8 +998,12 @@ val hash_gisec(val hash1, val hash2)
{
val found;
val data2 = gethash_f(hash2, car(entry), &found);
- if (found)
- sethash(hout, car(entry), append2(cdr(entry), data2));
+ if (found) {
+ if (missingp(join_func))
+ sethash(hout, car(entry), cdr(entry));
+ else
+ sethash(hout, car(entry), funcall2(join_func, cdr(entry), data2));
+ }
}
return hout;
diff --git a/hash.h b/hash.h
index 89048457..52783d37 100644
--- a/hash.h
+++ b/hash.h
@@ -53,11 +53,9 @@ val hash_keys(val hash);
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_uni(val hash1, val hash2, val join_func);
val hash_diff(val hash1, val hash2);
-val hash_isec(val hash1, val hash2);
-val hash_gisec(val hash1, val hash2);
+val hash_isec(val hash1, val hash2, val join_func);
val hash_update(val hash, val fun);
void hash_process_weak(void);
diff --git a/txr.1 b/txr.1
index cc6d127e..b537e1ed 100644
--- a/txr.1
+++ b/txr.1
@@ -10599,11 +10599,9 @@ dohash early using (return) or (return <value>).
.TP
Syntax:
- (hash-uni <hash1> <hash2>)
- (hash-guni <hash1> <hash2>)
+ (hash-uni <hash1> <hash2> [<join-func>])
(hash-diff <hash1> <hash2>)
- (hash-isec <hash1> <hash2>)
- (hash-gisec <hash1> <hash2>)
+ (hash-isec <hash1> <hash2> [<join-func>])
.TP
Description:
@@ -10621,26 +10619,22 @@ 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-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.)
+in the resulting hash. In this case, if the <join-func> argument is not given
+specified, value associated with this key is the one from <hash1>. If
+<join-func> is specified then it is called with two arguments: the respective
+data items from <hash1> and <hash2>. The return value of this function is used
+as the value in the union hash.
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
in <hash2> are deleted.
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.
+only those keys which occur both in <hash1> and <hash2>. If <join-func> is not
+specified, the values selected for these common keys are those from <hash1>.
+If <join-func> is specified, then for each key which occurs in both <hash1> and
+<hash2>, it is called with two arguments: the respective data items. The return
+value is then used as the data item in the intersection hash.
.SH PARTIAL EVALUATION AND COMBINATORS