From 260968beacb1a2e1c6bdd652f75fe087f907ce0f Mon Sep 17 00:00:00 2001 From: Kaz Kylheku Date: Wed, 12 Feb 2014 20:25:27 -0800 Subject: * 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. --- ChangeLog | 13 +++++++++++++ eval.c | 2 ++ hash.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- hash.h | 2 ++ txr.1 | 23 ++++++++++++++++++----- 5 files changed, 95 insertions(+), 6 deletions(-) diff --git a/ChangeLog b/ChangeLog index 90234c48..02a1b139 100644 --- a/ChangeLog +++ b/ChangeLog @@ -9,6 +9,19 @@ * txr.1: Documented inhash. Also, added surprisingly missing documentation for gethash! +2014-02-12 Kaz Kylheku + + * 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 * parser.l: Disallow syntax like 1.0a, flagging it as 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 and -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 ). -.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 ) + (hash-guni ) (hash-diff ) (hash-isec ) + (hash-gisec ) .TP Description: @@ -10616,10 +10618,16 @@ make-similar-hash operation. If has userdata, the resulting hash table has the same userdata. If 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 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-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.) 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 @@ -10629,6 +10637,11 @@ 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. + .SH PARTIAL EVALUATION AND COMBINATORS .SS Operators op and do -- cgit v1.2.3