diff --git a/src/main/java/net/imglib2/loops/BindActionToSamplers.java b/src/main/java/net/imglib2/loops/BindActionToSamplers.java index 1c66f0a393..80e2438bbc 100644 --- a/src/main/java/net/imglib2/loops/BindActionToSamplers.java +++ b/src/main/java/net/imglib2/loops/BindActionToSamplers.java @@ -34,8 +34,6 @@ package net.imglib2.loops; -import net.imglib2.Sampler; - import java.util.Arrays; import java.util.List; import java.util.function.BiConsumer; @@ -43,19 +41,38 @@ import java.util.stream.Collectors; import java.util.stream.Stream; +import net.imglib2.RandomAccess; +import net.imglib2.Sampler; + /** * Package-private utility class that's used by {@link LoopBuilder}. */ final class BindActionToSamplers { - private static final List< ClassCopyProvider< Runnable > > factories = Arrays.asList( + private static final List< ClassCopyProvider< Runnable > > LOCALIZING_FACTORIES = Arrays.asList( + new ClassCopyProvider<>( ConsumerLocalizingRunnable.class, Runnable.class ), + new ClassCopyProvider<>( BiConsumerLocalizingRunnable.class, Runnable.class ), + new ClassCopyProvider<>( TriConsumerLocalizingRunnable.class, Runnable.class ), + new ClassCopyProvider<>( FourConsumerLocalizingRunnable.class, Runnable.class ), + new ClassCopyProvider<>( FiveConsumerLocalizingRunnable.class, Runnable.class ), + new ClassCopyProvider<>( SixConsumerLocalizingRunnable.class, Runnable.class ), + new ClassCopyProvider<>( SevenConsumerLocalizingRunnable.class, Runnable.class ), + new ClassCopyProvider<>( EightConsumerLocalizingRunnable.class, Runnable.class ), + new ClassCopyProvider<>( NineConsumerLocalizingRunnable.class, Runnable.class ), + new ClassCopyProvider<>( TenConsumerLocalizingRunnable.class, Runnable.class )); + + private static final List< ClassCopyProvider< Runnable > > FACTORIES = Arrays.asList( new ClassCopyProvider<>( ConsumerRunnable.class, Runnable.class ), new ClassCopyProvider<>( BiConsumerRunnable.class, Runnable.class ), new ClassCopyProvider<>( TriConsumerRunnable.class, Runnable.class ), new ClassCopyProvider<>( FourConsumerRunnable.class, Runnable.class ), new ClassCopyProvider<>( FiveConsumerRunnable.class, Runnable.class ), - new ClassCopyProvider<>( SixConsumerRunnable.class, Runnable.class )); + new ClassCopyProvider<>( SixConsumerRunnable.class, Runnable.class ), + new ClassCopyProvider<>( SevenConsumerRunnable.class, Runnable.class ), + new ClassCopyProvider<>( EightConsumerRunnable.class, Runnable.class ), + new ClassCopyProvider<>( NineConsumerRunnable.class, Runnable.class ), + new ClassCopyProvider<>( TenConsumerRunnable.class, Runnable.class )); /** * For example.: Given a BiConsumer and two Samplers: @@ -88,17 +105,32 @@ final class BindActionToSamplers * @param action * This must be an instance of {@link Consumer}, * {@link BiConsumer} of {@link LoopBuilder.TriConsumer}. - * {@link LoopBuilder.FourConsumer}, {@link LoopBuilder.FourConsumer}, + * {@link LoopBuilder.FourConsumer}, {@link LoopBuilder.FiveConsumer}, * or {@link LoopBuilder.SixConsumer}. * @param samplers * A list of {@link Sampler}, the size of the list must fit - * the consumer given by {@param operation}. + * the consumer given by {@code action}. + * @param localizing + * If true, action operates on {@link RandomAccess} objects typed + * the same as type {@link Sampler}s; if false, action operates + * on {@link Sampler} elements directly. * @throws IllegalArgumentException * if the number of sampler does not fit the given consumer. */ - public static Runnable bindActionToSamplers( final Object action, final List< ? extends Sampler< ? > > samplers ) + public static Runnable bindActionToSamplers( final Object action, final List< ? extends Sampler< ? > > samplers, final boolean localizing ) { - final Object[] arguments = Stream.concat( Stream.of( action ), samplers.stream() ).toArray(); + final Object[] arguments; + final List< ClassCopyProvider< Runnable > > factories; + if ( localizing ) + { + arguments = Stream.concat( Stream.of( action ), samplers.stream() ).toArray(); + factories = LOCALIZING_FACTORIES; + } + else + { + arguments = Stream.concat( Stream.of( action ), samplers.stream() ).toArray(); + factories = FACTORIES; + } for ( final ClassCopyProvider< Runnable > factory : factories ) if ( factory.matches( arguments ) ) { @@ -272,4 +304,509 @@ public void run() action.accept( samplerA.get(), samplerB.get(), samplerC.get(), samplerD.get(), samplerE.get(), samplerF.get() ); } } + + public static class SevenConsumerRunnable< A, B, C, D, E, F, G > implements Runnable + { + + private final LoopBuilder.SevenConsumer< A, B, C, D, E, F, G > action; + + private final Sampler< A > samplerA; + + private final Sampler< B > samplerB; + + private final Sampler< C > samplerC; + + private final Sampler< D > samplerD; + + private final Sampler< E > samplerE; + + private final Sampler< F > samplerF; + + private final Sampler< G > samplerG; + + public SevenConsumerRunnable( final LoopBuilder.SevenConsumer< A, B, C, D, E, F, G > action, final Sampler< A > samplerA, final Sampler< B > samplerB, final Sampler< C > samplerC, final Sampler< D > samplerD, final Sampler< E > samplerE, final Sampler< F > samplerF, final Sampler< G > samplerG ) + { + this.action = action; + this.samplerA = samplerA; + this.samplerB = samplerB; + this.samplerC = samplerC; + this.samplerD = samplerD; + this.samplerE = samplerE; + this.samplerF = samplerF; + this.samplerG = samplerG; + } + + @Override + public void run() + { + action.accept( samplerA.get(), samplerB.get(), samplerC.get(), samplerD.get(), samplerE.get(), samplerF.get(), samplerG.get() ); + } + } + + public static class EightConsumerRunnable< A, B, C, D, E, F, G, H > implements Runnable + { + + private final LoopBuilder.EightConsumer< A, B, C, D, E, F, G, H > action; + + private final Sampler< A > samplerA; + + private final Sampler< B > samplerB; + + private final Sampler< C > samplerC; + + private final Sampler< D > samplerD; + + private final Sampler< E > samplerE; + + private final Sampler< F > samplerF; + + private final Sampler< G > samplerG; + + private final Sampler< H > samplerH; + + public EightConsumerRunnable( final LoopBuilder.EightConsumer< A, B, C, D, E, F, G, H > action, final Sampler< A > samplerA, final Sampler< B > samplerB, final Sampler< C > samplerC, final Sampler< D > samplerD, final Sampler< E > samplerE, final Sampler< F > samplerF, final Sampler< G > samplerG, final Sampler< H > samplerH ) + { + this.action = action; + this.samplerA = samplerA; + this.samplerB = samplerB; + this.samplerC = samplerC; + this.samplerD = samplerD; + this.samplerE = samplerE; + this.samplerF = samplerF; + this.samplerG = samplerG; + this.samplerH = samplerH; + } + + @Override + public void run() + { + action.accept( samplerA.get(), samplerB.get(), samplerC.get(), samplerD.get(), samplerE.get(), samplerF.get(), samplerG.get(), samplerH.get() ); + } + } + + public static class NineConsumerRunnable< A, B, C, D, E, F, G, H, I > implements Runnable + { + + private final LoopBuilder.NineConsumer< A, B, C, D, E, F, G, H, I > action; + + private final Sampler< A > samplerA; + + private final Sampler< B > samplerB; + + private final Sampler< C > samplerC; + + private final Sampler< D > samplerD; + + private final Sampler< E > samplerE; + + private final Sampler< F > samplerF; + + private final Sampler< G > samplerG; + + private final Sampler< H > samplerH; + + private final Sampler< I > samplerI; + + public NineConsumerRunnable( final LoopBuilder.NineConsumer< A, B, C, D, E, F, G, H, I > action, final Sampler< A > samplerA, final Sampler< B > samplerB, final Sampler< C > samplerC, final Sampler< D > samplerD, final Sampler< E > samplerE, final Sampler< F > samplerF, final Sampler< G > samplerG, final Sampler< H > samplerH, final Sampler< I > samplerI ) + { + this.action = action; + this.samplerA = samplerA; + this.samplerB = samplerB; + this.samplerC = samplerC; + this.samplerD = samplerD; + this.samplerE = samplerE; + this.samplerF = samplerF; + this.samplerG = samplerG; + this.samplerH = samplerH; + this.samplerI = samplerI; + } + + @Override + public void run() + { + action.accept( samplerA.get(), samplerB.get(), samplerC.get(), samplerD.get(), samplerE.get(), samplerF.get(), samplerG.get(), samplerH.get(), samplerI.get() ); + } + } + + public static class TenConsumerRunnable< A, B, C, D, E, F, G, H, I, J > implements Runnable + { + + private final LoopBuilder.TenConsumer< A, B, C, D, E, F, G, H, I, J > action; + + private final Sampler< A > samplerA; + + private final Sampler< B > samplerB; + + private final Sampler< C > samplerC; + + private final Sampler< D > samplerD; + + private final Sampler< E > samplerE; + + private final Sampler< F > samplerF; + + private final Sampler< G > samplerG; + + private final Sampler< H > samplerH; + + private final Sampler< I > samplerI; + + private final Sampler< J > samplerJ; + + public TenConsumerRunnable( final LoopBuilder.TenConsumer< A, B, C, D, E, F, G, H, I, J > action, final Sampler< A > samplerA, final Sampler< B > samplerB, final Sampler< C > samplerC, final Sampler< D > samplerD, final Sampler< E > samplerE, final Sampler< F > samplerF, final Sampler< G > samplerG, final Sampler< H > samplerH, final Sampler< I > samplerI, final Sampler< J > samplerJ ) + { + this.action = action; + this.samplerA = samplerA; + this.samplerB = samplerB; + this.samplerC = samplerC; + this.samplerD = samplerD; + this.samplerE = samplerE; + this.samplerF = samplerF; + this.samplerG = samplerG; + this.samplerH = samplerH; + this.samplerI = samplerI; + this.samplerJ = samplerJ; + } + + @Override + public void run() + { + action.accept( samplerA.get(), samplerB.get(), samplerC.get(), samplerD.get(), samplerE.get(), samplerF.get(), samplerG.get(), samplerH.get(), samplerI.get(), samplerJ.get() ); + } + } + + public static class ConsumerLocalizingRunnable< A > implements Runnable + { + + private final Consumer< RandomAccess< A > > action; + + private final RandomAccess< A > accessA; + + public ConsumerLocalizingRunnable( final Consumer< RandomAccess< A > > action, final RandomAccess< A > accessA ) + { + this.action = action; + this.accessA = accessA; + } + + @Override + public void run() + { + action.accept( accessA ); + } + } + + public static class BiConsumerLocalizingRunnable< A, B > implements Runnable + { + + private final BiConsumer< RandomAccess< A >, RandomAccess< B > > action; + + private final RandomAccess< A > accessA; + + private final RandomAccess< B > accessB; + + public BiConsumerLocalizingRunnable( final BiConsumer< RandomAccess< A >, RandomAccess< B > > action, final RandomAccess< A > accessA, final RandomAccess< B > accessB ) + { + this.action = action; + this.accessA = accessA; + this.accessB = accessB; + } + + @Override + public void run() + { + action.accept( accessA, accessB ); + } + } + + public static class TriConsumerLocalizingRunnable< A, B, C > implements Runnable + { + + private final LoopBuilder.TriConsumer< RandomAccess< A >, RandomAccess< B >, RandomAccess< C > > action; + + private final RandomAccess< A > accessA; + + private final RandomAccess< B > accessB; + + private final RandomAccess< C > accessC; + + public TriConsumerLocalizingRunnable( final LoopBuilder.TriConsumer< RandomAccess< A >, RandomAccess< B >, RandomAccess < C > > action, final RandomAccess< A > accessA, final RandomAccess< B > accessB, final RandomAccess< C > accessC ) + { + this.action = action; + this.accessA = accessA; + this.accessB = accessB; + this.accessC = accessC; + } + + @Override + public void run() + { + action.accept( accessA, accessB, accessC ); + } + } + + public static class FourConsumerLocalizingRunnable< A, B, C, D > implements Runnable + { + + private final LoopBuilder.FourConsumer< RandomAccess< A >, RandomAccess< B >, RandomAccess< C >, RandomAccess< D > > action; + + private final RandomAccess< A > accessA; + + private final RandomAccess< B > accessB; + + private final RandomAccess< C > accessC; + + private final RandomAccess< D > accessD; + + public FourConsumerLocalizingRunnable( final LoopBuilder.FourConsumer< RandomAccess< A >, RandomAccess< B >, RandomAccess < C >, RandomAccess< D > > action, final RandomAccess< A > accessA, final RandomAccess< B > accessB, final RandomAccess< C > accessC, final RandomAccess< D > accessD ) + { + this.action = action; + this.accessA = accessA; + this.accessB = accessB; + this.accessC = accessC; + this.accessD = accessD; + } + + @Override + public void run() + { + action.accept( accessA, accessB, accessC, accessD ); + } + } + + public static class FiveConsumerLocalizingRunnable< A, B, C, D, E > implements Runnable + { + + private final LoopBuilder.FiveConsumer< RandomAccess< A >, RandomAccess< B >, RandomAccess< C >, RandomAccess< D >, RandomAccess< E > > action; + + private final RandomAccess< A > accessA; + + private final RandomAccess< B > accessB; + + private final RandomAccess< C > accessC; + + private final RandomAccess< D > accessD; + + private final RandomAccess< E > accessE; + + public FiveConsumerLocalizingRunnable( final LoopBuilder.FiveConsumer< RandomAccess< A >, RandomAccess< B >, RandomAccess < C >, RandomAccess< D >, RandomAccess< E > > action, final RandomAccess< A > accessA, final RandomAccess< B > accessB, final RandomAccess< C > accessC, final RandomAccess< D > accessD, final RandomAccess< E > accessE ) + { + this.action = action; + this.accessA = accessA; + this.accessB = accessB; + this.accessC = accessC; + this.accessD = accessD; + this.accessE = accessE; + } + + @Override + public void run() + { + action.accept( accessA, accessB, accessC, accessD, accessE ); + } + } + + public static class SixConsumerLocalizingRunnable< A, B, C, D, E, F > implements Runnable + { + + private final LoopBuilder.SixConsumer< RandomAccess< A >, RandomAccess< B >, RandomAccess< C >, RandomAccess< D >, RandomAccess< E >, RandomAccess< F > > action; + + private final RandomAccess< A > accessA; + + private final RandomAccess< B > accessB; + + private final RandomAccess< C > accessC; + + private final RandomAccess< D > accessD; + + private final RandomAccess< E > accessE; + + private final RandomAccess< F > accessF; + + public SixConsumerLocalizingRunnable( final LoopBuilder.SixConsumer< RandomAccess< A >, RandomAccess< B >, RandomAccess < C >, RandomAccess< D >, RandomAccess< E >, RandomAccess< F > > action, final RandomAccess< A > accessA, final RandomAccess< B > accessB, final RandomAccess< C > accessC, final RandomAccess< D > accessD, final RandomAccess< E > accessE, final RandomAccess< F > accessF ) + { + this.action = action; + this.accessA = accessA; + this.accessB = accessB; + this.accessC = accessC; + this.accessD = accessD; + this.accessE = accessE; + this.accessF = accessF; + } + + @Override + public void run() + { + action.accept( accessA, accessB, accessC, accessD, accessE, accessF ); + } + } + + public static class SevenConsumerLocalizingRunnable< A, B, C, D, E, F, G > implements Runnable + { + + private final LoopBuilder.SevenConsumer< RandomAccess< A >, RandomAccess< B >, RandomAccess< C >, RandomAccess< D >, RandomAccess< E >, RandomAccess< F >, RandomAccess< G > > action; + + private final RandomAccess< A > accessA; + + private final RandomAccess< B > accessB; + + private final RandomAccess< C > accessC; + + private final RandomAccess< D > accessD; + + private final RandomAccess< E > accessE; + + private final RandomAccess< F > accessF; + + private final RandomAccess< G > accessG; + + public SevenConsumerLocalizingRunnable( final LoopBuilder.SevenConsumer< RandomAccess< A >, RandomAccess< B >, RandomAccess < C >, RandomAccess< D >, RandomAccess< E >, RandomAccess< F >, RandomAccess< G > > action, final RandomAccess< A > accessA, final RandomAccess< B > accessB, final RandomAccess< C > accessC, final RandomAccess< D > accessD, final RandomAccess< E > accessE, final RandomAccess< F > accessF, final RandomAccess< G > accessG ) + { + this.action = action; + this.accessA = accessA; + this.accessB = accessB; + this.accessC = accessC; + this.accessD = accessD; + this.accessE = accessE; + this.accessF = accessF; + this.accessG = accessG; + } + + @Override + public void run() + { + action.accept( accessA, accessB, accessC, accessD, accessE, accessF, accessG ); + } + } + + public static class EightConsumerLocalizingRunnable< A, B, C, D, E, F, G, H > implements Runnable + { + + private final LoopBuilder.EightConsumer< RandomAccess< A >, RandomAccess< B >, RandomAccess< C >, RandomAccess< D >, RandomAccess< E >, RandomAccess< F >, RandomAccess< G >, RandomAccess< H > > action; + + private final RandomAccess< A > accessA; + + private final RandomAccess< B > accessB; + + private final RandomAccess< C > accessC; + + private final RandomAccess< D > accessD; + + private final RandomAccess< E > accessE; + + private final RandomAccess< F > accessF; + + private final RandomAccess< G > accessG; + + private final RandomAccess< H > accessH; + + public EightConsumerLocalizingRunnable( final LoopBuilder.EightConsumer< RandomAccess< A >, RandomAccess< B >, RandomAccess < C >, RandomAccess< D >, RandomAccess< E >, RandomAccess< F >, RandomAccess< G >, RandomAccess< H > > action, final RandomAccess< A > accessA, final RandomAccess< B > accessB, final RandomAccess< C > accessC, final RandomAccess< D > accessD, final RandomAccess< E > accessE, final RandomAccess< F > accessF, final RandomAccess< G > accessG, final RandomAccess< H > accessH ) + { + this.action = action; + this.accessA = accessA; + this.accessB = accessB; + this.accessC = accessC; + this.accessD = accessD; + this.accessE = accessE; + this.accessF = accessF; + this.accessG = accessG; + this.accessH = accessH; + } + + @Override + public void run() + { + action.accept( accessA, accessB, accessC, accessD, accessE, accessF, accessG, accessH ); + } + } + + public static class NineConsumerLocalizingRunnable< A, B, C, D, E, F, G, H, I > implements Runnable + { + + private final LoopBuilder.NineConsumer< RandomAccess< A >, RandomAccess< B >, RandomAccess< C >, RandomAccess< D >, RandomAccess< E >, RandomAccess< F >, RandomAccess< G >, RandomAccess< H >, RandomAccess< I > > action; + + private final RandomAccess< A > accessA; + + private final RandomAccess< B > accessB; + + private final RandomAccess< C > accessC; + + private final RandomAccess< D > accessD; + + private final RandomAccess< E > accessE; + + private final RandomAccess< F > accessF; + + private final RandomAccess< G > accessG; + + private final RandomAccess< H > accessH; + + private final RandomAccess< I > accessI; + + public NineConsumerLocalizingRunnable( final LoopBuilder.NineConsumer< RandomAccess< A >, RandomAccess< B >, RandomAccess < C >, RandomAccess< D >, RandomAccess< E >, RandomAccess< F >, RandomAccess< G >, RandomAccess< H >, RandomAccess< I > > action, final RandomAccess< A > accessA, final RandomAccess< B > accessB, final RandomAccess< C > accessC, final RandomAccess< D > accessD, final RandomAccess< E > accessE, final RandomAccess< F > accessF, final RandomAccess< G > accessG, final RandomAccess< H > accessH, final RandomAccess< I > accessI ) + { + this.action = action; + this.accessA = accessA; + this.accessB = accessB; + this.accessC = accessC; + this.accessD = accessD; + this.accessE = accessE; + this.accessF = accessF; + this.accessG = accessG; + this.accessH = accessH; + this.accessI = accessI; + } + + @Override + public void run() + { + action.accept( accessA, accessB, accessC, accessD, accessE, accessF, accessG, accessH, accessI ); + } + } + + public static class TenConsumerLocalizingRunnable< A, B, C, D, E, F, G, H, I, J > implements Runnable + { + + private final LoopBuilder.TenConsumer< RandomAccess< A >, RandomAccess< B >, RandomAccess< C >, RandomAccess< D >, RandomAccess< E >, RandomAccess< F >, RandomAccess< G >, RandomAccess< H >, RandomAccess< I >, RandomAccess< J > > action; + + private final RandomAccess< A > accessA; + + private final RandomAccess< B > accessB; + + private final RandomAccess< C > accessC; + + private final RandomAccess< D > accessD; + + private final RandomAccess< E > accessE; + + private final RandomAccess< F > accessF; + + private final RandomAccess< G > accessG; + + private final RandomAccess< H > accessH; + + private final RandomAccess< I > accessI; + + private final RandomAccess< J > accessJ; + + public TenConsumerLocalizingRunnable( final LoopBuilder.TenConsumer< RandomAccess< A >, RandomAccess< B >, RandomAccess < C >, RandomAccess< D >, RandomAccess< E >, RandomAccess< F >, RandomAccess< G >, RandomAccess< H >, RandomAccess< I >, RandomAccess< J > > action, final RandomAccess< A > accessA, final RandomAccess< B > accessB, final RandomAccess< C > accessC, final RandomAccess< D > accessD, final RandomAccess< E > accessE, final RandomAccess< F > accessF, final RandomAccess< G > accessG, final RandomAccess< H > accessH, final RandomAccess< I > accessI, final RandomAccess< J > accessJ ) + { + this.action = action; + this.accessA = accessA; + this.accessB = accessB; + this.accessC = accessC; + this.accessD = accessD; + this.accessE = accessE; + this.accessF = accessF; + this.accessG = accessG; + this.accessH = accessH; + this.accessI = accessI; + this.accessJ = accessJ; + } + + @Override + public void run() + { + action.accept( accessA, accessB, accessC, accessD, accessE, accessF, accessG, accessH, accessI, accessJ ); + } + } } diff --git a/src/main/java/net/imglib2/loops/LoopBuilder.java b/src/main/java/net/imglib2/loops/LoopBuilder.java index a2139b854c..7394e691be 100644 --- a/src/main/java/net/imglib2/loops/LoopBuilder.java +++ b/src/main/java/net/imglib2/loops/LoopBuilder.java @@ -48,9 +48,11 @@ import net.imglib2.FinalInterval; import net.imglib2.Interval; import net.imglib2.IterableInterval; +import net.imglib2.Localizable; import net.imglib2.Positionable; import net.imglib2.RandomAccess; import net.imglib2.RandomAccessibleInterval; +import net.imglib2.Sampler; import net.imglib2.img.array.AbstractArrayCursor; import net.imglib2.img.cell.CellCursor; import net.imglib2.img.planar.PlanarCursor; @@ -82,8 +84,10 @@ * {@link Intervals} can differ. * * @author Matthias Arzt + * @param Action type of pixelwise operation, {@link #forEachPixel without localization}. + * @param Action type of pixelwise operation, {@link #forEachPixelLocalizing with localization}. */ -public class LoopBuilder< T > +public class LoopBuilder< T, LT > { // fields @@ -101,7 +105,7 @@ public class LoopBuilder< T > /** * @see LoopBuilder */ - public static < A > LoopBuilder< Consumer< A > > setImages( final RandomAccessibleInterval< A > a ) + public static < A, LA extends Localizable & Sampler< A > > LoopBuilder< Consumer< A >, Consumer< LA > > setImages( final RandomAccessibleInterval< A > a ) { return new LoopBuilder<>( a ); } @@ -109,7 +113,7 @@ public static < A > LoopBuilder< Consumer< A > > setImages( final RandomAccessib /** * @see LoopBuilder */ - public static < A, B > LoopBuilder< BiConsumer< A, B > > setImages( final RandomAccessibleInterval< A > a, final RandomAccessibleInterval< B > b ) + public static < A, B, LA extends Localizable & Sampler< A >, LB extends Localizable & Sampler< B > > LoopBuilder< BiConsumer< A, B >, BiConsumer< LA, LB > > setImages( final RandomAccessibleInterval< A > a, final RandomAccessibleInterval< B > b ) { return new LoopBuilder<>( a, b ); } @@ -117,7 +121,7 @@ public static < A, B > LoopBuilder< BiConsumer< A, B > > setImages( final Random /** * @see LoopBuilder */ - public static < A, B, C > LoopBuilder< TriConsumer< A, B, C > > setImages( final RandomAccessibleInterval< A > a, final RandomAccessibleInterval< B > b, final RandomAccessibleInterval< C > c ) + public static < A, B, C, LA extends Localizable & Sampler< A >, LB extends Localizable & Sampler< B >, LC extends Localizable & Sampler< C > > LoopBuilder< TriConsumer< A, B, C >, TriConsumer< LA, LB, LC > > setImages( final RandomAccessibleInterval< A > a, final RandomAccessibleInterval< B > b, final RandomAccessibleInterval< C > c ) { return new LoopBuilder<>( a, b, c ); } @@ -125,7 +129,7 @@ public static < A, B, C > LoopBuilder< TriConsumer< A, B, C > > setImages( final /** * @see LoopBuilder */ - public static < A, B, C, D > LoopBuilder< FourConsumer< A, B, C, D > > setImages( final RandomAccessibleInterval< A > a, final RandomAccessibleInterval< B > b, final RandomAccessibleInterval< C > c, final RandomAccessibleInterval< D > d ) + public static < A, B, C, D, LA extends Localizable & Sampler< A >, LB extends Localizable & Sampler< B >, LC extends Localizable & Sampler< C >, LD extends Localizable & Sampler< D > > LoopBuilder< FourConsumer< A, B, C, D >, FourConsumer< LA, LB, LC, LD > > setImages( final RandomAccessibleInterval< A > a, final RandomAccessibleInterval< B > b, final RandomAccessibleInterval< C > c, final RandomAccessibleInterval< D > d ) { return new LoopBuilder<>( a, b, c, d ); } @@ -133,7 +137,7 @@ public static < A, B, C, D > LoopBuilder< FourConsumer< A, B, C, D > > setImages /** * @see LoopBuilder */ - public static < A, B, C, D, E > LoopBuilder< FiveConsumer< A, B, C, D, E > > setImages( final RandomAccessibleInterval< A > a, final RandomAccessibleInterval< B > b, final RandomAccessibleInterval< C > c, final RandomAccessibleInterval< D > d, final RandomAccessibleInterval< E > e ) + public static < A, B, C, D, E, LA extends Localizable & Sampler< A >, LB extends Localizable & Sampler< B >, LC extends Localizable & Sampler< C >, LD extends Localizable & Sampler< D >, LE extends Localizable & Sampler< E > > LoopBuilder< FiveConsumer< A, B, C, D, E >, FiveConsumer< LA, LB, LC, LD, LE > > setImages( final RandomAccessibleInterval< A > a, final RandomAccessibleInterval< B > b, final RandomAccessibleInterval< C > c, final RandomAccessibleInterval< D > d, final RandomAccessibleInterval< E > e ) { return new LoopBuilder<>( a, b, c, d, e ); } @@ -141,11 +145,43 @@ public static < A, B, C, D, E > LoopBuilder< FiveConsumer< A, B, C, D, E > > set /** * @see LoopBuilder */ - public static < A, B, C, D, E, F > LoopBuilder< SixConsumer< A, B, C, D, E, F > > setImages( final RandomAccessibleInterval< A > a, final RandomAccessibleInterval< B > b, final RandomAccessibleInterval< C > c, final RandomAccessibleInterval< D > d, final RandomAccessibleInterval< E > e, final RandomAccessibleInterval< F > f ) + public static < A, B, C, D, E, F, LA extends Localizable & Sampler< A >, LB extends Localizable & Sampler< B >, LC extends Localizable & Sampler< C >, LD extends Localizable & Sampler< D >, LE extends Localizable & Sampler< E >, LF extends Localizable & Sampler< F > > LoopBuilder< SixConsumer< A, B, C, D, E, F >, SixConsumer< LA, LB, LC, LD, LE, LF > > setImages( final RandomAccessibleInterval< A > a, final RandomAccessibleInterval< B > b, final RandomAccessibleInterval< C > c, final RandomAccessibleInterval< D > d, final RandomAccessibleInterval< E > e, final RandomAccessibleInterval< F > f ) { return new LoopBuilder<>( a, b, c, d, e, f ); } + /** + * @see LoopBuilder + */ + public static < A, B, C, D, E, F, G, LA extends Localizable & Sampler< A >, LB extends Localizable & Sampler< B >, LC extends Localizable & Sampler< C >, LD extends Localizable & Sampler< D >, LE extends Localizable & Sampler< E >, LF extends Localizable & Sampler< F >, LG extends Localizable & Sampler< G > > LoopBuilder< SevenConsumer< A, B, C, D, E, F, G >, SevenConsumer< LA, LB, LC, LD, LE, LF, LG > > setImages( final RandomAccessibleInterval< A > a, final RandomAccessibleInterval< B > b, final RandomAccessibleInterval< C > c, final RandomAccessibleInterval< D > d, final RandomAccessibleInterval< E > e, final RandomAccessibleInterval< F > f, final RandomAccessibleInterval< G > g ) + { + return new LoopBuilder<>( a, b, c, d, e, f, g ); + } + + /** + * @see LoopBuilder + */ + public static < A, B, C, D, E, F, G, H, LA extends Localizable & Sampler< A >, LB extends Localizable & Sampler< B >, LC extends Localizable & Sampler< C >, LD extends Localizable & Sampler< D >, LE extends Localizable & Sampler< E >, LF extends Localizable & Sampler< F >, LG extends Localizable & Sampler< G >, LH extends Localizable & Sampler< H > > LoopBuilder< EightConsumer< A, B, C, D, E, F, G, H >, EightConsumer< LA, LB, LC, LD, LE, LF, LG, LH > > setImages( final RandomAccessibleInterval< A > a, final RandomAccessibleInterval< B > b, final RandomAccessibleInterval< C > c, final RandomAccessibleInterval< D > d, final RandomAccessibleInterval< E > e, final RandomAccessibleInterval< F > f, final RandomAccessibleInterval< G > g, final RandomAccessibleInterval< H > h ) + { + return new LoopBuilder<>( a, b, c, d, e, f, g, h ); + } + + /** + * @see LoopBuilder + */ + public static < A, B, C, D, E, F, G, H, I, LA extends Localizable & Sampler< A >, LB extends Localizable & Sampler< B >, LC extends Localizable & Sampler< C >, LD extends Localizable & Sampler< D >, LE extends Localizable & Sampler< E >, LF extends Localizable & Sampler< F >, LG extends Localizable & Sampler< G >, LH extends Localizable & Sampler< H >, LI extends Localizable & Sampler< I > > LoopBuilder< NineConsumer< A, B, C, D, E, F, G, H, I >, NineConsumer< LA, LB, LC, LD, LE, LF, LG, LH, LI > > setImages( final RandomAccessibleInterval< A > a, final RandomAccessibleInterval< B > b, final RandomAccessibleInterval< C > c, final RandomAccessibleInterval< D > d, final RandomAccessibleInterval< E > e, final RandomAccessibleInterval< F > f, final RandomAccessibleInterval< G > g, final RandomAccessibleInterval< H > h, final RandomAccessibleInterval< I > i ) + { + return new LoopBuilder<>( a, b, c, d, e, f, g, h, i ); + } + + /** + * @see LoopBuilder + */ + public static < A, B, C, D, E, F, G, H, I, J, LA extends Localizable & Sampler< A >, LB extends Localizable & Sampler< B >, LC extends Localizable & Sampler< C >, LD extends Localizable & Sampler< D >, LE extends Localizable & Sampler< E >, LF extends Localizable & Sampler< F >, LG extends Localizable & Sampler< G >, LH extends Localizable & Sampler< H >, LI extends Localizable & Sampler< I >, LJ extends Localizable & Sampler< J > > LoopBuilder< TenConsumer< A, B, C, D, E, F, G, H, I, J >, TenConsumer< LA, LB, LC, LD, LE, LF, LG, LH, LI, LJ > > setImages( final RandomAccessibleInterval< A > a, final RandomAccessibleInterval< B > b, final RandomAccessibleInterval< C > c, final RandomAccessibleInterval< D > d, final RandomAccessibleInterval< E > e, final RandomAccessibleInterval< F > f, final RandomAccessibleInterval< G > g, final RandomAccessibleInterval< H > h, final RandomAccessibleInterval< I > i, final RandomAccessibleInterval< J > j ) + { + return new LoopBuilder<>( a, b, c, d, e, f, g, h, i, j ); + } + /** * @see LoopBuilder */ @@ -158,7 +194,15 @@ public void forEachPixel( final T action ) if ( allCursorsAreFast( iterableIntervals ) ) runUsingCursors( iterableIntervals, action ); else - runUsingRandomAccesses( action ); + runUsingRandomAccesses( action, false ); + } + + public void forEachPixelLocalizing( final LT action ) + { + Objects.requireNonNull( action ); + if ( Intervals.numElements( dimensions ) == 0 ) + return; + runUsingRandomAccesses( action, true ); } private boolean allCursorsAreFast( List> iterableIntervals ) @@ -181,7 +225,7 @@ private boolean cursorIsFast( IterableInterval image ) *

* WARNING: You need to make sure that your operation is thread safe. */ - public LoopBuilder< T > multiThreaded() + public LoopBuilder< T, LT > multiThreaded() { this.multiThreaded = Objects.requireNonNull( MultiThreadSetting.MULTI ); return this; @@ -195,7 +239,7 @@ public LoopBuilder< T > multiThreaded() * WARNING: Don't use multi-threading if you want to have flat * iteration order. */ - public LoopBuilder< T > flatIterationOrder() + public LoopBuilder< T, LT > flatIterationOrder() { return this.flatIterationOrder( true ); } @@ -212,7 +256,7 @@ public LoopBuilder< T > flatIterationOrder() * * @see net.imglib2.FlatIterationOrder */ - public LoopBuilder< T > flatIterationOrder( boolean value ) + public LoopBuilder< T, LT > flatIterationOrder( boolean value ) { this.useFlatIterationOrder = value; return this; @@ -238,6 +282,26 @@ public interface SixConsumer< A, B, C, D, E, F > void accept( A a, B b, C c, D d, E e, F f ); } + public interface SevenConsumer< A, B, C, D, E, F, G > + { + void accept( A a, B b, C c, D d, E e, F f, G g ); + } + + public interface EightConsumer< A, B, C, D, E, F, G, H > + { + void accept( A a, B b, C c, D d, E e, F f, G g, H h ); + } + + public interface NineConsumer< A, B, C, D, E, F, G, H, I > + { + void accept( A a, B b, C c, D d, E e, F f, G g, H h, I i ); + } + + public interface TenConsumer< A, B, C, D, E, F, G, H, I, J > + { + void accept( A a, B b, C c, D d, E e, F f, G g, H h, I i, J j ); + } + // Helper methods private LoopBuilder( final RandomAccessibleInterval< ? >... images ) @@ -260,21 +324,21 @@ private void checkDimensions() } } - void runUsingRandomAccesses( T action ) + void runUsingRandomAccesses( Object action, boolean localizing ) { final int nTasks = multiThreaded.suggestNumberOfTasks(); final Interval interval = new FinalInterval( dimensions ); final List< Interval > chunks = IntervalChunks.chunkInterval( interval, nTasks ); - multiThreaded.forEach( chunks, chunk -> runOnChunkUsingRandomAccesses( images, action, chunk ) ); + multiThreaded.forEach( chunks, chunk -> runOnChunkUsingRandomAccesses( images, action, chunk, localizing ) ); } - static void runOnChunkUsingRandomAccesses( RandomAccessibleInterval[] images, Object action, Interval subInterval ) + static void runOnChunkUsingRandomAccesses( RandomAccessibleInterval[] images, Object action, Interval subInterval, boolean localizing ) { final List< RandomAccess< ? > > samplers = Stream.of( images ).map( LoopBuilder::initRandomAccess ).collect( Collectors.toList() ); final Positionable synced = SyncedPositionables.create( samplers ); if ( !Views.isZeroMin( subInterval ) ) synced.move( Intervals.minAsLongArray( subInterval ) ); - final Runnable runnable = BindActionToSamplers.bindActionToSamplers( action, samplers ); + final Runnable runnable = BindActionToSamplers.bindActionToSamplers( action, samplers, localizing ); LoopUtils.createIntervalLoop( synced, subInterval, runnable ).run(); } diff --git a/src/test/java/net/imglib2/loops/LoopBuilderTest.java b/src/test/java/net/imglib2/loops/LoopBuilderTest.java index 2a7b542d72..562fe685e7 100644 --- a/src/test/java/net/imglib2/loops/LoopBuilderTest.java +++ b/src/test/java/net/imglib2/loops/LoopBuilderTest.java @@ -33,6 +33,17 @@ */ package net.imglib2.loops; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.util.Arrays; +import java.util.List; +import java.util.Random; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.BiConsumer; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + import net.imglib2.Cursor; import net.imglib2.Interval; import net.imglib2.RandomAccessibleInterval; @@ -45,21 +56,11 @@ import net.imglib2.test.ImgLib2Assert; import net.imglib2.test.RandomImgs; import net.imglib2.type.numeric.integer.IntType; +import net.imglib2.util.IntervalIndexer; import net.imglib2.util.Intervals; import net.imglib2.view.Views; -import org.junit.Test; -import java.util.Arrays; -import java.util.List; -import java.util.Random; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.function.BiConsumer; -import java.util.stream.Collectors; -import java.util.stream.IntStream; - -import static org.junit.Assert.assertEquals; +import org.junit.Test; /** * Tests {@link LoopBuilder}. @@ -167,8 +168,8 @@ public void testRunUsingRandomAccessesOnSubInterval() Img< IntType > output = ArrayImgs.ints( dimensions ); // process Interval interval = Intervals.createMinSize( 1, 0, 1, 2 ); + LoopBuilder.runOnChunkUsingRandomAccesses( new RandomAccessibleInterval[] { input, output }, COPY_ACTION, interval, false ); // test - LoopBuilder.runOnChunkUsingRandomAccesses( new RandomAccessibleInterval[] { input, output }, COPY_ACTION, interval ); ImgLib2Assert.assertImageEquals( expected, output ); } @@ -224,4 +225,36 @@ public void testCheckDimensions() { RandomAccessibleInterval imageB = ArrayImgs.ints( 10, 10, 2 ); LoopBuilder.setImages( imageA, imageB ).forEachPixel( (a, b) -> {} ); } + + @Test + public void testLocalizing() + { + final RandomAccessibleInterval< IntType > imageA = ArrayImgs.ints( 7, 11 ); + final RandomAccessibleInterval< IntType > imageB = ArrayImgs.ints( 7, 11 ); + final long[] expected = new long[ 2 ]; + LoopBuilder.setImages( imageA, imageB ).forEachPixelLocalizing( ( a, b ) -> { + final long x = a.getLongPosition( 0 ), y = a.getLongPosition( 1 ); + assertEquals( expected[ 0 ], x ); + assertEquals( expected[ 1 ], y ); + expected[ 0 ]++; + if ( expected[ 0 ] == imageA.dimension( 0 ) ) + { + expected[ 0 ] = 0; + expected[ 1 ]++; + } + } ); + } + + @Test + public void testLocalizingMultiThreaded() + { + final RandomAccessibleInterval< IntType > imageA = ArrayImgs.ints( 671, 1152 ); + final RandomAccessibleInterval< IntType > imageB = ArrayImgs.ints( 671, 1152 ); + final int[] visited = new int[ ( int ) Intervals.numElements( imageA ) ]; + LoopBuilder.setImages( imageA, imageB ).multiThreaded().forEachPixelLocalizing( ( a, b ) -> { + final int index = ( int ) IntervalIndexer.positionToIndex( a, imageA ); + visited[ index ]++; + } ); + assertTrue( IntStream.of( visited ).allMatch( v -> v == 1 ) ); + } }