diff --git a/base/abstractarray.jl b/base/abstractarray.jl index 545be629ecbdad..4fff7deb2653a0 100644 --- a/base/abstractarray.jl +++ b/base/abstractarray.jl @@ -1164,7 +1164,11 @@ function map!{F}(f::F, dest::AbstractArray, A::AbstractArray) return dest end -map{F}(f::F, A::AbstractArray) = collect(Generator(f,A)) +# map on collections +map(f, A::Union{AbstractArray,AbstractSet,Associative}) = collect_similar(A, Generator(f,A)) + +# default to returning an Array for `map` on general iterators +map(f, A) = collect(Generator(f,A)) ## 2 argument function map!{F}(f::F, dest::AbstractArray, A::AbstractArray, B::AbstractArray) @@ -1189,9 +1193,7 @@ end map!{F}(f::F, dest::AbstractArray, As::AbstractArray...) = map_n!(f, dest, As) -spread(f) = (args)->f(args...) - -map(f, iters...) = collect(Generator(spread(f),zip(iters...))) +map(f, iters...) = collect(Generator(f, iters...)) # multi-item push!, unshift! (built on top of type-specific 1-item version) # (note: must not cause a dispatch loop when 1-item case is not defined) diff --git a/base/array.jl b/base/array.jl index 07d6298cd1aa57..acd2e8ecd6d532 100644 --- a/base/array.jl +++ b/base/array.jl @@ -199,39 +199,63 @@ convert{T,n,S}(::Type{Array{T,n}}, x::AbstractArray{S,n}) = copy!(Array(T, size( promote_rule{T,n,S}(::Type{Array{T,n}}, ::Type{Array{S,n}}) = Array{promote_type(T,S),n} +## copying iterators to containers + +# make a collection similar to `c` and appropriate for collecting `itr` +_similar_for(c::AbstractArray, T, itr, ::SizeUnknown) = similar(c, T, 0) +_similar_for(c::AbstractArray, T, itr, ::HasLength) = similar(c, T, Int(length(itr)::Integer)) +_similar_for(c::AbstractArray, T, itr, ::HasShape) = similar(c, T, convert(Dims,size(itr))) +_similar_for(c, T, itr, isz) = similar(c, T) + """ collect(element_type, collection) Return an array of type `Array{element_type,1}` of all items in a collection. """ -collect{T}(::Type{T}, itr) = _collect_t(T, itr, iteratorsize(itr)) +collect{T}(::Type{T}, itr) = collect(Generator(T, itr)) """ collect(collection) Return an array of all items in a collection. For associative collections, returns Pair{KeyType, ValType}. """ -collect(itr) = _collect(itr, iteratoreltype(itr), iteratorsize(itr)) +collect(itr) = _collect(1:1 #= Array =#, itr, iteratoreltype(itr), iteratorsize(itr)) -_collect(itr, ::HasEltype, isz) = _collect_t(eltype(itr), itr, isz) +collect_similar(cont, itr) = _collect(cont, itr, iteratoreltype(itr), iteratorsize(itr)) -_collect_t(T::Type, itr, ::HasLength) = copy!(Array(T,Int(length(itr)::Integer)), itr) -_collect_t(T::Type, itr, ::HasShape) = copy!(Array(T,convert(Dims,size(itr))), itr) -function _collect_t(T::Type, itr, ::SizeUnknown) - a = Array(T,0) +_collect(cont, itr, ::HasEltype, isz::Union{HasLength,HasShape}) = + copy!(_similar_for(cont, eltype(itr), itr, isz), itr) + +function _collect(cont, itr, ::HasEltype, isz::SizeUnknown) + a = _similar_for(cont, eltype(itr), itr, isz) for x in itr push!(a,x) end return a end -_collect(itr, ::EltypeUnknown, ::HasLength) = _collect_shaped(itr, (Int(length(itr)),)) -_collect(itr, ::EltypeUnknown, ::HasShape) = _collect_shaped(itr, convert(Dims,size(itr))) +_collect(c, itr, ::EltypeUnknown, isz::SizeUnknown) = grow_to!(_similar_for(c, Union{}, itr, isz), itr) + +function _collect(c, itr, ::EltypeUnknown, isz::Union{HasLength,HasShape}) + st = start(itr) + if done(itr,st) + return _similar_for(c, Union{}, itr, isz) + end + v1, st = next(itr, st) + collect_to_with_first!(_similar_for(c, typeof(v1), itr, isz), v1, itr, st) +end + +function collect_to_with_first!(dest::AbstractArray, v1, itr, st) + dest[1] = v1 + return collect_to!(dest, itr, 2, st) +end -_default_container(itr, elty, sz) = Array(elty, sz) -_default_container(itr::AbstractArray, elty, sz) = similar(itr, elty, sz) +function collect_to_with_first!(dest, v1, itr, st) + push!(dest, v1) + return grow_to!(dest, itr, st) +end -function collect_to!{T}(itr, offs, st, dest::AbstractArray{T}) +function collect_to!{T}(dest::AbstractArray{T}, itr, offs, st) # collect to dest array, checking the type of each result. if a result does not # match, widen the result type and re-dispatch. i = offs @@ -246,52 +270,29 @@ function collect_to!{T}(itr, offs, st, dest::AbstractArray{T}) new = similar(dest, R) copy!(new,1, dest,1, i-1) @inbounds new[i] = el - return collect_to!(itr, i+1, st, new) + return collect_to!(new, itr, i+1, st) end end return dest end -function _collect_shaped(itr, sz) - if prod(sz) == 0 - return _default_container(itr, Union{}, sz) - end - st = start(itr) - v1, st = next(itr, st) - dest = _default_container(itr, typeof(v1), sz) - dest[1] = v1 - return collect_to!(itr, 2, st, dest) -end - -function grow_to!{T}(itr, st, dest::AbstractArray{T}) +function grow_to!(dest, itr, st = start(itr)) + T = eltype(dest) while !done(itr, st) el, st = next(itr, st) S = typeof(el) if S === T || S <: T push!(dest, el::T) else - R = typejoin(T, S) - n = length(dest) - new = similar(dest, R, n+1) - copy!(new,1, dest,1, n) - @inbounds new[n+1] = el - return grow_to!(itr, st, new) + new = similar(dest, typejoin(T, S)) + copy!(new, dest) + push!(new, el) + return grow_to!(new, itr, st) end end return dest end -function _collect(itr, ::EltypeUnknown, ::SizeUnknown) - st = start(itr) - if done(itr,st) - return _default_container(itr, Union{}, 0) - end - v1, st = next(itr, st) - dest = _default_container(itr, typeof(v1), 1) - dest[1] = v1 - return grow_to!(itr, st, dest) -end - ## Iteration ## start(A::Array) = 1 next(a::Array,i) = (a[i],i+1) diff --git a/base/dict.jl b/base/dict.jl index c3d4ee24a8745e..38b7fce79492ad 100644 --- a/base/dict.jl +++ b/base/dict.jl @@ -2,8 +2,6 @@ # generic operations on associative collections -abstract Associative{K,V} - const secret_table_token = :__c782dbf1cf4d6a2e5e3865d7e95634f2e09b5902__ haskey(d::Associative, k) = in(k,keys(d)) @@ -225,6 +223,16 @@ function merge!(d::Associative, others::Associative...) end return d end + +# very similar to `merge!`, but accepts any iterable and extends code +# that would otherwise only use `copy!` with arrays. +function copy!(dest::Union{Associative,AbstractSet}, src) + for x in src + push!(dest, x) + end + return dest +end + keytype{K,V}(::Type{Associative{K,V}}) = K keytype(a::Associative) = keytype(typeof(a)) keytype{A<:Associative}(::Type{A}) = keytype(supertype(A)) @@ -449,19 +457,6 @@ copy(d::Dict) = Dict(d) const AnyDict = Dict{Any,Any} -# TODO: this can probably be simplified using `eltype` as a THT (Tim Holy trait) -Dict{K,V}(kv::Tuple{Vararg{Tuple{K,V}}}) = Dict{K,V}(kv) -Dict{K }(kv::Tuple{Vararg{Tuple{K,Any}}}) = Dict{K,Any}(kv) -Dict{V }(kv::Tuple{Vararg{Tuple{Any,V}}}) = Dict{Any,V}(kv) -Dict{K,V}(kv::Tuple{Vararg{Pair{K,V}}}) = Dict{K,V}(kv) -Dict{K }(kv::Tuple{Vararg{Pair{K}}}) = Dict{K,Any}(kv) -Dict{V }(kv::Tuple{Vararg{Pair{TypeVar(:K),V}}}) = Dict{Any,V}(kv) -Dict( kv::Tuple{Vararg{Pair}}) = Dict{Any,Any}(kv) - -Dict{K,V}(kv::AbstractArray{Tuple{K,V}}) = Dict{K,V}(kv) -Dict{K,V}(kv::AbstractArray{Pair{K,V}}) = Dict{K,V}(kv) -Dict{K,V}(kv::Associative{K,V}) = Dict{K,V}(kv) - Dict{K,V}(ps::Pair{K,V}...) = Dict{K,V}(ps) Dict{K }(ps::Pair{K}...,) = Dict{K,Any}(ps) Dict{V }(ps::Pair{TypeVar(:K),V}...,) = Dict{Any,V}(ps) @@ -482,9 +477,27 @@ end dict_with_eltype{K,V}(kv, ::Type{Tuple{K,V}}) = Dict{K,V}(kv) dict_with_eltype{K,V}(kv, ::Type{Pair{K,V}}) = Dict{K,V}(kv) -dict_with_eltype(kv, t) = Dict{Any,Any}(kv) +dict_with_eltype(kv, t) = grow_to!(Dict{Union{},Union{}}(), kv) + +# this is a special case due to (1) allowing both Pairs and Tuples as elements, +# and (2) Pair being invariant. a bit annoying. +function grow_to!{K,V}(dest::Associative{K,V}, itr, st = start(itr)) + while !done(itr, st) + (k,v), st = next(itr, st) + if isa(k,K) && isa(v,V) + dest[k] = v + else + new = similar(dest, Pair{typejoin(K,typeof(k)), typejoin(V,typeof(v))}) + copy!(new, dest) + new[k] = v + return grow_to!(new, itr, st) + end + end + return dest +end similar{K,V}(d::Dict{K,V}) = Dict{K,V}() +similar{K,V}(d::Dict, ::Type{Pair{K,V}}) = Dict{K,V}() # conversion between Dict types function convert{K,V}(::Type{Dict{K,V}},d::Associative) diff --git a/base/essentials.jl b/base/essentials.jl index 7d42dad0efdbbd..059fe58431c152 100644 --- a/base/essentials.jl +++ b/base/essentials.jl @@ -6,6 +6,9 @@ typealias Callable Union{Function,DataType} const Bottom = Union{} +abstract AbstractSet{T} +abstract Associative{K,V} + # The real @inline macro is not available until after array.jl, so this # internal macro splices the meta Expr directly into the function body. macro _inline_meta() diff --git a/base/intset.jl b/base/intset.jl index 5b610eae563c72..89f862d90f9da3 100644 --- a/base/intset.jl +++ b/base/intset.jl @@ -1,7 +1,5 @@ # This file is a part of Julia. License is MIT: http://julialang.org/license -abstract AbstractSet{T} - type IntSet <: AbstractSet{Int} bits::Array{UInt32,1} limit::Int diff --git a/base/set.jl b/base/set.jl index 46a14aa73e2790..d4ec130cd0c96c 100644 --- a/base/set.jl +++ b/base/set.jl @@ -11,6 +11,7 @@ Set(itr) = Set{eltype(itr)}(itr) eltype{T}(::Type{Set{T}}) = T similar{T}(s::Set{T}) = Set{T}() +similar(s::Set, T::Type) = Set{T}() function show(io::IO, s::Set) print(io,"Set") diff --git a/test/functional.jl b/test/functional.jl index 15add526e7d4ac..abc3279ffd3435 100644 --- a/test/functional.jl +++ b/test/functional.jl @@ -58,6 +58,9 @@ let z = zip(1:2, 3:4, 5:6) @test eltype(z) == Tuple{Int,Int,Int} end +# typed `collect` +@test collect(Float64, Filter(isodd, [1,2,3,4]))[1] === 1.0 + # enumerate (issue #6284) let b = IOBuffer("1\n2\n3\n"), a = [] for (i,x) in enumerate(eachline(b))