Skip to content

Commit d194625

Browse files
committed
new implementation of map for AbstractArray
This has better type behavior, calling promote_type to widen the result type as necessary. It is also faster, since each invocation of the inner loop function (map_to!) only handles a single element type, allowing a type declaration to be inserted. This is faster than the custom method for mapping over Ranges, so that has been subsumed.
1 parent c21e0b6 commit d194625

File tree

3 files changed

+47
-37
lines changed

3 files changed

+47
-37
lines changed

base/abstractarray.jl

Lines changed: 46 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1251,10 +1251,20 @@ end
12511251

12521252

12531253
## 1 argument
1254-
function map_to!(f::Callable, first, dest::AbstractArray, A::AbstractArray)
1255-
dest[1] = first
1256-
for i=2:length(A)
1257-
dest[i] = f(A[i])
1254+
function map_to!{T}(f::Callable, offs, dest::AbstractArray{T}, A::AbstractArray)
1255+
# map to dest array, checking the type of each result. if a result does not
1256+
# match, do a type promotion and re-dispatch.
1257+
@inbounds for i = offs:length(A)
1258+
el = f(A[i])
1259+
S = typeof(el)
1260+
if (S !== T) && !(S <: T)
1261+
R = promote_type(T, S)
1262+
new = similar(dest, R)
1263+
copy!(new,1, dest,1, i-1)
1264+
new[i] = el
1265+
return map_to!(f, i+1, new, A)
1266+
end
1267+
dest[i] = el::T
12581268
end
12591269
return dest
12601270
end
@@ -1263,14 +1273,23 @@ function map(f::Callable, A::AbstractArray)
12631273
if isempty(A); return similar(A); end
12641274
first = f(A[1])
12651275
dest = similar(A, typeof(first))
1266-
return map_to!(f, first, dest, A)
1276+
dest[1] = first
1277+
return map_to!(f, 2, dest, A)
12671278
end
12681279

12691280
## 2 argument
1270-
function map_to!(f::Callable, first, dest::AbstractArray, A::AbstractArray, B::AbstractArray)
1271-
dest[1] = first
1272-
for i=2:length(A)
1273-
dest[i] = f(A[i], B[i])
1281+
function map_to!{T}(f::Callable, offs, dest::AbstractArray{T}, A::AbstractArray, B::AbstractArray)
1282+
@inbounds for i = offs:length(A)
1283+
el = f(A[i], B[i])
1284+
S = typeof(el)
1285+
if (S !== T) && !(S <: T)
1286+
R = promote_type(T, S)
1287+
new = similar(dest, R)
1288+
copy!(new,1, dest,1, i-1)
1289+
new[i] = el
1290+
return map_to!(f, i+1, new, A, B)
1291+
end
1292+
dest[i] = el::T
12741293
end
12751294
return dest
12761295
end
@@ -1282,29 +1301,38 @@ function map(f::Callable, A::AbstractArray, B::AbstractArray)
12821301
end
12831302
first = f(A[1], B[1])
12841303
dest = similar(A, typeof(first), shp)
1285-
return map_to!(f, first, dest, A, B)
1304+
dest[1] = first
1305+
return map_to!(f, 2, dest, A, B)
12861306
end
12871307

12881308
## N argument
1289-
function map_to!(f::Callable, first, dest::AbstractArray, As::AbstractArray...)
1290-
n = length(As[1])
1291-
i = 1
1309+
function map_to!{T}(f::Callable, offs, dest::AbstractArray{T}, As::AbstractArray...)
1310+
local i
12921311
ith = a->a[i]
1293-
dest[1] = first
1294-
for i=2:n
1295-
dest[i] = f(map(ith, As)...)
1312+
@inbounds for i = offs:length(As[1])
1313+
el = f(map(ith, As)...)
1314+
S = typeof(el)
1315+
if (S !== T) && !(S <: T)
1316+
R = promote_type(T, S)
1317+
new = similar(dest, R)
1318+
copy!(new,1, dest,1, i-1)
1319+
new[i] = el
1320+
return map_to!(f, i+1, new, As...)
1321+
end
1322+
dest[i] = el::T
12961323
end
12971324
return dest
12981325
end
12991326

13001327
function map(f::Callable, As::AbstractArray...)
13011328
shape = mapreduce(size, promote_shape, As)
13021329
if prod(shape) == 0
1303-
return similar(As[1], Any, shape)
1330+
return similar(As[1], mapreduce(eltype, promote_type, As), shape)
13041331
end
13051332
first = f(map(a->a[1], As)...)
13061333
dest = similar(As[1], typeof(first), shape)
1307-
return map_to!(f, first, dest, As...)
1334+
dest[1] = first
1335+
return map_to!(f, 2, dest, As...)
13081336
end
13091337

13101338
# multi-item push!, unshift! (built on top of type-specific 1-item version)

base/range.jl

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -514,25 +514,6 @@ function map!(f::Callable, dest, r::Range)
514514
dest
515515
end
516516

517-
function map_range_to!(f::Callable, first, dest, r::Range, state)
518-
dest[1] = first
519-
i = 2
520-
while !done(r, state)
521-
ri, state = next(r, state)
522-
dest[i] = f(ri)
523-
i += 1
524-
end
525-
dest
526-
end
527-
528-
function map(f::Callable, r::Range)
529-
if isempty(r); return {}; end
530-
state = start(r)
531-
(ri, state) = next(r, state)
532-
first = f(ri)
533-
map_range_to!(f, first, Array(typeof(first), length(r)), r, state)
534-
end
535-
536517
function in(x, r::Range)
537518
n = step(r) == 0 ? 1 : iround((x-first(r))/step(r))+1
538519
n >= 1 && n <= length(r) && r[n] == x

base/tuple.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ map(f::Callable) = f()
4545
map(f::Callable, t::()) = ()
4646
map(f::Callable, t::(Any,)) = (f(t[1]),)
4747
map(f::Callable, t::(Any, Any)) = (f(t[1]), f(t[2]))
48+
map(f::Callable, t::(Any, Any, Any)) = (f(t[1]), f(t[2]), f(t[3]))
4849
map(f::Callable, t::Tuple) = tuple(f(t[1]), map(f,tail(t))...)
4950
# 2 argument function
5051
map(f::Callable, t::(), s::()) = ()

0 commit comments

Comments
 (0)