summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog15
-rw-r--r--eval.c6
-rw-r--r--hash.c122
-rw-r--r--hash.h5
-rw-r--r--txr.158
-rw-r--r--txr.vim6
6 files changed, 209 insertions, 3 deletions
diff --git a/ChangeLog b/ChangeLog
index dc92bba9..94dd5903 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,18 @@
+2012-09-12 Kaz Kylheku <kaz@kylheku.com>
+
+ * eval.c (eval_init): New intrinsics: make-similar-hash, copy-hash,
+ hash-uni, hash-diff, hash-isec.
+
+ * hash.c (make_similar_hash, copy_hash, hash_uni, hash_diff,
+ hash_isec): New functions.
+
+ * hash.h (make_similar_hash, copy_hash, hash_uni, hash_diff,
+ hash_isec): Declared.
+
+ * txr.1: Updated.
+
+ * txr.vim: Highlighting for these new functions.
+
2012-09-11 Kaz Kylheku <kaz@kylheku.com>
* configure: Added test for <sys/stat.h>
diff --git a/eval.c b/eval.c
index f7ecd06d..ecf44424 100644
--- a/eval.c
+++ b/eval.c
@@ -2238,8 +2238,9 @@ void eval_init(void)
reg_fun(intern(lit("match-regex"), user_package), func_n3o(match_regex, 2));
reg_fun(intern(lit("regsub"), user_package), func_n3(regsub));
-
reg_fun(intern(lit("make-hash"), user_package), func_n3(make_hash));
+ reg_fun(intern(lit("make-similar-hash"), user_package), func_n1(make_similar_hash));
+ reg_fun(intern(lit("copy-hash"), user_package), func_n1(copy_hash));
reg_fun(intern(lit("hash"), user_package), func_n0v(hashv));
reg_fun(intern(lit("hash-construct"), user_package), func_n2(hash_construct));
reg_fun(gethash_s, func_n3o(gethash_n, 2));
@@ -2259,6 +2260,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-diff"), user_package), func_n2(hash_diff));
+ reg_fun(intern(lit("hash-isec"), user_package), func_n2(hash_isec));
reg_fun(intern(lit("eval"), user_package), func_n2o(eval_intrinsic, 1));
diff --git a/hash.c b/hash.c
index 68f5929c..1b859cab 100644
--- a/hash.c
+++ b/hash.c
@@ -370,6 +370,51 @@ val make_hash(val weak_keys, val weak_vals, val equal_based)
return hash;
}
+val make_similar_hash(val existing)
+{
+ struct hash *ex = (struct hash *) cobj_handle(existing, hash_s);
+ struct hash *h = (struct hash *) chk_malloc(sizeof *h);
+ val mod = num(256);
+ val table = vector(mod);
+ val hash = cobj((mem_t *) h, hash_s, &hash_ops);
+
+ h->modulus = c_num(mod);
+ h->count = 0;
+ h->table = table;
+ h->userdata = ex->userdata;
+
+ h->flags = ex->flags;
+ h->hash_fun = ex->hash_fun;
+ h->assoc_fun = ex->assoc_fun;
+ h->acons_new_l_fun = ex->acons_new_l_fun;
+
+ return hash;
+}
+
+val copy_hash(val existing)
+{
+ struct hash *ex = (struct hash *) cobj_handle(existing, hash_s);
+ struct hash *h = (struct hash *) chk_malloc(sizeof *h);
+ val hash = cobj((mem_t *) h, hash_s, &hash_ops);
+ val mod = num(ex->modulus);
+ val iter;
+
+ h->modulus = ex->modulus;
+ h->count = ex->count;
+ h->table = vector(mod);
+ h->userdata = ex->userdata;
+
+ h->flags = ex->flags;
+ h->hash_fun = ex->hash_fun;
+ h->assoc_fun = ex->assoc_fun;
+ h->acons_new_l_fun = ex->acons_new_l_fun;
+
+ for (iter = zero; lt(iter, mod); iter = plus(iter, one))
+ *vecref_l(h->table, iter) = copy_alist(vecref(ex->table, iter));
+
+ return hash;
+}
+
val *gethash_l(val hash, val key, val *new_p)
{
struct hash *h = (struct hash *) cobj_handle(hash, hash_s);
@@ -706,6 +751,83 @@ val hash_alist(val hash)
return make_half_lazy_cons(func_f1(iter, hash_alist_lazy), cell);
}
+val hash_uni(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))
+ {
+ sethash(hout, car(entry), cdr(entry));
+ }
+
+ for (hiter = hash_begin(hash2), entry = hash_next(hiter);
+ entry;
+ entry = hash_next(hiter))
+ {
+ sethash(hout, car(entry), cdr(entry));
+ }
+
+ return hout;
+ }
+}
+
+val hash_diff(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-diff: ~a and ~a are incompatible hashes"), hash1, hash2, nao);
+
+ {
+ val hout = copy_hash(hash1);
+ val hiter, entry;
+
+ for (hiter = hash_begin(hash2), entry = hash_next(hiter);
+ entry;
+ entry = hash_next(hiter))
+ {
+ remhash(hout, car(entry));
+ }
+
+ return hout;
+ }
+}
+
+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))
+ {
+ if (gethash(hash2, car(entry)))
+ sethash(hout, car(entry), cdr(entry));
+ }
+
+ return hout;
+ }
+}
+
void hash_init(void)
{
weak_keys_k = intern(lit("weak-keys"), keyword_package);
diff --git a/hash.h b/hash.h
index f6f804b5..36c1f55c 100644
--- a/hash.h
+++ b/hash.h
@@ -27,6 +27,8 @@
extern val weak_keys_k, weak_vals_k, equal_based_k;
val make_hash(val weak_keys, val weak_vals, val equal_based);
+val make_similar_hash(val existing);
+val copy_hash(val existing);
val *gethash_l(val hash, val key, val *new_p);
val gethash(val hash, val key);
val gethash_n(val hash, val key, val notfound_val);
@@ -49,6 +51,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_diff(val hash1, val hash2);
+val hash_isec(val hash1, val hash2);
void hash_process_weak(void);
diff --git a/txr.1 b/txr.1
index 1571c0db..5750d954 100644
--- a/txr.1
+++ b/txr.1
@@ -8876,6 +8876,29 @@ the equal function instead.
In addition to storing key-value pairs, a hash table can have a piece of
information associated with it, called the user data.
+.SS Functions make-similar-hash and copy-hash
+
+.TP
+Syntax:
+
+ (make-similar-hash <hash>)
+ (copy-hash <hash>)
+
+.TP
+Description:
+
+The make-similar-hash and copy-hash functions create a new hash object based on
+the existing <hash> object.
+
+The make-similar-hash produces an empty hash table which inherits all of the
+attributes of <hash>. It uses the same kind of key equality, the
+same configuration of weak keys and values, and has the same user data (see
+the set-hash-userdata function).
+
+The copy-hash function is like make-similar-hash, except that instead of
+producing an empty hash table, it produces one which has all the same elements
+as <hash>: it contains the same key and value objects.
+
.SS Function sethash
.TP
@@ -9062,6 +9085,41 @@ 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
+
+.TP
+Syntax:
+
+ (hash-uni <hash1> <hash2>)
+ (hash-diff <hash1> <hash2>)
+ (hash-isec <hash1> <hash2>)
+
+.TP
+Description:
+
+These functions perform basic set operations on hash tables in a nondestructive
+way, returning a new hash table without altering the inputs. The arguments
+<hash1> and <hash2> must be compatible hash tables. This means that their keys
+must use the same kind of equality.
+
+The resulting hash table inherits attributes from <hash1>, as if by the
+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-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>.
+
.SH PARTIAL EVALUATION AND COMBINATORS
.SS Operator op
diff --git a/txr.vim b/txr.vim
index 746f51be..a857e32a 100644
--- a/txr.vim
+++ b/txr.vim
@@ -49,10 +49,12 @@ syn keyword txl_keyword contained fixnump bignump integerp floatp
syn keyword txl_keyword contained numberp zerop evenp oddp >
syn keyword txl_keyword contained zerop evenp oddp > < >= <= = max min
syn keyword txl_keyword contained search-regex match-regex regsub regexp regex-compile
-syn keyword txl_keyword contained make-hash hash hash-construct gethash sethash pushhash remhash
+syn keyword txl_keyword contained make-hash make-similar-hash copy-hash hash hash-construct
+syn keyword txl_keyword contained 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
-syn keyword txl_keyword contained hash_keys hash_values hash_pairs hash_alist
+syn keyword txl_keyword contained hash-keys hash-values hash-pairs hash-alist
+syn keyword txl_keyword contained hash-uni hash-diff hash-isec
syn keyword txl_keyword contained eval chain andf orf iff
syn keyword txl_keyword contained *stdout* *stdin* *stddebug*
syn keyword txl_keyword contained *stderr* format print pprint tostring tostringp