summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2021-07-20 23:17:59 -0700
committerKaz Kylheku <kaz@kylheku.com>2021-07-20 23:17:59 -0700
commita6f0c72306da0c628be9e180288f79fbf29bfa57 (patch)
treec47d4f40f9d3624f28277db5017db526178feef4
parent5e6dca52d383e649bc6e39de26ffa2474a2b9814 (diff)
downloadtxr-a6f0c72306da0c628be9e180288f79fbf29bfa57.tar.gz
txr-a6f0c72306da0c628be9e180288f79fbf29bfa57.tar.bz2
txr-a6f0c72306da0c628be9e180288f79fbf29bfa57.zip
hash: change semantics of weak-both hash tables.
From now on, hash tables with both weak keys and values have dijunctive retention semantics. If either the key or value of an entry is reachable, then the entry stays. This is subject to compatibility. * hash.c (do_weak_tables): Expire an entry if neither the key nor the value is reachable. In 266 or lower compatibility mode, expire an entry if either the key or value is unreachable, like before. * txr.1: Document the change, with compat notes. Add a cautionary note about the referencing issue which defeats weak key or weak value tables.
-rw-r--r--hash.c56
-rw-r--r--txr.120
2 files changed, 57 insertions, 19 deletions
diff --git a/hash.c b/hash.c
index 90e48858..3434b026 100644
--- a/hash.c
+++ b/hash.c
@@ -1274,24 +1274,48 @@ static void do_weak_tables(void)
case hash_weak_both:
/* Sweep through all entries. Delete any which have keys
or values that are garbage. */
- for (i = 0; i < h->modulus; i++) {
- val *pchain = &h->table->v.vec[i];
- val *iter;
-
- for (iter = pchain; *iter; ) {
- val entry = us_car(*iter);
- if (!gc_is_reachable(us_car(entry)) || !gc_is_reachable(us_cdr(entry)))
- {
- *iter = us_cdr(*iter);
+ if (opt_compat && opt_compat <= 266) {
+ for (i = 0; i < h->modulus; i++) {
+ val *pchain = &h->table->v.vec[i];
+ val *iter;
+
+ for (iter = pchain; *iter; ) {
+ val entry = us_car(*iter);
+ if (!gc_is_reachable(us_car(entry)) || !gc_is_reachable(us_cdr(entry)))
+ {
+ *iter = us_cdr(*iter);
#if CONFIG_EXTRA_DEBUGGING
- if (!gc_is_reachable(us_car(entry)) && us_car(entry) == break_obj)
- breakpt();
- if (!gc_is_reachable(us_cdr(entry)) && us_cdr(entry) == break_obj)
- breakpt();
+ if (!gc_is_reachable(us_car(entry)) && us_car(entry) == break_obj)
+ breakpt();
+ if (!gc_is_reachable(us_cdr(entry)) && us_cdr(entry) == break_obj)
+ breakpt();
#endif
- } else {
- iter = us_cdr_p(*iter);
- c++;
+ } else {
+ iter = us_cdr_p(*iter);
+ c++;
+ }
+ }
+ }
+ } else {
+ for (i = 0; i < h->modulus; i++) {
+ val *pchain = &h->table->v.vec[i];
+ val *iter;
+
+ for (iter = pchain; *iter; ) {
+ val entry = us_car(*iter);
+ if (!gc_is_reachable(us_car(entry)) && !gc_is_reachable(us_cdr(entry)))
+ {
+ *iter = us_cdr(*iter);
+#if CONFIG_EXTRA_DEBUGGING
+ if (!gc_is_reachable(us_car(entry)) && us_car(entry) == break_obj)
+ breakpt();
+ if (!gc_is_reachable(us_cdr(entry)) && us_cdr(entry) == break_obj)
+ breakpt();
+#endif
+ } else {
+ iter = us_cdr_p(*iter);
+ c++;
+ }
}
}
}
diff --git a/txr.1 b/txr.1
index e4c55f60..71da5676 100644
--- a/txr.1
+++ b/txr.1
@@ -51063,9 +51063,16 @@ as a key in in one or more weak-key hash tables becomes unreachable, those hash
entries disappear. This happens even if the values are themselves reachable.
Vice versa, when an object appearing as a value in one or more weak-value hash
tables becomes unreachable, those entries disappear, even if the keys are
-reachable. When a hash table has both weak keys and weak values, then its
-entries are removed when either keys or values become unreachable. In other
-words, both the key and value must be reachable in order to retain the entry.
+reachable. When a hash table has both weak keys and weak values, then an
+entry is removed when neither its key nor its value is reachable. In other
+words, if either the key or value is reachable, the entry is retained.
+Note: this behavior differed in \*(TX 266 and earlier versions.
+
+If the keys of a weak-key hash table are reachable from the values, or if the
+values of a weak-key hash table are reachable from the keys, then the weak
+semantics is defeated for the affected entries: the hash table retains those
+entries as if it were an ordinary table. A hash table with both weak keys and
+values does not have this issue.
An open traversal of a hash table is performed by the
.code maphash
@@ -83081,6 +83088,13 @@ of these version values, the described behaviors are provided if
is given an argument which is equal or lower. For instance
.code "-C 103"
selects the behaviors described below for version 105, but not those for 102.
+.IP 266
+Until \*(TX 266, hash tables with both weak values and keys are subject to
+a conjunctive rule for entry retention: entries are retained if both the
+key and value are reachable objects. If either the key or value is unreachable,
+the entry is eligible for removal. The behavior changed in favor of a disjunctive
+rule: the hash entry is retained if either the key or value is reachable.
+A compatibility option value of 266 or lower restores the old behavior.
.IP 265
Until \*(TX 265, the
.code with-resources