Skip to content

Commit a55f5ad

Browse files
committed
Fix slicing bugs
1 parent 5ea0dc4 commit a55f5ad

8 files changed

Lines changed: 73 additions & 39 deletions

File tree

asdf-core/src/main/java/org/asdfformat/asdf/Asdf.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ public class Asdf {
2828
* @param path path to a .asdf file
2929
* @return open ASDF file
3030
*/
31-
AsdfFile open(final Path path) throws IOException {
31+
public static AsdfFile open(final Path path) throws IOException {
3232
final RandomAccessFile file = new RandomAccessFile(path.toFile(), "r");
3333
try {
3434
final LowLevelFormat lowLevelFormat = LowLevelFormats.fromFile(file);

asdf-core/src/main/java/org/asdfformat/asdf/ndarray/Slice.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
public interface Slice {
88
void validate(int originalLength);
99

10-
int computeNewOffset(int originalOffset, int originalStride);
10+
int computeNewOffset(int originalLength, int originalOffset, int originalStride);
1111

1212
int computeNewLength(int originalLength);
1313

asdf-core/src/main/java/org/asdfformat/asdf/ndarray/Slices.java

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,24 +17,34 @@ public static Slice all() {
1717
return AllSlice.instance();
1818
}
1919

20+
/**
21+
* Select a range of a dimension, beginning at startIndexInclusive
22+
* and extending to the end of the array.
23+
* @param startIndexInclusive inclusive start index
24+
* @return slice
25+
*/
26+
public static Slice range(int startIndexInclusive) {
27+
return RangeSlice.of(startIndexInclusive, null);
28+
}
29+
2030
/**
2131
* Select a range of a dimension.
2232
* @param startIndexInclusive inclusive start index
23-
* @param endIndexExclusive exclusive end index
33+
* @param endIndexExclusive exclusive end index (or null for the end of the array)
2434
* @return slice
2535
*/
26-
public static Slice range(int startIndexInclusive, int endIndexExclusive) {
36+
public static Slice range(int startIndexInclusive, Integer endIndexExclusive) {
2737
return RangeSlice.of(startIndexInclusive, endIndexExclusive);
2838
}
2939

3040
/**
3141
* Select a range of a dimension, with spacing between selected values.
3242
* @param startIndexInclusive inclusive start index
33-
* @param endIndexExclusive exclusive end index
43+
* @param endIndexExclusive exclusive end index (or null for the end of the array)
3444
* @param step spacing between values
3545
* @return slice
3646
*/
37-
public static Slice range(int startIndexInclusive, int endIndexExclusive, int step) {
47+
public static Slice range(int startIndexInclusive, Integer endIndexExclusive, int step) {
3848
return RangeSlice.of(startIndexInclusive, endIndexExclusive, step);
3949
}
4050

asdf-core/src/main/java/org/asdfformat/asdf/ndarray/impl/AllSlice.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ public void validate(final int originalLength) {
2020
}
2121

2222
@Override
23-
public int computeNewOffset(final int originalOffset, final int originalStride) {
23+
public int computeNewOffset(final int originalLength, final int originalOffset, final int originalStride) {
2424
return originalOffset;
2525
}
2626

asdf-core/src/main/java/org/asdfformat/asdf/ndarray/impl/AtSlice.java

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,18 +9,16 @@
99
@AllArgsConstructor(access = AccessLevel.PRIVATE)
1010
public class AtSlice implements Slice {
1111
public static AtSlice of(final int index) {
12-
if (index < 0) {
13-
throw new IllegalArgumentException("Cannot slice at index < 0");
14-
}
15-
1612
return new AtSlice(index);
1713
}
1814

1915
private final int index;
2016

2117
@Override
2218
public void validate(final int originalLength) {
23-
if (index >= originalLength) {
19+
final int resolvedIndex = resolveIndex(originalLength);
20+
21+
if (resolvedIndex < 0 || resolvedIndex >= originalLength) {
2422
throw new IllegalArgumentException(
2523
String.format(
2624
"%s out of range for dimension of length %d",
@@ -32,8 +30,9 @@ public void validate(final int originalLength) {
3230
}
3331

3432
@Override
35-
public int computeNewOffset(final int originalOffset, final int originalStride) {
36-
return originalOffset + index * originalStride;
33+
public int computeNewOffset(final int originalLength, final int originalOffset, final int originalStride) {
34+
final int resolvedIndex = resolveIndex(originalLength);
35+
return originalOffset + resolvedIndex * originalStride;
3736
}
3837

3938
@Override
@@ -45,4 +44,12 @@ public int computeNewLength(final int originalLength) {
4544
public int computeNewStride(final int originalStride) {
4645
return originalStride;
4746
}
47+
48+
private int resolveIndex(final int length) {
49+
if (index >= 0) {
50+
return index;
51+
}
52+
53+
return length + index;
54+
}
4855
}

asdf-core/src/main/java/org/asdfformat/asdf/ndarray/impl/NdArrayBase.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,15 @@ public NdArray<T> slice(final Slice... slices) {
8181
sliceList.add(Slices.all());
8282
}
8383

84-
final int newOffset = sliceList.get(sliceList.size() - 1).computeNewOffset(offset, strides[strides.length - 1]);
84+
for (int i = 0; i < shape.length; i++) {
85+
sliceList.get(i).validate(shape[i]);
86+
}
87+
88+
int newOffset = offset;
89+
for (int i = 0; i < shape.length; i++) {
90+
newOffset += sliceList.get(i).computeNewOffset(shape[i], 0, strides[i]);
91+
}
92+
8593
final List<Integer> newShape = new ArrayList<>(shape.length);
8694
final List<Integer> newStrides = new ArrayList<>(shape.length);
8795

asdf-core/src/main/java/org/asdfformat/asdf/ndarray/impl/RangeSlice.java

Lines changed: 32 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -9,40 +9,27 @@
99
@AllArgsConstructor(access = AccessLevel.PRIVATE)
1010
public class RangeSlice implements Slice {
1111
private final int startIndexInclusive;
12-
private final int endIndexExclusive;
12+
private final Integer endIndexExclusive;
1313
private final int step;
1414

15-
public static RangeSlice of(final int startIndexInclusive, final int endIndexExclusive, final int step) {
16-
if (startIndexInclusive < 0) {
17-
throw new IllegalArgumentException("Cannot slice at start index < 0");
18-
}
19-
20-
if (endIndexExclusive < 0) {
21-
throw new IllegalArgumentException("Cannot slice at end index < 0");
22-
}
23-
15+
public static RangeSlice of(final int startIndexInclusive, final Integer endIndexExclusive, final int step) {
2416
if (step < 1) {
2517
throw new IllegalArgumentException("Cannot slice with step < 1");
2618
}
2719

28-
if (startIndexInclusive > endIndexExclusive) {
29-
throw new IllegalArgumentException("Cannot slice with start index > end index");
30-
}
31-
32-
if (endIndexExclusive == startIndexInclusive) {
33-
throw new IllegalArgumentException("Empty slice");
34-
}
35-
3620
return new RangeSlice(startIndexInclusive, endIndexExclusive, step);
3721
}
3822

39-
public static RangeSlice of(final int startIndexInclusive, final int endIndexExclusive) {
23+
public static RangeSlice of(final int startIndexInclusive, final Integer endIndexExclusive) {
4024
return of(startIndexInclusive, endIndexExclusive, 1);
4125
}
4226

4327
@Override
4428
public void validate(final int originalLength) {
45-
if (startIndexInclusive >= originalLength || endIndexExclusive > originalLength) {
29+
final int resolvedStartIndexInclusive = resolveIndex(originalLength, startIndexInclusive);
30+
final int resolvedEndIndexInclusive = resolveIndex(originalLength, endIndexExclusive);
31+
32+
if (resolvedStartIndexInclusive < 0 || resolvedStartIndexInclusive >= originalLength || resolvedEndIndexInclusive < 0 || resolvedEndIndexInclusive > originalLength) {
4633
throw new IllegalArgumentException(
4734
String.format(
4835
"%s out of range for dimension of length %d",
@@ -51,20 +38,42 @@ public void validate(final int originalLength) {
5138
)
5239
);
5340
}
41+
42+
if (resolvedEndIndexInclusive <= resolvedStartIndexInclusive) {
43+
throw new IllegalArgumentException(
44+
String.format(
45+
"%s is empty interval for dimension of length %d",
46+
this,
47+
originalLength
48+
)
49+
);
50+
}
5451
}
5552

5653
@Override
57-
public int computeNewOffset(final int originalOffset, final int originalStride) {
58-
return originalOffset + startIndexInclusive * originalStride;
54+
public int computeNewOffset(final int originalLength, final int originalOffset, final int originalStride) {
55+
return originalOffset + resolveIndex(originalLength, startIndexInclusive) * originalStride;
5956
}
6057

6158
@Override
6259
public int computeNewLength(final int originalLength) {
63-
return (endIndexExclusive - startIndexInclusive) / step;
60+
return (resolveIndex(originalLength, endIndexExclusive) - resolveIndex(originalLength, startIndexInclusive)) / step;
6461
}
6562

6663
@Override
6764
public int computeNewStride(final int originalStride) {
6865
return originalStride * step;
6966
}
67+
68+
private int resolveIndex(final int length, final Integer index) {
69+
if (index == null) {
70+
return length;
71+
}
72+
73+
if (index >= 0) {
74+
return index;
75+
}
76+
77+
return length + index;
78+
}
7079
}

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
<properties>
1212
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
1313
<maven.compiler.release>8</maven.compiler.release>
14-
<revision>1.0.0-SNAPSHOT</revision>
14+
<revision>0.1-alpha-1</revision>
1515
<lombok.version>1.18.36</lombok.version>
1616
<snakeyaml.version>2.4</snakeyaml.version>
1717
<maven-clean-plugin.version>3.4.0</maven-clean-plugin.version>

0 commit comments

Comments
 (0)