diff options
author | Martin Polden <mpolden@mpolden.no> | 2019-11-08 12:30:48 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-11-08 12:30:48 +0100 |
commit | 3197465b375861068e78699fb35181b9270a3b22 (patch) | |
tree | 569ca902899c4968defc0185c6323f09aabcfbf3 /vespajlib | |
parent | ca05589362db06d42d156968b279e99ed78053f2 (diff) | |
parent | bb87cf716748abffda3959389d1d82a3e0048976 (diff) |
Merge pull request #11242 from vespa-engine/jvenstad/instance-orchestration
Jvenstad/instance orchestration
Diffstat (limited to 'vespajlib')
-rw-r--r-- | vespajlib/src/main/java/com/yahoo/collections/AbstractFilteringList.java | 80 | ||||
-rw-r--r-- | vespajlib/src/test/java/com/yahoo/collections/AbstractFilteringListTest.java | 69 |
2 files changed, 149 insertions, 0 deletions
diff --git a/vespajlib/src/main/java/com/yahoo/collections/AbstractFilteringList.java b/vespajlib/src/main/java/com/yahoo/collections/AbstractFilteringList.java new file mode 100644 index 00000000000..efcdeeaebfc --- /dev/null +++ b/vespajlib/src/main/java/com/yahoo/collections/AbstractFilteringList.java @@ -0,0 +1,80 @@ +package com.yahoo.collections; + +import java.util.Collection; +import java.util.Comparator; +import java.util.HashSet; +import java.util.List; +import java.util.concurrent.atomic.AtomicLong; +import java.util.function.BiFunction; +import java.util.function.Function; +import java.util.function.Predicate; +import java.util.stream.Stream; + +import static java.util.stream.Collectors.reducing; +import static java.util.stream.Collectors.toUnmodifiableList; + +/** + * Abstract, immutable list for subclassing with concrete types, and domain specific filters. + * + * @author jonmv + */ +public abstract class AbstractFilteringList<Type, ListType extends AbstractFilteringList<Type, ListType>> { + + private final List<Type> items; + private final boolean negate; + private final BiFunction<List<Type>, Boolean, ListType> constructor; + + // Subclass constructor: + // private SomeFilteringList(Collection<? extends SomeType> items, boolean negate) { + // super(items, negate, SomeFilteringList::new); + // } + protected AbstractFilteringList(Collection<? extends Type> items, boolean negate, BiFunction<List<Type>, Boolean, ListType> constructor) { + this.items = List.copyOf(items); + this.negate = negate; + this.constructor = constructor; + } + + /** Negates the next filter operation. All other operations which return a new list reset this modifier. */ + public final ListType not() { + return constructor.apply(items, ! negate); + } + + /** Returns a new list which is the result of filtering with the -- possibly negated -- condition. */ + public final ListType matching(Predicate<Type> condition) { + return constructor.apply(items.stream().filter(negate ? condition.negate() : condition).collect(toUnmodifiableList()), false); + } + + /** Returns the first n items in this list, or everything except those if negated. */ + public ListType first(int n) { + n = Math.min(n, items.size()); + return constructor.apply(items.subList(negate ? n : 0, negate ? items.size() : n), false); + } + + /** Returns the subset of items in this which are (not) present in the other list. */ + public ListType in(ListType others) { + return matching(new HashSet<>(others.asList())::contains); + } + + /** Returns the union of the two lists. */ + public ListType and(ListType others) { + return constructor.apply(Stream.concat(items.stream(), others.asList().stream()).collect(toUnmodifiableList()), false); + } + + /** Returns the items in this as an immutable list. */ + public final List<Type> asList() { return items; } + + /** Returns the items in this as an immutable list after mapping with the given function. */ + public final <OtherType> List<OtherType> mapToList(Function<Type, OtherType> mapper) { + return items.stream().map(mapper).collect(toUnmodifiableList()); + } + + /** Returns the items sorted by the given comparator. */ + public final ListType sortedBy(Comparator<? super Type> comparator) { + return constructor.apply(items.stream().sorted(comparator).collect(toUnmodifiableList()), false); + } + + public final boolean isEmpty() { return items.isEmpty(); } + + public final int size() { return items.size(); } + +} diff --git a/vespajlib/src/test/java/com/yahoo/collections/AbstractFilteringListTest.java b/vespajlib/src/test/java/com/yahoo/collections/AbstractFilteringListTest.java new file mode 100644 index 00000000000..3f9342c5f45 --- /dev/null +++ b/vespajlib/src/test/java/com/yahoo/collections/AbstractFilteringListTest.java @@ -0,0 +1,69 @@ +package com.yahoo.collections; + +import org.junit.Test; + +import java.util.Comparator; +import java.util.List; +import java.util.Locale; + +import static org.junit.Assert.assertEquals; + +/** + * @author jonmv + */ +public class AbstractFilteringListTest { + + @Test + public void testOperations() { + MyList list = MyList.of("ABC", "abc", "cba", "bbb", "ABC"); + + assertEquals(List.of("ABC", "abc", "cba", "bbb", "ABC"), + list.first(100).asList()); + + assertEquals(List.of("ABC", "abc"), + list.first(2).asList()); + + assertEquals(List.of("cba", "bbb", "ABC"), + list.not().first(2).asList()); + + assertEquals(List.of("ABC", "ABC", "abc", "bbb"), + list.sortedBy(Comparator.naturalOrder()).first(4).asList()); + + assertEquals(List.of("abc", "cba", "bbb"), + list.allLowercase().asList()); + + assertEquals(List.of("ABC", "ABC"), + list.not().allLowercase().asList()); + + assertEquals(List.of("abc", "cba", "bbb"), + list.not().not().allLowercase().asList()); + + assertEquals(List.of(3, 3, 3, 3, 3), + list.mapToList(String::length)); + + assertEquals(List.of("ABC", "ABC"), + list.in(MyList.of("ABC", "CBA")).asList()); + + assertEquals(List.of("abc", "cba", "bbb"), + list.not().in(MyList.of("ABC", "CBA")).asList()); + + assertEquals(List.of("ABC", "abc", "cba", "bbb", "ABC", "aaa"), + list.and(MyList.of("aaa")).asList()); + } + + private static class MyList extends AbstractFilteringList<String, MyList> { + + private MyList(List<String> strings, boolean negate) { + super(strings, negate, MyList::new); + } + + private static MyList of(String... strings) { + return new MyList(List.of(strings), false); + } + + private MyList allLowercase() { + return matching(string -> string.toLowerCase(Locale.ROOT).equals(string)); + } + } + +} |