summaryrefslogtreecommitdiffstats
path: root/vespajlib
diff options
context:
space:
mode:
authorJon Bratseth <bratseth@gmail.com>2023-01-21 17:50:10 +0100
committerJon Bratseth <bratseth@gmail.com>2023-01-21 17:50:10 +0100
commit7a6af9caa065b3ab63b094d78b7347d7df6bea0f (patch)
tree48e80650a9cd88016ff8e618d85d727a28f3542c /vespajlib
parent00d86602a88c66486c8f4c68a1c8bdff096c7273 (diff)
Support a group size constraint in content clusters
Diffstat (limited to 'vespajlib')
-rw-r--r--vespajlib/src/main/java/com/yahoo/collections/IntRange.java120
-rw-r--r--vespajlib/src/test/java/com/yahoo/collections/IntRangeTestCase.java38
2 files changed, 158 insertions, 0 deletions
diff --git a/vespajlib/src/main/java/com/yahoo/collections/IntRange.java b/vespajlib/src/main/java/com/yahoo/collections/IntRange.java
new file mode 100644
index 00000000000..3c3815589ab
--- /dev/null
+++ b/vespajlib/src/main/java/com/yahoo/collections/IntRange.java
@@ -0,0 +1,120 @@
+package com.yahoo.collections;
+
+import java.util.Objects;
+import java.util.OptionalInt;
+
+/**
+ * An integer range.
+ *
+ * @author bratseth
+ */
+public class IntRange {
+
+ private static final IntRange empty = new IntRange(OptionalInt.empty(), OptionalInt.empty());
+
+ private final OptionalInt from, to;
+
+ public IntRange(OptionalInt from, OptionalInt to) {
+ if (from.isPresent() && to.isPresent() && from.getAsInt() > to.getAsInt())
+ throw new IllegalArgumentException("from " + from.getAsInt() + " is greater than to " + to.getAsInt());
+ this.from = from;
+ this.to = to;
+ }
+
+ /** Returns the minimum value which is in this range, or empty if it is open downwards. */
+ public OptionalInt from() { return from; }
+
+ /** Returns the maximum value which is in this range, or empty if it is open upwards. */
+ public OptionalInt to() { return to; }
+
+ public boolean isEmpty() {
+ return from.isEmpty() && to.isEmpty();
+ }
+
+ /** Returns whether the given value is in this range. */
+ public boolean includes(int value) {
+ if (from.isPresent() && value < from.getAsInt()) return false;
+ if (to.isPresent() && value > to.getAsInt()) return false;
+ return true;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if ( ! (o instanceof IntRange other)) return false;
+ if ( ! this.from.equals(other.from)) return false;
+ if ( ! this.to.equals(other.to)) return false;
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(from, to);
+ }
+
+ @Override
+ public String toString() {
+ if (isEmpty()) return "[]";
+ if (from.equals(to)) return String.valueOf(from.getAsInt());
+ return "[" + (from.isPresent() ? from.getAsInt() : "") + ", " + (to.isPresent() ? to.getAsInt() : "") + "]";
+ }
+
+ public static IntRange empty() { return empty; }
+
+ public static IntRange from(int from) {
+ return new IntRange(OptionalInt.of(from), OptionalInt.empty());
+ }
+
+ public static IntRange to(int to) {
+ return new IntRange(OptionalInt.empty(), OptionalInt.of(to));
+ }
+
+ public static IntRange of(int fromTo) {
+ return new IntRange(OptionalInt.of(fromTo), OptionalInt.of(fromTo));
+ }
+
+ public static IntRange of(int from, int to) {
+ return new IntRange(OptionalInt.of(from), OptionalInt.of(to));
+ }
+
+ /** Returns this with a from limit which is at most the given value */
+ public IntRange fromAtMost(int minLimit) {
+ if (from.isEmpty()) return this;
+ if (from.getAsInt() <= minLimit) return this;
+ return new IntRange(OptionalInt.of(minLimit), to);
+ }
+
+ /** Returns this with a to limit which is at least the given value */
+ public IntRange toAtLeast(int maxLimit) {
+ if (to.isEmpty()) return this;
+ if (to.getAsInt() >= maxLimit) return this;
+ return new IntRange(from, OptionalInt.of(maxLimit));
+ }
+
+ /** Parses a value ("value"), value range ("[min-value?, max-value?]"), or empty. */
+ public static IntRange from(String s) {
+ try {
+ s = s.trim();
+ if (s.startsWith("[") && s.endsWith("]")) {
+ String innards = s.substring(1, s.length() - 1).trim();
+ if (innards.isEmpty()) return empty();
+ String[] numbers = (" " + innards + " ").split(","); // pad to make sure we get 2 elements
+ if (numbers.length != 2) throw new IllegalArgumentException("Expected two numbers");
+ return new IntRange(parseOptionalInt(numbers[0]), parseOptionalInt(numbers[1]));
+ } else {
+ var fromTo = parseOptionalInt(s);
+ return new IntRange(fromTo, fromTo);
+ }
+ }
+ catch (IllegalArgumentException e) {
+ throw new IllegalArgumentException("Expected a number or range on the form [min, max], but got '" + s + "'", e);
+ }
+ }
+
+ private static OptionalInt parseOptionalInt(String s) {
+ s = s.trim();
+ if (s.isEmpty()) return OptionalInt.empty();
+ return OptionalInt.of(Integer.parseInt(s));
+ }
+
+}
diff --git a/vespajlib/src/test/java/com/yahoo/collections/IntRangeTestCase.java b/vespajlib/src/test/java/com/yahoo/collections/IntRangeTestCase.java
new file mode 100644
index 00000000000..dc3c39ea19b
--- /dev/null
+++ b/vespajlib/src/test/java/com/yahoo/collections/IntRangeTestCase.java
@@ -0,0 +1,38 @@
+package com.yahoo.collections;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * @author bratseth
+ */
+public class IntRangeTestCase {
+
+ @Test
+ public void testStringAndEquals() {
+ assertEquals(IntRange.empty(), IntRange.from(IntRange.from("[]").toString()));
+ assertEquals(IntRange.from(1), IntRange.from(IntRange.from("[1,]").toString()));
+ assertEquals(IntRange.to(3), IntRange.from(IntRange.from("[,3]").toString()));
+ assertEquals(IntRange.of(1, 3), IntRange.from(IntRange.from("[1,3]").toString()));
+ assertEquals(IntRange.of(1, 3), IntRange.from(IntRange.from("[1, 3]").toString()));
+ }
+
+ @Test
+ public void testInclusion() {
+ assertFalse(IntRange.of(3, 5).includes(2));
+ assertTrue(IntRange.of(3, 5).includes(3));
+ assertTrue(IntRange.of(3, 5).includes(4));
+ assertTrue(IntRange.of(3, 5).includes(5));
+ assertFalse(IntRange.of(3, 5).includes(6));
+
+ assertTrue(IntRange.from(3).includes(1000));
+ assertFalse(IntRange.from(3).includes(2));
+
+ assertTrue(IntRange.to(5).includes(-1000));
+ assertFalse(IntRange.to(3).includes(4));
+ }
+
+}