[Git][clojure-team/fast-zip-clojure][upstream] New upstream version 0.7.0
Jérôme Charaoui (@lavamind)
gitlab at salsa.debian.org
Fri Jul 1 20:56:58 BST 2022
Jérôme Charaoui pushed to branch upstream at Debian Clojure Maintainers / fast-zip-clojure
Commits:
ba7c4463 by Jérôme Charaoui at 2022-07-01T15:36:48-04:00
New upstream version 0.7.0
- - - - -
10 changed files:
- BENCHMARKS.md
- CHANGES.md
- README.md
- benchmarks/fast_zip/core_bench.clj
- benchmarks/fast_zip/core_bench.cljs
- project.clj
- − src/clj/fast_zip/core.clj
- src/cljs/fast_zip/core.cljs → src/fast_zip/core.cljc
- − test/cljs/fast_zip/core_test.cljs
- test/clj/fast_zip/core_test.clj → test/fast_zip/core_test.cljc
Changes:
=====================================
BENCHMARKS.md
=====================================
@@ -1,5 +1,247 @@
# Benchmark History
+## 0.7.0
+
+Run on a Late 2012 Mac mini witha 2.6 GHZ core i7, osx 10.10.5 and java 1.8.0_45-b14.
+
+### ClojureScript
+
+ Benchmark: vector zip walk...
+ :clojure.zip.walk x 209 ops/sec ±0.68% (91 runs sampled)
+ :fast-zip.walk x 695 ops/sec ±1.03% (94 runs sampled)
+ Fastest is :fast-zip.walk
+ Benchmark: vector zip edit...
+ :clojure.zip.edit x 116 ops/sec ±1.08% (77 runs sampled)
+ :fast-zip.edit x 266 ops/sec ±0.69% (93 runs sampled)
+ Fastest is :fast-zip.edit
+
+### Clojure
+
+ WARNING: Final GC required 1.1305691949835102 % of runtime
+ Goal: Benchmark vector zip walk.
+ -----
+ Case: :clojure.zip
+ Evaluation count : 51360 in 60 samples of 856 calls.
+ Execution time mean : 1.206185 ms
+ Execution time std-deviation : 29.527194 µs
+ Execution time lower quantile : 1.179620 ms ( 2.5%)
+ Execution time upper quantile : 1.239860 ms (97.5%)
+ Overhead used : 1.809668 ns
+
+ Found 3 outliers in 60 samples (5.0000 %)
+ low-severe 2 (3.3333 %)
+ low-mild 1 (1.6667 %)
+ Variance from outliers : 12.5608 % Variance is moderately inflated by outliers
+
+ Case: :fast-zip
+ Evaluation count : 554760 in 60 samples of 9246 calls.
+ Execution time mean : 108.874189 µs
+ Execution time std-deviation : 1.450027 µs
+ Execution time lower quantile : 106.084605 µs ( 2.5%)
+ Execution time upper quantile : 112.005702 µs (97.5%)
+ Overhead used : 1.809668 ns
+
+ Goal: Benchmark vector zip edit.
+ -----
+ Case: :clojure.zip
+ Evaluation count : 12660 in 60 samples of 211 calls.
+ Execution time mean : 5.047109 ms
+ Execution time std-deviation : 99.896647 µs
+ Execution time lower quantile : 4.918917 ms ( 2.5%)
+ Execution time upper quantile : 5.292446 ms (97.5%)
+ Overhead used : 1.809668 ns
+
+ Found 2 outliers in 60 samples (3.3333 %)
+ low-severe 2 (3.3333 %)
+ Variance from outliers : 7.8717 % Variance is slightly inflated by outliers
+
+ Case: :fast-zip
+ Evaluation count : 112260 in 60 samples of 1871 calls.
+ Execution time mean : 536.307234 µs
+ Execution time std-deviation : 6.423185 µs
+ Execution time lower quantile : 521.727835 µs ( 2.5%)
+ Execution time upper quantile : 545.561598 µs (97.5%)
+ Overhead used : 1.809668 ns
+
+## 0.6.1
+
+Run on a MBP2010 with a 2.66ghz core i7, osx 10.8.5 and java 1.8.0_25-b17.
+
+### ClojureScript
+
+ Benchmark: vector zip walk...
+ :clojure.zip.walk x 93.01 ops/sec ±5.02% (73 runs sampled)
+ :fast-zip.walk x 586 ops/sec ±1.26% (89 runs sampled)
+ Fastest is :fast-zip.walk
+ Benchmark: vector zip edit...
+ :clojure.zip.edit x 41.74 ops/sec ±1.45% (57 runs sampled)
+ :fast-zip.edit x 114 ops/sec ±1.41% (74 runs sampled)
+ Fastest is :fast-zip.edit
+
+### Clojure
+
+ WARNING: Final GC required 3.090076669784014 % of runtime
+ Goal: Benchmark vector zip edit.
+ -----
+ Case: :fast-zip
+ Evaluation count : 107640 in 60 samples of 1794 calls.
+ Execution time mean : 576.321696 µs
+ Execution time std-deviation : 57.513398 µs
+ Execution time lower quantile : 526.397688 µs ( 2.5%)
+ Execution time upper quantile : 713.719117 µs (97.5%)
+ Overhead used : 2.121629 ns
+
+ Found 2 outliers in 60 samples (3.3333 %)
+ low-severe 1 (1.6667 %)
+ low-mild 1 (1.6667 %)
+ Variance from outliers : 70.3236 % Variance is severely inflated by outliers
+
+ Case: :clojure.zip
+ Evaluation count : 34500 in 60 samples of 575 calls.
+ Execution time mean : 1.819284 ms
+ Execution time std-deviation : 163.955858 µs
+ Execution time lower quantile : 1.696950 ms ( 2.5%)
+ Execution time upper quantile : 2.178507 ms (97.5%)
+ Overhead used : 2.121629 ns
+
+ Found 6 outliers in 60 samples (10.0000 %)
+ low-severe 4 (6.6667 %)
+ low-mild 2 (3.3333 %)
+ Variance from outliers : 65.2416 % Variance is severely inflated by outliers
+
+ Goal: Benchmark vector zip walk.
+ -----
+ Case: :fast-zip
+ Evaluation count : 592080 in 60 samples of 9868 calls.
+ Execution time mean : 102.383653 µs
+ Execution time std-deviation : 1.349685 µs
+ Execution time lower quantile : 100.804221 µs ( 2.5%)
+ Execution time upper quantile : 106.239075 µs (97.5%)
+ Overhead used : 2.121629 ns
+
+ Found 4 outliers in 60 samples (6.6667 %)
+ low-severe 3 (5.0000 %)
+ low-mild 1 (1.6667 %)
+ Variance from outliers : 1.6389 % Variance is slightly inflated by outliers
+
+ Case: :clojure.zip
+ Evaluation count : 54240 in 60 samples of 904 calls.
+ Execution time mean : 1.152677 ms
+ Execution time std-deviation : 98.687775 µs
+ Execution time lower quantile : 1.078808 ms ( 2.5%)
+ Execution time upper quantile : 1.423912 ms (97.5%)
+ Overhead used : 2.121629 ns
+
+ Found 8 outliers in 60 samples (13.3333 %)
+ low-severe 5 (8.3333 %)
+ low-mild 3 (5.0000 %)
+ Variance from outliers : 61.9083 % Variance is severely inflated by outliers
+
+## 0.6.0
+
+Added new benchmarks for node editing. Existing/previous benchmark goal now named as "vector zip walk"...
+
+Run on a MBP2010 with a 2.66ghz core i7, osx 10.8.5 and java 1.8.0_25-b17.
+
+### ClojureScript
+
+ Benchmark: vector zip walk...
+ :clojure.zip.walk x 69.52 ops/sec ±3.58% (67 runs sampled)
+ :fast-zip.walk x 394 ops/sec ±1.88% (89 runs sampled)
+ Fastest is :fast-zip
+ Benchmark: vector zip edit...
+ :clojure.zip.edit x 33.89 ops/sec ±2.66% (61 runs sampled)
+ :fast-zip.edit x 89.38 ops/sec ±2.13% (78 runs sampled)
+ Fastest is :fast-zip.edit
+
+### Clojure
+
+ WARNING: Final GC required 2.904199000536039 % of runtime
+ Goal: Benchmark vector zip edit.
+ -----
+ Case: :fast-zip
+ Evaluation count : 96600 in 60 samples of 1610 calls.
+ Execution time mean : 613.696756 µs
+ Execution time std-deviation : 23.370402 µs
+ Execution time lower quantile : 588.826153 µs ( 2.5%)
+ Execution time upper quantile : 687.558243 µs (97.5%)
+ Overhead used : 2.997006 ns
+
+ Found 3 outliers in 60 samples (5.0000 %)
+ low-severe 3 (5.0000 %)
+ Variance from outliers : 23.8777 % Variance is moderately inflated by outliers
+
+ Case: :clojure.zip
+ Evaluation count : 27420 in 60 samples of 457 calls.
+ Execution time mean : 2.143100 ms
+ Execution time std-deviation : 55.341182 µs
+ Execution time lower quantile : 2.046640 ms ( 2.5%)
+ Execution time upper quantile : 2.248948 ms (97.5%)
+ Overhead used : 2.997006 ns
+
+ Goal: Benchmark vector zip walk.
+ -----
+ Case: :fast-zip
+ Evaluation count : 578700 in 60 samples of 9645 calls.
+ Execution time mean : 106.602340 µs
+ Execution time std-deviation : 3.705304 µs
+ Execution time lower quantile : 101.726377 µs ( 2.5%)
+ Execution time upper quantile : 117.508157 µs (97.5%)
+ Overhead used : 2.997006 ns
+
+ Found 5 outliers in 60 samples (8.3333 %)
+ low-severe 2 (3.3333 %)
+ low-mild 3 (5.0000 %)
+ Variance from outliers : 20.6548 % Variance is moderately inflated by outliers
+
+ Case: :clojure.zip
+ Evaluation count : 46020 in 60 samples of 767 calls.
+ Execution time mean : 1.326133 ms
+ Execution time std-deviation : 32.156029 µs
+ Execution time lower quantile : 1.262908 ms ( 2.5%)
+ Execution time upper quantile : 1.387965 ms (97.5%)
+ Overhead used : 2.997006 ns
+
+ Found 1 outliers in 60 samples (1.6667 %)
+ low-severe 1 (1.6667 %)
+ Variance from outliers : 12.5459 % Variance is moderately inflated by outliers
+
+## 0.5.1
+
+Run on a mac mini with a 2.6ghz core i7, osx 10.9.5, node.js 0.10.31,
+and java 1.7.0_51. ClojureScript uses simple optimization.
+
+### ClojureScript
+
+ :clojure.zip x 114 ops/sec ±0.64% (85 runs sampled)
+ :fast-zip x 197 ops/sec ±0.62% (88 runs sampled)
+ Fastest is :fast-zip
+
+### Clojure
+
+ ======================
+ WARNING: Final GC required 1.352547229118579 % of runtime
+ Goal: Benchmark vector zip.
+ -----
+ Case: :clojure.zip
+ Evaluation count : 58260 in 60 samples of 971 calls.
+ Execution time mean : 1.049589 ms
+ Execution time std-deviation : 17.962641 µs
+ Execution time lower quantile : 1.018927 ms ( 2.5%)
+ Execution time upper quantile : 1.082843 ms (97.5%)
+ Overhead used : 1.896478 ns
+
+ Case: :fast-zip
+ Evaluation count : 326400 in 60 samples of 5440 calls.
+ Execution time mean : 185.443364 µs
+ Execution time std-deviation : 2.938738 µs
+ Execution time lower quantile : 181.131376 µs ( 2.5%)
+ Execution time upper quantile : 192.279133 µs (97.5%)
+ Overhead used : 1.896478 ns
+
+ Found 2 outliers in 60 samples (3.3333 %)
+ low-severe 2 (3.3333 %)
+ Variance from outliers : 1.6389 % Variance is slightly inflated by outliers
## 0.5.0
@@ -7,11 +249,13 @@ Run on a mac mini with a 2.6ghz core i7, osx 10.9.5, node.js 0.10.31,
and java 1.7.0_51. ClojureScript uses simple optimization.
### ClojureScript
+
:clojure.zip x 116 ops/sec ±0.65% (83 runs sampled)
:fast-zip x 194 ops/sec ±0.85% (92 runs sampled)
Fastest is :fast-zip
### Clojure
+
======================
WARNING: Final GC required 1.467359386689346 % of runtime
Goal: Benchmark vector zip.
@@ -93,4 +337,4 @@ Run on a mac mini with a 2.6ghz core i7 and osx version 10.9.1.
Found 1 outliers in 60 samples (1.6667 %)
low-severe 1 (1.6667 %)
- Variance from outliers : 1.6389 % Variance is slightly inflated by outliers
\ No newline at end of file
+ Variance from outliers : 1.6389 % Variance is slightly inflated by outliers
=====================================
CHANGES.md
=====================================
@@ -1,5 +1,29 @@
# Release History
+## 0.7.0
+
+* Replace CLJX sources with CLJC (reader conditionals)
+* Update CLJ & CLJS dependencies (1.7.x)
+* Remove Piggieback & Austin dev dependencies
+
+## 0.6.1
+
+* Add ZipperOps deftype to minimize copying effort for new ZipperLocation instances
+
+## 0.6.0
+
+* Switch CLJ version to `deftype` implementation for further 2x speedup
+* Refactor project as CLJX setup (to avoid/minimize code duplication)
+* Update benchmark setup for both CLJ & CLJS, add benchmarks
+
+## 0.5.2
+
+* Bug fix for leftmost.
+
+## 0.5.1
+
+* Avoid redundant calls to up internally.
+
## 0.5.0
* ClojureScript support thanks to Joel Holdbrooks.
@@ -12,4 +36,4 @@
## 0.3.0
-* Initial version.
\ No newline at end of file
+* Initial version.
=====================================
README.md
=====================================
@@ -1,60 +1,119 @@
# fast-zip
-A modified version of clojure.zip that uses records internally.
+A modified version of [clojure.zip](http://clojuredocs.org/clojure.zip) that
+uses `deftype` internally and is written in CLJX format.
## Usage
+For Clojure 1.7 use:
+
```clojure
-[fast-zip "0.5.0"]
+[fast-zip "0.7.0"]
```
-This is a drop in replacement for clojure.zip. Simply require ``fast-zip.core``
-instead of ``clojure.zip``.
+For previous versions use:
+
+```clojure
+[fast-zip "0.6.1"]
+```
+
+This is a drop in replacement for clojure.zip. Simply require `fast-zip.core`
+instead of `clojure.zip`.
## Benchmark
-The below traverses a vector zip with three levels and sums the numbers. To
-run, use ``lein perforate``.
+Since 0.6.1 a benchmark run consists of two analysis goals:
+
+1. "walk" traverses a vector zip of three levels of ints and sums the numbers (reduction over leaves)
+2. "edit" same setup as for "walk", but actually edits each leaf `(* n 10)` and applies all changes at the end
+
+The current snapshot version of this lib is roughly twice as fast as the 0.5.2 release...
- ======================
- WARNING: Final GC required 1.450308932831415 % of runtime
- Goal: Benchmark vector zip.
+[Historical benchmarks for each version](BENCHMARKS.md)
+
+### Clojure
+
+To run, use `lein perforate`.
+
+ WARNING: Final GC required 2.904199000536039 % of runtime
+ Goal: Benchmark vector zip edit.
-----
Case: :fast-zip
- Evaluation count : 246120 in 60 samples of 4102 calls.
- Execution time mean : 242.777689 µs
- Execution time std-deviation : 1.965914 µs
- Execution time lower quantile : 238.996103 µs ( 2.5%)
- Execution time upper quantile : 247.075613 µs (97.5%)
- Overhead used : 1.947263 ns
+ Evaluation count : 96600 in 60 samples of 1610 calls.
+ Execution time mean : 613.696756 µs
+ Execution time std-deviation : 23.370402 µs
+ Execution time lower quantile : 588.826153 µs ( 2.5%)
+ Execution time upper quantile : 687.558243 µs (97.5%)
+ Overhead used : 2.997006 ns
- Found 2 outliers in 60 samples (3.3333 %)
- low-severe 2 (3.3333 %)
- Variance from outliers : 1.6389 % Variance is slightly inflated by outliers
+ Found 3 outliers in 60 samples (5.0000 %)
+ low-severe 3 (5.0000 %)
+ Variance from outliers : 23.8777 % Variance is moderately inflated by outliers
Case: :clojure.zip
- Evaluation count : 62820 in 60 samples of 1047 calls.
- Execution time mean : 960.326181 µs
- Execution time std-deviation : 4.915537 µs
- Execution time lower quantile : 950.592132 µs ( 2.5%)
- Execution time upper quantile : 969.813479 µs (97.5%)
- Overhead used : 1.947263 ns
+ Evaluation count : 27420 in 60 samples of 457 calls.
+ Execution time mean : 2.143100 ms
+ Execution time std-deviation : 55.341182 µs
+ Execution time lower quantile : 2.046640 ms ( 2.5%)
+ Execution time upper quantile : 2.248948 ms (97.5%)
+ Overhead used : 2.997006 ns
+
+ Goal: Benchmark vector zip walk.
+ -----
+ Case: :fast-zip
+ Evaluation count : 578700 in 60 samples of 9645 calls.
+ Execution time mean : 106.602340 µs
+ Execution time std-deviation : 3.705304 µs
+ Execution time lower quantile : 101.726377 µs ( 2.5%)
+ Execution time upper quantile : 117.508157 µs (97.5%)
+ Overhead used : 2.997006 ns
+
+ Found 5 outliers in 60 samples (8.3333 %)
+ low-severe 2 (3.3333 %)
+ low-mild 3 (5.0000 %)
+ Variance from outliers : 20.6548 % Variance is moderately inflated by outliers
-For the clojurescript version, make sure you have node.js installed along
-with the ``benchmark`` module. Then use ``lein clean-bench``
+ Case: :clojure.zip
+ Evaluation count : 46020 in 60 samples of 767 calls.
+ Execution time mean : 1.326133 ms
+ Execution time std-deviation : 32.156029 µs
+ Execution time lower quantile : 1.262908 ms ( 2.5%)
+ Execution time upper quantile : 1.387965 ms (97.5%)
+ Overhead used : 2.997006 ns
+
+ Found 1 outliers in 60 samples (1.6667 %)
+ low-severe 1 (1.6667 %)
+ Variance from outliers : 12.5459 % Variance is moderately inflated by outliers
+
+### ClojureScript
+
+For the clojurescript version, make sure you have node.js installed
+along with the [benchmark](https://www.npmjs.com/package/benchmark)
+NPM module. Then use `lein clean-bench`
+
+ Benchmark: vector zip walk...
+ :clojure.zip.walk x 69.52 ops/sec ±3.58% (67 runs sampled)
+ :fast-zip.walk x 394 ops/sec ±1.88% (89 runs sampled)
+ Fastest is :fast-zip
+ Benchmark: vector zip edit...
+ :clojure.zip.edit x 33.89 ops/sec ±2.66% (61 runs sampled)
+ :fast-zip.edit x 89.38 ops/sec ±2.13% (78 runs sampled)
+ Fastest is :fast-zip.edit
## TODO
* Create benchmarks that represent more functionality and different use
- cases.
+ cases (in progress)
-## Thanks
+## Contributors
Thanks to
* Brandon Bloom for his advice.
* Zach Tellman
* Joel Holdbrooks for the ClojureScript version.
+* David Thomas Hume
+* Karsten Schmidt (CLJX restructure, cljc restructure, deftype impl & benchmark updates)
## License
=====================================
benchmarks/fast_zip/core_bench.clj
=====================================
@@ -8,45 +8,32 @@
(def big-vec (vec (repeat 10 (vec (repeat 10 (vec (range 10)))))))
-(defn zip-test1
- []
- (loop [i 0, loc (z/vector-zip big-vec)]
- (if (z/end? loc)
+(defn zip-walk
+ [zipper node next end?]
+ (loop [i 0, loc zipper]
+ (if (end? loc)
i
- (recur (long (if (integer? (z/node loc)) (unchecked-add-int i (z/node loc)) i)) (z/next loc)))))
+ (recur (long (if (integer? (node loc)) (unchecked-add-int i (node loc)) i)) (next loc)))))
-(defn zip-test2
- []
- (loop [i 0, loc (fz/vector-zip big-vec)]
- (if (fz/end? loc)
- i
- (recur (long (if (integer? (fz/node loc)) (unchecked-add-int i (fz/node loc)) i)) (fz/next loc)))))
-
-(defgoal vector-zip-bench "Benchmark vector zip.")
-
-(defcase vector-zip-bench :clojure.zip
- [] (zip-test1))
-
-(defcase vector-zip-bench :fast-zip
- [] (zip-test2))
-
-;; 0.3.0
-;Goal: Benchmark vector zip.
-;-----
-;Case: :clojure.zip
-;Evaluation count : 68400 in 60 samples of 1140 calls.
-;Execution time mean : 879.080906 µs
-;Execution time std-deviation : 11.090444 µs
-;Execution time lower quantile : 864.859649 µs ( 2.5%)
-;Execution time upper quantile : 907.783816 µs (97.5%)
-;
-;Found 3 outliers in 60 samples (5.0000 %)
-;low-severe 3 (5.0000 %)
-;Variance from outliers : 1.6389 % Variance is slightly inflated by outliers
-;
-;Case: :fast-zip
-;Evaluation count : 226980 in 60 samples of 3783 calls.
-;Execution time mean : 259.947207 µs
-;Execution time std-deviation : 3.051484 µs
-;Execution time lower quantile : 255.424266 µs ( 2.5%)
-;Execution time upper quantile : 266.486446 µs (97.5%)
\ No newline at end of file
+(defn zip-edit
+ [zipper root node edit next end?]
+ (loop [loc zipper]
+ (if (end? loc)
+ (root loc)
+ (recur (next (if (integer? (node loc)) (edit loc * 10) loc))))))
+
+(defgoal vector-zip-walk-bench "Benchmark vector zip walk.")
+
+(defcase vector-zip-walk-bench :clojure.zip
+ [] (zip-walk (z/vector-zip big-vec) z/node z/next z/end?))
+
+(defcase vector-zip-walk-bench :fast-zip
+ [] (zip-walk (fz/vector-zip big-vec) fz/node fz/next fz/end?))
+
+(defgoal vector-zip-edit-bench "Benchmark vector zip edit.")
+
+(defcase vector-zip-edit-bench :clojure.zip
+ [] (zip-edit (z/vector-zip big-vec) z/root z/node z/edit z/next z/end?))
+
+(defcase vector-zip-edit-bench :fast-zip
+ [] (zip-edit (fz/vector-zip big-vec) fz/root fz/node fz/edit fz/next fz/end?))
=====================================
benchmarks/fast_zip/core_bench.cljs
=====================================
@@ -1,51 +1,67 @@
(ns fast-zip.core-bench
(:require
- [fast-zip.core :as fz]
- [clojure.zip :as z]
- [cljs.nodejs :as nodejs]))
+ [fast-zip.core :as fz]
+ [clojure.zip :as z]
+ [cljs.nodejs :as nodejs]))
(def Benchmark
(nodejs/require "benchmark"))
(def big-vec (vec (repeat 10 (vec (repeat 10 (vec (range 10)))))))
-(defn zip-test1
- []
- (loop [i 0, loc (z/vector-zip big-vec)]
- (if (z/end? loc)
+(defn zip-walk
+ [zipper node next end?]
+ (loop [i 0, loc zipper]
+ (if (end? loc)
i
- (recur (long (if (integer? (z/node loc)) (unchecked-add-int i (z/node loc)) i)) (z/next loc)))))
+ (recur (long (if (integer? (node loc)) (unchecked-add-int i (node loc)) i)) (next loc)))))
-(defn zip-test2
- []
- (loop [i 0, loc (fz/vector-zip big-vec)]
- (if (fz/end? loc)
- i
- (recur (long (if (integer? (fz/node loc)) (unchecked-add-int i (fz/node loc)) i)) (fz/next loc)))))
+(defn zip-edit
+ [zipper root node edit next end?]
+ (loop [loc zipper]
+ (if (end? loc)
+ (root loc)
+ (recur (next (if (integer? (node loc)) (edit loc * 10) loc))))))
-(def suite
+(defn make-benchmark
+ [id clj fz]
(.. (.Suite Benchmark)
- (add ":clojure.zip" zip-test1)
- (add ":fast-zip" zip-test2)
- (on "cycle"
- (fn [e]
- (.log js/console (js/String (.-target e)))))
- (on "complete"
- (fn [e]
- (this-as *this*
- (let [fastest (-> *this*
- (.filter "fastest")
- (.pluck "name")
- (aget 0))]
- (.log js/console "Fastest is" fastest)))))))
-
-(do
- (.log js/console "Benchmark vector zip.")
- (.run suite)
+ (add (str ":clojure.zip." id) clj)
+ (add (str ":fast-zip." id) fz)
+ (on "cycle" (fn [e] (.log js/console (js/String (.-target e)))))
+ (on "complete"
+ (fn [e]
+ (this-as
+ *this*
+ (let [fastest (-> *this*
+ (.filter "fastest")
+ (.pluck "name")
+ (aget 0))]
+ (.log js/console "Fastest is" fastest)))))))
+
+(def bench-walk
+ (make-benchmark
+ "walk"
+ #(zip-walk (z/vector-zip big-vec) z/node z/next z/end?)
+ #(zip-walk (fz/vector-zip big-vec) fz/node fz/next fz/end?)))
+
+(def bench-edit
+ (make-benchmark
+ "edit"
+ #(zip-edit (z/vector-zip big-vec) z/root z/node z/edit z/next z/end?)
+ #(zip-edit (fz/vector-zip big-vec) fz/root fz/node fz/edit fz/next fz/end?)))
+
+(defn main
+ []
+ (.log js/console "Benchmark: vector zip walk...")
+ (.run bench-walk)
+ (.log js/console "Benchmark: vector zip edit...")
+ (.run bench-edit)
(.exit js/process))
+(set! *main-cli-fn* main)
+
;; Benchmark vector zip.
;; :clojure.zip x 95.20 ops/sec ±1.75% (81 runs sampled)
;; :fast-zip x 222 ops/sec ±0.88% (90 runs sampled)
;; Fastest is :fast-zip
-
=====================================
project.clj
=====================================
@@ -1,44 +1,33 @@
-(defproject fast-zip "0.5.0"
+(defproject fast-zip "0.7.0"
:description "A modification of clojure.zip that uses protocols and records."
:url "https://github.com/akhudek/fast-zip"
:license {:name "Eclipse Public License"
:url "http://www.eclipse.org/legal/epl-v10.html"}
- :dependencies [[org.clojure/clojure "1.6.0" :scope "provided"]
- [org.clojure/clojurescript "0.0-2311" :scope "provided"]]
-
- :plugins [[perforate "0.3.2"]
- [lein-cljsbuild "1.0.3"]
- [com.cemerick/clojurescript.test "0.3.1"]]
-
- :source-paths
- ["src/clj" "src/cljs"]
-
- :test-paths
- ["test/clj" "test/cljs"]
+ :dependencies [[org.clojure/clojure "1.7.0" :scope "provided"]
+ [org.clojure/clojurescript "1.7.107" :scope "provided"]]
;; Prevent lein from disabling jvm optimizations.
- :jvm-opts ^:replace ["-server"]
+ :jvm-opts ^:replace []
:profiles {:dev
{:dependencies
- [[perforate "0.3.3"]
- [criterium "0.4.3"]
- [org.bodil/cljs-noderepl "0.1.11"]
- [com.cemerick/piggieback "0.1.3"]]
+ [[perforate "0.3.4"]
+ [criterium "0.4.3"]]
+ :plugins
+ [[perforate "0.3.4"]
+ [lein-npm "0.6.1"]
+ [lein-cljsbuild "1.0.6"]
+ [com.cemerick/clojurescript.test "0.3.3"]]
:node-dependencies
[benchmark "1.0.0"]
- :plugins
- [[lein-npm "0.4.0"]
- [com.cemerick/austin "0.1.5"]]
:aliases
{"clean-test" ~(clojure.string/split
- "do test, cljsbuild clean, cljsbuild test"
+ "do clean, test, cljsbuild test"
#" ")
"clean-bench" ~(clojure.string/split
- "do cljsbuild clean, cljsbuild once bench"
- #" ")}
- :repl-options {:nrepl-middleware [cemerick.piggieback/wrap-cljs-repl]}}}
+ "do clean, cljsbuild once bench"
+ #" ")}}}
:perforate {:environments [{:namespaces [fast-zip.core-bench]}]}
@@ -50,12 +39,12 @@
:cljsbuild
{:builds [{:id "test"
- :source-paths ["src/cljs" "test/cljs"]
+ :source-paths ["src" "test"]
:compiler {:output-to "target/cljs/testable.js"
:optimizations :whitespace
:pretty-print true}}
{:id "bench"
- :source-paths ["src/cljs" "benchmarks"]
+ :source-paths ["src" "benchmarks"]
:notify-command ["node" "target/cljs/benchmark.js"]
:compiler {:target :nodejs
:output-to "target/cljs/benchmark.js"
=====================================
src/clj/fast_zip/core.clj deleted
=====================================
@@ -1,298 +0,0 @@
-; Copyright (c) Rich Hickey. All rights reserved.
-; The use and distribution terms for this software are covered by the
-; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
-; which can be found in the file epl-v10.html at the root of this distribution.
-; By using this software in any fashion, you are agreeing to be bound by
-; the terms of this license.
-; You must not remove this notice, or any other, from this software.
-
-;functional hierarchical zipper, with navigation, editing and enumeration
-;see Huet
-
-(ns ^{:doc "Functional hierarchical zipper, with navigation, editing,
- and enumeration. See Huet"
- :author "Rich Hickey, modified by Alexander K. Hudek"}
- fast-zip.core
- (:refer-clojure :exclude (replace remove next)))
-
-(defrecord ZipperPath [l r ppath pnodes changed?])
-
-(defrecord ZipperLocation [branch? children make-node node path])
-
-(defn zipper
- "Creates a new zipper structure.
-
- branch? is a fn that, given a node, returns true if can have
- children, even if it currently doesn't.
-
- children is a fn that, given a branch node, returns a seq of its
- children.
-
- make-node is a fn that, given an existing node and a seq of
- children, returns a new branch node with the supplied children.
- root is the root node."
- {:added "1.0"}
- [branch? children make-node root]
- (ZipperLocation. branch? children make-node root nil))
-
-(defn seq-zip
- "Returns a zipper for nested sequences, given a root sequence"
- {:added "1.0"}
- [root]
- (zipper seq?
- identity
- (fn [node children] (with-meta children (meta node)))
- root))
-
-(defn vector-zip
- "Returns a zipper for nested vectors, given a root vector"
- {:added "1.0"}
- [root]
- (zipper
- vector?
- seq
- (fn [node children] (with-meta (vec children) (meta node)))
- root))
-
-(defn xml-zip
- "Returns a zipper for xml elements (as from xml/parse),
- given a root element"
- {:added "1.0"}
- [root]
- (zipper (complement string?)
- (comp seq :content)
- (fn [node children]
- (assoc node :content (and children (apply vector children))))
- root))
-
-(defn node
- "Returns the node at loc"
- [^ZipperLocation loc]
- (.node loc))
-
-(defn branch?
- "Returns true if the node at loc is a branch"
- [^ZipperLocation loc]
- ((.branch? loc) (.node loc)))
-
-(defn children
- "Returns a seq of the children of node at loc, which must be a branch"
- [^ZipperLocation loc]
- ((.children loc) (.node loc)))
-
-(defn make-node
- "Returns a new branch node, given an existing node and new children.
- The loc is only used to supply the constructor."
- [^ZipperLocation loc node children]
- ((.make-node loc) node children))
-
-(defn path
- "Returns a seq of nodes leading to this loc"
- [^ZipperLocation loc]
- (if-let [p (.path loc)] (.pnodes ^ZipperPath p)))
-
-(defn lefts
- "Returns a seq of the left siblings of this loc"
- [^ZipperLocation loc]
- (if-let [p (.path loc)] (seq (reverse (.l ^ZipperPath p)))))
-
-(defn rights
- "Returns a seq of the right siblings of this loc"
- [^ZipperLocation loc]
- (if-let [p (.path loc)] (.r ^ZipperPath p)))
-
-(defn down
- "Returns the loc of the leftmost child of the node at this loc,
- or nil if no children"
- [^ZipperLocation loc]
- (when (branch? loc)
- (when-let [cs (children loc)]
- (let [node (.node loc), path ^ZipperPath (.path loc)]
- (ZipperLocation.
- (.branch? loc)
- (.children loc)
- (.make-node loc)
- (first cs)
- (ZipperPath. '() (clojure.core/next cs) path (if path (conj (.pnodes path) node) [node]) nil))))))
-
-(defn up
- "Returns the loc of the parent of the node at this loc, or nil if at the top"
- [^ZipperLocation loc]
- (let [node (.node loc), path ^ZipperPath (.path loc)]
- (when-let [pnodes (and path (.pnodes path))]
- (let [pnode (peek pnodes)]
- (if (.changed? path)
- (ZipperLocation.
- (.branch? loc)
- (.children loc)
- (.make-node loc)
- (make-node loc pnode (concat (reverse (.l path)) (cons node (.r path))))
- (if-let [ppath (.ppath path)] (assoc ppath :changed? true)))
- (ZipperLocation.
- (.branch? loc)
- (.children loc)
- (.make-node loc)
- pnode
- (.ppath path)))))))
-
-(defn root
- "zips all the way up and returns the root node, reflecting any changes."
- [^ZipperLocation loc]
- (if (identical? :end (.path loc))
- (.node loc)
- (let [p (up loc)]
- (if p
- (recur p)
- (.node loc)))))
-
-(defn right
- "Returns the loc of the right sibling of the node at this loc, or nil"
- [^ZipperLocation loc]
- (let [path ^ZipperPath (.path loc)]
- (when-let [r (and path (.r path))]
- (ZipperLocation.
- (.branch? loc)
- (.children loc)
- (.make-node loc)
- (first r)
- (assoc path :l (conj (.l path) (.node loc)) :r (clojure.core/next r))))))
-
-(defn rightmost
- "Returns the loc of the rightmost sibling of the node at this loc, or self"
- [^ZipperLocation loc]
- (let [path ^ZipperPath (.path loc)]
- (if-let [r (and path (.r path))]
- (ZipperLocation.
- (.branch? loc)
- (.children loc)
- (.make-node loc)
- (last r)
- (assoc path :l (apply conj (.l path) (.node loc) (butlast r)) :r nil))
- loc)))
-
-(defn left
- "Returns the loc of the left sibling of the node at this loc, or nil"
- [^ZipperLocation loc]
- (let [path ^ZipperPath (.path loc)]
- (when (and path (seq (.l path)))
- (ZipperLocation.
- (.branch? loc)
- (.children loc)
- (.make-node loc)
- (peek (.l path))
- (assoc path :l (pop (.l path)) :r (cons (.node loc) (.r path)))))))
-
-(defn leftmost
- "Returns the loc of the leftmost sibling of the node at this loc, or self"
- [^ZipperLocation loc]
- (let [path ^ZipperPath (.path loc)]
- (if (and path (seq (.l path)))
- (ZipperLocation.
- (.branch? loc)
- (.children loc)
- (.make-node loc)
- (peek (.l path))
- (assoc path :l [] :r (concat (clojure.core/next (reverse (.l path))) [(.node loc)] (.r path))))
- loc)))
-
-(defn insert-left
- "Inserts the item as the left sibling of the node at this loc, without moving"
- [^ZipperLocation loc item]
- (if-let [path ^ZipperPath (.path loc)]
- (ZipperLocation.
- (.branch? loc)
- (.children loc)
- (.make-node loc)
- (.node loc)
- (assoc path :l (conj (.l path) item) :changed? true))
- (throw (new Exception "Insert at top"))))
-
-(defn insert-right
- "Inserts the item as the right sibling of the node at this loc, without moving"
- [^ZipperLocation loc item]
- (if-let [path ^ZipperPath (.path loc)]
- (ZipperLocation.
- (.branch? loc)
- (.children loc)
- (.make-node loc)
- (.node loc)
- (assoc path :r (cons item (.r path)) :changed? true))
- (throw (new Exception "Insert at top"))))
-
-(defn replace
- "Replaces the node at this loc, without moving"
- [^ZipperLocation loc node]
- (ZipperLocation.
- (.branch? loc)
- (.children loc)
- (.make-node loc)
- node
- (if-let [path (.path loc)] (assoc path :changed? true))))
-
-(defn insert-child
- "Inserts the item as the leftmost child of the node at this loc, without moving"
- [^ZipperLocation loc item]
- (replace loc (make-node loc (.node loc) (cons item (children loc)))))
-
-(defn append-child
- "Inserts the item as the rightmost child of the node at this loc, without moving"
- [^ZipperLocation loc item]
- (replace loc (make-node loc (.node loc) (concat (children loc) [item]))))
-
-(defn next
- "Moves to the next loc in the hierarchy, depth-first. When reaching
- the end, returns a distinguished loc detectable via end?. If already
- at the end, stays there."
- [^ZipperLocation loc]
- (let [path (.path loc)]
- (if (identical? :end path)
- loc
- (or
- (and (branch? loc) (down loc))
- (right loc)
- (loop [p loc]
- (if (up p)
- (or (right (up p)) (recur (up p)))
- (ZipperLocation. (.branch? loc) (.children loc) (.make-node loc) (.node p) :end)))))))
-
-(defn prev
- "Moves to the previous loc in the hierarchy, depth-first. If already at the root, returns nil."
- [loc]
- (if-let [lloc (left loc)]
- (loop [loc lloc]
- (if-let [child (and (branch? loc) (down loc))]
- (recur (rightmost child))
- loc))
- (up loc)))
-
-(defn end?
- "Returns true if loc represents the end of a depth-first walk"
- [^ZipperLocation loc]
- (identical? :end (.path loc)))
-
-(defn remove
- "Removes the node at loc, returning the loc that would have preceded it in a depth-first walk."
- [^ZipperLocation loc]
- (if-let [path ^ZipperPath (.path loc)]
- (if (pos? (count (.l path)))
- (loop [loc (ZipperLocation.
- (.branch? loc)
- (.children loc)
- (.make-node loc)
- (peek (.l path))
- (assoc path :l (pop (.l path)) :changed? true))]
- (if-let [child (and (branch? loc) (down loc))]
- (recur (rightmost child))
- loc))
- (ZipperLocation.
- (.branch? loc)
- (.children loc)
- (.make-node loc)
- (make-node loc (peek (.pnodes path)) (.r path))
- (if-let [ppath (.ppath path)] (and ppath (assoc ppath :changed? true)))))
- (throw (new Exception "Remove at top"))))
-
-(defn edit
- "Replaces the node at this loc with the value of (f node args)"
- [^ZipperLocation loc f & args]
- (replace loc (apply f (.node loc) args)))
=====================================
src/cljs/fast_zip/core.cljs → src/fast_zip/core.cljc
=====================================
@@ -1,13 +1,13 @@
-; Copyright (c) Rich Hickey. All rights reserved.
-; The use and distribution terms for this software are covered by the
-; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
-; which can be found in the file epl-v10.html at the root of this distribution.
-; By using this software in any fashion, you are agreeing to be bound by
-; the terms of this license.
-; You must not remove this notice, or any other, from this software.
+;; Copyright (c) Rich Hickey. All rights reserved.
+;; The use and distribution terms for this software are covered by the
+;; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
+;; which can be found in the file epl-v10.html at the root of this distribution.
+;; By using this software in any fashion, you are agreeing to be bound by
+;; the terms of this license.
+;; You must not remove this notice, or any other, from this software.
-;functional hierarchical zipper, with navigation, editing and enumeration
-;see Huet
+;; functional hierarchical zipper, with navigation, editing and enumeration
+;; see Huet
(ns ^{:doc "Functional hierarchical zipper, with navigation, editing,
and enumeration. See Huet"
@@ -15,9 +15,11 @@
fast-zip.core
(:refer-clojure :exclude [replace remove next]))
-(defrecord ZipperPath [l r ppath pnodes changed?])
+(deftype ZipperOps [branch? children make-node])
-(defrecord ZipperLocation [branch? children make-node node path])
+(deftype ZipperPath [l r ppath pnodes changed?])
+
+(deftype ZipperLocation [^ZipperOps ops node ^ZipperPath path])
(defn zipper
"Creates a new zipper structure.
@@ -33,37 +35,39 @@
root is the root node."
{:added "1.0"}
[branch? children make-node root]
- (ZipperLocation. branch? children make-node root nil))
+ (ZipperLocation. (ZipperOps. branch? children make-node) root nil))
(defn seq-zip
"Returns a zipper for nested sequences, given a root sequence"
{:added "1.0"}
[root]
- (zipper seq?
- identity
- (fn [node children] (with-meta children (meta node)))
- root))
+ (zipper
+ seq?
+ identity
+ (fn [node children] (with-meta children (meta node)))
+ root))
(defn vector-zip
"Returns a zipper for nested vectors, given a root vector"
{:added "1.0"}
[root]
(zipper
- vector?
- seq
- (fn [node children] (with-meta (vec children) (meta node)))
- root))
+ vector?
+ seq
+ (fn [node children] (with-meta (vec children) (meta node)))
+ root))
(defn xml-zip
"Returns a zipper for xml elements (as from xml/parse),
given a root element"
{:added "1.0"}
[root]
- (zipper (complement string?)
- (comp seq :content)
- (fn [node children]
- (assoc node :content (and children (apply vector children))))
- root))
+ (zipper
+ (complement string?)
+ (comp seq :content)
+ (fn [node children]
+ (assoc node :content (and children (apply vector children))))
+ root))
(defn node
"Returns the node at loc"
@@ -73,33 +77,33 @@
(defn branch?
"Returns true if the node at loc is a branch"
[^ZipperLocation loc]
- ((.-branch? loc) (.-node loc)))
+ ((.-branch? ^ZipperOps (.-ops loc)) (.-node loc)))
(defn children
"Returns a seq of the children of node at loc, which must be a branch"
[^ZipperLocation loc]
- ((.-children loc) (.-node loc)))
+ ((.-children ^ZipperOps (.-ops loc)) (.-node loc)))
(defn make-node
"Returns a new branch node, given an existing node and new children.
The loc is only used to supply the constructor."
[^ZipperLocation loc node children]
- ((.-make-node loc) node children))
+ ((.-make-node ^ZipperOps (.-ops loc)) node children))
(defn path
"Returns a seq of nodes leading to this loc"
[^ZipperLocation loc]
- (if-let [p (.-path loc)] (.-pnodes ^ZipperPath p)))
+ (if-let [^ZipperPath p (.-path loc)] (.-pnodes p)))
(defn lefts
"Returns a seq of the left siblings of this loc"
[^ZipperLocation loc]
- (if-let [p (.-path loc)] (seq (reverse (.-l ^ZipperPath p)))))
+ (if-let [^ZipperPath p (.-path loc)] (seq (reverse (.-l p)))))
(defn rights
"Returns a seq of the right siblings of this loc"
[^ZipperLocation loc]
- (if-let [p (.-path loc)] (.-r ^ZipperPath p)))
+ (if-let [^ZipperPath p (.-path loc)] (.-r p)))
(defn down
"Returns the loc of the leftmost child of the node at this loc,
@@ -107,38 +111,38 @@
[^ZipperLocation loc]
(when (branch? loc)
(when-let [cs (children loc)]
- (let [node (.-node loc), path ^ZipperPath (.-path loc)]
+ (let [node (.-node loc), ^ZipperPath path (.-path loc)]
(ZipperLocation.
- (.-branch? loc)
- (.-children loc)
- (.-make-node loc)
- (first cs)
- (ZipperPath. '() (clojure.core/next cs) path (if path (conj (.-pnodes path) node) [node]) nil))))))
+ (.-ops loc)
+ (first cs)
+ (ZipperPath.
+ '()
+ #?(:clj (.next ^clojure.lang.ISeq cs) :cljs (cljs.core/next cs))
+ path
+ (if path (conj (.-pnodes path) node) [node])
+ nil))))))
(defn up
"Returns the loc of the parent of the node at this loc, or nil if at the top"
[^ZipperLocation loc]
- (let [node (.-node loc), path ^ZipperPath (.-path loc)]
+ (let [^ZipperPath path (.-path loc)]
(when-let [pnodes (and path (.-pnodes path))]
(let [pnode (peek pnodes)]
(if (.-changed? path)
(ZipperLocation.
- (.-branch? loc)
- (.-children loc)
- (.-make-node loc)
- (make-node loc pnode (concat (reverse (.-l path)) (cons node (.-r path))))
- (if-let [ppath (.-ppath path)] (assoc ppath :changed? true)))
+ (.-ops loc)
+ (make-node loc pnode (concat (reverse (.-l path)) (cons (.-node loc) (.-r path))))
+ (if-let [^ZipperPath ppath (.-ppath path)]
+ (ZipperPath. (.-l ppath) (.-r ppath) (.-ppath ppath) (.-pnodes ppath) true)))
(ZipperLocation.
- (.-branch? loc)
- (.-children loc)
- (.-make-node loc)
- pnode
- (.-ppath path)))))))
+ (.-ops loc)
+ pnode
+ (.-ppath path)))))))
(defn root
"zips all the way up and returns the root node, reflecting any changes."
[^ZipperLocation loc]
- (if (= :end (.-path loc))
+ (if (#?(:clj identical? :cljs =) :end (.-path loc))
(.-node loc)
(let [p (up loc)]
(if p
@@ -148,86 +152,96 @@
(defn right
"Returns the loc of the right sibling of the node at this loc, or nil"
[^ZipperLocation loc]
- (let [path ^ZipperPath (.-path loc)]
+ (let [^ZipperPath path (.-path loc)]
(when-let [r (and path (.-r path))]
(ZipperLocation.
- (.-branch? loc)
- (.-children loc)
- (.-make-node loc)
- (first r)
- (assoc path :l (conj (.-l path) (.-node loc)) :r (clojure.core/next r))))))
+ (.-ops loc)
+ (first r)
+ (ZipperPath.
+ (conj (.-l path) (.-node loc))
+ #?(:clj (.next ^clojure.lang.ISeq r) :cljs (cljs.core/next r))
+ (.-ppath path)
+ (.-pnodes path)
+ (.-changed? path))))))
(defn rightmost
"Returns the loc of the rightmost sibling of the node at this loc, or self"
[^ZipperLocation loc]
- (let [path ^ZipperPath (.-path loc)]
+ (let [^ZipperPath path (.-path loc)]
(if-let [r (and path (.-r path))]
(ZipperLocation.
- (.-branch? loc)
- (.-children loc)
- (.-make-node loc)
- (last r)
- (assoc path :l (apply conj (.-l path) (.-node loc) (butlast r)) :r nil))
+ (.-ops loc)
+ (last r)
+ (ZipperPath.
+ (apply conj (.-l path) (.-node loc) (butlast r))
+ nil
+ (.-ppath path)
+ (.-pnodes path)
+ (.-changed? path)))
loc)))
(defn left
"Returns the loc of the left sibling of the node at this loc, or nil"
[^ZipperLocation loc]
- (let [path ^ZipperPath (.-path loc)]
+ (let [^ZipperPath path (.-path loc)]
(when (and path (seq (.-l path)))
(ZipperLocation.
- (.-branch? loc)
- (.-children loc)
- (.-make-node loc)
- (peek (.-l path))
- (assoc path :l (pop (.-l path)) :r (cons (.-node loc) (.-r path)))))))
+ (.-ops loc)
+ (peek (.-l path))
+ (ZipperPath.
+ (pop (.-l path))
+ (cons (.-node loc) (.-r path))
+ (.-ppath path)
+ (.-pnodes path)
+ (.-changed? path))))))
(defn leftmost
"Returns the loc of the leftmost sibling of the node at this loc, or self"
[^ZipperLocation loc]
- (let [path ^ZipperPath (.-path loc)]
+ (let [^ZipperPath path (.-path loc)]
(if (and path (seq (.-l path)))
(ZipperLocation.
- (.-branch? loc)
- (.-children loc)
- (.-make-node loc)
- (peek (.-l path))
- (assoc path :l [] :r (concat (clojure.core/next (reverse (.-l path))) [(.-node loc)] (.-r path))))
+ (.-ops loc)
+ (last (.-l path))
+ (ZipperPath.
+ '()
+ (concat
+ #?(:clj (.next ^clojure.lang.ISeq (reverse (.-l path)))
+ :cljs (cljs.core/next (reverse (.-l path))))
+ [(.-node loc)] (.-r path))
+ (.-ppath path)
+ (.-pnodes path)
+ (.-changed? path)))
loc)))
(defn insert-left
"Inserts the item as the left sibling of the node at this loc, without moving"
[^ZipperLocation loc item]
- (if-let [path ^ZipperPath (.-path loc)]
+ (if-let [^ZipperPath path (.-path loc)]
(ZipperLocation.
- (.-branch? loc)
- (.-children loc)
- (.-make-node loc)
- (.-node loc)
- (assoc path :l (conj (.-l path) item) :changed? true))
- (throw (new js/Error "Insert at top"))))
+ (.-ops loc)
+ (.-node loc)
+ (ZipperPath. (conj (.-l path) item) (.-r path) (.-ppath path) (.-pnodes path) true))
+ (throw (new #?(:clj Exception :cljs js/Error) "Insert at top"))))
(defn insert-right
"Inserts the item as the right sibling of the node at this loc, without moving"
[^ZipperLocation loc item]
- (if-let [path ^ZipperPath (.-path loc)]
+ (if-let [^ZipperPath path (.-path loc)]
(ZipperLocation.
- (.-branch? loc)
- (.-children loc)
- (.-make-node loc)
- (.-node loc)
- (assoc path :r (cons item (.-r path)) :changed? true))
- (throw (new js/Error "Insert at top"))))
+ (.-ops loc)
+ (.-node loc)
+ (ZipperPath. (.-l path) (cons item (.-r path)) (.-ppath path) (.-pnodes path) true))
+ (throw (new #?(:clj Exception :cljs js/Error) "Insert at top"))))
(defn replace
"Replaces the node at this loc, without moving"
[^ZipperLocation loc node]
(ZipperLocation.
- (.-branch? loc)
- (.-children loc)
- (.-make-node loc)
- node
- (if-let [path (.-path loc)] (assoc path :changed? true))))
+ (.-ops loc)
+ node
+ (if-let [^ZipperPath path (.-path loc)]
+ (ZipperPath. (.-l path) (.-r path) (.-ppath path) (.-pnodes path) true))))
(defn insert-child
"Inserts the item as the leftmost child of the node at this loc, without moving"
@@ -245,15 +259,15 @@
at the end, stays there."
[^ZipperLocation loc]
(let [path (.-path loc)]
- (if (= :end path)
+ (if (#?(:clj identical? :cljs =) :end path)
loc
(or
- (and (branch? loc) (down loc))
- (right loc)
- (loop [p loc]
- (if (up p)
- (or (right (up p)) (recur (up p)))
- (ZipperLocation. (.-branch? loc) (.-children loc) (.-make-node loc) (.-node p) :end)))))))
+ (if (branch? loc) (down loc))
+ (right loc)
+ (loop [p loc]
+ (if-let [u (up p)]
+ (or (right u) (recur u))
+ (ZipperLocation. (.-ops loc) (.-node p) :end)))))))
(defn prev
"Moves to the previous loc in the hierarchy, depth-first. If already at the root, returns nil."
@@ -268,29 +282,26 @@
(defn end?
"Returns true if loc represents the end of a depth-first walk"
[^ZipperLocation loc]
- (= :end (.-path loc)))
+ (#?(:clj identical? :cljs =) :end (.-path loc)))
(defn remove
"Removes the node at loc, returning the loc that would have preceded it in a depth-first walk."
[^ZipperLocation loc]
- (if-let [path ^ZipperPath (.-path loc)]
+ (if-let [^ZipperPath path (.-path loc)]
(if (pos? (count (.-l path)))
(loop [loc (ZipperLocation.
- (.-branch? loc)
- (.-children loc)
- (.-make-node loc)
- (peek (.-l path))
- (assoc path :l (pop (.-l path)) :changed? true))]
+ (.-ops loc)
+ (peek (.-l path))
+ (ZipperPath. (pop (.-l path)) (.-r path) (.-ppath path) (.-pnodes path) true))]
(if-let [child (and (branch? loc) (down loc))]
(recur (rightmost child))
loc))
(ZipperLocation.
- (.-branch? loc)
- (.-children loc)
- (.-make-node loc)
- (make-node loc (peek (.-pnodes path)) (.-r path))
- (if-let [ppath (.-ppath path)] (and ppath (assoc ppath :changed? true)))))
- (throw (new js/Error "Remove at top"))))
+ (.-ops loc)
+ (make-node loc (peek (.-pnodes path)) (.-r path))
+ (if-let [^ZipperPath ppath (.-ppath path)]
+ (if ppath (ZipperPath. (.-l ppath) (.-r ppath) (.-ppath ppath) (.-pnodes ppath) true)))))
+ (throw (new #?(:clj Exception :cljs js/Error) "Remove at top"))))
(defn edit
"Replaces the node at this loc with the value of (f node args)"
=====================================
test/cljs/fast_zip/core_test.cljs deleted
=====================================
@@ -1,73 +0,0 @@
-(ns fast-zip.core-test
- (:require
- [cemerick.cljs.test :as t]
- [fast-zip.core :as z])
- (:require-macros
- [cemerick.cljs.test :refer [deftest testing is]]))
-
-(def data '[[a * b] + [c * d]])
-(def dz (z/vector-zip data))
-
-(deftest zipper-tests
- (testing "Edge cases"
- (let [ez (z/seq-zip [])]
- (is (nil? (z/path ez)))
- (is (nil? (z/lefts ez)))
- (is (nil? (z/rights ez)))
- (is (nil? (z/down ez)))
- (is (nil? (z/right ez)))
- (is (nil? (z/left ez)))
- (is (nil? (z/up ez)))
- (is (= [] (z/node (z/seq-zip []))))
- (is (= '() (z/node (z/seq-zip '()))))))
-
- (testing "Basic navigation"
- (is (= (z/node (z/right (z/down (z/right (z/right (z/down dz))))))
- '* ))
- (is (= (z/lefts (z/right (z/down (z/right (z/right (z/down dz))))))
- '(c)))
- (is (= (z/rights (z/right (z/down (z/right (z/right (z/down dz))))))
- '(d)))
- (is (= (z/node (z/up (z/up (z/right (z/down (z/right (z/right (z/down dz))))))))
- data))
- (is (= (z/path (z/right (z/down (z/right (z/right (z/down dz))))))
- '[[[a * b] + [c * d]] [c * d]]))
- (is (= (-> dz z/down z/right z/right z/down z/right z/node)
- '*))
- (is (= (-> dz z/down z/rights)
- '(+ [c * d])))
- (is (= (-> dz z/down z/right z/right z/lefts)
- '([a * b] +)))
- (is (= (-> dz z/down z/rightmost z/lefts)
- '([a * b] +)))
- (is (= (-> dz z/down z/right z/right z/leftmost z/rights)
- '(+ [c * d]))))
-
- (testing "Edits"
- (is (= (-> dz z/down z/right z/right z/down z/right (z/replace '/) z/root)
- '[[a * b] + [c / d]]))
- (is (= (-> dz z/next z/next (z/edit str) z/next z/next z/next (z/replace '/) z/root)
- '[["a" * b] / [c * d]]))
- (is (= (-> dz z/next z/next z/next z/next z/next z/next z/next z/next z/next z/remove z/root)
- '[[a * b] + [c *]]))
- (is (= (-> dz z/next z/next z/next z/next z/next z/next z/next z/next z/next z/remove (z/insert-right 'e) z/root)
- '[[a * b] + [c * e]]))
- (is (= (-> dz z/next z/next z/next z/next z/next z/next z/next z/next z/next z/remove z/up (z/append-child 'e) z/root)
- '[[a * b] + [c * e]]))
- (is (z/end? (-> dz z/next z/next z/next z/next z/next z/next z/next z/next z/next z/remove z/next)))
- (is (= (-> dz z/next z/remove z/next z/remove z/root)
- '[[c * d]]))
- (is (= '[[a / b] + [c / d]]
- (loop [loc dz]
- (if (z/end? loc)
- (z/root loc)
- (recur (z/next (if (= '* (z/node loc))
- (z/replace loc '/)
- loc)))))))
- (is (= '[[a b] + [c d]]
- (loop [loc dz]
- (if (z/end? loc)
- (z/root loc)
- (recur (z/next (if (= '* (z/node loc))
- (z/remove loc)
- loc)))))))))
=====================================
test/clj/fast_zip/core_test.clj → test/fast_zip/core_test.cljc
=====================================
@@ -1,6 +1,7 @@
(ns fast-zip.core-test
(:require
- [clojure.test :refer :all]
+ #?(:clj [clojure.test :refer :all]
+ :cljs [cemerick.cljs.test :refer-macros [deftest testing is]])
[fast-zip.core :as z]))
(def data '[[a * b] + [c * d]])
@@ -39,7 +40,9 @@
(is (= (-> dz z/down z/rightmost z/lefts)
'([a * b] +)))
(is (= (-> dz z/down z/right z/right z/leftmost z/rights)
- '(+ [c * d]))))
+ '(+ [c * d])))
+ (is (= (-> (z/seq-zip '(a b c d)) z/down z/right z/right z/leftmost z/node)
+ 'a)))
(testing "Edits"
(is (= (-> dz z/down z/right z/right z/down z/right (z/replace '/) z/root)
View it on GitLab: https://salsa.debian.org/clojure-team/fast-zip-clojure/-/commit/ba7c4463e8535fb479984431bf280180f162fa4e
--
View it on GitLab: https://salsa.debian.org/clojure-team/fast-zip-clojure/-/commit/ba7c4463e8535fb479984431bf280180f162fa4e
You're receiving this email because of your account on salsa.debian.org.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/pkg-java-commits/attachments/20220701/720331a6/attachment.htm>
More information about the pkg-java-commits
mailing list