[Git][clojure-team/fast-zip-clojure][upstream] New upstream version 0.7.0+really0.5.0
Jérôme Charaoui (@lavamind)
gitlab at salsa.debian.org
Sat Jul 9 01:25:37 BST 2022
Jérôme Charaoui pushed to branch upstream at Debian Clojure Maintainers / fast-zip-clojure
Commits:
4399f948 by Jérôme Charaoui at 2022-07-08T17:02:48-04:00
New upstream version 0.7.0+really0.5.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/fast_zip/core.cljc → src/cljs/fast_zip/core.cljs
- test/fast_zip/core_test.cljc → test/clj/fast_zip/core_test.clj
- + test/cljs/fast_zip/core_test.cljs
Changes:
=====================================
BENCHMARKS.md
=====================================
@@ -1,247 +1,5 @@
# 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
@@ -249,13 +7,11 @@ 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.
@@ -337,4 +93,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
+ Variance from outliers : 1.6389 % Variance is slightly inflated by outliers
\ No newline at end of file
=====================================
CHANGES.md
=====================================
@@ -1,29 +1,5 @@
# 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.
@@ -36,4 +12,4 @@
## 0.3.0
-* Initial version.
+* Initial version.
\ No newline at end of file
=====================================
README.md
=====================================
@@ -1,119 +1,60 @@
# fast-zip
-A modified version of [clojure.zip](http://clojuredocs.org/clojure.zip) that
-uses `deftype` internally and is written in CLJX format.
+A modified version of clojure.zip that uses records internally.
## Usage
-For Clojure 1.7 use:
-
```clojure
-[fast-zip "0.7.0"]
+[fast-zip "0.5.0"]
```
-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`.
+This is a drop in replacement for clojure.zip. Simply require ``fast-zip.core``
+instead of ``clojure.zip``.
## Benchmark
-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...
+The below traverses a vector zip with three levels and sums the numbers. To
+run, use ``lein perforate``.
-[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.
+ ======================
+ WARNING: Final GC required 1.450308932831415 % of runtime
+ Goal: Benchmark vector zip.
-----
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
+ 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
- Found 3 outliers in 60 samples (5.0000 %)
- low-severe 3 (5.0000 %)
- Variance from outliers : 23.8777 % Variance is moderately inflated by outliers
+ Found 2 outliers in 60 samples (3.3333 %)
+ low-severe 2 (3.3333 %)
+ Variance from outliers : 1.6389 % Variance is slightly 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
+ 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
- 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
+For the clojurescript version, make sure you have node.js installed along
+with the ``benchmark`` module. Then use ``lein clean-bench``
## TODO
* Create benchmarks that represent more functionality and different use
- cases (in progress)
+ cases.
-## Contributors
+## Thanks
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,32 +8,45 @@
(def big-vec (vec (repeat 10 (vec (repeat 10 (vec (range 10)))))))
-(defn zip-walk
- [zipper node next end?]
- (loop [i 0, loc zipper]
- (if (end? loc)
+(defn zip-test1
+ []
+ (loop [i 0, loc (z/vector-zip big-vec)]
+ (if (z/end? loc)
i
- (recur (long (if (integer? (node loc)) (unchecked-add-int i (node loc)) i)) (next loc)))))
+ (recur (long (if (integer? (z/node loc)) (unchecked-add-int i (z/node loc)) i)) (z/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))))))
-
-(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?))
+(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
=====================================
benchmarks/fast_zip/core_bench.cljs
=====================================
@@ -1,67 +1,51 @@
(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-walk
- [zipper node next end?]
- (loop [i 0, loc zipper]
- (if (end? loc)
+(defn zip-test1
+ []
+ (loop [i 0, loc (z/vector-zip big-vec)]
+ (if (z/end? loc)
i
- (recur (long (if (integer? (node loc)) (unchecked-add-int i (node loc)) i)) (next loc)))))
+ (recur (long (if (integer? (z/node loc)) (unchecked-add-int i (z/node loc)) i)) (z/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))))))
+(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 make-benchmark
- [id clj fz]
+(def suite
(.. (.Suite Benchmark)
- (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)
+ (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)
(.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,33 +1,44 @@
-(defproject fast-zip "0.7.0"
+(defproject fast-zip "0.5.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.7.0" :scope "provided"]
- [org.clojure/clojurescript "1.7.107" :scope "provided"]]
+ :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"]
;; Prevent lein from disabling jvm optimizations.
- :jvm-opts ^:replace []
+ :jvm-opts ^:replace ["-server"]
:profiles {:dev
{:dependencies
- [[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"]]
+ [[perforate "0.3.3"]
+ [criterium "0.4.3"]
+ [org.bodil/cljs-noderepl "0.1.11"]
+ [com.cemerick/piggieback "0.1.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 clean, test, cljsbuild test"
+ "do test, cljsbuild clean, cljsbuild test"
#" ")
"clean-bench" ~(clojure.string/split
- "do clean, cljsbuild once bench"
- #" ")}}}
+ "do cljsbuild clean, cljsbuild once bench"
+ #" ")}
+ :repl-options {:nrepl-middleware [cemerick.piggieback/wrap-cljs-repl]}}}
:perforate {:environments [{:namespaces [fast-zip.core-bench]}]}
@@ -39,12 +50,12 @@
:cljsbuild
{:builds [{:id "test"
- :source-paths ["src" "test"]
+ :source-paths ["src/cljs" "test/cljs"]
:compiler {:output-to "target/cljs/testable.js"
:optimizations :whitespace
:pretty-print true}}
{:id "bench"
- :source-paths ["src" "benchmarks"]
+ :source-paths ["src/cljs" "benchmarks"]
:notify-command ["node" "target/cljs/benchmark.js"]
:compiler {:target :nodejs
:output-to "target/cljs/benchmark.js"
=====================================
src/clj/fast_zip/core.clj
=====================================
@@ -0,0 +1,298 @@
+; 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/fast_zip/core.cljc → src/cljs/fast_zip/core.cljs
=====================================
@@ -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,11 +15,9 @@
fast-zip.core
(:refer-clojure :exclude [replace remove next]))
-(deftype ZipperOps [branch? children make-node])
+(defrecord ZipperPath [l r ppath pnodes changed?])
-(deftype ZipperPath [l r ppath pnodes changed?])
-
-(deftype ZipperLocation [^ZipperOps ops node ^ZipperPath path])
+(defrecord ZipperLocation [branch? children make-node node path])
(defn zipper
"Creates a new zipper structure.
@@ -35,39 +33,37 @@
root is the root node."
{:added "1.0"}
[branch? children make-node root]
- (ZipperLocation. (ZipperOps. branch? children make-node) root nil))
+ (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))
+ (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"
@@ -77,33 +73,33 @@
(defn branch?
"Returns true if the node at loc is a branch"
[^ZipperLocation loc]
- ((.-branch? ^ZipperOps (.-ops loc)) (.-node 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 ^ZipperOps (.-ops loc)) (.-node 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 ^ZipperOps (.-ops loc)) node children))
+ ((.-make-node loc) node children))
(defn path
"Returns a seq of nodes leading to this loc"
[^ZipperLocation loc]
- (if-let [^ZipperPath p (.-path loc)] (.-pnodes p)))
+ (if-let [p (.-path loc)] (.-pnodes ^ZipperPath p)))
(defn lefts
"Returns a seq of the left siblings of this loc"
[^ZipperLocation loc]
- (if-let [^ZipperPath p (.-path loc)] (seq (reverse (.-l p)))))
+ (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 [^ZipperPath p (.-path loc)] (.-r p)))
+ (if-let [p (.-path loc)] (.-r ^ZipperPath p)))
(defn down
"Returns the loc of the leftmost child of the node at this loc,
@@ -111,38 +107,38 @@
[^ZipperLocation loc]
(when (branch? loc)
(when-let [cs (children loc)]
- (let [node (.-node loc), ^ZipperPath path (.-path loc)]
+ (let [node (.-node loc), path ^ZipperPath (.-path loc)]
(ZipperLocation.
- (.-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))))))
+ (.-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 [^ZipperPath path (.-path loc)]
+ (let [node (.-node loc), path ^ZipperPath (.-path loc)]
(when-let [pnodes (and path (.-pnodes path))]
(let [pnode (peek pnodes)]
(if (.-changed? path)
(ZipperLocation.
- (.-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)))
+ (.-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.
- (.-ops loc)
- pnode
- (.-ppath path)))))))
+ (.-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 (#?(:clj identical? :cljs =) :end (.-path loc))
+ (if (= :end (.-path loc))
(.-node loc)
(let [p (up loc)]
(if p
@@ -152,96 +148,86 @@
(defn right
"Returns the loc of the right sibling of the node at this loc, or nil"
[^ZipperLocation loc]
- (let [^ZipperPath path (.-path loc)]
+ (let [path ^ZipperPath (.-path loc)]
(when-let [r (and path (.-r path))]
(ZipperLocation.
- (.-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))))))
+ (.-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 [^ZipperPath path (.-path loc)]
+ (let [path ^ZipperPath (.-path loc)]
(if-let [r (and path (.-r path))]
(ZipperLocation.
- (.-ops loc)
- (last r)
- (ZipperPath.
- (apply conj (.-l path) (.-node loc) (butlast r))
- nil
- (.-ppath path)
- (.-pnodes path)
- (.-changed? path)))
+ (.-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 [^ZipperPath path (.-path loc)]
+ (let [path ^ZipperPath (.-path loc)]
(when (and path (seq (.-l path)))
(ZipperLocation.
- (.-ops loc)
- (peek (.-l path))
- (ZipperPath.
- (pop (.-l path))
- (cons (.-node loc) (.-r path))
- (.-ppath path)
- (.-pnodes path)
- (.-changed? path))))))
+ (.-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 [^ZipperPath path (.-path loc)]
+ (let [path ^ZipperPath (.-path loc)]
(if (and path (seq (.-l path)))
(ZipperLocation.
- (.-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)))
+ (.-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 [^ZipperPath path (.-path loc)]
+ (if-let [path ^ZipperPath (.-path loc)]
(ZipperLocation.
- (.-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"))))
+ (.-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"))))
(defn insert-right
"Inserts the item as the right sibling of the node at this loc, without moving"
[^ZipperLocation loc item]
- (if-let [^ZipperPath path (.-path loc)]
+ (if-let [path ^ZipperPath (.-path loc)]
(ZipperLocation.
- (.-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"))))
+ (.-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"))))
(defn replace
"Replaces the node at this loc, without moving"
[^ZipperLocation loc node]
(ZipperLocation.
- (.-ops loc)
- node
- (if-let [^ZipperPath path (.-path loc)]
- (ZipperPath. (.-l path) (.-r path) (.-ppath path) (.-pnodes path) true))))
+ (.-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"
@@ -259,15 +245,15 @@
at the end, stays there."
[^ZipperLocation loc]
(let [path (.-path loc)]
- (if (#?(:clj identical? :cljs =) :end path)
+ (if (= :end path)
loc
(or
- (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)))))))
+ (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."
@@ -282,26 +268,29 @@
(defn end?
"Returns true if loc represents the end of a depth-first walk"
[^ZipperLocation loc]
- (#?(:clj identical? :cljs =) :end (.-path loc)))
+ (= :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 [^ZipperPath path (.-path loc)]
+ (if-let [path ^ZipperPath (.-path loc)]
(if (pos? (count (.-l path)))
(loop [loc (ZipperLocation.
- (.-ops loc)
- (peek (.-l path))
- (ZipperPath. (pop (.-l path)) (.-r path) (.-ppath path) (.-pnodes path) true))]
+ (.-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.
- (.-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"))))
+ (.-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"))))
(defn edit
"Replaces the node at this loc with the value of (f node args)"
=====================================
test/fast_zip/core_test.cljc → test/clj/fast_zip/core_test.clj
=====================================
@@ -1,7 +1,6 @@
(ns fast-zip.core-test
(:require
- #?(:clj [clojure.test :refer :all]
- :cljs [cemerick.cljs.test :refer-macros [deftest testing is]])
+ [clojure.test :refer :all]
[fast-zip.core :as z]))
(def data '[[a * b] + [c * d]])
@@ -40,9 +39,7 @@
(is (= (-> dz z/down z/rightmost z/lefts)
'([a * b] +)))
(is (= (-> dz z/down z/right z/right z/leftmost z/rights)
- '(+ [c * d])))
- (is (= (-> (z/seq-zip '(a b c d)) z/down z/right z/right z/leftmost z/node)
- 'a)))
+ '(+ [c * d]))))
(testing "Edits"
(is (= (-> dz z/down z/right z/right z/down z/right (z/replace '/) z/root)
=====================================
test/cljs/fast_zip/core_test.cljs
=====================================
@@ -0,0 +1,73 @@
+(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)))))))))
View it on GitLab: https://salsa.debian.org/clojure-team/fast-zip-clojure/-/commit/4399f948b03c5e623654404d904a9760117b6f38
--
View it on GitLab: https://salsa.debian.org/clojure-team/fast-zip-clojure/-/commit/4399f948b03c5e623654404d904a9760117b6f38
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/20220709/2b60f7f9/attachment.htm>
More information about the pkg-java-commits
mailing list