[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