@@ -645,6 +645,22 @@ See also `circshift`.
645
645
end
646
646
circshift! (dest:: AbstractArray , src, shiftamt) = circshift! (dest, src, (shiftamt... ,))
647
647
648
+ # For each dimension, we copy the first half of src to the second half
649
+ # of dest, and the second half of src to the first half of dest. This
650
+ # uses a recursive bifurcation strategy so that these splits can be
651
+ # encoded by ranges, which means that we need only one call to `mod`
652
+ # per dimension rather than one call per index.
653
+ # `rdest` and `rsrc` are tuples-of-ranges that grow one dimension at a
654
+ # time; when all the dimensions have been filled in, you call `copy!`
655
+ # for that block. In other words, in two dimensions schematically we
656
+ # have the following call sequence (--> means a call):
657
+ # circshift!(dest, src, shiftamt) -->
658
+ # _circshift!(dest, src, ("first half of dim1",)) -->
659
+ # _circshift!(dest, src, ("first half of dim1", "first half of dim2")) --> copy!
660
+ # _circshift!(dest, src, ("first half of dim1", "second half of dim2")) --> copy!
661
+ # _circshift!(dest, src, ("second half of dim1",)) -->
662
+ # _circshift!(dest, src, ("second half of dim1", "first half of dim2")) --> copy!
663
+ # _circshift!(dest, src, ("second half of dim1", "second half of dim2")) --> copy!
648
664
@inline function _circshift! (dest, rdest, src, rsrc,
649
665
inds:: Tuple{AbstractUnitRange,Vararg{Any}} ,
650
666
shiftamt:: Tuple{Integer,Vararg{Any}} )
@@ -662,6 +678,68 @@ function _circshift!(dest, rdest, src, rsrc, inds, shiftamt)
662
678
copy! (dest, CartesianRange (rdest), src, CartesianRange (rsrc))
663
679
end
664
680
681
+ # circcopy!
682
+ """
683
+ circcopy!(dest, src)
684
+
685
+ Copy `src` to `dest`, indexing each dimension modulo its length.
686
+ `src` and `dest` must have the same size, but can be offset in
687
+ their indices; any offset results in a (circular) wraparound. If the
688
+ arrays have overlapping indices, then on the domain of the overlap
689
+ `dest` agrees with `src`.
690
+
691
+ ```julia
692
+ julia> src = reshape(collect(1:16), (4,4))
693
+ 4×4 Array{Int64,2}:
694
+ 1 5 9 13
695
+ 2 6 10 14
696
+ 3 7 11 15
697
+ 4 8 12 16
698
+
699
+ julia> dest = OffsetArray{Int}((0:3,2:5))
700
+
701
+ julia> circcopy!(dest, src)
702
+ OffsetArrays.OffsetArray{Int64,2,Array{Int64,2}} with indices 0:3×2:5:
703
+ 8 12 16 4
704
+ 5 9 13 1
705
+ 6 10 14 2
706
+ 7 11 15 3
707
+
708
+ julia> dest[1:3,2:4] == src[1:3,2:4]
709
+ true
710
+ ```
711
+ """
712
+ function circcopy! (dest, src)
713
+ dest === src && throw (ArgumentError (" dest and src must be separate arrays" ))
714
+ indssrc, indsdest = indices (src), indices (dest)
715
+ if (szsrc = map (length, indssrc)) != (szdest = map (length, indsdest))
716
+ throw (DimensionMismatch (" src and dest must have the same sizes (got $szsrc and $szdest )" ))
717
+ end
718
+ shift = map ((isrc, idest)-> first (isrc)- first (idest), indssrc, indsdest)
719
+ all (x-> x== 0 , shift) && return copy! (dest, src)
720
+ _circcopy! (dest, (), indsdest, src, (), indssrc)
721
+ end
722
+
723
+ # This uses the same strategy described above for _circshift!
724
+ @inline function _circcopy! (dest, rdest, indsdest:: Tuple{AbstractUnitRange,Vararg{Any}} ,
725
+ src, rsrc, indssrc:: Tuple{AbstractUnitRange,Vararg{Any}} )
726
+ indd1, inds1 = indsdest[1 ], indssrc[1 ]
727
+ l = length (indd1)
728
+ s = mod (first (inds1)- first (indd1), l)
729
+ sdf = first (indd1)+ s
730
+ rd1, rd2 = first (indd1): sdf- 1 , sdf: last (indd1)
731
+ ssf = last (inds1)- s
732
+ rs1, rs2 = first (inds1): ssf, ssf+ 1 : last (inds1)
733
+ tindsd, tindss = tail (indsdest), tail (indssrc)
734
+ _circcopy! (dest, (rdest... , rd1), tindsd, src, (rsrc... , rs2), tindss)
735
+ _circcopy! (dest, (rdest... , rd2), tindsd, src, (rsrc... , rs1), tindss)
736
+ end
737
+
738
+ # At least one of indsdest, indssrc are empty (and both should be, since we've checked)
739
+ function _circcopy! (dest, rdest, indsdest, src, rsrc, indssrc)
740
+ copy! (dest, CartesianRange (rdest), src, CartesianRange (rsrc))
741
+ end
742
+
665
743
# ## BitArrays
666
744
667
745
# # getindex
0 commit comments