Skip to content

Commit

Permalink
redplanetlabs#236 - Generalize continuous-subseqs
Browse files Browse the repository at this point in the history
Adding new subseq-pred-fn macro to create the new form of predicate function (taking the previous and current item), to preserve backward compatibility (still allowing predicate functions that only take the current item)

Adding SubseqsDynamicPredFn, which works the same as SrangeEndFn, to support backward compatibility

Adding wrapper to take a predicate on [prev current] and turn it into a predicate also taking the current index as the first param

Creating transducer to combine this with the user-supplied predicate function

Adding tests for select and transform

WORK IN PROGRESS

TODO: figure out how to make predicate function handle an open-ended subsequence (ex: end marker not yet seen)
  • Loading branch information
jeff303 committed Aug 14, 2020
1 parent 40add56 commit 6191b5b
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 2 deletions.
3 changes: 3 additions & 0 deletions src/clj/com/rpl/specter.cljc
Expand Up @@ -471,6 +471,9 @@
(defmacro end-fn [& args]
`(n/->SrangeEndFunction (fn ~@args)))

(defmacro subseq-pred-fn [& args]
`(i/->SubseqsDynamicPredFn (i/wrap-pred-with-index (fn ~@args))))

))


Expand Down
31 changes: 30 additions & 1 deletion src/clj/com/rpl/specter/impl.cljc
Expand Up @@ -560,8 +560,37 @@
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 [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)]
(map last (filter (comp true? 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
Expand Down
21 changes: 20 additions & 1 deletion test/com/rpl/specter/core_test.cljc
Expand Up @@ -960,7 +960,26 @@
(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"])))
(defn- make-bounds-pred-fn [start end]
(s/subseq-pred-fn [elem prev]
(cond
(identical? start elem) start
(identical? end elem) end
(identical? end prev) false
:else (or (identical? start prev) prev)
)))
(is (= [[1 2 3] [8 9]]
(select
[(s/continuous-subseqs (make-bounds-pred-fn :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 13 14]
(transform
(s/continuous-subseqs (make-bounds-pred-fn :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])))
)



Expand Down

0 comments on commit 6191b5b

Please sign in to comment.