summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--hash.c21
-rw-r--r--hash.h1
-rw-r--r--tests/010/hash.tl11
-rw-r--r--txr.122
4 files changed, 54 insertions, 1 deletions
diff --git a/hash.c b/hash.c
index 6b62854d..58732193 100644
--- a/hash.c
+++ b/hash.c
@@ -1283,7 +1283,7 @@ static struct cobj_ops hash_iter_ops = cobj_ops_init(eq,
cobj_destroy_free_op,
hash_iter_mark,
cobj_eq_hash_op,
- 0);
+ copy_hash_iter);
void hash_iter_init(struct hash_iter *hi, val hash, val self)
{
@@ -1402,6 +1402,24 @@ val hash_reset(val iter, val hash)
return iter;
}
+val copy_hash_iter(val iter)
+{
+ val self = lit("copy-hash-iter");
+ val hi_obj;
+ struct hash_iter *ohi = coerce(struct hash_iter *,
+ cobj_handle(self, iter, hash_iter_cls));
+ struct hash_iter *nhi = coerce(struct hash_iter *,
+ chk_copy_obj(coerce(mem_t *, ohi),
+ sizeof *ohi));
+ struct hash *h = coerce(struct hash *, cobj_handle(self, ohi->hash,
+ hash_cls));
+
+ hi_obj = cobj(coerce(mem_t *, nhi), hash_iter_cls, &hash_iter_ops);
+ h->usecount++;
+ gc_hint(iter);
+ return hi_obj;
+}
+
val maphash(val fun, val hash)
{
val self = lit("maphash");
@@ -2309,6 +2327,7 @@ void hash_init(void)
reg_fun(intern(lit("hash-next"), user_package), func_n1(hash_next));
reg_fun(intern(lit("hash-peek"), user_package), func_n1(hash_peek));
reg_fun(intern(lit("hash-reset"), user_package), func_n2(hash_reset));
+ reg_fun(intern(lit("copy-hash-iter"), user_package), func_n1(copy_hash_iter));
reg_fun(intern(lit("set-hash-traversal-limit"), system_package),
func_n1(set_hash_traversal_limit));
reg_fun(intern(lit("gen-hash-seed"), user_package), func_n0(gen_hash_seed));
diff --git a/hash.h b/hash.h
index 36efde14..724c8aa2 100644
--- a/hash.h
+++ b/hash.h
@@ -77,6 +77,7 @@ val hash_begin(val hash);
val hash_next(val iter);
val hash_peek(val iter);
val hash_reset(val iter, val hash);
+val copy_hash_iter(val iter);
val hash_eql(val obj);
val hash_equal(val obj, val seed);
val hashv(struct args *args);
diff --git a/tests/010/hash.tl b/tests/010/hash.tl
index d6a8542b..bd37e180 100644
--- a/tests/010/hash.tl
+++ b/tests/010/hash.tl
@@ -92,3 +92,14 @@
(eql (hash-equal (expt 2 128)) (hash-equal (expt 2 128))) t
(eql (hash-eql "abc") (hash-eql "abc")) nil
(eql (hash-eql (expt 2 128)) (hash-eql (expt 2 128))) t)
+
+(let* ((h #H(() (a 1) (b 2) (c 3) (d 4)))
+ (hi1 (hash-begin h))
+ (hi2 (progn (hash-next hi1) (copy-hash-iter hi1))))
+ (mvtest
+ (hash-next hi1) (hash-next hi2)
+ (hash-next hi2) (hash-next hi1)
+ (hash-next hi1) (hash-next hi2)
+ (hash-next hi2) (hash-next hi1)
+ (hash-next hi1) nil
+ (hash-next hi2) nil))
diff --git a/txr.1 b/txr.1
index 32aacb6f..fde65f54 100644
--- a/txr.1
+++ b/txr.1
@@ -21557,6 +21557,10 @@ as if by:
.mono
.meti (copy-search-tree << object )
.onom
+.coIP hash-iter
+.mono
+.meti (copy-hash-iter << object )
+.onom
.coIP tree-iter
.mono
.meti (copy-tree-iter << object )
@@ -58514,6 +58518,24 @@ to
.code nil
if there is no next value.
+.coNP Function @ copy-hash-iter
+.synb
+.mets (copy-hash-iter << iter )
+.syne
+.desc
+The
+.code copy-hash-iter
+function creates and returns a duplicate of the
+.meta iter
+object, which must be a hash iterator returned by
+.codn hash-begin .
+
+The returned object has the same state as the original; it references the same
+traversal position in the same hash. However, it is independent of the original.
+Calls to
+.code hash-next
+on the original have no effect on the duplicate and vice versa.
+
.coNP Special Variable @ *hash-seed*
.desc
The