diff options
Diffstat (limited to 'src/main/java/sevenUnits/math/ConditionalExistenceCollections.java')
-rw-r--r-- | src/main/java/sevenUnits/math/ConditionalExistenceCollections.java | 468 |
1 files changed, 0 insertions, 468 deletions
diff --git a/src/main/java/sevenUnits/math/ConditionalExistenceCollections.java b/src/main/java/sevenUnits/math/ConditionalExistenceCollections.java deleted file mode 100644 index 5ce1bd7..0000000 --- a/src/main/java/sevenUnits/math/ConditionalExistenceCollections.java +++ /dev/null @@ -1,468 +0,0 @@ -/** - * Copyright (C) 2019 Adrien Hopkins - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/>. - */ -package sevenUnits.math; - -import java.util.AbstractCollection; -import java.util.AbstractMap; -import java.util.AbstractSet; -import java.util.Collection; -import java.util.Iterator; -import java.util.Map; -import java.util.Map.Entry; -import java.util.NoSuchElementException; -import java.util.Set; -import java.util.function.Predicate; - -/** - * Elements in these wrapper collections only exist if they pass a condition. - * <p> - * All of the collections in this class are "views" of the provided collections. - * They are mutable if the provided collections are mutable, they allow null if - * the provided collections allow null, they will reflect changes in the - * provided collection, etc. - * <p> - * The modification operations will always run the corresponding operations, - * even if the conditional existence collection doesn't change. For example, if - * you have a set that ignores even numbers, add(2) will still add a 2 to the - * backing set (but the conditional existence set will say it doesn't exist). - * <p> - * The returned collections do <i>not</i> pass the hashCode and equals - * operations through to the backing collections, but rely on {@code Object}'s - * {@code equals} and {@code hashCode} methods. This is necessary to preserve - * the contracts of these operations in the case that the backing collections - * are sets or lists. - * <p> - * Other than that, <i>the only difference between the provided collections and - * the returned collections are that elements don't exist if they don't pass the - * provided condition</i>. - * - * - * @author Adrien Hopkins - * @since 2019-10-17 - */ -// TODO add conditional existence Lists and Sorted/Navigable Sets/Maps -public final class ConditionalExistenceCollections { - /** - * Elements in this collection only exist if they meet a condition. - * - * @author Adrien Hopkins - * @since 2019-10-17 - * @param <E> type of element in collection - */ - static final class ConditionalExistenceCollection<E> - extends AbstractCollection<E> { - final Collection<E> collection; - final Predicate<E> existenceCondition; - - /** - * Creates the {@code ConditionalExistenceCollection}. - * - * @param collection - * @param existenceCondition - * @since 2019-10-17 - */ - private ConditionalExistenceCollection(final Collection<E> collection, - final Predicate<E> existenceCondition) { - this.collection = collection; - this.existenceCondition = existenceCondition; - } - - @Override - public boolean add(final E e) { - return this.collection.add(e) && this.existenceCondition.test(e); - } - - @Override - public void clear() { - this.collection.clear(); - } - - @Override - public boolean contains(final Object o) { - if (!this.collection.contains(o)) - return false; - - // this collection can only contain instances of E - // since the object is in the collection, we know that it must be an - // instance of E - // therefore this cast will always work - @SuppressWarnings("unchecked") - final E e = (E) o; - - return this.existenceCondition.test(e); - } - - @Override - public Iterator<E> iterator() { - return conditionalExistenceIterator(this.collection.iterator(), - this.existenceCondition); - } - - @Override - public boolean remove(final Object o) { - // remove() must be first in the && statement, otherwise it may not - // execute - final boolean containedObject = this.contains(o); - return this.collection.remove(o) && containedObject; - } - - @Override - public int size() { - return (int) this.collection.stream().filter(this.existenceCondition) - .count(); - } - - @Override - public Object[] toArray() { - // ensure the toArray operation is supported - this.collection.toArray(); - - // if it works, do it for real - return super.toArray(); - } - - @Override - public <T> T[] toArray(T[] a) { - // ensure the toArray operation is supported - this.collection.toArray(); - - // if it works, do it for real - return super.toArray(a); - } - } - - /** - * Elements in this wrapper iterator only exist if they pass a condition. - * - * @author Adrien Hopkins - * @since 2019-10-17 - * @param <E> type of elements in iterator - */ - static final class ConditionalExistenceIterator<E> implements Iterator<E> { - final Iterator<E> iterator; - final Predicate<E> existenceCondition; - E nextElement; - boolean hasNext; - - /** - * Creates the {@code ConditionalExistenceIterator}. - * - * @param iterator - * @param condition - * @since 2019-10-17 - */ - private ConditionalExistenceIterator(final Iterator<E> iterator, - final Predicate<E> condition) { - this.iterator = iterator; - this.existenceCondition = condition; - this.getAndSetNextElement(); - } - - /** - * Gets the next element, and sets nextElement and hasNext accordingly. - * - * @since 2019-10-17 - */ - private void getAndSetNextElement() { - do { - if (!this.iterator.hasNext()) { - this.nextElement = null; - this.hasNext = false; - return; - } - this.nextElement = this.iterator.next(); - } while (!this.existenceCondition.test(this.nextElement)); - this.hasNext = true; - } - - @Override - public boolean hasNext() { - return this.hasNext; - } - - @Override - public E next() { - if (this.hasNext()) { - final E next = this.nextElement; - this.getAndSetNextElement(); - return next; - } else - throw new NoSuchElementException(); - } - - @Override - public void remove() { - this.iterator.remove(); - } - } - - /** - * Mappings in this map only exist if the entry passes some condition. - * - * @author Adrien Hopkins - * @since 2019-10-17 - * @param <K> key type - * @param <V> value type - */ - static final class ConditionalExistenceMap<K, V> extends AbstractMap<K, V> { - Map<K, V> map; - Predicate<Entry<K, V>> entryExistenceCondition; - - /** - * Creates the {@code ConditionalExistenceMap}. - * - * @param map - * @param entryExistenceCondition - * @since 2019-10-17 - */ - private ConditionalExistenceMap(final Map<K, V> map, - final Predicate<Entry<K, V>> entryExistenceCondition) { - this.map = map; - this.entryExistenceCondition = entryExistenceCondition; - } - - @Override - public boolean containsKey(final Object key) { - if (!this.map.containsKey(key)) - return false; - - // only instances of K have mappings in the backing map - // since we know that key is a valid key, it must be an instance of K - @SuppressWarnings("unchecked") - final K keyAsK = (K) key; - - // get and test entry - final V value = this.map.get(key); - final Entry<K, V> entry = new SimpleEntry<>(keyAsK, value); - return this.entryExistenceCondition.test(entry); - } - - @Override - public Set<Entry<K, V>> entrySet() { - return conditionalExistenceSet(this.map.entrySet(), - this.entryExistenceCondition); - } - - @Override - public V get(final Object key) { - return this.containsKey(key) ? this.map.get(key) : null; - } - - private final Entry<K, V> getEntry(K key) { - return new Entry<>() { - @Override - public K getKey() { - return key; - } - - @Override - public V getValue() { - return ConditionalExistenceMap.this.map.get(key); - } - - @Override - public V setValue(V value) { - return ConditionalExistenceMap.this.map.put(key, value); - } - }; - } - - @Override - public Set<K> keySet() { - return conditionalExistenceSet(super.keySet(), - k -> this.entryExistenceCondition.test(this.getEntry(k))); - } - - @Override - public V put(final K key, final V value) { - final V oldValue = this.map.put(key, value); - - // get and test entry - final Entry<K, V> entry = new SimpleEntry<>(key, oldValue); - return this.entryExistenceCondition.test(entry) ? oldValue : null; - } - - @Override - public V remove(final Object key) { - final V oldValue = this.map.remove(key); - return this.containsKey(key) ? oldValue : null; - } - - @Override - public Collection<V> values() { - // maybe change this to use ConditionalExistenceCollection - return super.values(); - } - } - - /** - * Elements in this set only exist if a certain condition is true. - * - * @author Adrien Hopkins - * @since 2019-10-17 - * @param <E> type of element in set - */ - static final class ConditionalExistenceSet<E> extends AbstractSet<E> { - private final Set<E> set; - private final Predicate<E> existenceCondition; - - /** - * Creates the {@code ConditionalNonexistenceSet}. - * - * @param set set to use - * @param existenceCondition condition where element exists - * @since 2019-10-17 - */ - private ConditionalExistenceSet(final Set<E> set, - final Predicate<E> existenceCondition) { - this.set = set; - this.existenceCondition = existenceCondition; - } - - /** - * {@inheritDoc} - * <p> - * Note that this method returns {@code false} if {@code e} does not pass - * the existence condition. - */ - @Override - public boolean add(final E e) { - return this.set.add(e) && this.existenceCondition.test(e); - } - - @Override - public void clear() { - this.set.clear(); - } - - @Override - public boolean contains(final Object o) { - if (!this.set.contains(o)) - return false; - - // this set can only contain instances of E - // since the object is in the set, we know that it must be an instance - // of E - // therefore this cast will always work - @SuppressWarnings("unchecked") - final E e = (E) o; - - return this.existenceCondition.test(e); - } - - @Override - public Iterator<E> iterator() { - return conditionalExistenceIterator(this.set.iterator(), - this.existenceCondition); - } - - @Override - public boolean remove(final Object o) { - // remove() must be first in the && statement, otherwise it may not - // execute - final boolean containedObject = this.contains(o); - return this.set.remove(o) && containedObject; - } - - @Override - public int size() { - return (int) this.set.stream().filter(this.existenceCondition).count(); - } - - @Override - public Object[] toArray() { - // ensure the toArray operation is supported - this.set.toArray(); - - // if it works, do it for real - return super.toArray(); - } - - @Override - public <T> T[] toArray(T[] a) { - // ensure the toArray operation is supported - this.set.toArray(); - - // if it works, do it for real - return super.toArray(a); - } - } - - /** - * Elements in the returned wrapper collection are ignored if they don't pass - * a condition. - * - * @param <E> type of elements in collection - * @param collection collection to wrap - * @param existenceCondition elements only exist if this returns true - * @return wrapper collection - * @since 2019-10-17 - */ - public static final <E> Collection<E> conditionalExistenceCollection( - final Collection<E> collection, - final Predicate<E> existenceCondition) { - return new ConditionalExistenceCollection<>(collection, - existenceCondition); - } - - /** - * Elements in the returned wrapper iterator are ignored if they don't pass a - * condition. - * - * @param <E> type of elements in iterator - * @param iterator iterator to wrap - * @param existenceCondition elements only exist if this returns true - * @return wrapper iterator - * @since 2019-10-17 - */ - public static final <E> Iterator<E> conditionalExistenceIterator( - final Iterator<E> iterator, final Predicate<E> existenceCondition) { - return new ConditionalExistenceIterator<>(iterator, existenceCondition); - } - - /** - * Mappings in the returned wrapper map are ignored if the corresponding - * entry doesn't pass a condition - * - * @param <K> type of key in map - * @param <V> type of value in map - * @param map map to wrap - * @param entryExistenceCondition mappings only exist if this returns true - * @return wrapper map - * @since 2019-10-17 - */ - public static final <K, V> Map<K, V> conditionalExistenceMap( - final Map<K, V> map, - final Predicate<Entry<K, V>> entryExistenceCondition) { - return new ConditionalExistenceMap<>(map, entryExistenceCondition); - } - - /** - * Elements in the returned wrapper set are ignored if they don't pass a - * condition. - * - * @param <E> type of elements in set - * @param set set to wrap - * @param existenceCondition elements only exist if this returns true - * @return wrapper set - * @since 2019-10-17 - */ - public static final <E> Set<E> conditionalExistenceSet(final Set<E> set, - final Predicate<E> existenceCondition) { - return new ConditionalExistenceSet<>(set, existenceCondition); - } -} |