Skip to content

Commit

Permalink
Revise blocks API
Browse files Browse the repository at this point in the history
* Instead of delegating execution to BlockProcessor, UnaryBlockOperator
  takes care of chaining operations now:
  The new compute(BlockSupplier source, Interval, Object dest) method
  handles source interval computation, getting source data, and
  computing result in one go, instead of the sequential BlockProcessor
  API.
  This is much nicer. It enables pass-through operators
  (Convert.Identity or logging for example). It should also be easier
  now to extend the API to keep data on the GPU for sequences of GPU
  operators.
* The copy/compute API all operate on Interval now. Other signatures
  have been removed for simplicity. With the new BlockInterval class
  from imglib2 core, unnecessarily converting between int[] and long[]
  is usually avoided.
  • Loading branch information
tpietzsch committed Nov 20, 2024
1 parent 9e7ee27 commit ba36be1
Show file tree
Hide file tree
Showing 22 changed files with 476 additions and 749 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,8 @@

import static net.imglib2.util.Util.safeInt;

import java.util.Arrays;

import net.imglib2.Interval;
import net.imglib2.algorithm.blocks.util.BlockProcessorSourceInterval;
import net.imglib2.blocks.BlockInterval;
import net.imglib2.blocks.TempArray;
import net.imglib2.type.PrimitiveType;
import net.imglib2.util.Intervals;
Expand All @@ -51,12 +49,12 @@
* adaptable number of dimensions (such as converters), see {@link
* AbstractDimensionlessBlockProcessor}.
* <p>
* {@link BlockProcessor#getSourcePos() getSourcePos()}, {@link
* BlockProcessor#getSourceSize() getSourceSize()}, and {@link
* BlockProcessor#getSourceInterval() getSourceInterval()} are implemented to
* return the {@code protected} fields {@code long[] sourcePos} and {@code
* }int[] sourceSize}. The {@code }protected} method {@code }int sourceLength()}
* can be used to get the number of elements in the source interval.
* A {@link BlockInterval} of the desired number of dimensions is exposed
* through {@link #getSourceInterval()}. (For convenience, {@code min} and
* {@code dimensions} of the interval are also exposed through the {@code
* protected} fields {@link #sourcePos} and {@link #sourceSize}.) The {@code
* protected} method {@link #sourceLength()} returns the number of elements in
* the source interval.
* <p>
* {@link BlockProcessor#getSourceBuffer() getSourceBuffer()} is implemented
* according to the {@code sourcePrimitiveType} specified at construction.
Expand All @@ -70,53 +68,41 @@ public abstract class AbstractBlockProcessor< I, O > implements BlockProcessor<
{
private final TempArray< I > tempArray;

private final BlockInterval sourceInterval;

protected final long[] sourcePos;

protected final int[] sourceSize;

private final BlockProcessorSourceInterval sourceInterval = new BlockProcessorSourceInterval( this );

protected AbstractBlockProcessor( final PrimitiveType sourcePrimitiveType, final int numSourceDimensions )
{
tempArray = TempArray.forPrimitiveType( sourcePrimitiveType );
sourcePos = new long[ numSourceDimensions ];
sourceSize = new int[ numSourceDimensions ];
sourceInterval = new BlockInterval( numSourceDimensions );
sourcePos = sourceInterval.min();
sourceSize = sourceInterval.size();
}

protected AbstractBlockProcessor( final AbstractBlockProcessor< I, O > proc )
{
tempArray = proc.tempArray.newInstance();
final int numSourceDimensions = proc.sourcePos.length;
sourcePos = new long[ numSourceDimensions ];
sourceSize = new int[ numSourceDimensions ];
sourceInterval = new BlockInterval( proc.sourceInterval.numDimensions() );
sourcePos = sourceInterval.min();
sourceSize = sourceInterval.size();
}

protected int sourceLength()
{
return safeInt( Intervals.numElements( sourceSize ) );
return safeInt( Intervals.numElements( sourceInterval ) );
}

@Override
public void setTargetInterval( final Interval interval )
{
interval.min( sourcePos );
Arrays.setAll( sourceSize, d -> safeInt( interval.dimension( d ) ) );
}

@Override
public long[] getSourcePos()
{
return sourcePos;
}

@Override
public int[] getSourceSize()
{
return sourceSize;
sourceInterval.setFrom( interval );
}

@Override
public Interval getSourceInterval()
public BlockInterval getSourceInterval()
{
return sourceInterval;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@

import java.util.function.Supplier;

import net.imglib2.Interval;
import net.imglib2.type.NativeType;
import net.imglib2.util.CloseableThreadLocal;

Expand Down Expand Up @@ -68,9 +69,9 @@ public int numDimensions()
}

@Override
public void copy( final long[] srcPos, final Object dest, final int[] size )
public void copy( final Interval interval, final Object dest )
{
threadSafeSupplier.get().copy( srcPos, dest, size );
threadSafeSupplier.get().copy( interval, dest );
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,8 @@

import static net.imglib2.util.Util.safeInt;

import java.util.Arrays;

import net.imglib2.Interval;
import net.imglib2.algorithm.blocks.util.BlockProcessorSourceInterval;
import net.imglib2.blocks.BlockInterval;
import net.imglib2.blocks.TempArray;
import net.imglib2.type.PrimitiveType;
import net.imglib2.util.Intervals;
Expand All @@ -50,12 +48,10 @@
* number of dimensions (such as converters). For {@code BlockProcessor} with a
* fixed number of source dimensions, see {@link AbstractBlockProcessor}.
* <p>
* {@link BlockProcessor#getSourcePos() getSourcePos()}, {@link
* BlockProcessor#getSourceSize() getSourceSize()}, and {@link
* BlockProcessor#getSourceInterval() getSourceInterval()} are implemented to
* return the {@code protected} fields {@code long[] sourcePos} and {@code
* }int[] sourceSize}. The {@code }protected} method {@code }int sourceLength()}
* can be used to get the number of elements in the source interval.
* A {@link BlockInterval} is exposed through {@link #getSourceInterval()}
* (after {@link #setTargetInterval} has been called). The {@code protected}
* method {@link #sourceLength()} returns the number of elements in the source
* interval.
* <p>
* {@link BlockProcessor#getSourceBuffer() getSourceBuffer()} is implemented
* according to the {@code sourcePrimitiveType} specified at construction.
Expand All @@ -69,11 +65,7 @@ public abstract class AbstractDimensionlessBlockProcessor< I, O > implements Blo
{
private final TempArray< I > tempArray;

protected long[] sourcePos;

protected int[] sourceSize;

private final BlockProcessorSourceInterval sourceInterval = new BlockProcessorSourceInterval( this );
protected BlockInterval sourceInterval;

protected AbstractDimensionlessBlockProcessor( final PrimitiveType sourcePrimitiveType )
{
Expand All @@ -88,50 +80,36 @@ protected AbstractDimensionlessBlockProcessor( final AbstractDimensionlessBlockP
@Override
public void setTargetInterval( final Interval interval )
{
updateNumSourceDimsensions( interval.numDimensions() );
interval.min( sourcePos );
Arrays.setAll( sourceSize, d -> safeInt( interval.dimension( d ) ) );
updateNumSourceDimensions( interval.numDimensions() );
sourceInterval.setFrom( interval );
}

/**
* Re-allocates {@code sourcePos} and {@code sourceSize} arrays if they do
* not already exist and have {@code length==n}.
* Re-allocates {@code sourceInterval} if it does not already exist and
* match {@code numDimensions()==n}.
*
* @param n
* new number of source dimensions
*
* @return {@code true} if {@code sourcePos} and {@code sourceSize} arrays were re-allocated
* @return {@code true} if {@code sourceInterval} was re-allocated
*/
protected boolean updateNumSourceDimsensions( final int n )
protected boolean updateNumSourceDimensions( final int n )
{
if ( sourcePos == null || sourcePos.length != n )
if ( sourceInterval == null || sourceInterval.numDimensions() != n )
{
sourcePos = new long[ n ];
sourceSize = new int[ n ];
sourceInterval = new BlockInterval( n );
return true;
}
return false;
}

protected int sourceLength()
{
return safeInt( Intervals.numElements( sourceSize ) );
}

@Override
public long[] getSourcePos()
{
return sourcePos;
}

@Override
public int[] getSourceSize()
{
return sourceSize;
return safeInt( Intervals.numElements( sourceInterval ) );
}

@Override
public Interval getSourceInterval()
public BlockInterval getSourceInterval()
{
return sourceInterval;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@
* %%
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
Expand All @@ -33,65 +33,61 @@
*/
package net.imglib2.algorithm.blocks;

import java.util.function.Supplier;

import net.imglib2.type.NativeType;
import net.imglib2.util.Cast;
import net.imglib2.util.CloseableThreadLocal;

/**
* Does nothing. This should be eliminated when concatenating through
* {@link UnaryBlockOperator#andThen(UnaryBlockOperator)} or {@link BlockSupplier#andThen(UnaryBlockOperator)}.
* Abstract implementation of {@link UnaryBlockOperator}.
* Takes care of source/target type/dimensionality boilerplate.
*
* @param <S>
* source type
* @param <T>
* target type
*/
public class NoOpUnaryBlockOperator< S extends NativeType< S >, T extends NativeType< T > > implements UnaryBlockOperator< S, T >
public abstract class AbstractUnaryBlockOperator< S extends NativeType< S >, T extends NativeType< T > > implements UnaryBlockOperator< S, T >
{
@Override
public < I, O > BlockProcessor< I, O > blockProcessor()
private final S sourceType;
private final T targetType;
private final int numSourceDimensions;
private final int numTargetDimensions;

protected AbstractUnaryBlockOperator( S sourceType, T targetType, int numSourceDimensions, int numTargetDimensions )
{
throw new UnsupportedOperationException();
this.sourceType = sourceType;
this.targetType = targetType;
this.numSourceDimensions = numSourceDimensions;
this.numTargetDimensions = numTargetDimensions;
}

@Override
public < U extends NativeType< U > > UnaryBlockOperator< S, U > andThen( UnaryBlockOperator< T, U > op )
protected AbstractUnaryBlockOperator( AbstractUnaryBlockOperator< S, T > op )
{
return Cast.unchecked( op );
this.sourceType = op.sourceType;
this.targetType = op.targetType;
this.numSourceDimensions = op.numSourceDimensions;
this.numTargetDimensions = op.numTargetDimensions;
}

@Override
public S getSourceType()
{
throw new UnsupportedOperationException();
return sourceType;
}

@Override
public T getTargetType()
{
throw new UnsupportedOperationException();
return targetType;
}

@Override
public int numSourceDimensions()
{
return 0;
return numSourceDimensions;
}

@Override
public int numTargetDimensions()
{
return 0;
}

@Override
public UnaryBlockOperator< S, T > independentCopy()
{
return this;
}

@Override
public UnaryBlockOperator< S, T > threadSafe()
{
return this;
return numTargetDimensions;
}
}
Loading

0 comments on commit ba36be1

Please sign in to comment.