Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 82 additions & 0 deletions src/main/java/org/janelia/saalfeldlab/n5/DatasetAttributes.java
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,88 @@ public HashMap<String, Object> asMap() {
return map;
}

public static Builder builder(final long[] dimensions, final DataType dataType) {

return new Builder(dimensions, dataType);
}

public static Builder builder(final DatasetAttributes attributes) {

return new Builder(attributes);
}

private static final int[] DEFAULT_1D_BLOCK_SIZE = new int[]{65536};
private static final int[] DEFAULT_2D_BLOCK_SIZE = new int[]{512,512};
private static final int[] DEFAULT_3D_BLOCK_SIZE = new int[]{128,128,128};
private static final int DEFAULT_ND_DIM_LEN = 64;

protected static int[] defaultBlockSize(final long[] dimensions) {

final int[] blockSize;
if (dimensions.length == 1)
blockSize = DEFAULT_1D_BLOCK_SIZE.clone();
else if (dimensions.length == 2)
blockSize = DEFAULT_2D_BLOCK_SIZE.clone();
else if (dimensions.length == 3)
blockSize = DEFAULT_3D_BLOCK_SIZE.clone();
else {
blockSize = new int[dimensions.length];
Arrays.fill(blockSize, DEFAULT_ND_DIM_LEN);
}
for (int i = 0; i < blockSize.length; i++)
blockSize[i] = (int)Math.min(blockSize[i], dimensions[i]);
return blockSize;
}

public static class Builder {

private final long[] dimensions;
private final DataType dataType;

private int[] blockSize;
private DataCodecInfo[] dataCodecInfos = new DataCodecInfo[0];

public Builder(final long[] dimensions, final DataType dataType) {

this.dimensions = dimensions.clone();
this.dataType = dataType;
this.blockSize = defaultBlockSize(dimensions);
}

public Builder(final DatasetAttributes attributes) {

this.dimensions = attributes.getDimensions();
this.dataType = attributes.getDataType();
this.blockSize = attributes.getBlockSize();
this.dataCodecInfos = attributes.getDataCodecInfos();
}

public Builder blockSize(final int[] blockSize) {

this.blockSize = blockSize.clone();
return this;
}

/**
* Sets the compression codec. Has no effect if {@code compression} is
* null or {@link RawCompression}.
*
* @param compression the compression to use
* @return this builder
*/
public Builder compression(final Compression compression) {

if (compression != null && !(compression instanceof RawCompression))
this.dataCodecInfos = new DataCodecInfo[]{compression};
return this;
}

public DatasetAttributes build() {
final int[] resolvedBlockSize = blockSize != null ? blockSize : defaultBlockSize(dimensions);
return new DatasetAttributes(dimensions, resolvedBlockSize, dataType, new N5BlockCodecInfo(), null, dataCodecInfos);
}
}

private static DatasetAttributesAdapter adapter = null;

public static DatasetAttributesAdapter getJsonAdapter() {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package org.janelia.saalfeldlab.n5;

import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;

Expand Down Expand Up @@ -82,6 +84,39 @@ private static DatasetAttributes shardDatasetAttributes(
return new DatasetAttributes(dimensions, shardSize, dataType, blockCodecInfo);
}

@Test
public void builderTests() {

final long[] dims = new long[]{100, 200, 300};
final int[] blk = new int[]{32, 32, 32};

// default blockSize uses defaultBlockSize, not full dimensions
final DatasetAttributes defaultBlk = DatasetAttributes.builder(dims, DataType.FLOAT32).build();
assertArrayEquals(DatasetAttributes.defaultBlockSize(dims), defaultBlk.getBlockSize());

// blockSize is reflected in output
final DatasetAttributes withBlk = DatasetAttributes.builder(dims, DataType.FLOAT32)
.blockSize(blk).build();
assertArrayEquals(blk, withBlk.getBlockSize());
assertFalse(withBlk.isSharded());

// compression sets a data codec; RawCompression is a no-op
final DatasetAttributes withGzip = DatasetAttributes.builder(dims, DataType.FLOAT32)
.blockSize(blk).compression(new GzipCompression()).build();
assertEquals(1, withGzip.getDataCodecInfos().length);

final DatasetAttributes withRaw = DatasetAttributes.builder(dims, DataType.FLOAT32)
.blockSize(blk).compression(new RawCompression()).build();
assertEquals(0, withRaw.getDataCodecInfos().length);

// round-trip through Builder(DatasetAttributes)
final DatasetAttributes roundTrip = DatasetAttributes.builder(withGzip).build();
assertArrayEquals(withGzip.getDimensions(), roundTrip.getDimensions());
assertArrayEquals(withGzip.getBlockSize(), roundTrip.getBlockSize());
assertEquals(withGzip.getDataType(), roundTrip.getDataType());
assertEquals(withGzip.getDataCodecInfos().length, roundTrip.getDataCodecInfos().length);
}

/**
* Test that validateBlockShardSizes method rejects invalid shard and block size combinations.
*/
Expand All @@ -91,7 +126,7 @@ public void testValidateBlockShardSizesInvalid() {
final long[] dimensions = new long[]{100, 200, 300};
final DataType dataType = DataType.UINT8;

// Block size too small
// Block size too smallcompression != null && !(compression instanceof RawCompression)
IllegalArgumentException ex0 = assertThrows(
IllegalArgumentException.class,
() -> shardDatasetAttributes(dimensions, new int[]{1, 1, 1}, new int[]{1, 0, -1}, dataType));
Expand Down
Loading