├── .gitignore ├── .travis.yml ├── README.md ├── project.clj ├── public └── index.html ├── src └── cljs │ └── tailrecursion │ └── priority_map.cljs └── test ├── firefox-profile └── user.js ├── run.sh ├── runner.js └── tailrecursion └── priority_map └── test.cljs /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | /lib 3 | /classes 4 | /checkouts 5 | pom.xml 6 | *.jar 7 | *.class 8 | .lein-deps-sum 9 | .lein-failures 10 | .lein-plugins 11 | .lein-repl-history 12 | /public/test.js 13 | /test/firefox-profile 14 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | language: clojure 3 | lein: lein2 4 | script: lein2 cljsbuild once test && test/run.sh 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # cljs-priority-map [![Build Status][1]][2] 2 | 3 | This is a ClojureScript port of Mark Engelberg's [clojure.data.priority-map][3] 4 | for Clojure. 5 | 6 | A priority map is very similar to a sorted map, but whereas a sorted 7 | map produces a sequence of the entries sorted by key, a priority map 8 | produces the entries sorted by value. 9 | 10 | ## Usage 11 | 12 | ### Dependency 13 | 14 | Artifacts are published on [Clojars][4]. 15 | 16 | ```clojure 17 | [tailrecursion/cljs-priority-map "1.2.1"] 18 | ``` 19 | 20 | ```xml 21 | 22 | tailrecursion 23 | cljs-priority-map 24 | 1.2.1 25 | 26 | ``` 27 | 28 | ### Example 29 | 30 | ```clojure 31 | ;; Require or use tailrecursion.priority-map in your namespace. 32 | 33 | (ns your-ns 34 | (:require [tailrecursion.priority-map :refer [priority-map priority-map-by]]))) 35 | 36 | ;; The standard way to construct a priority map is with priority-map: 37 | 38 | (def p (priority-map :a 2 :b 1 :c 3 :d 5 :e 4 :f 3)) 39 | 40 | p ;=> {:b 1, :a 2, :c 3, :f 3, :e 4, :d 5} 41 | 42 | ;; So :b has priority 1, :a has priority 2, and so on. Notice how the 43 | ;; priority map prints in an order sorted by its priorities (i.e., the 44 | ;; map's values) 45 | 46 | ;; We can use assoc to assign a priority to a new item: 47 | 48 | (assoc p :g 1) ;=> {:b 1, :g 1, :a 2, :c 3, :f 3, :e 4, :d 5} 49 | 50 | ;; or to assign a new priority to an extant item: 51 | 52 | (assoc p :c 4) ;=> {:b 1, :a 2, :f 3, :c 4, :e 4, :d 5} 53 | 54 | ;; We can remove an item from the priority map: 55 | 56 | (dissoc p :e) ;=> {:b 1, :a 2, :c 3, :f 3, :d 5} 57 | 58 | ;; An alternative way to add to the priority map is to conj a [item priority] pair: 59 | 60 | (conj p [:g 0]) ;=> {:g 0, :b 1, :a 2, :c 3, :f 3, :e 4, :d 5} 61 | 62 | (into p [[:g 0] [:h 1] [:i 2]]) ;=> {:g 0, :b 1, :h 1, :a 2, :i 2, :c 3, :f 3, :e 4, :d 5} 63 | 64 | ;; Priority maps are countable: 65 | 66 | (count p) ;=> 6 67 | 68 | ;; Like other maps, equivalence is based not on type, but on contents. 69 | ;; In other words, just as a sorted-map can be equal to a hash-map, so 70 | ;; can a priority-map. 71 | 72 | (= p {:b 1, :a 2, :c 3, :f 3, :e 4, :d 5}) ;=> true 73 | 74 | ;; You can test them for emptiness: 75 | 76 | (empty? (priority-map)) ;=> true 77 | 78 | (empty? p) ;=> false 79 | 80 | ;; You can test whether an item is in the priority map: 81 | 82 | (contains? p :a) ;=> true 83 | 84 | (contains? p :g) ;=> false 85 | 86 | ;; It is easy to look up the priority of a given item, using any of 87 | ;; the standard map mechanisms: 88 | 89 | (get p :a) ;=> 2 90 | 91 | (get p :g 10) ;=> 10 92 | 93 | (p :a) ;=> 2 94 | 95 | (:a p) ;=> 2 96 | 97 | ;; Priority maps derive much of their utility by providing priority-based 98 | ;; seq. Note that no guarantees are made about the order in which items 99 | ;; of the same priority appear. 100 | 101 | (seq p) ;=> ([:b 1] [:a 2] [:c 3] [:f 3] [:e 4] [:d 5]) 102 | 103 | ;; Because no guarantees are made about the order of same-priority items, 104 | ;; note that rseq might not be an exact reverse of the seq. It is only 105 | ;; guaranteed to be in descending order. 106 | 107 | (rseq p) ;=> ([:d 5] [:e 4] [:c 3] [:f 3] [:a 2] [:b 1]) 108 | 109 | ;; This means first/rest/next/for/map/etc. All operate in priority order. 110 | 111 | (first p) ;=> [:b 1] 112 | 113 | (rest p) ;=> ([:a 2] [:c 3] [:f 3] [:e 4] [:d 5]) 114 | 115 | ;; This implementation supports subseq for obtaining sorted seqs of 116 | ;; entries for which one or two predicates are true. 117 | 118 | ;; seq of entries of priority > 3: 119 | 120 | (subseq p > 3) ;=> ([:e 4] [:d 5]) 121 | 122 | ;; seq of entries of priority >= 3 but < 5: 123 | 124 | (subseq p >= 3 < 5) ;=> ([:c 3] [:f 3] [:e 4]) 125 | 126 | ;; Priority maps support metadata: 127 | 128 | (meta (with-meta p {:extra :info})) ;=> {:extra :info} 129 | 130 | ;; But perhaps most importantly, priority maps can also function as 131 | ;; priority queues. peek, like first, gives you the first 132 | ;; [item priority] pair in the collection. pop removes the first 133 | ;; [item priority] from the collection. (Note that unlike rest, which 134 | ;; returns a seq, pop returns a priority map). 135 | 136 | (peek p) ;=> [:b 1] 137 | 138 | (pop p) ;=> {:a 2, :c 3, :f 3, :e 4, :d 5} 139 | 140 | ;; It is also possible to use a custom comparator: 141 | 142 | (priority-map-by > :a 1 :b 2 :c 3) ;=> {:c 3, :b 2, :a 1} 143 | ``` 144 | 145 | ## Testing 146 | 147 | [PhantomJS](http://phantomjs.org/) is used for unit testing. With it 148 | installed, you can run the tests like so: 149 | 150 | lein cljsbuild test 151 | 152 | ## License 153 | 154 | Copyright © 2013 Alan Dipert 155 | 156 | Distributed under the Eclipse Public License, the same as Clojure. 157 | 158 | [1]: https://travis-ci.org/tailrecursion/cljs-priority-map.png?branch=master 159 | [2]: https://travis-ci.org/tailrecursion/cljs-priority-map 160 | [3]: https://github.com/clojure/data.priority-map 161 | [4]: https://clojars.org/tailrecursion/cljs-priority-map 162 | -------------------------------------------------------------------------------- /project.clj: -------------------------------------------------------------------------------- 1 | (defproject tailrecursion/cljs-priority-map "1.2.1" 2 | :description "ClojureScript priority map implementation based on clojure.data.priority-map" 3 | :url "https://github.com/tailrecursion/cljs-priority-map" 4 | :license {:name "Eclipse Public License" 5 | :url "http://www.eclipse.org/legal/epl-v10.html"} 6 | :dependencies [[org.clojure/clojure "1.7.0"] 7 | [org.clojure/clojurescript "1.7.170"]] 8 | :source-paths ["src/cljs"] 9 | :plugins [[lein-cljsbuild "1.1.1"]] 10 | :cljsbuild {:builds {:test 11 | {:source-paths ["test"] 12 | :compiler {:output-to "public/test.js" 13 | :optimizations :advanced} 14 | :jar false}} 15 | :test-commands {"phantomjs" ["phantomjs" "public/test.js"]}}) 16 | -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | priority-map test 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /src/cljs/tailrecursion/priority_map.cljs: -------------------------------------------------------------------------------- 1 | (ns tailrecursion.priority-map 2 | (:require [cljs.core :as core]) 3 | (:use [cljs.reader :only [register-tag-parser!]]) 4 | (:require-macros [cljs.core :as coreclj])) 5 | 6 | (deftype PersistentPriorityMap [priority->set-of-items item->priority meta keyfn ^:mutable __hash] 7 | IPrintWithWriter 8 | (-pr-writer [coll writer opts] 9 | (let [pr-pair (fn [keyval] (pr-sequential-writer writer pr-writer "" " " "" opts keyval))] 10 | (pr-sequential-writer writer pr-pair "#tailrecursion.priority-map {" ", " "}" opts coll))) 11 | 12 | IWithMeta 13 | (-with-meta [this meta] 14 | (PersistentPriorityMap. priority->set-of-items item->priority meta keyfn __hash)) 15 | 16 | IMeta 17 | (-meta [this] meta) 18 | 19 | ICollection 20 | (-conj [this entry] 21 | (if (vector? entry) 22 | (-assoc this (-nth entry 0) (-nth entry 1)) 23 | (reduce -conj this entry))) 24 | 25 | IEmptyableCollection 26 | (-empty [this] (with-meta 27 | tailrecursion.priority-map.PersistentPriorityMap.EMPTY 28 | meta)) 29 | 30 | IEquiv 31 | (-equiv [this other] 32 | (-equiv item->priority other)) 33 | 34 | IHash 35 | (-hash [this] 36 | (coreclj/caching-hash this core/hash-unordered-coll __hash)) 37 | 38 | ISeqable 39 | (-seq [this] 40 | (if keyfn 41 | (seq (for [[priority item-set] priority->set-of-items, item item-set] 42 | [item (item->priority item)])) 43 | (seq (for [[priority item-set] priority->set-of-items, item item-set] 44 | [item priority])))) 45 | 46 | IReversible 47 | (-rseq [coll] 48 | (if keyfn 49 | (seq (for [[priority item-set] (rseq priority->set-of-items), item item-set] 50 | [item (item->priority item)])) 51 | (seq (for [[priority item-set] (rseq priority->set-of-items), item item-set] 52 | [item priority])))) 53 | 54 | ICounted 55 | (-count [this] 56 | (count item->priority)) 57 | 58 | ILookup 59 | (-lookup [this item] 60 | (get item->priority item)) 61 | (-lookup [coll item not-found] 62 | (get item->priority item not-found)) 63 | 64 | IStack 65 | (-peek [this] 66 | (when-not (zero? (count item->priority)) 67 | (let [f (first priority->set-of-items) 68 | item (first (val f))] 69 | (if keyfn 70 | [item (item->priority item)] 71 | [item (key f)])))) 72 | (-pop [this] 73 | (if (zero? (count item->priority)) 74 | (throw (js/Error. "Can't pop empty priority map")) 75 | (let [f (first priority->set-of-items) 76 | item-set (val f) 77 | item (first item-set) 78 | priority-key (key f)] 79 | (if (= (count item-set) 1) 80 | (PersistentPriorityMap. 81 | (dissoc priority->set-of-items priority-key) 82 | (dissoc item->priority item) 83 | meta 84 | keyfn 85 | nil) 86 | (PersistentPriorityMap. 87 | (assoc priority->set-of-items priority-key (disj item-set item)), 88 | (dissoc item->priority item) 89 | meta 90 | keyfn 91 | nil))))) 92 | 93 | IAssociative 94 | (-assoc [this item priority] 95 | (if-let [current-priority (get item->priority item nil)] 96 | (if (= current-priority priority) 97 | this 98 | (let [priority-key (keyfn priority) 99 | current-priority-key (keyfn current-priority) 100 | item-set (get priority->set-of-items current-priority-key)] 101 | (if (= (count item-set) 1) 102 | (PersistentPriorityMap. 103 | (assoc (dissoc priority->set-of-items current-priority-key) 104 | priority-key (conj (get priority->set-of-items priority-key #{}) item)) 105 | (assoc item->priority item priority) 106 | meta 107 | keyfn 108 | nil) 109 | (PersistentPriorityMap. 110 | (assoc priority->set-of-items 111 | current-priority-key (disj (get priority->set-of-items current-priority-key) item) 112 | priority-key (conj (get priority->set-of-items priority-key #{}) item)) 113 | (assoc item->priority item priority) 114 | meta 115 | keyfn 116 | nil)))) 117 | (let [priority-key (keyfn priority)] 118 | (PersistentPriorityMap. 119 | (assoc priority->set-of-items 120 | priority-key (conj (get priority->set-of-items priority-key #{}) item)) 121 | (assoc item->priority item priority) 122 | meta 123 | keyfn 124 | nil)))) 125 | 126 | (-contains-key? [this item] 127 | (contains? item->priority item)) 128 | 129 | IMap 130 | (-dissoc [this item] 131 | (let [priority (item->priority item ::not-found)] 132 | (if (= priority ::not-found) 133 | this 134 | (let [priority-key (keyfn priority) 135 | item-set (priority->set-of-items priority-key)] 136 | (if (= (count item-set) 1) 137 | (PersistentPriorityMap. 138 | (dissoc priority->set-of-items priority-key) 139 | (dissoc item->priority item) 140 | meta 141 | keyfn 142 | nil) 143 | (PersistentPriorityMap. 144 | (assoc priority->set-of-items priority-key (disj item-set item)), 145 | (dissoc item->priority item) 146 | meta 147 | keyfn 148 | nil)))))) 149 | 150 | ISorted 151 | (-sorted-seq [this ascending?] 152 | ((if ascending? seq rseq) this)) 153 | (-sorted-seq-from [this k ascending?] 154 | (let [sets (if ascending? 155 | (subseq priority->set-of-items >= k) 156 | (rsubseq priority->set-of-items <= k))] 157 | (if keyfn 158 | (seq (for [[priority item-set] sets, item item-set] 159 | [item (item->priority item)])) 160 | (seq (for [[priority item-set] sets, item item-set] 161 | [item priority]))))) 162 | (-entry-key [this entry] 163 | (keyfn (val entry))) 164 | (-comparator [this] compare) 165 | 166 | IFn 167 | (-invoke [this item] 168 | (-lookup this item)) 169 | (-invoke [this item not-found] 170 | (-lookup this item not-found))) 171 | 172 | (set! tailrecursion.priority-map.PersistentPriorityMap.EMPTY 173 | (PersistentPriorityMap. (sorted-map) {} {} identity nil)) 174 | 175 | (defn- pm-empty-by [comparator] 176 | (PersistentPriorityMap. (sorted-map-by comparator) {} {} identity nil)) 177 | 178 | (defn- pm-empty-keyfn 179 | ([keyfn] (PersistentPriorityMap. (sorted-map) {} {} keyfn nil)) 180 | ([keyfn comparator] (PersistentPriorityMap. (sorted-map-by comparator) {} {} keyfn nil))) 181 | 182 | (defn- read-priority-map [elems] 183 | (if (map? elems) 184 | (into tailrecursion.priority-map.PersistentPriorityMap.EMPTY elems) 185 | (throw (js/Error "Priority map literal expects a map for its elements.")))) 186 | 187 | (register-tag-parser! "tailrecursion.priority-map" read-priority-map) 188 | 189 | (defn priority-map 190 | "keyval => key val 191 | Returns a new priority map with supplied mappings." 192 | ([& keyvals] 193 | (loop [in (seq keyvals) out tailrecursion.priority-map.PersistentPriorityMap.EMPTY] 194 | (if in 195 | (recur (nnext in) (assoc out (first in) (second in))) 196 | out)))) 197 | 198 | (defn priority-map-by 199 | "keyval => key val 200 | Returns a new priority map with supplied 201 | mappings, using the supplied comparator." 202 | ([comparator & keyvals] 203 | (loop [in (seq keyvals) out (pm-empty-by comparator)] 204 | (if in 205 | (recur (nnext in) (assoc out (first in) (second in))) 206 | out)))) 207 | 208 | (defn priority-map-keyfn 209 | "keyval => key val 210 | Returns a new priority map with supplied 211 | mappings, using the supplied keyfn." 212 | ([keyfn & keyvals] 213 | (loop [in (seq keyvals) out (pm-empty-keyfn keyfn)] 214 | (if in 215 | (recur (nnext in) (assoc out (first in) (second in))) 216 | out)))) 217 | 218 | (defn priority-map-keyfn-by 219 | "keyval => key val 220 | Returns a new priority map with supplied 221 | mappings, using the supplied keyfn and comparator." 222 | ([keyfn comparator & keyvals] 223 | (loop [in (seq keyvals) out (pm-empty-keyfn keyfn comparator)] 224 | (if in 225 | (recur (nnext in) (assoc out (first in) (second in))) 226 | out)))) 227 | -------------------------------------------------------------------------------- /test/firefox-profile/user.js: -------------------------------------------------------------------------------- 1 | user_pref("browser.dom.window.dump.enabled", true); 2 | user_pref("dom.max_script_run_time", 9007199254740992); 3 | -------------------------------------------------------------------------------- /test/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | run_phantom() { 6 | phantomjs --version 7 | phantomjs test/runner.js 8 | } 9 | 10 | run_ff() { 11 | firefox -version 12 | this_tty=$(tty) 13 | xvfb-run -a firefox -profile test/firefox-profile -no-remote "public/index.html" \ 14 | | while read line; do 15 | if [ "$line" = "Done." ]; then 16 | kill -n 2 $(ps -t $this_tty | grep firefox | awk '{print $1}') 17 | echo "All tests passed (on firefox)." 18 | else 19 | echo "$line" 20 | fi 21 | done 22 | } 23 | 24 | run_phantom 25 | run_ff 26 | -------------------------------------------------------------------------------- /test/runner.js: -------------------------------------------------------------------------------- 1 | function info(msg, type) { 2 | var red, green, reset; 3 | red = '\u001b[31m'; 4 | green = '\u001b[32m'; 5 | reset = '\u001b[0m'; 6 | if(type == 'error') { 7 | console.error(red + msg + reset); 8 | } else { 9 | console.log(green + msg + reset); 10 | } 11 | } 12 | 13 | page = new WebPage(); 14 | 15 | page.onConsoleMessage = info; 16 | 17 | page.onError = function(msg, trace) { 18 | var msgStack = ['ERROR: ' + msg]; 19 | if (trace) { 20 | msgStack.push('TRACE:'); 21 | trace.forEach(function(t) { 22 | msgStack.push(' -> ' + t.file + ': ' + t.line + (t.function ? ' (in function "' + t.function + '")' : '')); 23 | }); 24 | } 25 | info(msgStack.join('\n'), 'error'); 26 | phantom.exit(1); 27 | }; 28 | 29 | page.onLoadFinished = function(status) { 30 | info("All tests passed (on phantomjs)."); 31 | phantom.exit(0); 32 | }; 33 | 34 | page.open("public/index.html"); 35 | -------------------------------------------------------------------------------- /test/tailrecursion/priority_map/test.cljs: -------------------------------------------------------------------------------- 1 | (ns tailrecursion.priority-map.test 2 | (:require [tailrecursion.priority-map :as pm] 3 | [cljs.reader :refer [read-string]])) 4 | 5 | (set! cljs.core/*print-fn* 6 | (if (undefined? (aget js/window "dump")) 7 | ;; phantomjs 8 | #(.apply (.-log js/console) 9 | (.-console js/window) 10 | (apply array %&)) 11 | ;; firefox 12 | #(.apply (aget js/window "dump") 13 | js/window 14 | (apply array %&)))) 15 | 16 | (def p (pm/priority-map :a 2 :b 1 :c 3 :d 5 :e 4 :f 3)) 17 | (def h {:a 2 :b 1 :c 3 :d 5 :e 4 :f 3}) 18 | 19 | (assert (= p {:a 2 :b 1 :c 3 :d 5 :e 4 :f 3})) 20 | (assert (= h p)) 21 | (assert (= :b (first (peek (into (pm/priority-map) h))))) 22 | (assert (= (pm/priority-map 1 2) (pm/priority-map 1 2))) 23 | (assert (= (-hash p) (-hash {:a 2 :b 1 :c 3 :d 5 :e 4 :f 3}))) 24 | (assert (= (assoc p :g 1) (assoc h :g 1))) 25 | (assert (= (assoc p :g 0) (assoc h :g 0))) 26 | (assert (= (assoc p :c 4) (assoc h :c 4))) 27 | (assert (= (assoc p :c 6) (assoc h :c 6))) 28 | (assert (= (assoc p :b 2) (assoc h :b 2))) 29 | (assert (= (assoc p :b 6) (assoc h :b 6))) 30 | (assert (= (dissoc p :e) (dissoc h :e))) 31 | (assert (= (dissoc p :g) (dissoc h :g))) 32 | (assert (= (dissoc p :c) (dissoc h :c))) 33 | (assert (= (dissoc p :x) p)) 34 | (assert (= (peek (dissoc p :x)) (peek p))) 35 | (assert (= (pop (dissoc p :x)) (pop p))) 36 | (assert (= (conj p [:g 1]) (conj h [:g 1]))) 37 | (assert (= (conj p [:g 0]) (conj h [:g 0]))) 38 | (assert (= (conj p [:c 4]) (conj h [:c 4]))) 39 | (assert (= (conj p [:c 6]) (conj h [:c 6]))) 40 | (assert (= (conj p [:b 2]) (conj h [:b 2]))) 41 | (assert (= (conj p [:b 6]) (conj h [:b 6]))) 42 | (assert (= (into p [[:g 0] [:h 1] [:i 2]]) (into h [[:g 0] [:h 1] [:i 2]]))) 43 | (assert (= (count p) (count h))) 44 | (assert (= (empty? p) false)) 45 | (assert (= (empty? (pm/priority-map)) true)) 46 | (assert (= (contains? p :a) true)) 47 | (assert (= (contains? p :g) false)) 48 | (assert (= (get p :a) 2)) 49 | (assert (= (get p :a 8) 2)) 50 | (assert (= (get p :g) nil)) 51 | (assert (= (get p :g 8) 8)) 52 | (assert (= (p :a) 2)) 53 | (assert (= (:a p) 2)) 54 | (assert (= (seq p) '([:b 1] [:a 2] [:c 3] [:f 3] [:e 4] [:d 5]))) 55 | (assert (= (rseq p) '([:d 5] [:e 4] [:c 3] [:f 3] [:a 2] [:b 1]))) 56 | (assert (= (first p) [:b 1])) 57 | (assert (= (rest p) '([:a 2] [:c 3] [:f 3] [:e 4] [:d 5]))) 58 | (assert (= (meta (with-meta p {:extra :info})) {:extra :info})) 59 | (assert (= (meta (dissoc (with-meta p {:extra :info}) :a)) {:extra :info})) 60 | (assert (= (meta (assoc (with-meta p {:extra :info}) :g 0)) {:extra :info})) 61 | (assert (= (peek p) [:b 1])) 62 | (assert (= (pop p) {:a 2 :c 3 :f 3 :e 4 :d 5})) 63 | (assert (= (peek (pm/priority-map)) nil)) 64 | (assert (= (seq (pm/priority-map-by > :a 1 :b 2 :c 3)) [[:c 3] [:b 2] [:a 1]])) 65 | (assert (= (meta (empty (with-meta p {:x 123}))) {:x 123})) 66 | (assert (= (subseq p < 3) '([:b 1] [:a 2]))) 67 | (assert (= (subseq p >= 4) '([:e 4] [:d 5]))) 68 | (assert (= (subseq p >= 4 < 5) '([:e 4]))) 69 | 70 | (def pk (pm/priority-map-keyfn :order :a {:order 2} :b {:order 1} :c {:order 3})) 71 | 72 | (assert (= (seq pk) [[:b {:order 1}] [:a {:order 2}] [:c {:order 3}]])) 73 | (assert (= (subseq pk > 1) '([:a {:order 2}] [:c {:order 3}]))) 74 | (assert (= (rsubseq pk < 3) '([:a {:order 2}] [:b {:order 1}]))) 75 | (assert (assoc (pm/priority-map-keyfn first :a [1] :b [1]) :a [2])) 76 | 77 | (def pkb (pm/priority-map-keyfn-by :order > :a {:order 2} :b {:order 1} :c {:order 3})) 78 | (assert (= (seq pkb) [[:c {:order 3}] [:a {:order 2}] [:b {:order 1}]])) 79 | (assert (= (rsubseq pkb < 1) '([:a {:order 2}] [:c {:order 3}]))) 80 | (assert (= (subseq pkb > 3) '([:a {:order 2}] [:b {:order 1}]))) 81 | 82 | ;;; printing, reader 83 | 84 | (assert (= p (read-string (pr-str p)))) 85 | 86 | ;;; perf 87 | 88 | (dotimes [_ 10] 89 | (time 90 | (loop [p2 (apply pm/priority-map (range 10000))] 91 | (when-not (empty? p2) 92 | (recur (pop p2)))))) 93 | 94 | (dotimes [_ 10] 95 | (time 96 | (loop [p2 (apply pm/priority-map (range 10000))] 97 | (when-not (empty? p2) 98 | (peek p2) 99 | (recur (pop p2)))))) 100 | 101 | ;; (def basis (atom 0)) 102 | 103 | ;; (defn gstr [] 104 | ;; (str "g__" (swap! basis inc))) 105 | 106 | ;; (defn bigmap [n] 107 | ;; (reduce merge 108 | ;; (take (* 100 n) 109 | ;; (repeatedly #(reduce 110 | ;; (fn [xs k] {k xs}) 111 | ;; (take (* 10 n) (repeatedly gstr))))))) 112 | 113 | ;; (def bm1 (bigmap 3)) 114 | 115 | ;; (reset! basis 0) 116 | 117 | ;; (def bm2 (bigmap 3)) 118 | 119 | ;; (time 120 | ;; (dotimes [_ 10] 121 | ;; (println (= bm1 bm2)))) 122 | 123 | 124 | (println "Done.") 125 | --------------------------------------------------------------------------------