From 5e4c0d8a0cb12b1b48c48926035262a5cdc71899 Mon Sep 17 00:00:00 2001 From: Neven Sajko Date: Wed, 9 Jul 2025 01:20:06 +0200 Subject: [PATCH 01/14] add `sliding_window_maxima` Feature addition: add iterator whose elements are maxima of a sliding window over an original iterator. --- src/IterTools.jl | 144 ++++++++++++++++++++++++++++++++++++++++++++++- test/runtests.jl | 12 ++++ 2 files changed, 155 insertions(+), 1 deletion(-) diff --git a/src/IterTools.jl b/src/IterTools.jl index 1211bb9..dbbe42e 100644 --- a/src/IterTools.jl +++ b/src/IterTools.jl @@ -35,7 +35,8 @@ export fieldvalues, interleaveby, cache, - zip_longest + zip_longest, + sliding_window_maxima function has_length(it) it_size = IteratorSize(it) @@ -1235,4 +1236,145 @@ t = ('e', 'x') """ zip_longest(its...; default=nothing) = ZipLongest(Tuple(_Padded.(its, default))) +module ValidatedPositiveInt + export validated_positive_int + @noinline function throw_err_not_positive() + throw(ArgumentError("not positive")) + end + Base.@constprop :aggressive function validated_positive_int(m::Int) + if m < 1 + @noinline throw_err_not_positive() + end + m + end +end + +module SlidingWindowMaximumIterators + export SlidingWindowMaximumIterator + using ..ValidatedPositiveInt + struct SlidingWindowMaximumIterator{WindowSize, Iterator, Ord <: Base.Order.Ordering} + iterator::Iterator + order::Ord + Base.@constprop :aggressive function SlidingWindowMaximumIterator{WindowSize}(iterator, order::Base.Order.Ordering) where {WindowSize} + s = validated_positive_int(WindowSize) + new{s, typeof(iterator), typeof(order)}(iterator, order) + end + end + function Base.IteratorSize(::Type{<:SlidingWindowMaximumIterator}) + Base.SizeUnknown() + end + function Base.IteratorEltype(::Type{<:SlidingWindowMaximumIterator{<:Any, Iterator}}) where {Iterator} + Base.IteratorEltype(Iterator) + end + function Base.eltype(::Type{<:SlidingWindowMaximumIterator{<:Any, Iterator}}) where {Iterator} + eltype(Iterator) + end + Base.@constprop :aggressive function get_window_size(::SlidingWindowMaximumIterator{WindowSize}) where {WindowSize} + validated_positive_int(WindowSize) + end + # `window_queue` is logically a double-ended queue data structure: only mutating it + # with `pop!`, `popfirst` and `push!`. + Base.@assume_effects :terminates_locally function _iterate(iterator::SlidingWindowMaximumIterator, state::Tuple{Any}) + (window_queue, counter, inner_iterator_state_initial) = state[1] + counter = counter::Int + iter = iterate(iterator.iterator, inner_iterator_state_initial) + if iter === nothing + return iter + end + (elem, inner_iterator_state) = iter + order = iterator.order + while (!isempty(window_queue)) && Base.Order.lt(order, window_queue[end][1], elem) + pop!(window_queue) + end + if (!isempty(window_queue)) && (get_window_size(iterator) ≤ counter - window_queue[1][2]::Int) + popfirst!(window_queue) + end + push!(window_queue, (elem, counter)) + next_state = (window_queue, counter + 1, inner_iterator_state) + (window_queue[1][1], (next_state,)) + end + Base.@assume_effects :terminates_locally function _iterate(iterator::SlidingWindowMaximumIterator, ::Tuple{}) + inner_iterator = iterator.iterator + iter_initial = iterate(inner_iterator) + if iter_initial === nothing + return iter_initial + end + (elem_initial, inner_iterator_state) = iter_initial + window_size = get_window_size(iterator) + counter = 0 + window_queue = [(elem_initial, counter)] + order = iterator.order + for _ ∈ 2:window_size + iter = iterate(inner_iterator, inner_iterator_state) + if iter === nothing + return iter + end + (elem, inner_iterator_state) = iter + while (!isempty(window_queue)) && Base.Order.lt(order, window_queue[end][1], elem) + pop!(window_queue) + end + counter = counter + 1 + push!(window_queue, (elem, counter)) + end + state = (window_queue, counter + 1, inner_iterator_state) + (window_queue[1][1], (state,)) + end + function Base.iterate(iterator::SlidingWindowMaximumIterator, state = ()) + _iterate(iterator, state) + end +end + +""" + sliding_window_maxima(window_size, iterator, [order::Base.Order.Ordering]) + +An iterator. Each element is the maximum of a sliding window of size `window_size`, with +the original elements being taken from the other iterator, `iterator`. + +```jldoctest +julia> v = rand(Float32, 5) +5-element Vector{Float32}: + 0.17564094 + 0.73419166 + 0.7873744 + 0.4568473 + 0.9182026 + +julia> collect(sliding_window_maxima(1, v)) == v +true + +julia> collect(sliding_window_maxima(2, v)) +4-element Vector{Float32}: + 0.73419166 + 0.7873744 + 0.7873744 + 0.9182026 + +julia> collect(sliding_window_maxima(3, v)) +3-element Vector{Float32}: + 0.7873744 + 0.7873744 + 0.9182026 +``` + +The optional argument `order` determines how the maximum is computed. + +```jldoctest +julia> collect(sliding_window_maxima(3, 1:5)) +3-element Vector{Int64}: + 3 + 4 + 5 + +julia> collect(sliding_window_maxima(3, 1:5, Base.Order.Reverse)) +3-element Vector{Int64}: + 1 + 2 + 3 +``` +""" +Base.@constprop :aggressive function sliding_window_maxima(window_size::Integer, iterator, order::Base.Order.Ordering = Base.Order.Forward) + s = Int(window_size) + SlidingWindowMaximumIterators.SlidingWindowMaximumIterator{s}(iterator, order) +end + end # module IterTools diff --git a/test/runtests.jl b/test/runtests.jl index 6aa6372..b4b44be 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -612,5 +612,17 @@ include("testing_macros.jl") @test collect(it_mixed) == [(1,10),(2,9),(3,8),(4,' '),(5, ' ')] @test eltype(it_mixed) == Tuple{Union{Missing, Int}, Union{Char, Int}} end + + @testset "sliding_window_maxima" begin + function inferrable_due_to_constprop(iterator) + sliding_window_maxima(2, iterator) + end + vec = Float32[1, 2, 3, 3, 4, 5, 4] + iter = @inferred inferrable_due_to_constprop(vec) + @test (@inferred collect(iter)) isa Vector{Float32} + @test collect(sliding_window_maxima(1, vec))::Vector{Float32} == vec + @test collect(sliding_window_maxima(2, vec))::Vector{Float32} == [2, 3, 3, 4, 5, 5] + @test collect(sliding_window_maxima(3, vec))::Vector{Float32} == [3, 3, 4, 5, 5] + end end end From ca13caab091132bfaf98d8e622de58c412c6b423 Mon Sep 17 00:00:00 2001 From: Neven Sajko Date: Wed, 9 Jul 2025 02:06:49 +0200 Subject: [PATCH 02/14] fix doc test --- src/IterTools.jl | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/IterTools.jl b/src/IterTools.jl index dbbe42e..e25b775 100644 --- a/src/IterTools.jl +++ b/src/IterTools.jl @@ -1331,29 +1331,29 @@ An iterator. Each element is the maximum of a sliding window of size `window_siz the original elements being taken from the other iterator, `iterator`. ```jldoctest -julia> v = rand(Float32, 5) +julia> v = Float32[1, 7, 7, 4, 9] 5-element Vector{Float32}: - 0.17564094 - 0.73419166 - 0.7873744 - 0.4568473 - 0.9182026 + 1.0 + 7.0 + 7.0 + 4.0 + 9.0 julia> collect(sliding_window_maxima(1, v)) == v true julia> collect(sliding_window_maxima(2, v)) 4-element Vector{Float32}: - 0.73419166 - 0.7873744 - 0.7873744 - 0.9182026 + 7.0 + 7.0 + 7.0 + 9.0 julia> collect(sliding_window_maxima(3, v)) 3-element Vector{Float32}: - 0.7873744 - 0.7873744 - 0.9182026 + 7.0 + 7.0 + 9.0 ``` The optional argument `order` determines how the maximum is computed. From 81176e25b5e5743c7f2fd9e70c6c63f1c4c7e3ef Mon Sep 17 00:00:00 2001 From: Neven Sajko Date: Wed, 9 Jul 2025 02:09:33 +0200 Subject: [PATCH 03/14] test reverse order --- test/runtests.jl | 1 + 1 file changed, 1 insertion(+) diff --git a/test/runtests.jl b/test/runtests.jl index b4b44be..0315783 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -623,6 +623,7 @@ include("testing_macros.jl") @test collect(sliding_window_maxima(1, vec))::Vector{Float32} == vec @test collect(sliding_window_maxima(2, vec))::Vector{Float32} == [2, 3, 3, 4, 5, 5] @test collect(sliding_window_maxima(3, vec))::Vector{Float32} == [3, 3, 4, 5, 5] + @test collect(sliding_window_maxima(3, vec, Base.Order.Reverse))::Vector{Float32} == [1, 2, 3, 3, 3] end end end From 47fc506bb19b77520467f21d105e5905eb6488c6 Mon Sep 17 00:00:00 2001 From: Neven Sajko Date: Wed, 9 Jul 2025 02:11:56 +0200 Subject: [PATCH 04/14] fix test --- test/runtests.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/runtests.jl b/test/runtests.jl index 0315783..9a52ba9 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -623,7 +623,7 @@ include("testing_macros.jl") @test collect(sliding_window_maxima(1, vec))::Vector{Float32} == vec @test collect(sliding_window_maxima(2, vec))::Vector{Float32} == [2, 3, 3, 4, 5, 5] @test collect(sliding_window_maxima(3, vec))::Vector{Float32} == [3, 3, 4, 5, 5] - @test collect(sliding_window_maxima(3, vec, Base.Order.Reverse))::Vector{Float32} == [1, 2, 3, 3, 3] + @test collect(sliding_window_maxima(3, vec, Base.Order.Reverse))::Vector{Float32} == [1, 2, 3, 3, 4] end end end From b3b81f189c9884a70950b8b1f642650a4c9a1769 Mon Sep 17 00:00:00 2001 From: Neven Sajko Date: Wed, 9 Jul 2025 02:15:42 +0200 Subject: [PATCH 05/14] test: fix code coverage --- test/runtests.jl | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/runtests.jl b/test/runtests.jl index 9a52ba9..01a812d 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -624,6 +624,8 @@ include("testing_macros.jl") @test collect(sliding_window_maxima(2, vec))::Vector{Float32} == [2, 3, 3, 4, 5, 5] @test collect(sliding_window_maxima(3, vec))::Vector{Float32} == [3, 3, 4, 5, 5] @test collect(sliding_window_maxima(3, vec, Base.Order.Reverse))::Vector{Float32} == [1, 2, 3, 3, 4] + @test collect(sliding_window_maxima(100, vec))::Vector{Float32} == [] + @test_throws ArgumentError sliding_window_maxima(-1, vec) end end end From 5858b2f109f0eb1a335eec6a0283820ac4092469 Mon Sep 17 00:00:00 2001 From: Neven Sajko Date: Wed, 9 Jul 2025 02:18:33 +0200 Subject: [PATCH 06/14] really fix code coverage --- test/runtests.jl | 1 + 1 file changed, 1 insertion(+) diff --git a/test/runtests.jl b/test/runtests.jl index 01a812d..2340dfa 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -625,6 +625,7 @@ include("testing_macros.jl") @test collect(sliding_window_maxima(3, vec))::Vector{Float32} == [3, 3, 4, 5, 5] @test collect(sliding_window_maxima(3, vec, Base.Order.Reverse))::Vector{Float32} == [1, 2, 3, 3, 4] @test collect(sliding_window_maxima(100, vec))::Vector{Float32} == [] + @test collect(sliding_window_maxima(1, Float32[]))::Vector{Float32} == [] @test_throws ArgumentError sliding_window_maxima(-1, vec) end end From 2517b696acbf4b66366329ca0a396647e8b93533 Mon Sep 17 00:00:00 2001 From: Neven Sajko Date: Sat, 26 Jul 2025 01:12:47 +0200 Subject: [PATCH 07/14] stricter argument type constraint for `_iterate` --- src/IterTools.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/IterTools.jl b/src/IterTools.jl index e25b775..7df5d74 100644 --- a/src/IterTools.jl +++ b/src/IterTools.jl @@ -1274,7 +1274,7 @@ module SlidingWindowMaximumIterators end # `window_queue` is logically a double-ended queue data structure: only mutating it # with `pop!`, `popfirst` and `push!`. - Base.@assume_effects :terminates_locally function _iterate(iterator::SlidingWindowMaximumIterator, state::Tuple{Any}) + Base.@assume_effects :terminates_locally function _iterate(iterator::SlidingWindowMaximumIterator, state::Tuple{Tuple{(Vector{Tuple{T, Int}} where {T}), Int, Any}}) (window_queue, counter, inner_iterator_state_initial) = state[1] counter = counter::Int iter = iterate(iterator.iterator, inner_iterator_state_initial) From 3b759121c90dd813b3cf7faef29c241454f61e26 Mon Sep 17 00:00:00 2001 From: Neven Sajko Date: Sat, 26 Jul 2025 01:25:35 +0200 Subject: [PATCH 08/14] refrain from `assume_effects` --- src/IterTools.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/IterTools.jl b/src/IterTools.jl index 7df5d74..6914171 100644 --- a/src/IterTools.jl +++ b/src/IterTools.jl @@ -1274,7 +1274,7 @@ module SlidingWindowMaximumIterators end # `window_queue` is logically a double-ended queue data structure: only mutating it # with `pop!`, `popfirst` and `push!`. - Base.@assume_effects :terminates_locally function _iterate(iterator::SlidingWindowMaximumIterator, state::Tuple{Tuple{(Vector{Tuple{T, Int}} where {T}), Int, Any}}) + function _iterate(iterator::SlidingWindowMaximumIterator, state::Tuple{Tuple{(Vector{Tuple{T, Int}} where {T}), Int, Any}}) (window_queue, counter, inner_iterator_state_initial) = state[1] counter = counter::Int iter = iterate(iterator.iterator, inner_iterator_state_initial) @@ -1293,7 +1293,7 @@ module SlidingWindowMaximumIterators next_state = (window_queue, counter + 1, inner_iterator_state) (window_queue[1][1], (next_state,)) end - Base.@assume_effects :terminates_locally function _iterate(iterator::SlidingWindowMaximumIterator, ::Tuple{}) + function _iterate(iterator::SlidingWindowMaximumIterator, ::Tuple{}) inner_iterator = iterator.iterator iter_initial = iterate(inner_iterator) if iter_initial === nothing From 694ffbdf014c33a6443c4543dbf526b3e8f8e643 Mon Sep 17 00:00:00 2001 From: Neven Sajko Date: Sat, 26 Jul 2025 01:34:20 +0200 Subject: [PATCH 09/14] expand signature in doc string --- src/IterTools.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/IterTools.jl b/src/IterTools.jl index 6914171..3a01b57 100644 --- a/src/IterTools.jl +++ b/src/IterTools.jl @@ -1325,7 +1325,7 @@ module SlidingWindowMaximumIterators end """ - sliding_window_maxima(window_size, iterator, [order::Base.Order.Ordering]) + sliding_window_maxima(window_size::Integer, iterator, [order::Base.Order.Ordering]) An iterator. Each element is the maximum of a sliding window of size `window_size`, with the original elements being taken from the other iterator, `iterator`. From 0570aa211fa3a50941b725a61a4bef49bb117b95 Mon Sep 17 00:00:00 2001 From: Neven Sajko Date: Sat, 26 Jul 2025 09:41:36 +0200 Subject: [PATCH 10/14] make the iterator type not depend on the window size Should mean better type stability for users. --- src/IterTools.jl | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/IterTools.jl b/src/IterTools.jl index 3a01b57..6fcc0ee 100644 --- a/src/IterTools.jl +++ b/src/IterTools.jl @@ -1252,25 +1252,26 @@ end module SlidingWindowMaximumIterators export SlidingWindowMaximumIterator using ..ValidatedPositiveInt - struct SlidingWindowMaximumIterator{WindowSize, Iterator, Ord <: Base.Order.Ordering} + struct SlidingWindowMaximumIterator{Iterator, Ord <: Base.Order.Ordering} + window_size::Int iterator::Iterator order::Ord - Base.@constprop :aggressive function SlidingWindowMaximumIterator{WindowSize}(iterator, order::Base.Order.Ordering) where {WindowSize} - s = validated_positive_int(WindowSize) - new{s, typeof(iterator), typeof(order)}(iterator, order) + Base.@constprop :aggressive function SlidingWindowMaximumIterator(window_size::Int, iterator, order::Base.Order.Ordering) + s = validated_positive_int(window_size) + new{typeof(iterator), typeof(order)}(s, iterator, order) end end function Base.IteratorSize(::Type{<:SlidingWindowMaximumIterator}) Base.SizeUnknown() end - function Base.IteratorEltype(::Type{<:SlidingWindowMaximumIterator{<:Any, Iterator}}) where {Iterator} + function Base.IteratorEltype(::Type{<:SlidingWindowMaximumIterator{Iterator}}) where {Iterator} Base.IteratorEltype(Iterator) end - function Base.eltype(::Type{<:SlidingWindowMaximumIterator{<:Any, Iterator}}) where {Iterator} + function Base.eltype(::Type{<:SlidingWindowMaximumIterator{Iterator}}) where {Iterator} eltype(Iterator) end - Base.@constprop :aggressive function get_window_size(::SlidingWindowMaximumIterator{WindowSize}) where {WindowSize} - validated_positive_int(WindowSize) + Base.@constprop :aggressive function get_window_size(iterator::SlidingWindowMaximumIterator) + iterator.window_size end # `window_queue` is logically a double-ended queue data structure: only mutating it # with `pop!`, `popfirst` and `push!`. @@ -1374,7 +1375,7 @@ julia> collect(sliding_window_maxima(3, 1:5, Base.Order.Reverse)) """ Base.@constprop :aggressive function sliding_window_maxima(window_size::Integer, iterator, order::Base.Order.Ordering = Base.Order.Forward) s = Int(window_size) - SlidingWindowMaximumIterators.SlidingWindowMaximumIterator{s}(iterator, order) + SlidingWindowMaximumIterators.SlidingWindowMaximumIterator(s, iterator, order) end end # module IterTools From d43d1a360f3f50d9721c155b81427a37399b3357 Mon Sep 17 00:00:00 2001 From: Neven Sajko Date: Sat, 26 Jul 2025 10:12:19 +0200 Subject: [PATCH 11/14] deduplicate code, change loop for two loops with simpler bodies --- src/IterTools.jl | 35 ++++++++++++++++++++++++++++------- 1 file changed, 28 insertions(+), 7 deletions(-) diff --git a/src/IterTools.jl b/src/IterTools.jl index 6fcc0ee..d74c330 100644 --- a/src/IterTools.jl +++ b/src/IterTools.jl @@ -1249,9 +1249,26 @@ module ValidatedPositiveInt end end +module DeleteFromEnd + export delete_from_end! + @noinline function cannot_delete_more_than_length() + throw(ArgumentError("the collection does not have that many elements")) + end + function delete_from_end!(c::Vector, n::Int) + l = length(c) + if l < n + @noinline cannot_delete_more_than_length() + end + for _ ∈ 1:n + pop!(c) + end + c + end +end + module SlidingWindowMaximumIterators export SlidingWindowMaximumIterator - using ..ValidatedPositiveInt + using ..ValidatedPositiveInt, ..DeleteFromEnd struct SlidingWindowMaximumIterator{Iterator, Ord <: Base.Order.Ordering} window_size::Int iterator::Iterator @@ -1273,6 +1290,14 @@ module SlidingWindowMaximumIterators Base.@constprop :aggressive function get_window_size(iterator::SlidingWindowMaximumIterator) iterator.window_size end + function delete_all_lesser_from_end!(window_queue::Vector, order::Base.Order.Ordering, elem) + pop_count = 0 + len = length(window_queue) + while (pop_count < len) && Base.Order.lt(order, window_queue[end - pop_count][1], elem) + pop_count = pop_count + 1 + end + delete_from_end!(window_queue, pop_count) + end # `window_queue` is logically a double-ended queue data structure: only mutating it # with `pop!`, `popfirst` and `push!`. function _iterate(iterator::SlidingWindowMaximumIterator, state::Tuple{Tuple{(Vector{Tuple{T, Int}} where {T}), Int, Any}}) @@ -1284,9 +1309,7 @@ module SlidingWindowMaximumIterators end (elem, inner_iterator_state) = iter order = iterator.order - while (!isempty(window_queue)) && Base.Order.lt(order, window_queue[end][1], elem) - pop!(window_queue) - end + delete_all_lesser_from_end!(window_queue, order, elem) if (!isempty(window_queue)) && (get_window_size(iterator) ≤ counter - window_queue[1][2]::Int) popfirst!(window_queue) end @@ -1311,9 +1334,7 @@ module SlidingWindowMaximumIterators return iter end (elem, inner_iterator_state) = iter - while (!isempty(window_queue)) && Base.Order.lt(order, window_queue[end][1], elem) - pop!(window_queue) - end + delete_all_lesser_from_end!(window_queue, order, elem) counter = counter + 1 push!(window_queue, (elem, counter)) end From e6174591e4095210f15920738261bda6c17f5d16 Mon Sep 17 00:00:00 2001 From: Neven Sajko Date: Sat, 9 Aug 2025 05:48:59 +0200 Subject: [PATCH 12/14] relax argument type constraint from `Integer` to `Number` --- src/IterTools.jl | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/IterTools.jl b/src/IterTools.jl index d74c330..1128685 100644 --- a/src/IterTools.jl +++ b/src/IterTools.jl @@ -1347,10 +1347,11 @@ module SlidingWindowMaximumIterators end """ - sliding_window_maxima(window_size::Integer, iterator, [order::Base.Order.Ordering]) + sliding_window_maxima(window_size::Number, iterator, [order::Base.Order.Ordering]) An iterator. Each element is the maximum of a sliding window of size `window_size`, with -the original elements being taken from the other iterator, `iterator`. +the original elements being taken from the other iterator, `iterator`. `window_size` +must be convertible to `Int`. ```jldoctest julia> v = Float32[1, 7, 7, 4, 9] @@ -1394,7 +1395,7 @@ julia> collect(sliding_window_maxima(3, 1:5, Base.Order.Reverse)) 3 ``` """ -Base.@constprop :aggressive function sliding_window_maxima(window_size::Integer, iterator, order::Base.Order.Ordering = Base.Order.Forward) +Base.@constprop :aggressive function sliding_window_maxima(window_size::Number, iterator, order::Base.Order.Ordering = Base.Order.Forward) s = Int(window_size) SlidingWindowMaximumIterators.SlidingWindowMaximumIterator(s, iterator, order) end From 082f28763a34249520046e18f727e116e129e5de Mon Sep 17 00:00:00 2001 From: Neven Sajko Date: Sat, 9 Aug 2025 05:51:30 +0200 Subject: [PATCH 13/14] delete the `constprop` directives They're not necessary now that the iterator type does not depend on the window size. --- src/IterTools.jl | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/IterTools.jl b/src/IterTools.jl index 1128685..bebc7a3 100644 --- a/src/IterTools.jl +++ b/src/IterTools.jl @@ -1241,7 +1241,7 @@ module ValidatedPositiveInt @noinline function throw_err_not_positive() throw(ArgumentError("not positive")) end - Base.@constprop :aggressive function validated_positive_int(m::Int) + function validated_positive_int(m::Int) if m < 1 @noinline throw_err_not_positive() end @@ -1273,7 +1273,7 @@ module SlidingWindowMaximumIterators window_size::Int iterator::Iterator order::Ord - Base.@constprop :aggressive function SlidingWindowMaximumIterator(window_size::Int, iterator, order::Base.Order.Ordering) + function SlidingWindowMaximumIterator(window_size::Int, iterator, order::Base.Order.Ordering) s = validated_positive_int(window_size) new{typeof(iterator), typeof(order)}(s, iterator, order) end @@ -1287,7 +1287,7 @@ module SlidingWindowMaximumIterators function Base.eltype(::Type{<:SlidingWindowMaximumIterator{Iterator}}) where {Iterator} eltype(Iterator) end - Base.@constprop :aggressive function get_window_size(iterator::SlidingWindowMaximumIterator) + function get_window_size(iterator::SlidingWindowMaximumIterator) iterator.window_size end function delete_all_lesser_from_end!(window_queue::Vector, order::Base.Order.Ordering, elem) @@ -1395,7 +1395,7 @@ julia> collect(sliding_window_maxima(3, 1:5, Base.Order.Reverse)) 3 ``` """ -Base.@constprop :aggressive function sliding_window_maxima(window_size::Number, iterator, order::Base.Order.Ordering = Base.Order.Forward) +function sliding_window_maxima(window_size::Number, iterator, order::Base.Order.Ordering = Base.Order.Forward) s = Int(window_size) SlidingWindowMaximumIterators.SlidingWindowMaximumIterator(s, iterator, order) end From b5897623e71ad3b9467c2f39f831b67a6fe980d1 Mon Sep 17 00:00:00 2001 From: Neven Sajko Date: Sat, 9 Aug 2025 05:57:21 +0200 Subject: [PATCH 14/14] simplify test --- test/runtests.jl | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/test/runtests.jl b/test/runtests.jl index 2340dfa..ef3ca4f 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -614,11 +614,8 @@ include("testing_macros.jl") end @testset "sliding_window_maxima" begin - function inferrable_due_to_constprop(iterator) - sliding_window_maxima(2, iterator) - end vec = Float32[1, 2, 3, 3, 4, 5, 4] - iter = @inferred inferrable_due_to_constprop(vec) + iter = @inferred sliding_window_maxima(2, vec) @test (@inferred collect(iter)) isa Vector{Float32} @test collect(sliding_window_maxima(1, vec))::Vector{Float32} == vec @test collect(sliding_window_maxima(2, vec))::Vector{Float32} == [2, 3, 3, 4, 5, 5]