@@ -786,6 +786,81 @@ reshaped = reshape(tile, (2, 16)) # Shape (2, 16), still 32 elements
786786end
787787@inline Base. reshape (tile:: Tile{T} , dims:: Int... ) where {T} = reshape (tile, dims)
788788
789+ """
790+ repeat(tile::Tile, counts::Integer...) -> Tile
791+
792+ Repeat a tile along each dimension (outer repetition), matching `Base.repeat`.
793+ `counts[i]` is the number of times to tile the whole tile along dimension `i`;
794+ dimensions beyond `length(counts)` are repeated once, and counts beyond
795+ `ndims(tile)` introduce new trailing dimensions.
796+
797+ `counts` must be compile-time constants, and every resulting dimension
798+ `size(tile, i) * counts[i]` (as well as the new repeat dimensions) must be a
799+ power of two.
800+
801+ # Example
802+ ```julia
803+ tile = ct.load(arr, (1, 1), (4, 8)) # Shape (4, 8)
804+ tiled = repeat(tile, 2, 2) # Shape (8, 16)
805+ ```
806+ """
807+ Base. repeat (tile:: Tile , counts:: Integer... ) = repeat (tile; outer = counts)
808+
809+ """
810+ repeat(tile::Tile; inner=nothing, outer=nothing) -> Tile
811+
812+ Keyword form of `repeat`, matching `Base.repeat`. `inner[i]` repeats each element
813+ `inner[i]` times along dimension `i` (inner repetition), while `outer[i]` tiles the
814+ whole tile `outer[i]` times along dimension `i` (outer repetition). When both are
815+ given, the inner repetition is applied first. Each of `inner`/`outer` may be an
816+ `Integer` or a tuple, and must be a compile-time constant.
817+
818+ # Example
819+ ```julia
820+ tile = ct.load(arr, (1, 1), (2, 4)) # Shape (2, 4)
821+ repeat(tile; inner=(2, 1), outer=(1, 2)) # Shape (4, 8)
822+ ```
823+ """
824+ function Base. repeat (tile:: Tile ; inner = nothing , outer = nothing )
825+ t = inner === nothing ? tile :
826+ _repeat (tile, :inner , inner isa Integer ? (inner,) : Tuple (inner))
827+ return outer === nothing ? t :
828+ _repeat (t, :outer , outer isa Integer ? (outer,) : Tuple (outer))
829+ end
830+
831+ # Implements both inner and outer repetition by reshaping the tile to interleave
832+ # a singleton dimension next to each data dimension, broadcasting that singleton
833+ # up to the repeat count, then collapsing each pair back together. For outer
834+ # repetition the data dimension is the fast (inner) one within each pair; for
835+ # inner repetition the repeat count is. Shapes derive from the tile type and the
836+ # (constant) counts, so const-prop folds them away.
837+ function _repeat (tile:: Tile , mode:: Symbol , counts:: Tuple{Vararg{Integer}} )
838+ sz = size (tile)
839+ N = ndims (tile)
840+ M = length (counts)
841+ P = max (N, M)
842+ szp = ntuple (i -> i <= N ? sz[i] : 1 , P)
843+ cntp = ntuple (i -> i <= M ? Int (counts[i]) : 1 , P)
844+
845+ # Nothing to repeat and no new dimensions: identity.
846+ (all (== (1 ), cntp) && P == N) && return tile
847+
848+ data_first = mode === :outer
849+ interleaved = ntuple (2 P) do j
850+ pair, lo = divrem (j - 1 , 2 )
851+ (lo == 0 ) == data_first ? szp[pair + 1 ] : 1
852+ end
853+ target = ntuple (2 P) do j
854+ pair, lo = divrem (j - 1 , 2 )
855+ (lo == 0 ) == data_first ? szp[pair + 1 ] : cntp[pair + 1 ]
856+ end
857+ final = ntuple (i -> szp[i] * cntp[i], P)
858+
859+ t = reshape (tile, interleaved)
860+ t = broadcast_to (t, target)
861+ return reshape (t, final)
862+ end
863+
789864"""
790865 permutedims(tile::Tile{T, S}, perm) -> Tile{T, permuted_shape}
791866
0 commit comments