Merge pull request #114 from jolt-lang/refactor-phase3c-dedups
Refactor phase 3c: dedup collection readers + phm bucket scans (jolt-26dm)
This commit is contained in:
commit
7632be811b
2 changed files with 38 additions and 58 deletions
|
|
@ -39,25 +39,26 @@
|
||||||
(defn- hash-idx [m k]
|
(defn- hash-idx [m k]
|
||||||
(if (nil? k) 0 (mod (hash (ck k)) (length (m :buckets)))))
|
(if (nil? k) 0 (mod (hash (ck k)) (length (m :buckets)))))
|
||||||
|
|
||||||
(defn- phm-bucket-find [bucket k]
|
# Index of key k in a bucket (entries are stored stride-2: k v k v ...), or nil.
|
||||||
(var i 0) (var n (length bucket)) (var found nil)
|
# The single scan all the bucket ops share — keeping it one place stops the
|
||||||
|
# stride logic drifting between them.
|
||||||
|
(defn- bucket-index-of [bucket k]
|
||||||
|
(var i 0) (def n (length bucket)) (var found nil)
|
||||||
(while (< i n)
|
(while (< i n)
|
||||||
(if (key= k (in bucket i)) (do (set found (in bucket (+ i 1))) (break)))
|
(if (key= k (in bucket i)) (do (set found i) (break)))
|
||||||
(+= i 2))
|
(+= i 2))
|
||||||
found)
|
found)
|
||||||
|
|
||||||
|
(defn- phm-bucket-find [bucket k]
|
||||||
|
(let [i (bucket-index-of bucket k)]
|
||||||
|
(if i (in bucket (+ i 1)) nil)))
|
||||||
|
|
||||||
(defn phm-bucket-contains? [bucket k]
|
(defn phm-bucket-contains? [bucket k]
|
||||||
(var i 0) (var n (length bucket)) (var found false)
|
(not (nil? (bucket-index-of bucket k))))
|
||||||
(while (< i n)
|
|
||||||
(if (key= k (in bucket i)) (do (set found true) (break)))
|
|
||||||
(+= i 2))
|
|
||||||
found)
|
|
||||||
|
|
||||||
(defn- phm-bucket-assoc [bucket k v]
|
(defn- phm-bucket-assoc [bucket k v]
|
||||||
(var i 0) (var n (length bucket)) (var found-i nil)
|
(def n (length bucket))
|
||||||
(while (< i n)
|
(def found-i (bucket-index-of bucket k))
|
||||||
(if (key= k (in bucket i)) (do (set found-i i) (break)))
|
|
||||||
(+= i 2))
|
|
||||||
(if (not (nil? found-i))
|
(if (not (nil? found-i))
|
||||||
(let [nb @[]] (var j 0)
|
(let [nb @[]] (var j 0)
|
||||||
(while (< j n) (array/push nb (if (= j (+ found-i 1)) v (in bucket j))) (++ j)) nb)
|
(while (< j n) (array/push nb (if (= j (+ found-i 1)) v (in bucket j))) (++ j)) nb)
|
||||||
|
|
@ -66,10 +67,8 @@
|
||||||
(array/push nb k) (array/push nb v) nb)))
|
(array/push nb k) (array/push nb v) nb)))
|
||||||
|
|
||||||
(defn- phm-bucket-dissoc [bucket k]
|
(defn- phm-bucket-dissoc [bucket k]
|
||||||
(var i 0) (var n (length bucket)) (var found-i nil)
|
(def n (length bucket))
|
||||||
(while (< i n)
|
(def found-i (bucket-index-of bucket k))
|
||||||
(if (key= k (in bucket i)) (do (set found-i i) (break)))
|
|
||||||
(+= i 2))
|
|
||||||
(if (nil? found-i) bucket
|
(if (nil? found-i) bucket
|
||||||
(if (= n 2) nil
|
(if (= n 2) nil
|
||||||
(let [nb @[]] (var j 0)
|
(let [nb @[]] (var j 0)
|
||||||
|
|
@ -82,12 +81,8 @@
|
||||||
# Single pass with a presence flag (not nil-of-value): a key mapped to nil
|
# Single pass with a presence flag (not nil-of-value): a key mapped to nil
|
||||||
# is still present, so return nil (not the default) when it exists.
|
# is still present, so return nil (not the default) when it exists.
|
||||||
(if bucket
|
(if bucket
|
||||||
(do
|
(let [i (bucket-index-of bucket k)]
|
||||||
(var i 0) (var n (length bucket)) (var result default)
|
(if i (in bucket (+ i 1)) default))
|
||||||
(while (< i n)
|
|
||||||
(if (key= k (in bucket i)) (do (set result (in bucket (+ i 1))) (break)))
|
|
||||||
(+= i 2))
|
|
||||||
result)
|
|
||||||
default)))
|
default)))
|
||||||
|
|
||||||
# Rehash every entry of `buckets` into a fresh array of `nb` buckets.
|
# Rehash every entry of `buckets` into a fresh array of `nb` buckets.
|
||||||
|
|
|
||||||
|
|
@ -298,39 +298,35 @@
|
||||||
(+ exp-end 1) exp-end)]
|
(+ exp-end 1) exp-end)]
|
||||||
[(if neg (- val) val) fin]))))))
|
[(if neg (- val) val) fin]))))))
|
||||||
|
|
||||||
(defn read-list [s pos]
|
# Read forms until `close` (a byte), returning [items end-pos]. Shared by the
|
||||||
# pos is at opening paren
|
# list/vector/set readers: skip #_ discards and splice #?@ items uniformly, so the
|
||||||
(defn read-list-items [s pos items]
|
# skip/splice handling can't drift between them (it did once). The map reader
|
||||||
|
# keeps its own loop — its key/value pairing needs a different value-slot scan.
|
||||||
|
(defn read-delimited [s start-pos close err]
|
||||||
|
(defn read-items [s pos items]
|
||||||
(let [pos (skip-whitespace s pos)]
|
(let [pos (skip-whitespace s pos)]
|
||||||
(if (>= pos (length s))
|
(if (>= pos (length s))
|
||||||
(reader-error "Unterminated list" pos))
|
(reader-error err pos))
|
||||||
(if (= (s pos) 41) # )
|
(if (= (s pos) close)
|
||||||
[items (+ pos 1)]
|
[items (+ pos 1)]
|
||||||
(let [[form new-pos] (read-form s pos)]
|
(let [[form new-pos] (read-form s pos)]
|
||||||
# skip #_ discarded forms
|
# skip #_ discarded forms
|
||||||
(if (and (struct? form) (= :jolt/skip (form :jolt/type)))
|
(if (and (struct? form) (= :jolt/skip (form :jolt/type)))
|
||||||
(read-list-items s new-pos items)
|
(read-items s new-pos items)
|
||||||
# splice #?@ items into the list
|
# splice #?@ items into the collection
|
||||||
(if (and (struct? form) (= :jolt/splice (form :jolt/type)))
|
(if (and (struct? form) (= :jolt/splice (form :jolt/type)))
|
||||||
(read-list-items s new-pos (array/concat items (form :items)))
|
(read-items s new-pos (array/concat items (form :items)))
|
||||||
(read-list-items s new-pos (array/push items form))))))))
|
(read-items s new-pos (array/push items form))))))))
|
||||||
(read-list-items s (+ pos 1) @[]))
|
(read-items s start-pos @[]))
|
||||||
|
|
||||||
|
(defn read-list [s pos]
|
||||||
|
# pos is at opening paren
|
||||||
|
(read-delimited s (+ pos 1) 41 "Unterminated list")) # )
|
||||||
|
|
||||||
(defn read-vector [s pos]
|
(defn read-vector [s pos]
|
||||||
# pos is at opening bracket
|
# pos is at opening bracket
|
||||||
(defn read-vec-items [s pos items]
|
(let [[items end] (read-delimited s (+ pos 1) 93 "Unterminated vector")] # ]
|
||||||
(let [pos (skip-whitespace s pos)]
|
[(tuple/slice (tuple ;items)) end]))
|
||||||
(if (>= pos (length s))
|
|
||||||
(reader-error "Unterminated vector" pos))
|
|
||||||
(if (= (s pos) 93) # ]
|
|
||||||
[(tuple/slice (tuple ;items)) (+ pos 1)]
|
|
||||||
(let [[form new-pos] (read-form s pos)]
|
|
||||||
(if (and (struct? form) (= :jolt/skip (form :jolt/type)))
|
|
||||||
(read-vec-items s new-pos items)
|
|
||||||
(if (and (struct? form) (= :jolt/splice (form :jolt/type)))
|
|
||||||
(read-vec-items s new-pos (array/concat items (form :items)))
|
|
||||||
(read-vec-items s new-pos (array/push items form))))))))
|
|
||||||
(read-vec-items s (+ pos 1) @[]))
|
|
||||||
|
|
||||||
# A map-literal form. Janet structs drop nil keys/values, so when a key or value
|
# A map-literal form. Janet structs drop nil keys/values, so when a key or value
|
||||||
# is nil (e.g. {:a nil}) build a phm — it preserves nil, matching Clojure. The
|
# is nil (e.g. {:a nil}) build a phm — it preserves nil, matching Clojure. The
|
||||||
|
|
@ -400,19 +396,8 @@
|
||||||
|
|
||||||
(defn read-set [s pos]
|
(defn read-set [s pos]
|
||||||
# pos is at #, next char is {
|
# pos is at #, next char is {
|
||||||
(defn read-set-items [s pos items]
|
(let [[items end] (read-delimited s (+ pos 2) 125 "Unterminated set")] # }
|
||||||
(let [pos (skip-whitespace s pos)]
|
[{:jolt/type :jolt/set :value (tuple/slice (tuple ;items))} end]))
|
||||||
(if (>= pos (length s))
|
|
||||||
(reader-error "Unterminated set" pos))
|
|
||||||
(if (= (s pos) 125) # }
|
|
||||||
[{:jolt/type :jolt/set :value (tuple/slice (tuple ;items))} (+ pos 1)]
|
|
||||||
(let [[form new-pos] (read-form s pos)]
|
|
||||||
(if (and (struct? form) (= :jolt/skip (form :jolt/type)))
|
|
||||||
(read-set-items s new-pos items)
|
|
||||||
(if (and (struct? form) (= :jolt/splice (form :jolt/type)))
|
|
||||||
(read-set-items s new-pos (array/concat items (form :items)))
|
|
||||||
(read-set-items s new-pos (array/push items form))))))))
|
|
||||||
(read-set-items s (+ pos 2) @[]))
|
|
||||||
|
|
||||||
(defn read-char-name-end [s pos]
|
(defn read-char-name-end [s pos]
|
||||||
(if (and (< pos (length s)) (symbol-char? (s pos)))
|
(if (and (< pos (length s)) (symbol-char? (s pos)))
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue