Skip to content

Commit

Permalink
Merge pull request #20720 from pabloferz/pz/maptups
Browse files Browse the repository at this point in the history
Couple of tuple speed-ups and fixes
  • Loading branch information
pabloferz committed Apr 6, 2017
2 parents d20c66d + 1d1ff14 commit d5d7280
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 23 deletions.
5 changes: 5 additions & 0 deletions base/range.jl
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,11 @@ unitrange_last{T}(start::T, stop::T) =
ifelse(stop >= start, convert(T,start+floor(stop-start)),
convert(T,start-oneunit(stop-start)))

if isdefined(Main, :Base)
getindex(t::Tuple, r::AbstractUnitRange{<:Real}) =
(o = first(r) - 1; ntuple(n -> t[o + n], length(r)))
end

"""
Base.OneTo(n)
Expand Down
59 changes: 37 additions & 22 deletions base/tuple.jl
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ endof(t::Tuple) = length(t)
size(t::Tuple, d) = d==1 ? length(t) : throw(ArgumentError("invalid tuple dimension $d"))
getindex(t::Tuple, i::Int) = getfield(t, i)
getindex(t::Tuple, i::Real) = getfield(t, convert(Int, i))
getindex(t::Tuple, r::AbstractArray{<:Any,1}) = tuple([t[ri] for ri in r]...)
getindex(t::Tuple, r::AbstractArray{<:Any,1}) = ([t[ri] for ri in r]...)
getindex(t::Tuple, b::AbstractArray{Bool,1}) = length(b) == length(t) ? getindex(t,find(b)) : throw(BoundsError(t, b))

# returns new tuple; N.B.: becomes no-op if i is out-of-bounds
Expand Down Expand Up @@ -104,17 +104,23 @@ julia> ntuple(i -> 2*i, 4)
(2, 4, 6, 8)
```
"""
ntuple(f::Function, n::Integer) =
n <= 0 ? () :
n == 1 ? (f(1),) :
n == 2 ? (f(1),f(2),) :
n == 3 ? (f(1),f(2),f(3),) :
n == 4 ? (f(1),f(2),f(3),f(4),) :
n == 5 ? (f(1),f(2),f(3),f(4),f(5),) :
n < 16 ? (ntuple(f,n-5)..., f(n-4), f(n-3), f(n-2), f(n-1), f(n)) :
_ntuple(f, n)

_ntuple(f::Function, n::Integer) = (@_noinline_meta; ((f(i) for i = 1:n)...))
function ntuple{F}(f::F, n::Integer)
t = n <= 0 ? () :
n == 1 ? (f(1),) :
n == 2 ? (f(1), f(2)) :
n == 3 ? (f(1), f(2), f(3)) :
n == 4 ? (f(1), f(2), f(3), f(4)) :
n == 5 ? (f(1), f(2), f(3), f(4), f(5)) :
n == 6 ? (f(1), f(2), f(3), f(4), f(5), f(6)) :
n == 7 ? (f(1), f(2), f(3), f(4), f(5), f(6), f(7)) :
n == 8 ? (f(1), f(2), f(3), f(4), f(5), f(6), f(7), f(8)) :
n == 9 ? (f(1), f(2), f(3), f(4), f(5), f(6), f(7), f(8), f(9)) :
n == 10 ? (f(1), f(2), f(3), f(4), f(5), f(6), f(7), f(8), f(9), f(10)) :
_ntuple(f, n)
return t
end

_ntuple(f, n) = (@_noinline_meta; ([f(i) for i = 1:n]...))

# inferrable ntuple
function ntuple{F,N}(f::F, ::Type{Val{N}})
Expand Down Expand Up @@ -142,11 +148,11 @@ All16{T,N} = Tuple{T,T,T,T,T,T,T,T,
T,T,T,T,T,T,T,T,Vararg{T,N}}
function map(f, t::Any16)
n = length(t)
A = Array{Any}(n)
A = Array{Any,1}(n)
for i=1:n
A[i] = f(t[i])
end
(A...,)
(A...)
end
# 2 argument function
map(f, t::Tuple{}, s::Tuple{}) = ()
Expand All @@ -158,19 +164,28 @@ function map(f, t::Tuple, s::Tuple)
end
function map(f, t::Any16, s::Any16)
n = length(t)
A = Array{Any}(n)
A = Array{Any,1}(n)
for i = 1:n
A[i] = f(t[i], s[i])
end
(A...,)
(A...)
end
# n argument function
heads() = ()
heads(t::Tuple, ts::Tuple...) = (t[1], heads(ts...)...)
tails() = ()
tails(t::Tuple, ts::Tuple...) = (tail(t), tails(ts...)...)
map(f, ::Tuple{}, ts::Tuple...) = ()
map(f, t1::Tuple, t2::Tuple, ts::Tuple...) = (f(heads(t1, t2, ts...)...), map(f, tails(t1, t2, ts...)...)...)
heads(ts::Tuple...) = map(t -> t[1], ts)
tails(ts::Tuple...) = map(tail, ts)
map(f, ::Tuple{}...) = ()
function map(f, t1::Tuple, t2::Tuple, ts::Tuple...)
@_inline_meta
(f(heads(t1, t2, ts...)...), map(f, tails(t1, t2, ts...)...)...)
end
function map(f, t1::Any16, t2::Any16, ts::Any16...)
n = length(t1)
A = Array{Any,1}(n)
for i = 1:n
A[i] = f(t1[i], t2[i], map(t -> t[i], ts)...)
end
(A...)
end


# type-stable padding
Expand Down
5 changes: 4 additions & 1 deletion test/tuple.jl
Original file line number Diff line number Diff line change
Expand Up @@ -96,14 +96,17 @@ begin
@test map(foo, (1,2), (1,2)) === (2,4)
@test map(foo, (1,2,3,4), (1,2,3,4)) === (2,4,6,8)
@test map(foo, longtuple, longtuple) === ntuple(i->2i,20)
@test_throws BoundsError map(foo, (), (1,))
@test_throws BoundsError map(foo, (1,), ())

# n arguments
@test map(foo, (), (), ()) === ()
@test map(foo, (), (1,2,3), (1,2,3)) === ()
@test map(foo, (1,), (1,), (1,)) === (3,)
@test map(foo, (1,2), (1,2), (1,2)) === (3,6)
@test map(foo, (1,2,3,4), (1,2,3,4), (1,2,3,4)) === (3,6,9,12)
@test map(foo, longtuple, longtuple, longtuple) === ntuple(i->3i,20)
@test_throws BoundsError map(foo, (), (1,), (1,))
@test_throws BoundsError map(foo, (1,), (1,), ())
end

## comparison ##
Expand Down

0 comments on commit d5d7280

Please sign in to comment.