2016-06-05 15:39:58 +00:00
|
|
|
(ns com.rpl.specter.benchmarks
|
|
|
|
|
(:use [com.rpl.specter]
|
2017-06-03 22:23:13 +00:00
|
|
|
[com.rpl.specter.transients])
|
|
|
|
|
(:require [clojure.walk :as walk]
|
2018-12-13 11:54:28 +00:00
|
|
|
[com.rpl.specter.impl :as i]
|
|
|
|
|
[criterium.core :as bench]))
|
2016-06-05 15:39:58 +00:00
|
|
|
|
|
|
|
|
(defn pretty-float3 [anum]
|
|
|
|
|
(format "%.3g" anum))
|
|
|
|
|
|
2018-12-13 11:54:28 +00:00
|
|
|
(defn mean [a-fn]
|
|
|
|
|
(-> a-fn (bench/benchmark* {}) :mean first (* 1000000)))
|
2016-08-11 14:13:27 +00:00
|
|
|
|
2018-12-13 11:54:28 +00:00
|
|
|
(defn compare-benchmark [afn-map]
|
|
|
|
|
(let [results (transform MAP-VALS mean afn-map)
|
|
|
|
|
[[_ best-time] & _ :as sorted] (sort-by last results)]
|
|
|
|
|
(println "\nMean(us)\tvs best\t\tCode")
|
2016-06-05 15:39:58 +00:00
|
|
|
(doseq [[k t] sorted]
|
2018-12-13 11:54:28 +00:00
|
|
|
(println (pretty-float3 t) "\t\t" (pretty-float3 (/ t best-time 1.0)) "\t\t" k))))
|
2016-06-05 15:39:58 +00:00
|
|
|
|
2018-12-13 11:54:28 +00:00
|
|
|
(defmacro run-benchmark [name & exprs]
|
2020-10-22 21:51:04 +00:00
|
|
|
(let [only-benchmarks (set (filter some? *command-line-args*))
|
|
|
|
|
all-benchmarks? (empty? only-benchmarks)]
|
|
|
|
|
(if (or all-benchmarks? (contains? only-benchmarks name))
|
|
|
|
|
(let [afn-map (->> exprs shuffle (map (fn [e] [`(quote ~e) `(fn [] ~e)])) (into {}))]
|
|
|
|
|
`(do
|
|
|
|
|
(println "Benchmark:" ~name)
|
|
|
|
|
(compare-benchmark ~afn-map)
|
|
|
|
|
(println "\n********************************\n"))))))
|
2016-08-11 14:13:27 +00:00
|
|
|
|
2016-09-02 03:41:27 +00:00
|
|
|
(defn specter-dynamic-nested-get [data a b c]
|
2017-04-11 15:58:52 +00:00
|
|
|
(select-any (keypath a b c) data))
|
2016-09-02 03:41:27 +00:00
|
|
|
|
2016-09-07 14:01:30 +00:00
|
|
|
|
|
|
|
|
(defn get-k [k] (fn [m next] (next (get m k))))
|
|
|
|
|
|
|
|
|
|
(def get-a-b-c
|
|
|
|
|
(reduce
|
|
|
|
|
(fn [curr afn]
|
|
|
|
|
(fn [structure]
|
|
|
|
|
(afn structure curr)))
|
|
|
|
|
[identity (get-k :c) (get-k :b) (get-k :a)]))
|
|
|
|
|
|
2016-06-05 15:39:58 +00:00
|
|
|
(let [data {:a {:b {:c 1}}}
|
|
|
|
|
p (comp-paths :a :b :c)]
|
2018-12-13 11:54:28 +00:00
|
|
|
(run-benchmark "get value in nested map"
|
2016-06-07 00:29:45 +00:00
|
|
|
(select-any [:a :b :c] data)
|
2016-11-07 12:47:56 +00:00
|
|
|
(select-any (keypath :a :b :c) data)
|
2016-06-07 14:18:20 +00:00
|
|
|
(select-one [:a :b :c] data)
|
|
|
|
|
(select-first [:a :b :c] data)
|
|
|
|
|
(select-one! [:a :b :c] data)
|
2016-06-07 00:29:45 +00:00
|
|
|
(compiled-select-any p data)
|
2016-09-02 03:41:27 +00:00
|
|
|
(specter-dynamic-nested-get data :a :b :c)
|
2016-06-05 15:39:58 +00:00
|
|
|
(get-in data [:a :b :c])
|
2016-09-07 14:01:30 +00:00
|
|
|
(get-a-b-c data)
|
|
|
|
|
(-> data :a :b :c identity)
|
2016-09-03 00:20:49 +00:00
|
|
|
(-> data (get :a) (get :b) (get :c))
|
2016-06-07 00:29:45 +00:00
|
|
|
(-> data :a :b :c)
|
2016-08-11 14:13:27 +00:00
|
|
|
(select-any [(keypath :a) (keypath :b) (keypath :c)] data)))
|
|
|
|
|
|
2016-06-05 15:39:58 +00:00
|
|
|
|
2017-01-27 15:39:50 +00:00
|
|
|
(let [data {:a {:b {:c 1}}}]
|
2018-12-13 11:54:28 +00:00
|
|
|
(run-benchmark "set value in nested map"
|
2017-01-27 15:39:50 +00:00
|
|
|
(assoc-in data [:a :b :c] 1)
|
|
|
|
|
(setval [:a :b :c] 1 data)))
|
|
|
|
|
|
2016-06-05 15:39:58 +00:00
|
|
|
|
|
|
|
|
;; because below 1.7 there is no update function
|
|
|
|
|
(defn- my-update [m k afn]
|
|
|
|
|
(assoc m k (afn (get m k))))
|
|
|
|
|
|
|
|
|
|
(defn manual-transform [m afn]
|
|
|
|
|
(my-update m :a
|
|
|
|
|
(fn [m2]
|
|
|
|
|
(my-update m2 :b
|
|
|
|
|
(fn [m3]
|
|
|
|
|
(my-update m3 :c afn))))))
|
|
|
|
|
|
|
|
|
|
(let [data {:a {:b {:c 1}}}]
|
2018-12-13 11:54:28 +00:00
|
|
|
(run-benchmark "update value in nested map"
|
2016-06-05 15:39:58 +00:00
|
|
|
(update-in data [:a :b :c] inc)
|
|
|
|
|
(transform [:a :b :c] inc data)
|
2016-08-11 14:13:27 +00:00
|
|
|
(manual-transform data inc)))
|
|
|
|
|
|
2016-06-05 15:39:58 +00:00
|
|
|
|
2016-06-15 16:23:03 +00:00
|
|
|
(defn map-vals-map-iterable [^clojure.lang.IMapIterable m afn]
|
|
|
|
|
(let [k-it (.keyIterator m)
|
|
|
|
|
v-it (.valIterator m)]
|
|
|
|
|
(loop [ret {}]
|
|
|
|
|
(if (.hasNext k-it)
|
|
|
|
|
(let [k (.next k-it)
|
|
|
|
|
v (.next v-it)]
|
2016-08-11 14:13:27 +00:00
|
|
|
(recur (assoc ret k (afn v))))
|
|
|
|
|
|
|
|
|
|
ret))))
|
|
|
|
|
|
2016-06-15 16:23:03 +00:00
|
|
|
|
|
|
|
|
(defn map-vals-map-iterable-transient [^clojure.lang.IMapIterable m afn]
|
|
|
|
|
(persistent!
|
|
|
|
|
(let [k-it (.keyIterator m)
|
|
|
|
|
v-it (.valIterator m)]
|
|
|
|
|
(loop [ret (transient {})]
|
|
|
|
|
(if (.hasNext k-it)
|
|
|
|
|
(let [k (.next k-it)
|
|
|
|
|
v (.next v-it)]
|
2016-08-11 14:13:27 +00:00
|
|
|
(recur (assoc! ret k (afn v))))
|
|
|
|
|
|
|
|
|
|
ret)))))
|
|
|
|
|
|
2016-06-15 16:23:03 +00:00
|
|
|
|
2017-04-11 15:44:39 +00:00
|
|
|
(let [data '(1 2 3 4 5)]
|
2018-12-13 11:54:28 +00:00
|
|
|
(run-benchmark "transform values of a list"
|
2017-04-11 15:44:39 +00:00
|
|
|
(transform ALL inc data)
|
2017-04-11 15:58:52 +00:00
|
|
|
(doall (sequence (map inc) data))
|
2017-04-11 15:44:39 +00:00
|
|
|
(reverse (into '() (map inc) data))
|
|
|
|
|
))
|
|
|
|
|
|
2016-06-15 14:31:59 +00:00
|
|
|
(let [data {:a 1 :b 2 :c 3 :d 4}]
|
2018-12-13 11:54:28 +00:00
|
|
|
(run-benchmark "transform values of a small map"
|
2016-06-15 14:31:59 +00:00
|
|
|
(into {} (for [[k v] data] [k (inc v)]))
|
|
|
|
|
(reduce-kv (fn [m k v] (assoc m k (inc v))) {} data)
|
2016-06-15 15:02:07 +00:00
|
|
|
(persistent! (reduce-kv (fn [m k v] (assoc! m k (inc v))) (transient {}) data))
|
2016-06-15 14:31:59 +00:00
|
|
|
(reduce-kv (fn [m k v] (assoc m k (inc v))) (empty data) data)
|
|
|
|
|
(transform [ALL LAST] inc data)
|
|
|
|
|
(transform MAP-VALS inc data)
|
|
|
|
|
(zipmap (keys data) (map inc (vals data)))
|
2016-06-15 16:23:03 +00:00
|
|
|
(into {} (map (fn [e] [(key e) (inc (val e))]) data))
|
2017-06-06 19:12:57 +00:00
|
|
|
(into {} (map (fn [e] [(key e) (inc (val e))])) data)
|
2016-06-15 16:23:03 +00:00
|
|
|
(map-vals-map-iterable data inc)
|
2017-06-06 19:12:57 +00:00
|
|
|
(map-vals-map-iterable-transient data inc)
|
|
|
|
|
))
|
2016-08-11 14:13:27 +00:00
|
|
|
|
2016-06-15 14:31:59 +00:00
|
|
|
|
|
|
|
|
(let [data (->> (for [i (range 1000)] [i i]) (into {}))]
|
2018-12-13 11:54:28 +00:00
|
|
|
(run-benchmark "transform values of large map"
|
2016-06-15 14:31:59 +00:00
|
|
|
(into {} (for [[k v] data] [k (inc v)]))
|
|
|
|
|
(reduce-kv (fn [m k v] (assoc m k (inc v))) {} data)
|
2016-06-15 15:02:07 +00:00
|
|
|
(persistent! (reduce-kv (fn [m k v] (assoc! m k (inc v))) (transient {}) data))
|
2016-06-15 16:23:03 +00:00
|
|
|
(persistent! (reduce-kv (fn [m k v] (assoc! m k (inc v))) (transient clojure.lang.PersistentHashMap/EMPTY) data))
|
2016-06-15 14:31:59 +00:00
|
|
|
(reduce-kv (fn [m k v] (assoc m k (inc v))) (empty data) data)
|
|
|
|
|
(transform [ALL LAST] inc data)
|
|
|
|
|
(transform MAP-VALS inc data)
|
|
|
|
|
(zipmap (keys data) (map inc (vals data)))
|
2016-06-15 16:23:03 +00:00
|
|
|
(into {} (map (fn [e] [(key e) (inc (val e))]) data))
|
2017-06-06 19:12:57 +00:00
|
|
|
(into {} (map (fn [e] [(key e) (inc (val e))])) data)
|
2016-06-15 16:23:03 +00:00
|
|
|
(map-vals-map-iterable data inc)
|
2016-08-11 14:13:27 +00:00
|
|
|
(map-vals-map-iterable-transient data inc)))
|
|
|
|
|
|
2016-06-15 14:31:59 +00:00
|
|
|
|
2017-02-12 17:13:13 +00:00
|
|
|
(let [data [1 2 3 4 5 6 7 8 9 10]]
|
2018-12-13 11:54:28 +00:00
|
|
|
(run-benchmark "first value of a size 10 vector"
|
2017-02-12 17:13:13 +00:00
|
|
|
(first data)
|
|
|
|
|
(select-any ALL data)
|
|
|
|
|
(select-any FIRST data)
|
|
|
|
|
(select-first ALL data)
|
|
|
|
|
))
|
|
|
|
|
|
2016-06-05 15:39:58 +00:00
|
|
|
(let [data [1 2 3 4 5]]
|
2018-12-13 11:54:28 +00:00
|
|
|
(run-benchmark "map a function over a vector"
|
2016-06-05 15:39:58 +00:00
|
|
|
(vec (map inc data))
|
|
|
|
|
(mapv inc data)
|
2016-09-06 23:32:17 +00:00
|
|
|
(transform ALL inc data)
|
|
|
|
|
(into [] (map inc) data)))
|
2016-08-11 14:13:27 +00:00
|
|
|
|
2016-06-05 15:39:58 +00:00
|
|
|
|
2016-06-07 00:29:45 +00:00
|
|
|
(let [data [1 2 3 4 5 6 7 8 9 10]]
|
2018-12-13 11:54:28 +00:00
|
|
|
(run-benchmark "filter a sequence"
|
2016-06-07 00:29:45 +00:00
|
|
|
(doall (filter even? data))
|
2016-06-07 04:49:52 +00:00
|
|
|
(filterv even? data)
|
2016-06-07 00:29:45 +00:00
|
|
|
(select [ALL even?] data)
|
2016-09-06 23:32:17 +00:00
|
|
|
(select-any (filterer even?) data)
|
|
|
|
|
(into [] (filter even?) data)))
|
2016-08-11 14:13:27 +00:00
|
|
|
|
2016-06-07 00:29:45 +00:00
|
|
|
|
2016-06-17 16:56:33 +00:00
|
|
|
(let [data [{:a 2 :b 2} {:a 1} {:a 4} {:a 6}]
|
|
|
|
|
xf (comp (map :a) (filter even?))]
|
2018-12-13 11:54:28 +00:00
|
|
|
(run-benchmark "even :a values from sequence of maps"
|
2016-06-07 13:40:14 +00:00
|
|
|
(select [ALL :a even?] data)
|
|
|
|
|
(->> data (mapv :a) (filter even?) doall)
|
2016-06-17 16:56:33 +00:00
|
|
|
(into [] (comp (map :a) (filter even?)) data)
|
2016-08-11 14:13:27 +00:00
|
|
|
(into [] xf data)))
|
|
|
|
|
|
2016-06-07 13:40:14 +00:00
|
|
|
|
2016-06-07 20:07:01 +00:00
|
|
|
(let [v (vec (range 1000))]
|
2017-02-16 01:34:44 +00:00
|
|
|
(run-benchmark "Append to a large vector"
|
2016-06-07 20:07:01 +00:00
|
|
|
(setval END [1] v)
|
2017-02-16 01:34:44 +00:00
|
|
|
(setval AFTER-ELEM 1 v)
|
2016-06-07 20:07:01 +00:00
|
|
|
(reduce conj v [1])
|
|
|
|
|
(conj v 1)))
|
2016-06-05 15:39:58 +00:00
|
|
|
|
2017-02-21 16:18:32 +00:00
|
|
|
(let [data [1 2 3 4 5 6 7 8 9 10]]
|
2018-12-13 11:54:28 +00:00
|
|
|
(run-benchmark "prepend to a vector"
|
2017-02-21 16:18:32 +00:00
|
|
|
(vec (cons 0 data))
|
|
|
|
|
(setval BEFORE-ELEM 0 data)
|
|
|
|
|
(into [0] data)
|
|
|
|
|
))
|
2016-06-05 15:39:58 +00:00
|
|
|
|
|
|
|
|
(declarepath TreeValues)
|
|
|
|
|
|
|
|
|
|
(providepath TreeValues
|
|
|
|
|
(if-path vector?
|
|
|
|
|
[ALL TreeValues]
|
|
|
|
|
STAY))
|
|
|
|
|
|
|
|
|
|
(defprotocolpath TreeValuesProt)
|
|
|
|
|
|
|
|
|
|
(extend-protocolpath TreeValuesProt
|
|
|
|
|
clojure.lang.PersistentVector [ALL TreeValuesProt]
|
|
|
|
|
Object STAY)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
(defn tree-value-transform [afn atree]
|
|
|
|
|
(if (vector? atree)
|
|
|
|
|
(mapv #(tree-value-transform afn %) atree)
|
2016-08-11 14:13:27 +00:00
|
|
|
(afn atree)))
|
|
|
|
|
|
2016-06-05 15:39:58 +00:00
|
|
|
|
|
|
|
|
(let [data [1 2 [[3]] [4 6 [7 [8]] 10]]]
|
|
|
|
|
(run-benchmark "update every value in a tree (represented with vectors)"
|
|
|
|
|
(walk/postwalk (fn [e] (if (and (number? e) (even? e)) (inc e) e)) data)
|
|
|
|
|
(transform [(walker number?) even?] inc data)
|
|
|
|
|
(transform [TreeValues even?] inc data)
|
|
|
|
|
(transform [TreeValuesProt even?] inc data)
|
2016-08-11 14:13:27 +00:00
|
|
|
(tree-value-transform (fn [e] (if (even? e) (inc e) e)) data)))
|
|
|
|
|
|
2016-06-05 15:39:58 +00:00
|
|
|
|
2016-06-08 10:02:41 +00:00
|
|
|
(let [toappend (range 1000)]
|
|
|
|
|
(run-benchmark "transient comparison: building up vectors"
|
|
|
|
|
(reduce (fn [v i] (conj v i)) [] toappend)
|
|
|
|
|
(reduce (fn [v i] (conj! v i)) (transient []) toappend)
|
|
|
|
|
(setval END toappend [])
|
|
|
|
|
(setval END! toappend (transient []))))
|
2016-06-08 06:16:23 +00:00
|
|
|
|
2016-06-08 10:57:15 +00:00
|
|
|
(let [toappend (range 1000)]
|
|
|
|
|
(run-benchmark "transient comparison: building up vectors one at a time"
|
|
|
|
|
(reduce (fn [v i] (conj v i)) [] toappend)
|
|
|
|
|
(reduce (fn [v i] (conj! v i)) (transient []) toappend)
|
|
|
|
|
(reduce (fn [v i] (setval END [i] v)) [] toappend)
|
2016-08-11 14:13:27 +00:00
|
|
|
(reduce (fn [v i] (setval END! [i] v)) (transient []) toappend)))
|
|
|
|
|
|
2016-06-08 10:57:15 +00:00
|
|
|
|
2016-06-08 06:16:23 +00:00
|
|
|
(let [data (vec (range 1000))
|
2016-06-08 10:02:41 +00:00
|
|
|
tdata (transient data)
|
2016-08-06 06:22:51 +00:00
|
|
|
tdata2 (transient data)]
|
2016-06-08 06:16:23 +00:00
|
|
|
(run-benchmark "transient comparison: assoc'ing in vectors"
|
2016-08-06 06:22:51 +00:00
|
|
|
(assoc data 600 0)
|
|
|
|
|
(assoc! tdata 600 0)
|
|
|
|
|
(setval (keypath 600) 0 data)
|
|
|
|
|
(setval (keypath! 600) 0 tdata2)))
|
2016-06-08 06:16:23 +00:00
|
|
|
|
|
|
|
|
(let [data (into {} (for [k (range 1000)]
|
|
|
|
|
[k (rand)]))
|
2016-06-08 10:02:41 +00:00
|
|
|
tdata (transient data)
|
2016-08-06 06:22:51 +00:00
|
|
|
tdata2 (transient data)]
|
2016-06-08 06:16:23 +00:00
|
|
|
(run-benchmark "transient comparison: assoc'ing in maps"
|
2016-08-06 06:22:51 +00:00
|
|
|
(assoc data 600 0)
|
|
|
|
|
(assoc! tdata 600 0)
|
|
|
|
|
(setval (keypath 600) 0 data)
|
|
|
|
|
(setval (keypath! 600) 0 tdata2)))
|
2016-06-08 06:16:23 +00:00
|
|
|
|
|
|
|
|
(defn modify-submap
|
|
|
|
|
[m]
|
|
|
|
|
(assoc m 0 1 458 89))
|
|
|
|
|
|
|
|
|
|
(let [data (into {} (for [k (range 1000)]
|
|
|
|
|
[k (rand)]))
|
|
|
|
|
tdata (transient data)]
|
|
|
|
|
(run-benchmark "transient comparison: submap"
|
2016-06-08 10:02:41 +00:00
|
|
|
(transform (submap [600 700]) modify-submap data)
|
|
|
|
|
(transform (submap! [600 700]) modify-submap tdata)))
|
2016-06-08 15:18:10 +00:00
|
|
|
|
|
|
|
|
(let [data {:x 1}
|
|
|
|
|
meta-map {:my :metadata}]
|
|
|
|
|
(run-benchmark "set metadata"
|
|
|
|
|
(with-meta data meta-map)
|
|
|
|
|
(setval META meta-map data)))
|
|
|
|
|
|
|
|
|
|
(let [data (with-meta {:x 1} {:my :metadata})]
|
|
|
|
|
(run-benchmark "get metadata"
|
2016-06-08 17:58:15 +00:00
|
|
|
(meta data)
|
|
|
|
|
(select-any META data)))
|
2016-06-08 15:25:03 +00:00
|
|
|
|
|
|
|
|
(let [data (with-meta {:x 1} {:my :metadata})]
|
|
|
|
|
(run-benchmark "vary metadata"
|
|
|
|
|
(vary-meta data assoc :y 2)
|
|
|
|
|
(setval [META :y] 2 data)))
|
2016-06-09 20:36:20 +00:00
|
|
|
|
2016-06-15 13:31:24 +00:00
|
|
|
(let [data (range 1000)]
|
2018-12-13 11:54:28 +00:00
|
|
|
(run-benchmark "Traverse into a set"
|
2016-06-15 13:31:24 +00:00
|
|
|
(set data)
|
|
|
|
|
(set (select ALL data))
|
|
|
|
|
(into #{} (traverse ALL data))
|
|
|
|
|
(persistent!
|
|
|
|
|
(reduce conj! (transient #{}) (traverse ALL data)))
|
2016-08-11 14:13:27 +00:00
|
|
|
(reduce conj #{} (traverse ALL data))))
|
|
|
|
|
|
2016-06-15 13:31:24 +00:00
|
|
|
|
2016-06-23 16:30:50 +00:00
|
|
|
(defn mult-10 [v] (* 10 v))
|
|
|
|
|
|
|
|
|
|
(let [data [1 2 3 4 5 6 7 8 9]]
|
2018-12-13 11:54:28 +00:00
|
|
|
(run-benchmark "multi-transform vs. consecutive transforms, one shared nav"
|
2016-06-23 16:30:50 +00:00
|
|
|
(->> data (transform [ALL even?] mult-10) (transform [ALL odd?] dec))
|
2016-08-11 14:13:27 +00:00
|
|
|
(multi-transform [ALL (multi-path [even? (terminal mult-10)] [odd? (terminal dec)])] data)))
|
|
|
|
|
|
2016-06-23 16:30:50 +00:00
|
|
|
|
|
|
|
|
(let [data [[1 2 3 4 :a] [5] [6 7 :b 8 9] [10 11 12 13]]]
|
2018-12-13 11:54:28 +00:00
|
|
|
(run-benchmark "multi-transform vs. consecutive transforms, three shared navs"
|
2016-06-23 16:30:50 +00:00
|
|
|
(->> data (transform [ALL ALL number? even?] mult-10) (transform [ALL ALL number? odd?] dec))
|
2016-08-11 14:13:27 +00:00
|
|
|
(multi-transform [ALL ALL number? (multi-path [even? (terminal mult-10)] [odd? (terminal dec)])] data)))
|
2017-02-28 21:23:10 +00:00
|
|
|
|
|
|
|
|
(let [data {:a 1 :b 2 :c 3 :d 4}]
|
2018-12-13 11:54:28 +00:00
|
|
|
(run-benchmark "namespace qualify keys of a small map"
|
2017-02-28 21:23:10 +00:00
|
|
|
(into {}
|
|
|
|
|
(map (fn [[k v]] [(keyword (str *ns*) (name k)) v]))
|
|
|
|
|
data)
|
|
|
|
|
(reduce-kv (fn [m k v] (assoc m (keyword (str *ns*) (name k)) v)) {} data)
|
|
|
|
|
(setval [MAP-KEYS NAMESPACE] (str *ns*) data)
|
|
|
|
|
))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
(let [data (->> (for [i (range 1000)] [(keyword (str i)) i]) (into {}))]
|
2018-12-13 11:54:28 +00:00
|
|
|
(run-benchmark "namespace qualify keys of a large map"
|
2017-02-28 21:23:10 +00:00
|
|
|
(into {}
|
|
|
|
|
(map (fn [[k v]] [(keyword (str *ns*) (name k)) v]))
|
|
|
|
|
data)
|
|
|
|
|
(reduce-kv (fn [m k v] (assoc m (keyword (str *ns*) (name k)) v)) {} data)
|
|
|
|
|
(setval [MAP-KEYS NAMESPACE] (str *ns*) data)
|
|
|
|
|
))
|
2017-06-03 22:23:13 +00:00
|
|
|
|
|
|
|
|
(defnav walker-old [afn]
|
|
|
|
|
(select* [this structure next-fn]
|
|
|
|
|
(i/walk-select afn next-fn structure))
|
|
|
|
|
(transform* [this structure next-fn]
|
|
|
|
|
(i/walk-until afn next-fn structure)))
|
|
|
|
|
|
|
|
|
|
(let [data {:a [1 2 {:c '(3 4) :d {:e [1 2 3] 7 8 9 10}}]}]
|
2018-12-13 11:54:28 +00:00
|
|
|
(run-benchmark "walker vs. clojure.walk version"
|
2017-06-03 22:23:13 +00:00
|
|
|
(transform (walker number?) inc data)
|
|
|
|
|
(transform (walker-old number?) inc data)
|
|
|
|
|
))
|
2020-09-17 19:15:42 +00:00
|
|
|
|
|
|
|
|
(let [size 1000
|
|
|
|
|
middle-idx (/ size 2)
|
|
|
|
|
v -1
|
|
|
|
|
rng (range size)
|
|
|
|
|
data-vec (vec rng)
|
|
|
|
|
data-lst (apply list rng)]
|
|
|
|
|
(run-benchmark "before-index vs. srange in middle (vector)"
|
|
|
|
|
(setval (before-index middle-idx) v data-vec)
|
|
|
|
|
(setval (srange middle-idx middle-idx) [v] data-vec))
|
|
|
|
|
(run-benchmark "before-index vs. srange in middle (list)"
|
|
|
|
|
(setval (before-index middle-idx) v data-lst)
|
|
|
|
|
(setval (srange middle-idx middle-idx) [v] data-lst))
|
|
|
|
|
(run-benchmark "before-index at 0 vs. srange vs. cons (list)"
|
|
|
|
|
(setval (before-index 0) v data-lst)
|
|
|
|
|
(setval (srange 0 0) [v] data-lst)
|
|
|
|
|
(cons v data-lst)))
|