Keep a nil element in sets and transient sets (jolt-bn2p) (#156)
Two paths dropped a nil set member. phs-seq read members via phm-to-struct, whose Janet struct can't hold a nil key, so the nil was lost on seq/print and on into-an-existing-set even though the backing phm counted it (count/contains? then disagreed). Re-attach the nil from the phm's has-nil slot, keeping struct-key order for the rest so set printing stays stable. The transient set keyed its native table by canon-key and stored the member as the value; canon-key returns nil for nil and a nil value also drops the entry, so conj!/disj!/contains?/persistent! lost a nil member outright. Key by tbl-key (the same nil sentinel the transient map uses) and box a nil value through tbl-nil-key, unboxing on persistent!. A nil-containing set used as a map key still collides with the nil-free one (canon-key drops nil during key canonicalization) — separate latent bug, filed as jolt-zcm9. Co-authored-by: Yogthos <yogthos@gmail.com>
This commit is contained in:
parent
2668a76837
commit
630eb2b9d3
6 changed files with 43 additions and 7 deletions
|
|
@ -33,6 +33,27 @@
|
|||
["dedup equal maps" "1" "(count (set [{:a 1} (hash-map :a 1)]))"]
|
||||
["vector elements" "true" "(contains? #{[1 2]} (vec [1 2]))"])
|
||||
|
||||
(defspec "set / nil element (jolt-bn2p)"
|
||||
# canon-key returns nil for nil and Janet tables drop a nil key, so a nil
|
||||
# member used to be silently lost while count/contains? disagreed.
|
||||
["set keeps nil" "2" "(count (set [nil 1 nil]))"]
|
||||
["contains? nil true" "true" "(contains? (set [nil 1]) nil)"]
|
||||
["contains? nil false" "false" "(contains? #{1} nil)"]
|
||||
["seq includes nil" "true" "(some nil? (seq (set [nil 1])))"]
|
||||
["disj nil" "#{1}" "(disj (set [nil 1]) nil)"]
|
||||
["disj nil count" "1" "(count (disj (set [nil 1]) nil))"]
|
||||
["conj nil count" "2" "(count (conj #{1} nil))"]
|
||||
["conj nil contains?" "true" "(contains? (conj #{1} nil) nil)"]
|
||||
["into #{} keeps nil" "2" "(count (into #{} [nil 1]))"]
|
||||
["into #{} contains? nil" "true" "(contains? (into #{} [nil 1]) nil)"]
|
||||
["into keeps existing nil" "true" "(contains? (into #{nil} [1]) nil)"]
|
||||
# transient set path: tr-conj!/persistent!/disj!/contains?
|
||||
["transient conj! nil" "2" "(count (persistent! (conj! (transient #{}) nil 1)))"]
|
||||
["transient contains? nil" "true" "(contains? (persistent! (conj! (transient #{}) nil 1)) nil)"]
|
||||
["transient disj! nil cnt" "1" "(count (persistent! (disj! (conj! (transient #{}) nil 1) nil)))"]
|
||||
["transient disj! removes" "false" "(contains? (persistent! (disj! (conj! (transient #{}) nil 1) nil)) nil)"]
|
||||
["transient of set w/ nil" "true" "(contains? (persistent! (transient (set [nil 1]))) nil)"])
|
||||
|
||||
(defspec "clojure.set"
|
||||
["union" "#{1 2 3 4}" "(do (require (quote [clojure.set :as s])) (s/union #{1 2} #{3 4}))"]
|
||||
["intersection" "#{2}" "(do (require (quote [clojure.set :as s])) (s/intersection #{1 2} #{2 3}))"]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue