From 72fd9ec438b2b6ef7fa6f3dafdf4872c35eb53f1 Mon Sep 17 00:00:00 2001 From: tpietzsch Date: Sun, 10 Mar 2024 10:55:28 +0100 Subject: [PATCH] Add SubArrayCopy for copying sub-regions between flattened arrays (of different sizes) Add javadoc --- .../java/net/imglib2/blocks/SubArrayCopy.java | 166 ++++++++++++++++++ 1 file changed, 166 insertions(+) create mode 100644 src/main/java/net/imglib2/blocks/SubArrayCopy.java diff --git a/src/main/java/net/imglib2/blocks/SubArrayCopy.java b/src/main/java/net/imglib2/blocks/SubArrayCopy.java new file mode 100644 index 000000000..57a548dd2 --- /dev/null +++ b/src/main/java/net/imglib2/blocks/SubArrayCopy.java @@ -0,0 +1,166 @@ +package net.imglib2.blocks; + +import net.imglib2.type.PrimitiveType; +import net.imglib2.util.Cast; +import net.imglib2.util.IntervalIndexer; + +/** + * Copy sub-region between flattened arrays (of different sizes). + *

+ * The {@link #copy(Object, int[], int[], Object, int[], int[], int[]) SubArrayCopy.copy} + * method requires the nD size of the flattened source and target arrays, the nD + * starting position and nD size of the source region to copy, and the nD + * starting position in the target to copy to. + *

+ * The {@link #copy(Object, int[], int[], Object, int[], int[], int[]) + * SubArrayCopy.copy} method determines the appropriate implementation by + * looking at the types of the {@code src} and {@code dest} arguments. + *

+ * If for repeated calls the types are known beforehand, this implementation + * lookup can be done once, up-front. {@link #forPrimitiveType(PrimitiveType, + * boolean, boolean) SubArrayCopy.forPrimitiveType} returns a {@link + * SubArrayCopy.Typed} instance with explicit {@code src} and {@code dest} + * types. + */ +public interface SubArrayCopy +{ + /** + * Copy a nD region from {@code src} to {@code dest}, where {@code src} and + * {@code dest} are flattened nD array of dimensions {@code srcSize} and + * {@code destSize}, respectively. + * + * @param src + * flattened nD source array + * @param srcSize + * dimensions of src + * @param srcPos + * starting position, in src, of the range to copy + * @param dest + * flattened nD destination array + * @param destSize + * dimensions of dest + * @param destPos + * starting position, in dest, of the range to copy + * @param size + * size of the range to copy + */ + @SuppressWarnings( { "unchecked", "rawtypes" } ) + static void copy( Object src, int[] srcSize, int[] srcPos, Object dest, int[] destSize, int[] destPos, int[] size ) + { + final MemCopy memcopy = MemCopy.forClasses( src.getClass(), dest.getClass() ); + + final int n = srcSize.length; + assert srcPos.length == n; + assert destSize.length == n; + assert destPos.length == n; + assert size.length == n; + + final int[] srcStrides = IntervalIndexer.createAllocationSteps( srcSize ); + final int[] destStrides = IntervalIndexer.createAllocationSteps( destSize ); + final int oSrc = IntervalIndexer.positionToIndex( srcPos, srcSize ); + final int oDest = IntervalIndexer.positionToIndex( destPos, destSize ); + + memcopy.copyNDRangeRecursive( n - 1, + src, srcStrides, oSrc, + dest, destStrides, oDest, + size ); + } + + static < T > Typed< T, T > forPrimitiveType( final PrimitiveType primitiveType ) + { + MemCopy< T, T > memcopy = Cast.unchecked( MemCopy.forPrimitiveType( primitiveType, false, false ) ); + return memcopy::copyNDRangeRecursive; + } + + static < S, T > Typed< S, T > forPrimitiveType( final PrimitiveType primitiveType, final boolean fromBuffer, final boolean toBuffer ) + { + MemCopy< S, T > memcopy = Cast.unchecked( MemCopy.forPrimitiveType( primitiveType, fromBuffer, toBuffer ) ); + return memcopy::copyNDRangeRecursive; + } + + /** + * @param + * the source type. Must be a primitive array or buffer type (e.g., {@code double[]} or {@code IntBuffer}) + * @param + * the target type. Must be a primitive array or buffer type (e.g., {@code double[]} or {@code IntBuffer}) + */ + interface Typed< S, T > + { + /** + * Copy a nD region from {@code src} to {@code dest}, where {@code src} and + * {@code dest} are flattened nD array of dimensions {@code srcSize} and + * {@code destSize}, respectively. + * + * @param src + * flattened nD source array + * @param srcSize + * dimensions of src + * @param srcPos + * starting position, in src, of the range to copy + * @param dest + * flattened nD destination array + * @param destSize + * dimensions of dest + * @param destPos + * starting position, in dest, of the range to copy + * @param size + * size of the range to copy + */ + default void copy( + final S src, final int[] srcSize, final int[] srcPos, + final T dest, final int[] destSize, final int[] destPos, + final int[] size ) + { + final int n = srcSize.length; + assert srcPos.length == n; + assert destSize.length == n; + assert destPos.length == n; + assert size.length == n; + + final int[] srcStrides = IntervalIndexer.createAllocationSteps( srcSize ); + final int[] destStrides = IntervalIndexer.createAllocationSteps( destSize ); + final int oSrc = IntervalIndexer.positionToIndex( srcPos, srcSize ); + final int oDest = IntervalIndexer.positionToIndex( destPos, destSize ); + + copyNDRangeRecursive( n - 1, + src, srcStrides, oSrc, + dest, destStrides, oDest, + size ); + } + + /** + * Recursively copy a {@code (d+1)} dimensional region from {@code src} to + * {@code dest}, where {@code src} and {@code dest} are flattened nD array + * with strides {@code srcStrides} and {@code destStrides}, respectively. + *

+ * For {@code d=0}, a 1D line of length {@code size[0]} is copied + * (equivalent to {@code System.arraycopy}). For {@code d=1}, a 2D plane of + * size {@code size[0] * size[1]} is copied, by recursively copying 1D + * lines, starting {@code srcStrides[1]} (respectively {@code + * destStrides[1]}) apart. For {@code d=2}, a 3D box is copied by + * recursively copying 2D planes, etc. + * + * @param d + * current dimension + * @param src + * flattened nD source array + * @param srcStrides + * nD strides of src + * @param srcPos + * flattened index (in src) to start copying from + * @param dest + * flattened nD destination array + * @param destStrides + * nD strides of dest + * @param destPos + * flattened index (in dest) to start copying to + * @param size + * nD size of the range to copy + */ + void copyNDRangeRecursive( + int d, + S src, int[] srcStrides, int srcPos, + T dest, int[] destStrides, int destPos, + int[] size ); + } +}