From 1ddab938b35a38f5e51b708b8280b7d647017906 Mon Sep 17 00:00:00 2001 From: Carsten Bauer Date: Wed, 3 Apr 2024 14:33:03 +0200 Subject: [PATCH 1/3] handle empty input (#87 etc) --- src/implementation.jl | 15 ++++----------- test/runtests.jl | 13 ++++++++++++- 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/src/implementation.jl b/src/implementation.jl index 217f67d7..88786cbe 100644 --- a/src/implementation.jl +++ b/src/implementation.jl @@ -60,13 +60,9 @@ function tmapreduce(f, op, Arrs...; kwargs...) mapreduce_kwargs = isgiven(init) ? (; init) : (;) _scheduler = _scheduler_from_userinput(scheduler; kwargs...) - if isempty(first(Arrs)) - isempty(mapreduce_kwargs) && reduce_empty_err() - return mapreduce_kwargs.init - end - # @show _scheduler - if _scheduler isa SerialScheduler + if _scheduler isa SerialScheduler || isempty(first(Arrs)) + # empty input collection → align with Base.mapreduce behavior mapreduce(f, op, Arrs...; mapreduce_kwargs...) else @noinline _tmapreduce(f, op, Arrs, outputtype, _scheduler, mapreduce_kwargs) @@ -78,10 +74,6 @@ end throw(ArgumentError("Providing an explicit scheduler as well as direct keyword arguments (e.g. $(kwargstr)) is currently not supported.")) end -@noinline function reduce_empty_err() - throw(ArgumentError("reducing over an empty collection is not allowed; consider supplying `init`")) -end - treducemap(op, f, A...; kwargs...) = tmapreduce(f, op, A...; kwargs...) # DynamicScheduler: AbstractArray/Generic @@ -357,7 +349,8 @@ function tmap(f, end Arrs = (A, _Arrs...) - if _scheduler isa SerialScheduler + if _scheduler isa SerialScheduler || isempty(A) + # empty input collection → align with Base.map behavior map(f, Arrs...; kwargs...) else check_all_have_same_indices(Arrs) diff --git a/test/runtests.jl b/test/runtests.jl index 035dbb65..93179396 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -367,11 +367,22 @@ end; for empty_coll in (11:9, Float64[]) for f in (sin, x -> im * x, identity) for op in (+, *, min) - @test_throws ArgumentError tmapreduce(f, op, empty_coll) + # mapreduce for init in (0.0, 0, 0.0 * im, 0.0f0) @test tmapreduce(f, op, empty_coll; init) == init end + # foreach @test tforeach(f, empty_coll) |> isnothing + # reduce + if op != min + @test treduce(op, empty_coll) == reduce(op, empty_coll) + else + @test_throws MethodError treduce(op, empty_coll) + end + # map + @test tmap(f, empty_coll) == map(f, empty_coll) + # collect + @test tcollect(empty_coll) == collect(empty_coll) end end end From fef50d1f8b19ded47ea49b4882d272a6dfb79b1f Mon Sep 17 00:00:00 2001 From: Carsten Bauer Date: Wed, 3 Apr 2024 14:35:11 +0200 Subject: [PATCH 2/3] changelog --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4a0c5db3..bf92e1a7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,10 @@ OhMyThreads.jl Changelog ========================= +Version 0.5.2 +------------- +- ![Enhancement][badge-enhancement] For empty input (e.g. `Float64[]` or `11:10`) behavior is now aligned with the serial functions in `Base`. + Version 0.5.1 ------------- - ![Feature][badge-feature] Within a parallel `@tasks` block one can now mark a region with `@one_by_one`. This region will be run by one task at a time ("critical region"). From fb92034437a5e53c12cfcdeaa4028ccf9ed62a26 Mon Sep 17 00:00:00 2001 From: Carsten Bauer Date: Wed, 3 Apr 2024 14:48:38 +0200 Subject: [PATCH 3/3] fix error type --- test/runtests.jl | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/test/runtests.jl b/test/runtests.jl index 93179396..fcac91b7 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -364,6 +364,11 @@ end; end; @testset "empty collections" begin + @static if VERSION < v"1.11.0-" + err = MethodError + else + err = ArgumentError + end for empty_coll in (11:9, Float64[]) for f in (sin, x -> im * x, identity) for op in (+, *, min) @@ -377,7 +382,7 @@ end; if op != min @test treduce(op, empty_coll) == reduce(op, empty_coll) else - @test_throws MethodError treduce(op, empty_coll) + @test_throws err treduce(op, empty_coll) end # map @test tmap(f, empty_coll) == map(f, empty_coll)