Skip to content

Commit 32a7ed8

Browse files
authored
Fix reduction over empty array (#780)
1 parent 38f5e80 commit 32a7ed8

File tree

2 files changed

+49
-0
lines changed

2 files changed

+49
-0
lines changed

src/mapreduce.jl

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,17 @@ end
113113
@inline _mapreduce(args::Vararg{Any,N}) where N = _mapfoldl(args...)
114114

115115
@generated function _mapfoldl(f, op, dims::Colon, init, ::Size{S}, a::StaticArray...) where {S}
116+
if prod(S) == 0
117+
if init === _InitialValue
118+
if length(a) == 1
119+
return :(Base.mapreduce_empty(f, op, $(eltype(a[1]))))
120+
else
121+
return :(throw(ArgumentError("reducing over an empty collection is not allowed")))
122+
end
123+
else
124+
return :init
125+
end
126+
end
116127
tmp = [:(a[$j][1]) for j 1:length(a)]
117128
expr = :(f($(tmp...)))
118129
if init === _InitialValue

test/mapreduce.jl

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,44 @@ using Statistics: mean
5858
@test mapfoldl(-, +, sv1; init=0) === mapfoldl(-, +, v1, init=0)
5959
end
6060

61+
@testset "empty array" begin
62+
# issue #778
63+
@test iszero(SVector{0,Int}())
64+
65+
@testset "$fold" for fold in [reduce, foldl]
66+
@test fold(+, SVector{0,Bool}()) === 0
67+
@test fold(nothing, SVector{0,Int}(), init=:INIT) === :INIT
68+
end
69+
70+
@testset "$mapfold" for mapfold in [mapreduce, mapfoldl]
71+
@test mapfold(identity, +, SVector{0,Bool}()) === 0
72+
@test mapfold(abs, +, SVector{0,Bool}()) === 0
73+
@test mapfold(nothing, nothing, SVector{0,Int}(), init=:INIT) === :INIT
74+
end
75+
76+
@test mapreduce(
77+
(a, b) -> a + b,
78+
(a, b) -> a * b,
79+
SVector{0,Int}(),
80+
SVector{0,Int}();
81+
init = :INIT,
82+
) == :INIT
83+
84+
# When there are multiple inputs, the error is thrown by
85+
# StaticArrays.jl:
86+
@test_throws(
87+
ArgumentError("reducing over an empty collection is not allowed"),
88+
mapreduce((a, b) -> a + b, (a, b) -> a * b, SVector{0,Int}(), SVector{0,Int}())
89+
)
90+
91+
# When the mapping and/or reducing functions are unsupported,
92+
# the error is thrown by `Base.mapreduce_empty`:
93+
@test_throws(
94+
ArgumentError("reducing over an empty collection is not allowed"),
95+
mapreduce(nothing, nothing, SVector{0,Int}())
96+
)
97+
end
98+
6199
@testset "implemented by [map]reduce and [map]reducedim" begin
62100
I, J, K = 2, 2, 2
63101
OSArray = SArray{Tuple{I,J,K}} # original

0 commit comments

Comments
 (0)