diff --git a/src/main/java/org/modelingvalue/collections/Collection.java b/src/main/java/org/modelingvalue/collections/Collection.java index da1ea6d6..69cf9b29 100644 --- a/src/main/java/org/modelingvalue/collections/Collection.java +++ b/src/main/java/org/modelingvalue/collections/Collection.java @@ -48,6 +48,15 @@ public interface Collection extends Stream, Iterable, Serializable { ThreadLocal SEQUENTIAL_ONLY = ThreadLocal.withInitial(() -> false); + /** + * Returns a {@code Runnable} that executes the given runnable within a context where the + * {@code SEQUENTIAL_ONLY} thread-local is set to {@code true}. Sets {@code SEQUENTIAL_ONLY} + * back to its original value after. + * + * @param runnable runnable to be executed + * @return the result of the supplier where the {@code SEQUENTIAL_ONLY} thread-local is set to + * {@code true}. + */ static Runnable sequential(Runnable runnable) { return () -> { boolean old = SEQUENTIAL_ONLY.get(); @@ -60,6 +69,15 @@ static Runnable sequential(Runnable runnable) { }; } + /** + * Executes the {@code Supplier} and returns the result within a context where the + * {@code SEQUENTIAL_ONLY} thread-local is set to {@code true}. Sets {@code SEQUENTIAL_ONLY} + * back to its original value after. + * + * @param supplier supplier to be called + * @return the result of the supplier where the {@code SEQUENTIAL_ONLY} thread-local is set to + * {@code true}. + */ static T getSequential(Supplier supplier) { boolean old = SEQUENTIAL_ONLY.get(); SEQUENTIAL_ONLY.set(true); @@ -76,21 +94,62 @@ static T getSequential(Supplier supplier) { @Override Iterator iterator(); + /** + * Returns the number of elements in this collection. + * + * @return the number of elements in this collection + */ int size(); + /** + * Returns true if there are no elements in this collection. + * + * @return true if there are no elements in this collection + */ boolean isEmpty(); + /** + * Returns true if one of the elements in this collection is equal to {@code e}. + * + * @param e element to be checked + * @return true if this collection contains {@code e}. + */ boolean contains(Object e); + /** + * Returns this collection with only elements that are instances of the specified type + * + * @param type class of the type to filter + * @return this collection with only the elements that are instances of the specified type + */ Collection filter(Class type); + /** + * Returns this collection with only elements that are non-null. + * + * @return this collection with only the non-null elements + */ Collection notNull(); + /** + * Returns this collection if none of the elements are null. + * + * @return {@code this} + * @throws NullPointerException if any of the elements are null + */ Collection requireNonNull(); @Override Collection filter(Predicate predicate); + /** + * Returns a collection consisting of the elements of this collection that do not match the + * given {@code Predicate}. + * @param predicate a predicate to apply to each element to determine if it should be not + * included + * @return a collection consisting of the elements of this collection that do not match the + * given predicate. + */ default Collection exclude(Predicate predicate) { return filter(predicate.negate()); } @@ -107,16 +166,39 @@ default Collection exclude(Predicate predicate) { @Override Collection sorted(); + /** + * Returns a collection consisting of the elements of this collection in a random order. + * + * @return a collection consisting of the elements of this collection in a random order + */ Collection random(); @Override Collection sorted(Comparator comparator); + /** + * Returns a collection consisting of the elements of this collection sorted in ascending + * order by the result of passing each element through the given {@code Function}. The output + * of the {@code Function} must be a subtype of {@link Comparable}. + * + * @param by the {@code Function} to pass each element through + * @return a collection consisting of the elements of this collection sorted in ascending + * order by the result of passing each element through the given {@code Function} + */ @SuppressWarnings({"rawtypes", "unchecked"}) default Collection sortedBy(Function by) { return sorted((o1, o2) -> by.apply(o1).compareTo(by.apply(o2))); } + /** + * Returns a collection consisting of the elements of this collection sorted in descending + * order by the result of passing each element through the given {@code Function}. The output + * of the {@code Function} must be a subtype of {@link Comparable}. + * + * @param by the {@code Function} to pass each element through + * @return a collection consisting of the elements of this collection sorted in descending + * order by the result of passing each element through the given {@code Function} + */ @SuppressWarnings({"rawtypes", "unchecked"}) default Collection sortedByDesc(Function by) { return sorted((o1, o2) -> by.apply(o2).compareTo(by.apply(o1))); @@ -146,22 +228,56 @@ default Collection sortedByDesc(Function by) { @Override void forEach(Consumer action); + /** + * Constructs and returns a {@link Set} consisting of the elements of this collection. + * + * @return a {@link Set} consisting of the elements of this collection + */ default Set asSet() { return reduce(Set.of(), Set::add, Set::addAll); } + /** + * Constructs and returns a {@link List} consisting of the elements of this collection. + * + * @return a {@link List} consisting of the elements of this collection + */ default List asList() { return reduce(List.of(), List::append, List::appendList); } + /** + * Constructs and returns a {@link Map} where each {@link Entry} in the map is the result of + * passing each element of this collection through the provided function. + * + * @param entry {@code Function} to convert each element of this collection into an entry + * @return a {@link Map} that consists of the elements of this collection passed through the + * provided function + */ default Map asMap(Function> entry) { return reduce(Map.of(), (s, a) -> s.put(entry.apply(a)), Map::putAll); } + /** + * Constructs and returns a {@link DefaultMap} where each {@link Entry} in the map is the result of + * passing each element of this collection through the provided function. + * + * @param defaultFunction a {@code SerializableFunction} to use whenever + * {@link DefaultMap#get(Object)} is called with a key that does not exist in the map + * @param entry {@code Function} to convert each element of this collection into an entry + * @return a {@link DefaultMap} that consists of the elements of this collection passed through the + * provided function + */ default DefaultMap asDefaultMap(SerializableFunction defaultFunction, Function> entry) { return reduce(DefaultMap.of(defaultFunction), (s, a) -> s.put(entry.apply(a)), DefaultMap::putAll); } + /** + * Constructs and returns a {@link QualifiedSet} consisting of the elements of this collection. + * + * @param qualifier a {@code SerializableFunction} as the qualifier + * @return a {@link QualifiedSet} consisting of the elements of this collection + */ @SuppressWarnings("unchecked") default QualifiedSet asQualifiedSet(SerializableFunction qualifier) { return reduce(QualifiedSet.of(qualifier), (s, a) -> s.add((V) a), QualifiedSet::addAll); @@ -172,65 +288,195 @@ default QualifiedDefaultSet asQualifiedDefaultSet(SerializableFunct return reduce(QualifiedDefaultSet.of(qualifier, defaultFunction), (s, a) -> s.add((V) a), QualifiedDefaultSet::addAll); } + /** + * Constructs and returns a collection consisting of the elements of the provided + * {@code BaseStream}. + * + * @param base stream that will be converted to a collection + * @return a collection consisting of the elements of the provided stream + */ @SuppressWarnings("rawtypes") static Collection of(BaseStream base) { return new StreamCollectionImpl<>(base); } + /** + * Constructs and returns a collection consisting of the elements of the provided + * {@code Stream}. + * + * @param base stream that will be converted to a collection + * @return a collection consisting of the elements of the provided stream + */ static Collection of(Stream base) { return base instanceof Collection ? (Collection) base : new StreamCollectionImpl<>(base); } + /** + * Constructs and returns a collection consisting of the elements of the provided + * {@code Spliterator}. + * + * @param base spliterator that will be converted to a collection + * @return a collection consisting of the elements of the provided spliterator + */ static Collection of(Spliterator base) { return new StreamCollectionImpl<>(base); } + /** + * Constructs and returns a collection consisting of the elements of the provided + * {@code Iterable}. + * + * @param base iterable that will be converted to a collection + * @return a collection consisting of the elements of the provided iterable + */ @SuppressWarnings("unchecked") static Collection of(Iterable base) { return base instanceof Collection ? (Collection) base : base instanceof Mutable ? ((Mutable) base).toImmutable() : new StreamCollectionImpl<>(base); } + /** + * Constructs and returns a collection consisting of infinite elements where each element is + * generated by the provided {@code Supplier}. + * + * @param base supplier that will be converted to a collection + * @return a collection consisting of the elements of the provided iterable + */ static Collection of(Supplier base) { return new StreamCollectionImpl<>(Stream.generate(base)); } + /** + * Constructs and returns a collection consisting of the provided elements. + * + * @param elements array of elements that will be contained in the constructed collection + * @return a collection consisting of the provided elements. + */ @SafeVarargs static Collection of(T... elements) { return new StreamCollectionImpl<>(Stream.of(elements)); } + /** + * Constructs and returns a collection consisting of integers in the provided range. + * + * @param from inclusive start to the range + * @param to exclusive end to the range + * @return a collection consisting of integers in the provided range + */ static Collection range(int from, int to) { return of(IntStream.range(from, to)); } + /** + * Constructs and returns a collection consisting of a range of integers from 0 up to but not + * including the provided size. + * + * @param size exclusive end to the range + * @return a collection consisting of integers in the range from 0 up to but not including size + */ static Collection range(int size) { return range(0, size); } + /** + * Builds an object of type {@code U} starting with {@code identity}, and iterating through the + * elements of this collection, replacing the object with the result of calling the + * {@code BiFunction} on the current object and the next element in this collection. + * + * @param identity initial object + * @param accumulator function to pass previous object and current element in this collection + * to get current object + * @return an object of type {@code U} that starts with {@code identity} and is passed through + * a function call with each element in this collection, replacing its object with the result + * each time + */ > U reduce(U identity, BiFunction accumulator); + /** + * Returns a collection with the result of passing each three adjacent elements of this + * collection through the provided {@code Function}. + * + * @param function function that each three adjacent elements in this collection are passed + * through + * @return a collection with the result of passing each three adjacent elements of this + * * collection through the provided function + */ Collection linked(TriFunction function); + /** + * Passes each three adjacent elements of this collection through the provided + * {@code Consumer}. + * + * @param consumer consumer that each three adjacent elements in this collection are passed + * through + */ void linked(TriConsumer consumer); + /** + * Returns a collection with the result of passing each element and its index in this + * collection through the provided {@code Function}. + * @param function function that each element and its index in this collection is passed + * through + * @return a collection with the result of passing each element and its index in this + * collection through the provided {@code Function} + */ Collection indexed(BiFunction function); + /** + * Returns a collection consisting of all the elements in the four provided collections in the + * order they are provided. + * + * @return a collection consisting of all the elements in the four provided collections in the + * order they are provided + */ static Collection concat(Collection a, Collection b, Collection c, Collection d) { return Collection.of(Stream.concat(Stream.concat(Stream.concat(a, b), c), d)); } + /** + * Returns a collection consisting of all the elements in the three provided collections in the + * order they are provided. + * + * @return a collection consisting of all the elements in the three provided collections in the + * order they are provided + */ static Collection concat(Collection a, Collection b, Collection c) { return Collection.of(Stream.concat(Stream.concat(a, b), c)); } + /** + * Returns a collection consisting of all the elements in the two provided collections in the + * order they are provided. + * + * @return a collection consisting of all the elements in the two provided collections in the + * order they are provided + */ static Collection concat(Collection a, Collection b) { return Collection.of(Stream.concat(a, b)); } + /** + * Returns a collection consisting of all the elements in the provided collection with + * {@code b} appended to the end. + * + * @param a initial collection + * @param b value to be appended to end of the provided collection + * @return a collection consisting of the provided collection with {@code b} appended to the + * end + */ static Collection concat(Collection a, E b) { return Collection.of(Stream.concat(a, Collection.of(b))); } + /** + * Returns a collection consisting of {@code a} followed by all the elements in the provided + * collection. + * + * @param a value to be the first in the new collection + * @param b collection containing the rest of the elements in the new collection + * @return a collection consisting of {@code a} followed by all the elements in the provided + * collection + */ static Collection concat(E a, Collection b) { return Collection.of(Stream.concat(Collection.of(a), b)); } diff --git a/src/main/java/org/modelingvalue/collections/ContainingCollection.java b/src/main/java/org/modelingvalue/collections/ContainingCollection.java index 6e331728..38f09f20 100644 --- a/src/main/java/org/modelingvalue/collections/ContainingCollection.java +++ b/src/main/java/org/modelingvalue/collections/ContainingCollection.java @@ -26,45 +26,147 @@ import org.modelingvalue.collections.util.Deserializer; import org.modelingvalue.collections.util.Internable; import org.modelingvalue.collections.util.Serializer; +import org.modelingvalue.collections.util.Triple; @SuppressWarnings("unused") public interface ContainingCollection extends Collection, Internable { > StreamCollection compare(R other); + /** + * Returns the element at the provided index in this collection. + * + * @param index the position whose associated value is to be returned + * @return the element at the provided index in this collection + */ T get(int index); + /** + * Removes the provided value from this collection and returns the updated collection. + * + * @param e value to be removed + * @return a new collection consisting of the elements of this collection without the provided + * value. + */ ContainingCollection remove(Object e); + /** + * Removes all the values in the provided collection from this collection and returns the + * updated collection. + * + * @param e collection of values to be removed + * @return a new collection consisting of the elements of this collection without any of the + * provided values + */ ContainingCollection removeAll(Collection e); + /** + * Adds the provided value to this collection and returns the updated collection. + * + * @param e value to be added + * @return a new collection consisting of the elements of this collection with the provided + * value added + */ ContainingCollection add(T e); + /** + * Adds all the values in the provided collection to this collection and returns the updated + * collection. + * + * @param e collection of values to be added + * @return a new collection consisting of the elements of this collection with all the provided + * values added + */ ContainingCollection addAll(Collection e); + /** + * Adds the provided value to this collection if it does not exist in this collection and + * returns the updated collection. + * + * @param e value to be added + * @return a new collection consisting of the elements of this collection with the provided + * value added if it does not already exist + */ ContainingCollection addUnique(T e); + /** + * Adds each of the provided values to this collection if it does not exist in this collection + * and returns the updated collection. + * + * @param e collection of values to be added + * @return a new collection consisting of the elements of this collection with each of the + * provided values added if it does not already exist + */ ContainingCollection addAllUnique(Collection e); + /** + * All instances of {@code pre} are replaced with {@code post} and the updated collection is + * returned. + * + * @param pre value to be removed + * @param post value to be added + * @return a new collection with all instances of {@code pre} replaced with {@code post} in + * this collection + */ ContainingCollection replace(Object pre, T post); + /** + * The first instance of {@code pre} is replaced with {@code post} and the updated collection + * is returned. + * + * @param pre value to be removed + * @param post value to be added + * @return a new collection with the first instance of {@code pre} replaced with {@code post} + * in this collection + */ ContainingCollection replaceFirst(Object pre, T post); + /** + * Constructs and returns an empty collection. + * + * @return an empty collection + */ ContainingCollection clear(); @Override boolean contains(Object e); + /** + * Return true if the provided value does not exist in this collection. + * @param e value to be checked for + * @return true if the provided value does not exist in this collection + */ default boolean notContains(Object e) { return !contains(e); } + /** + * Reverses the order of the elements in this collection and returns the updated collection. + * + * @return a new collection consisting of the elements of this collection in a reversed order + */ Collection reverse(); + + /** + * Creates a {@link Spliterator} of the elements of this collection in a reversed order. + * + * @return a {@link Spliterator} of the elements of this collection in a reversed order + */ Spliterator reverseSpliterator(); + /** + * Creates a {@link ListIterator} of the elements of this collection. + * + * @return a {@link ListIterator} of the elements of this collection + */ ListIterator listIterator(); + /** + * Creates a {@link ListIterator} + * @param index + * @return + */ ListIterator listIterator(int index); ListIterator listIteratorAtEnd(); diff --git a/src/main/java/org/modelingvalue/collections/DefaultMap.java b/src/main/java/org/modelingvalue/collections/DefaultMap.java index 3103091f..803d128c 100644 --- a/src/main/java/org/modelingvalue/collections/DefaultMap.java +++ b/src/main/java/org/modelingvalue/collections/DefaultMap.java @@ -33,15 +33,47 @@ @SuppressWarnings("unused") public interface DefaultMap extends ContainingCollection>, Mergeable> { + /** + * Constructs an immutable map with the specified key-value pairs and returns it. + * + * @param defaultFunction a {@code SerializableFunction} to use whenever + * * {@link DefaultMap#get(Object)} is called with a key that does not exist in the map + * @param e array of key-value pairs to be added + * @return the constructed immutable map + * @throws NullPointerException if null is passed in as a key-value pair + */ @SafeVarargs static DefaultMap of(SerializableFunction defaultFunction, Entry... e) { return new DefaultMapImpl<>(e, defaultFunction); } + /** + * Returns the value that the provided key maps to in this map. If this key does not exist in + * the map, the key is passed through the {@code defaultFunction} and the result is returned. + * + * @param key key to be checked + * @return the value in the key-value pair with the provided key if it exists, + * otherwise, the result of passing {@code key} through the {@code defaultFunction} + */ V get(K key); + /** + * Returns the key-value pair that contains the provided key as its key. If the provided key + * does not exist in this map, {@code null} is returned. + * + * @param key key to be checked + * @return the key-value pair with the provided key if it exists, otherwise {@code null} is + * returned + */ Entry getEntry(K key); + + /** + * Returns a set of key-value pairs that have equal hashes for their keys. + * + * @param key key whose hash is to be checked + * @return a set of key-value pairs that have equal hashes for their keys + */ Set> allWithEqualhash(K key); Collection getAll(Set keys);