From 0245594222bfa0bd9a47d8326ed323c7356ac27c Mon Sep 17 00:00:00 2001 From: Adrien Hopkins Date: Thu, 27 Aug 2020 07:06:35 -0500 Subject: Added Complex Repetition. --- .../math/ConditionalExistenceCollections.java | 295 +++++++++++++-------- 1 file changed, 178 insertions(+), 117 deletions(-) (limited to 'src/org/unitConverter/math/ConditionalExistenceCollections.java') diff --git a/src/org/unitConverter/math/ConditionalExistenceCollections.java b/src/org/unitConverter/math/ConditionalExistenceCollections.java index 9522885..ac1c0cf 100644 --- a/src/org/unitConverter/math/ConditionalExistenceCollections.java +++ b/src/org/unitConverter/math/ConditionalExistenceCollections.java @@ -30,20 +30,25 @@ import java.util.function.Predicate; /** * Elements in these wrapper collections only exist if they pass a condition. *

- * 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 + * 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. *

- * 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 + * 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). *

- * The returned collections do not 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. + * The returned collections do not 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. *

- * Other than that, 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. + * Other than that, 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. * * * @author Adrien Hopkins @@ -56,13 +61,13 @@ public final class ConditionalExistenceCollections { * * @author Adrien Hopkins * @since 2019-10-17 - * @param - * type of element in collection + * @param type of element in collection */ - static final class ConditionalExistenceCollection extends AbstractCollection { + static final class ConditionalExistenceCollection + extends AbstractCollection { final Collection collection; final Predicate existenceCondition; - + /** * Creates the {@code ConditionalExistenceCollection}. * @@ -70,67 +75,89 @@ public final class ConditionalExistenceCollections { * @param existenceCondition * @since 2019-10-17 */ - private ConditionalExistenceCollection(final Collection collection, final Predicate existenceCondition) { + private ConditionalExistenceCollection(final Collection collection, + final Predicate 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 + // 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 iterator() { - return conditionalExistenceIterator(this.collection.iterator(), this.existenceCondition); + 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 + // 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(); + 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[] 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 - * type of elements in iterator + * @param type of elements in iterator */ static final class ConditionalExistenceIterator implements Iterator { final Iterator iterator; final Predicate existenceCondition; E nextElement; boolean hasNext; - + /** * Creates the {@code ConditionalExistenceIterator}. * @@ -138,12 +165,13 @@ public final class ConditionalExistenceCollections { * @param condition * @since 2019-10-17 */ - private ConditionalExistenceIterator(final Iterator iterator, final Predicate condition) { + private ConditionalExistenceIterator(final Iterator iterator, + final Predicate condition) { this.iterator = iterator; this.existenceCondition = condition; this.getAndSetNextElement(); } - + /** * Gets the next element, and sets nextElement and hasNext accordingly. * @@ -160,12 +188,12 @@ public final class ConditionalExistenceCollections { } while (!this.existenceCondition.test(this.nextElement)); this.hasNext = true; } - + @Override public boolean hasNext() { return this.hasNext; } - + @Override public E next() { if (this.hasNext()) { @@ -175,27 +203,25 @@ public final class ConditionalExistenceCollections { } 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 - * key type - * @param - * value type + * @param key type + * @param value type */ static final class ConditionalExistenceMap extends AbstractMap { Map map; Predicate> entryExistenceCondition; - + /** * Creates the {@code ConditionalExistenceMap}. * @@ -203,205 +229,240 @@ public final class ConditionalExistenceCollections { * @param entryExistenceCondition * @since 2019-10-17 */ - private ConditionalExistenceMap(final Map map, final Predicate> entryExistenceCondition) { + private ConditionalExistenceMap(final Map map, + final Predicate> 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 entry = new SimpleEntry<>(keyAsK, value); return this.entryExistenceCondition.test(entry); } - + @Override public Set> entrySet() { - return conditionalExistenceSet(this.map.entrySet(), this.entryExistenceCondition); + 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 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 keySet() { - // maybe change this to use ConditionalExistenceSet - return super.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 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 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 - * type of element in set + * @param type of element in set */ static final class ConditionalExistenceSet extends AbstractSet { private final Set set; private final Predicate existenceCondition; - + /** * Creates the {@code ConditionalNonexistenceSet}. * - * @param set - * set to use - * @param existenceCondition - * condition where element exists + * @param set set to use + * @param existenceCondition condition where element exists * @since 2019-10-17 */ - private ConditionalExistenceSet(final Set set, final Predicate existenceCondition) { + private ConditionalExistenceSet(final Set set, + final Predicate existenceCondition) { this.set = set; this.existenceCondition = existenceCondition; } - + /** * {@inheritDoc} *

- * Note that this method returns {@code false} if {@code e} does not pass the existence condition. + * 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 + // 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 iterator() { - return conditionalExistenceIterator(this.set.iterator(), this.existenceCondition); + 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 + // 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[] 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. + * Elements in the returned wrapper collection are ignored if they don't pass + * a condition. * - * @param - * type of elements in collection - * @param collection - * collection to wrap - * @param existenceCondition - * elements only exist if this returns true + * @param 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 Collection conditionalExistenceCollection(final Collection collection, + public static final Collection conditionalExistenceCollection( + final Collection collection, final Predicate existenceCondition) { - return new ConditionalExistenceCollection<>(collection, existenceCondition); + return new ConditionalExistenceCollection<>(collection, + existenceCondition); } - + /** - * Elements in the returned wrapper iterator are ignored if they don't pass a condition. + * Elements in the returned wrapper iterator are ignored if they don't pass a + * condition. * - * @param - * type of elements in iterator - * @param iterator - * iterator to wrap - * @param existenceCondition - * elements only exist if this returns true + * @param 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 Iterator conditionalExistenceIterator(final Iterator iterator, - final Predicate existenceCondition) { + public static final Iterator conditionalExistenceIterator( + final Iterator iterator, final Predicate existenceCondition) { return new ConditionalExistenceIterator<>(iterator, existenceCondition); } - + /** - * Mappings in the returned wrapper map are ignored if the corresponding entry doesn't pass a condition + * Mappings in the returned wrapper map are ignored if the corresponding + * entry doesn't pass a condition * - * @param - * type of key in map - * @param - * type of value in map - * @param map - * map to wrap - * @param entryExistenceCondition - * mappings only exist if this returns true + * @param type of key in map + * @param 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 Map conditionalExistenceMap(final Map map, + public static final Map conditionalExistenceMap( + final Map map, final Predicate> entryExistenceCondition) { return new ConditionalExistenceMap<>(map, entryExistenceCondition); } - + /** - * Elements in the returned wrapper set are ignored if they don't pass a condition. + * Elements in the returned wrapper set are ignored if they don't pass a + * condition. * - * @param - * type of elements in set - * @param set - * set to wrap - * @param existenceCondition - * elements only exist if this returns true + * @param 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 Set conditionalExistenceSet(final Set set, final Predicate existenceCondition) { + public static final Set conditionalExistenceSet(final Set set, + final Predicate existenceCondition) { return new ConditionalExistenceSet<>(set, existenceCondition); } } -- cgit v1.2.3