jolt/jolt-core/clojure/core
Dmitri Sotnikov 2668a76837
group-by: transient-vector buckets + fix nil keys in transient maps (#155)
The map build already used a transient map, but each bucket was rebuilt with
a persistent (conj (get ret k []) x) per element — an O(log n) trie path
rebuild + alloc each. A coarse grouping (few large buckets) was bound on that
conj, not the map build. Buckets are now native arrays (transient vectors,
O(1) push) frozen once; distinct keys are tracked in a side vector so the
buckets freeze in place with no second map rebuild. A bucket's first element
stays a cheap persistent [x] and only promotes to a transient on the second,
so an all-singletons grouping pays no transient alloc.

  coarse (10/100 buckets, 50k): ~313ms -> ~125ms (~2.5x)
  2 buckets (50k):              ~322ms -> ~129ms (~2.5x)
  all-unique (50k):             ~949ms -> ~892ms (no regression)

Surfaced a latent bug: canon-key returns nil for a nil key and Janet tables
drop a nil key, so the canon-keyed transient map silently lost a nil-key
entry — group-by/frequencies/assoc!/into{} dropped the whole nil bucket
((group-by identity [nil nil 1]) gave {1 [1]}, not {nil [nil nil], 1 [1]}).
Route nil through a sentinel (tbl-key) at the transient-map keying sites;
persistent!/count/dissoc! work unchanged since the real [nil v] pair is kept
as the stored value, and phm already has its own has-nil slot. The transient
set has the analogous bug (needs phs nil support) — filed separately.

Co-authored-by: Yogthos <yogthos@gmail.com>
2026-06-16 23:10:08 +00:00
..
00-kernel.clj Compiler research (#10) 2026-06-09 07:30:25 +08:00
00-syntax.clj feat: run the real clojure.tools.logging (defmacro/syntax-quote/ns + host shims) 2026-06-13 18:50:53 -04:00
10-seq.clj errors: unresolved symbols error with Clojure's message (jolt-2o7.3) 2026-06-12 10:07:48 -04:00
20-coll.clj group-by: transient-vector buckets + fix nil keys in transient maps (#155) 2026-06-16 23:10:08 +00:00
25-sorted.clj sorted-map/set: red-black tree instead of O(n) sorted vector (jolt-0hbr) (#137) 2026-06-16 06:04:46 +00:00
30-macros.clj Specialize record field reads in method bodies; fix with-meta on symbols (#141) 2026-06-16 15:14:59 +00:00
40-lazy.clj core: lazy realization is shared across walks (once-only effects); pmap family 2026-06-10 19:14:49 -04:00
50-io.clj feat: run the real clojure.tools.logging (defmacro/syntax-quote/ns + host shims) 2026-06-13 18:50:53 -04:00