From ec04b899bfa8e9bd8abfd3c11b0659a4c8d727db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Legat?= Date: Wed, 31 Jul 2019 14:49:17 +0200 Subject: [PATCH 1/4] Add array utilities --- src/Bridges/utilities.jl | 63 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 src/Bridges/utilities.jl diff --git a/src/Bridges/utilities.jl b/src/Bridges/utilities.jl new file mode 100644 index 0000000000..cfc71e1a3c --- /dev/null +++ b/src/Bridges/utilities.jl @@ -0,0 +1,63 @@ +struct EmptyVector{T} <: AbstractVector{T} end +Base.isempty(::EmptyVector) = true +Base.eltype(::EmptyVector{T}) where {T} = T +Base.iterate(::EmptyVector) = nothing + +struct LazyMap{T, VT} + f::Function + data::VT +end +function LazyMap{T}(f::Function, data) where {T} + return LazyMap{T, typeof(data)}(f, data) +end +function Base.iterate(it::LazyMap, args...) + elem_state = iterate(it.data, args...) + if elem_state === nothing + return nothing + else + return it.f(elem_state[1]), elem_state[2] + end +end +Base.IteratorSize(it::LazyMap) = Base.IteratorSize(it.data) +Base.eltype(::LazyMap{T}) where {T} = T + +struct LazyFilter{T, VT} + f::Function + data::VT +end +LazyFilter(f::Function, data) = LazyFilter{eltype(data), typeof(data)}(f, data) +function Base.iterate(it::LazyFilter, args...) + elem_state = iterate(it.data, args...) + while elem_state !== nothing && !it.f(elem_state[1]) + elem_state = iterate(it.data, elem_state[2]) + end + if elem_state === nothing + return nothing + else + return elem_state + end +end +Base.IteratorSize(::LazyFilter) = Base.SizeUnknown() +Base.eltype(::LazyFilter{T}) where {T} = T + +struct LazyCat{VT} + data::VT +end +function _iterate(it::LazyCat, i, state) + while i < length(it.data) && state === nothing + i += 1 + state = iterate(it.data[i]) + end + if state === nothing + return nothing + else + return state[1], (i, state[2]) + end +end +Base.iterate(it::LazyCat) = _iterate(it, 0, nothing) +function Base.iterate(it::LazyCat, state) + i = state[1] + return _iterate(it, i, iterate(it.data[i], state[2])) +end +Base.IteratorSize(::LazyCat) = Base.SizeUnknown() +Base.IteratorEltype(::LazyCat) = Base.EltypeUnknown() From 535320c178b8e8d867d0ae24d6d620ad8cd6bea1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Legat?= Date: Thu, 1 Aug 2019 15:16:51 +0200 Subject: [PATCH 2/4] Move to Utilities --- src/{Bridges/utilities.jl => Utilities/lazy_iterators.jl} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/{Bridges/utilities.jl => Utilities/lazy_iterators.jl} (100%) diff --git a/src/Bridges/utilities.jl b/src/Utilities/lazy_iterators.jl similarity index 100% rename from src/Bridges/utilities.jl rename to src/Utilities/lazy_iterators.jl From e0eda6377fb4de70338c6855c3499806d7253f1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Legat?= Date: Thu, 1 Aug 2019 15:17:05 +0200 Subject: [PATCH 3/4] Add tests --- src/Utilities/Utilities.jl | 1 + src/Utilities/lazy_iterators.jl | 2 ++ test/Utilities/Utilities.jl | 3 +++ test/Utilities/lazy_iterators.jl | 42 ++++++++++++++++++++++++++++++++ 4 files changed, 48 insertions(+) create mode 100644 test/Utilities/lazy_iterators.jl diff --git a/src/Utilities/Utilities.jl b/src/Utilities/Utilities.jl index 6ab5ba9c8a..b7a0915c0c 100644 --- a/src/Utilities/Utilities.jl +++ b/src/Utilities/Utilities.jl @@ -30,5 +30,6 @@ include("cachingoptimizer.jl") include("universalfallback.jl") include("CleverDicts.jl") +include("lazy_iterators.jl") end # module diff --git a/src/Utilities/lazy_iterators.jl b/src/Utilities/lazy_iterators.jl index cfc71e1a3c..904e651ef6 100644 --- a/src/Utilities/lazy_iterators.jl +++ b/src/Utilities/lazy_iterators.jl @@ -1,4 +1,5 @@ struct EmptyVector{T} <: AbstractVector{T} end +Base.size(::EmptyVector) = (0,) Base.isempty(::EmptyVector) = true Base.eltype(::EmptyVector{T}) where {T} = T Base.iterate(::EmptyVector) = nothing @@ -10,6 +11,7 @@ end function LazyMap{T}(f::Function, data) where {T} return LazyMap{T, typeof(data)}(f, data) end +Base.size(it::LazyMap) = size(it.data) function Base.iterate(it::LazyMap, args...) elem_state = iterate(it.data, args...) if elem_state === nothing diff --git a/test/Utilities/Utilities.jl b/test/Utilities/Utilities.jl index df160637c0..b1d041221b 100644 --- a/test/Utilities/Utilities.jl +++ b/test/Utilities/Utilities.jl @@ -31,3 +31,6 @@ end @testset "CleverDicts" begin include("CleverDicts.jl") end +@testset "Lazy iterators" begin + include("lazy_iterators.jl") +end diff --git a/test/Utilities/lazy_iterators.jl b/test/Utilities/lazy_iterators.jl new file mode 100644 index 0000000000..1b474b1eaa --- /dev/null +++ b/test/Utilities/lazy_iterators.jl @@ -0,0 +1,42 @@ +using Test +using MathOptInterface +const MOI = MathOptInterface +const MOIU = MOI.Utilities + +@testset "EmptyVector{$T}" for T in [Int, Float64] + v = MOIU.EmptyVector{T}() + @test size(v) == (0,) + @test isempty(v) + @test eltype(v) == T + @test iterate(v) === nothing + c = collect(v) + @test c isa Vector{T} + @test isempty(c) +end + +@testset "LazyMap{$T}" for T in [Int, Float64] + v = MOIU.LazyMap{T}(x -> x^2, [2, 3]) + @test size(v) == (2,) + @test !isempty(v) + @test eltype(v) == T + c = collect(v) + @test c isa Vector{T} + @test c == [4, 9] +end + +@testset "LazyFilter{$T}" for T in [Int32, Int64] + v = MOIU.LazyFilter(isodd, T[2, 3, 5, 4]) + @test eltype(v) == T + c = collect(v) + @test c isa Vector{T} + @test c == [3, 5] +end + +@testset "LazyCat{$T}" for T in [Int, Float64] + v1 = T[2, 3] + v2 = T[5] + v = MOIU.LazyCat((v1, v2)) + c = collect(v) + @test c isa Vector{T} + @test c == T[2, 3, 5] +end From 8b30e6e06bb4e386fe96df9196aa50b5418eca8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Legat?= Date: Thu, 1 Aug 2019 16:28:36 +0200 Subject: [PATCH 4/4] Address comments --- src/Utilities/lazy_iterators.jl | 51 +++++++------------------------- test/Utilities/lazy_iterators.jl | 17 ----------- 2 files changed, 10 insertions(+), 58 deletions(-) diff --git a/src/Utilities/lazy_iterators.jl b/src/Utilities/lazy_iterators.jl index 904e651ef6..a7b44938a9 100644 --- a/src/Utilities/lazy_iterators.jl +++ b/src/Utilities/lazy_iterators.jl @@ -4,6 +4,16 @@ Base.isempty(::EmptyVector) = true Base.eltype(::EmptyVector{T}) where {T} = T Base.iterate(::EmptyVector) = nothing +""" + struct LazyMap{T, VT} + f::Function + data::VT + end + +Iterator over the elements of `data` mapped by `f`. This is similar to +`Base.Generator(f, data)` except that the `eltype` of a `LazyMap` is given at +construction while the `eltype` of `Base.Generator(f, data)` is `Any`. +""" struct LazyMap{T, VT} f::Function data::VT @@ -22,44 +32,3 @@ function Base.iterate(it::LazyMap, args...) end Base.IteratorSize(it::LazyMap) = Base.IteratorSize(it.data) Base.eltype(::LazyMap{T}) where {T} = T - -struct LazyFilter{T, VT} - f::Function - data::VT -end -LazyFilter(f::Function, data) = LazyFilter{eltype(data), typeof(data)}(f, data) -function Base.iterate(it::LazyFilter, args...) - elem_state = iterate(it.data, args...) - while elem_state !== nothing && !it.f(elem_state[1]) - elem_state = iterate(it.data, elem_state[2]) - end - if elem_state === nothing - return nothing - else - return elem_state - end -end -Base.IteratorSize(::LazyFilter) = Base.SizeUnknown() -Base.eltype(::LazyFilter{T}) where {T} = T - -struct LazyCat{VT} - data::VT -end -function _iterate(it::LazyCat, i, state) - while i < length(it.data) && state === nothing - i += 1 - state = iterate(it.data[i]) - end - if state === nothing - return nothing - else - return state[1], (i, state[2]) - end -end -Base.iterate(it::LazyCat) = _iterate(it, 0, nothing) -function Base.iterate(it::LazyCat, state) - i = state[1] - return _iterate(it, i, iterate(it.data[i], state[2])) -end -Base.IteratorSize(::LazyCat) = Base.SizeUnknown() -Base.IteratorEltype(::LazyCat) = Base.EltypeUnknown() diff --git a/test/Utilities/lazy_iterators.jl b/test/Utilities/lazy_iterators.jl index 1b474b1eaa..9da31338b6 100644 --- a/test/Utilities/lazy_iterators.jl +++ b/test/Utilities/lazy_iterators.jl @@ -23,20 +23,3 @@ end @test c isa Vector{T} @test c == [4, 9] end - -@testset "LazyFilter{$T}" for T in [Int32, Int64] - v = MOIU.LazyFilter(isodd, T[2, 3, 5, 4]) - @test eltype(v) == T - c = collect(v) - @test c isa Vector{T} - @test c == [3, 5] -end - -@testset "LazyCat{$T}" for T in [Int, Float64] - v1 = T[2, 3] - v2 = T[5] - v = MOIU.LazyCat((v1, v2)) - c = collect(v) - @test c isa Vector{T} - @test c == T[2, 3, 5] -end