This is an automated email from the ASF dual-hosted git repository.
ahuber pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/causeway.git
The following commit(s) were added to refs/heads/master by this push:
new 6e9f0c0051 CAUSEWAY-3404: adds negative end-index semantics to
Can#subCan
6e9f0c0051 is described below
commit 6e9f0c00512f35b23fc0873ed038f0c2ecc01162
Author: Andi Huber <[email protected]>
AuthorDate: Wed Feb 7 10:28:52 2024 +0100
CAUSEWAY-3404: adds negative end-index semantics to Can#subCan
---
.../apache/causeway/commons/collections/Can.java | 13 +++-
.../causeway/commons/collections/Can_Empty.java | 5 ++
.../causeway/commons/collections/Can_Multiple.java | 12 ++-
.../commons/collections/Can_Singleton.java | 7 ++
.../causeway/commons/collections/CanTest.java | 85 ++++++++++++++++++++++
5 files changed, 119 insertions(+), 3 deletions(-)
diff --git
a/commons/src/main/java/org/apache/causeway/commons/collections/Can.java
b/commons/src/main/java/org/apache/causeway/commons/collections/Can.java
index da1080ac9e..22c25d83ea 100644
--- a/commons/src/main/java/org/apache/causeway/commons/collections/Can.java
+++ b/commons/src/main/java/org/apache/causeway/commons/collections/Can.java
@@ -577,15 +577,26 @@ extends ImmutableCollection<T>, Comparable<Can<T>>,
Serializable {
// -- SUB SETS AND PARTITIONS
+ /**
+ * Returns a sub-{@link Can} that is made of elements from this {@link
Can},
+ * starting with indices from {@code startInclusive}.
+ * <p>
+ * Out of bounds picking is simply ignored.
+ *
+ * @param startInclusive the (inclusive) initial index
+ */
+ Can<T> subCan(int startInclusive);
+
/**
* Returns a sub-{@link Can} that is made of elements from this {@link
Can},
* when selected by those indices,
- * that result from given range {@code[startInclusive, endExclusive)}.
+ * that result from given range {@code [startInclusive, endExclusive]}.
* <p>
* Out of bounds picking is simply ignored.
*
* @param startInclusive the (inclusive) initial index
* @param endExclusive the exclusive upper bound index
+ * - if negative is interpreted as {@code this.size -
abs(endExclusive)}
*/
Can<T> subCan(int startInclusive, int endExclusive);
diff --git
a/commons/src/main/java/org/apache/causeway/commons/collections/Can_Empty.java
b/commons/src/main/java/org/apache/causeway/commons/collections/Can_Empty.java
index f57ed37fc8..ba2c1144e7 100644
---
a/commons/src/main/java/org/apache/causeway/commons/collections/Can_Empty.java
+++
b/commons/src/main/java/org/apache/causeway/commons/collections/Can_Empty.java
@@ -212,6 +212,11 @@ final class Can_Empty<T> implements Can<T> {
return Can.empty();
}
+ @Override
+ public Can<T> subCan(final int startInclusive) {
+ return Can.empty();
+ }
+
@Override
public Can<T> subCan(final int startInclusive, final int endExclusive) {
return Can.empty();
diff --git
a/commons/src/main/java/org/apache/causeway/commons/collections/Can_Multiple.java
b/commons/src/main/java/org/apache/causeway/commons/collections/Can_Multiple.java
index f0cdfb4c72..320a571631 100644
---
a/commons/src/main/java/org/apache/causeway/commons/collections/Can_Multiple.java
+++
b/commons/src/main/java/org/apache/causeway/commons/collections/Can_Multiple.java
@@ -310,12 +310,20 @@ final class Can_Multiple<T> implements Can<T> {
return _CanFactory.ofNonNullElements(newElements);
}
+ @Override
+ public Can<T> subCan(final int startInclusive) {
+ return pickByIndex(IntStream.range(startInclusive, size()));
+ }
+
@Override
public Can<T> subCan(final int startInclusive, final int endExclusive) {
- if (startInclusive >= endExclusive) {
+ final int upperBoundExclusive = endExclusive < 0
+ ? size() + endExclusive
+ : endExclusive;
+ if (startInclusive >= upperBoundExclusive) {
return Can.empty();
}
- return pickByIndex(IntStream.range(startInclusive, endExclusive));
+ return pickByIndex(IntStream.range(startInclusive,
upperBoundExclusive));
}
@Override
diff --git
a/commons/src/main/java/org/apache/causeway/commons/collections/Can_Singleton.java
b/commons/src/main/java/org/apache/causeway/commons/collections/Can_Singleton.java
index 1d7122ed40..49efe88903 100644
---
a/commons/src/main/java/org/apache/causeway/commons/collections/Can_Singleton.java
+++
b/commons/src/main/java/org/apache/causeway/commons/collections/Can_Singleton.java
@@ -282,6 +282,13 @@ final class Can_Singleton<T> implements Can<T> {
return _CanFactory.ofNonNullElements(newElements);
}
+ @Override
+ public Can<T> subCan(final int startInclusive) {
+ return startInclusive <= 0
+ ? this
+ : Can.empty();
+ }
+
@Override
public Can<T> subCan(final int startInclusive, final int endExclusive) {
if (startInclusive >= endExclusive) {
diff --git
a/commons/src/test/java/org/apache/causeway/commons/collections/CanTest.java
b/commons/src/test/java/org/apache/causeway/commons/collections/CanTest.java
index d8ef8de3a6..932bd8c96a 100644
--- a/commons/src/test/java/org/apache/causeway/commons/collections/CanTest.java
+++ b/commons/src/test/java/org/apache/causeway/commons/collections/CanTest.java
@@ -303,6 +303,91 @@ class CanTest {
subCans.getElseFail(2));
}
+ // -- SUB-CAN 1 ARG
+
+ @Test
+ void subCan_singleArg_emptyCan() {
+ final Can<Integer> origin = Can.empty();
+ assertEquals(origin, origin.subCan(-1));
+ assertEquals(origin, origin.subCan(0));
+ assertEquals(origin, origin.subCan(1));
+ }
+
+ @Test
+ void subCan_singleArg_singleCan() {
+ final Can<Integer> origin = Can.of(9);
+ assertEquals(origin, origin.subCan(-1));
+ assertEquals(origin, origin.subCan(0));
+ assertEquals(Can.empty(), origin.subCan(1));
+ assertEquals(Can.empty(), origin.subCan(2));
+ }
+
+ @Test
+ void subCan_singleArg_multiCan() {
+ final Can<Integer> origin = Can.of(1, 2, 3);
+ assertEquals(origin, origin.subCan(-1));
+ assertEquals(origin, origin.subCan(0));
+ assertEquals(Can.of(2, 3), origin.subCan(1));
+ assertEquals(Can.of(3), origin.subCan(2));
+ assertEquals(Can.empty(), origin.subCan(3));
+ assertEquals(Can.empty(), origin.subCan(4));
+ }
+
+ // -- SUB-CAN 2 ARGS
+
+ @Test
+ void subCan_biArg_emptyCan() {
+ final Can<Integer> origin = Can.empty();
+ // negative end index semantics
+ assertEquals(origin, origin.subCan(-1, -1));
+ assertEquals(origin, origin.subCan(0, -1));
+ assertEquals(origin, origin.subCan(1, -1));
+ // ignore upper index overflow - same expectations as single arg call
+ assertEquals(origin, origin.subCan(-1, 1));
+ assertEquals(origin, origin.subCan(0, 1));
+ assertEquals(origin, origin.subCan(1, 1));
+ }
+
+ @Test
+ void subCan_biArg_singleCan() {
+ final Can<Integer> origin = Can.of(9);
+ assertEquals(Can.empty(), origin.subCan(-1, 0));
+ assertEquals(Can.empty(), origin.subCan(0, 0));
+ assertEquals(Can.empty(), origin.subCan(1, 0));
+ // negative end index semantics
+ assertEquals(Can.empty(), origin.subCan(-1, -1));
+ assertEquals(Can.empty(), origin.subCan(0, -1));
+ assertEquals(Can.empty(), origin.subCan(1, -1));
+ // ignore upper index overflow - same expectations as single arg call
+ assertEquals(origin, origin.subCan(-1, 2));
+ assertEquals(origin, origin.subCan(0, 2));
+ assertEquals(Can.empty(), origin.subCan(1, 2));
+ assertEquals(Can.empty(), origin.subCan(2, 2));
+ }
+
+ @Test
+ void subCan_biArg_multiCan() {
+ final Can<Integer> origin = Can.of(1, 2, 3);
+ assertEquals(Can.of(1, 2), origin.subCan(-1, 2));
+ assertEquals(Can.of(1, 2), origin.subCan(0, 2));
+ assertEquals(Can.of(2), origin.subCan(1, 2));
+ assertEquals(Can.empty(), origin.subCan(2, 2));
+ assertEquals(Can.empty(), origin.subCan(3, 2));
+ // negative end index semantics
+ assertEquals(Can.of(1, 2), origin.subCan(-1, -1));
+ assertEquals(Can.of(1, 2), origin.subCan(0, -1));
+ assertEquals(Can.of(2), origin.subCan(1, -1));
+ assertEquals(Can.empty(), origin.subCan(2, -1));
+ assertEquals(Can.empty(), origin.subCan(3, -1));
+ // ignore upper index overflow - same expectations as single arg call
+ assertEquals(origin, origin.subCan(-1, 4));
+ assertEquals(origin, origin.subCan(0, 4));
+ assertEquals(Can.of(2, 3), origin.subCan(1, 4));
+ assertEquals(Can.of(3), origin.subCan(2, 4));
+ assertEquals(Can.empty(), origin.subCan(3, 4));
+ assertEquals(Can.empty(), origin.subCan(4, 4));
+ }
+
// -- HEPER