diff --git a/README.md b/README.md index 93777c6fe..c9bca82ec 100644 --- a/README.md +++ b/README.md @@ -201,6 +201,8 @@ Currently, the `@compat` macro supports the following syntaxes: * `IOContext` accepting key-value `Pair`s ([#23271]). +* `pairs` for iterating over key-value `Pair`s ([#22907]). + * `get` do-block syntax supported when using `ENV` ([#23412]). ## Renaming @@ -368,6 +370,7 @@ includes this fix. Find the minimum version from there. [#22751]: https://github.com/JuliaLang/julia/issues/22751 [#22761]: https://github.com/JuliaLang/julia/issues/22761 [#22864]: https://github.com/JuliaLang/julia/issues/22864 +[#22907]: https://github.com/JuliaLang/julia/issues/22907 [#23051]: https://github.com/JuliaLang/julia/issues/23051 [#23235]: https://github.com/JuliaLang/julia/issues/23235 [#23271]: https://github.com/JuliaLang/julia/issues/23271 diff --git a/src/Compat.jl b/src/Compat.jl index 3cd332ef6..676e196f8 100644 --- a/src/Compat.jl +++ b/src/Compat.jl @@ -673,6 +673,51 @@ end export partialsort, partialsort!, partialsortperm, partialsortperm! end +# 0.7.0-DEV.1660 +@static if !isdefined(Base, :pairs) + pairs(collection) = Base.Generator(=>, keys(collection), values(collection)) + pairs(a::Associative) = a + + # 0.6.0-dev+2834 + @static if !isdefined(Iterators, :IndexValue) + include_string(@__MODULE__, """ + immutable IndexValue{I,A<:AbstractArray} + data::A + itr::I + end + """) + + Base.length(v::IndexValue) = length(v.itr) + Base.indices(v::IndexValue) = indices(v.itr) + Base.size(v::IndexValue) = size(v.itr) + @inline Base.start(v::IndexValue) = start(v.itr) + Base.@propagate_inbounds function Base.next(v::IndexValue, state) + indx, n = next(v.itr, state) + item = v.data[indx] + (indx => item), n + end + @inline Base.done(v::IndexValue, state) = done(v.itr, state) + + Base.eltype{I,A}(::Type{IndexValue{I,A}}) = Pair{eltype(I), eltype(A)} + + Base.iteratorsize{I}(::Type{IndexValue{I}}) = iteratorsize(I) + Base.iteratoreltype{I}(::Type{IndexValue{I}}) = iteratoreltype(I) + + Base.reverse(v::IndexValue) = IndexValue(v.data, reverse(v.itr)) + else + const IndexValue = Iterators.IndexValue + end + + pairs(::IndexLinear, A::AbstractArray) = IndexValue(A, linearindices(A)) + pairs(::IndexCartesian, A::AbstractArray) = IndexValue(A, CartesianRange(indices(A))) + + Base.keys(a::AbstractArray) = CartesianRange(indices(a)) + Base.keys(a::AbstractVector) = linearindices(a) + Base.keys(s::IndexStyle, A::AbstractArray, B::AbstractArray...) = eachindex(s, A, B...) + + Base.values(itr) = itr +end + # 0.7.0-DEV.1721 @static if !isdefined(Base, :AbstractRange) const AbstractRange = Range diff --git a/test/runtests.jl b/test/runtests.jl index 51700611b..05afe97e0 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -741,6 +741,34 @@ let x = fill!(StringVector(5), 0x61) @test pointer(x) == pointer(String(x)) end +# PR 22907 +using Compat: pairs + +# keys, values, pairs +for A in (rand(2), rand(2,3)) + local A + for (i, v) in pairs(A) + @test A[i] == v + end + @test collect(values(A)) == collect(A) +end + +let A = Dict(:foo=>1, :bar=>3) + for (k, v) in pairs(A) + @test A[k] == v + end + @test sort!(collect(pairs(A))) == sort!(collect(A)) +end + +let + A14 = [11 13; 12 14] + R = CartesianRange(indices(A14)) + @test [a for (a,b) in pairs(IndexLinear(), A14)] == [1,2,3,4] + @test [a for (a,b) in pairs(IndexCartesian(), A14)] == vec(collect(R)) + @test [b for (a,b) in pairs(IndexLinear(), A14)] == [11,12,13,14] + @test [b for (a,b) in pairs(IndexCartesian(), A14)] == [11,12,13,14] +end + # Val(x) # 0.7 begin