phm: preserve nil-valued keys in get/keys/vals

phm-get returned the default for a key present with a nil value; fix it to
presence-check the bucket so a nil value reads back as nil, not the default.
core-keys/core-vals went through phm-to-struct, which drops nil-valued keys —
read phm-entries directly instead so those keys survive.

Isolated phm correctness only; no map-representation change. Battery holds at
3919, conformance 218/218 in all three modes. The earlier -8 came from
assoc's struct->phm promotion, not these accessors.
This commit is contained in:
Yogthos 2026-06-06 21:54:07 -04:00
parent 0878c803d7
commit bd76eddb74
2 changed files with 8 additions and 3 deletions

View file

@ -655,10 +655,11 @@
(do (var result @{}) (each m maps (each k (if (phm? m) (keys (phm-to-struct m)) (keys m)) (let [existing (result k)] (put result k (if (nil? existing) (m k) (f existing (m k))))))) (table/to-struct result)))) (do (var result @{}) (each m maps (each k (if (phm? m) (keys (phm-to-struct m)) (keys m)) (let [existing (result k)] (put result k (if (nil? existing) (m k) (f existing (m k))))))) (table/to-struct result))))
(defn core-keys [m] (defn core-keys [m]
(if (phm? m) (tuple ;(keys (phm-to-struct m))) (tuple ;(keys m)))) # phm-entries (not phm-to-struct) so keys mapped to nil values are not dropped.
(if (phm? m) (tuple ;(map |(in $ 0) (phm-entries m))) (tuple ;(keys m))))
(defn core-vals [m] (defn core-vals [m]
(if (phm? m) (do (def s (phm-to-struct m)) (tuple ;(map |(s $) (keys s)))) (tuple ;(map |(m $) (keys m))))) (if (phm? m) (tuple ;(map |(in $ 1) (phm-entries m))) (tuple ;(map |(m $) (keys m)))))
(defn core-select-keys [m ks] (defn core-select-keys [m ks]
(var result @{}) (var result @{})

View file

@ -72,7 +72,11 @@
(defn phm-get [m k &opt default] (defn phm-get [m k &opt default]
(default default nil) (default default nil)
(let [bucket (get (m :buckets) (phm-hash-key k))] (let [bucket (get (m :buckets) (phm-hash-key k))]
(if bucket (let [v (phm-bucket-find bucket k)] (if (nil? v) default v)) default))) # presence-check, not nil-of-value: a key mapped to nil is still present,
# so return nil (not the default) when the key exists with a nil value.
(if (and bucket (phm-bucket-contains? bucket k))
(phm-bucket-find bucket k)
default)))
(defn phm-assoc [m k v] (defn phm-assoc [m k v]
(let [cnt (m :cnt) idx (phm-hash-key k) (let [cnt (m :cnt) idx (phm-hash-key k)