General cleanup and performance review changes
- move to transducer for walking the tagged range boundary items - remove use of core.match, after getting logic correct to reduce loading of unneeded library - added docstrings to function - added type hints and removed reflection warnings
This commit is contained in:
1
deps.edn
1
deps.edn
@@ -1,5 +1,4 @@
|
|||||||
{:deps {org.clojure/clojure {:mvn/version "1.11.2"}
|
{:deps {org.clojure/clojure {:mvn/version "1.11.2"}
|
||||||
org.clojure/core.match {:mvn/version "1.1.1"}
|
|
||||||
org.threeten/threeten-extra {:mvn/version "1.8.0"}}
|
org.threeten/threeten-extra {:mvn/version "1.8.0"}}
|
||||||
:paths ["src"]
|
:paths ["src"]
|
||||||
:aliases {:test {:extra-paths ["test"]
|
:aliases {:test {:extra-paths ["test"]
|
||||||
|
|||||||
@@ -5,23 +5,23 @@
|
|||||||
|
|
||||||
(extend-type LocalDateRange
|
(extend-type LocalDateRange
|
||||||
range/DiscreteValueRange
|
range/DiscreteValueRange
|
||||||
(abuts [this other]
|
(abuts? [^LocalDateRange this ^LocalDateRange other]
|
||||||
(.abuts this other))
|
(.abuts this other))
|
||||||
(value-before [this]
|
(value-before ^LocalDate [^LocalDateRange this]
|
||||||
(if (.isUnboundedStart this)
|
(if (.isUnboundedStart this)
|
||||||
(.getStart this)
|
(.getStart this)
|
||||||
(.. this getStart (minusDays 1))))
|
(.. this getStart (minusDays 1))))
|
||||||
(value-after [this]
|
(value-after [^LocalDateRange this]
|
||||||
(if (.isUnboundedEnd this)
|
(if (.isUnboundedEnd this)
|
||||||
(.getEnd this)
|
(.getEnd this)
|
||||||
(.. this getEndInclusive (plusDays 1))))
|
(.. this getEndInclusive (plusDays 1))))
|
||||||
(start [this]
|
(start ^LocalDate [^LocalDateRange this]
|
||||||
(.getStart this))
|
(.getStart this))
|
||||||
(end [this]
|
(end ^LocalDate [^LocalDateRange this]
|
||||||
(.getEndInclusive this))
|
(.getEndInclusive this))
|
||||||
(range-type [_this]
|
(range-type [_this]
|
||||||
:local-date-range)
|
:local-date-range)
|
||||||
(union [this other]
|
(union [this ^LocalDateRange other]
|
||||||
(when-not (.isConnected this other)
|
(when-not (.isConnected this other)
|
||||||
(throw (ex-info "Cannot union non-connecting ranges" {})))
|
(throw (ex-info "Cannot union non-connecting ranges" {})))
|
||||||
(.union this other)))
|
(.union this other)))
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
(ns challenge.discrete-value-range
|
(ns challenge.discrete-value-range
|
||||||
(:require
|
(:require [clojure.set :as set]))
|
||||||
[clojure.core.match :refer [match]]
|
|
||||||
[clojure.set :as set]))
|
|
||||||
|
|
||||||
(defprotocol DiscreteValueRange
|
(defprotocol DiscreteValueRange
|
||||||
"A protocol for generic behavior on Ranges over
|
"A protocol for generic behavior on Ranges over
|
||||||
@@ -26,15 +24,23 @@
|
|||||||
that before/after values against other values that the range
|
that before/after values against other values that the range
|
||||||
is over.
|
is over.
|
||||||
"
|
"
|
||||||
(abuts [this other])
|
(abuts? [this other] "Does this range abuts the specified range")
|
||||||
(value-before [this])
|
(value-before [this] "The discrete value that is considered to be directly before the start value")
|
||||||
(value-after [this])
|
(value-after [this] "The discrete value that is considered to be directly after the end value")
|
||||||
(start [this])
|
(start [this] "The starting value (inclusive) for this range")
|
||||||
(end [this])
|
(end [this] "The ending value (inclusive) for this range")
|
||||||
(range-type [this])
|
(range-type [this]
|
||||||
(union [this other]))
|
"Type of the range. Used in dispatch of multimethod to construct new ranges of the type.")
|
||||||
|
(union [this other]
|
||||||
|
"Calculates the range that is the union of this range and the other range.
|
||||||
|
The two ranges should overlap or abut each other."))
|
||||||
|
|
||||||
(defn ->range-boundaries* [range]
|
(defmulti ->discrete-value-range (fn [range-type _start _end]
|
||||||
|
range-type))
|
||||||
|
|
||||||
|
(defn ->range-boundaries*
|
||||||
|
"Construct range boundary 'fencepost' markers for the range"
|
||||||
|
[range]
|
||||||
[{:value (start range)
|
[{:value (start range)
|
||||||
:boundary-type :start
|
:boundary-type :start
|
||||||
:type (range-type range)
|
:type (range-type range)
|
||||||
@@ -46,6 +52,9 @@
|
|||||||
|
|
||||||
(def ->range-boundaries (memoize ->range-boundaries*))
|
(def ->range-boundaries (memoize ->range-boundaries*))
|
||||||
|
|
||||||
|
(def untagged-range-boundary-compare
|
||||||
|
(juxt :value (comp {:start 0 :end 1} :boundary-type)))
|
||||||
|
|
||||||
(defn- ordered-range-values
|
(defn- ordered-range-values
|
||||||
"Builds an ordered list or 'fenceposts' for the start and end
|
"Builds an ordered list or 'fenceposts' for the start and end
|
||||||
of all given ranges, to prepare to produces a consolidated
|
of all given ranges, to prepare to produces a consolidated
|
||||||
@@ -61,12 +70,9 @@
|
|||||||
[ranges]
|
[ranges]
|
||||||
(->> ranges
|
(->> ranges
|
||||||
(mapcat ->range-boundaries)
|
(mapcat ->range-boundaries)
|
||||||
(sort-by (juxt :value (comp {:start 0 :end 1} :boundary-type)))))
|
(sort-by untagged-range-boundary-compare)))
|
||||||
|
|
||||||
(defmulti ->discrete-value-range (fn [range-type _start _end]
|
(defn- combine-overlapping-ranges-xf
|
||||||
range-type))
|
|
||||||
|
|
||||||
(defn- combine-overlapping-ranges
|
|
||||||
"transducer to find and combine overlapping ranges by looking at
|
"transducer to find and combine overlapping ranges by looking at
|
||||||
ordered range value markers.
|
ordered range value markers.
|
||||||
|
|
||||||
@@ -97,11 +103,11 @@
|
|||||||
result)
|
result)
|
||||||
:end (do
|
:end (do
|
||||||
(.pop stack)
|
(.pop stack)
|
||||||
(if (not (.empty stack))
|
(if (.empty stack)
|
||||||
result
|
(xf result (->discrete-value-range type @start value))
|
||||||
(xf result (->discrete-value-range type @start value)))))))))))
|
result)))))))))
|
||||||
|
|
||||||
(defn- combine-abutting-ranges
|
(defn- combine-abutting-ranges-xf
|
||||||
"transducer to join ranges where the start and end of two ranges are consective
|
"transducer to join ranges where the start and end of two ranges are consective
|
||||||
discrete values.
|
discrete values.
|
||||||
|
|
||||||
@@ -109,82 +115,97 @@
|
|||||||
combined."
|
combined."
|
||||||
[]
|
[]
|
||||||
(fn [xf]
|
(fn [xf]
|
||||||
(let [prev (volatile! nil)]
|
(let [previous-range (volatile! nil)]
|
||||||
(fn
|
(fn
|
||||||
([] (xf))
|
([] (xf))
|
||||||
([result] (if @prev
|
([result] (if-let [prev @previous-range]
|
||||||
(xf (xf result @prev))
|
(xf (xf result prev))
|
||||||
(xf result)))
|
(xf result)))
|
||||||
([result input]
|
([result input]
|
||||||
(cond
|
(let [prev @previous-range]
|
||||||
(reduced? input) result
|
(cond
|
||||||
|
(reduced? input) result
|
||||||
|
|
||||||
(nil? @prev) (do
|
(nil? prev) (do
|
||||||
(vreset! prev input)
|
(vreset! previous-range input)
|
||||||
result)
|
result)
|
||||||
|
|
||||||
(abuts @prev input)
|
(abuts? prev input)
|
||||||
(let [item (union @prev input)]
|
(let [item (union prev input)]
|
||||||
(vreset! prev item)
|
(vreset! previous-range item)
|
||||||
result)
|
result)
|
||||||
|
|
||||||
:else (let [item @prev]
|
:else (let [item prev]
|
||||||
(vreset! prev input)
|
(vreset! previous-range input)
|
||||||
(xf result item))))))))
|
(xf result item)))))))))
|
||||||
|
|
||||||
(def consolidate-ranges-xf
|
(def consolidate-ranges-xf
|
||||||
(comp
|
(comp
|
||||||
(combine-overlapping-ranges)
|
(combine-overlapping-ranges-xf)
|
||||||
(combine-abutting-ranges)))
|
(combine-abutting-ranges-xf)))
|
||||||
|
|
||||||
(defn consolidate [ranges]
|
(defn consolidate
|
||||||
|
"Take a set of ranges and consolidate/collapse the ranges
|
||||||
|
into the minimal set of ranges needed to represent the original
|
||||||
|
range set"
|
||||||
|
[ranges]
|
||||||
(into #{} consolidate-ranges-xf (ordered-range-values ranges)))
|
(into #{} consolidate-ranges-xf (ordered-range-values ranges)))
|
||||||
|
|
||||||
(defn walk-range-boundaries [range-boundary-items]
|
(defn- walk-tagged-range-boundaries-xf
|
||||||
(let [close-working-range (fn [range-type start end ranges]
|
"transducer to create the set of ranges for the difference function
|
||||||
(conj! ranges (->discrete-value-range range-type
|
by walking range boundaries items that have been taged as either
|
||||||
start
|
belonging to the the source set, or the set of ranges to filter
|
||||||
end)))]
|
out of the source set, and construct the set of resulting ranges
|
||||||
(loop [[boundary-item & boundary-items] range-boundary-items
|
with the ranges in the filter ranges item removed from the source
|
||||||
in-filter-range nil
|
set of ranges."
|
||||||
in-source-range nil
|
[]
|
||||||
ranges (transient #{})
|
(let [close-working-range (fn [range-type start end]
|
||||||
close-fn nil]
|
(->discrete-value-range range-type
|
||||||
(match [boundary-item]
|
start
|
||||||
[nil]
|
end))
|
||||||
(persistent! ranges)
|
in-filter-range (volatile! nil)
|
||||||
|
in-source-range (volatile! nil)
|
||||||
|
close-fn (volatile! nil)]
|
||||||
|
(fn [xf]
|
||||||
|
(fn
|
||||||
|
([] (xf))
|
||||||
|
([result] (xf result))
|
||||||
|
([result boundary-item]
|
||||||
|
(case [(:boundary-type boundary-item) (:range-source-type boundary-item)]
|
||||||
|
[:start :source-range]
|
||||||
|
(do
|
||||||
|
(vreset! in-source-range true)
|
||||||
|
(vreset! close-fn (partial close-working-range
|
||||||
|
(:type boundary-item)
|
||||||
|
(:value boundary-item)))
|
||||||
|
result)
|
||||||
|
|
||||||
[{:boundary-type :start
|
[:end :source-range]
|
||||||
:range-source-type :source-range
|
(let [close @close-fn]
|
||||||
:type range-type
|
(vreset! in-source-range false)
|
||||||
:value new-working-range-start-value}]
|
(vreset! close-fn nil)
|
||||||
(recur boundary-items in-filter-range true ranges (partial close-working-range
|
(if @in-filter-range
|
||||||
range-type
|
result
|
||||||
new-working-range-start-value))
|
(xf result (close (:value boundary-item)))))
|
||||||
|
|
||||||
[{:boundary-type :end
|
[:start :filter-range]
|
||||||
:range-source-type :source-range
|
(do
|
||||||
:value value}]
|
(vreset! in-filter-range true)
|
||||||
(if in-filter-range
|
(if-let [close @close-fn]
|
||||||
(recur boundary-items in-filter-range false ranges nil)
|
(do
|
||||||
(recur boundary-items in-filter-range false (close-fn value ranges) nil))
|
(vreset! close-fn nil)
|
||||||
|
(xf result (close (:prev-value boundary-item))))
|
||||||
|
result))
|
||||||
|
|
||||||
[{:boundary-type :start
|
[:end :filter-range]
|
||||||
:range-source-type :filter-range
|
|
||||||
:prev-value prev-value}]
|
|
||||||
(if close-fn
|
|
||||||
(recur boundary-items true in-source-range (close-fn prev-value ranges) nil)
|
|
||||||
(recur boundary-items true in-source-range ranges close-fn))
|
|
||||||
|
|
||||||
[{:boundary-type :end
|
(do
|
||||||
:range-source-type :filter-range
|
(vreset! in-filter-range false)
|
||||||
:type range-type
|
(when @in-source-range
|
||||||
:next-value new-working-range-start-value}]
|
(vreset! close-fn (partial close-working-range
|
||||||
(if in-source-range
|
(:type boundary-item)
|
||||||
(recur boundary-items false in-source-range ranges (partial close-working-range
|
(:next-value boundary-item))))
|
||||||
range-type
|
result)))))))
|
||||||
new-working-range-start-value))
|
|
||||||
(recur boundary-items false in-source-range ranges close-fn))))))
|
|
||||||
|
|
||||||
(def ^:private range-boundary-source-compare
|
(def ^:private range-boundary-source-compare
|
||||||
"Sorts range boundary items
|
"Sorts range boundary items
|
||||||
@@ -219,6 +240,6 @@
|
|||||||
all-range-set-boundaries (->> (into range-set-boundaries
|
all-range-set-boundaries (->> (into range-set-boundaries
|
||||||
range-sets-to-remove-boundaries)
|
range-sets-to-remove-boundaries)
|
||||||
(sort-by range-boundary-source-compare))]
|
(sort-by range-boundary-source-compare))]
|
||||||
(walk-range-boundaries all-range-set-boundaries)))
|
(into #{} (walk-tagged-range-boundaries-xf) all-range-set-boundaries)))
|
||||||
([range-set range-set-to-remove & additional-range-sets-to-remove]
|
([range-set range-set-to-remove & additional-range-sets-to-remove]
|
||||||
(difference range-set (apply set/union (conj additional-range-sets-to-remove range-set-to-remove)))))
|
(difference range-set (apply set/union (conj additional-range-sets-to-remove range-set-to-remove)))))
|
||||||
|
|||||||
@@ -6,13 +6,17 @@
|
|||||||
(defrecord IntInclusiveDiscreteValueRange
|
(defrecord IntInclusiveDiscreteValueRange
|
||||||
[^int start ^int end]
|
[^int start ^int end]
|
||||||
range/DiscreteValueRange
|
range/DiscreteValueRange
|
||||||
(abuts [_this other]
|
(range/abuts? [_this other]
|
||||||
(or (= 1 (abs (- start (.end other))))
|
(or (= 1 (abs (- start (range/end other))))
|
||||||
(= 1 (abs (- end (.start other))))))
|
(= 1 (abs (- end (range/start other))))))
|
||||||
(value-before [__this]
|
(value-before [__this]
|
||||||
(dec start))
|
(if (= start Integer/MIN_VALUE)
|
||||||
|
Integer/MIN_VALUE
|
||||||
|
(dec start)))
|
||||||
(value-after [_this]
|
(value-after [_this]
|
||||||
(inc end))
|
(if (= end Integer/MAX_VALUE)
|
||||||
|
Integer/MAX_VALUE
|
||||||
|
(inc end)))
|
||||||
(start [_this]
|
(start [_this]
|
||||||
start)
|
start)
|
||||||
(end [_this]
|
(end [_this]
|
||||||
@@ -20,12 +24,14 @@
|
|||||||
(range-type [_this]
|
(range-type [_this]
|
||||||
:int-range-inclusive)
|
:int-range-inclusive)
|
||||||
(union [this other]
|
(union [this other]
|
||||||
(when-not (range/abuts this other)
|
(when-not (or (range/abuts? this other)
|
||||||
|
(or (<= start (range/start other) end)
|
||||||
|
(<= (range/start other) start (range/end other))))
|
||||||
(throw (ex-info "Cannot union non-abutting ranges" {})))
|
(throw (ex-info "Cannot union non-abutting ranges" {})))
|
||||||
|
|
||||||
(range/->discrete-value-range (.range-type this)
|
(range/->discrete-value-range (range/range-type this)
|
||||||
(min start (.start other))
|
(min start (range/start other))
|
||||||
(max end (.end other))))
|
(max end (range/end other))))
|
||||||
|
|
||||||
Object
|
Object
|
||||||
(toString [_this]
|
(toString [_this]
|
||||||
@@ -45,15 +51,15 @@
|
|||||||
(is (= (int-range-inclusive 0 1)
|
(is (= (int-range-inclusive 0 1)
|
||||||
(int-range-inclusive 0 1))))
|
(int-range-inclusive 0 1))))
|
||||||
|
|
||||||
(testing "abuts"
|
(testing "abuts?"
|
||||||
(is (= true (range/abuts (int-range-inclusive 0 1)
|
(is (= true (range/abuts? (int-range-inclusive 0 1)
|
||||||
(int-range-inclusive 2 3))))
|
(int-range-inclusive 2 3))))
|
||||||
(is (= true (range/abuts (int-range-inclusive 1 1)
|
(is (= true (range/abuts? (int-range-inclusive 1 1)
|
||||||
(int-range-inclusive 2 3))))
|
(int-range-inclusive 2 3))))
|
||||||
(is (= true (range/abuts (int-range-inclusive 4 7)
|
(is (= true (range/abuts? (int-range-inclusive 4 7)
|
||||||
(int-range-inclusive 2 3))))
|
(int-range-inclusive 2 3))))
|
||||||
(is (= false (range/abuts (int-range-inclusive 4 7)
|
(is (= false (range/abuts? (int-range-inclusive 4 7)
|
||||||
(int-range-inclusive 1 2)))))
|
(int-range-inclusive 1 2)))))
|
||||||
(testing "value-before"
|
(testing "value-before"
|
||||||
(is (= 0 (range/value-before (int-range-inclusive 1 8)))))
|
(is (= 0 (range/value-before (int-range-inclusive 1 8)))))
|
||||||
(testing "value-after"
|
(testing "value-after"
|
||||||
@@ -134,260 +140,260 @@
|
|||||||
(deftest walk-range-boundaries-test
|
(deftest walk-range-boundaries-test
|
||||||
(testing "only filter-ranges"
|
(testing "only filter-ranges"
|
||||||
(is (= #{}
|
(is (= #{}
|
||||||
(range/walk-range-boundaries [{:boundary-type :start
|
(into #{} (#'range/walk-tagged-range-boundaries-xf) [{:boundary-type :start
|
||||||
:range-source-type :filter-range
|
:range-source-type :filter-range
|
||||||
:value 1
|
:value 1
|
||||||
:prev-value 0
|
:prev-value 0
|
||||||
:type :int-range-inclusive}
|
:type :int-range-inclusive}
|
||||||
{:boundary-type :end
|
{:boundary-type :end
|
||||||
:range-source-type :filter-range
|
:range-source-type :filter-range
|
||||||
:value 4
|
:value 4
|
||||||
:next-value 5
|
:next-value 5
|
||||||
:type :int-range-inclusive}]))))
|
:type :int-range-inclusive}]))))
|
||||||
(testing "only source-ranges"
|
(testing "only source-ranges"
|
||||||
(is (= #{(int-range-inclusive 1 5)}
|
(is (= #{(int-range-inclusive 1 5)}
|
||||||
(range/walk-range-boundaries [{:boundary-type :start
|
(into #{} (#'range/walk-tagged-range-boundaries-xf) [{:boundary-type :start
|
||||||
:range-source-type :source-range
|
:range-source-type :source-range
|
||||||
:value 1
|
:value 1
|
||||||
:prev-value 0
|
:prev-value 0
|
||||||
:type :int-range-inclusive}
|
:type :int-range-inclusive}
|
||||||
{:boundary-type :end
|
{:boundary-type :end
|
||||||
:range-source-type :source-range
|
:range-source-type :source-range
|
||||||
:value 5
|
:value 5
|
||||||
:next-value 6
|
:next-value 6
|
||||||
:type :int-range-inclusive}])))
|
:type :int-range-inclusive}])))
|
||||||
(is (= #{(int-range-inclusive 1 5)
|
(is (= #{(int-range-inclusive 1 5)
|
||||||
(int-range-inclusive 11 15)}
|
(int-range-inclusive 11 15)}
|
||||||
(range/walk-range-boundaries [{:boundary-type :start
|
(into #{} (#'range/walk-tagged-range-boundaries-xf) [{:boundary-type :start
|
||||||
:range-source-type :source-range
|
:range-source-type :source-range
|
||||||
:value 1
|
:value 1
|
||||||
:next-value 2
|
:next-value 2
|
||||||
:type :int-range-inclusive}
|
:type :int-range-inclusive}
|
||||||
{:boundary-type :end
|
{:boundary-type :end
|
||||||
:range-source-type :source-range
|
:range-source-type :source-range
|
||||||
:value 5
|
:value 5
|
||||||
:prev-value 4
|
:prev-value 4
|
||||||
:type :int-range-inclusive}
|
:type :int-range-inclusive}
|
||||||
{:boundary-type :start
|
{:boundary-type :start
|
||||||
:range-source-type :source-range
|
:range-source-type :source-range
|
||||||
:value 11
|
:value 11
|
||||||
:next-value 12
|
:next-value 12
|
||||||
:type :int-range-inclusive}
|
:type :int-range-inclusive}
|
||||||
{:boundary-type :end
|
{:boundary-type :end
|
||||||
:range-source-type :source-range
|
:range-source-type :source-range
|
||||||
:value 15
|
:value 15
|
||||||
:prev-value 14
|
:prev-value 14
|
||||||
:type :int-range-inclusive}]))))
|
:type :int-range-inclusive}]))))
|
||||||
(testing "filter-ranges and source-ranges are the same"
|
(testing "filter-ranges and source-ranges are the same"
|
||||||
(is (= #{}
|
(is (= #{}
|
||||||
(range/walk-range-boundaries [{:boundary-type :start
|
(into #{} (#'range/walk-tagged-range-boundaries-xf) [{:boundary-type :start
|
||||||
:range-source-type :filter-range
|
:range-source-type :filter-range
|
||||||
:value 1
|
:value 1
|
||||||
:prev-value 0
|
:prev-value 0
|
||||||
:type :int-range-inclusive}
|
:type :int-range-inclusive}
|
||||||
{:boundary-type :start
|
{:boundary-type :start
|
||||||
:range-source-type :source-range
|
:range-source-type :source-range
|
||||||
:value 1
|
:value 1
|
||||||
:prev-value 0
|
:prev-value 0
|
||||||
:type :int-range-inclusive}
|
:type :int-range-inclusive}
|
||||||
{:boundary-type :end
|
{:boundary-type :end
|
||||||
:range-source-type :source-range
|
:range-source-type :source-range
|
||||||
:value 5
|
:value 5
|
||||||
:next-value 6
|
:next-value 6
|
||||||
:type :int-range-inclusive}
|
:type :int-range-inclusive}
|
||||||
{:boundary-type :end
|
{:boundary-type :end
|
||||||
:range-source-type :filter-range
|
:range-source-type :filter-range
|
||||||
:value 5
|
:value 5
|
||||||
:next-value 6
|
:next-value 6
|
||||||
:type :int-range-inclusive}]))))
|
:type :int-range-inclusive}]))))
|
||||||
(testing "filter-ranges before source-ranges"
|
(testing "filter-ranges before source-ranges"
|
||||||
(is (= #{(int-range-inclusive 11 15)}
|
(is (= #{(int-range-inclusive 11 15)}
|
||||||
(range/walk-range-boundaries [{:boundary-type :start
|
(into #{} (#'range/walk-tagged-range-boundaries-xf) [{:boundary-type :start
|
||||||
:range-source-type :filter-range
|
:range-source-type :filter-range
|
||||||
:value 1
|
:value 1
|
||||||
:prev-value 0
|
:prev-value 0
|
||||||
:type :int-range-inclusive}
|
:type :int-range-inclusive}
|
||||||
{:boundary-type :end
|
{:boundary-type :end
|
||||||
:range-source-type :filter-range
|
:range-source-type :filter-range
|
||||||
:value 5
|
:value 5
|
||||||
:next-value 6
|
:next-value 6
|
||||||
:type :int-range-inclusive}
|
:type :int-range-inclusive}
|
||||||
{:boundary-type :start
|
{:boundary-type :start
|
||||||
:range-source-type :source-range
|
:range-source-type :source-range
|
||||||
:value 11
|
:value 11
|
||||||
:prev-value 10
|
:prev-value 10
|
||||||
:type :int-range-inclusive}
|
:type :int-range-inclusive}
|
||||||
{:boundary-type :end
|
{:boundary-type :end
|
||||||
:range-source-type :source-range
|
:range-source-type :source-range
|
||||||
:value 15
|
:value 15
|
||||||
:next-value 16
|
:next-value 16
|
||||||
:type :int-range-inclusive}]))))
|
:type :int-range-inclusive}]))))
|
||||||
(testing "filter-ranges after source-ranges"
|
(testing "filter-ranges after source-ranges"
|
||||||
(is (= #{(int-range-inclusive 1 5)}
|
(is (= #{(int-range-inclusive 1 5)}
|
||||||
(range/walk-range-boundaries [{:boundary-type :start
|
(into #{} (#'range/walk-tagged-range-boundaries-xf) [{:boundary-type :start
|
||||||
:range-source-type :source-range
|
:range-source-type :source-range
|
||||||
:value 1
|
:value 1
|
||||||
:prev-value 0
|
:prev-value 0
|
||||||
:type :int-range-inclusive}
|
:type :int-range-inclusive}
|
||||||
{:boundary-type :end
|
{:boundary-type :end
|
||||||
:range-source-type :source-range
|
:range-source-type :source-range
|
||||||
:value 5
|
:value 5
|
||||||
:next-value 6
|
:next-value 6
|
||||||
:type :int-range-inclusive}
|
:type :int-range-inclusive}
|
||||||
{:boundary-type :start
|
{:boundary-type :start
|
||||||
:range-source-type :filter-range
|
:range-source-type :filter-range
|
||||||
:prev-value 10
|
:prev-value 10
|
||||||
:value 11
|
:value 11
|
||||||
:type :int-range-inclusive}
|
:type :int-range-inclusive}
|
||||||
{:boundary-type :end
|
{:boundary-type :end
|
||||||
:range-source-type :filter-range
|
:range-source-type :filter-range
|
||||||
:value 15
|
:value 15
|
||||||
:next-value 16
|
:next-value 16
|
||||||
:type :int-range-inclusive}]))))
|
:type :int-range-inclusive}]))))
|
||||||
(testing "single filter-range between source-range"
|
(testing "single filter-range between source-range"
|
||||||
(is (= #{(int-range-inclusive 1 5)
|
(is (= #{(int-range-inclusive 1 5)
|
||||||
(int-range-inclusive 11 20)}
|
(int-range-inclusive 11 20)}
|
||||||
(range/walk-range-boundaries [{:boundary-type :start
|
(into #{} (#'range/walk-tagged-range-boundaries-xf) [{:boundary-type :start
|
||||||
:range-source-type :source-range
|
:range-source-type :source-range
|
||||||
:value 1
|
:value 1
|
||||||
:prev-value 0
|
:prev-value 0
|
||||||
:type :int-range-inclusive}
|
:type :int-range-inclusive}
|
||||||
{:boundary-type :start
|
{:boundary-type :start
|
||||||
:range-source-type :filter-range
|
:range-source-type :filter-range
|
||||||
:prev-value 5
|
:prev-value 5
|
||||||
:value 6
|
:value 6
|
||||||
:type :int-range-inclusive}
|
:type :int-range-inclusive}
|
||||||
{:boundary-type :end
|
{:boundary-type :end
|
||||||
:range-source-type :filter-range
|
:range-source-type :filter-range
|
||||||
:value 10
|
:value 10
|
||||||
:next-value 11
|
:next-value 11
|
||||||
:type :int-range-inclusive}
|
:type :int-range-inclusive}
|
||||||
{:boundary-type :end
|
{:boundary-type :end
|
||||||
:range-source-type :source-range
|
:range-source-type :source-range
|
||||||
:value 20
|
:value 20
|
||||||
:next-value 21
|
:next-value 21
|
||||||
:type :int-range-inclusive}]))))
|
:type :int-range-inclusive}]))))
|
||||||
(testing "single filter-range between source-range but ends align"
|
(testing "single filter-range between source-range but ends align"
|
||||||
(is (= #{(int-range-inclusive 1 5)}
|
(is (= #{(int-range-inclusive 1 5)}
|
||||||
(range/walk-range-boundaries [{:boundary-type :start
|
(into #{} (#'range/walk-tagged-range-boundaries-xf) [{:boundary-type :start
|
||||||
:range-source-type :source-range
|
:range-source-type :source-range
|
||||||
:value 1
|
:value 1
|
||||||
:prev-value 0
|
:prev-value 0
|
||||||
:type :int-range-inclusive}
|
:type :int-range-inclusive}
|
||||||
{:boundary-type :start
|
{:boundary-type :start
|
||||||
:range-source-type :filter-range
|
:range-source-type :filter-range
|
||||||
:prev-value 5
|
:prev-value 5
|
||||||
:value 6
|
:value 6
|
||||||
:type :int-range-inclusive}
|
:type :int-range-inclusive}
|
||||||
{:boundary-type :end
|
{:boundary-type :end
|
||||||
:range-source-type :source-range
|
:range-source-type :source-range
|
||||||
:value 10
|
:value 10
|
||||||
:next-value 11
|
:next-value 11
|
||||||
:type :int-range-inclusive}
|
:type :int-range-inclusive}
|
||||||
{:boundary-type :end
|
{:boundary-type :end
|
||||||
:range-source-type :filter-range
|
:range-source-type :filter-range
|
||||||
:value 10
|
:value 10
|
||||||
:next-value 11
|
:next-value 11
|
||||||
:type :int-range-inclusive}]))))
|
:type :int-range-inclusive}]))))
|
||||||
(testing "multiple filter-ranges between source-range"
|
(testing "multiple filter-ranges between source-range"
|
||||||
(is (= #{(int-range-inclusive 1 5)
|
(is (= #{(int-range-inclusive 1 5)
|
||||||
(int-range-inclusive 11 12)
|
(int-range-inclusive 11 12)
|
||||||
(int-range-inclusive 20 20)}
|
(int-range-inclusive 20 20)}
|
||||||
(range/walk-range-boundaries [{:boundary-type :start
|
(into #{} (#'range/walk-tagged-range-boundaries-xf) [{:boundary-type :start
|
||||||
:range-source-type :source-range
|
:range-source-type :source-range
|
||||||
:value 1
|
:value 1
|
||||||
:prev-value 0
|
:prev-value 0
|
||||||
:type :int-range-inclusive}
|
:type :int-range-inclusive}
|
||||||
{:boundary-type :start
|
{:boundary-type :start
|
||||||
:range-source-type :filter-range
|
:range-source-type :filter-range
|
||||||
:prev-value 5
|
:prev-value 5
|
||||||
:value 6
|
:value 6
|
||||||
:type :int-range-inclusive}
|
:type :int-range-inclusive}
|
||||||
{:boundary-type :end
|
{:boundary-type :end
|
||||||
:range-source-type :filter-range
|
:range-source-type :filter-range
|
||||||
:value 10
|
:value 10
|
||||||
:next-value 11
|
:next-value 11
|
||||||
:type :int-range-inclusive}
|
:type :int-range-inclusive}
|
||||||
{:boundary-type :start
|
{:boundary-type :start
|
||||||
:range-source-type :filter-range
|
:range-source-type :filter-range
|
||||||
:prev-value 12
|
:prev-value 12
|
||||||
:value 13
|
:value 13
|
||||||
:type :int-range-inclusive}
|
:type :int-range-inclusive}
|
||||||
{:boundary-type :end
|
{:boundary-type :end
|
||||||
:range-source-type :filter-range
|
:range-source-type :filter-range
|
||||||
:value 19
|
:value 19
|
||||||
:next-value 20
|
:next-value 20
|
||||||
:type :int-range-inclusive}
|
:type :int-range-inclusive}
|
||||||
{:boundary-type :end
|
{:boundary-type :end
|
||||||
:range-source-type :source-range
|
:range-source-type :source-range
|
||||||
:value 20
|
:value 20
|
||||||
:prev-value 19
|
:prev-value 19
|
||||||
:type :int-range-inclusive}]))))
|
:type :int-range-inclusive}]))))
|
||||||
(testing "source range between filter-range"
|
(testing "source range between filter-range"
|
||||||
(is (= #{}
|
(is (= #{}
|
||||||
(range/walk-range-boundaries [{:boundary-type :start
|
(into #{} (#'range/walk-tagged-range-boundaries-xf) [{:boundary-type :start
|
||||||
:range-source-type :filter-range
|
:range-source-type :filter-range
|
||||||
:prev-value 1
|
:prev-value 1
|
||||||
:value 1
|
:value 1
|
||||||
:type :int-range-inclusive}
|
:type :int-range-inclusive}
|
||||||
{:boundary-type :start
|
{:boundary-type :start
|
||||||
:range-source-type :source-range
|
:range-source-type :source-range
|
||||||
:value 6
|
:value 6
|
||||||
:prev-value 5
|
:prev-value 5
|
||||||
:type :int-range-inclusive}
|
:type :int-range-inclusive}
|
||||||
{:boundary-type :end
|
{:boundary-type :end
|
||||||
:range-source-type :source-range
|
:range-source-type :source-range
|
||||||
:value 10
|
:value 10
|
||||||
:next-value 11
|
:next-value 11
|
||||||
:type :int-range-inclusive}
|
:type :int-range-inclusive}
|
||||||
{:boundary-type :start
|
{:boundary-type :start
|
||||||
:range-source-type :source-range
|
:range-source-type :source-range
|
||||||
:value 13
|
:value 13
|
||||||
:prev-value 12
|
:prev-value 12
|
||||||
:type :int-range-inclusive}
|
:type :int-range-inclusive}
|
||||||
{:boundary-type :end
|
{:boundary-type :end
|
||||||
:range-source-type :source-range
|
:range-source-type :source-range
|
||||||
:value 19
|
:value 19
|
||||||
:next-value 20
|
:next-value 20
|
||||||
:type :int-range-inclusive}
|
:type :int-range-inclusive}
|
||||||
{:boundary-type :end
|
{:boundary-type :end
|
||||||
:range-source-type :filter-range
|
:range-source-type :filter-range
|
||||||
:value 20
|
:value 20
|
||||||
:next-value 21
|
:next-value 21
|
||||||
:type :int-range-inclusive}]))))
|
:type :int-range-inclusive}]))))
|
||||||
(testing "filter range overlaps source ranges"
|
(testing "filter range overlaps source ranges"
|
||||||
(is (= #{(int-range-inclusive 1 4)
|
(is (= #{(int-range-inclusive 1 4)
|
||||||
(int-range-inclusive 11 13)}
|
(int-range-inclusive 11 13)}
|
||||||
(range/walk-range-boundaries [{:boundary-type :start
|
(into #{} (#'range/walk-tagged-range-boundaries-xf) [{:boundary-type :start
|
||||||
:range-source-type :source-range
|
:range-source-type :source-range
|
||||||
:value 1
|
:value 1
|
||||||
:prev-value 0
|
:prev-value 0
|
||||||
:type :int-range-inclusive}
|
:type :int-range-inclusive}
|
||||||
{:boundary-type :start
|
{:boundary-type :start
|
||||||
:range-source-type :filter-range
|
:range-source-type :filter-range
|
||||||
:prev-value 4
|
:prev-value 4
|
||||||
:value 5
|
:value 5
|
||||||
:type :int-range-inclusive}
|
:type :int-range-inclusive}
|
||||||
{:boundary-type :end
|
{:boundary-type :end
|
||||||
:range-source-type :source-range
|
:range-source-type :source-range
|
||||||
:value 6
|
:value 6
|
||||||
:next-value 7
|
:next-value 7
|
||||||
:type :int-range-inclusive}
|
:type :int-range-inclusive}
|
||||||
{:boundary-type :start
|
{:boundary-type :start
|
||||||
:range-source-type :source-range
|
:range-source-type :source-range
|
||||||
:value 8
|
:value 8
|
||||||
:prev-value 7
|
:prev-value 7
|
||||||
:type :int-range-inclusive}
|
:type :int-range-inclusive}
|
||||||
{:boundary-type :end
|
{:boundary-type :end
|
||||||
:range-source-type :filter-range
|
:range-source-type :filter-range
|
||||||
:value 10
|
:value 10
|
||||||
:next-value 11
|
:next-value 11
|
||||||
:type :int-range-inclusive}
|
:type :int-range-inclusive}
|
||||||
{:boundary-type :end
|
{:boundary-type :end
|
||||||
:range-source-type :source-range
|
:range-source-type :source-range
|
||||||
:value 13
|
:value 13
|
||||||
:next-value 14
|
:next-value 14
|
||||||
:type :int-range-inclusive}])))))
|
:type :int-range-inclusive}])))))
|
||||||
|
|
||||||
(deftest difference-test
|
(deftest difference-test
|
||||||
(testing "unary"
|
(testing "unary"
|
||||||
|
|||||||
Reference in New Issue
Block a user