This commit is contained in:
Jeff Evans 2024-11-29 04:33:19 +00:00 committed by GitHub
commit bea6b59724
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 80 additions and 9 deletions

View file

@ -7,8 +7,7 @@ lein do clean, test
# Running ClojureScript tests
```
lein javac
lein doo node test-build once
lein do clean, javac, test-cljs
```
# Running benchmarks

View file

@ -40,4 +40,5 @@
[["clojars" {:url "https://repo.clojars.org"
:sign-releases false}]]
:aliases {"deploy" ["do" "clean," "deploy" "clojars"]})
:aliases {"deploy" ["do" "clean," "deploy" "clojars"]
"test-cljs" ["do" "doo" "node" "test-build" "once"]})

View file

@ -507,6 +507,11 @@
(defmacro end-fn [& args]
`(n/->SrangeEndFunction (fn ~@args)))
(defmacro subseq-pred-fn
"Used in conjunction with `continuous-subseqs`. See [[continuous-subseqs]]."
[get-truthy-fn & args]
`(i/->SubseqsDynamicPredFn ~get-truthy-fn (i/wrap-pred-with-index (fn ~@args))))
))
@ -800,7 +805,14 @@
(defnav
^{:doc "Navigates to every continuous subsequence of elements matching `pred`"}
^{:doc "Navigates to every continuous subsequence of elements matching `pred`. `pred` can be specified one of two
forms. If a regular function (e.g. defined with `fn`), it takes in only the current element as input. If
defined using the special `subseq-pred-fn` macro, it takes in a `get-truthy-fn` as its first parameter,
followed by arguments to a predicate function [`elem` `prev`], followed by the predicate function body. The
`elem` argument to the predicate function is the current element, and the `pred` argument is the value
returned by your predicate on the previous element, so it can be in any structure you choose. `get-truthy-fn`
is a function that should return true from your predicate's return structure if that element should be
included in a subsequence."}
continuous-subseqs
[pred]
(select* [this structure next-fn]

View file

@ -570,8 +570,38 @@
res
))))
(defn wrap-pred-with-index [pred]
(fn [i elem prev]
[(pred elem (first prev)), i]))
;; adapted from clojure.core$keep_indexed
(defn- subseq-pred-fn-transducer
([pred-fn]
(fn [rf]
(let [last-val (volatile! nil) idx (volatile! -1)]
(fn
([] (rf)) ;; init arity
([result] (rf result)) ;; completion arity
([result input] ;; reduction arity
(let [last @last-val
i (vswap! idx inc)
curr ((:pred-fn pred-fn) i input last)]
(vreset! last-val curr)
(if (nil? curr)
result
(rf result curr)))))))))
;; see com.rpl.specter.navs.SrangeEndFunction
(defrecord SubseqsDynamicPredFn [get-truthy-fn pred-fn])
(defn- matching-indices [aseq p]
(keep-indexed (fn [i e] (if (p e) i)) aseq))
(if (instance? SubseqsDynamicPredFn p)
;; use new subseq predicate form (taking current and previous vals)
(let [index-results (into [] (subseq-pred-fn-transducer p) aseq)]
;; apply the get-truthy-fn to extract the truthy (i.e. include) result
(map last (filter (comp true? (:get-truthy-fn p) first) index-results)))
;; else use the previous 1-arity predicate
(keep-indexed (fn [i e] (if (p e) i)) aseq)))
(defn matching-ranges [aseq p]
(first

View file

@ -11,7 +11,7 @@
select-any selected-any? collected? traverse
multi-transform path dynamicnav recursive-path
defdynamicnav traverse-all satisfies-protpath? end-fn
vtransform]]))
subseq-pred-fn vtransform]]))
(:use
#?(:clj [clojure.test :only [deftest is]])
#?(:clj [clojure.test.check.clojure-test :only [defspec]])
@ -23,7 +23,7 @@
select-any selected-any? collected? traverse
multi-transform path dynamicnav recursive-path
defdynamicnav traverse-all satisfies-protpath? end-fn
vtransform]]))
subseq-pred-fn vtransform]]))
@ -949,6 +949,23 @@
(= (setval (s/continuous-subseqs pred) nil aseq)
(filter (complement pred) aseq))))
(defn- make-bounds-pred-fn-vecs [start end]
(s/subseq-pred-fn first [elem prev]
(let [[included last] prev]
(cond
(= start elem) [false start]
(= end elem) [false end]
(= end last) [false elem]
:else [(or (= start last) included) elem]))))
(defn- make-bounds-pred-fn-maps [start end]
(s/subseq-pred-fn :include [elem prev]
(let [{include :include last :last} prev]
(cond
(= start elem) {:include false :last start}
(= end elem) {:include false :last end}
(= end last) {:include false :last elem}
:else {:include (or (= start last) include) :last elem}))))
(deftest continuous-subseqs-test
(is (= [1 "ab" 2 3 "c" 4 "def"]
@ -960,7 +977,19 @@
(is (= [[] [2] [4 6]]
(select
[(s/continuous-subseqs number?) (s/filterer even?)]
[1 "a" "b" 2 3 "c" 4 5 6 "d" "e" "f"]))))
[1 "a" "b" 2 3 "c" 4 5 6 "d" "e" "f"])))
(is (= [[1 2 3] [8 9]]
(select
[(s/continuous-subseqs (make-bounds-pred-fn-vecs :START :END))]
[:START 1 2 3 :END 5 6 7 :START 8 9 :END])))
(is (= [1 2 3 :START-SUM 15 :END-SUM 7 8 9 :START-SUM 21 :END-SUM 12 :START-SUM 27 :END-SUM]
(transform
(s/continuous-subseqs (make-bounds-pred-fn-maps :START-SUM :END-SUM))
(fn [vals] [(apply + vals)])
[1 2 3 :START-SUM 4 5 6 :END-SUM 7 8 9 :START-SUM 10 11 :END-SUM 12 :START-SUM 13 14 :END-SUM])))
)
@ -1598,7 +1627,7 @@
(s/comp-paths
(s/srange-dynamic
(fn [aseq] (long (/ (count aseq) 2)))
(end-fn [aseq s] (if (empty? aseq) 0 (inc s))))
(s/end-fn [aseq s] (if (empty? aseq) 0 (inc s))))
s/FIRST
))