pv: build the vector trie bottom-up, not n incremental conjs (jolt-5vsp) (#153)
pv-from-indexed (behind vec/mapv/filterv/into-a-vector) built a pvec by calling
pv-conj once per element — each call allocated a fresh pvec wrapper and copied
the up-to-32 tail tuple, so building an n-vector was O(n) allocations + tail
copies. Replace it with a single bottom-up trie construction: chunk the elements
into 32-wide value leaves, group nodes 32-wide up to the root, split off the
tail. The structure is identical to the incremental one — tail-offset(n) =
((n-1)>>5)<<5 is exactly the trie/tail boundary, so nth/conj/assoc/seq read it
unchanged (validated against the old builder across the size boundaries).
into-a-vector likewise stops doing a persistent pv-conj per element: it
accumulates into a native array and bulk-builds once (the transient-style path).
Measured (50k): vec 211 -> 6 ms (~36x), into [] 197 -> 15 ms (~13x). mapv is
unchanged here — it's bottlenecked on lazy map realization, not the build.
The map/set builders (into {}, frequencies, group-by, set — all HAMT-backed)
need the same bulk treatment and are a separate follow-up. Gate: conformance x3,
full suite, new bulk-boundary rows in vectors-spec.
Co-authored-by: Yogthos <yogthos@gmail.com>
This commit is contained in:
parent
b771908e5b
commit
43e5426601
3 changed files with 51 additions and 6 deletions
|
|
@ -52,3 +52,18 @@
|
|||
["large vector nth" "1500" "(nth (vec (range 2000)) 1500)"]
|
||||
["large vector count" "2000" "(count (vec (range 2000)))"]
|
||||
["large conj immutable" "true" "(let [v (vec (range 1000)) w (conj v :end)] (and (= 1000 (count v)) (= 1001 (count w))))"])
|
||||
|
||||
# vec/into build the pvec trie BOTTOM-UP in one pass (pv-from-indexed, jolt-5vsp
|
||||
# collections). Exercise the structure transitions: 32 (tail full), 33 (first
|
||||
# trie leaf), 1024 (root full at shift 5), 1025 (root grows to shift 10) — and
|
||||
# that a conj/assoc after a bulk build still lands and reads back.
|
||||
(defspec "vector / bulk build boundaries"
|
||||
["count at 1025" "1025" "(count (vec (range 1025)))"]
|
||||
["into = vec at 1025" "true" "(= (vec (range 1025)) (into [] (range 1025)))"]
|
||||
["nth at leaf boundary" "32" "(nth (vec (range 1025)) 32)"]
|
||||
["nth at root boundary" "1024" "(nth (vec (range 1025)) 1024)"]
|
||||
["vec=into at 33" "true" "(= (vec (range 33)) (into [] (range 33)))"]
|
||||
["conj after bulk 1024" "1025" "(count (conj (vec (range 1024)) :x))"]
|
||||
["conj-after reads back" ":x" "(nth (conj (vec (range 1024)) :x) 1024)"]
|
||||
["assoc into bulk vec" "9" "(nth (assoc (vec (range 1025)) 1000 9) 1000)"]
|
||||
["into onto non-empty" "[0 1 2 0 1]" "(into (vec (range 3)) (range 2))"])
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue