diff --git a/NEWS.md b/NEWS.md index 035b3ffd6094a..4f785147c0498 100644 --- a/NEWS.md +++ b/NEWS.md @@ -28,6 +28,7 @@ Standard library changes ------------------------ * `CartesianIndices` can now be constructed from two `CartesianIndex`es `I` and `J` with `I:J` ([#29440]). + * `CartesianIndices` support broadcasting arithmetic (+ and -) with a `CartesianIndex` ([#29890]). * `copy!` support for arrays, dicts, and sets has been moved to Base from the Future package ([#29173]). * Channels now convert inserted values (like containers) instead of requiring types to match ([#29092]). * `range` can accept the stop value as a positional argument, e.g. `range(1,10,step=2)` ([#28708]). diff --git a/base/broadcast.jl b/base/broadcast.jl index 0eb2362b8a497..e55678bb5e0cc 100644 --- a/base/broadcast.jl +++ b/base/broadcast.jl @@ -1006,6 +1006,18 @@ broadcasted(::DefaultArrayStyle{1}, ::typeof(big), r::StepRange) = big(r.start): broadcasted(::DefaultArrayStyle{1}, ::typeof(big), r::StepRangeLen) = StepRangeLen(big(r.ref), big(r.step), length(r), r.offset) broadcasted(::DefaultArrayStyle{1}, ::typeof(big), r::LinRange) = LinRange(big(r.start), big(r.stop), length(r)) +## CartesianIndices +broadcasted(::typeof(+), I::CartesianIndices{N}, j::CartesianIndex{N}) where N = + CartesianIndices(map((rng, offset)->rng .+ offset, I.indices, Tuple(j))) +broadcasted(::typeof(+), j::CartesianIndex{N}, I::CartesianIndices{N}) where N = + I .+ j +broadcasted(::typeof(-), I::CartesianIndices{N}, j::CartesianIndex{N}) where N = + CartesianIndices(map((rng, offset)->rng .- offset, I.indices, Tuple(j))) +function broadcasted(::typeof(-), j::CartesianIndex{N}, I::CartesianIndices{N}) where N + diffrange(offset, rng) = range(offset-last(rng), length=length(rng)) + Iterators.reverse(CartesianIndices(map(diffrange, Tuple(j), I.indices))) +end + ## In specific instances, we can broadcast masked BitArrays whole chunks at a time # Very intentionally do not support much functionality here: scalar indexing would be O(n) struct BitMaskedBitArray{N,M} diff --git a/test/abstractarray.jl b/test/abstractarray.jl index 6c5027a673847..d53916a05f31a 100644 --- a/test/abstractarray.jl +++ b/test/abstractarray.jl @@ -909,6 +909,11 @@ end J1, J2 = @inferred(promote(I1, I2)) @test J1 === J2 end + + i = CartesianIndex(17,-2) + @test CR .+ i === i .+ CR === CartesianIndices((19:21, -1:3)) + @test CR .- i === CartesianIndices((-15:-13, 3:7)) + @test collect(i .- CR) == Ref(i) .- collect(CR) end @testset "issue #25770" begin