From b21d9c695dfb570a459129885063749e6efa561e Mon Sep 17 00:00:00 2001 From: Kaz Kylheku Date: Wed, 12 Feb 2014 22:09:48 -0800 Subject: 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. --- ChangeLog | 22 ++++++++++++++++++ eval.c | 6 ++--- hash.c | 76 ++++++++++++--------------------------------------------------- hash.h | 6 ++--- txr.1 | 30 ++++++++++--------------- 5 files changed, 52 insertions(+), 88 deletions(-) diff --git a/ChangeLog b/ChangeLog index 02a1b139..544d470c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -9,6 +9,28 @@ * txr.1: Documented inhash. Also, added surprisingly missing documentation for gethash! +2014-02-12 Kaz Kylheku + + 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 * eval.c (eval_init): Register hash_guni and hash_gisec as intrinsics. 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 ). .TP Syntax: - (hash-uni ) - (hash-guni ) + (hash-uni []) (hash-diff ) - (hash-isec ) - (hash-gisec ) + (hash-isec []) .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 and all of the keys from , and their corresponding values. If a key occurs both in and , then it occurs only once -in the resulting hash. The value for this common key is the one from . -The hash-guni function is similar, except that if a key occurs in both -and , then the respective data items from and 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 argument is not given +specified, value associated with this key is the one from . If + is specified then it is called with two arguments: the respective +data items from and . 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 is made as if by the copy-has function. Then from this copy, all keys which occur in are deleted. The hash-isec function performs a set intersection. The resulting hash contains -only those keys which occur both in and . The values selected -for these common keys are those from . - -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 and from , in -that order. +only those keys which occur both in and . If is not +specified, the values selected for these common keys are those from . +If is specified, then for each key which occurs in both and +, 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 -- cgit v1.2.3