hzzz
7 years ago
454 changed files with 136820 additions and 2 deletions
@ -0,0 +1,167 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package com.fr.third.org.apache.commons.collections4; |
||||
|
||||
import java.util.ArrayList; |
||||
import java.util.EmptyStackException; |
||||
|
||||
/** |
||||
* An implementation of the {@link java.util.Stack} API that is based on an |
||||
* <code>ArrayList</code> instead of a <code>Vector</code>, so it is not |
||||
* synchronized to protect against multi-threaded access. The implementation |
||||
* is therefore operates faster in environments where you do not need to |
||||
* worry about multiple thread contention. |
||||
* <p> |
||||
* The removal order of an <code>ArrayStack</code> is based on insertion |
||||
* order: The most recently added element is removed first. The iteration |
||||
* order is <i>not</i> the same as the removal order. The iterator returns |
||||
* elements from the bottom up. |
||||
* <p> |
||||
* Unlike <code>Stack</code>, <code>ArrayStack</code> accepts null entries. |
||||
* <p> |
||||
* <b>Note:</b> From version 4.0 onwards, this class does not implement the |
||||
* removed {@code Buffer} interface anymore. |
||||
* |
||||
* @see java.util.Stack |
||||
* @since 1.0 |
||||
* @version $Id: ArrayStack.java 1477779 2013-04-30 18:55:24Z tn $ |
||||
* @deprecated use {@link java.util.ArrayDeque} instead (available from Java 1.6) |
||||
*/ |
||||
@Deprecated |
||||
public class ArrayStack<E> extends ArrayList<E> { |
||||
|
||||
/** Ensure serialization compatibility */ |
||||
private static final long serialVersionUID = 2130079159931574599L; |
||||
|
||||
/** |
||||
* Constructs a new empty <code>ArrayStack</code>. The initial size |
||||
* is controlled by <code>ArrayList</code> and is currently 10. |
||||
*/ |
||||
public ArrayStack() { |
||||
super(); |
||||
} |
||||
|
||||
/** |
||||
* Constructs a new empty <code>ArrayStack</code> with an initial size. |
||||
* |
||||
* @param initialSize the initial size to use |
||||
* @throws IllegalArgumentException if the specified initial size |
||||
* is negative |
||||
*/ |
||||
public ArrayStack(final int initialSize) { |
||||
super(initialSize); |
||||
} |
||||
|
||||
/** |
||||
* Return <code>true</code> if this stack is currently empty. |
||||
* <p> |
||||
* This method exists for compatibility with <code>java.util.Stack</code>. |
||||
* New users of this class should use <code>isEmpty</code> instead. |
||||
* |
||||
* @return true if the stack is currently empty |
||||
*/ |
||||
public boolean empty() { |
||||
return isEmpty(); |
||||
} |
||||
|
||||
/** |
||||
* Returns the top item off of this stack without removing it. |
||||
* |
||||
* @return the top item on the stack |
||||
* @throws EmptyStackException if the stack is empty |
||||
*/ |
||||
public E peek() throws EmptyStackException { |
||||
final int n = size(); |
||||
if (n <= 0) { |
||||
throw new EmptyStackException(); |
||||
} else { |
||||
return get(n - 1); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Returns the n'th item down (zero-relative) from the top of this |
||||
* stack without removing it. |
||||
* |
||||
* @param n the number of items down to go |
||||
* @return the n'th item on the stack, zero relative |
||||
* @throws EmptyStackException if there are not enough items on the |
||||
* stack to satisfy this request |
||||
*/ |
||||
public E peek(final int n) throws EmptyStackException { |
||||
final int m = (size() - n) - 1; |
||||
if (m < 0) { |
||||
throw new EmptyStackException(); |
||||
} else { |
||||
return get(m); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Pops the top item off of this stack and return it. |
||||
* |
||||
* @return the top item on the stack |
||||
* @throws EmptyStackException if the stack is empty |
||||
*/ |
||||
public E pop() throws EmptyStackException { |
||||
final int n = size(); |
||||
if (n <= 0) { |
||||
throw new EmptyStackException(); |
||||
} else { |
||||
return remove(n - 1); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Pushes a new item onto the top of this stack. The pushed item is also |
||||
* returned. This is equivalent to calling <code>add</code>. |
||||
* |
||||
* @param item the item to be added |
||||
* @return the item just pushed |
||||
*/ |
||||
public E push(final E item) { |
||||
add(item); |
||||
return item; |
||||
} |
||||
|
||||
/** |
||||
* Returns the one-based position of the distance from the top that the |
||||
* specified object exists on this stack, where the top-most element is |
||||
* considered to be at distance <code>1</code>. If the object is not |
||||
* present on the stack, return <code>-1</code> instead. The |
||||
* <code>equals()</code> method is used to compare to the items |
||||
* in this stack. |
||||
* |
||||
* @param object the object to be searched for |
||||
* @return the 1-based depth into the stack of the object, or -1 if not found |
||||
*/ |
||||
public int search(final Object object) { |
||||
int i = size() - 1; // Current index
|
||||
int n = 1; // Current distance
|
||||
while (i >= 0) { |
||||
final Object current = get(i); |
||||
if ((object == null && current == null) || |
||||
(object != null && object.equals(current))) { |
||||
return n; |
||||
} |
||||
i--; |
||||
n++; |
||||
} |
||||
return -1; |
||||
} |
||||
|
||||
} |
@ -0,0 +1,221 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package com.fr.third.org.apache.commons.collections4; |
||||
|
||||
import java.util.Collection; |
||||
import java.util.Iterator; |
||||
import java.util.Set; |
||||
|
||||
/** |
||||
* Defines a collection that counts the number of times an object appears in |
||||
* the collection. |
||||
* <p> |
||||
* Suppose you have a Bag that contains <code>{a, a, b, c}</code>. |
||||
* Calling {@link #getCount(Object)} on <code>a</code> would return 2, while |
||||
* calling {@link #uniqueSet()} would return <code>{a, b, c}</code>. |
||||
* <p> |
||||
* <i>NOTE: This interface violates the {@link Collection} contract.</i> |
||||
* The behavior specified in many of these methods is <i>not</i> the same |
||||
* as the behavior specified by <code>Collection</code>. |
||||
* The noncompliant methods are clearly marked with "(Violation)". |
||||
* Exercise caution when using a bag as a <code>Collection</code>. |
||||
* <p> |
||||
* This violation resulted from the original specification of this interface. |
||||
* In an ideal world, the interface would be changed to fix the problems, however |
||||
* it has been decided to maintain backwards compatibility instead. |
||||
* |
||||
* @param <E> the type held in the bag |
||||
* @since 2.0 |
||||
* @version $Id: Bag.java 1477779 2013-04-30 18:55:24Z tn $ |
||||
*/ |
||||
public interface Bag<E> extends Collection<E> { |
||||
|
||||
/** |
||||
* Returns the number of occurrences (cardinality) of the given |
||||
* object currently in the bag. If the object does not exist in the |
||||
* bag, return 0. |
||||
* |
||||
* @param object the object to search for |
||||
* @return the number of occurrences of the object, zero if not found |
||||
*/ |
||||
int getCount(Object object); |
||||
|
||||
/** |
||||
* <i>(Violation)</i> |
||||
* Adds one copy of the specified object to the Bag. |
||||
* <p> |
||||
* If the object is already in the {@link #uniqueSet()} then increment its |
||||
* count as reported by {@link #getCount(Object)}. Otherwise add it to the |
||||
* {@link #uniqueSet()} and report its count as 1. |
||||
* <p> |
||||
* Since this method always increases the size of the bag, |
||||
* according to the {@link Collection#add(Object)} contract, it |
||||
* should always return <code>true</code>. Since it sometimes returns |
||||
* <code>false</code>, this method violates the contract. |
||||
* |
||||
* @param object the object to add |
||||
* @return <code>true</code> if the object was not already in the <code>uniqueSet</code> |
||||
*/ |
||||
boolean add(E object); |
||||
|
||||
/** |
||||
* Adds <code>nCopies</code> copies of the specified object to the Bag. |
||||
* <p> |
||||
* If the object is already in the {@link #uniqueSet()} then increment its |
||||
* count as reported by {@link #getCount(Object)}. Otherwise add it to the |
||||
* {@link #uniqueSet()} and report its count as <code>nCopies</code>. |
||||
* |
||||
* @param object the object to add |
||||
* @param nCopies the number of copies to add |
||||
* @return <code>true</code> if the object was not already in the <code>uniqueSet</code> |
||||
*/ |
||||
boolean add(E object, int nCopies); |
||||
|
||||
/** |
||||
* <i>(Violation)</i> |
||||
* Removes all occurrences of the given object from the bag. |
||||
* <p> |
||||
* This will also remove the object from the {@link #uniqueSet()}. |
||||
* <p> |
||||
* According to the {@link Collection#remove(Object)} method, |
||||
* this method should only remove the <i>first</i> occurrence of the |
||||
* given object, not <i>all</i> occurrences. |
||||
* |
||||
* @param object the object to remove |
||||
* @return <code>true</code> if this call changed the collection |
||||
*/ |
||||
boolean remove(Object object); |
||||
|
||||
/** |
||||
* Removes <code>nCopies</code> copies of the specified object from the Bag. |
||||
* <p> |
||||
* If the number of copies to remove is greater than the actual number of |
||||
* copies in the Bag, no error is thrown. |
||||
* |
||||
* @param object the object to remove |
||||
* @param nCopies the number of copies to remove |
||||
* @return <code>true</code> if this call changed the collection |
||||
*/ |
||||
boolean remove(Object object, int nCopies); |
||||
|
||||
/** |
||||
* Returns a {@link Set} of unique elements in the Bag. |
||||
* <p> |
||||
* Uniqueness constraints are the same as those in {@link java.util.Set}. |
||||
* |
||||
* @return the Set of unique Bag elements |
||||
*/ |
||||
Set<E> uniqueSet(); |
||||
|
||||
/** |
||||
* Returns the total number of items in the bag across all types. |
||||
* |
||||
* @return the total size of the Bag |
||||
*/ |
||||
int size(); |
||||
|
||||
/** |
||||
* <i>(Violation)</i> |
||||
* Returns <code>true</code> if the bag contains all elements in |
||||
* the given collection, respecting cardinality. That is, if the |
||||
* given collection <code>coll</code> contains <code>n</code> copies |
||||
* of a given object, calling {@link #getCount(Object)} on that object must |
||||
* be <code>>= n</code> for all <code>n</code> in <code>coll</code>. |
||||
* <p> |
||||
* The {@link Collection#containsAll(Collection)} method specifies |
||||
* that cardinality should <i>not</i> be respected; this method should |
||||
* return true if the bag contains at least one of every object contained |
||||
* in the given collection. |
||||
* |
||||
* @param coll the collection to check against |
||||
* @return <code>true</code> if the Bag contains all the collection |
||||
*/ |
||||
boolean containsAll(Collection<?> coll); |
||||
|
||||
/** |
||||
* <i>(Violation)</i> |
||||
* Remove all elements represented in the given collection, |
||||
* respecting cardinality. That is, if the given collection |
||||
* <code>coll</code> contains <code>n</code> copies of a given object, |
||||
* the bag will have <code>n</code> fewer copies, assuming the bag |
||||
* had at least <code>n</code> copies to begin with. |
||||
* |
||||
* <p>The {@link Collection#removeAll(Collection)} method specifies |
||||
* that cardinality should <i>not</i> be respected; this method should |
||||
* remove <i>all</i> occurrences of every object contained in the |
||||
* given collection. |
||||
* |
||||
* @param coll the collection to remove |
||||
* @return <code>true</code> if this call changed the collection |
||||
*/ |
||||
boolean removeAll(Collection<?> coll); |
||||
|
||||
/** |
||||
* <i>(Violation)</i> |
||||
* Remove any members of the bag that are not in the given |
||||
* collection, respecting cardinality. That is, if the given |
||||
* collection <code>coll</code> contains <code>n</code> copies of a |
||||
* given object and the bag has <code>m > n</code> copies, then |
||||
* delete <code>m - n</code> copies from the bag. In addition, if |
||||
* <code>e</code> is an object in the bag but |
||||
* <code>!coll.contains(e)</code>, then remove <code>e</code> and any |
||||
* of its copies. |
||||
* |
||||
* <p>The {@link Collection#retainAll(Collection)} method specifies |
||||
* that cardinality should <i>not</i> be respected; this method should |
||||
* keep <i>all</i> occurrences of every object contained in the |
||||
* given collection. |
||||
* |
||||
* @param coll the collection to retain |
||||
* @return <code>true</code> if this call changed the collection |
||||
*/ |
||||
boolean retainAll(Collection<?> coll); |
||||
|
||||
/** |
||||
* Returns an {@link Iterator} over the entire set of members, |
||||
* including copies due to cardinality. This iterator is fail-fast |
||||
* and will not tolerate concurrent modifications. |
||||
* |
||||
* @return iterator over all elements in the Bag |
||||
*/ |
||||
Iterator<E> iterator(); |
||||
|
||||
// The following is not part of the formal Bag interface, however where possible
|
||||
// Bag implementations should follow these comments.
|
||||
// /**
|
||||
// * Compares this Bag to another.
|
||||
// * This Bag equals another Bag if it contains the same number of occurrences of
|
||||
// * the same elements.
|
||||
// * This equals definition is compatible with the Set interface.
|
||||
// *
|
||||
// * @param obj the Bag to compare to
|
||||
// * @return true if equal
|
||||
// */
|
||||
// boolean equals(Object obj);
|
||||
//
|
||||
// /**
|
||||
// * Gets a hash code for the Bag compatible with the definition of equals.
|
||||
// * The hash code is defined as the sum total of a hash code for each element.
|
||||
// * The per element hash code is defined as
|
||||
// * <code>(e==null ? 0 : e.hashCode()) ^ noOccurances)</code>.
|
||||
// * This hash code definition is compatible with the Set interface.
|
||||
// *
|
||||
// * @return the hash code of the Bag
|
||||
// */
|
||||
// int hashCode();
|
||||
|
||||
} |
@ -0,0 +1,273 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package com.fr.third.org.apache.commons.collections4; |
||||
|
||||
import com.fr.third.org.apache.commons.collections4.bag.CollectionBag; |
||||
import com.fr.third.org.apache.commons.collections4.bag.HashBag; |
||||
import com.fr.third.org.apache.commons.collections4.bag.PredicatedBag; |
||||
import com.fr.third.org.apache.commons.collections4.bag.PredicatedSortedBag; |
||||
import com.fr.third.org.apache.commons.collections4.bag.SynchronizedBag; |
||||
import com.fr.third.org.apache.commons.collections4.bag.SynchronizedSortedBag; |
||||
import com.fr.third.org.apache.commons.collections4.bag.TransformedBag; |
||||
import com.fr.third.org.apache.commons.collections4.bag.TransformedSortedBag; |
||||
import com.fr.third.org.apache.commons.collections4.bag.TreeBag; |
||||
import com.fr.third.org.apache.commons.collections4.bag.UnmodifiableBag; |
||||
import com.fr.third.org.apache.commons.collections4.bag.UnmodifiableSortedBag; |
||||
import com.fr.third.org.apache.commons.collections4.bag.CollectionBag; |
||||
import com.fr.third.org.apache.commons.collections4.bag.HashBag; |
||||
import com.fr.third.org.apache.commons.collections4.bag.PredicatedBag; |
||||
import com.fr.third.org.apache.commons.collections4.bag.PredicatedSortedBag; |
||||
import com.fr.third.org.apache.commons.collections4.bag.SynchronizedBag; |
||||
import com.fr.third.org.apache.commons.collections4.bag.SynchronizedSortedBag; |
||||
import com.fr.third.org.apache.commons.collections4.bag.TransformedBag; |
||||
import com.fr.third.org.apache.commons.collections4.bag.TransformedSortedBag; |
||||
import com.fr.third.org.apache.commons.collections4.bag.TreeBag; |
||||
import com.fr.third.org.apache.commons.collections4.bag.UnmodifiableBag; |
||||
import com.fr.third.org.apache.commons.collections4.bag.UnmodifiableSortedBag; |
||||
|
||||
/** |
||||
* Provides utility methods and decorators for {@link Bag} and {@link SortedBag} instances. |
||||
* |
||||
* @since 2.1 |
||||
* @version $Id: BagUtils.java 1686855 2015-06-22 13:00:27Z tn $ |
||||
*/ |
||||
public class BagUtils { |
||||
|
||||
/** |
||||
* An empty unmodifiable bag. |
||||
*/ |
||||
@SuppressWarnings("rawtypes") // OK, empty bag is compatible with any type
|
||||
public static final Bag EMPTY_BAG = UnmodifiableBag.unmodifiableBag(new HashBag<Object>()); |
||||
|
||||
/** |
||||
* An empty unmodifiable sorted bag. |
||||
*/ |
||||
@SuppressWarnings("rawtypes") // OK, empty bag is compatible with any type
|
||||
public static final Bag EMPTY_SORTED_BAG = |
||||
UnmodifiableSortedBag.unmodifiableSortedBag(new TreeBag<Object>()); |
||||
|
||||
/** |
||||
* Instantiation of BagUtils is not intended or required. |
||||
*/ |
||||
private BagUtils() {} |
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/** |
||||
* Returns a synchronized (thread-safe) bag backed by the given bag. In |
||||
* order to guarantee serial access, it is critical that all access to the |
||||
* backing bag is accomplished through the returned bag. |
||||
* <p> |
||||
* It is imperative that the user manually synchronize on the returned bag |
||||
* when iterating over it: |
||||
* |
||||
* <pre> |
||||
* Bag bag = BagUtils.synchronizedBag(new HashBag()); |
||||
* ... |
||||
* synchronized(bag) { |
||||
* Iterator i = bag.iterator(); // Must be in synchronized block
|
||||
* while (i.hasNext()) |
||||
* foo(i.next()); |
||||
* } |
||||
* } |
||||
* </pre> |
||||
* |
||||
* Failure to follow this advice may result in non-deterministic behavior. |
||||
* |
||||
* @param <E> the element type |
||||
* @param bag the bag to synchronize, must not be null |
||||
* @return a synchronized bag backed by that bag |
||||
* @throws NullPointerException if the Bag is null |
||||
*/ |
||||
public static <E> Bag<E> synchronizedBag(final Bag<E> bag) { |
||||
return SynchronizedBag.synchronizedBag(bag); |
||||
} |
||||
|
||||
/** |
||||
* Returns an unmodifiable view of the given bag. Any modification attempts |
||||
* to the returned bag will raise an {@link UnsupportedOperationException}. |
||||
* |
||||
* @param <E> the element type |
||||
* @param bag the bag whose unmodifiable view is to be returned, must not be null |
||||
* @return an unmodifiable view of that bag |
||||
* @throws NullPointerException if the Bag is null |
||||
*/ |
||||
public static <E> Bag<E> unmodifiableBag(final Bag<? extends E> bag) { |
||||
return UnmodifiableBag.unmodifiableBag(bag); |
||||
} |
||||
|
||||
/** |
||||
* Returns a predicated (validating) bag backed by the given bag. |
||||
* <p> |
||||
* Only objects that pass the test in the given predicate can be added to |
||||
* the bag. Trying to add an invalid object results in an |
||||
* IllegalArgumentException. It is important not to use the original bag |
||||
* after invoking this method, as it is a backdoor for adding invalid |
||||
* objects. |
||||
* |
||||
* @param <E> the element type |
||||
* @param bag the bag to predicate, must not be null |
||||
* @param predicate the predicate for the bag, must not be null |
||||
* @return a predicated bag backed by the given bag |
||||
* @throws NullPointerException if the Bag or Predicate is null |
||||
*/ |
||||
public static <E> Bag<E> predicatedBag(final Bag<E> bag, final Predicate<? super E> predicate) { |
||||
return PredicatedBag.predicatedBag(bag, predicate); |
||||
} |
||||
|
||||
/** |
||||
* Returns a transformed bag backed by the given bag. |
||||
* <p> |
||||
* Each object is passed through the transformer as it is added to the Bag. |
||||
* It is important not to use the original bag after invoking this method, |
||||
* as it is a backdoor for adding untransformed objects. |
||||
* <p> |
||||
* Existing entries in the specified bag will not be transformed. |
||||
* If you want that behaviour, see {@link TransformedBag#transformedBag(Bag, Transformer)}. |
||||
* |
||||
* @param <E> the element type |
||||
* @param bag the bag to predicate, must not be null |
||||
* @param transformer the transformer for the bag, must not be null |
||||
* @return a transformed bag backed by the given bag |
||||
* @throws NullPointerException if the Bag or Transformer is null |
||||
*/ |
||||
public static <E> Bag<E> transformingBag(final Bag<E> bag, final Transformer<? super E, ? extends E> transformer) { |
||||
return TransformedBag.transformingBag(bag, transformer); |
||||
} |
||||
|
||||
/** |
||||
* Returns a bag that complies to the Collection contract, backed by the given bag. |
||||
* |
||||
* @param <E> the element type |
||||
* @param bag the bag to decorate, must not be null |
||||
* @return a Bag that complies to the Collection contract |
||||
* @throws NullPointerException if bag is null |
||||
* @since 4.0 |
||||
*/ |
||||
public static <E> Bag<E> collectionBag(final Bag<E> bag) { |
||||
return CollectionBag.collectionBag(bag); |
||||
} |
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/** |
||||
* Returns a synchronized (thread-safe) sorted bag backed by the given |
||||
* sorted bag. In order to guarantee serial access, it is critical that all |
||||
* access to the backing bag is accomplished through the returned bag. |
||||
* <p> |
||||
* It is imperative that the user manually synchronize on the returned bag |
||||
* when iterating over it: |
||||
* |
||||
* <pre> |
||||
* SortedBag bag = BagUtils.synchronizedSortedBag(new TreeBag()); |
||||
* ... |
||||
* synchronized(bag) { |
||||
* Iterator i = bag.iterator(); // Must be in synchronized block
|
||||
* while (i.hasNext()) |
||||
* foo(i.next()); |
||||
* } |
||||
* } |
||||
* </pre> |
||||
* |
||||
* Failure to follow this advice may result in non-deterministic behavior. |
||||
* |
||||
* @param <E> the element type |
||||
* @param bag the bag to synchronize, must not be null |
||||
* @return a synchronized bag backed by that bag |
||||
* @throws NullPointerException if the SortedBag is null |
||||
*/ |
||||
public static <E> SortedBag<E> synchronizedSortedBag(final SortedBag<E> bag) { |
||||
return SynchronizedSortedBag.synchronizedSortedBag(bag); |
||||
} |
||||
|
||||
/** |
||||
* Returns an unmodifiable view of the given sorted bag. Any modification |
||||
* attempts to the returned bag will raise an |
||||
* {@link UnsupportedOperationException}. |
||||
* |
||||
* @param <E> the element type |
||||
* @param bag the bag whose unmodifiable view is to be returned, must not be null |
||||
* @return an unmodifiable view of that bag |
||||
* @throws NullPointerException if the SortedBag is null |
||||
*/ |
||||
public static <E> SortedBag<E> unmodifiableSortedBag(final SortedBag<E> bag) { |
||||
return UnmodifiableSortedBag.unmodifiableSortedBag(bag); |
||||
} |
||||
|
||||
/** |
||||
* Returns a predicated (validating) sorted bag backed by the given sorted |
||||
* bag. |
||||
* <p> |
||||
* Only objects that pass the test in the given predicate can be added to |
||||
* the bag. Trying to add an invalid object results in an |
||||
* IllegalArgumentException. It is important not to use the original bag |
||||
* after invoking this method, as it is a backdoor for adding invalid |
||||
* objects. |
||||
* |
||||
* @param <E> the element type |
||||
* @param bag the sorted bag to predicate, must not be null |
||||
* @param predicate the predicate for the bag, must not be null |
||||
* @return a predicated bag backed by the given bag |
||||
* @throws NullPointerException if the SortedBag or Predicate is null |
||||
*/ |
||||
public static <E> SortedBag<E> predicatedSortedBag(final SortedBag<E> bag, |
||||
final Predicate<? super E> predicate) { |
||||
return PredicatedSortedBag.predicatedSortedBag(bag, predicate); |
||||
} |
||||
|
||||
/** |
||||
* Returns a transformed sorted bag backed by the given bag. |
||||
* <p> |
||||
* Each object is passed through the transformer as it is added to the Bag. |
||||
* It is important not to use the original bag after invoking this method, |
||||
* as it is a backdoor for adding untransformed objects. |
||||
* <p> |
||||
* Existing entries in the specified bag will not be transformed. |
||||
* If you want that behaviour, see |
||||
* {@link TransformedSortedBag#transformedSortedBag(SortedBag, Transformer)}. |
||||
* |
||||
* @param <E> the element type |
||||
* @param bag the bag to predicate, must not be null |
||||
* @param transformer the transformer for the bag, must not be null |
||||
* @return a transformed bag backed by the given bag |
||||
* @throws NullPointerException if the Bag or Transformer is null |
||||
*/ |
||||
public static <E> SortedBag<E> transformingSortedBag(final SortedBag<E> bag, |
||||
final Transformer<? super E, ? extends E> transformer) { |
||||
return TransformedSortedBag.transformingSortedBag(bag, transformer); |
||||
} |
||||
|
||||
/** |
||||
* Get an empty <code>Bag</code>. |
||||
* |
||||
* @param <E> the element type |
||||
* @return an empty Bag |
||||
*/ |
||||
@SuppressWarnings("unchecked") // OK, empty bag is compatible with any type
|
||||
public static <E> Bag<E> emptyBag() { |
||||
return (Bag<E>) EMPTY_BAG; |
||||
} |
||||
|
||||
/** |
||||
* Get an empty <code>SortedBag</code>. |
||||
* |
||||
* @param <E> the element type |
||||
* @return an empty sorted Bag |
||||
*/ |
||||
@SuppressWarnings("unchecked") // OK, empty bag is compatible with any type
|
||||
public static <E> SortedBag<E> emptySortedBag() { |
||||
return (SortedBag<E>) EMPTY_SORTED_BAG; |
||||
} |
||||
} |
@ -0,0 +1,144 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package com.fr.third.org.apache.commons.collections4; |
||||
|
||||
import java.util.Set; |
||||
|
||||
/** |
||||
* Defines a map that allows bidirectional lookup between key and values. |
||||
* <p> |
||||
* This extended <code>Map</code> represents a mapping where a key may |
||||
* lookup a value and a value may lookup a key with equal ease. |
||||
* This interface extends <code>Map</code> and so may be used anywhere a map |
||||
* is required. The interface provides an inverse map view, enabling |
||||
* full access to both directions of the <code>BidiMap</code>. |
||||
* <p> |
||||
* Implementations should allow a value to be looked up from a key and |
||||
* a key to be looked up from a value with equal performance. |
||||
* <p> |
||||
* This map enforces the restriction that there is a 1:1 relation between |
||||
* keys and values, meaning that multiple keys cannot map to the same value. |
||||
* This is required so that "inverting" the map results in a map without |
||||
* duplicate keys. See the {@link #put} method description for more information. |
||||
* |
||||
* @param <K> the type of the keys in the map |
||||
* @param <V> the type of the values in the map |
||||
* |
||||
* @since 3.0 |
||||
* @version $Id: BidiMap.java 1612021 2014-07-20 04:51:05Z ggregory $ |
||||
*/ |
||||
public interface BidiMap<K, V> extends IterableMap<K, V> { |
||||
|
||||
/** |
||||
* Puts the key-value pair into the map, replacing any previous pair. |
||||
* <p> |
||||
* When adding a key-value pair, the value may already exist in the map |
||||
* against a different key. That mapping is removed, to ensure that the |
||||
* value only occurs once in the inverse map. |
||||
* <pre> |
||||
* BidiMap map1 = new DualHashBidiMap(); |
||||
* map.put("A","B"); // contains A mapped to B, as per Map
|
||||
* map.put("A","C"); // contains A mapped to C, as per Map
|
||||
* |
||||
* BidiMap map2 = new DualHashBidiMap(); |
||||
* map.put("A","B"); // contains A mapped to B, as per Map
|
||||
* map.put("C","B"); // contains C mapped to B, key A is removed
|
||||
* </pre> |
||||
* |
||||
* @param key the key to store |
||||
* @param value the value to store |
||||
* @return the previous value mapped to this key |
||||
* |
||||
* @throws UnsupportedOperationException if the <code>put</code> method is not supported |
||||
* @throws ClassCastException (optional) if the map limits the type of the |
||||
* value and the specified value is inappropriate |
||||
* @throws IllegalArgumentException (optional) if the map limits the values |
||||
* in some way and the value was invalid |
||||
* @throws NullPointerException (optional) if the map limits the values to |
||||
* non-null and null was specified |
||||
*/ |
||||
V put(K key, V value); |
||||
|
||||
/** |
||||
* Gets the key that is currently mapped to the specified value. |
||||
* <p> |
||||
* If the value is not contained in the map, <code>null</code> is returned. |
||||
* <p> |
||||
* Implementations should seek to make this method perform equally as well |
||||
* as <code>get(Object)</code>. |
||||
* |
||||
* @param value the value to find the key for |
||||
* @return the mapped key, or <code>null</code> if not found |
||||
* |
||||
* @throws ClassCastException (optional) if the map limits the type of the |
||||
* value and the specified value is inappropriate |
||||
* @throws NullPointerException (optional) if the map limits the values to |
||||
* non-null and null was specified |
||||
*/ |
||||
K getKey(Object value); |
||||
|
||||
/** |
||||
* Removes the key-value pair that is currently mapped to the specified |
||||
* value (optional operation). |
||||
* <p> |
||||
* If the value is not contained in the map, <code>null</code> is returned. |
||||
* <p> |
||||
* Implementations should seek to make this method perform equally as well |
||||
* as <code>remove(Object)</code>. |
||||
* |
||||
* @param value the value to find the key-value pair for |
||||
* @return the key that was removed, <code>null</code> if nothing removed |
||||
* |
||||
* @throws ClassCastException (optional) if the map limits the type of the |
||||
* value and the specified value is inappropriate |
||||
* @throws NullPointerException (optional) if the map limits the values to |
||||
* non-null and null was specified |
||||
* @throws UnsupportedOperationException if this method is not supported |
||||
* by the implementation |
||||
*/ |
||||
K removeValue(Object value); |
||||
|
||||
/** |
||||
* Gets a view of this map where the keys and values are reversed. |
||||
* <p> |
||||
* Changes to one map will be visible in the other and vice versa. |
||||
* This enables both directions of the map to be accessed as a <code>Map</code>. |
||||
* <p> |
||||
* Implementations should seek to avoid creating a new object every time this |
||||
* method is called. See <code>AbstractMap.values()</code> etc. Calling this |
||||
* method on the inverse map should return the original. |
||||
* |
||||
* @return an inverted bidirectional map |
||||
*/ |
||||
BidiMap<V, K> inverseBidiMap(); |
||||
|
||||
/** |
||||
* Returns a {@link Set} view of the values contained in this map. |
||||
* The set is backed by the map, so changes to the map are reflected |
||||
* in the set, and vice-versa. If the map is modified while an iteration |
||||
* over the set is in progress (except through the iterator's own |
||||
* {@code remove} operation), the results of the iteration are undefined. |
||||
* The set supports element removal, which removes the corresponding |
||||
* mapping from the map, via the {@code Iterator.remove}, |
||||
* {@code Collection.remove}, {@code removeAll}, |
||||
* {@code retainAll} and {@code clear} operations. It does not |
||||
* support the {@code add} or {@code addAll} operations. |
||||
* |
||||
* @return a set view of the values contained in this map |
||||
*/ |
||||
Set<V> values(); |
||||
} |
@ -0,0 +1,50 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package com.fr.third.org.apache.commons.collections4; |
||||
|
||||
import java.util.Collection; |
||||
|
||||
/** |
||||
* Defines a collection that is bounded in size. |
||||
* <p> |
||||
* The size of the collection can vary, but it can never exceed a preset |
||||
* maximum number of elements. This interface allows the querying of details |
||||
* associated with the maximum number of elements. |
||||
* |
||||
* @see CollectionUtils#isFull |
||||
* @see CollectionUtils#maxSize |
||||
* |
||||
* @since 3.0 |
||||
* @version $Id: BoundedCollection.java 1477779 2013-04-30 18:55:24Z tn $ |
||||
*/ |
||||
public interface BoundedCollection<E> extends Collection<E> { |
||||
|
||||
/** |
||||
* Returns true if this collection is full and no new elements can be added. |
||||
* |
||||
* @return <code>true</code> if the collection is full |
||||
*/ |
||||
boolean isFull(); |
||||
|
||||
/** |
||||
* Gets the maximum size of the collection (the bound). |
||||
* |
||||
* @return the maximum number of elements the collection can hold |
||||
*/ |
||||
int maxSize(); |
||||
|
||||
} |
@ -0,0 +1,45 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package com.fr.third.org.apache.commons.collections4; |
||||
|
||||
/** |
||||
* Defines a map that is bounded in size. |
||||
* <p> |
||||
* The size of the map can vary, but it can never exceed a preset |
||||
* maximum number of elements. This interface allows the querying of details |
||||
* associated with the maximum number of elements. |
||||
* |
||||
* @since 3.0 |
||||
* @version $Id: BoundedMap.java 1477779 2013-04-30 18:55:24Z tn $ |
||||
*/ |
||||
public interface BoundedMap<K, V> extends IterableMap<K, V> { |
||||
|
||||
/** |
||||
* Returns true if this map is full and no new elements can be added. |
||||
* |
||||
* @return <code>true</code> if the map is full |
||||
*/ |
||||
boolean isFull(); |
||||
|
||||
/** |
||||
* Gets the maximum size of the map (the bound). |
||||
* |
||||
* @return the maximum number of elements the map can hold |
||||
*/ |
||||
int maxSize(); |
||||
|
||||
} |
@ -0,0 +1,44 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package com.fr.third.org.apache.commons.collections4; |
||||
|
||||
/** |
||||
* Defines a functor interface implemented by classes that do something. |
||||
* <p> |
||||
* A <code>Closure</code> represents a block of code which is executed from |
||||
* inside some block, function or iteration. It operates an input object. |
||||
* <p> |
||||
* Standard implementations of common closures are provided by |
||||
* {@link ClosureUtils}. These include method invocation and for/while loops. |
||||
* |
||||
* @param <T> the type that the closure acts on |
||||
* @since 1.0 |
||||
* @version $Id: Closure.java 1543261 2013-11-19 00:47:34Z ggregory $ |
||||
*/ |
||||
public interface Closure<T> { |
||||
|
||||
/** |
||||
* Performs an action on the specified input object. |
||||
* |
||||
* @param input the input to execute on |
||||
* @throws ClassCastException (runtime) if the input is the wrong class
|
||||
* @throws IllegalArgumentException (runtime) if the input is invalid |
||||
* @throws FunctorException (runtime) if any other error occurs |
||||
*/ |
||||
void execute(T input); |
||||
|
||||
} |
@ -0,0 +1,386 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package com.fr.third.org.apache.commons.collections4; |
||||
|
||||
import java.util.Collection; |
||||
import java.util.Map; |
||||
|
||||
import com.fr.third.org.apache.commons.collections4.functors.ChainedClosure; |
||||
import com.fr.third.org.apache.commons.collections4.functors.EqualPredicate; |
||||
import com.fr.third.org.apache.commons.collections4.functors.ExceptionClosure; |
||||
import com.fr.third.org.apache.commons.collections4.functors.ForClosure; |
||||
import com.fr.third.org.apache.commons.collections4.functors.IfClosure; |
||||
import com.fr.third.org.apache.commons.collections4.functors.InvokerTransformer; |
||||
import com.fr.third.org.apache.commons.collections4.functors.NOPClosure; |
||||
import com.fr.third.org.apache.commons.collections4.functors.SwitchClosure; |
||||
import com.fr.third.org.apache.commons.collections4.functors.TransformerClosure; |
||||
import com.fr.third.org.apache.commons.collections4.functors.WhileClosure; |
||||
import com.fr.third.org.apache.commons.collections4.functors.ChainedClosure; |
||||
import com.fr.third.org.apache.commons.collections4.functors.EqualPredicate; |
||||
import com.fr.third.org.apache.commons.collections4.functors.ExceptionClosure; |
||||
import com.fr.third.org.apache.commons.collections4.functors.ForClosure; |
||||
import com.fr.third.org.apache.commons.collections4.functors.IfClosure; |
||||
import com.fr.third.org.apache.commons.collections4.functors.InvokerTransformer; |
||||
import com.fr.third.org.apache.commons.collections4.functors.NOPClosure; |
||||
import com.fr.third.org.apache.commons.collections4.functors.SwitchClosure; |
||||
import com.fr.third.org.apache.commons.collections4.functors.TransformerClosure; |
||||
import com.fr.third.org.apache.commons.collections4.functors.WhileClosure; |
||||
|
||||
/** |
||||
* <code>ClosureUtils</code> provides reference implementations and utilities |
||||
* for the Closure functor interface. The supplied closures are: |
||||
* <ul> |
||||
* <li>Invoker - invokes a method on the input object |
||||
* <li>For - repeatedly calls a closure for a fixed number of times |
||||
* <li>While - repeatedly calls a closure while a predicate is true |
||||
* <li>Chained - chains two or more closures together |
||||
* <li>If - calls one closure or another based on a predicate |
||||
* <li>Switch - calls one closure based on one or more predicates |
||||
* <li>SwitchMap - calls one closure looked up from a Map |
||||
* <li>Transformer - wraps a Transformer as a Closure |
||||
* <li>NOP - does nothing |
||||
* <li>Exception - always throws an exception |
||||
* </ul> |
||||
* <p> |
||||
* Since v4.1 only closures which are considered to be unsafe are |
||||
* Serializable. Closures considered to be unsafe for serialization are: |
||||
* <ul> |
||||
* <li>Invoker |
||||
* <li>For |
||||
* <li>While |
||||
* </ul> |
||||
* |
||||
* @since 3.0 |
||||
* @version $Id: ClosureUtils.java 1714362 2015-11-14 20:38:02Z tn $ |
||||
*/ |
||||
public class ClosureUtils { |
||||
|
||||
/** |
||||
* This class is not normally instantiated. |
||||
*/ |
||||
private ClosureUtils() {} |
||||
|
||||
/** |
||||
* Gets a Closure that always throws an exception. |
||||
* This could be useful during testing as a placeholder. |
||||
* |
||||
* @see ExceptionClosure |
||||
* |
||||
* @param <E> the type that the closure acts on |
||||
* @return the closure |
||||
*/ |
||||
public static <E> Closure<E> exceptionClosure() { |
||||
return ExceptionClosure.<E>exceptionClosure(); |
||||
} |
||||
|
||||
/** |
||||
* Gets a Closure that will do nothing. |
||||
* This could be useful during testing as a placeholder. |
||||
* |
||||
* @see NOPClosure |
||||
* |
||||
* @param <E> the type that the closure acts on |
||||
* @return the closure |
||||
*/ |
||||
public static <E> Closure<E> nopClosure() { |
||||
return NOPClosure.<E>nopClosure(); |
||||
} |
||||
|
||||
/** |
||||
* Creates a Closure that calls a Transformer each time it is called. |
||||
* The transformer will be called using the closure's input object. |
||||
* The transformer's result will be ignored. |
||||
* |
||||
* @see TransformerClosure |
||||
* |
||||
* @param <E> the type that the closure acts on |
||||
* @param transformer the transformer to run each time in the closure, null means nop |
||||
* @return the closure |
||||
*/ |
||||
public static <E> Closure<E> asClosure(final Transformer<? super E, ?> transformer) { |
||||
return TransformerClosure.transformerClosure(transformer); |
||||
} |
||||
|
||||
/** |
||||
* Creates a Closure that will call the closure <code>count</code> times. |
||||
* <p> |
||||
* A null closure or zero count returns the <code>NOPClosure</code>. |
||||
* |
||||
* @see ForClosure |
||||
* |
||||
* @param <E> the type that the closure acts on |
||||
* @param count the number of times to loop |
||||
* @param closure the closure to call repeatedly |
||||
* @return the <code>for</code> closure |
||||
*/ |
||||
public static <E> Closure<E> forClosure(final int count, final Closure<? super E> closure) { |
||||
return ForClosure.forClosure(count, closure); |
||||
} |
||||
|
||||
/** |
||||
* Creates a Closure that will call the closure repeatedly until the |
||||
* predicate returns false. |
||||
* |
||||
* @see WhileClosure |
||||
* |
||||
* @param <E> the type that the closure acts on |
||||
* @param predicate the predicate to use as an end of loop test, not null |
||||
* @param closure the closure to call repeatedly, not null |
||||
* @return the <code>while</code> closure |
||||
* @throws NullPointerException if either argument is null |
||||
*/ |
||||
public static <E> Closure<E> whileClosure(final Predicate<? super E> predicate, final Closure<? super E> closure) { |
||||
return WhileClosure.<E>whileClosure(predicate, closure, false); |
||||
} |
||||
|
||||
/** |
||||
* Creates a Closure that will call the closure once and then repeatedly |
||||
* until the predicate returns false. |
||||
* |
||||
* @see WhileClosure |
||||
* |
||||
* @param <E> the type that the closure acts on |
||||
* @param closure the closure to call repeatedly, not null |
||||
* @param predicate the predicate to use as an end of loop test, not null |
||||
* @return the <code>do-while</code> closure |
||||
* @throws NullPointerException if either argument is null |
||||
*/ |
||||
public static <E> Closure<E> doWhileClosure(final Closure<? super E> closure, |
||||
final Predicate<? super E> predicate) { |
||||
return WhileClosure.<E>whileClosure(predicate, closure, true); |
||||
} |
||||
|
||||
/** |
||||
* Creates a Closure that will invoke a specific method on the closure's |
||||
* input object by reflection. |
||||
* |
||||
* @see InvokerTransformer |
||||
* @see TransformerClosure |
||||
* |
||||
* @param <E> the type that the closure acts on |
||||
* @param methodName the name of the method |
||||
* @return the <code>invoker</code> closure |
||||
* @throws NullPointerException if the method name is null |
||||
*/ |
||||
public static <E> Closure<E> invokerClosure(final String methodName) { |
||||
// reuse transformer as it has caching - this is lazy really, should have inner class here
|
||||
return asClosure(InvokerTransformer.<E, Object>invokerTransformer(methodName)); |
||||
} |
||||
|
||||
/** |
||||
* Creates a Closure that will invoke a specific method on the closure's |
||||
* input object by reflection. |
||||
* |
||||
* @see InvokerTransformer |
||||
* @see TransformerClosure |
||||
* |
||||
* @param <E> the type that the closure acts on |
||||
* @param methodName the name of the method |
||||
* @param paramTypes the parameter types |
||||
* @param args the arguments |
||||
* @return the <code>invoker</code> closure |
||||
* @throws NullPointerException if the method name is null |
||||
* @throws IllegalArgumentException if the paramTypes and args don't match |
||||
*/ |
||||
public static <E> Closure<E> invokerClosure(final String methodName, final Class<?>[] paramTypes, |
||||
final Object[] args) { |
||||
// reuse transformer as it has caching - this is lazy really, should have inner class here
|
||||
return asClosure(InvokerTransformer.<E, Object>invokerTransformer(methodName, paramTypes, args)); |
||||
} |
||||
|
||||
/** |
||||
* Create a new Closure that calls each closure in turn, passing the |
||||
* result into the next closure. |
||||
* |
||||
* @see ChainedClosure |
||||
* |
||||
* @param <E> the type that the closure acts on |
||||
* @param closures an array of closures to chain |
||||
* @return the <code>chained</code> closure |
||||
* @throws NullPointerException if the closures array is null |
||||
* @throws NullPointerException if any closure in the array is null |
||||
*/ |
||||
public static <E> Closure<E> chainedClosure(final Closure<? super E>... closures) { |
||||
return ChainedClosure.chainedClosure(closures); |
||||
} |
||||
|
||||
/** |
||||
* Create a new Closure that calls each closure in turn, passing the |
||||
* result into the next closure. The ordering is that of the iterator() |
||||
* method on the collection. |
||||
* |
||||
* @see ChainedClosure |
||||
* |
||||
* @param <E> the type that the closure acts on |
||||
* @param closures a collection of closures to chain |
||||
* @return the <code>chained</code> closure |
||||
* @throws NullPointerException if the closures collection is null |
||||
* @throws NullPointerException if any closure in the collection is null |
||||
* @throws IllegalArgumentException if the closures collection is empty |
||||
*/ |
||||
public static <E> Closure<E> chainedClosure(final Collection<? extends Closure<? super E>> closures) { |
||||
return ChainedClosure.chainedClosure(closures); |
||||
} |
||||
|
||||
/** |
||||
* Create a new Closure that calls another closure based on the |
||||
* result of the specified predicate. |
||||
* |
||||
* @see IfClosure |
||||
* |
||||
* @param <E> the type that the closure acts on |
||||
* @param predicate the validating predicate |
||||
* @param trueClosure the closure called if the predicate is true |
||||
* @return the <code>if</code> closure |
||||
* @throws NullPointerException if the predicate or closure is null |
||||
* @since 3.2 |
||||
*/ |
||||
public static <E> Closure<E> ifClosure(final Predicate<? super E> predicate, |
||||
final Closure<? super E> trueClosure) { |
||||
return IfClosure.<E>ifClosure(predicate, trueClosure); |
||||
} |
||||
|
||||
/** |
||||
* Create a new Closure that calls one of two closures depending |
||||
* on the specified predicate. |
||||
* |
||||
* @see IfClosure |
||||
* |
||||
* @param <E> the type that the closure acts on |
||||
* @param predicate the predicate to switch on |
||||
* @param trueClosure the closure called if the predicate is true |
||||
* @param falseClosure the closure called if the predicate is false |
||||
* @return the <code>switch</code> closure |
||||
* @throws NullPointerException if the predicate or either closure is null |
||||
*/ |
||||
public static <E> Closure<E> ifClosure(final Predicate<? super E> predicate, |
||||
final Closure<? super E> trueClosure, |
||||
final Closure<? super E> falseClosure) { |
||||
return IfClosure.<E>ifClosure(predicate, trueClosure, falseClosure); |
||||
} |
||||
|
||||
/** |
||||
* Create a new Closure that calls one of the closures depending |
||||
* on the predicates. |
||||
* <p> |
||||
* The closure at array location 0 is called if the predicate at array |
||||
* location 0 returned true. Each predicate is evaluated |
||||
* until one returns true. |
||||
* |
||||
* @see SwitchClosure |
||||
* |
||||
* @param <E> the type that the closure acts on |
||||
* @param predicates an array of predicates to check, not null |
||||
* @param closures an array of closures to call, not null |
||||
* @return the <code>switch</code> closure |
||||
* @throws NullPointerException if the either array is null |
||||
* @throws NullPointerException if any element in the arrays is null |
||||
* @throws IllegalArgumentException if the arrays have different sizes |
||||
*/ |
||||
public static <E> Closure<E> switchClosure(final Predicate<? super E>[] predicates, |
||||
final Closure<? super E>[] closures) { |
||||
return SwitchClosure.<E>switchClosure(predicates, closures, null); |
||||
} |
||||
|
||||
/** |
||||
* Create a new Closure that calls one of the closures depending |
||||
* on the predicates. |
||||
* <p> |
||||
* The closure at array location 0 is called if the predicate at array |
||||
* location 0 returned true. Each predicate is evaluated |
||||
* until one returns true. If no predicates evaluate to true, the default |
||||
* closure is called. |
||||
* |
||||
* @see SwitchClosure |
||||
* |
||||
* @param <E> the type that the closure acts on |
||||
* @param predicates an array of predicates to check, not null |
||||
* @param closures an array of closures to call, not null |
||||
* @param defaultClosure the default to call if no predicate matches |
||||
* @return the <code>switch</code> closure |
||||
* @throws NullPointerException if the either array is null |
||||
* @throws NullPointerException if any element in the arrays is null |
||||
* @throws IllegalArgumentException if the arrays are different sizes |
||||
*/ |
||||
public static <E> Closure<E> switchClosure(final Predicate<? super E>[] predicates, |
||||
final Closure<? super E>[] closures, |
||||
final Closure<? super E> defaultClosure) { |
||||
return SwitchClosure.<E>switchClosure(predicates, closures, defaultClosure); |
||||
} |
||||
|
||||
/** |
||||
* Create a new Closure that calls one of the closures depending |
||||
* on the predicates. |
||||
* <p> |
||||
* The Map consists of Predicate keys and Closure values. A closure |
||||
* is called if its matching predicate returns true. Each predicate is evaluated |
||||
* until one returns true. If no predicates evaluate to true, the default |
||||
* closure is called. The default closure is set in the map with a |
||||
* null key. The ordering is that of the iterator() method on the entryset |
||||
* collection of the map. |
||||
* |
||||
* @see SwitchClosure |
||||
* |
||||
* @param <E> the type that the closure acts on |
||||
* @param predicatesAndClosures a map of predicates to closures |
||||
* @return the <code>switch</code> closure |
||||
* @throws NullPointerException if the map is null |
||||
* @throws NullPointerException if any closure in the map is null |
||||
* @throws IllegalArgumentException if the map is empty |
||||
* @throws ClassCastException if the map elements are of the wrong type |
||||
*/ |
||||
public static <E> Closure<E> switchClosure(final Map<Predicate<E>, Closure<E>> predicatesAndClosures) { |
||||
return SwitchClosure.switchClosure(predicatesAndClosures); |
||||
} |
||||
|
||||
/** |
||||
* Create a new Closure that uses the input object as a key to find the |
||||
* closure to call. |
||||
* <p> |
||||
* The Map consists of object keys and Closure values. A closure |
||||
* is called if the input object equals the key. If there is no match, the |
||||
* default closure is called. The default closure is set in the map |
||||
* using a null key. |
||||
* |
||||
* @see SwitchClosure |
||||
* |
||||
* @param <E> the type that the closure acts on |
||||
* @param objectsAndClosures a map of objects to closures |
||||
* @return the closure |
||||
* @throws NullPointerException if the map is null |
||||
* @throws NullPointerException if any closure in the map is null |
||||
* @throws IllegalArgumentException if the map is empty |
||||
*/ |
||||
@SuppressWarnings("unchecked") |
||||
public static <E> Closure<E> switchMapClosure(final Map<? extends E, Closure<E>> objectsAndClosures) { |
||||
if (objectsAndClosures == null) { |
||||
throw new NullPointerException("The object and closure map must not be null"); |
||||
} |
||||
final Closure<? super E> def = objectsAndClosures.remove(null); |
||||
final int size = objectsAndClosures.size(); |
||||
final Closure<? super E>[] trs = new Closure[size]; |
||||
final Predicate<E>[] preds = new Predicate[size]; |
||||
int i = 0; |
||||
for (final Map.Entry<? extends E, Closure<E>> entry : objectsAndClosures.entrySet()) { |
||||
preds[i] = EqualPredicate.<E>equalPredicate(entry.getKey()); |
||||
trs[i] = entry.getValue(); |
||||
i++; |
||||
} |
||||
return ClosureUtils.<E>switchClosure(preds, trs, def); |
||||
} |
||||
|
||||
} |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,239 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package com.fr.third.org.apache.commons.collections4; |
||||
|
||||
import java.util.Collection; |
||||
import java.util.Comparator; |
||||
|
||||
import com.fr.third.org.apache.commons.collections4.comparators.BooleanComparator; |
||||
import com.fr.third.org.apache.commons.collections4.comparators.ComparableComparator; |
||||
import com.fr.third.org.apache.commons.collections4.comparators.ComparatorChain; |
||||
import com.fr.third.org.apache.commons.collections4.comparators.NullComparator; |
||||
import com.fr.third.org.apache.commons.collections4.comparators.ReverseComparator; |
||||
import com.fr.third.org.apache.commons.collections4.comparators.TransformingComparator; |
||||
|
||||
/** |
||||
* Provides convenient static utility methods for <Code>Comparator</Code> |
||||
* objects. |
||||
* <p> |
||||
* Most of the functionality in this class can also be found in the |
||||
* <code>comparators</code> package. This class merely provides a |
||||
* convenient central place if you have use for more than one class
|
||||
* in the <code>comparators</code> subpackage. |
||||
* |
||||
* @since 2.1 |
||||
* @version $Id: ComparatorUtils.java 1591832 2014-05-02 08:58:40Z tn $ |
||||
*/ |
||||
public class ComparatorUtils { |
||||
|
||||
/** |
||||
* ComparatorUtils should not normally be instantiated. |
||||
*/ |
||||
private ComparatorUtils() {} |
||||
|
||||
/** |
||||
* Comparator for natural sort order. |
||||
* |
||||
* @see ComparableComparator#comparableComparator() |
||||
*/ |
||||
@SuppressWarnings({ "rawtypes", "unchecked" }) // explicit type needed for Java 1.5 compilation
|
||||
public static final Comparator NATURAL_COMPARATOR = ComparableComparator.<Comparable>comparableComparator(); |
||||
|
||||
/** |
||||
* Gets a comparator that uses the natural order of the objects. |
||||
* |
||||
* @param <E> the object type to compare |
||||
* @return a comparator which uses natural order |
||||
*/ |
||||
@SuppressWarnings("unchecked") |
||||
public static <E extends Comparable<? super E>> Comparator<E> naturalComparator() { |
||||
return NATURAL_COMPARATOR; |
||||
} |
||||
|
||||
/** |
||||
* Gets a comparator that compares using an array of {@link Comparator}s, applied |
||||
* in sequence until one returns not equal or the array is exhausted. |
||||
* |
||||
* @param <E> the object type to compare |
||||
* @param comparators the comparators to use, not null or empty or containing nulls |
||||
* @return a {@link ComparatorChain} formed from the input comparators |
||||
* @throws NullPointerException if comparators array is null or contains a null |
||||
* @see ComparatorChain |
||||
*/ |
||||
public static <E> Comparator<E> chainedComparator(final Comparator<E>... comparators) { |
||||
final ComparatorChain<E> chain = new ComparatorChain<E>(); |
||||
for (final Comparator<E> comparator : comparators) { |
||||
if (comparator == null) { |
||||
throw new NullPointerException("Comparator cannot be null"); |
||||
} |
||||
chain.addComparator(comparator); |
||||
} |
||||
return chain; |
||||
} |
||||
|
||||
/** |
||||
* Gets a comparator that compares using a collection of {@link Comparator}s, |
||||
* applied in (default iterator) sequence until one returns not equal or the |
||||
* collection is exhausted. |
||||
* |
||||
* @param <E> the object type to compare |
||||
* @param comparators the comparators to use, not null or empty or containing nulls |
||||
* @return a {@link ComparatorChain} formed from the input comparators |
||||
* @throws NullPointerException if comparators collection is null or contains a null |
||||
* @throws ClassCastException if the comparators collection contains the wrong object type |
||||
* @see ComparatorChain |
||||
*/ |
||||
@SuppressWarnings("unchecked") |
||||
public static <E> Comparator<E> chainedComparator(final Collection<Comparator<E>> comparators) { |
||||
return chainedComparator( |
||||
(Comparator<E>[]) comparators.toArray(new Comparator[comparators.size()]) |
||||
); |
||||
} |
||||
|
||||
/** |
||||
* Gets a comparator that reverses the order of the given comparator. |
||||
* |
||||
* @param <E> the object type to compare |
||||
* @param comparator the comparator to reverse |
||||
* @return a comparator that reverses the order of the input comparator |
||||
* @see ReverseComparator |
||||
*/ |
||||
public static <E> Comparator<E> reversedComparator(final Comparator<E> comparator) { |
||||
return new ReverseComparator<E>(comparator); |
||||
} |
||||
|
||||
/** |
||||
* Gets a Comparator that can sort Boolean objects. |
||||
* <p> |
||||
* The parameter specifies whether true or false is sorted first. |
||||
* <p> |
||||
* The comparator throws NullPointerException if a null value is compared. |
||||
* |
||||
* @param trueFirst when <code>true</code>, sort |
||||
* <code>true</code> {@link Boolean}s before |
||||
* <code>false</code> {@link Boolean}s. |
||||
* @return a comparator that sorts booleans |
||||
*/ |
||||
public static Comparator<Boolean> booleanComparator(final boolean trueFirst) { |
||||
return BooleanComparator.booleanComparator(trueFirst); |
||||
} |
||||
|
||||
/** |
||||
* Gets a Comparator that controls the comparison of <code>null</code> values. |
||||
* <p> |
||||
* The returned comparator will consider a null value to be less than |
||||
* any nonnull value, and equal to any other null value. Two nonnull |
||||
* values will be evaluated with the given comparator. |
||||
* |
||||
* @param <E> the object type to compare |
||||
* @param comparator the comparator that wants to allow nulls |
||||
* @return a version of that comparator that allows nulls |
||||
* @see NullComparator |
||||
*/ |
||||
@SuppressWarnings("unchecked") |
||||
public static <E> Comparator<E> nullLowComparator(Comparator<E> comparator) { |
||||
if (comparator == null) { |
||||
comparator = NATURAL_COMPARATOR; |
||||
} |
||||
return new NullComparator<E>(comparator, false); |
||||
} |
||||
|
||||
/** |
||||
* Gets a Comparator that controls the comparison of <code>null</code> values. |
||||
* <p> |
||||
* The returned comparator will consider a null value to be greater than |
||||
* any nonnull value, and equal to any other null value. Two nonnull |
||||
* values will be evaluated with the given comparator. |
||||
* |
||||
* @param <E> the object type to compare |
||||
* @param comparator the comparator that wants to allow nulls |
||||
* @return a version of that comparator that allows nulls |
||||
* @see NullComparator |
||||
*/ |
||||
@SuppressWarnings("unchecked") |
||||
public static <E> Comparator<E> nullHighComparator(Comparator<E> comparator) { |
||||
if (comparator == null) { |
||||
comparator = NATURAL_COMPARATOR; |
||||
} |
||||
return new NullComparator<E>(comparator, true); |
||||
} |
||||
|
||||
/** |
||||
* Gets a Comparator that passes transformed objects to the given comparator. |
||||
* <p> |
||||
* Objects passed to the returned comparator will first be transformed |
||||
* by the given transformer before they are compared by the given |
||||
* comparator. |
||||
* |
||||
* @param <I> the input object type of the transformed comparator |
||||
* @param <O> the object type of the decorated comparator |
||||
* @param comparator the sort order to use |
||||
* @param transformer the transformer to use |
||||
* @return a comparator that transforms its input objects before comparing them |
||||
* @see TransformingComparator |
||||
*/ |
||||
@SuppressWarnings("unchecked") |
||||
public static <I, O> Comparator<I> transformedComparator(Comparator<O> comparator, |
||||
final Transformer<? super I, ? extends O> transformer) { |
||||
|
||||
if (comparator == null) { |
||||
comparator = NATURAL_COMPARATOR; |
||||
} |
||||
return new TransformingComparator<I, O>(transformer, comparator); |
||||
} |
||||
|
||||
/** |
||||
* Returns the smaller of the given objects according to the given |
||||
* comparator, returning the second object if the comparator |
||||
* returns equal. |
||||
* |
||||
* @param <E> the object type to compare |
||||
* @param o1 the first object to compare |
||||
* @param o2 the second object to compare |
||||
* @param comparator the sort order to use |
||||
* @return the smaller of the two objects |
||||
*/ |
||||
@SuppressWarnings("unchecked") |
||||
public static <E> E min(final E o1, final E o2, Comparator<E> comparator) { |
||||
if (comparator == null) { |
||||
comparator = NATURAL_COMPARATOR; |
||||
} |
||||
final int c = comparator.compare(o1, o2); |
||||
return c < 0 ? o1 : o2; |
||||
} |
||||
|
||||
/** |
||||
* Returns the larger of the given objects according to the given |
||||
* comparator, returning the second object if the comparator |
||||
* returns equal. |
||||
* |
||||
* @param <E> the object type to compare |
||||
* @param o1 the first object to compare |
||||
* @param o2 the second object to compare |
||||
* @param comparator the sort order to use |
||||
* @return the larger of the two objects |
||||
*/ |
||||
@SuppressWarnings("unchecked") |
||||
public static <E> E max(final E o1, final E o2, Comparator<E> comparator) { |
||||
if (comparator == null) { |
||||
comparator = NATURAL_COMPARATOR; |
||||
} |
||||
final int c = comparator.compare(o1, o2); |
||||
return c > 0 ? o1 : o2; |
||||
} |
||||
|
||||
} |
@ -0,0 +1,97 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package com.fr.third.org.apache.commons.collections4; |
||||
|
||||
import java.util.ArrayList; |
||||
import java.util.Enumeration; |
||||
import java.util.List; |
||||
import java.util.StringTokenizer; |
||||
|
||||
import com.fr.third.org.apache.commons.collections4.iterators.EnumerationIterator; |
||||
|
||||
/** |
||||
* Provides utility methods for {@link Enumeration} instances. |
||||
* |
||||
* @since 3.0 |
||||
* @version $Id: EnumerationUtils.java 1683009 2015-06-01 21:53:01Z tn $ |
||||
*/ |
||||
public class EnumerationUtils { |
||||
|
||||
/** |
||||
* EnumerationUtils is not normally instantiated. |
||||
*/ |
||||
private EnumerationUtils() {} |
||||
|
||||
/** |
||||
* Returns the <code>index</code>-th value in the {@link Enumeration}, throwing |
||||
* <code>IndexOutOfBoundsException</code> if there is no such element. |
||||
* <p> |
||||
* The Enumeration is advanced to <code>index</code> (or to the end, if |
||||
* <code>index</code> exceeds the number of entries) as a side effect of this method. |
||||
* |
||||
* @param e the enumeration to get a value from |
||||
* @param index the index to get |
||||
* @param <T> the type of object in the {@link Enumeration} |
||||
* @return the object at the specified index |
||||
* @throws IndexOutOfBoundsException if the index is invalid |
||||
* @throws IllegalArgumentException if the object type is invalid |
||||
* @since 4.1 |
||||
*/ |
||||
public static <T> T get(final Enumeration<T> e, final int index) { |
||||
int i = index; |
||||
CollectionUtils.checkIndexBounds(i); |
||||
while (e.hasMoreElements()) { |
||||
i--; |
||||
if (i == -1) { |
||||
return e.nextElement(); |
||||
} else { |
||||
e.nextElement(); |
||||
} |
||||
} |
||||
throw new IndexOutOfBoundsException("Entry does not exist: " + i); |
||||
} |
||||
|
||||
/** |
||||
* Creates a list based on an enumeration. |
||||
* |
||||
* <p>As the enumeration is traversed, an ArrayList of its values is |
||||
* created. The new list is returned.</p> |
||||
* |
||||
* @param <E> the element type |
||||
* @param enumeration the enumeration to traverse, which should not be <code>null</code>. |
||||
* @return a list containing all elements of the given enumeration |
||||
* @throws NullPointerException if the enumeration parameter is <code>null</code>. |
||||
*/ |
||||
public static <E> List<E> toList(final Enumeration<? extends E> enumeration) { |
||||
return IteratorUtils.toList(new EnumerationIterator<E>(enumeration)); |
||||
} |
||||
|
||||
/** |
||||
* Override toList(Enumeration) for StringTokenizer as it implements Enumeration<Object> |
||||
* for the sake of backward compatibility. |
||||
* |
||||
* @param stringTokenizer the tokenizer to convert to a {@link List}<{@link String}> |
||||
* @return a list containing all tokens of the given StringTokenizer |
||||
*/ |
||||
public static List<String> toList(final StringTokenizer stringTokenizer) { |
||||
final List<String> result = new ArrayList<String>(stringTokenizer.countTokens()); |
||||
while (stringTokenizer.hasMoreTokens()) { |
||||
result.add(stringTokenizer.nextToken()); |
||||
} |
||||
return result; |
||||
} |
||||
} |
@ -0,0 +1,45 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more contributor license |
||||
* agreements. See the NOTICE file distributed with this work for additional information regarding |
||||
* copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the |
||||
* "License"); you may not use this file except in compliance with the License. You may obtain a |
||||
* copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable
|
||||
* law or agreed to in writing, software distributed under the License is distributed on an "AS IS" |
||||
* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License |
||||
* for the specific language governing permissions and limitations under the License. |
||||
*/ |
||||
package com.fr.third.org.apache.commons.collections4; |
||||
|
||||
import com.fr.third.org.apache.commons.collections4.map.HashedMap; |
||||
|
||||
/** |
||||
* An equation function, which determines equality between objects of type T. |
||||
* <p> |
||||
* It is the functional sibling of {@link java.util.Comparator}; {@link Equator} is to |
||||
* {@link Object} as {@link java.util.Comparator} is to {@link java.lang.Comparable}. |
||||
* |
||||
* @param <T> the types of object this {@link Equator} can evaluate. |
||||
* @since 4.0 |
||||
* @version $Id: Equator.java 1540567 2013-11-10 22:19:29Z tn $ |
||||
*/ |
||||
public interface Equator<T> { |
||||
/** |
||||
* Evaluates the two arguments for their equality. |
||||
* |
||||
* @param o1 the first object to be equated. |
||||
* @param o2 the second object to be equated. |
||||
* @return whether the two objects are equal. |
||||
*/ |
||||
boolean equate(T o1, T o2); |
||||
|
||||
/** |
||||
* Calculates the hash for the object, based on the method of equality used in the equate |
||||
* method. This is used for classes that delegate their {@link Object#equals(Object) equals(Object)} method to an |
||||
* Equator (and so must also delegate their {@link Object#hashCode() hashCode()} method), or for implementations |
||||
* of {@link HashedMap} that use an Equator for the key objects. |
||||
* |
||||
* @param o the object to calculate the hash for. |
||||
* @return the hash of the object. |
||||
*/ |
||||
int hash(T o); |
||||
} |
@ -0,0 +1,44 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package com.fr.third.org.apache.commons.collections4; |
||||
|
||||
/** |
||||
* Defines a functor interface implemented by classes that create objects. |
||||
* <p> |
||||
* A <code>Factory</code> creates an object without using an input parameter. |
||||
* If an input parameter is required, then {@link Transformer} is more appropriate. |
||||
* <p> |
||||
* Standard implementations of common factories are provided by |
||||
* {@link FactoryUtils}. These include factories that return a constant, |
||||
* a copy of a prototype or a new instance. |
||||
* |
||||
* @param <T> the type that the factory creates |
||||
* |
||||
* @since 2.1 |
||||
* @version $Id: Factory.java 1543256 2013-11-19 00:45:38Z ggregory $ |
||||
*/ |
||||
public interface Factory<T> { |
||||
|
||||
/** |
||||
* Create a new object. |
||||
* |
||||
* @return a new object |
||||
* @throws FunctorException (runtime) if the factory cannot create an object |
||||
*/ |
||||
T create(); |
||||
|
||||
} |
@ -0,0 +1,154 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package com.fr.third.org.apache.commons.collections4; |
||||
|
||||
import com.fr.third.org.apache.commons.collections4.functors.ConstantFactory; |
||||
import com.fr.third.org.apache.commons.collections4.functors.ExceptionFactory; |
||||
import com.fr.third.org.apache.commons.collections4.functors.InstantiateFactory; |
||||
import com.fr.third.org.apache.commons.collections4.functors.PrototypeFactory; |
||||
import com.fr.third.org.apache.commons.collections4.functors.ConstantFactory; |
||||
import com.fr.third.org.apache.commons.collections4.functors.ExceptionFactory; |
||||
import com.fr.third.org.apache.commons.collections4.functors.InstantiateFactory; |
||||
import com.fr.third.org.apache.commons.collections4.functors.PrototypeFactory; |
||||
|
||||
/** |
||||
* <code>FactoryUtils</code> provides reference implementations and utilities |
||||
* for the Factory functor interface. The supplied factories are: |
||||
* <ul> |
||||
* <li>Prototype - clones a specified object |
||||
* <li>Instantiate - creates objects using reflection |
||||
* <li>Constant - always returns the same object |
||||
* <li>Null - always returns null |
||||
* <li>Exception - always throws an exception |
||||
* </ul> |
||||
* <p> |
||||
* Since v4.1 only factories which are considered to be unsafe are |
||||
* Serializable. Factories considered to be unsafe for serialization are: |
||||
* <ul> |
||||
* <li>Prototype |
||||
* <li>Instantiate |
||||
* </ul> |
||||
* |
||||
* @since 3.0 |
||||
* @version $Id: FactoryUtils.java 1714362 2015-11-14 20:38:02Z tn $ |
||||
*/ |
||||
public class FactoryUtils { |
||||
|
||||
/** |
||||
* This class is not normally instantiated. |
||||
*/ |
||||
private FactoryUtils() {} |
||||
|
||||
/** |
||||
* Gets a Factory that always throws an exception. |
||||
* This could be useful during testing as a placeholder. |
||||
* |
||||
* @see ExceptionFactory |
||||
* |
||||
* @param <T> the type that the factory creates |
||||
* @return the factory |
||||
*/ |
||||
public static <T> Factory<T> exceptionFactory() { |
||||
return ExceptionFactory.<T>exceptionFactory(); |
||||
} |
||||
|
||||
/** |
||||
* Gets a Factory that will return null each time the factory is used. |
||||
* This could be useful during testing as a placeholder. |
||||
* |
||||
* @see ConstantFactory |
||||
* @param <T> the "type" of null object the factory should return. |
||||
* @return the factory |
||||
*/ |
||||
public static <T> Factory<T> nullFactory() { |
||||
return ConstantFactory.<T>constantFactory(null); |
||||
} |
||||
|
||||
/** |
||||
* Creates a Factory that will return the same object each time the factory |
||||
* is used. No check is made that the object is immutable. In general, only |
||||
* immutable objects should use the constant factory. Mutable objects should |
||||
* use the prototype factory. |
||||
* |
||||
* @see ConstantFactory |
||||
* |
||||
* @param <T> the type that the factory creates |
||||
* @param constantToReturn the constant object to return each time in the factory |
||||
* @return the <code>constant</code> factory. |
||||
*/ |
||||
public static <T> Factory<T> constantFactory(final T constantToReturn) { |
||||
return ConstantFactory.constantFactory(constantToReturn); |
||||
} |
||||
|
||||
/** |
||||
* Creates a Factory that will return a clone of the same prototype object |
||||
* each time the factory is used. The prototype will be cloned using one of these |
||||
* techniques (in order): |
||||
* <ul> |
||||
* <li>public clone method |
||||
* <li>public copy constructor |
||||
* <li>serialization clone |
||||
* <ul> |
||||
* |
||||
* @see PrototypeFactory |
||||
* |
||||
* @param <T> the type that the factory creates |
||||
* @param prototype the object to clone each time in the factory |
||||
* @return the <code>prototype</code> factory, or a {@link ConstantFactory#NULL_INSTANCE} if |
||||
* the {@code prototype} is {@code null} |
||||
* @throws IllegalArgumentException if the prototype cannot be cloned |
||||
*/ |
||||
public static <T> Factory<T> prototypeFactory(final T prototype) { |
||||
return PrototypeFactory.<T>prototypeFactory(prototype); |
||||
} |
||||
|
||||
/** |
||||
* Creates a Factory that can create objects of a specific type using |
||||
* a no-args constructor. |
||||
* |
||||
* @see InstantiateFactory |
||||
* |
||||
* @param <T> the type that the factory creates |
||||
* @param classToInstantiate the Class to instantiate each time in the factory |
||||
* @return the <code>reflection</code> factory |
||||
* @throws NullPointerException if the classToInstantiate is null |
||||
*/ |
||||
public static <T> Factory<T> instantiateFactory(final Class<T> classToInstantiate) { |
||||
return InstantiateFactory.instantiateFactory(classToInstantiate, null, null); |
||||
} |
||||
|
||||
/** |
||||
* Creates a Factory that can create objects of a specific type using |
||||
* the arguments specified to this method. |
||||
* |
||||
* @see InstantiateFactory |
||||
* |
||||
* @param <T> the type that the factory creates |
||||
* @param classToInstantiate the Class to instantiate each time in the factory |
||||
* @param paramTypes parameter types for the constructor, can be null |
||||
* @param args the arguments to pass to the constructor, can be null |
||||
* @return the <code>reflection</code> factory |
||||
* @throws NullPointerException if the classToInstantiate is null |
||||
* @throws IllegalArgumentException if the paramTypes and args don't match |
||||
* @throws IllegalArgumentException if the constructor doesn't exist |
||||
*/ |
||||
public static <T> Factory<T> instantiateFactory(final Class<T> classToInstantiate, final Class<?>[] paramTypes, |
||||
final Object[] args) { |
||||
return InstantiateFactory.instantiateFactory(classToInstantiate, paramTypes, args); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,505 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package com.fr.third.org.apache.commons.collections4; |
||||
|
||||
import java.util.Arrays; |
||||
import java.util.Collection; |
||||
import java.util.Comparator; |
||||
import java.util.Enumeration; |
||||
import java.util.Iterator; |
||||
import java.util.List; |
||||
|
||||
import com.fr.third.org.apache.commons.collections4.iterators.SingletonIterator; |
||||
|
||||
/** |
||||
* A FluentIterable provides a powerful yet simple API for manipulating |
||||
* Iterable instances in a fluent manner. |
||||
* <p> |
||||
* A FluentIterable can be created either from an Iterable or from a set |
||||
* of elements. The following types of methods are provided: |
||||
* <ul> |
||||
* <li>fluent methods which return a new {@code FluentIterable} instance, |
||||
* providing a view of the original iterable (e.g. filter(Predicate)); |
||||
* <li>conversion methods which copy the FluentIterable's contents into a |
||||
* new collection or array (e.g. toList()); |
||||
* <li>utility methods which answer questions about the FluentIterable's |
||||
* contents (e.g. size(), anyMatch(Predicate)). |
||||
* <li> |
||||
* </ul> |
||||
* <p> |
||||
* The following example outputs the first 3 even numbers in the range [1, 10] |
||||
* into a list: |
||||
* <pre> |
||||
* List<String> result = |
||||
* FluentIterable |
||||
* .of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) |
||||
* .filter(new Predicate<Integer>() { |
||||
* public boolean evaluate(Integer number) { |
||||
* return number % 2 == 0; |
||||
* } |
||||
* ) |
||||
* .transform(TransformerUtils.stringValueTransformer()) |
||||
* .limit(3) |
||||
* .toList(); |
||||
* </pre> |
||||
* The resulting list will contain the following elements: |
||||
* <pre>[2, 4, 6]</pre> |
||||
* |
||||
* @param <E> the element type |
||||
* @since 4.1 |
||||
* @version $Id: FluentIterable.java 1684264 2015-06-08 20:06:29Z tn $ |
||||
*/ |
||||
public class FluentIterable<E> implements Iterable<E> { |
||||
|
||||
/** A reference to the wrapped iterable. */ |
||||
private final Iterable<E> iterable; |
||||
|
||||
// Static factory methods
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
/** |
||||
* Creates a new empty FluentIterable. |
||||
* |
||||
* @param <T> the element type |
||||
* @return a new empty FluentIterable |
||||
*/ |
||||
@SuppressWarnings("unchecked") |
||||
public static <T> FluentIterable<T> empty() { |
||||
return IterableUtils.EMPTY_ITERABLE; |
||||
} |
||||
|
||||
/** |
||||
* Creates a new FluentIterable of the single provided element. |
||||
* <p> |
||||
* The returned iterable's iterator does not support {@code remove()}. |
||||
* |
||||
* @param <T> the element type |
||||
* @param singleton the singleton element |
||||
* @return a new FluentIterable containing the singleton |
||||
*/ |
||||
public static <T> FluentIterable<T> of(final T singleton) { |
||||
return of(IteratorUtils.asIterable(new SingletonIterator<T>(singleton, false))); |
||||
} |
||||
|
||||
/** |
||||
* Creates a new FluentIterable from the provided elements. |
||||
* <p> |
||||
* The returned iterable's iterator does not support {@code remove()}. |
||||
* |
||||
* @param <T> the element type |
||||
* @param elements the elements to be contained in the FluentIterable |
||||
* @return a new FluentIterable containing the provided elements |
||||
*/ |
||||
public static <T> FluentIterable<T> of(final T... elements) { |
||||
return of(Arrays.asList(elements)); |
||||
} |
||||
|
||||
/** |
||||
* Construct a new FluentIterable from the provided iterable. If the |
||||
* iterable is already an instance of FluentIterable, the instance |
||||
* will be returned instead. |
||||
* <p> |
||||
* The returned iterable's iterator supports {@code remove()} when the |
||||
* corresponding input iterator supports it. |
||||
* |
||||
* @param <T> the element type |
||||
* @param iterable the iterable to wrap into a FluentIterable, may not be null |
||||
* @return a new FluentIterable wrapping the provided iterable |
||||
* @throws NullPointerException if iterable is null |
||||
*/ |
||||
public static <T> FluentIterable<T> of(final Iterable<T> iterable) { |
||||
IterableUtils.checkNotNull(iterable); |
||||
if (iterable instanceof FluentIterable<?>) { |
||||
return (FluentIterable<T>) iterable; |
||||
} else { |
||||
return new FluentIterable<T>(iterable); |
||||
} |
||||
} |
||||
|
||||
// Constructor
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
/** |
||||
* Package-private constructor, used by IterableUtils. |
||||
*/ |
||||
FluentIterable() { |
||||
this.iterable = this; |
||||
} |
||||
|
||||
/** |
||||
* Create a new FluentIterable by wrapping the provided iterable. |
||||
* @param iterable the iterable to wrap |
||||
*/ |
||||
private FluentIterable(final Iterable<E> iterable) { |
||||
this.iterable = iterable; |
||||
} |
||||
|
||||
// fluent construction methods
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
/** |
||||
* Returns a new FluentIterable whose iterator will first traverse |
||||
* the elements of the current iterable, followed by the provided |
||||
* elements. |
||||
* |
||||
* @param elements the elements to append to the iterable |
||||
* @return a new iterable, combining this iterable with the elements |
||||
*/ |
||||
public FluentIterable<E> append(final E... elements) { |
||||
return append(Arrays.asList(elements)); |
||||
} |
||||
|
||||
/** |
||||
* Returns a new FluentIterable whose iterator will first traverse |
||||
* the elements of the current iterable, followed by the elements |
||||
* of the provided iterable. |
||||
* |
||||
* @param other the other iterable to combine, may not be null |
||||
* @return a new iterable, combining this iterable with other |
||||
* @throws NullPointerException if other is null |
||||
*/ |
||||
public FluentIterable<E> append(final Iterable<? extends E> other) { |
||||
return of(IterableUtils.chainedIterable(iterable, other)); |
||||
} |
||||
|
||||
/** |
||||
* Returns a new FluentIterable whose iterator will traverse the |
||||
* elements of the current and provided iterable in natural order. |
||||
* <p> |
||||
* Example: natural ordering |
||||
* <ul> |
||||
* <li>this contains elements [1, 3, 5, 7] |
||||
* <li>other contains elements [2, 4, 6, 8] |
||||
* </ul> |
||||
* <p> |
||||
* The returned iterable will traverse the elements in the following |
||||
* order: [1, 2, 3, 4, 5, 6, 7, 8] |
||||
* |
||||
* @param other the other iterable to collate, may not be null |
||||
* @return a new iterable, collating this iterable with the other in natural order |
||||
* @throws NullPointerException if other is null |
||||
* @see {@link org.apache.commons.collections4.iterators.CollatingIterator CollatingIterator} |
||||
*/ |
||||
public FluentIterable<E> collate(final Iterable<? extends E> other) { |
||||
return of(IterableUtils.collatedIterable(iterable, other)); |
||||
} |
||||
|
||||
/** |
||||
* Returns a new FluentIterable whose iterator will traverse the |
||||
* elements of the current and provided iterable according to the |
||||
* ordering defined by an comparator. |
||||
* <p> |
||||
* Example: descending order |
||||
* <ul> |
||||
* <li>this contains elements [7, 5, 3, 1] |
||||
* <li>other contains elements [8, 6, 4, 2] |
||||
* </ul> |
||||
* <p> |
||||
* The returned iterable will traverse the elements in the following |
||||
* order: [8, 7, 6, 5, 4, 3, 2, 1] |
||||
* |
||||
* @param comparator the comparator to define an ordering, may be null, |
||||
* in which case natural ordering will be used |
||||
* @param other the other iterable to collate, may not be null |
||||
* @return a new iterable, collating this iterable with the other in natural order |
||||
* @throws NullPointerException if other is null |
||||
* @see {@link org.apache.commons.collections4.iterators.CollatingIterator CollatingIterator} |
||||
*/ |
||||
public FluentIterable<E> collate(final Iterable<? extends E> other, |
||||
final Comparator<? super E> comparator) { |
||||
return of(IterableUtils.collatedIterable(comparator, iterable, other)); |
||||
} |
||||
|
||||
/** |
||||
* This method fully traverses an iterator of this iterable and returns |
||||
* a new iterable with the same contents, but without any reference |
||||
* to the originating iterables and/or iterators. |
||||
* <p> |
||||
* Calling this method is equivalent to: |
||||
* <pre> |
||||
* FluentIterable<E> someIterable = ...; |
||||
* FluentIterable.of(someIterable.toList()); |
||||
* </pre> |
||||
* |
||||
* @return a new iterable with the same contents as this iterable |
||||
*/ |
||||
public FluentIterable<E> eval() { |
||||
return of(toList()); |
||||
} |
||||
|
||||
/** |
||||
* Returns a new FluentIterable whose iterator will only return |
||||
* elements from this iterable matching the provided predicate. |
||||
* |
||||
* @param predicate the predicate used to filter elements |
||||
* @return a new iterable, providing a filtered view of this iterable |
||||
* @throws NullPointerException if predicate is null |
||||
*/ |
||||
public FluentIterable<E> filter(final Predicate<? super E> predicate) { |
||||
return of(IterableUtils.filteredIterable(iterable, predicate)); |
||||
} |
||||
|
||||
/** |
||||
* Returns a new FluentIterable whose iterator will return at most |
||||
* the provided maximum number of elements from this iterable. |
||||
* |
||||
* @param maxSize the maximum number of elements |
||||
* @return a new iterable, providing a bounded view of this iterable |
||||
* @throws IllegalArgumentException if maxSize is negative |
||||
*/ |
||||
public FluentIterable<E> limit(final long maxSize) { |
||||
return of(IterableUtils.boundedIterable(iterable, maxSize)); |
||||
} |
||||
|
||||
/** |
||||
* Returns a new FluentIterable whose iterator will loop infinitely |
||||
* over the elements from this iterable. |
||||
* |
||||
* @return a new iterable, providing a looping view of this iterable |
||||
*/ |
||||
public FluentIterable<E> loop() { |
||||
return of(IterableUtils.loopingIterable(iterable)); |
||||
} |
||||
|
||||
/** |
||||
* Returns a new FluentIterable whose iterator will traverse the |
||||
* elements from this iterable in reverse order. |
||||
* |
||||
* @return a new iterable, providing a reversed view of this iterable |
||||
*/ |
||||
public FluentIterable<E> reverse() { |
||||
return of(IterableUtils.reversedIterable(iterable)); |
||||
} |
||||
|
||||
/** |
||||
* Returns a new FluentIterable whose iterator will skip the first |
||||
* N elements from this iterable. |
||||
* |
||||
* @param elementsToSkip the number of elements to skip |
||||
* @return a new iterable, providing a view of this iterable by skipping |
||||
* the first N elements |
||||
* @throws IllegalArgumentException if elementsToSkip is negative |
||||
*/ |
||||
public FluentIterable<E> skip(final long elementsToSkip) { |
||||
return of(IterableUtils.skippingIterable(iterable, elementsToSkip)); |
||||
} |
||||
|
||||
/** |
||||
* Returns a new FluentIterable whose iterator will return all elements |
||||
* of this iterable transformed by the provided transformer. |
||||
* |
||||
* @param <O> the output element type |
||||
* @param transformer the transformer applied to each element |
||||
* @return a new iterable, providing a transformed view of this iterable |
||||
* @throws NullPointerException if transformer is null |
||||
*/ |
||||
public <O> FluentIterable<O> transform(final Transformer<? super E, ? extends O> transformer) { |
||||
return of(IterableUtils.transformedIterable(iterable, transformer)); |
||||
} |
||||
|
||||
/** |
||||
* Returns a new FluentIterable whose iterator will return a unique view |
||||
* of this iterable. |
||||
* |
||||
* @return a new iterable, providing a unique view of this iterable |
||||
*/ |
||||
public FluentIterable<E> unique() { |
||||
return of(IterableUtils.uniqueIterable(iterable)); |
||||
} |
||||
|
||||
/** |
||||
* Returns a new FluentIterable whose iterator will return an unmodifiable |
||||
* view of this iterable. |
||||
* |
||||
* @return a new iterable, providing an unmodifiable view of this iterable |
||||
*/ |
||||
public FluentIterable<E> unmodifiable() { |
||||
return of(IterableUtils.unmodifiableIterable(iterable)); |
||||
} |
||||
|
||||
/** |
||||
* Returns a new FluentIterable whose iterator will traverse |
||||
* the elements of this iterable and the other iterable in |
||||
* alternating order. |
||||
* |
||||
* @param other the other iterable to interleave, may not be null |
||||
* @return a new iterable, interleaving this iterable with others |
||||
* @throws NullPointerException if other is null |
||||
*/ |
||||
public FluentIterable<E> zip(final Iterable<? extends E> other) { |
||||
return of(IterableUtils.zippingIterable(iterable, other)); |
||||
} |
||||
|
||||
/** |
||||
* Returns a new FluentIterable whose iterator will traverse |
||||
* the elements of this iterable and the other iterables in |
||||
* alternating order. |
||||
* |
||||
* @param others the iterables to interleave, may not be null |
||||
* @return a new iterable, interleaving this iterable with others |
||||
* @throws NullPointerException if either of the provided iterables is null |
||||
*/ |
||||
public FluentIterable<E> zip(final Iterable<? extends E>... others) { |
||||
return of(IterableUtils.zippingIterable(iterable, others)); |
||||
} |
||||
|
||||
// convenience methods
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
/** {@inheritDoc} */ |
||||
@Override |
||||
public Iterator<E> iterator() { |
||||
return iterable.iterator(); |
||||
} |
||||
|
||||
/** |
||||
* Returns an Enumeration that will enumerate all elements contained |
||||
* in this iterable. |
||||
* |
||||
* @return an Enumeration over the elements of this iterable |
||||
*/ |
||||
public Enumeration<E> asEnumeration() { |
||||
return IteratorUtils.asEnumeration(iterator()); |
||||
} |
||||
|
||||
/** |
||||
* Checks if all elements contained in this iterable are matching the |
||||
* provided predicate. |
||||
* <p> |
||||
* A <code>null</code> or empty iterable returns true. |
||||
* |
||||
* @param predicate the predicate to use, may not be null |
||||
* @return true if all elements contained in this iterable match the predicate, |
||||
* false otherwise |
||||
* @throws NullPointerException if predicate is null |
||||
*/ |
||||
public boolean allMatch(final Predicate<? super E> predicate) { |
||||
return IterableUtils.matchesAll(iterable, predicate); |
||||
} |
||||
|
||||
/** |
||||
* Checks if this iterable contains any element matching the provided predicate. |
||||
* <p> |
||||
* A <code>null</code> or empty iterable returns false. |
||||
* |
||||
* @param predicate the predicate to use, may not be null |
||||
* @return true if at least one element contained in this iterable matches the predicate, |
||||
* false otherwise |
||||
* @throws NullPointerException if predicate is null |
||||
*/ |
||||
public boolean anyMatch(final Predicate<? super E> predicate) { |
||||
return IterableUtils.matchesAny(iterable, predicate); |
||||
} |
||||
|
||||
/** |
||||
* Checks if this iterable is empty. |
||||
* |
||||
* @return true if this iterable does not contain any elements, false otherwise |
||||
*/ |
||||
public boolean isEmpty() { |
||||
return IterableUtils.isEmpty(iterable); |
||||
} |
||||
|
||||
/** |
||||
* Checks if the object is contained in this iterable. |
||||
* |
||||
* @param object the object to check |
||||
* @return true if the object is contained in this iterable, false otherwise |
||||
*/ |
||||
public boolean contains(final Object object) { |
||||
return IterableUtils.contains(iterable, object); |
||||
} |
||||
|
||||
/** |
||||
* Applies the closure to all elements contained in this iterable. |
||||
* |
||||
* @param closure the closure to apply to each element, may not be null |
||||
* @throws NullPointerException if closure is null |
||||
*/ |
||||
public void forEach(final Closure<? super E> closure) { |
||||
IterableUtils.forEach(iterable, closure); |
||||
} |
||||
|
||||
/** |
||||
* Returns the element at the provided position in this iterable. |
||||
* In order to return the element, an iterator needs to be traversed |
||||
* up to the requested position. |
||||
* |
||||
* @param position the position of the element to return |
||||
* @return the element |
||||
* @throws IndexOutOfBoundsException if the provided position is outside the |
||||
* valid range of this iterable: [0, size) |
||||
*/ |
||||
public E get(final int position) { |
||||
return IterableUtils.get(iterable, position); |
||||
} |
||||
|
||||
/** |
||||
* Returns the number of elements that are contained in this iterable. |
||||
* In order to determine the size, an iterator needs to be traversed. |
||||
* |
||||
* @return the size of this iterable |
||||
*/ |
||||
public int size() { |
||||
return IterableUtils.size(iterable); |
||||
} |
||||
|
||||
/** |
||||
* Traverses an iterator of this iterable and adds all elements |
||||
* to the provided collection. |
||||
* |
||||
* @param collection the collection to add the elements |
||||
* @throws NullPointerException if collection is null |
||||
*/ |
||||
public void copyInto(final Collection<? super E> collection) { |
||||
if (collection == null) { |
||||
throw new NullPointerException("Collection must not be null"); |
||||
} |
||||
CollectionUtils.addAll(collection, iterable); |
||||
} |
||||
|
||||
/** |
||||
* Returns an array containing all elements of this iterable by traversing |
||||
* its iterator. |
||||
* |
||||
* @param arrayClass the class of array to create |
||||
* @return an array of the iterable contents |
||||
* @throws ArrayStoreException if arrayClass is invalid |
||||
*/ |
||||
public E[] toArray(final Class<E> arrayClass) { |
||||
return IteratorUtils.toArray(iterator(), arrayClass); |
||||
} |
||||
|
||||
/** |
||||
* Returns a mutable list containing all elements of this iterable |
||||
* by traversing its iterator. |
||||
* <p> |
||||
* The returned list is guaranteed to be mutable. |
||||
* |
||||
* @return a list of the iterable contents |
||||
*/ |
||||
public List<E> toList() { |
||||
return IterableUtils.toList(iterable); |
||||
} |
||||
|
||||
/** {@inheritDoc} */ |
||||
@Override |
||||
public String toString() { |
||||
return IterableUtils.toString(iterable); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,72 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package com.fr.third.org.apache.commons.collections4; |
||||
|
||||
/** |
||||
* Runtime exception thrown from functors. |
||||
* If required, a root cause error can be wrapped within this one. |
||||
* |
||||
* @since 3.0 |
||||
* @version $Id: FunctorException.java 1477779 2013-04-30 18:55:24Z tn $ |
||||
*/ |
||||
public class FunctorException extends RuntimeException { |
||||
|
||||
/** Serialization version */ |
||||
private static final long serialVersionUID = -4704772662059351193L; |
||||
|
||||
/** |
||||
* Constructs a new <code>FunctorException</code> without specified |
||||
* detail message. |
||||
*/ |
||||
public FunctorException() { |
||||
super(); |
||||
} |
||||
|
||||
/** |
||||
* Constructs a new <code>FunctorException</code> with specified |
||||
* detail message. |
||||
* |
||||
* @param msg the error message. |
||||
*/ |
||||
public FunctorException(final String msg) { |
||||
super(msg); |
||||
} |
||||
|
||||
/** |
||||
* Constructs a new <code>FunctorException</code> with specified |
||||
* nested <code>Throwable</code> root cause. |
||||
* |
||||
* @param rootCause the exception or error that caused this exception |
||||
* to be thrown. |
||||
*/ |
||||
public FunctorException(final Throwable rootCause) { |
||||
super(rootCause); |
||||
} |
||||
|
||||
/** |
||||
* Constructs a new <code>FunctorException</code> with specified |
||||
* detail message and nested <code>Throwable</code> root cause. |
||||
* |
||||
* @param msg the error message. |
||||
* @param rootCause the exception or error that caused this exception |
||||
* to be thrown. |
||||
*/ |
||||
public FunctorException(final String msg, final Throwable rootCause) { |
||||
super(msg, rootCause); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,77 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package com.fr.third.org.apache.commons.collections4; |
||||
|
||||
import java.util.Collection; |
||||
import java.util.Set; |
||||
|
||||
/** |
||||
* The "read" subset of the {@link java.util.Map} interface. |
||||
* |
||||
* @since 4.0 |
||||
* @version $Id: Get.java 1543265 2013-11-19 00:48:44Z ggregory $ |
||||
* |
||||
* @see Put |
||||
*/ |
||||
public interface Get<K, V> { |
||||
|
||||
/** |
||||
* @see java.util.Map#containsKey(Object) |
||||
*/ |
||||
boolean containsKey(Object key); |
||||
|
||||
/** |
||||
* @see java.util.Map#containsValue(Object) |
||||
*/ |
||||
boolean containsValue(Object value); |
||||
|
||||
/** |
||||
* @see java.util.Map#entrySet() |
||||
*/ |
||||
Set<java.util.Map.Entry<K, V>> entrySet(); |
||||
|
||||
/** |
||||
* @see java.util.Map#get(Object) |
||||
*/ |
||||
V get(Object key); |
||||
|
||||
/** |
||||
* @see java.util.Map#remove(Object) |
||||
*/ |
||||
V remove(Object key); |
||||
|
||||
/** |
||||
* @see java.util.Map#isEmpty() |
||||
*/ |
||||
boolean isEmpty(); |
||||
|
||||
/** |
||||
* @see java.util.Map#keySet() |
||||
*/ |
||||
Set<K> keySet(); |
||||
|
||||
/** |
||||
* @see java.util.Map#size() |
||||
*/ |
||||
int size(); |
||||
|
||||
/** |
||||
* @see java.util.Map#values() |
||||
*/ |
||||
Collection<V> values(); |
||||
|
||||
} |
@ -0,0 +1,47 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package com.fr.third.org.apache.commons.collections4; |
||||
|
||||
/** |
||||
* The "read" subset of the {@link java.util.Map} interface. |
||||
* |
||||
* @since 4.0 |
||||
* @version $Id: IterableGet.java 1477779 2013-04-30 18:55:24Z tn $ |
||||
* |
||||
* @see Put |
||||
*/ |
||||
public interface IterableGet<K, V> extends Get<K, V> { |
||||
/** |
||||
* Obtains a <code>MapIterator</code> over the map. |
||||
* <p> |
||||
* A map iterator is an efficient way of iterating over maps. |
||||
* There is no need to access the entry set or use Map Entry objects. |
||||
* <pre> |
||||
* IterableMap<String,Integer> map = new HashedMap<String,Integer>(); |
||||
* MapIterator<String,Integer> it = map.mapIterator(); |
||||
* while (it.hasNext()) { |
||||
* String key = it.next(); |
||||
* Integer value = it.getValue(); |
||||
* it.setValue(value + 1); |
||||
* } |
||||
* </pre> |
||||
* |
||||
* @return a map iterator |
||||
*/ |
||||
MapIterator<K, V> mapIterator(); |
||||
|
||||
} |
@ -0,0 +1,43 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package com.fr.third.org.apache.commons.collections4; |
||||
|
||||
import java.util.Map; |
||||
|
||||
/** |
||||
* Defines a map that can be iterated directly without needing to create an entry set. |
||||
* <p> |
||||
* A map iterator is an efficient way of iterating over maps. |
||||
* There is no need to access the entry set or use Map Entry objects. |
||||
* <pre> |
||||
* IterableMap<String,Integer> map = new HashedMap<String,Integer>(); |
||||
* MapIterator<String,Integer> it = map.mapIterator(); |
||||
* while (it.hasNext()) { |
||||
* String key = it.next(); |
||||
* Integer value = it.getValue(); |
||||
* it.setValue(value + 1); |
||||
* } |
||||
* </pre> |
||||
* |
||||
* @param <K> the type of the keys in the map |
||||
* @param <V> the type of the values in the map |
||||
* |
||||
* @since 3.0 |
||||
* @version $Id: IterableMap.java 1469004 2013-04-17 17:37:03Z tn $ |
||||
*/ |
||||
public interface IterableMap<K, V> extends Map<K, V>, Put<K, V>, IterableGet<K, V> { |
||||
} |
@ -0,0 +1,31 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package com.fr.third.org.apache.commons.collections4; |
||||
|
||||
import java.util.SortedMap; |
||||
|
||||
/** |
||||
* {@link SortedMap} + {@link OrderedMap}. |
||||
* |
||||
* @param <K> the type of the keys in the map |
||||
* @param <V> the type of the values in the map |
||||
* |
||||
* @since 4.0 |
||||
* @version $Id: IterableSortedMap.java 1469004 2013-04-17 17:37:03Z tn $ |
||||
*/ |
||||
public interface IterableSortedMap<K, V> extends SortedMap<K, V>, OrderedMap<K, V> { |
||||
} |
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,47 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package com.fr.third.org.apache.commons.collections4; |
||||
|
||||
/** |
||||
* Defines a simple key value pair. |
||||
* <p> |
||||
* A Map Entry has considerable additional semantics over and above a simple |
||||
* key-value pair. This interface defines the minimum key value, with just the |
||||
* two get methods. |
||||
* |
||||
* @param <K> the type of the key |
||||
* @param <V> the type of the value |
||||
* @since 3.0 |
||||
* @version $Id: KeyValue.java 1477779 2013-04-30 18:55:24Z tn $ |
||||
*/ |
||||
public interface KeyValue<K, V> { |
||||
|
||||
/** |
||||
* Gets the key from the pair. |
||||
* |
||||
* @return the key |
||||
*/ |
||||
K getKey(); |
||||
|
||||
/** |
||||
* Gets the value from the pair. |
||||
* |
||||
* @return the value |
||||
*/ |
||||
V getValue(); |
||||
|
||||
} |
@ -0,0 +1,709 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package com.fr.third.org.apache.commons.collections4; |
||||
|
||||
import java.util.AbstractList; |
||||
import java.util.ArrayList; |
||||
import java.util.Collection; |
||||
import java.util.Collections; |
||||
import java.util.HashSet; |
||||
import java.util.Iterator; |
||||
import java.util.List; |
||||
|
||||
import com.fr.third.org.apache.commons.collections4.bag.HashBag; |
||||
import com.fr.third.org.apache.commons.collections4.functors.DefaultEquator; |
||||
import com.fr.third.org.apache.commons.collections4.list.FixedSizeList; |
||||
import com.fr.third.org.apache.commons.collections4.list.LazyList; |
||||
import com.fr.third.org.apache.commons.collections4.list.PredicatedList; |
||||
import com.fr.third.org.apache.commons.collections4.list.TransformedList; |
||||
import com.fr.third.org.apache.commons.collections4.list.UnmodifiableList; |
||||
import com.fr.third.org.apache.commons.collections4.sequence.CommandVisitor; |
||||
import com.fr.third.org.apache.commons.collections4.sequence.EditScript; |
||||
import com.fr.third.org.apache.commons.collections4.sequence.SequencesComparator; |
||||
import com.fr.third.org.apache.commons.collections4.bag.HashBag; |
||||
import com.fr.third.org.apache.commons.collections4.functors.DefaultEquator; |
||||
import com.fr.third.org.apache.commons.collections4.list.FixedSizeList; |
||||
import com.fr.third.org.apache.commons.collections4.list.LazyList; |
||||
import com.fr.third.org.apache.commons.collections4.list.PredicatedList; |
||||
import com.fr.third.org.apache.commons.collections4.list.TransformedList; |
||||
import com.fr.third.org.apache.commons.collections4.list.UnmodifiableList; |
||||
import com.fr.third.org.apache.commons.collections4.sequence.CommandVisitor; |
||||
import com.fr.third.org.apache.commons.collections4.sequence.EditScript; |
||||
import com.fr.third.org.apache.commons.collections4.sequence.SequencesComparator; |
||||
|
||||
/** |
||||
* Provides utility methods and decorators for {@link List} instances. |
||||
* |
||||
* @since 1.0 |
||||
* @version $Id: ListUtils.java 1686855 2015-06-22 13:00:27Z tn $ |
||||
*/ |
||||
public class ListUtils { |
||||
|
||||
/** |
||||
* <code>ListUtils</code> should not normally be instantiated. |
||||
*/ |
||||
private ListUtils() {} |
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
/** |
||||
* Returns an immutable empty list if the argument is <code>null</code>, |
||||
* or the argument itself otherwise. |
||||
* |
||||
* @param <T> the element type |
||||
* @param list the list, possibly <code>null</code> |
||||
* @return an empty list if the argument is <code>null</code> |
||||
*/ |
||||
public static <T> List<T> emptyIfNull(final List<T> list) { |
||||
return list == null ? Collections.<T>emptyList() : list; |
||||
} |
||||
|
||||
/** |
||||
* Returns either the passed in list, or if the list is {@code null}, |
||||
* the value of {@code defaultList}. |
||||
* |
||||
* @param <T> the element type |
||||
* @param list the list, possibly {@code null} |
||||
* @param defaultList the returned values if list is {@code null} |
||||
* @return an empty list if the argument is <code>null</code> |
||||
* @since 4.0 |
||||
*/ |
||||
public static <T> List<T> defaultIfNull(final List<T> list, final List<T> defaultList) { |
||||
return list == null ? defaultList : list; |
||||
} |
||||
|
||||
/** |
||||
* Returns a new list containing all elements that are contained in |
||||
* both given lists. |
||||
* |
||||
* @param <E> the element type |
||||
* @param list1 the first list |
||||
* @param list2 the second list |
||||
* @return the intersection of those two lists |
||||
* @throws NullPointerException if either list is null |
||||
*/ |
||||
public static <E> List<E> intersection(final List<? extends E> list1, final List<? extends E> list2) { |
||||
final List<E> result = new ArrayList<E>(); |
||||
|
||||
List<? extends E> smaller = list1; |
||||
List<? extends E> larger = list2; |
||||
if (list1.size() > list2.size()) { |
||||
smaller = list2; |
||||
larger = list1; |
||||
} |
||||
|
||||
final HashSet<E> hashSet = new HashSet<E>(smaller); |
||||
|
||||
for (final E e : larger) { |
||||
if (hashSet.contains(e)) { |
||||
result.add(e); |
||||
hashSet.remove(e); |
||||
} |
||||
} |
||||
return result; |
||||
} |
||||
|
||||
/** |
||||
* Subtracts all elements in the second list from the first list, |
||||
* placing the results in a new list. |
||||
* <p> |
||||
* This differs from {@link List#removeAll(Collection)} in that |
||||
* cardinality is respected; if <Code>list1</Code> contains two |
||||
* occurrences of <Code>null</Code> and <Code>list2</Code> only |
||||
* contains one occurrence, then the returned list will still contain |
||||
* one occurrence. |
||||
* |
||||
* @param <E> the element type |
||||
* @param list1 the list to subtract from |
||||
* @param list2 the list to subtract |
||||
* @return a new list containing the results |
||||
* @throws NullPointerException if either list is null |
||||
*/ |
||||
public static <E> List<E> subtract(final List<E> list1, final List<? extends E> list2) { |
||||
final ArrayList<E> result = new ArrayList<E>(); |
||||
final HashBag<E> bag = new HashBag<E>(list2); |
||||
for (final E e : list1) { |
||||
if (!bag.remove(e, 1)) { |
||||
result.add(e); |
||||
} |
||||
} |
||||
return result; |
||||
} |
||||
|
||||
/** |
||||
* Returns the sum of the given lists. This is their intersection |
||||
* subtracted from their union. |
||||
* |
||||
* @param <E> the element type |
||||
* @param list1 the first list |
||||
* @param list2 the second list |
||||
* @return a new list containing the sum of those lists |
||||
* @throws NullPointerException if either list is null |
||||
*/ |
||||
public static <E> List<E> sum(final List<? extends E> list1, final List<? extends E> list2) { |
||||
return subtract(union(list1, list2), intersection(list1, list2)); |
||||
} |
||||
|
||||
/** |
||||
* Returns a new list containing the second list appended to the |
||||
* first list. The {@link List#addAll(Collection)} operation is |
||||
* used to append the two given lists into a new list. |
||||
* |
||||
* @param <E> the element type |
||||
* @param list1 the first list |
||||
* @param list2 the second list |
||||
* @return a new list containing the union of those lists |
||||
* @throws NullPointerException if either list is null |
||||
*/ |
||||
public static <E> List<E> union(final List<? extends E> list1, final List<? extends E> list2) { |
||||
final ArrayList<E> result = new ArrayList<E>(list1); |
||||
result.addAll(list2); |
||||
return result; |
||||
} |
||||
|
||||
/** |
||||
* Selects all elements from input collection which match the given |
||||
* predicate into an output list. |
||||
* <p> |
||||
* A <code>null</code> predicate matches no elements. |
||||
* |
||||
* @param <E> the element type |
||||
* @param inputCollection the collection to get the input from, may not be null |
||||
* @param predicate the predicate to use, may be null |
||||
* @return the elements matching the predicate (new list) |
||||
* @throws NullPointerException if the input list is null |
||||
* |
||||
* @since 4.0 |
||||
* @see CollectionUtils#select(Iterable, Predicate) |
||||
*/ |
||||
public static <E> List<E> select(final Collection<? extends E> inputCollection, |
||||
final Predicate<? super E> predicate) { |
||||
return CollectionUtils.select(inputCollection, predicate, new ArrayList<E>(inputCollection.size())); |
||||
} |
||||
|
||||
/** |
||||
* Selects all elements from inputCollection which don't match the given |
||||
* predicate into an output collection. |
||||
* <p> |
||||
* If the input predicate is <code>null</code>, the result is an empty list. |
||||
* |
||||
* @param <E> the element type |
||||
* @param inputCollection the collection to get the input from, may not be null |
||||
* @param predicate the predicate to use, may be null |
||||
* @return the elements <b>not</b> matching the predicate (new list) |
||||
* @throws NullPointerException if the input collection is null |
||||
* |
||||
* @since 4.0 |
||||
* @see CollectionUtils#selectRejected(Iterable, Predicate) |
||||
*/ |
||||
public static <E> List<E> selectRejected(final Collection<? extends E> inputCollection, |
||||
final Predicate<? super E> predicate) { |
||||
return CollectionUtils.selectRejected(inputCollection, predicate, new ArrayList<E>(inputCollection.size())); |
||||
} |
||||
|
||||
/** |
||||
* Tests two lists for value-equality as per the equality contract in |
||||
* {@link java.util.List#equals(java.lang.Object)}. |
||||
* <p> |
||||
* This method is useful for implementing <code>List</code> when you cannot |
||||
* extend AbstractList. The method takes Collection instances to enable other |
||||
* collection types to use the List implementation algorithm. |
||||
* <p> |
||||
* The relevant text (slightly paraphrased as this is a static method) is: |
||||
* <blockquote> |
||||
* Compares the two list objects for equality. Returns |
||||
* {@code true} if and only if both |
||||
* lists have the same size, and all corresponding pairs of elements in |
||||
* the two lists are <i>equal</i>. (Two elements {@code e1} and |
||||
* {@code e2} are <i>equal</i> if <tt>(e1==null ? e2==null : |
||||
* e1.equals(e2))</tt>.) In other words, two lists are defined to be |
||||
* equal if they contain the same elements in the same order. This |
||||
* definition ensures that the equals method works properly across |
||||
* different implementations of the {@code List} interface. |
||||
* </blockquote> |
||||
* |
||||
* <b>Note:</b> The behaviour of this method is undefined if the lists are |
||||
* modified during the equals comparison. |
||||
* |
||||
* @see java.util.List |
||||
* @param list1 the first list, may be null |
||||
* @param list2 the second list, may be null |
||||
* @return whether the lists are equal by value comparison |
||||
*/ |
||||
public static boolean isEqualList(final Collection<?> list1, final Collection<?> list2) { |
||||
if (list1 == list2) { |
||||
return true; |
||||
} |
||||
if (list1 == null || list2 == null || list1.size() != list2.size()) { |
||||
return false; |
||||
} |
||||
|
||||
final Iterator<?> it1 = list1.iterator(); |
||||
final Iterator<?> it2 = list2.iterator(); |
||||
Object obj1 = null; |
||||
Object obj2 = null; |
||||
|
||||
while (it1.hasNext() && it2.hasNext()) { |
||||
obj1 = it1.next(); |
||||
obj2 = it2.next(); |
||||
|
||||
if (!(obj1 == null ? obj2 == null : obj1.equals(obj2))) { |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
return !(it1.hasNext() || it2.hasNext()); |
||||
} |
||||
|
||||
/** |
||||
* Generates a hash code using the algorithm specified in |
||||
* {@link java.util.List#hashCode()}. |
||||
* <p> |
||||
* This method is useful for implementing <code>List</code> when you cannot |
||||
* extend AbstractList. The method takes Collection instances to enable other |
||||
* collection types to use the List implementation algorithm. |
||||
* |
||||
* @see java.util.List#hashCode() |
||||
* @param list the list to generate the hashCode for, may be null |
||||
* @return the hash code |
||||
*/ |
||||
public static int hashCodeForList(final Collection<?> list) { |
||||
if (list == null) { |
||||
return 0; |
||||
} |
||||
int hashCode = 1; |
||||
final Iterator<?> it = list.iterator(); |
||||
|
||||
while (it.hasNext()) { |
||||
final Object obj = it.next(); |
||||
hashCode = 31 * hashCode + (obj == null ? 0 : obj.hashCode()); |
||||
} |
||||
return hashCode; |
||||
} |
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/** |
||||
* Returns a List containing all the elements in <code>collection</code> |
||||
* that are also in <code>retain</code>. The cardinality of an element <code>e</code> |
||||
* in the returned list is the same as the cardinality of <code>e</code> |
||||
* in <code>collection</code> unless <code>retain</code> does not contain <code>e</code>, in which |
||||
* case the cardinality is zero. This method is useful if you do not wish to modify |
||||
* the collection <code>c</code> and thus cannot call <code>collection.retainAll(retain);</code>. |
||||
* <p> |
||||
* This implementation iterates over <code>collection</code>, checking each element in |
||||
* turn to see if it's contained in <code>retain</code>. If it's contained, it's added |
||||
* to the returned list. As a consequence, it is advised to use a collection type for |
||||
* <code>retain</code> that provides a fast (e.g. O(1)) implementation of |
||||
* {@link Collection#contains(Object)}. |
||||
* |
||||
* @param <E> the element type |
||||
* @param collection the collection whose contents are the target of the #retailAll operation |
||||
* @param retain the collection containing the elements to be retained in the returned collection |
||||
* @return a <code>List</code> containing all the elements of <code>c</code> |
||||
* that occur at least once in <code>retain</code>. |
||||
* @throws NullPointerException if either parameter is null |
||||
* @since 3.2 |
||||
*/ |
||||
public static <E> List<E> retainAll(final Collection<E> collection, final Collection<?> retain) { |
||||
final List<E> list = new ArrayList<E>(Math.min(collection.size(), retain.size())); |
||||
|
||||
for (final E obj : collection) { |
||||
if (retain.contains(obj)) { |
||||
list.add(obj); |
||||
} |
||||
} |
||||
return list; |
||||
} |
||||
|
||||
/** |
||||
* Removes the elements in <code>remove</code> from <code>collection</code>. That is, this |
||||
* method returns a list containing all the elements in <code>collection</code> |
||||
* that are not in <code>remove</code>. The cardinality of an element <code>e</code> |
||||
* in the returned collection is the same as the cardinality of <code>e</code> |
||||
* in <code>collection</code> unless <code>remove</code> contains <code>e</code>, in which |
||||
* case the cardinality is zero. This method is useful if you do not wish to modify |
||||
* <code>collection</code> and thus cannot call <code>collection.removeAll(remove);</code>. |
||||
* <p> |
||||
* This implementation iterates over <code>collection</code>, checking each element in |
||||
* turn to see if it's contained in <code>remove</code>. If it's not contained, it's added |
||||
* to the returned list. As a consequence, it is advised to use a collection type for |
||||
* <code>remove</code> that provides a fast (e.g. O(1)) implementation of |
||||
* {@link Collection#contains(Object)}. |
||||
* |
||||
* @param <E> the element type |
||||
* @param collection the collection from which items are removed (in the returned collection) |
||||
* @param remove the items to be removed from the returned <code>collection</code> |
||||
* @return a <code>List</code> containing all the elements of <code>c</code> except |
||||
* any elements that also occur in <code>remove</code>. |
||||
* @throws NullPointerException if either parameter is null |
||||
* @since 3.2 |
||||
*/ |
||||
public static <E> List<E> removeAll(final Collection<E> collection, final Collection<?> remove) { |
||||
final List<E> list = new ArrayList<E>(); |
||||
for (final E obj : collection) { |
||||
if (!remove.contains(obj)) { |
||||
list.add(obj); |
||||
} |
||||
} |
||||
return list; |
||||
} |
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/** |
||||
* Returns a synchronized list backed by the given list. |
||||
* <p> |
||||
* You must manually synchronize on the returned list's iterator to |
||||
* avoid non-deterministic behavior: |
||||
* |
||||
* <pre> |
||||
* List list = ListUtils.synchronizedList(myList); |
||||
* synchronized (list) { |
||||
* Iterator i = list.iterator(); |
||||
* while (i.hasNext()) { |
||||
* process (i.next()); |
||||
* } |
||||
* } |
||||
* </pre> |
||||
* |
||||
* This method is just a wrapper for {@link Collections#synchronizedList(List)}. |
||||
* |
||||
* @param <E> the element type |
||||
* @param list the list to synchronize, must not be null |
||||
* @return a synchronized list backed by the given list |
||||
* @throws NullPointerException if the list is null |
||||
*/ |
||||
public static <E> List<E> synchronizedList(final List<E> list) { |
||||
return Collections.synchronizedList(list); |
||||
} |
||||
|
||||
/** |
||||
* Returns an unmodifiable list backed by the given list. |
||||
* <p> |
||||
* This method uses the implementation in the decorators subpackage. |
||||
* |
||||
* @param <E> the element type |
||||
* @param list the list to make unmodifiable, must not be null |
||||
* @return an unmodifiable list backed by the given list |
||||
* @throws NullPointerException if the list is null |
||||
*/ |
||||
public static <E> List<E> unmodifiableList(final List<? extends E> list) { |
||||
return UnmodifiableList.unmodifiableList(list); |
||||
} |
||||
|
||||
/** |
||||
* Returns a predicated (validating) list backed by the given list. |
||||
* <p> |
||||
* Only objects that pass the test in the given predicate can be added to the list. |
||||
* Trying to add an invalid object results in an IllegalArgumentException. |
||||
* It is important not to use the original list after invoking this method, |
||||
* as it is a backdoor for adding invalid objects. |
||||
* |
||||
* @param <E> the element type |
||||
* @param list the list to predicate, must not be null |
||||
* @param predicate the predicate for the list, must not be null |
||||
* @return a predicated list backed by the given list |
||||
* @throws NullPointerException if the List or Predicate is null |
||||
*/ |
||||
public static <E> List<E> predicatedList(final List<E> list, final Predicate<E> predicate) { |
||||
return PredicatedList.predicatedList(list, predicate); |
||||
} |
||||
|
||||
/** |
||||
* Returns a transformed list backed by the given list. |
||||
* <p> |
||||
* This method returns a new list (decorating the specified list) that |
||||
* will transform any new entries added to it. |
||||
* Existing entries in the specified list will not be transformed. |
||||
* <p> |
||||
* Each object is passed through the transformer as it is added to the |
||||
* List. It is important not to use the original list after invoking this |
||||
* method, as it is a backdoor for adding untransformed objects. |
||||
* <p> |
||||
* Existing entries in the specified list will not be transformed. |
||||
* If you want that behaviour, see {@link TransformedList#transformedList}. |
||||
* |
||||
* @param <E> the element type |
||||
* @param list the list to predicate, must not be null |
||||
* @param transformer the transformer for the list, must not be null |
||||
* @return a transformed list backed by the given list |
||||
* @throws NullPointerException if the List or Transformer is null |
||||
*/ |
||||
public static <E> List<E> transformedList(final List<E> list, |
||||
final Transformer<? super E, ? extends E> transformer) { |
||||
return TransformedList.transformingList(list, transformer); |
||||
} |
||||
|
||||
/** |
||||
* Returns a "lazy" list whose elements will be created on demand. |
||||
* <p> |
||||
* When the index passed to the returned list's {@link List#get(int) get} |
||||
* method is greater than the list's size, then the factory will be used |
||||
* to create a new object and that object will be inserted at that index. |
||||
* <p> |
||||
* For instance: |
||||
* |
||||
* <pre> |
||||
* Factory<Date> factory = new Factory<Date>() { |
||||
* public Date create() { |
||||
* return new Date(); |
||||
* } |
||||
* } |
||||
* List<Date> lazy = ListUtils.lazyList(new ArrayList<Date>(), factory); |
||||
* Date date = lazy.get(3); |
||||
* </pre> |
||||
* |
||||
* After the above code is executed, <code>date</code> will refer to |
||||
* a new <code>Date</code> instance. Furthermore, that <code>Date</code> |
||||
* instance is the fourth element in the list. The first, second, |
||||
* and third element are all set to <code>null</code>. |
||||
* |
||||
* @param <E> the element type |
||||
* @param list the list to make lazy, must not be null |
||||
* @param factory the factory for creating new objects, must not be null |
||||
* @return a lazy list backed by the given list |
||||
* @throws NullPointerException if the List or Factory is null |
||||
*/ |
||||
public static <E> List<E> lazyList(final List<E> list, final Factory<? extends E> factory) { |
||||
return LazyList.lazyList(list, factory); |
||||
} |
||||
|
||||
/** |
||||
* Returns a fixed-sized list backed by the given list. |
||||
* Elements may not be added or removed from the returned list, but |
||||
* existing elements can be changed (for instance, via the |
||||
* {@link List#set(int, Object)} method). |
||||
* |
||||
* @param <E> the element type |
||||
* @param list the list whose size to fix, must not be null |
||||
* @return a fixed-size list backed by that list |
||||
* @throws NullPointerException if the List is null |
||||
*/ |
||||
public static <E> List<E> fixedSizeList(final List<E> list) { |
||||
return FixedSizeList.fixedSizeList(list); |
||||
} |
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/** |
||||
* Finds the first index in the given List which matches the given predicate. |
||||
* <p> |
||||
* If the input List or predicate is null, or no element of the List |
||||
* matches the predicate, -1 is returned. |
||||
* |
||||
* @param <E> the element type |
||||
* @param list the List to search, may be null |
||||
* @param predicate the predicate to use, may be null |
||||
* @return the first index of an Object in the List which matches the predicate or -1 if none could be found |
||||
*/ |
||||
public static <E> int indexOf(final List<E> list, final Predicate<E> predicate) { |
||||
if (list != null && predicate != null) { |
||||
for (int i = 0; i < list.size(); i++) { |
||||
final E item = list.get(i); |
||||
if (predicate.evaluate(item)) { |
||||
return i; |
||||
} |
||||
} |
||||
} |
||||
return -1; |
||||
} |
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/** |
||||
* Returns the longest common subsequence (LCS) of two sequences (lists). |
||||
* |
||||
* @param <E> the element type |
||||
* @param a the first list |
||||
* @param b the second list |
||||
* @return the longest common subsequence |
||||
* @throws NullPointerException if either list is {@code null} |
||||
* @since 4.0 |
||||
*/ |
||||
public static <E> List<E> longestCommonSubsequence(final List<E> a, final List<E> b) { |
||||
return longestCommonSubsequence( a, b, DefaultEquator.defaultEquator() ); |
||||
} |
||||
|
||||
/** |
||||
* Returns the longest common subsequence (LCS) of two sequences (lists). |
||||
* |
||||
* @param <E> the element type |
||||
* @param a the first list |
||||
* @param b the second list |
||||
* @param equator the equator used to test object equality |
||||
* @return the longest common subsequence |
||||
* @throws NullPointerException if either list or the equator is {@code null} |
||||
* @since 4.0 |
||||
*/ |
||||
public static <E> List<E> longestCommonSubsequence(final List<E> a, final List<E> b, |
||||
final Equator<? super E> equator) { |
||||
if (a == null || b == null) { |
||||
throw new NullPointerException("List must not be null"); |
||||
} |
||||
if (equator == null) { |
||||
throw new NullPointerException("Equator must not be null"); |
||||
} |
||||
|
||||
final SequencesComparator<E> comparator = new SequencesComparator<E>(a, b, equator); |
||||
final EditScript<E> script = comparator.getScript(); |
||||
final LcsVisitor<E> visitor = new LcsVisitor<E>(); |
||||
script.visit(visitor); |
||||
return visitor.getSubSequence(); |
||||
} |
||||
|
||||
/** |
||||
* Returns the longest common subsequence (LCS) of two {@link CharSequence} objects. |
||||
* <p> |
||||
* This is a convenience method for using {@link #longestCommonSubsequence(List, List)} |
||||
* with {@link CharSequence} instances. |
||||
* |
||||
* @param a the first sequence |
||||
* @param b the second sequence |
||||
* @return the longest common subsequence as {@link String} |
||||
* @throws NullPointerException if either sequence is {@code null} |
||||
* @since 4.0 |
||||
*/ |
||||
public static String longestCommonSubsequence(final CharSequence a, final CharSequence b) { |
||||
if (a == null || b == null) { |
||||
throw new NullPointerException("CharSequence must not be null"); |
||||
} |
||||
final List<Character> lcs = longestCommonSubsequence(new CharSequenceAsList( a ), new CharSequenceAsList( b )); |
||||
final StringBuilder sb = new StringBuilder(); |
||||
for ( Character ch : lcs ) { |
||||
sb.append(ch); |
||||
} |
||||
return sb.toString(); |
||||
} |
||||
|
||||
/** |
||||
* A helper class used to construct the longest common subsequence. |
||||
*/ |
||||
private static final class LcsVisitor<E> implements CommandVisitor<E> { |
||||
private ArrayList<E> sequence; |
||||
|
||||
public LcsVisitor() { |
||||
sequence = new ArrayList<E>(); |
||||
} |
||||
|
||||
public void visitInsertCommand(final E object) {} |
||||
|
||||
public void visitDeleteCommand(final E object) {} |
||||
|
||||
public void visitKeepCommand(final E object) { |
||||
sequence.add(object); |
||||
} |
||||
|
||||
public List<E> getSubSequence() { |
||||
return sequence; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* A simple wrapper to use a CharSequence as List. |
||||
*/ |
||||
private static final class CharSequenceAsList extends AbstractList<Character> { |
||||
|
||||
private final CharSequence sequence; |
||||
|
||||
public CharSequenceAsList(final CharSequence sequence) { |
||||
this.sequence = sequence; |
||||
} |
||||
|
||||
@Override |
||||
public Character get( int index ) { |
||||
return Character.valueOf(sequence.charAt( index )); |
||||
} |
||||
|
||||
@Override |
||||
public int size() { |
||||
return sequence.length(); |
||||
} |
||||
|
||||
} |
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/** |
||||
* Returns consecutive {@link List#subList(int, int) sublists} of a |
||||
* list, each of the same size (the final list may be smaller). For example, |
||||
* partitioning a list containing {@code [a, b, c, d, e]} with a partition |
||||
* size of 3 yields {@code [[a, b, c], [d, e]]} -- an outer list containing |
||||
* two inner lists of three and two elements, all in the original order. |
||||
* <p> |
||||
* The outer list is unmodifiable, but reflects the latest state of the |
||||
* source list. The inner lists are sublist views of the original list, |
||||
* produced on demand using {@link List#subList(int, int)}, and are subject |
||||
* to all the usual caveats about modification as explained in that API. |
||||
* <p> |
||||
* Adapted from http://code.google.com/p/guava-libraries/
|
||||
* |
||||
* @param <T> the element type |
||||
* @param list the list to return consecutive sublists of |
||||
* @param size the desired size of each sublist (the last may be smaller) |
||||
* @return a list of consecutive sublists |
||||
* @throws NullPointerException if list is null |
||||
* @throws IllegalArgumentException if size is not strictly positive |
||||
* @since 4.0 |
||||
*/ |
||||
public static <T> List<List<T>> partition(final List<T> list, final int size) { |
||||
if (list == null) { |
||||
throw new NullPointerException("List must not be null"); |
||||
} |
||||
if (size <= 0) { |
||||
throw new IllegalArgumentException("Size must be greater than 0"); |
||||
} |
||||
return new Partition<T>(list, size); |
||||
} |
||||
|
||||
/** |
||||
* Provides a partition view on a {@link List}. |
||||
* @since 4.0 |
||||
*/ |
||||
private static class Partition<T> extends AbstractList<List<T>> { |
||||
private final List<T> list; |
||||
private final int size; |
||||
|
||||
private Partition(final List<T> list, final int size) { |
||||
this.list = list; |
||||
this.size = size; |
||||
} |
||||
|
||||
@Override |
||||
public List<T> get(final int index) { |
||||
final int listSize = size(); |
||||
if (listSize < 0) { |
||||
throw new IllegalArgumentException("negative size: " + listSize); |
||||
} |
||||
if (index < 0) { |
||||
throw new IndexOutOfBoundsException("Index " + index + " must not be negative"); |
||||
} |
||||
if (index >= listSize) { |
||||
throw new IndexOutOfBoundsException("Index " + index + " must be less than size " + |
||||
listSize); |
||||
} |
||||
final int start = index * size; |
||||
final int end = Math.min(start + size, list.size()); |
||||
return list.subList(start, end); |
||||
} |
||||
|
||||
@Override |
||||
public int size() { |
||||
return (list.size() + size - 1) / size; |
||||
} |
||||
|
||||
@Override |
||||
public boolean isEmpty() { |
||||
return list.isEmpty(); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,67 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package com.fr.third.org.apache.commons.collections4; |
||||
|
||||
import java.util.List; |
||||
|
||||
/** |
||||
* Defines a map that holds a list of values against each key. |
||||
* <p> |
||||
* A {@code ListValuedMap} is a Map with slightly different semantics: |
||||
* <ul> |
||||
* <li>Putting a value into the map will add the value to a {@link List} at that key.</li> |
||||
* <li>Getting a value will return a {@link List}, holding all the values put to that key.</li> |
||||
* </ul> |
||||
* |
||||
* @since 4.1 |
||||
* @version $Id: ListValuedMap.java 1685299 2015-06-13 18:27:11Z tn $ |
||||
*/ |
||||
public interface ListValuedMap<K, V> extends MultiValuedMap<K, V> { |
||||
|
||||
/** |
||||
* Gets the list of values associated with the specified key. |
||||
* <p> |
||||
* This method will return an <b>empty</b> list if |
||||
* {@link #containsKey(Object)} returns {@code false}. Changes to the |
||||
* returned list will update the underlying {@code ListValuedMap} and |
||||
* vice-versa. |
||||
* |
||||
* @param key the key to retrieve |
||||
* @return the {@code List} of values, implementations should return an |
||||
* empty {@code List} for no mapping |
||||
* @throws NullPointerException if the key is null and null keys are invalid |
||||
*/ |
||||
@Override |
||||
List<V> get(K key); |
||||
|
||||
/** |
||||
* Removes all values associated with the specified key. |
||||
* <p> |
||||
* The returned list <i>may</i> be modifiable, but updates will not be |
||||
* propagated to this list-valued map. In case no mapping was stored for the |
||||
* specified key, an empty, unmodifiable list will be returned. |
||||
* |
||||
* @param key the key to remove values from |
||||
* @return the {@code List} of values removed, implementations |
||||
* typically return an empty, unmodifiable {@code List} for no mapping found |
||||
* @throws UnsupportedOperationException if the map is unmodifiable |
||||
* @throws NullPointerException if the key is null and null keys are invalid |
||||
*/ |
||||
@Override |
||||
List<V> remove(Object key); |
||||
|
||||
} |
@ -0,0 +1,109 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package com.fr.third.org.apache.commons.collections4; |
||||
|
||||
import java.util.Iterator; |
||||
|
||||
/** |
||||
* Defines an iterator that operates over a <code>Map</code>. |
||||
* <p> |
||||
* This iterator is a special version designed for maps. It can be more |
||||
* efficient to use this rather than an entry set iterator where the option |
||||
* is available, and it is certainly more convenient. |
||||
* <p> |
||||
* A map that provides this interface may not hold the data internally using |
||||
* Map Entry objects, thus this interface can avoid lots of object creation. |
||||
* <p> |
||||
* In use, this iterator iterates through the keys in the map. After each call |
||||
* to <code>next()</code>, the <code>getValue()</code> method provides direct |
||||
* access to the value. The value can also be set using <code>setValue()</code>. |
||||
* <pre> |
||||
* MapIterator<String,Integer> it = map.mapIterator(); |
||||
* while (it.hasNext()) { |
||||
* String key = it.next(); |
||||
* Integer value = it.getValue(); |
||||
* it.setValue(value + 1); |
||||
* } |
||||
* </pre> |
||||
* |
||||
* @param <K> the type of the keys in the map |
||||
* @param <V> the type of the values in the map |
||||
* @since 3.0 |
||||
* @version $Id: MapIterator.java 1469004 2013-04-17 17:37:03Z tn $ |
||||
*/ |
||||
public interface MapIterator<K, V> extends Iterator<K> { |
||||
|
||||
/** |
||||
* Checks to see if there are more entries still to be iterated. |
||||
* |
||||
* @return <code>true</code> if the iterator has more elements |
||||
*/ |
||||
boolean hasNext(); |
||||
|
||||
/** |
||||
* Gets the next <em>key</em> from the <code>Map</code>. |
||||
* |
||||
* @return the next key in the iteration |
||||
* @throws java.util.NoSuchElementException if the iteration is finished |
||||
*/ |
||||
K next(); |
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/** |
||||
* Gets the current key, which is the key returned by the last call |
||||
* to <code>next()</code>. |
||||
* |
||||
* @return the current key |
||||
* @throws IllegalStateException if <code>next()</code> has not yet been called |
||||
*/ |
||||
K getKey(); |
||||
|
||||
/** |
||||
* Gets the current value, which is the value associated with the last key |
||||
* returned by <code>next()</code>. |
||||
* |
||||
* @return the current value |
||||
* @throws IllegalStateException if <code>next()</code> has not yet been called |
||||
*/ |
||||
V getValue(); |
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/** |
||||
* Removes the last returned key from the underlying <code>Map</code> (optional operation). |
||||
* <p> |
||||
* This method can be called once per call to <code>next()</code>. |
||||
* |
||||
* @throws UnsupportedOperationException if remove is not supported by the map |
||||
* @throws IllegalStateException if <code>next()</code> has not yet been called |
||||
* @throws IllegalStateException if <code>remove()</code> has already been called |
||||
* since the last call to <code>next()</code> |
||||
*/ |
||||
void remove(); |
||||
|
||||
/** |
||||
* Sets the value associated with the current key (optional operation). |
||||
* |
||||
* @param value the new value |
||||
* @return the previous value |
||||
* @throws UnsupportedOperationException if setValue is not supported by the map |
||||
* @throws IllegalStateException if <code>next()</code> has not yet been called |
||||
* @throws IllegalStateException if <code>remove()</code> has been called since the |
||||
* last call to <code>next()</code> |
||||
*/ |
||||
V setValue(V value); |
||||
|
||||
} |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,158 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package com.fr.third.org.apache.commons.collections4; |
||||
|
||||
import java.util.Collection; |
||||
|
||||
/** |
||||
* Defines a map that holds a collection of values against each key. |
||||
* <p> |
||||
* A <code>MultiMap</code> is a Map with slightly different semantics. |
||||
* Putting a value into the map will add the value to a Collection at that key. |
||||
* Getting a value will return a Collection, holding all the values put to that key. |
||||
* <p> |
||||
* For example: |
||||
* <pre> |
||||
* MultiMap mhm = new MultiValueMap(); |
||||
* mhm.put(key, "A"); |
||||
* mhm.put(key, "B"); |
||||
* mhm.put(key, "C"); |
||||
* Collection coll = (Collection) mhm.get(key);</pre> |
||||
* <p> |
||||
* <code>coll</code> will be a collection containing "A", "B", "C". |
||||
* <p> |
||||
* NOTE: Additional methods were added to this interface in Commons Collections 3.1. |
||||
* These were added solely for documentation purposes and do not change the interface
|
||||
* as they were defined in the superinterface <code>Map</code> anyway. |
||||
* |
||||
* @since 2.0 |
||||
* @version $Id: MultiMap.java 1683018 2015-06-01 22:41:31Z tn $ |
||||
* @deprecated since 4.1, use {@link MultiValuedMap} instead |
||||
*/ |
||||
@Deprecated |
||||
public interface MultiMap<K, V> extends IterableMap<K, Object> { |
||||
|
||||
/** |
||||
* Removes a specific value from map. |
||||
* <p> |
||||
* The item is removed from the collection mapped to the specified key. |
||||
* Other values attached to that key are unaffected. |
||||
* <p> |
||||
* If the last value for a key is removed, implementations typically |
||||
* return <code>null</code> from a subsequent <code>get(Object)</code>, however |
||||
* they may choose to return an empty collection. |
||||
* |
||||
* @param key the key to remove from |
||||
* @param item the item to remove |
||||
* @return {@code true} if the mapping was removed, {@code false} otherwise |
||||
* @throws UnsupportedOperationException if the map is unmodifiable |
||||
* @throws ClassCastException if the key or value is of an invalid type |
||||
* @throws NullPointerException if the key or value is null and null is invalid |
||||
* @since 4.0 (signature in previous releases: V remove(K, V)) |
||||
*/ |
||||
boolean removeMapping(K key, V item); |
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/** |
||||
* Gets the number of keys in this map. |
||||
* <p> |
||||
* Implementations typically return only the count of keys in the map |
||||
* This cannot be mandated due to backwards compatibility of this interface. |
||||
* |
||||
* @return the number of key-collection mappings in this map |
||||
*/ |
||||
int size(); |
||||
|
||||
/** |
||||
* Gets the collection of values associated with the specified key. |
||||
* <p> |
||||
* The returned value will implement <code>Collection</code>. Implementations |
||||
* are free to declare that they return <code>Collection</code> subclasses |
||||
* such as <code>List</code> or <code>Set</code>. |
||||
* <p> |
||||
* Implementations typically return <code>null</code> if no values have |
||||
* been mapped to the key, however the implementation may choose to |
||||
* return an empty collection. |
||||
* <p> |
||||
* Implementations may choose to return a clone of the internal collection. |
||||
* |
||||
* @param key the key to retrieve |
||||
* @return the <code>Collection</code> of values, implementations should |
||||
* return <code>null</code> for no mapping, but may return an empty collection |
||||
* @throws ClassCastException if the key is of an invalid type |
||||
* @throws NullPointerException if the key is null and null keys are invalid |
||||
*/ |
||||
Object get(Object key); // Cannot use get(K key) as that does not properly implement Map#get
|
||||
|
||||
/** |
||||
* Checks whether the map contains the value specified. |
||||
* <p> |
||||
* Implementations typically check all collections against all keys for the value. |
||||
* This cannot be mandated due to backwards compatibility of this interface. |
||||
* |
||||
* @param value the value to search for |
||||
* @return true if the map contains the value |
||||
* @throws ClassCastException if the value is of an invalid type |
||||
* @throws NullPointerException if the value is null and null value are invalid |
||||
*/ |
||||
boolean containsValue(Object value); |
||||
|
||||
/** |
||||
* Adds the value to the collection associated with the specified key. |
||||
* <p> |
||||
* Unlike a normal <code>Map</code> the previous value is not replaced. |
||||
* Instead the new value is added to the collection stored against the key. |
||||
* The collection may be a <code>List</code>, <code>Set</code> or other |
||||
* collection dependent on implementation. |
||||
* |
||||
* @param key the key to store against |
||||
* @param value the value to add to the collection at the key |
||||
* @return typically the value added if the map changed and null if the map did not change |
||||
* @throws UnsupportedOperationException if the map is unmodifiable |
||||
* @throws ClassCastException if the key or value is of an invalid type |
||||
* @throws NullPointerException if the key or value is null and null is invalid |
||||
* @throws IllegalArgumentException if the key or value is invalid |
||||
*/ |
||||
Object put(K key, Object value); |
||||
|
||||
/** |
||||
* Removes all values associated with the specified key. |
||||
* <p> |
||||
* Implementations typically return <code>null</code> from a subsequent |
||||
* <code>get(Object)</code>, however they may choose to return an empty collection. |
||||
* |
||||
* @param key the key to remove values from |
||||
* @return the <code>Collection</code> of values removed, implementations should |
||||
* return <code>null</code> for no mapping found, but may return an empty collection |
||||
* @throws UnsupportedOperationException if the map is unmodifiable |
||||
* @throws ClassCastException if the key is of an invalid type |
||||
* @throws NullPointerException if the key is null and null keys are invalid |
||||
*/ |
||||
Object remove(Object key); // Cannot use remove(K key) as that does not properly implement Map#remove
|
||||
|
||||
/** |
||||
* Gets a collection containing all the values in the map. |
||||
* <p> |
||||
* Implementations typically return a collection containing the combination |
||||
* of values from all keys. |
||||
* This cannot be mandated due to backwards compatibility of this interface. |
||||
* |
||||
* @return a collection view of the values contained in this map |
||||
*/ |
||||
Collection<Object> values(); |
||||
|
||||
} |
@ -0,0 +1,259 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package com.fr.third.org.apache.commons.collections4; |
||||
|
||||
import java.util.ArrayList; |
||||
import java.util.Collection; |
||||
import java.util.HashSet; |
||||
import java.util.List; |
||||
import java.util.Set; |
||||
|
||||
import com.fr.third.org.apache.commons.collections4.bag.HashBag; |
||||
import com.fr.third.org.apache.commons.collections4.multimap.ArrayListValuedHashMap; |
||||
import com.fr.third.org.apache.commons.collections4.multimap.HashSetValuedHashMap; |
||||
import com.fr.third.org.apache.commons.collections4.multimap.TransformedMultiValuedMap; |
||||
import com.fr.third.org.apache.commons.collections4.multimap.UnmodifiableMultiValuedMap; |
||||
import com.fr.third.org.apache.commons.collections4.bag.HashBag; |
||||
import com.fr.third.org.apache.commons.collections4.multimap.ArrayListValuedHashMap; |
||||
import com.fr.third.org.apache.commons.collections4.multimap.HashSetValuedHashMap; |
||||
import com.fr.third.org.apache.commons.collections4.multimap.TransformedMultiValuedMap; |
||||
import com.fr.third.org.apache.commons.collections4.multimap.UnmodifiableMultiValuedMap; |
||||
|
||||
/** |
||||
* Provides utility methods and decorators for {@link MultiValuedMap} instances. |
||||
* <p> |
||||
* It contains various type safe and null safe methods. Additionally, it provides |
||||
* the following decorators: |
||||
* <ul> |
||||
* <li>{@link #unmodifiableMultiValuedMap(MultiValuedMap)}</li> |
||||
* <li>{@link #transformedMultiValuedMap(MultiValuedMap, Transformer, Transformer)}</li> |
||||
* </ul> |
||||
* |
||||
* @since 4.1 |
||||
* @version $Id: MultiMapUtils.java 1715302 2015-11-19 23:08:01Z tn $ |
||||
*/ |
||||
public class MultiMapUtils { |
||||
|
||||
/** |
||||
* <code>MultiMapUtils</code> should not normally be instantiated. |
||||
*/ |
||||
private MultiMapUtils() {} |
||||
|
||||
/** |
||||
* An empty {@link UnmodifiableMultiValuedMap}. |
||||
*/ |
||||
@SuppressWarnings({ "rawtypes", "unchecked" }) |
||||
public static final MultiValuedMap EMPTY_MULTI_VALUED_MAP = |
||||
UnmodifiableMultiValuedMap.unmodifiableMultiValuedMap(new ArrayListValuedHashMap(0, 0)); |
||||
|
||||
/** |
||||
* Returns immutable EMPTY_MULTI_VALUED_MAP with generic type safety. |
||||
* |
||||
* @param <K> the type of key in the map |
||||
* @param <V> the type of value in the map |
||||
* @return immutable and empty <code>MultiValuedMap</code> |
||||
*/ |
||||
@SuppressWarnings("unchecked") |
||||
public static <K, V> MultiValuedMap<K, V> emptyMultiValuedMap() { |
||||
return EMPTY_MULTI_VALUED_MAP; |
||||
} |
||||
|
||||
// Null safe methods
|
||||
|
||||
/** |
||||
* Returns an immutable empty <code>MultiValuedMap</code> if the argument is |
||||
* <code>null</code>, or the argument itself otherwise. |
||||
* |
||||
* @param <K> the type of key in the map |
||||
* @param <V> the type of value in the map |
||||
* @param map the map, may be null |
||||
* @return an empty {@link MultiValuedMap} if the argument is null |
||||
*/ |
||||
@SuppressWarnings("unchecked") |
||||
public static <K, V> MultiValuedMap<K, V> emptyIfNull(final MultiValuedMap<K, V> map) { |
||||
return map == null ? EMPTY_MULTI_VALUED_MAP : map; |
||||
} |
||||
|
||||
/** |
||||
* Null-safe check if the specified <code>MultiValuedMap</code> is empty. |
||||
* <p> |
||||
* If the provided map is null, returns true. |
||||
* |
||||
* @param map the map to check, may be null |
||||
* @return true if the map is empty or null |
||||
*/ |
||||
public static boolean isEmpty(final MultiValuedMap<?, ?> map) { |
||||
return map == null || map.isEmpty(); |
||||
} |
||||
|
||||
// Null safe getters
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/** |
||||
* Gets a Collection from <code>MultiValuedMap</code> in a null-safe manner. |
||||
* |
||||
* @param <K> the key type |
||||
* @param <V> the value type |
||||
* @param map the {@link MultiValuedMap} to use |
||||
* @param key the key to look up |
||||
* @return the Collection in the {@link MultiValuedMap}, or null if input map is null |
||||
*/ |
||||
public static <K, V> Collection<V> getCollection(final MultiValuedMap<K, V> map, final K key) { |
||||
if (map != null) { |
||||
return map.get(key); |
||||
} |
||||
return null; |
||||
} |
||||
|
||||
// TODO: review the getValuesAsXXX methods - depending on the actual MultiValuedMap type, changes
|
||||
// to the returned collection might update the backing map. This should be clarified and/or prevented.
|
||||
|
||||
/** |
||||
* Gets a List from <code>MultiValuedMap</code> in a null-safe manner. |
||||
* |
||||
* @param <K> the key type |
||||
* @param <V> the value type |
||||
* @param map the {@link MultiValuedMap} to use |
||||
* @param key the key to look up |
||||
* @return the Collection in the {@link MultiValuedMap} as List, or null if input map is null |
||||
*/ |
||||
public static <K, V> List<V> getValuesAsList(final MultiValuedMap<K, V> map, final K key) { |
||||
if (map != null) { |
||||
Collection<V> col = map.get(key); |
||||
if (col instanceof List) { |
||||
return (List<V>) col; |
||||
} |
||||
return new ArrayList<V>(col); |
||||
} |
||||
return null; |
||||
} |
||||
|
||||
/** |
||||
* Gets a Set from <code>MultiValuedMap</code> in a null-safe manner. |
||||
* |
||||
* @param <K> the key type |
||||
* @param <V> the value type |
||||
* @param map the {@link MultiValuedMap} to use |
||||
* @param key the key to look up |
||||
* @return the Collection in the {@link MultiValuedMap} as Set, or null if input map is null |
||||
*/ |
||||
public static <K, V> Set<V> getValuesAsSet(final MultiValuedMap<K, V> map, final K key) { |
||||
if (map != null) { |
||||
Collection<V> col = map.get(key); |
||||
if (col instanceof Set) { |
||||
return (Set<V>) col; |
||||
} |
||||
return new HashSet<V>(col); |
||||
} |
||||
return null; |
||||
} |
||||
|
||||
/** |
||||
* Gets a Bag from <code>MultiValuedMap</code> in a null-safe manner. |
||||
* |
||||
* @param <K> the key type |
||||
* @param <V> the value type |
||||
* @param map the {@link MultiValuedMap} to use |
||||
* @param key the key to look up |
||||
* @return the Collection in the {@link MultiValuedMap} as Bag, or null if input map is null |
||||
*/ |
||||
public static <K, V> Bag<V> getValuesAsBag(final MultiValuedMap<K, V> map, final K key) { |
||||
if (map != null) { |
||||
Collection<V> col = map.get(key); |
||||
if (col instanceof Bag) { |
||||
return (Bag<V>) col; |
||||
} |
||||
return new HashBag<V>(col); |
||||
} |
||||
return null; |
||||
} |
||||
|
||||
// Factory Methods
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
/** |
||||
* Creates a {@link ListValuedMap} with an {@link java.util.ArrayList ArrayList} as |
||||
* collection class to store the values mapped to a key. |
||||
* |
||||
* @param <K> the key type |
||||
* @param <V> the value type |
||||
* @return a new <code>ListValuedMap</code> |
||||
*/ |
||||
public static <K, V> ListValuedMap<K, V> newListValuedHashMap() { |
||||
return new ArrayListValuedHashMap<K, V>(); |
||||
} |
||||
|
||||
/** |
||||
* Creates a {@link SetValuedMap} with an {@link java.util.HashSet HashSet} as |
||||
* collection class to store the values mapped to a key. |
||||
* |
||||
* @param <K> the key type |
||||
* @param <V> the value type |
||||
* @return a new {@link SetValuedMap} |
||||
*/ |
||||
public static <K, V> SetValuedMap<K, V> newSetValuedHashMap() { |
||||
return new HashSetValuedHashMap<K, V>(); |
||||
} |
||||
|
||||
// MultiValuedMap Decorators
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
/** |
||||
* Returns an <code>UnmodifiableMultiValuedMap</code> backed by the given |
||||
* map. |
||||
* |
||||
* @param <K> the key type |
||||
* @param <V> the value type |
||||
* @param map the {@link MultiValuedMap} to decorate, must not be null |
||||
* @return an unmodifiable {@link MultiValuedMap} backed by the provided map |
||||
* @throws NullPointerException if map is null |
||||
*/ |
||||
public static <K, V> MultiValuedMap<K, V> unmodifiableMultiValuedMap( |
||||
final MultiValuedMap<? extends K, ? extends V> map) { |
||||
return UnmodifiableMultiValuedMap.<K, V>unmodifiableMultiValuedMap(map); |
||||
} |
||||
|
||||
/** |
||||
* Returns a <code>TransformedMultiValuedMap</code> backed by the given map. |
||||
* <p> |
||||
* This method returns a new <code>MultiValuedMap</code> (decorating the |
||||
* specified map) that will transform any new entries added to it. Existing |
||||
* entries in the specified map will not be transformed. If you want that |
||||
* behaviour, see {@link TransformedMultiValuedMap#transformedMap}. |
||||
* <p> |
||||
* Each object is passed through the transformers as it is added to the Map. |
||||
* It is important not to use the original map after invoking this method, |
||||
* as it is a back door for adding untransformed objects. |
||||
* <p> |
||||
* If there are any elements already in the map being decorated, they are |
||||
* NOT transformed. |
||||
* |
||||
* @param <K> the key type |
||||
* @param <V> the value type |
||||
* @param map the {@link MultiValuedMap} to transform, must not be null, typically empty |
||||
* @param keyTransformer the transformer for the map keys, null means no transformation |
||||
* @param valueTransformer the transformer for the map values, null means no transformation |
||||
* @return a transformed <code>MultiValuedMap</code> backed by the given map |
||||
* @throws NullPointerException if map is null |
||||
*/ |
||||
public static <K, V> MultiValuedMap<K, V> transformedMultiValuedMap(final MultiValuedMap<K, V> map, |
||||
final Transformer<? super K, ? extends K> keyTransformer, |
||||
final Transformer<? super V, ? extends V> valueTransformer) { |
||||
return TransformedMultiValuedMap.transformingMap(map, keyTransformer, valueTransformer); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,272 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package com.fr.third.org.apache.commons.collections4; |
||||
|
||||
import java.util.Collection; |
||||
import java.util.Iterator; |
||||
import java.util.Set; |
||||
|
||||
/** |
||||
* Defines a collection that counts the number of times an object appears in |
||||
* the collection. |
||||
* <p> |
||||
* Suppose you have a MultiSet that contains <code>{a, a, b, c}</code>. |
||||
* Calling {@link #getCount(Object)} on <code>a</code> would return 2, while |
||||
* calling {@link #uniqueSet()} would return <code>{a, b, c}</code>. |
||||
* |
||||
* @param <E> the type held in the multiset |
||||
* @since 4.1 |
||||
* @version $Id: MultiSet.java 1714424 2015-11-15 10:06:16Z tn $ |
||||
*/ |
||||
public interface MultiSet<E> extends Collection<E> { |
||||
|
||||
/** |
||||
* Returns the number of occurrences of the given object currently |
||||
* in the MultiSet. If the object does not exist in the multiset, |
||||
* return 0. |
||||
* |
||||
* @param object the object to search for |
||||
* @return the number of occurrences of the object, zero if not found |
||||
*/ |
||||
int getCount(Object object); |
||||
|
||||
/** |
||||
* Sets the number of occurrences of the specified object in the MultiSet |
||||
* to the given count. |
||||
* <p> |
||||
* If the provided count is zero, the object will be removed from the |
||||
* {@link #uniqueSet()}. |
||||
* |
||||
* @param object the object to update |
||||
* @param count the number of occurrences of the object |
||||
* @return the number of occurrences of the object before this operation, zero |
||||
* if the object was not contained in the multiset |
||||
* @throws IllegalArgumentException if count is negative |
||||
*/ |
||||
int setCount(E object, int count); |
||||
|
||||
/** |
||||
* Adds one copy of the specified object to the MultiSet. |
||||
* <p> |
||||
* If the object is already in the {@link #uniqueSet()} then increment its |
||||
* count as reported by {@link #getCount(Object)}. Otherwise add it to the |
||||
* {@link #uniqueSet()} and report its count as 1. |
||||
* |
||||
* @param object the object to add |
||||
* @return <code>true</code> always, as the size of the MultiSet is increased |
||||
* in any case |
||||
*/ |
||||
@Override |
||||
boolean add(E object); |
||||
|
||||
/** |
||||
* Adds a number of occurrences of the specified object to the MultiSet. |
||||
* <p> |
||||
* If the object is already in the {@link #uniqueSet()} then increment its |
||||
* count as reported by {@link #getCount(Object)}. Otherwise add it to the |
||||
* {@link #uniqueSet()} and report its count as <code>occurrences</code>. |
||||
* |
||||
* @param object the object to add |
||||
* @param occurrences the number of occurrences to add, may be zero, |
||||
* in which case no change is made to the multiset |
||||
* @return the number of occurrences of the object in the multiset before |
||||
* this operation; possibly zero |
||||
* @throws IllegalArgumentException if occurrences is negative |
||||
*/ |
||||
int add(E object, int occurrences); |
||||
|
||||
/** |
||||
* Removes one occurrence of the given object from the MultiSet. |
||||
* <p> |
||||
* If the number of occurrences after this operations is reduced |
||||
* to zero, the object will be removed from the {@link #uniqueSet()}. |
||||
* |
||||
* @param object the object to remove |
||||
* @return <code>true</code> if this call changed the collection |
||||
*/ |
||||
@Override |
||||
boolean remove(Object object); |
||||
|
||||
/** |
||||
* Removes a number of occurrences of the specified object from the MultiSet. |
||||
* <p> |
||||
* If the number of occurrences to remove is greater than the actual number of |
||||
* occurrences in the multiset, the object will be removed from the multiset. |
||||
* |
||||
* @param object the object to remove |
||||
* @param occurrences the number of occurrences to remove, may be zero, |
||||
* in which case no change is made to the multiset |
||||
* @return the number of occurrences of the object in the multiset |
||||
* before the operation; possibly zero |
||||
* @throws IllegalArgumentException if occurrences is negative |
||||
*/ |
||||
int remove(Object object, int occurrences); |
||||
|
||||
/** |
||||
* Returns a {@link Set} of unique elements in the MultiSet. |
||||
* <p> |
||||
* Uniqueness constraints are the same as those in {@link java.util.Set}. |
||||
* <p> |
||||
* The returned set is backed by this multiset, so any change to either |
||||
* is immediately reflected in the other. Only removal operations are |
||||
* supported, in which case all occurrences of the element are removed |
||||
* from the backing multiset. |
||||
* |
||||
* @return the Set of unique MultiSet elements |
||||
*/ |
||||
Set<E> uniqueSet(); |
||||
|
||||
/** |
||||
* Returns a {@link Set} of all entries contained in the MultiSet. |
||||
* <p> |
||||
* The returned set is backed by this multiset, so any change to either |
||||
* is immediately reflected in the other. |
||||
* |
||||
* @return the Set of MultiSet entries |
||||
*/ |
||||
Set<Entry<E>> entrySet(); |
||||
|
||||
/** |
||||
* Returns an {@link Iterator} over the entire set of members, |
||||
* including copies due to cardinality. This iterator is fail-fast |
||||
* and will not tolerate concurrent modifications. |
||||
* |
||||
* @return iterator over all elements in the MultiSet |
||||
*/ |
||||
@Override |
||||
Iterator<E> iterator(); |
||||
|
||||
/** |
||||
* Returns the total number of items in the MultiSet. |
||||
* |
||||
* @return the total size of the multiset |
||||
*/ |
||||
@Override |
||||
int size(); |
||||
|
||||
/** |
||||
* Returns <code>true</code> if the MultiSet contains at least one |
||||
* occurrence for each element contained in the given collection. |
||||
* |
||||
* @param coll the collection to check against |
||||
* @return <code>true</code> if the MultiSet contains all the collection |
||||
*/ |
||||
@Override |
||||
boolean containsAll(Collection<?> coll); |
||||
|
||||
/** |
||||
* Remove all occurrences of all elements from this MultiSet represented |
||||
* in the given collection. |
||||
* |
||||
* @param coll the collection of elements to remove |
||||
* @return <code>true</code> if this call changed the multiset |
||||
*/ |
||||
@Override |
||||
boolean removeAll(Collection<?> coll); |
||||
|
||||
/** |
||||
* Remove any elements of this MultiSet that are not contained in the |
||||
* given collection. |
||||
* |
||||
* @param coll the collection of elements to retain |
||||
* @return <code>true</code> if this call changed the multiset |
||||
*/ |
||||
@Override |
||||
boolean retainAll(Collection<?> coll); |
||||
|
||||
/** |
||||
* Compares this MultiSet to another object. |
||||
* <p> |
||||
* This MultiSet equals another object if it is also a MultiSet |
||||
* that contains the same number of occurrences of the same elements. |
||||
* |
||||
* @param obj the object to compare to |
||||
* @return true if equal |
||||
*/ |
||||
@Override |
||||
boolean equals(Object obj); |
||||
|
||||
/** |
||||
* Gets a hash code for the MultiSet compatible with the definition of equals. |
||||
* The hash code is defined as the sum total of a hash code for each element. |
||||
* The per element hash code is defined as |
||||
* <code>(e==null ? 0 : e.hashCode()) ^ noOccurances)</code>. |
||||
* |
||||
* @return the hash code of the MultiSet |
||||
*/ |
||||
@Override |
||||
int hashCode(); |
||||
|
||||
/** |
||||
* An unmodifiable entry for an element and its occurrence as contained in a MultiSet. |
||||
* <p> |
||||
* The {@link MultiSet#entrySet()} method returns a view of the multiset whose elements |
||||
* implements this interface. |
||||
* |
||||
* @param <E> the element type |
||||
*/ |
||||
interface Entry<E> { |
||||
|
||||
/** |
||||
* Returns the element corresponding to this entry. |
||||
* |
||||
* @return the element corresponding to this entry |
||||
*/ |
||||
E getElement(); |
||||
|
||||
/** |
||||
* Returns the number of occurrences for the element of this entry. |
||||
* |
||||
* @return the number of occurrences of the element |
||||
*/ |
||||
int getCount(); |
||||
|
||||
/** |
||||
* Compares the specified object with this entry for equality. |
||||
* Returns true if the given object is also a multiset entry |
||||
* and the two entries represent the same element with the same |
||||
* number of occurrences. |
||||
* <p> |
||||
* More formally, two entries <tt>e1</tt> and <tt>e2</tt> represent |
||||
* the same mapping if |
||||
* <pre> |
||||
* (e1.getElement()==null ? e2.getElement()==null |
||||
* : e1.getElement().equals(e2.getElement())) && |
||||
* (e1.getCount()==e2.getCount()) |
||||
* </pre> |
||||
* |
||||
* @param o object to be compared for equality with this multiset entry |
||||
* @return true if the specified object is equal to this multiset entry |
||||
*/ |
||||
@Override |
||||
boolean equals(Object o); |
||||
|
||||
/** |
||||
* Returns the hash code value for this multiset entry. |
||||
* <p> |
||||
* The hash code of a multiset entry <tt>e</tt> is defined to be: |
||||
* <pre> |
||||
* (e==null ? 0 : e.hashCode()) ^ noOccurances) |
||||
* </pre> |
||||
* |
||||
* @return the hash code value for this multiset entry |
||||
*/ |
||||
@Override |
||||
int hashCode(); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,123 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package com.fr.third.org.apache.commons.collections4; |
||||
|
||||
import com.fr.third.org.apache.commons.collections4.multiset.HashMultiSet; |
||||
import com.fr.third.org.apache.commons.collections4.multiset.PredicatedMultiSet; |
||||
import com.fr.third.org.apache.commons.collections4.multiset.SynchronizedMultiSet; |
||||
import com.fr.third.org.apache.commons.collections4.multiset.UnmodifiableMultiSet; |
||||
import com.fr.third.org.apache.commons.collections4.multiset.HashMultiSet; |
||||
import com.fr.third.org.apache.commons.collections4.multiset.PredicatedMultiSet; |
||||
import com.fr.third.org.apache.commons.collections4.multiset.SynchronizedMultiSet; |
||||
import com.fr.third.org.apache.commons.collections4.multiset.UnmodifiableMultiSet; |
||||
|
||||
/** |
||||
* Provides utility methods and decorators for {@link MultiSet} instances. |
||||
* |
||||
* @since 4.1 |
||||
* @version $Id: MultiSetUtils.java 1714424 2015-11-15 10:06:16Z tn $ |
||||
*/ |
||||
public class MultiSetUtils { |
||||
|
||||
/** |
||||
* An empty unmodifiable multiset. |
||||
*/ |
||||
@SuppressWarnings("rawtypes") // OK, empty multiset is compatible with any type
|
||||
public static final MultiSet EMPTY_MULTISET = |
||||
UnmodifiableMultiSet.unmodifiableMultiSet(new HashMultiSet<Object>()); |
||||
|
||||
/** |
||||
* Instantiation of MultiSetUtils is not intended or required. |
||||
*/ |
||||
private MultiSetUtils() {} |
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/** |
||||
* Returns a synchronized (thread-safe) multiset backed by the given multiset. |
||||
* In order to guarantee serial access, it is critical that all access to the |
||||
* backing multiset is accomplished through the returned multiset. |
||||
* <p> |
||||
* It is imperative that the user manually synchronize on the returned multiset |
||||
* when iterating over it: |
||||
* |
||||
* <pre> |
||||
* MultiSet multiset = MultiSetUtils.synchronizedMultiSet(new HashMultiSet()); |
||||
* ... |
||||
* synchronized(multiset) { |
||||
* Iterator i = multiset.iterator(); // Must be in synchronized block
|
||||
* while (i.hasNext()) |
||||
* foo(i.next()); |
||||
* } |
||||
* } |
||||
* </pre> |
||||
* |
||||
* Failure to follow this advice may result in non-deterministic behavior. |
||||
* |
||||
* @param <E> the element type |
||||
* @param multiset the multiset to synchronize, must not be null |
||||
* @return a synchronized multiset backed by that multiset |
||||
* @throws NullPointerException if the MultiSet is null |
||||
*/ |
||||
public static <E> MultiSet<E> synchronizedMultiSet(final MultiSet<E> multiset) { |
||||
return SynchronizedMultiSet.synchronizedMultiSet(multiset); |
||||
} |
||||
|
||||
/** |
||||
* Returns an unmodifiable view of the given multiset. Any modification attempts |
||||
* to the returned multiset will raise an {@link UnsupportedOperationException}. |
||||
* |
||||
* @param <E> the element type |
||||
* @param multiset the multiset whose unmodifiable view is to be returned, must not be null |
||||
* @return an unmodifiable view of that multiset |
||||
* @throws NullPointerException if the MultiSet is null |
||||
*/ |
||||
public static <E> MultiSet<E> unmodifiableMultiSet(final MultiSet<? extends E> multiset) { |
||||
return UnmodifiableMultiSet.unmodifiableMultiSet(multiset); |
||||
} |
||||
|
||||
/** |
||||
* Returns a predicated (validating) multiset backed by the given multiset. |
||||
* <p> |
||||
* Only objects that pass the test in the given predicate can be added to |
||||
* the multiset. Trying to add an invalid object results in an |
||||
* IllegalArgumentException. It is important not to use the original multiset |
||||
* after invoking this method, as it is a backdoor for adding invalid |
||||
* objects. |
||||
* |
||||
* @param <E> the element type |
||||
* @param multiset the multiset to predicate, must not be null |
||||
* @param predicate the predicate for the multiset, must not be null |
||||
* @return a predicated multiset backed by the given multiset |
||||
* @throws NullPointerException if the MultiSet or Predicate is null |
||||
*/ |
||||
public static <E> MultiSet<E> predicatedMultiSet(final MultiSet<E> multiset, |
||||
final Predicate<? super E> predicate) { |
||||
return PredicatedMultiSet.predicatedMultiSet(multiset, predicate); |
||||
} |
||||
|
||||
/** |
||||
* Get an empty <code>MultiSet</code>. |
||||
* |
||||
* @param <E> the element type |
||||
* @return an empty MultiSet |
||||
*/ |
||||
@SuppressWarnings("unchecked") // OK, empty multiset is compatible with any type
|
||||
public static <E> MultiSet<E> emptyMultiSet() { |
||||
return EMPTY_MULTISET; |
||||
} |
||||
|
||||
} |
@ -0,0 +1,320 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package com.fr.third.org.apache.commons.collections4; |
||||
|
||||
import java.util.Collection; |
||||
import java.util.Map; |
||||
import java.util.Map.Entry; |
||||
import java.util.Set; |
||||
|
||||
/** |
||||
* Defines a map that holds a collection of values against each key. |
||||
* <p> |
||||
* A {@code MultiValuedMap} is a Map with slightly different semantics: |
||||
* <ul> |
||||
* <li>Putting a value into the map will add the value to a {@link Collection} at that key.</li> |
||||
* <li>Getting a value will return a {@link Collection}, holding all the values put to that key.</li> |
||||
* </ul> |
||||
* <p> |
||||
* For example: |
||||
* <pre> |
||||
* MultiValuedMap<K, String> map = new MultiValuedHashMap<K, String>(); |
||||
* map.put(key, "A"); |
||||
* map.put(key, "B"); |
||||
* map.put(key, "C"); |
||||
* Collection<String> coll = map.get(key); |
||||
* </pre> |
||||
* <p> |
||||
* <code>coll</code> will be a collection containing "A", "B", "C". |
||||
* <p> |
||||
* |
||||
* @since 4.1 |
||||
* @version $Id: MultiValuedMap.java 1716537 2015-11-25 20:27:24Z tn $ |
||||
*/ |
||||
public interface MultiValuedMap<K, V> { |
||||
// Query operations
|
||||
|
||||
/** |
||||
* Gets the total size of the map. |
||||
* <p> |
||||
* Implementations would return the total size of the map which is the count |
||||
* of the values from all keys. |
||||
* |
||||
* @return the total size of the map |
||||
*/ |
||||
int size(); |
||||
|
||||
/** |
||||
* Returns {@code true} if this map contains no key-value mappings. |
||||
* |
||||
* @return {@code true} if this map contains no key-value mappings |
||||
*/ |
||||
boolean isEmpty(); |
||||
|
||||
/** |
||||
* Returns {@code true} if this map contains a mapping for the specified |
||||
* key. More formally, returns {@code true} if and only if this map contains |
||||
* a mapping for a key {@code k} such that {@code (key==null ? k==null : key.equals(k))}. |
||||
* (There can be at most one such mapping.) |
||||
* |
||||
* @param key key whose presence in this map is to be tested |
||||
* @return true if this map contains a mapping for the specified key |
||||
* @throws NullPointerException if the specified key is null and this map |
||||
* does not permit null keys (optional) |
||||
*/ |
||||
boolean containsKey(Object key); |
||||
|
||||
/** |
||||
* Checks whether the map contains at least one mapping for the specified value. |
||||
* |
||||
* @param value the value to search for |
||||
* @return true if the map contains the value |
||||
* @throws NullPointerException if the value is null and null values are not supported |
||||
* by the used collection types (optional) |
||||
*/ |
||||
boolean containsValue(Object value); |
||||
|
||||
/** |
||||
* Checks whether the map contains a mapping for the specified key and value. |
||||
* |
||||
* @param key the key to search for |
||||
* @param value the value to search for |
||||
* @return true if the map contains the value |
||||
*/ |
||||
boolean containsMapping(Object key, Object value); |
||||
|
||||
/** |
||||
* Returns a view collection of the values associated with the specified key. |
||||
* <p> |
||||
* This method will return an <b>empty</b> collection if {@link #containsKey(Object)} |
||||
* returns {@code false}. Changes to the returned collection will update the underlying |
||||
* {@code MultiValuedMap} and vice-versa. |
||||
* |
||||
* @param key the key to retrieve |
||||
* @return the {@code Collection} of values, implementations should |
||||
* return an empty collection for no mapping |
||||
* @throws NullPointerException if the key is null and null keys are invalid (optional) |
||||
*/ |
||||
Collection<V> get(K key); |
||||
|
||||
// Modification operations
|
||||
|
||||
/** |
||||
* Adds a key-value mapping to this multi-valued map. |
||||
* <p> |
||||
* Unlike a normal {@code Map} the previous value is not replaced. |
||||
* Instead the new value is added to the collection stored against the key. |
||||
* Depending on the collection type used, duplicate key-value mappings may |
||||
* be allowed. |
||||
* <p> |
||||
* The method will return {@code true} if the size of the multi-valued map |
||||
* has been increased because of this operation. |
||||
* |
||||
* @param key the key to store against |
||||
* @param value the value to add to the collection at the key |
||||
* @return true if the map changed as a result of this put operation, or false |
||||
* if the map already contained the key-value mapping and the collection |
||||
* type does not allow duplicate values, e.g. when using a Set |
||||
* @throws UnsupportedOperationException if the put operation is not supported by |
||||
* this multi-valued map, e.g. if it is unmodifiable |
||||
* @throws NullPointerException if the key or value is null and null is invalid (optional) |
||||
* @throws IllegalArgumentException if some aspect of the specified key or value prevents |
||||
* it from being stored in this multi-valued map |
||||
*/ |
||||
boolean put(K key, V value); |
||||
|
||||
/** |
||||
* Adds a mapping to the specified key for all values contained in the given Iterable. |
||||
* |
||||
* @param key the key to store against |
||||
* @param values the values to add to the collection at the key, may not be null |
||||
* @return true if the map changed as a result of this operation |
||||
* @throws NullPointerException if the specified iterable is null, or if this map |
||||
* does not permit null keys or values, and the specified key or values contain |
||||
* null (optional) |
||||
*/ |
||||
boolean putAll(K key, Iterable<? extends V> values); |
||||
|
||||
/** |
||||
* Copies all mappings from the specified map to this multi-valued map |
||||
* (optional operation). |
||||
* <p> |
||||
* The effect of this call is equivalent to that of calling |
||||
* {@link #put(Object,Object) put(k, v)} on this map once for each mapping |
||||
* from key {@code k} to value {@code v} in the specified map. |
||||
* <p> |
||||
* The behavior of this operation is undefined if the specified map is modified |
||||
* while the operation is in progress. |
||||
* |
||||
* @param map mappings to be stored in this map, may not be null |
||||
* @return true if the map changed as a result of this operation |
||||
* @throws UnsupportedOperationException if the {@code putAll} operation is |
||||
* not supported by this map |
||||
* @throws NullPointerException if the specified map is null, or if this map |
||||
* does not permit null keys or values, and the specified map |
||||
* contains null keys or values (optional) |
||||
* @throws IllegalArgumentException if some property of a key or value in |
||||
* the specified map prevents it from being stored in this map |
||||
*/ |
||||
boolean putAll(Map<? extends K, ? extends V> map); |
||||
|
||||
/** |
||||
* Copies all mappings from the specified map to this multi-valued map |
||||
* (optional operation). |
||||
* <p> |
||||
* The effect of this call is equivalent to that of calling |
||||
* {@link #put(Object,Object) put(k, v)} on this map once for each |
||||
* mapping from key {@code k} to value {@code v} in the specified map. |
||||
* <p> |
||||
* The behavior of this operation is undefined if the specified map is modified |
||||
* while the operation is in progress. |
||||
* |
||||
* @param map mappings to be stored in this map, may not be null |
||||
* @return true if the map changed as a result of this operation |
||||
* @throws UnsupportedOperationException if the {@code putAll} operation is |
||||
* not supported by this map |
||||
* @throws NullPointerException if the specified map is null, or if this map |
||||
* does not permit null keys or values, and the specified map |
||||
* contains null keys or values (optional) |
||||
* @throws IllegalArgumentException if some property of a key or value in |
||||
* the specified map prevents it from being stored in this map |
||||
*/ |
||||
boolean putAll(MultiValuedMap<? extends K, ? extends V> map); |
||||
|
||||
/** |
||||
* Removes all values associated with the specified key. |
||||
* <p> |
||||
* The returned collection <i>may</i> be modifiable, but updates will not be propagated |
||||
* to this multi-valued map. In case no mapping was stored for the specified |
||||
* key, an empty, unmodifiable collection will be returned. |
||||
* |
||||
* @param key the key to remove values from |
||||
* @return the values that were removed |
||||
* @throws UnsupportedOperationException if the map is unmodifiable |
||||
* @throws NullPointerException if the key is null and null keys are invalid (optional) |
||||
*/ |
||||
Collection<V> remove(Object key); |
||||
|
||||
/** |
||||
* Removes a key-value mapping from the map. |
||||
* <p> |
||||
* The item is removed from the collection mapped to the specified key. |
||||
* Other values attached to that key are unaffected. |
||||
* <p> |
||||
* If the last value for a key is removed, implementations typically return |
||||
* an empty collection from a subsequent <code>get(Object)</code>. |
||||
* |
||||
* @param key the key to remove from |
||||
* @param item the item to remove |
||||
* @return true if the mapping was removed, false otherwise |
||||
* @throws UnsupportedOperationException if the map is unmodifiable |
||||
* @throws NullPointerException if the key or value is null and null is invalid (optional) |
||||
*/ |
||||
boolean removeMapping(Object key, Object item); |
||||
|
||||
/** |
||||
* Removes all of the mappings from this map (optional operation). |
||||
* <p> |
||||
* The map will be empty after this call returns. |
||||
* |
||||
* @throws UnsupportedOperationException if the map is unmodifiable |
||||
*/ |
||||
void clear(); |
||||
|
||||
// Views
|
||||
|
||||
/** |
||||
* Returns a {@link Collection} view of the mappings contained in this multi-valued map. |
||||
* <p> |
||||
* The collection is backed by the map, so changes to the map are reflected |
||||
* in the collection, and vice-versa. |
||||
* |
||||
* @return a set view of the mappings contained in this map |
||||
*/ |
||||
Collection<Entry<K, V>> entries(); |
||||
|
||||
/** |
||||
* Returns a {@link MultiSet} view of the keys contained in this multi-valued map. |
||||
* <p> |
||||
* The {@link MultiSet#getCount(Object)} method of the returned multiset will give |
||||
* the same result a calling {@code get(Object).size()} for the same key. |
||||
* <p> |
||||
* This multiset is backed by the map, so any changes in the map are reflected in |
||||
* the multiset. |
||||
* |
||||
* @return a multiset view of the keys contained in this map |
||||
*/ |
||||
MultiSet<K> keys(); |
||||
|
||||
/** |
||||
* Returns a {@link Set} view of the keys contained in this multi-valued map. |
||||
* <p> |
||||
* The set is backed by the map, so changes to the map are reflected |
||||
* in the set, and vice-versa. |
||||
* <p> |
||||
* If the map is modified while an iteration over the set is in |
||||
* progress (except through the iterator's own {@code remove} operation), |
||||
* the result of the iteration is undefined. The set supports element |
||||
* removal, which removes the corresponding mapping from the map, via the |
||||
* {@code Iterator.remove}, {@code Set.remove}, {@code removeAll}, |
||||
* {@code retainAll}, and {@code clear} operations. It does not support |
||||
* the {@code add} or {@code addAll} operations. |
||||
* |
||||
* @return a set view of the keys contained in this map |
||||
*/ |
||||
Set<K> keySet(); |
||||
|
||||
/** |
||||
* Gets a {@link Collection} view of all values contained in this multi-valued map. |
||||
* <p> |
||||
* Implementations typically return a collection containing the combination |
||||
* of values from all keys. |
||||
* |
||||
* @return a collection view of the values contained in this multi-valued map |
||||
*/ |
||||
Collection<V> values(); |
||||
|
||||
/** |
||||
* Returns a view of this multi-valued map as a {@code Map} from each distinct |
||||
* key to the non-empty collection of that key's associated values. |
||||
* <p> |
||||
* Note that {@code this.asMap().get(k)} is equivalent to {@code this.get(k)} |
||||
* only when {@code k} is a key contained in the multi-valued map; otherwise it |
||||
* returns {@code null} as opposed to an empty collection. |
||||
* <p> |
||||
* Changes to the returned map or the collections that serve as its values |
||||
* will update the underlying multi-valued map, and vice versa. The map does |
||||
* not support {@code put} or {@code putAll}, nor do its entries support |
||||
* {@link Map.Entry#setValue setValue}. |
||||
* |
||||
* @return a map view of the mappings in this multi-valued map |
||||
*/ |
||||
Map<K, Collection<V>> asMap(); |
||||
|
||||
// Iterators
|
||||
|
||||
/** |
||||
* Obtains a <code>MapIterator</code> over this multi-valued map. |
||||
* <p> |
||||
* A map iterator is an efficient way of iterating over maps. There is no |
||||
* need to access the entries collection or use {@code Map.Entry} objects. |
||||
* |
||||
* @return a map iterator |
||||
*/ |
||||
MapIterator<K, V> mapIterator(); |
||||
|
||||
} |
@ -0,0 +1,51 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package com.fr.third.org.apache.commons.collections4; |
||||
|
||||
/** |
||||
* Defines a map that allows bidirectional lookup between key and values |
||||
* and retains and provides access to an ordering. |
||||
* <p> |
||||
* Implementations should allow a value to be looked up from a key and |
||||
* a key to be looked up from a value with equal performance. |
||||
* |
||||
* @param <K> the type of the keys in the map |
||||
* @param <V> the type of the values in the map |
||||
* |
||||
* @since 3.0 |
||||
* @version $Id: OrderedBidiMap.java 1543260 2013-11-19 00:47:22Z ggregory $ |
||||
*/ |
||||
public interface OrderedBidiMap<K, V> extends BidiMap<K, V>, OrderedMap<K, V> { |
||||
|
||||
/** |
||||
* Gets a view of this map where the keys and values are reversed. |
||||
* <p> |
||||
* Changes to one map will be visible in the other and vice versa. |
||||
* This enables both directions of the map to be accessed equally. |
||||
* <p> |
||||
* Implementations should seek to avoid creating a new object every time this |
||||
* method is called. See <code>AbstractMap.values()</code> etc. Calling this |
||||
* method on the inverse map should return the original. |
||||
* <p> |
||||
* Implementations must return an <code>OrderedBidiMap</code> instance, |
||||
* usually by forwarding to <code>inverseOrderedBidiMap()</code>. |
||||
* |
||||
* @return an inverted bidirectional map |
||||
*/ |
||||
OrderedBidiMap<V, K> inverseBidiMap(); |
||||
|
||||
} |
@ -0,0 +1,47 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package com.fr.third.org.apache.commons.collections4; |
||||
|
||||
import java.util.Iterator; |
||||
|
||||
/** |
||||
* Defines an iterator that operates over an ordered container. Subset of {@link java.util.ListIterator}. |
||||
* <p> |
||||
* This iterator allows both forward and reverse iteration through the container. |
||||
* |
||||
* @param <E> the type to iterate over |
||||
* @since 3.0 |
||||
* @version $Id: OrderedIterator.java 1469004 2013-04-17 17:37:03Z tn $ |
||||
*/ |
||||
public interface OrderedIterator<E> extends Iterator<E> { |
||||
|
||||
/** |
||||
* Checks to see if there is a previous element that can be iterated to. |
||||
* |
||||
* @return <code>true</code> if the iterator has a previous element |
||||
*/ |
||||
boolean hasPrevious(); |
||||
|
||||
/** |
||||
* Gets the previous element from the container. |
||||
* |
||||
* @return the previous element in the iteration |
||||
* @throws java.util.NoSuchElementException if the iteration is finished |
||||
*/ |
||||
E previous(); |
||||
|
||||
} |
@ -0,0 +1,73 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package com.fr.third.org.apache.commons.collections4; |
||||
|
||||
/** |
||||
* Defines a map that maintains order and allows both forward and backward |
||||
* iteration through that order. |
||||
* |
||||
* @param <K> the type of the keys in the map |
||||
* @param <V> the type of the values in the map |
||||
* |
||||
* @since 3.0 |
||||
* @version $Id: OrderedMap.java 1543259 2013-11-19 00:47:07Z ggregory $ |
||||
*/ |
||||
public interface OrderedMap<K, V> extends IterableMap<K, V> { |
||||
|
||||
/** |
||||
* Obtains an <code>OrderedMapIterator</code> over the map. |
||||
* <p> |
||||
* A ordered map iterator is an efficient way of iterating over maps |
||||
* in both directions. |
||||
* |
||||
* @return a map iterator |
||||
*/ |
||||
OrderedMapIterator<K, V> mapIterator(); |
||||
|
||||
/** |
||||
* Gets the first key currently in this map. |
||||
* |
||||
* @return the first key currently in this map |
||||
* @throws java.util.NoSuchElementException if this map is empty |
||||
*/ |
||||
K firstKey(); |
||||
|
||||
/** |
||||
* Gets the last key currently in this map. |
||||
* |
||||
* @return the last key currently in this map |
||||
* @throws java.util.NoSuchElementException if this map is empty |
||||
*/ |
||||
K lastKey(); |
||||
|
||||
/** |
||||
* Gets the next key after the one specified. |
||||
* |
||||
* @param key the key to search for next from |
||||
* @return the next key, null if no match or at end |
||||
*/ |
||||
K nextKey(K key); |
||||
|
||||
/** |
||||
* Gets the previous key before the one specified. |
||||
* |
||||
* @param key the key to search for previous from |
||||
* @return the previous key, null if no match or at start |
||||
*/ |
||||
K previousKey(K key); |
||||
|
||||
} |
@ -0,0 +1,46 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package com.fr.third.org.apache.commons.collections4; |
||||
|
||||
/** |
||||
* Defines an iterator that operates over an ordered <code>Map</code>. |
||||
* <p> |
||||
* This iterator allows both forward and reverse iteration through the map. |
||||
* |
||||
* @param <K> the type of the keys in the map |
||||
* @param <V> the type of the values in the map |
||||
* @since 3.0 |
||||
* @version $Id: OrderedMapIterator.java 1469004 2013-04-17 17:37:03Z tn $ |
||||
*/ |
||||
public interface OrderedMapIterator<K, V> extends MapIterator<K, V>, OrderedIterator<K> { |
||||
|
||||
/** |
||||
* Checks to see if there is a previous entry that can be iterated to. |
||||
* |
||||
* @return <code>true</code> if the iterator has a previous element |
||||
*/ |
||||
boolean hasPrevious(); |
||||
|
||||
/** |
||||
* Gets the previous <em>key</em> from the <code>Map</code>. |
||||
* |
||||
* @return the previous key in the iteration |
||||
* @throws java.util.NoSuchElementException if the iteration is finished |
||||
*/ |
||||
K previous(); |
||||
|
||||
} |
@ -0,0 +1,49 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package com.fr.third.org.apache.commons.collections4; |
||||
|
||||
/** |
||||
* Defines a functor interface implemented by classes that perform a predicate |
||||
* test on an object. |
||||
* <p> |
||||
* A <code>Predicate</code> is the object equivalent of an <code>if</code> statement. |
||||
* It uses the input object to return a true or false value, and is often used in |
||||
* validation or filtering. |
||||
* <p> |
||||
* Standard implementations of common predicates are provided by |
||||
* {@link PredicateUtils}. These include true, false, instanceof, equals, and, |
||||
* or, not, method invokation and null testing. |
||||
* |
||||
* @param <T> the type that the predicate queries |
||||
* |
||||
* @since 1.0 |
||||
* @version $Id: Predicate.java 1543262 2013-11-19 00:47:45Z ggregory $ |
||||
*/ |
||||
public interface Predicate<T> { |
||||
|
||||
/** |
||||
* Use the specified parameter to perform a test that returns true or false. |
||||
* |
||||
* @param object the object to evaluate, should not be changed |
||||
* @return true or false |
||||
* @throws ClassCastException (runtime) if the input is the wrong class
|
||||
* @throws IllegalArgumentException (runtime) if the input is invalid |
||||
* @throws FunctorException (runtime) if the predicate encounters a problem |
||||
*/ |
||||
boolean evaluate(T object); |
||||
|
||||
} |
@ -0,0 +1,562 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package com.fr.third.org.apache.commons.collections4; |
||||
|
||||
import java.util.Collection; |
||||
|
||||
import com.fr.third.org.apache.commons.collections4.functors.AllPredicate; |
||||
import com.fr.third.org.apache.commons.collections4.functors.AndPredicate; |
||||
import com.fr.third.org.apache.commons.collections4.functors.AnyPredicate; |
||||
import com.fr.third.org.apache.commons.collections4.functors.EqualPredicate; |
||||
import com.fr.third.org.apache.commons.collections4.functors.ExceptionPredicate; |
||||
import com.fr.third.org.apache.commons.collections4.functors.FalsePredicate; |
||||
import com.fr.third.org.apache.commons.collections4.functors.IdentityPredicate; |
||||
import com.fr.third.org.apache.commons.collections4.functors.InstanceofPredicate; |
||||
import com.fr.third.org.apache.commons.collections4.functors.InvokerTransformer; |
||||
import com.fr.third.org.apache.commons.collections4.functors.NonePredicate; |
||||
import com.fr.third.org.apache.commons.collections4.functors.NotNullPredicate; |
||||
import com.fr.third.org.apache.commons.collections4.functors.NotPredicate; |
||||
import com.fr.third.org.apache.commons.collections4.functors.NullIsExceptionPredicate; |
||||
import com.fr.third.org.apache.commons.collections4.functors.NullIsFalsePredicate; |
||||
import com.fr.third.org.apache.commons.collections4.functors.NullIsTruePredicate; |
||||
import com.fr.third.org.apache.commons.collections4.functors.NullPredicate; |
||||
import com.fr.third.org.apache.commons.collections4.functors.OnePredicate; |
||||
import com.fr.third.org.apache.commons.collections4.functors.OrPredicate; |
||||
import com.fr.third.org.apache.commons.collections4.functors.TransformedPredicate; |
||||
import com.fr.third.org.apache.commons.collections4.functors.TransformerPredicate; |
||||
import com.fr.third.org.apache.commons.collections4.functors.TruePredicate; |
||||
import com.fr.third.org.apache.commons.collections4.functors.UniquePredicate; |
||||
import com.fr.third.org.apache.commons.collections4.functors.AllPredicate; |
||||
import com.fr.third.org.apache.commons.collections4.functors.AndPredicate; |
||||
import com.fr.third.org.apache.commons.collections4.functors.AnyPredicate; |
||||
import com.fr.third.org.apache.commons.collections4.functors.EqualPredicate; |
||||
import com.fr.third.org.apache.commons.collections4.functors.ExceptionPredicate; |
||||
import com.fr.third.org.apache.commons.collections4.functors.FalsePredicate; |
||||
import com.fr.third.org.apache.commons.collections4.functors.IdentityPredicate; |
||||
import com.fr.third.org.apache.commons.collections4.functors.InstanceofPredicate; |
||||
import com.fr.third.org.apache.commons.collections4.functors.InvokerTransformer; |
||||
import com.fr.third.org.apache.commons.collections4.functors.NonePredicate; |
||||
import com.fr.third.org.apache.commons.collections4.functors.NotNullPredicate; |
||||
import com.fr.third.org.apache.commons.collections4.functors.NotPredicate; |
||||
import com.fr.third.org.apache.commons.collections4.functors.NullIsExceptionPredicate; |
||||
import com.fr.third.org.apache.commons.collections4.functors.NullIsFalsePredicate; |
||||
import com.fr.third.org.apache.commons.collections4.functors.NullIsTruePredicate; |
||||
import com.fr.third.org.apache.commons.collections4.functors.NullPredicate; |
||||
import com.fr.third.org.apache.commons.collections4.functors.OnePredicate; |
||||
import com.fr.third.org.apache.commons.collections4.functors.OrPredicate; |
||||
import com.fr.third.org.apache.commons.collections4.functors.TransformedPredicate; |
||||
import com.fr.third.org.apache.commons.collections4.functors.TransformerPredicate; |
||||
import com.fr.third.org.apache.commons.collections4.functors.TruePredicate; |
||||
import com.fr.third.org.apache.commons.collections4.functors.UniquePredicate; |
||||
|
||||
/** |
||||
* <code>PredicateUtils</code> provides reference implementations and utilities |
||||
* for the Predicate functor interface. The supplied predicates are: |
||||
* <ul> |
||||
* <li>Invoker - returns the result of a method call on the input object |
||||
* <li>InstanceOf - true if the object is an instanceof a class
|
||||
* <li>Equal - true if the object equals() a specified object |
||||
* <li>Identity - true if the object == a specified object |
||||
* <li>Null - true if the object is null |
||||
* <li>NotNull - true if the object is not null |
||||
* <li>Unique - true if the object has not already been evaluated |
||||
* <li>And/All - true if all of the predicates are true |
||||
* <li>Or/Any - true if any of the predicates is true |
||||
* <li>Either/One - true if only one of the predicate is true |
||||
* <li>Neither/None - true if none of the predicates are true |
||||
* <li>Not - true if the predicate is false, and vice versa |
||||
* <li>Transformer - wraps a Transformer as a Predicate |
||||
* <li>True - always return true |
||||
* <li>False - always return false |
||||
* <li>Exception - always throws an exception |
||||
* <li>NullIsException/NullIsFalse/NullIsTrue - check for null input |
||||
* <li>Transformed - transforms the input before calling the predicate |
||||
* </ul> |
||||
* All the supplied predicates are Serializable. |
||||
* |
||||
* @since 3.0 |
||||
* @version $Id: PredicateUtils.java 1686855 2015-06-22 13:00:27Z tn $ |
||||
*/ |
||||
public class PredicateUtils { |
||||
|
||||
/** |
||||
* This class is not normally instantiated. |
||||
*/ |
||||
private PredicateUtils() {} |
||||
|
||||
// Simple predicates
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
/** |
||||
* Gets a Predicate that always throws an exception. |
||||
* This could be useful during testing as a placeholder. |
||||
* |
||||
* @param <T> the type that the predicate queries |
||||
* @return the predicate |
||||
* @see ExceptionPredicate |
||||
*/ |
||||
public static <T> Predicate<T> exceptionPredicate() { |
||||
return ExceptionPredicate.exceptionPredicate(); |
||||
} |
||||
|
||||
/** |
||||
* Gets a Predicate that always returns true. |
||||
* |
||||
* @param <T> the type that the predicate queries |
||||
* @return the predicate |
||||
* @see TruePredicate |
||||
*/ |
||||
public static <T> Predicate<T> truePredicate() { |
||||
return TruePredicate.truePredicate(); |
||||
} |
||||
|
||||
/** |
||||
* Gets a Predicate that always returns false. |
||||
* |
||||
* @param <T> the type that the predicate queries |
||||
* @return the predicate |
||||
* @see FalsePredicate |
||||
*/ |
||||
public static <T> Predicate<T> falsePredicate() { |
||||
return FalsePredicate.falsePredicate(); |
||||
} |
||||
|
||||
/** |
||||
* Gets a Predicate that checks if the input object passed in is null. |
||||
* |
||||
* @param <T> the type that the predicate queries |
||||
* @return the predicate |
||||
* @see NullPredicate |
||||
*/ |
||||
public static <T> Predicate<T> nullPredicate() { |
||||
return NullPredicate.nullPredicate(); |
||||
} |
||||
|
||||
/** |
||||
* Gets a Predicate that checks if the input object passed in is not null. |
||||
* |
||||
* @param <T> the type that the predicate queries |
||||
* @return the predicate |
||||
* @see NotNullPredicate |
||||
*/ |
||||
public static <T> Predicate<T> notNullPredicate() { |
||||
return NotNullPredicate.notNullPredicate(); |
||||
} |
||||
|
||||
/** |
||||
* Creates a Predicate that checks if the input object is equal to the |
||||
* specified object using equals(). |
||||
* |
||||
* @param <T> the type that the predicate queries |
||||
* @param value the value to compare against |
||||
* @return the predicate |
||||
* @see EqualPredicate |
||||
*/ |
||||
public static <T> Predicate<T> equalPredicate(final T value) { |
||||
return EqualPredicate.equalPredicate(value); |
||||
} |
||||
|
||||
/** |
||||
* Creates a Predicate that checks if the input object is equal to the |
||||
* specified object by identity. |
||||
* |
||||
* @param <T> the type that the predicate queries |
||||
* @param value the value to compare against |
||||
* @return the predicate |
||||
* @see IdentityPredicate |
||||
*/ |
||||
public static <T> Predicate<T> identityPredicate(final T value) { |
||||
return IdentityPredicate.identityPredicate(value); |
||||
} |
||||
|
||||
/** |
||||
* Creates a Predicate that checks if the object passed in is of |
||||
* a particular type, using instanceof. A <code>null</code> input |
||||
* object will return <code>false</code>. |
||||
* |
||||
* @param type the type to check for, may not be null |
||||
* @return the predicate |
||||
* @throws NullPointerException if the class is null |
||||
* @see InstanceofPredicate |
||||
*/ |
||||
public static Predicate<Object> instanceofPredicate(final Class<?> type) { |
||||
return InstanceofPredicate.instanceOfPredicate(type); |
||||
} |
||||
|
||||
/** |
||||
* Creates a Predicate that returns true the first time an object is |
||||
* encountered, and false if the same object is received |
||||
* again. The comparison is by equals(). A <code>null</code> input object |
||||
* is accepted and will return true the first time, and false subsequently |
||||
* as well. |
||||
* |
||||
* @param <T> the type that the predicate queries |
||||
* @return the predicate |
||||
* @see UniquePredicate |
||||
*/ |
||||
public static <T> Predicate<T> uniquePredicate() { |
||||
// must return new instance each time
|
||||
return UniquePredicate.uniquePredicate(); |
||||
} |
||||
|
||||
/** |
||||
* Creates a Predicate that invokes a method on the input object. |
||||
* The method must return either a boolean or a non-null Boolean, |
||||
* and have no parameters. If the input object is null, a |
||||
* PredicateException is thrown. |
||||
* <p> |
||||
* For example, <code>PredicateUtils.invokerPredicate("isEmpty");</code> |
||||
* will call the <code>isEmpty</code> method on the input object to |
||||
* determine the predicate result. |
||||
* |
||||
* @param <T> the type that the predicate queries |
||||
* @param methodName the method name to call on the input object, may not be null |
||||
* @return the predicate |
||||
* @throws NullPointerException if the methodName is null. |
||||
* @see InvokerTransformer |
||||
* @see TransformerPredicate |
||||
*/ |
||||
public static <T> Predicate<T> invokerPredicate(final String methodName) { |
||||
// reuse transformer as it has caching - this is lazy really, should have inner class here
|
||||
return asPredicate(InvokerTransformer.<Object, Boolean>invokerTransformer(methodName)); |
||||
} |
||||
|
||||
/** |
||||
* Creates a Predicate that invokes a method on the input object. |
||||
* The method must return either a boolean or a non-null Boolean, |
||||
* and have no parameters. If the input object is null, a |
||||
* PredicateException is thrown. |
||||
* <p> |
||||
* For example, <code>PredicateUtils.invokerPredicate("isEmpty");</code> |
||||
* will call the <code>isEmpty</code> method on the input object to |
||||
* determine the predicate result. |
||||
* |
||||
* @param <T> the type that the predicate queries |
||||
* @param methodName the method name to call on the input object, may not be null |
||||
* @param paramTypes the parameter types |
||||
* @param args the arguments |
||||
* @return the predicate |
||||
* @throws NullPointerException if the method name is null |
||||
* @throws IllegalArgumentException if the paramTypes and args don't match |
||||
* @see InvokerTransformer |
||||
* @see TransformerPredicate |
||||
*/ |
||||
public static <T> Predicate<T> invokerPredicate(final String methodName, final Class<?>[] paramTypes, |
||||
final Object[] args) { |
||||
// reuse transformer as it has caching - this is lazy really, should have inner class here
|
||||
return asPredicate(InvokerTransformer.<Object, Boolean>invokerTransformer(methodName, paramTypes, args)); |
||||
} |
||||
|
||||
// Boolean combinations
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
/** |
||||
* Create a new Predicate that returns true only if both of the specified |
||||
* predicates are true. |
||||
* |
||||
* @param <T> the type that the predicate queries |
||||
* @param predicate1 the first predicate, may not be null |
||||
* @param predicate2 the second predicate, may not be null |
||||
* @return the <code>and</code> predicate |
||||
* @throws NullPointerException if either predicate is null |
||||
* @see AndPredicate |
||||
*/ |
||||
public static <T> Predicate<T> andPredicate(final Predicate<? super T> predicate1, |
||||
final Predicate<? super T> predicate2) { |
||||
return AndPredicate.andPredicate(predicate1, predicate2); |
||||
} |
||||
|
||||
/** |
||||
* Create a new Predicate that returns true only if all of the specified |
||||
* predicates are true. |
||||
* If the array of predicates is empty, then this predicate returns true. |
||||
* |
||||
* @param <T> the type that the predicate queries |
||||
* @param predicates an array of predicates to check, may not be null |
||||
* @return the <code>all</code> predicate |
||||
* @throws NullPointerException if the predicates array is null |
||||
* @throws NullPointerException if any predicate in the array is null |
||||
* @see AllPredicate |
||||
*/ |
||||
public static <T> Predicate<T> allPredicate(final Predicate<? super T>... predicates) { |
||||
return AllPredicate.allPredicate(predicates); |
||||
} |
||||
|
||||
/** |
||||
* Create a new Predicate that returns true only if all of the specified |
||||
* predicates are true. The predicates are checked in iterator order. |
||||
* If the collection of predicates is empty, then this predicate returns true. |
||||
* |
||||
* @param <T> the type that the predicate queries |
||||
* @param predicates a collection of predicates to check, may not be null |
||||
* @return the <code>all</code> predicate |
||||
* @throws NullPointerException if the predicates collection is null |
||||
* @throws NullPointerException if any predicate in the collection is null |
||||
* @see AllPredicate |
||||
*/ |
||||
public static <T> Predicate<T> allPredicate(final Collection<? extends Predicate<? super T>> predicates) { |
||||
return AllPredicate.allPredicate(predicates); |
||||
} |
||||
|
||||
/** |
||||
* Create a new Predicate that returns true if either of the specified |
||||
* predicates are true. |
||||
* |
||||
* @param <T> the type that the predicate queries |
||||
* @param predicate1 the first predicate, may not be null |
||||
* @param predicate2 the second predicate, may not be null |
||||
* @return the <code>or</code> predicate |
||||
* @throws NullPointerException if either predicate is null |
||||
* @see OrPredicate |
||||
*/ |
||||
public static <T> Predicate<T> orPredicate(final Predicate<? super T> predicate1, |
||||
final Predicate<? super T> predicate2) { |
||||
return OrPredicate.orPredicate(predicate1, predicate2); |
||||
} |
||||
|
||||
/** |
||||
* Create a new Predicate that returns true if any of the specified |
||||
* predicates are true. |
||||
* If the array of predicates is empty, then this predicate returns false. |
||||
* |
||||
* @param <T> the type that the predicate queries |
||||
* @param predicates an array of predicates to check, may not be null |
||||
* @return the <code>any</code> predicate |
||||
* @throws NullPointerException if the predicates array is null |
||||
* @throws NullPointerException if any predicate in the array is null |
||||
* @see AnyPredicate |
||||
*/ |
||||
public static <T> Predicate<T> anyPredicate(final Predicate<? super T>... predicates) { |
||||
return AnyPredicate.anyPredicate(predicates); |
||||
} |
||||
|
||||
/** |
||||
* Create a new Predicate that returns true if any of the specified |
||||
* predicates are true. The predicates are checked in iterator order. |
||||
* If the collection of predicates is empty, then this predicate returns false. |
||||
* |
||||
* @param <T> the type that the predicate queries |
||||
* @param predicates a collection of predicates to check, may not be null |
||||
* @return the <code>any</code> predicate |
||||
* @throws NullPointerException if the predicates collection is null |
||||
* @throws NullPointerException if any predicate in the collection is null |
||||
* @see AnyPredicate |
||||
*/ |
||||
public static <T> Predicate<T> anyPredicate(final Collection<? extends Predicate<? super T>> predicates) { |
||||
return AnyPredicate.anyPredicate(predicates); |
||||
} |
||||
|
||||
/** |
||||
* Create a new Predicate that returns true if one, but not both, of the |
||||
* specified predicates are true. XOR |
||||
* |
||||
* @param <T> the type that the predicate queries |
||||
* @param predicate1 the first predicate, may not be null |
||||
* @param predicate2 the second predicate, may not be null |
||||
* @return the <code>either</code> predicate |
||||
* @throws NullPointerException if either predicate is null |
||||
* @see OnePredicate |
||||
*/ |
||||
public static <T> Predicate<T> eitherPredicate(final Predicate<? super T> predicate1, |
||||
final Predicate<? super T> predicate2) { |
||||
@SuppressWarnings("unchecked") |
||||
final Predicate<T> onePredicate = PredicateUtils.onePredicate(predicate1, predicate2); |
||||
return onePredicate; |
||||
} |
||||
|
||||
/** |
||||
* Create a new Predicate that returns true if only one of the specified |
||||
* predicates are true. |
||||
* If the array of predicates is empty, then this predicate returns false. |
||||
* |
||||
* @param <T> the type that the predicate queries |
||||
* @param predicates an array of predicates to check, may not be null |
||||
* @return the <code>one</code> predicate |
||||
* @throws NullPointerException if the predicates array is null |
||||
* @throws NullPointerException if any predicate in the array is null |
||||
* @see OnePredicate |
||||
*/ |
||||
public static <T> Predicate<T> onePredicate(final Predicate<? super T>... predicates) { |
||||
return OnePredicate.onePredicate(predicates); |
||||
} |
||||
|
||||
/** |
||||
* Create a new Predicate that returns true if only one of the specified |
||||
* predicates are true. The predicates are checked in iterator order. |
||||
* If the collection of predicates is empty, then this predicate returns false. |
||||
* |
||||
* @param <T> the type that the predicate queries |
||||
* @param predicates a collection of predicates to check, may not be null |
||||
* @return the <code>one</code> predicate |
||||
* @throws NullPointerException if the predicates collection is null |
||||
* @throws NullPointerException if any predicate in the collection is null |
||||
* @see OnePredicate |
||||
*/ |
||||
public static <T> Predicate<T> onePredicate(final Collection<? extends Predicate<? super T>> predicates) { |
||||
return OnePredicate.onePredicate(predicates); |
||||
} |
||||
|
||||
/** |
||||
* Create a new Predicate that returns true if neither of the specified |
||||
* predicates are true. |
||||
* |
||||
* @param <T> the type that the predicate queries |
||||
* @param predicate1 the first predicate, may not be null |
||||
* @param predicate2 the second predicate, may not be null |
||||
* @return the <code>neither</code> predicate |
||||
* @throws NullPointerException if either predicate is null |
||||
* @see NonePredicate |
||||
*/ |
||||
public static <T> Predicate<T> neitherPredicate(final Predicate<? super T> predicate1, |
||||
final Predicate<? super T> predicate2) { |
||||
@SuppressWarnings("unchecked") |
||||
final Predicate<T> nonePredicate = PredicateUtils.nonePredicate(predicate1, predicate2); |
||||
return nonePredicate; |
||||
} |
||||
|
||||
/** |
||||
* Create a new Predicate that returns true if none of the specified |
||||
* predicates are true. |
||||
* If the array of predicates is empty, then this predicate returns true. |
||||
* |
||||
* @param <T> the type that the predicate queries |
||||
* @param predicates an array of predicates to check, may not be null |
||||
* @return the <code>none</code> predicate |
||||
* @throws NullPointerException if the predicates array is null |
||||
* @throws NullPointerException if any predicate in the array is null |
||||
* @see NonePredicate |
||||
*/ |
||||
public static <T> Predicate<T> nonePredicate(final Predicate<? super T>... predicates) { |
||||
return NonePredicate.nonePredicate(predicates); |
||||
} |
||||
|
||||
/** |
||||
* Create a new Predicate that returns true if none of the specified |
||||
* predicates are true. The predicates are checked in iterator order. |
||||
* If the collection of predicates is empty, then this predicate returns true. |
||||
* |
||||
* @param <T> the type that the predicate queries |
||||
* @param predicates a collection of predicates to check, may not be null |
||||
* @return the <code>none</code> predicate |
||||
* @throws NullPointerException if the predicates collection is null |
||||
* @throws NullPointerException if any predicate in the collection is null |
||||
* @see NonePredicate |
||||
*/ |
||||
public static <T> Predicate<T> nonePredicate(final Collection<? extends Predicate<? super T>> predicates) { |
||||
return NonePredicate.nonePredicate(predicates); |
||||
} |
||||
|
||||
/** |
||||
* Create a new Predicate that returns true if the specified predicate |
||||
* returns false and vice versa. |
||||
* |
||||
* @param <T> the type that the predicate queries |
||||
* @param predicate the predicate to not |
||||
* @return the <code>not</code> predicate |
||||
* @throws NullPointerException if the predicate is null |
||||
* @see NotPredicate |
||||
*/ |
||||
public static <T> Predicate<T> notPredicate(final Predicate<? super T> predicate) { |
||||
return NotPredicate.notPredicate(predicate); |
||||
} |
||||
|
||||
// Adaptors
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
/** |
||||
* Create a new Predicate that wraps a Transformer. The Transformer must |
||||
* return either Boolean.TRUE or Boolean.FALSE otherwise a PredicateException |
||||
* will be thrown. |
||||
* |
||||
* @param <T> the type that the predicate queries |
||||
* @param transformer the transformer to wrap, may not be null |
||||
* @return the transformer wrapping predicate |
||||
* @throws NullPointerException if the transformer is null |
||||
* @see TransformerPredicate |
||||
*/ |
||||
public static <T> Predicate<T> asPredicate(final Transformer<? super T, Boolean> transformer) { |
||||
return TransformerPredicate.transformerPredicate(transformer); |
||||
} |
||||
|
||||
// Null handlers
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
/** |
||||
* Gets a Predicate that throws an exception if the input object is null, |
||||
* otherwise it calls the specified Predicate. This allows null handling |
||||
* behaviour to be added to Predicates that don't support nulls. |
||||
* |
||||
* @param <T> the type that the predicate queries |
||||
* @param predicate the predicate to wrap, may not be null |
||||
* @return the predicate |
||||
* @throws NullPointerException if the predicate is null. |
||||
* @see NullIsExceptionPredicate |
||||
*/ |
||||
public static <T> Predicate<T> nullIsExceptionPredicate(final Predicate<? super T> predicate){ |
||||
return NullIsExceptionPredicate.nullIsExceptionPredicate(predicate); |
||||
} |
||||
|
||||
/** |
||||
* Gets a Predicate that returns false if the input object is null, otherwise |
||||
* it calls the specified Predicate. This allows null handling behaviour to |
||||
* be added to Predicates that don't support nulls. |
||||
* |
||||
* @param <T> the type that the predicate queries |
||||
* @param predicate the predicate to wrap, may not be null |
||||
* @return the predicate |
||||
* @throws NullPointerException if the predicate is null. |
||||
* @see NullIsFalsePredicate |
||||
*/ |
||||
public static <T> Predicate<T> nullIsFalsePredicate(final Predicate<? super T> predicate){ |
||||
return NullIsFalsePredicate.nullIsFalsePredicate(predicate); |
||||
} |
||||
|
||||
/** |
||||
* Gets a Predicate that returns true if the input object is null, otherwise |
||||
* it calls the specified Predicate. This allows null handling behaviour to |
||||
* be added to Predicates that don't support nulls. |
||||
* |
||||
* @param <T> the type that the predicate queries |
||||
* @param predicate the predicate to wrap, may not be null |
||||
* @return the predicate |
||||
* @throws NullPointerException if the predicate is null. |
||||
* @see NullIsTruePredicate |
||||
*/ |
||||
public static <T> Predicate<T> nullIsTruePredicate(final Predicate<? super T> predicate){ |
||||
return NullIsTruePredicate.nullIsTruePredicate(predicate); |
||||
} |
||||
|
||||
// Transformed
|
||||
//-----------------------------------------------------------------------
|
||||
/** |
||||
* Creates a predicate that transforms the input object before passing it |
||||
* to the predicate. |
||||
* |
||||
* @param <T> the type that the predicate queries |
||||
* @param transformer the transformer to call first |
||||
* @param predicate the predicate to call with the result of the transform |
||||
* @return the predicate |
||||
* @throws NullPointerException if the transformer or the predicate is null |
||||
* @see TransformedPredicate |
||||
* @since 3.1 |
||||
*/ |
||||
public static <T> Predicate<T> transformedPredicate( |
||||
final Transformer<? super T, ? extends T> transformer, final Predicate<? super T> predicate) { |
||||
return TransformedPredicate.transformedPredicate(transformer, predicate); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,55 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package com.fr.third.org.apache.commons.collections4; |
||||
|
||||
import java.util.Map; |
||||
|
||||
/** |
||||
* The "write" subset of the {@link Map} interface. |
||||
* <p> |
||||
* NOTE: in the original {@link Map} interface, {@link Map#put(Object, Object)} is known |
||||
* to have the same return type as {@link Map#get(Object)}, namely {@code V}. {@link Put} |
||||
* makes no assumptions in this regard (there is no association with, nor even knowledge |
||||
* of, a "reading" interface) and thus defines {@link #put(Object, Object)} as returning |
||||
* {@link Object}. |
||||
* |
||||
* @since 4.0 |
||||
* @version $Id: Put.java 1543257 2013-11-19 00:45:55Z ggregory $ |
||||
* |
||||
* @see Get |
||||
*/ |
||||
public interface Put<K, V> { |
||||
|
||||
/** |
||||
* @see Map#clear() |
||||
*/ |
||||
void clear(); |
||||
|
||||
/** |
||||
* Note that the return type is Object, rather than V as in the Map interface. |
||||
* See the class Javadoc for further info. |
||||
* |
||||
* @see Map#put(Object, Object) |
||||
*/ |
||||
Object put(K key, V value); |
||||
|
||||
/** |
||||
* @see Map#putAll(Map) |
||||
*/ |
||||
void putAll(Map<? extends K, ? extends V> t); |
||||
|
||||
} |
@ -0,0 +1,111 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package com.fr.third.org.apache.commons.collections4; |
||||
|
||||
import java.util.LinkedList; |
||||
import java.util.Queue; |
||||
|
||||
import com.fr.third.org.apache.commons.collections4.queue.PredicatedQueue; |
||||
import com.fr.third.org.apache.commons.collections4.queue.TransformedQueue; |
||||
import com.fr.third.org.apache.commons.collections4.queue.UnmodifiableQueue; |
||||
import com.fr.third.org.apache.commons.collections4.queue.PredicatedQueue; |
||||
import com.fr.third.org.apache.commons.collections4.queue.TransformedQueue; |
||||
import com.fr.third.org.apache.commons.collections4.queue.UnmodifiableQueue; |
||||
|
||||
/** |
||||
* Provides utility methods and decorators for {@link Queue} instances. |
||||
* |
||||
* @since 4.0 |
||||
* @version $Id: QueueUtils.java 1686855 2015-06-22 13:00:27Z tn $ |
||||
*/ |
||||
public class QueueUtils { |
||||
|
||||
/** |
||||
* An empty unmodifiable queue. |
||||
*/ |
||||
@SuppressWarnings("rawtypes") // OK, empty queue is compatible with any type
|
||||
public static final Queue EMPTY_QUEUE = UnmodifiableQueue.unmodifiableQueue(new LinkedList<Object>()); |
||||
|
||||
/** |
||||
* <code>QueueUtils</code> should not normally be instantiated. |
||||
*/ |
||||
private QueueUtils() {} |
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
/** |
||||
* Returns an unmodifiable queue backed by the given queue. |
||||
* |
||||
* @param <E> the type of the elements in the queue |
||||
* @param queue the queue to make unmodifiable, must not be null |
||||
* @return an unmodifiable queue backed by that queue |
||||
* @throws NullPointerException if the queue is null |
||||
*/ |
||||
public static <E> Queue<E> unmodifiableQueue(final Queue<? extends E> queue) { |
||||
return UnmodifiableQueue.unmodifiableQueue(queue); |
||||
} |
||||
|
||||
/** |
||||
* Returns a predicated (validating) queue backed by the given queue. |
||||
* <p> |
||||
* Only objects that pass the test in the given predicate can be added to the queue. |
||||
* Trying to add an invalid object results in an IllegalArgumentException. |
||||
* It is important not to use the original queue after invoking this method, |
||||
* as it is a backdoor for adding invalid objects. |
||||
* |
||||
* @param <E> the type of the elements in the queue |
||||
* @param queue the queue to predicate, must not be null |
||||
* @param predicate the predicate used to evaluate new elements, must not be null |
||||
* @return a predicated queue |
||||
* @throws NullPointerException if the queue or predicate is null |
||||
*/ |
||||
public static <E> Queue<E> predicatedQueue(final Queue<E> queue, final Predicate<? super E> predicate) { |
||||
return PredicatedQueue.predicatedQueue(queue, predicate); |
||||
} |
||||
|
||||
/** |
||||
* Returns a transformed queue backed by the given queue. |
||||
* <p> |
||||
* Each object is passed through the transformer as it is added to the |
||||
* Queue. It is important not to use the original queue after invoking this |
||||
* method, as it is a backdoor for adding untransformed objects. |
||||
* <p> |
||||
* Existing entries in the specified queue will not be transformed. |
||||
* If you want that behaviour, see {@link TransformedQueue#transformedQueue}. |
||||
* |
||||
* @param <E> the type of the elements in the queue |
||||
* @param queue the queue to predicate, must not be null |
||||
* @param transformer the transformer for the queue, must not be null |
||||
* @return a transformed queue backed by the given queue |
||||
* @throws NullPointerException if the queue or transformer is null |
||||
*/ |
||||
public static <E> Queue<E> transformingQueue(final Queue<E> queue, |
||||
final Transformer<? super E, ? extends E> transformer) { |
||||
return TransformedQueue.transformingQueue(queue, transformer); |
||||
} |
||||
|
||||
/** |
||||
* Get an empty <code>Queue</code>. |
||||
* |
||||
* @param <E> the type of the elements in the queue |
||||
* @return an empty {@link Queue} |
||||
*/ |
||||
@SuppressWarnings("unchecked") // OK, empty queue is compatible with any type
|
||||
public static <E> Queue<E> emptyQueue() { |
||||
return (Queue<E>) EMPTY_QUEUE; |
||||
} |
||||
} |
@ -0,0 +1,38 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package com.fr.third.org.apache.commons.collections4; |
||||
|
||||
import java.util.Iterator; |
||||
|
||||
/** |
||||
* Defines an iterator that can be reset back to an initial state. |
||||
* <p> |
||||
* This interface allows an iterator to be repeatedly reused. |
||||
* |
||||
* @param <E> the type to iterate over |
||||
* @since 3.0 |
||||
* @version $Id: ResettableIterator.java 1543263 2013-11-19 00:47:55Z ggregory $ |
||||
*/ |
||||
public interface ResettableIterator<E> extends Iterator<E> { |
||||
|
||||
/** |
||||
* Resets the iterator back to the position at which the iterator |
||||
* was created. |
||||
*/ |
||||
void reset(); |
||||
|
||||
} |
@ -0,0 +1,32 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package com.fr.third.org.apache.commons.collections4; |
||||
|
||||
import java.util.ListIterator; |
||||
|
||||
/** |
||||
* Defines a list iterator that can be reset back to an initial state. |
||||
* <p> |
||||
* This interface allows an iterator to be repeatedly reused. |
||||
* |
||||
* @param <E> the type to iterate over |
||||
* @since 3.0 |
||||
* @version $Id: ResettableListIterator.java 1477779 2013-04-30 18:55:24Z tn $ |
||||
*/ |
||||
public interface ResettableListIterator<E> extends ListIterator<E>, ResettableIterator<E>, OrderedIterator<E> { |
||||
|
||||
} |
@ -0,0 +1,655 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package com.fr.third.org.apache.commons.collections4; |
||||
|
||||
import java.util.AbstractSet; |
||||
import java.util.Collection; |
||||
import java.util.Collections; |
||||
import java.util.HashSet; |
||||
import java.util.IdentityHashMap; |
||||
import java.util.Iterator; |
||||
import java.util.NavigableSet; |
||||
import java.util.Set; |
||||
import java.util.SortedSet; |
||||
import java.util.TreeSet; |
||||
|
||||
import com.fr.third.org.apache.commons.collections4.set.ListOrderedSet; |
||||
import com.fr.third.org.apache.commons.collections4.set.PredicatedNavigableSet; |
||||
import com.fr.third.org.apache.commons.collections4.set.PredicatedSet; |
||||
import com.fr.third.org.apache.commons.collections4.set.PredicatedSortedSet; |
||||
import com.fr.third.org.apache.commons.collections4.set.TransformedNavigableSet; |
||||
import com.fr.third.org.apache.commons.collections4.set.TransformedSet; |
||||
import com.fr.third.org.apache.commons.collections4.set.TransformedSortedSet; |
||||
import com.fr.third.org.apache.commons.collections4.set.UnmodifiableNavigableSet; |
||||
import com.fr.third.org.apache.commons.collections4.set.UnmodifiableSet; |
||||
import com.fr.third.org.apache.commons.collections4.set.UnmodifiableSortedSet; |
||||
import com.fr.third.org.apache.commons.collections4.set.ListOrderedSet; |
||||
import com.fr.third.org.apache.commons.collections4.set.PredicatedNavigableSet; |
||||
import com.fr.third.org.apache.commons.collections4.set.PredicatedSet; |
||||
import com.fr.third.org.apache.commons.collections4.set.PredicatedSortedSet; |
||||
import com.fr.third.org.apache.commons.collections4.set.TransformedNavigableSet; |
||||
import com.fr.third.org.apache.commons.collections4.set.TransformedSet; |
||||
import com.fr.third.org.apache.commons.collections4.set.TransformedSortedSet; |
||||
import com.fr.third.org.apache.commons.collections4.set.UnmodifiableNavigableSet; |
||||
import com.fr.third.org.apache.commons.collections4.set.UnmodifiableSet; |
||||
import com.fr.third.org.apache.commons.collections4.set.UnmodifiableSortedSet; |
||||
|
||||
/** |
||||
* Provides utility methods and decorators for |
||||
* {@link Set} and {@link SortedSet} instances. |
||||
* |
||||
* @since 2.1 |
||||
* @version $Id: SetUtils.java 1686950 2015-06-22 21:51:07Z tn $ |
||||
*/ |
||||
public class SetUtils { |
||||
|
||||
/** |
||||
* Get a typed empty unmodifiable Set. |
||||
* @param <E> the element type |
||||
* @return an empty Set |
||||
*/ |
||||
public static <E> Set<E> emptySet() { |
||||
return Collections.<E>emptySet(); |
||||
} |
||||
|
||||
/** |
||||
* An empty unmodifiable sorted set. |
||||
* This is not provided in the JDK. |
||||
*/ |
||||
@SuppressWarnings("rawtypes") |
||||
public static final SortedSet EMPTY_SORTED_SET = |
||||
UnmodifiableSortedSet.unmodifiableSortedSet(new TreeSet<Object>()); |
||||
|
||||
/** |
||||
* Get a typed empty unmodifiable sorted set. |
||||
* @param <E> the element type |
||||
* @return an empty sorted Set |
||||
*/ |
||||
@SuppressWarnings("unchecked") // empty set is OK for any type
|
||||
public static <E> SortedSet<E> emptySortedSet() { |
||||
return EMPTY_SORTED_SET; |
||||
} |
||||
|
||||
/** |
||||
* <code>SetUtils</code> should not normally be instantiated. |
||||
*/ |
||||
private SetUtils() {} |
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
/** |
||||
* Returns an immutable empty set if the argument is <code>null</code>, |
||||
* or the argument itself otherwise. |
||||
* |
||||
* @param <T> the element type |
||||
* @param set the set, possibly <code>null</code> |
||||
* @return an empty set if the argument is <code>null</code> |
||||
*/ |
||||
public static <T> Set<T> emptyIfNull(final Set<T> set) { |
||||
return set == null ? Collections.<T>emptySet() : set; |
||||
} |
||||
|
||||
/** |
||||
* Tests two sets for equality as per the <code>equals()</code> contract |
||||
* in {@link java.util.Set#equals(java.lang.Object)}. |
||||
* <p> |
||||
* This method is useful for implementing <code>Set</code> when you cannot |
||||
* extend AbstractSet. The method takes Collection instances to enable other |
||||
* collection types to use the Set implementation algorithm. |
||||
* <p> |
||||
* The relevant text (slightly paraphrased as this is a static method) is: |
||||
* <blockquote> |
||||
* <p>Two sets are considered equal if they have |
||||
* the same size, and every member of the first set is contained in |
||||
* the second. This ensures that the {@code equals} method works |
||||
* properly across different implementations of the {@code Set} |
||||
* interface.</p> |
||||
* |
||||
* <p> |
||||
* This implementation first checks if the two sets are the same object: |
||||
* if so it returns {@code true}. Then, it checks if the two sets are |
||||
* identical in size; if not, it returns false. If so, it returns |
||||
* {@code a.containsAll((Collection) b)}.</p> |
||||
* </blockquote> |
||||
* |
||||
* @see java.util.Set |
||||
* @param set1 the first set, may be null |
||||
* @param set2 the second set, may be null |
||||
* @return whether the sets are equal by value comparison |
||||
*/ |
||||
public static boolean isEqualSet(final Collection<?> set1, final Collection<?> set2) { |
||||
if (set1 == set2) { |
||||
return true; |
||||
} |
||||
if (set1 == null || set2 == null || set1.size() != set2.size()) { |
||||
return false; |
||||
} |
||||
|
||||
return set1.containsAll(set2); |
||||
} |
||||
|
||||
/** |
||||
* Generates a hash code using the algorithm specified in |
||||
* {@link java.util.Set#hashCode()}. |
||||
* <p> |
||||
* This method is useful for implementing <code>Set</code> when you cannot |
||||
* extend AbstractSet. The method takes Collection instances to enable other |
||||
* collection types to use the Set implementation algorithm. |
||||
* |
||||
* @param <T> the element type |
||||
* @see java.util.Set#hashCode() |
||||
* @param set the set to calculate the hash code for, may be null |
||||
* @return the hash code |
||||
*/ |
||||
public static <T> int hashCodeForSet(final Collection<T> set) { |
||||
if (set == null) { |
||||
return 0; |
||||
} |
||||
|
||||
int hashCode = 0; |
||||
for (final T obj : set) { |
||||
if (obj != null) { |
||||
hashCode += obj.hashCode(); |
||||
} |
||||
} |
||||
return hashCode; |
||||
} |
||||
|
||||
/** |
||||
* Returns a new hash set that matches elements based on <code>==</code> not |
||||
* <code>equals()</code>. |
||||
* <p> |
||||
* <strong>This set will violate the detail of various Set contracts.</note> |
||||
* As a general rule, don't compare this set to other sets. In particular, you can't |
||||
* use decorators like {@link ListOrderedSet} on it, which silently assume that these |
||||
* contracts are fulfilled.</strong> |
||||
* <p> |
||||
* <strong>Note that the returned set is not synchronized and is not thread-safe.</strong> |
||||
* If you wish to use this set from multiple threads concurrently, you must use |
||||
* appropriate synchronization. The simplest approach is to wrap this map |
||||
* using {@link java.util.Collections#synchronizedSet(Set)}. This class may throw |
||||
* exceptions when accessed by concurrent threads without synchronization. |
||||
* |
||||
* @param <E> the element type |
||||
* @return a new identity hash set |
||||
* @since 4.1 |
||||
*/ |
||||
public static <E> Set<E> newIdentityHashSet() { |
||||
return Collections.newSetFromMap(new IdentityHashMap<E, Boolean>()); |
||||
} |
||||
|
||||
// Set
|
||||
//-----------------------------------------------------------------------
|
||||
/** |
||||
* Returns a synchronized set backed by the given set. |
||||
* <p> |
||||
* You must manually synchronize on the returned set's iterator to |
||||
* avoid non-deterministic behavior: |
||||
* |
||||
* <pre> |
||||
* Set s = SetUtils.synchronizedSet(mySet); |
||||
* synchronized (s) { |
||||
* Iterator i = s.iterator(); |
||||
* while (i.hasNext()) { |
||||
* process (i.next()); |
||||
* } |
||||
* } |
||||
* </pre> |
||||
* |
||||
* This method is just a wrapper for {@link Collections#synchronizedSet(Set)}. |
||||
* |
||||
* @param <E> the element type |
||||
* @param set the set to synchronize, must not be null |
||||
* @return a synchronized set backed by the given set |
||||
* @throws NullPointerException if the set is null |
||||
*/ |
||||
public static <E> Set<E> synchronizedSet(final Set<E> set) { |
||||
return Collections.synchronizedSet(set); |
||||
} |
||||
|
||||
/** |
||||
* Returns an unmodifiable set backed by the given set. |
||||
* <p> |
||||
* This method uses the implementation in the decorators subpackage. |
||||
* |
||||
* @param <E> the element type |
||||
* @param set the set to make unmodifiable, must not be null |
||||
* @return an unmodifiable set backed by the given set |
||||
* @throws NullPointerException if the set is null |
||||
*/ |
||||
public static <E> Set<E> unmodifiableSet(final Set<? extends E> set) { |
||||
return UnmodifiableSet.unmodifiableSet(set); |
||||
} |
||||
|
||||
/** |
||||
* Returns a predicated (validating) set backed by the given set. |
||||
* <p> |
||||
* Only objects that pass the test in the given predicate can be added to the set. |
||||
* Trying to add an invalid object results in an IllegalArgumentException. |
||||
* It is important not to use the original set after invoking this method, |
||||
* as it is a backdoor for adding invalid objects. |
||||
* |
||||
* @param <E> the element type |
||||
* @param set the set to predicate, must not be null |
||||
* @param predicate the predicate for the set, must not be null |
||||
* @return a predicated set backed by the given set |
||||
* @throws NullPointerException if the set or predicate is null |
||||
*/ |
||||
public static <E> Set<E> predicatedSet(final Set<E> set, final Predicate<? super E> predicate) { |
||||
return PredicatedSet.predicatedSet(set, predicate); |
||||
} |
||||
|
||||
/** |
||||
* Returns a transformed set backed by the given set. |
||||
* <p> |
||||
* Each object is passed through the transformer as it is added to the |
||||
* Set. It is important not to use the original set after invoking this |
||||
* method, as it is a backdoor for adding untransformed objects. |
||||
* <p> |
||||
* Existing entries in the specified set will not be transformed. |
||||
* If you want that behaviour, see {@link TransformedSet#transformedSet}. |
||||
* |
||||
* @param <E> the element type |
||||
* @param set the set to transform, must not be null |
||||
* @param transformer the transformer for the set, must not be null |
||||
* @return a transformed set backed by the given set |
||||
* @throws NullPointerException if the set or transformer is null |
||||
*/ |
||||
public static <E> Set<E> transformedSet(final Set<E> set, |
||||
final Transformer<? super E, ? extends E> transformer) { |
||||
return TransformedSet.transformingSet(set, transformer); |
||||
} |
||||
|
||||
/** |
||||
* Returns a set that maintains the order of elements that are added |
||||
* backed by the given set. |
||||
* <p> |
||||
* If an element is added twice, the order is determined by the first add. |
||||
* The order is observed through the iterator or toArray. |
||||
* |
||||
* @param <E> the element type |
||||
* @param set the set to order, must not be null |
||||
* @return an ordered set backed by the given set |
||||
* @throws NullPointerException if the set is null |
||||
*/ |
||||
public static <E> Set<E> orderedSet(final Set<E> set) { |
||||
return ListOrderedSet.listOrderedSet(set); |
||||
} |
||||
|
||||
// SortedSet
|
||||
//-----------------------------------------------------------------------
|
||||
/** |
||||
* Returns a synchronized sorted set backed by the given sorted set. |
||||
* <p> |
||||
* You must manually synchronize on the returned set's iterator to |
||||
* avoid non-deterministic behavior: |
||||
* |
||||
* <pre> |
||||
* Set s = SetUtils.synchronizedSortedSet(mySet); |
||||
* synchronized (s) { |
||||
* Iterator i = s.iterator(); |
||||
* while (i.hasNext()) { |
||||
* process (i.next()); |
||||
* } |
||||
* } |
||||
* </pre> |
||||
* |
||||
* This method is just a wrapper for {@link Collections#synchronizedSortedSet(SortedSet)}. |
||||
* |
||||
* @param <E> the element type |
||||
* @param set the sorted set to synchronize, must not be null |
||||
* @return a synchronized set backed by the given set |
||||
* @throws NullPointerException if the set is null |
||||
*/ |
||||
public static <E> SortedSet<E> synchronizedSortedSet(final SortedSet<E> set) { |
||||
return Collections.synchronizedSortedSet(set); |
||||
} |
||||
|
||||
/** |
||||
* Returns an unmodifiable sorted set backed by the given sorted set. |
||||
* <p> |
||||
* This method uses the implementation in the decorators subpackage. |
||||
* |
||||
* @param <E> the element type |
||||
* @param set the sorted set to make unmodifiable, must not be null |
||||
* @return an unmodifiable set backed by the given set |
||||
* @throws NullPointerException if the set is null |
||||
*/ |
||||
public static <E> SortedSet<E> unmodifiableSortedSet(final SortedSet<E> set) { |
||||
return UnmodifiableSortedSet.unmodifiableSortedSet(set); |
||||
} |
||||
|
||||
/** |
||||
* Returns a predicated (validating) sorted set backed by the given sorted set. |
||||
* <p> |
||||
* Only objects that pass the test in the given predicate can be added to the set. |
||||
* Trying to add an invalid object results in an IllegalArgumentException. |
||||
* It is important not to use the original set after invoking this method, |
||||
* as it is a backdoor for adding invalid objects. |
||||
* |
||||
* @param <E> the element type |
||||
* @param set the sorted set to predicate, must not be null |
||||
* @param predicate the predicate for the sorted set, must not be null |
||||
* @return a predicated sorted set backed by the given sorted set |
||||
* @throws NullPointerException if the set or predicate is null |
||||
*/ |
||||
public static <E> SortedSet<E> predicatedSortedSet(final SortedSet<E> set, |
||||
final Predicate<? super E> predicate) { |
||||
return PredicatedSortedSet.predicatedSortedSet(set, predicate); |
||||
} |
||||
|
||||
/** |
||||
* Returns a transformed sorted set backed by the given set. |
||||
* <p> |
||||
* Each object is passed through the transformer as it is added to the |
||||
* Set. It is important not to use the original set after invoking this |
||||
* method, as it is a backdoor for adding untransformed objects. |
||||
* <p> |
||||
* Existing entries in the specified set will not be transformed. |
||||
* If you want that behaviour, see {@link TransformedSortedSet#transformedSortedSet}. |
||||
* |
||||
* @param <E> the element type |
||||
* @param set the set to transform, must not be null |
||||
* @param transformer the transformer for the set, must not be null |
||||
* @return a transformed set backed by the given set |
||||
* @throws NullPointerException if the set or transformer is null |
||||
*/ |
||||
public static <E> SortedSet<E> transformedSortedSet(final SortedSet<E> set, |
||||
final Transformer<? super E, ? extends E> transformer) { |
||||
return TransformedSortedSet.transformingSortedSet(set, transformer); |
||||
} |
||||
|
||||
// NavigableSet
|
||||
//-----------------------------------------------------------------------
|
||||
/** |
||||
* Returns an unmodifiable navigable set backed by the given navigable set. |
||||
* <p> |
||||
* This method uses the implementation in the decorators subpackage. |
||||
* |
||||
* @param <E> the element type |
||||
* @param set the navigable set to make unmodifiable, must not be null |
||||
* @return an unmodifiable set backed by the given set |
||||
* @throws NullPointerException if the set is null |
||||
* @since 4.1 |
||||
*/ |
||||
public static <E> SortedSet<E> unmodifiableNavigableSet(final NavigableSet<E> set) { |
||||
return UnmodifiableNavigableSet.unmodifiableNavigableSet(set); |
||||
} |
||||
|
||||
/** |
||||
* Returns a predicated (validating) navigable set backed by the given navigable set. |
||||
* <p> |
||||
* Only objects that pass the test in the given predicate can be added to the set. |
||||
* Trying to add an invalid object results in an IllegalArgumentException. |
||||
* It is important not to use the original set after invoking this method, |
||||
* as it is a backdoor for adding invalid objects. |
||||
* |
||||
* @param <E> the element type |
||||
* @param set the navigable set to predicate, must not be null |
||||
* @param predicate the predicate for the navigable set, must not be null |
||||
* @return a predicated navigable set backed by the given navigable set |
||||
* @throws NullPointerException if the set or predicate is null |
||||
* @since 4.1 |
||||
*/ |
||||
public static <E> SortedSet<E> predicatedNavigableSet(final NavigableSet<E> set, |
||||
final Predicate<? super E> predicate) { |
||||
return PredicatedNavigableSet.predicatedNavigableSet(set, predicate); |
||||
} |
||||
|
||||
/** |
||||
* Returns a transformed navigable set backed by the given navigable set. |
||||
* <p> |
||||
* Each object is passed through the transformer as it is added to the |
||||
* Set. It is important not to use the original set after invoking this |
||||
* method, as it is a backdoor for adding untransformed objects. |
||||
* <p> |
||||
* Existing entries in the specified set will not be transformed. |
||||
* If you want that behaviour, see {@link TransformedNavigableSet#transformedNavigableSet}. |
||||
* |
||||
* @param <E> the element type |
||||
* @param set the navigable set to transform, must not be null |
||||
* @param transformer the transformer for the set, must not be null |
||||
* @return a transformed set backed by the given set |
||||
* @throws NullPointerException if the set or transformer is null |
||||
* @since 4.1 |
||||
*/ |
||||
public static <E> SortedSet<E> transformedNavigableSet(final NavigableSet<E> set, |
||||
final Transformer<? super E, ? extends E> transformer) { |
||||
return TransformedNavigableSet.transformingNavigableSet(set, transformer); |
||||
} |
||||
|
||||
// Set operations
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
/** |
||||
* Returns a unmodifiable <b>view</b> of the union of the given {@link Set}s. |
||||
* <p> |
||||
* The returned view contains all elements of {@code a} and {@code b}. |
||||
* |
||||
* @param <E> the generic type that is able to represent the types contained |
||||
* in both input sets. |
||||
* @param a the first set, must not be null |
||||
* @param b the second set, must not be null |
||||
* @return a view of the union of the two set |
||||
* @throws NullPointerException if either input set is null |
||||
* @since 4.1 |
||||
*/ |
||||
public static <E> SetView<E> union(final Set<? extends E> a, final Set<? extends E> b) { |
||||
if (a == null || b == null) { |
||||
throw new NullPointerException("Sets must not be null."); |
||||
} |
||||
|
||||
final SetView<E> bMinusA = difference(b, a); |
||||
|
||||
return new SetView<E>() { |
||||
@Override |
||||
public boolean contains(Object o) { |
||||
return a.contains(o) || b.contains(o); |
||||
} |
||||
|
||||
@Override |
||||
public Iterator<E> createIterator() { |
||||
return IteratorUtils.chainedIterator(a.iterator(), bMinusA.iterator()); |
||||
} |
||||
|
||||
@Override |
||||
public boolean isEmpty() { |
||||
return a.isEmpty() && b.isEmpty(); |
||||
} |
||||
|
||||
@Override |
||||
public int size() { |
||||
return a.size() + bMinusA.size(); |
||||
} |
||||
}; |
||||
} |
||||
|
||||
/** |
||||
* Returns a unmodifiable <b>view</b> containing the difference of the given |
||||
* {@link Set}s, denoted by {@code a \ b} (or {@code a - b}). |
||||
* <p> |
||||
* The returned view contains all elements of {@code a} that are not a member |
||||
* of {@code b}. |
||||
* |
||||
* @param <E> the generic type that is able to represent the types contained |
||||
* in both input sets. |
||||
* @param a the set to subtract from, must not be null |
||||
* @param b the set to subtract, must not be null |
||||
* @return a view of the relative complement of of the two sets |
||||
* @since 4.1 |
||||
*/ |
||||
public static <E> SetView<E> difference(final Set<? extends E> a, final Set<? extends E> b) { |
||||
if (a == null || b == null) { |
||||
throw new NullPointerException("Sets must not be null."); |
||||
} |
||||
|
||||
final Predicate<E> notContainedInB = new Predicate<E>() { |
||||
@Override |
||||
public boolean evaluate(E object) { |
||||
return !b.contains(object); |
||||
} |
||||
}; |
||||
|
||||
return new SetView<E>() { |
||||
@Override |
||||
public boolean contains(Object o) { |
||||
return a.contains(o) && !b.contains(o); |
||||
} |
||||
|
||||
@Override |
||||
public Iterator<E> createIterator() { |
||||
return IteratorUtils.filteredIterator(a.iterator(), notContainedInB); |
||||
} |
||||
}; |
||||
} |
||||
|
||||
/** |
||||
* Returns a unmodifiable <b>view</b> of the intersection of the given {@link Set}s. |
||||
* <p> |
||||
* The returned view contains all elements that are members of both input sets |
||||
* ({@code a} and {@code b}). |
||||
* |
||||
* @param <E> the generic type that is able to represent the types contained |
||||
* in both input sets. |
||||
* @param a the first set, must not be null |
||||
* @param b the second set, must not be null |
||||
* @return a view of the intersection of the two sets |
||||
* @since 4.1 |
||||
*/ |
||||
public static <E> SetView<E> intersection(final Set<? extends E> a, final Set<? extends E> b) { |
||||
if (a == null || b == null) { |
||||
throw new NullPointerException("Sets must not be null."); |
||||
} |
||||
|
||||
final Predicate<E> containedInB = new Predicate<E>() { |
||||
@Override |
||||
public boolean evaluate(E object) { |
||||
return b.contains(object); |
||||
} |
||||
}; |
||||
|
||||
return new SetView<E>() { |
||||
@Override |
||||
public boolean contains(Object o) { |
||||
return a.contains(o) && b.contains(o); |
||||
} |
||||
|
||||
@Override |
||||
public Iterator<E> createIterator() { |
||||
return IteratorUtils.filteredIterator(a.iterator(), containedInB); |
||||
} |
||||
}; |
||||
} |
||||
|
||||
/** |
||||
* Returns a unmodifiable <b>view</b> of the symmetric difference of the given |
||||
* {@link Set}s. |
||||
* <p> |
||||
* The returned view contains all elements of {@code a} and {@code b} that are |
||||
* not a member of the other set. |
||||
* <p> |
||||
* This is equivalent to {@code union(difference(a, b), difference(b, a))}. |
||||
* |
||||
* @param <E> the generic type that is able to represent the types contained |
||||
* in both input sets. |
||||
* @param a the first set, must not be null |
||||
* @param b the second set, must not be null |
||||
* @return a view of the symmetric difference of the two sets |
||||
* @since 4.1 |
||||
*/ |
||||
public static <E> SetView<E> disjunction(final Set<? extends E> a, final Set<? extends E> b) { |
||||
if (a == null || b == null) { |
||||
throw new NullPointerException("Sets must not be null."); |
||||
} |
||||
|
||||
final SetView<E> aMinusB = difference(a, b); |
||||
final SetView<E> bMinusA = difference(b, a); |
||||
|
||||
return new SetView<E>() { |
||||
@Override |
||||
public boolean contains(Object o) { |
||||
return a.contains(o) ^ b.contains(o); |
||||
} |
||||
|
||||
@Override |
||||
public Iterator<E> createIterator() { |
||||
return IteratorUtils.chainedIterator(aMinusB.iterator(), bMinusA.iterator()); |
||||
} |
||||
|
||||
@Override |
||||
public boolean isEmpty() { |
||||
return aMinusB.isEmpty() && bMinusA.isEmpty(); |
||||
} |
||||
|
||||
@Override |
||||
public int size() { |
||||
return aMinusB.size() + bMinusA.size(); |
||||
} |
||||
}; |
||||
} |
||||
|
||||
/** |
||||
* An unmodifiable <b>view</b> of a set that may be backed by other sets. |
||||
* <p> |
||||
* If the decorated sets change, this view will change as well. The contents |
||||
* of this view can be transferred to another instance via the {@link #copyInto(Set)} |
||||
* and {@link #toSet()} methods. |
||||
* |
||||
* @param <E> the element type |
||||
* @since 4.1 |
||||
*/ |
||||
public static abstract class SetView<E> extends AbstractSet<E> { |
||||
|
||||
@Override |
||||
public Iterator<E> iterator() { |
||||
return IteratorUtils.unmodifiableIterator(createIterator()); |
||||
} |
||||
|
||||
/** |
||||
* Return an iterator for this view; the returned iterator is |
||||
* not required to be unmodifiable. |
||||
* @return a new iterator for this view |
||||
*/ |
||||
protected abstract Iterator<E> createIterator(); |
||||
|
||||
@Override |
||||
public int size() { |
||||
return IteratorUtils.size(iterator()); |
||||
} |
||||
|
||||
/** |
||||
* Copies the contents of this view into the provided set. |
||||
* |
||||
* @param <S> the set type |
||||
* @param set the set for copying the contents |
||||
*/ |
||||
public <S extends Set<E>> void copyInto(final S set) { |
||||
CollectionUtils.addAll(set, this); |
||||
} |
||||
|
||||
/** |
||||
* Returns a new set containing the contents of this view. |
||||
* |
||||
* @return a new set containing all elements of this view |
||||
*/ |
||||
public Set<E> toSet() { |
||||
final Set<E> set = new HashSet<E>(size()); |
||||
copyInto(set); |
||||
return set; |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,65 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package com.fr.third.org.apache.commons.collections4; |
||||
|
||||
import java.util.Set; |
||||
|
||||
/** |
||||
* Defines a map that holds a set of values against each key. |
||||
* <p> |
||||
* A {@code SetValuedMap} is a Map with slightly different semantics: |
||||
* <ul> |
||||
* <li>Putting a value into the map will add the value to a {@link Set} at that key.</li> |
||||
* <li>Getting a value will return a {@link Set}, holding all the values put to that key.</li> |
||||
* </ul> |
||||
* |
||||
* @since 4.1 |
||||
* @version $Id: SetValuedMap.java 1685299 2015-06-13 18:27:11Z tn $ |
||||
*/ |
||||
public interface SetValuedMap<K, V> extends MultiValuedMap<K, V> { |
||||
|
||||
/** |
||||
* Gets the set of values associated with the specified key. |
||||
* <p> |
||||
* Implementations typically return an empty {@code Set} if no values |
||||
* have been mapped to the key. |
||||
* <p> |
||||
* |
||||
* @param key the key to retrieve |
||||
* @return the {@code Set} of values, implementations should return an |
||||
* empty {@code Set} for no mapping |
||||
* @throws NullPointerException if the key is null and null keys are invalid |
||||
*/ |
||||
@Override |
||||
Set<V> get(K key); |
||||
|
||||
/** |
||||
* Removes all values associated with the specified key. |
||||
* <p> |
||||
* The returned set <i>may</i> be modifiable, but updates will not be |
||||
* propagated to this set-valued map. In case no mapping was stored for the |
||||
* specified key, an empty, unmodifiable set will be returned. |
||||
* |
||||
* @param key the key to remove values from |
||||
* @return the {@code Set} of values removed, implementations should |
||||
* return null for no mapping found, but may return an empty collection |
||||
* @throws UnsupportedOperationException if the map is unmodifiable |
||||
* @throws NullPointerException if the key is null and null keys are invalid |
||||
*/ |
||||
@Override |
||||
Set<V> remove(Object key); |
||||
} |
@ -0,0 +1,53 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package com.fr.third.org.apache.commons.collections4; |
||||
|
||||
import java.util.Comparator; |
||||
|
||||
/** |
||||
* Defines a type of <code>Bag</code> that maintains a sorted order among |
||||
* its unique representative members. |
||||
* |
||||
* @param <E> the type to iterate over |
||||
* @since 2.0 |
||||
* @version $Id: SortedBag.java 1543264 2013-11-19 00:48:12Z ggregory $ |
||||
*/ |
||||
public interface SortedBag<E> extends Bag<E> { |
||||
|
||||
/** |
||||
* Returns the comparator associated with this sorted set, or null |
||||
* if it uses its elements' natural ordering. |
||||
* |
||||
* @return the comparator in use, or null if natural ordering |
||||
*/ |
||||
Comparator<? super E> comparator(); |
||||
|
||||
/** |
||||
* Returns the first (lowest) member. |
||||
* |
||||
* @return the first element in the sorted bag |
||||
*/ |
||||
E first(); |
||||
|
||||
/** |
||||
* Returns the last (highest) member. |
||||
* |
||||
* @return the last element in the sorted bag |
||||
*/ |
||||
E last(); |
||||
|
||||
} |
@ -0,0 +1,58 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package com.fr.third.org.apache.commons.collections4; |
||||
|
||||
import java.util.Comparator; |
||||
import java.util.SortedMap; |
||||
|
||||
/** |
||||
* Defines a map that allows bidirectional lookup between key and values |
||||
* and retains both keys and values in sorted order. |
||||
* <p> |
||||
* Implementations should allow a value to be looked up from a key and |
||||
* a key to be looked up from a value with equal performance. |
||||
* |
||||
* @param <K> the type of the keys in the map |
||||
* @param <V> the type of the values in the map |
||||
* @since 3.0 |
||||
* @version $Id: SortedBidiMap.java 1543255 2013-11-19 00:45:24Z ggregory $ |
||||
*/ |
||||
public interface SortedBidiMap<K, V> extends OrderedBidiMap<K, V>, SortedMap<K, V> { |
||||
|
||||
/** |
||||
* Gets a view of this map where the keys and values are reversed. |
||||
* <p> |
||||
* Changes to one map will be visible in the other and vice versa. |
||||
* This enables both directions of the map to be accessed equally. |
||||
* <p> |
||||
* Implementations should seek to avoid creating a new object every time this |
||||
* method is called. See <code>AbstractMap.values()</code> etc. Calling this |
||||
* method on the inverse map should return the original. |
||||
* <p> |
||||
* Implementations must return a <code>SortedBidiMap</code> instance, |
||||
* usually by forwarding to <code>inverseSortedBidiMap()</code>. |
||||
* |
||||
* @return an inverted bidirectional map |
||||
*/ |
||||
SortedBidiMap<V, K> inverseBidiMap(); |
||||
|
||||
/** |
||||
* Get the comparator used for the values in the value-to-key map aspect. |
||||
* @return Comparator<? super V> |
||||
*/ |
||||
Comparator<? super V> valueComparator(); |
||||
} |
@ -0,0 +1,250 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package com.fr.third.org.apache.commons.collections4; |
||||
|
||||
import java.util.Collection; |
||||
import java.util.Map; |
||||
import java.util.Set; |
||||
|
||||
import com.fr.third.org.apache.commons.collections4.map.EntrySetToMapIteratorAdapter; |
||||
import com.fr.third.org.apache.commons.collections4.map.UnmodifiableEntrySet; |
||||
import com.fr.third.org.apache.commons.collections4.set.UnmodifiableSet; |
||||
import com.fr.third.org.apache.commons.collections4.collection.UnmodifiableCollection; |
||||
import com.fr.third.org.apache.commons.collections4.iterators.UnmodifiableMapIterator; |
||||
import com.fr.third.org.apache.commons.collections4.map.EntrySetToMapIteratorAdapter; |
||||
import com.fr.third.org.apache.commons.collections4.map.UnmodifiableEntrySet; |
||||
import com.fr.third.org.apache.commons.collections4.set.UnmodifiableSet; |
||||
|
||||
/** |
||||
* Utilities for working with "split maps:" objects that implement {@link Put} |
||||
* and/or {@link Get} but not {@link Map}. |
||||
* |
||||
* @since 4.0 |
||||
* @version $Id: SplitMapUtils.java 1686855 2015-06-22 13:00:27Z tn $ |
||||
* |
||||
* @see Get |
||||
* @see Put |
||||
*/ |
||||
public class SplitMapUtils { |
||||
|
||||
/** |
||||
* <code>SplitMapUtils</code> should not normally be instantiated. |
||||
*/ |
||||
private SplitMapUtils() {} |
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
private static class WrappedGet<K, V> implements IterableMap<K, V>, Unmodifiable { |
||||
private final Get<K, V> get; |
||||
|
||||
private WrappedGet(final Get<K, V> get) { |
||||
this.get = get; |
||||
} |
||||
|
||||
public void clear() { |
||||
throw new UnsupportedOperationException(); |
||||
} |
||||
|
||||
public boolean containsKey(final Object key) { |
||||
return get.containsKey(key); |
||||
} |
||||
|
||||
public boolean containsValue(final Object value) { |
||||
return get.containsValue(value); |
||||
} |
||||
|
||||
public Set<Map.Entry<K, V>> entrySet() { |
||||
return UnmodifiableEntrySet.unmodifiableEntrySet(get.entrySet()); |
||||
} |
||||
|
||||
@Override |
||||
public boolean equals(final Object arg0) { |
||||
if (arg0 == this) { |
||||
return true; |
||||
} |
||||
return arg0 instanceof WrappedGet && ((WrappedGet<?, ?>) arg0).get.equals(this.get); |
||||
} |
||||
|
||||
public V get(final Object key) { |
||||
return get.get(key); |
||||
} |
||||
|
||||
@Override |
||||
public int hashCode() { |
||||
return ("WrappedGet".hashCode() << 4) | get.hashCode(); |
||||
} |
||||
|
||||
public boolean isEmpty() { |
||||
return get.isEmpty(); |
||||
} |
||||
|
||||
public Set<K> keySet() { |
||||
return UnmodifiableSet.unmodifiableSet(get.keySet()); |
||||
} |
||||
|
||||
public V put(final K key, final V value) { |
||||
throw new UnsupportedOperationException(); |
||||
} |
||||
|
||||
public void putAll(final Map<? extends K, ? extends V> t) { |
||||
throw new UnsupportedOperationException(); |
||||
} |
||||
|
||||
public V remove(final Object key) { |
||||
return get.remove(key); |
||||
} |
||||
|
||||
public int size() { |
||||
return get.size(); |
||||
} |
||||
|
||||
public Collection<V> values() { |
||||
return UnmodifiableCollection.unmodifiableCollection(get.values()); |
||||
} |
||||
|
||||
public MapIterator<K, V> mapIterator() { |
||||
MapIterator<K, V> it; |
||||
if (get instanceof IterableGet) { |
||||
it = ((IterableGet<K, V>) get).mapIterator(); |
||||
} else { |
||||
it = new EntrySetToMapIteratorAdapter<K, V>(get.entrySet()); |
||||
} |
||||
return UnmodifiableMapIterator.unmodifiableMapIterator(it); |
||||
} |
||||
} |
||||
|
||||
private static class WrappedPut<K, V> implements Map<K, V>, Put<K, V> { |
||||
private final Put<K, V> put; |
||||
|
||||
private WrappedPut(final Put<K, V> put) { |
||||
this.put = put; |
||||
} |
||||
|
||||
public void clear() { |
||||
put.clear(); |
||||
} |
||||
|
||||
public boolean containsKey(final Object key) { |
||||
throw new UnsupportedOperationException(); |
||||
} |
||||
|
||||
public boolean containsValue(final Object value) { |
||||
throw new UnsupportedOperationException(); |
||||
} |
||||
|
||||
public Set<Map.Entry<K, V>> entrySet() { |
||||
throw new UnsupportedOperationException(); |
||||
} |
||||
|
||||
@Override |
||||
public boolean equals(final Object obj) { |
||||
if (obj == this) { |
||||
return true; |
||||
} |
||||
return obj instanceof WrappedPut && ((WrappedPut<?, ?>) obj).put.equals(this.put); |
||||
} |
||||
|
||||
public V get(final Object key) { |
||||
throw new UnsupportedOperationException(); |
||||
} |
||||
|
||||
@Override |
||||
public int hashCode() { |
||||
return ("WrappedPut".hashCode() << 4) | put.hashCode(); |
||||
} |
||||
|
||||
public boolean isEmpty() { |
||||
throw new UnsupportedOperationException(); |
||||
} |
||||
|
||||
public Set<K> keySet() { |
||||
throw new UnsupportedOperationException(); |
||||
} |
||||
|
||||
@SuppressWarnings("unchecked") |
||||
public V put(final K key, final V value) { |
||||
return (V) put.put(key, value); |
||||
} |
||||
|
||||
public void putAll(final Map<? extends K, ? extends V> t) { |
||||
put.putAll(t); |
||||
} |
||||
|
||||
public V remove(final Object key) { |
||||
throw new UnsupportedOperationException(); |
||||
} |
||||
|
||||
public int size() { |
||||
throw new UnsupportedOperationException(); |
||||
} |
||||
|
||||
public Collection<V> values() { |
||||
throw new UnsupportedOperationException(); |
||||
} |
||||
} |
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
/** |
||||
* Get the specified {@link Get} as an instance of {@link IterableMap}. |
||||
* If <code>get</code> implements {@link IterableMap} directly, no conversion will take place. |
||||
* If <code>get</code> implements {@link Map} but not {@link IterableMap} it will be decorated. |
||||
* Otherwise an {@link Unmodifiable} {@link IterableMap} will be returned. |
||||
* @param <K> the key type |
||||
* @param <V> the value type |
||||
* @param get to wrap, must not be null |
||||
* @return {@link IterableMap} |
||||
* @throws NullPointerException if the argument is null |
||||
*/ |
||||
@SuppressWarnings("unchecked") |
||||
public static <K, V> IterableMap<K, V> readableMap(final Get<K, V> get) { |
||||
if (get == null) { |
||||
throw new NullPointerException("Get must not be null"); |
||||
} |
||||
if (get instanceof Map) { |
||||
return get instanceof IterableMap ? |
||||
((IterableMap<K, V>) get) : |
||||
MapUtils.iterableMap((Map<K, V>) get); |
||||
} |
||||
return new WrappedGet<K, V>(get); |
||||
} |
||||
|
||||
/** |
||||
* Get the specified {@link Put} as an instanceof {@link Map}. |
||||
* If <code>put</code> implements {@link Map} directly, no conversion will take place. |
||||
* Otherwise a <em>write-only</em> {@link Map} will be returned. On such a {@link Map} |
||||
* it is recommended that the result of #put(K, V) be discarded as it likely will not |
||||
* match <code>V</code> at runtime. |
||||
* |
||||
* @param <K> the key type |
||||
* @param <V> the element type |
||||
* @param put to wrap, must not be null |
||||
* @return {@link Map} |
||||
* @throws NullPointerException if the argument is null |
||||
*/ |
||||
@SuppressWarnings("unchecked") |
||||
public static <K, V> Map<K, V> writableMap(final Put<K, V> put) { |
||||
if (put == null) { |
||||
throw new NullPointerException("Put must not be null"); |
||||
} |
||||
if (put instanceof Map) { |
||||
return (Map<K, V>) put; |
||||
} |
||||
return new WrappedPut<K, V>(put); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,51 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package com.fr.third.org.apache.commons.collections4; |
||||
|
||||
/** |
||||
* Defines a functor interface implemented by classes that transform one |
||||
* object into another. |
||||
* <p> |
||||
* A <code>Transformer</code> converts the input object to the output object. |
||||
* The input object should be left unchanged. |
||||
* Transformers are typically used for type conversions, or extracting data |
||||
* from an object. |
||||
* <p> |
||||
* Standard implementations of common transformers are provided by |
||||
* {@link TransformerUtils}. These include method invocation, returning a constant, |
||||
* cloning and returning the string value. |
||||
* |
||||
* @param <I> the input type to the transformer |
||||
* @param <O> the output type from the transformer |
||||
* |
||||
* @since 1.0 |
||||
* @version $Id: Transformer.java 1543278 2013-11-19 00:54:07Z ggregory $ |
||||
*/ |
||||
public interface Transformer<I, O> { |
||||
|
||||
/** |
||||
* Transforms the input object (leaving it unchanged) into some output object. |
||||
* |
||||
* @param input the object to be transformed, should be left unchanged |
||||
* @return a transformed object |
||||
* @throws ClassCastException (runtime) if the input is the wrong class
|
||||
* @throws IllegalArgumentException (runtime) if the input is invalid |
||||
* @throws FunctorException (runtime) if the transform cannot be completed |
||||
*/ |
||||
O transform(I input); |
||||
|
||||
} |
@ -0,0 +1,499 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package com.fr.third.org.apache.commons.collections4; |
||||
|
||||
import java.util.Collection; |
||||
import java.util.Map; |
||||
|
||||
import com.fr.third.org.apache.commons.collections4.functors.ChainedTransformer; |
||||
import com.fr.third.org.apache.commons.collections4.functors.CloneTransformer; |
||||
import com.fr.third.org.apache.commons.collections4.functors.ClosureTransformer; |
||||
import com.fr.third.org.apache.commons.collections4.functors.ConstantTransformer; |
||||
import com.fr.third.org.apache.commons.collections4.functors.EqualPredicate; |
||||
import com.fr.third.org.apache.commons.collections4.functors.ExceptionTransformer; |
||||
import com.fr.third.org.apache.commons.collections4.functors.FactoryTransformer; |
||||
import com.fr.third.org.apache.commons.collections4.functors.IfTransformer; |
||||
import com.fr.third.org.apache.commons.collections4.functors.InstantiateTransformer; |
||||
import com.fr.third.org.apache.commons.collections4.functors.InvokerTransformer; |
||||
import com.fr.third.org.apache.commons.collections4.functors.MapTransformer; |
||||
import com.fr.third.org.apache.commons.collections4.functors.NOPTransformer; |
||||
import com.fr.third.org.apache.commons.collections4.functors.PredicateTransformer; |
||||
import com.fr.third.org.apache.commons.collections4.functors.StringValueTransformer; |
||||
import com.fr.third.org.apache.commons.collections4.functors.SwitchTransformer; |
||||
import com.fr.third.org.apache.commons.collections4.functors.ChainedTransformer; |
||||
import com.fr.third.org.apache.commons.collections4.functors.CloneTransformer; |
||||
import com.fr.third.org.apache.commons.collections4.functors.ClosureTransformer; |
||||
import com.fr.third.org.apache.commons.collections4.functors.ConstantTransformer; |
||||
import com.fr.third.org.apache.commons.collections4.functors.EqualPredicate; |
||||
import com.fr.third.org.apache.commons.collections4.functors.ExceptionTransformer; |
||||
import com.fr.third.org.apache.commons.collections4.functors.FactoryTransformer; |
||||
import com.fr.third.org.apache.commons.collections4.functors.IfTransformer; |
||||
import com.fr.third.org.apache.commons.collections4.functors.InstantiateTransformer; |
||||
import com.fr.third.org.apache.commons.collections4.functors.InvokerTransformer; |
||||
import com.fr.third.org.apache.commons.collections4.functors.MapTransformer; |
||||
import com.fr.third.org.apache.commons.collections4.functors.NOPTransformer; |
||||
import com.fr.third.org.apache.commons.collections4.functors.PredicateTransformer; |
||||
import com.fr.third.org.apache.commons.collections4.functors.StringValueTransformer; |
||||
import com.fr.third.org.apache.commons.collections4.functors.SwitchTransformer; |
||||
|
||||
/** |
||||
* <code>TransformerUtils</code> provides reference implementations and |
||||
* utilities for the Transformer functor interface. The supplied transformers are: |
||||
* <ul> |
||||
* <li>Invoker - returns the result of a method call on the input object |
||||
* <li>Clone - returns a clone of the input object |
||||
* <li>Constant - always returns the same object |
||||
* <li>Closure - performs a Closure and returns the input object |
||||
* <li>Predicate - returns the result of the predicate as a Boolean |
||||
* <li>Factory - returns a new object from a factory |
||||
* <li>Chained - chains two or more transformers together |
||||
* <li>If - calls one transformer or another based on a predicate |
||||
* <li>Switch - calls one transformer based on one or more predicates |
||||
* <li>SwitchMap - calls one transformer looked up from a Map |
||||
* <li>Instantiate - the Class input object is instantiated |
||||
* <li>Map - returns an object from a supplied Map |
||||
* <li>Null - always returns null |
||||
* <li>NOP - returns the input object, which should be immutable |
||||
* <li>Exception - always throws an exception |
||||
* <li>StringValue - returns a <code>java.lang.String</code> representation of the input object |
||||
* </ul> |
||||
* <p> |
||||
* Since v4.1 only transformers which are considered to be unsafe are |
||||
* Serializable. Transformers considered to be unsafe for serialization are: |
||||
* <ul> |
||||
* <li>Invoker |
||||
* <li>Clone |
||||
* <li>Instantiate |
||||
* </ul> |
||||
* |
||||
* @since 3.0 |
||||
* @version $Id: TransformerUtils.java 1714362 2015-11-14 20:38:02Z tn $ |
||||
*/ |
||||
public class TransformerUtils { |
||||
|
||||
/** |
||||
* This class is not normally instantiated. |
||||
*/ |
||||
private TransformerUtils() {} |
||||
|
||||
/** |
||||
* Gets a transformer that always throws an exception. |
||||
* This could be useful during testing as a placeholder. |
||||
* |
||||
* @param <I> the input type |
||||
* @param <O> the output type |
||||
* @return the transformer |
||||
* @see ExceptionTransformer |
||||
*/ |
||||
public static <I, O> Transformer<I, O> exceptionTransformer() { |
||||
return ExceptionTransformer.exceptionTransformer(); |
||||
} |
||||
|
||||
/** |
||||
* Gets a transformer that always returns null. |
||||
* |
||||
* @param <I> the input type |
||||
* @param <O> the output type |
||||
* @return the transformer |
||||
* @see ConstantTransformer |
||||
*/ |
||||
public static <I, O> Transformer<I, O> nullTransformer() { |
||||
return ConstantTransformer.nullTransformer(); |
||||
} |
||||
|
||||
/** |
||||
* Gets a transformer that returns the input object. |
||||
* The input object should be immutable to maintain the |
||||
* contract of Transformer (although this is not checked). |
||||
* |
||||
* @param <T> the input/output type |
||||
* @return the transformer |
||||
* @see NOPTransformer |
||||
*/ |
||||
public static <T> Transformer<T, T> nopTransformer() { |
||||
return NOPTransformer.nopTransformer(); |
||||
} |
||||
|
||||
/** |
||||
* Gets a transformer that returns a clone of the input object. |
||||
* The input object will be cloned using one of these techniques (in order): |
||||
* <ul> |
||||
* <li>public clone method |
||||
* <li>public copy constructor |
||||
* <li>serialization clone |
||||
* <ul> |
||||
* |
||||
* @param <T> the input/output type |
||||
* @return the transformer |
||||
* @see CloneTransformer |
||||
*/ |
||||
public static <T> Transformer<T, T> cloneTransformer() { |
||||
return CloneTransformer.cloneTransformer(); |
||||
} |
||||
|
||||
/** |
||||
* Creates a Transformer that will return the same object each time the |
||||
* transformer is used. |
||||
* |
||||
* @param <I> the input type |
||||
* @param <O> the output type |
||||
* @param constantToReturn the constant object to return each time in the transformer |
||||
* @return the transformer. |
||||
* @see ConstantTransformer |
||||
*/ |
||||
public static <I, O> Transformer<I, O> constantTransformer(final O constantToReturn) { |
||||
return ConstantTransformer.constantTransformer(constantToReturn); |
||||
} |
||||
|
||||
/** |
||||
* Creates a Transformer that calls a Closure each time the transformer is used. |
||||
* The transformer returns the input object. |
||||
* |
||||
* @param <T> the input/output type |
||||
* @param closure the closure to run each time in the transformer, not null |
||||
* @return the transformer |
||||
* @throws NullPointerException if the closure is null |
||||
* @see ClosureTransformer |
||||
*/ |
||||
public static <T> Transformer<T, T> asTransformer(final Closure<? super T> closure) { |
||||
return ClosureTransformer.closureTransformer(closure); |
||||
} |
||||
|
||||
/** |
||||
* Creates a Transformer that calls a Predicate each time the transformer is used. |
||||
* The transformer will return either Boolean.TRUE or Boolean.FALSE. |
||||
* |
||||
* @param <T> the input type |
||||
* @param predicate the predicate to run each time in the transformer, not null |
||||
* @return the transformer |
||||
* @throws NullPointerException if the predicate is null |
||||
* @see PredicateTransformer |
||||
*/ |
||||
public static <T> Transformer<T, Boolean> asTransformer(final Predicate<? super T> predicate) { |
||||
return PredicateTransformer.predicateTransformer(predicate); |
||||
} |
||||
|
||||
/** |
||||
* Creates a Transformer that calls a Factory each time the transformer is used. |
||||
* The transformer will return the value returned by the factory. |
||||
* |
||||
* @param <I> the input type |
||||
* @param <O> the output type |
||||
* @param factory the factory to run each time in the transformer, not null |
||||
* @return the transformer |
||||
* @throws NullPointerException if the factory is null |
||||
* @see FactoryTransformer |
||||
*/ |
||||
public static <I, O> Transformer<I, O> asTransformer(final Factory<? extends O> factory) { |
||||
return FactoryTransformer.factoryTransformer(factory); |
||||
} |
||||
|
||||
/** |
||||
* Create a new Transformer that calls each transformer in turn, passing the |
||||
* result into the next transformer. |
||||
* |
||||
* @param <T> the input/output type |
||||
* @param transformers an array of transformers to chain |
||||
* @return the transformer |
||||
* @throws NullPointerException if the transformers array or any of the transformers is null |
||||
* @see ChainedTransformer |
||||
*/ |
||||
public static <T> Transformer<T, T> chainedTransformer( |
||||
final Transformer<? super T, ? extends T>... transformers) { |
||||
return ChainedTransformer.chainedTransformer(transformers); |
||||
} |
||||
|
||||
/** |
||||
* Create a new Transformer that calls each transformer in turn, passing the |
||||
* result into the next transformer. The ordering is that of the iterator() |
||||
* method on the collection. |
||||
* |
||||
* @param <T> the input/output type |
||||
* @param transformers a collection of transformers to chain |
||||
* @return the transformer |
||||
* @throws NullPointerException if the transformers collection or any of the transformers is null |
||||
* @see ChainedTransformer |
||||
*/ |
||||
public static <T> Transformer<T, T> chainedTransformer( |
||||
final Collection<? extends Transformer<? super T, ? extends T>> transformers) { |
||||
return ChainedTransformer.chainedTransformer(transformers); |
||||
} |
||||
|
||||
/** |
||||
* Create a new Transformer that calls the transformer if the predicate is true, |
||||
* otherwise the input object is returned unchanged. |
||||
* |
||||
* @param <T> the input / output type |
||||
* @param predicate the predicate to switch on |
||||
* @param trueTransformer the transformer called if the predicate is true |
||||
* @return the transformer |
||||
* @throws NullPointerException if either the predicate or transformer is null |
||||
* @see IfTransformer |
||||
* @since 4.1 |
||||
*/ |
||||
public static <T> Transformer<T, T> ifTransformer(final Predicate<? super T> predicate, |
||||
final Transformer<? super T, ? extends T> trueTransformer) { |
||||
return IfTransformer.ifTransformer(predicate, trueTransformer); |
||||
} |
||||
|
||||
/** |
||||
* Create a new Transformer that calls one of two transformers depending |
||||
* on the specified predicate. |
||||
* |
||||
* @param <I> the input type |
||||
* @param <O> the output type |
||||
* @param predicate the predicate to switch on |
||||
* @param trueTransformer the transformer called if the predicate is true |
||||
* @param falseTransformer the transformer called if the predicate is false |
||||
* @return the transformer |
||||
* @throws NullPointerException if either the predicate or transformer is null |
||||
* @see IfTransformer |
||||
* @since 4.1 |
||||
*/ |
||||
public static <I, O> Transformer<I, O> ifTransformer(final Predicate<? super I> predicate, |
||||
final Transformer<? super I, ? extends O> trueTransformer, |
||||
final Transformer<? super I, ? extends O> falseTransformer) { |
||||
return IfTransformer.ifTransformer(predicate, trueTransformer, falseTransformer); |
||||
} |
||||
|
||||
/** |
||||
* Create a new Transformer that calls one of two transformers depending |
||||
* on the specified predicate. |
||||
* |
||||
* @param <I> the input type |
||||
* @param <O> the output type |
||||
* @param predicate the predicate to switch on |
||||
* @param trueTransformer the transformer called if the predicate is true |
||||
* @param falseTransformer the transformer called if the predicate is false |
||||
* @return the transformer |
||||
* @throws NullPointerException if either the predicate or transformer is null |
||||
* @see SwitchTransformer |
||||
* @deprecated as of 4.1, use {@link #ifTransformer(Predicate, Transformer, Transformer)) |
||||
*/ |
||||
@SuppressWarnings("unchecked") |
||||
@Deprecated |
||||
public static <I, O> Transformer<I, O> switchTransformer(final Predicate<? super I> predicate, |
||||
final Transformer<? super I, ? extends O> trueTransformer, |
||||
final Transformer<? super I, ? extends O> falseTransformer) { |
||||
return SwitchTransformer.switchTransformer(new Predicate[] { predicate }, |
||||
new Transformer[] { trueTransformer }, falseTransformer); |
||||
} |
||||
|
||||
/** |
||||
* Create a new Transformer that calls one of the transformers depending |
||||
* on the predicates. The transformer at array location 0 is called if the |
||||
* predicate at array location 0 returned true. Each predicate is evaluated |
||||
* until one returns true. If no predicates evaluate to true, null is returned. |
||||
* |
||||
* @param <I> the input type |
||||
* @param <O> the output type |
||||
* @param predicates an array of predicates to check |
||||
* @param transformers an array of transformers to call |
||||
* @return the transformer |
||||
* @throws NullPointerException if the either array is null |
||||
* @throws NullPointerException if any element in the arrays is null |
||||
* @throws IllegalArgumentException if the arrays have different sizes |
||||
* @see SwitchTransformer |
||||
*/ |
||||
public static <I, O> Transformer<I, O> switchTransformer(final Predicate<? super I>[] predicates, |
||||
final Transformer<? super I, ? extends O>[] transformers) { |
||||
return SwitchTransformer.switchTransformer(predicates, transformers, null); |
||||
} |
||||
|
||||
/** |
||||
* Create a new Transformer that calls one of the transformers depending |
||||
* on the predicates. The transformer at array location 0 is called if the |
||||
* predicate at array location 0 returned true. Each predicate is evaluated |
||||
* until one returns true. If no predicates evaluate to true, the default |
||||
* transformer is called. If the default transformer is null, null is returned. |
||||
* |
||||
* @param <I> the input type |
||||
* @param <O> the output type |
||||
* @param predicates an array of predicates to check |
||||
* @param transformers an array of transformers to call |
||||
* @param defaultTransformer the default to call if no predicate matches, null means return null |
||||
* @return the transformer |
||||
* @throws NullPointerException if the either array is null |
||||
* @throws NullPointerException if any element in the arrays is null |
||||
* @throws IllegalArgumentException if the arrays have different sizes |
||||
* @see SwitchTransformer |
||||
*/ |
||||
public static <I, O> Transformer<I, O> switchTransformer(final Predicate<? super I>[] predicates, |
||||
final Transformer<? super I, ? extends O>[] transformers, |
||||
final Transformer<? super I, ? extends O> defaultTransformer) { |
||||
return SwitchTransformer.switchTransformer(predicates, transformers, defaultTransformer); |
||||
} |
||||
|
||||
/** |
||||
* Create a new Transformer that calls one of the transformers depending |
||||
* on the predicates. |
||||
* <p> |
||||
* The Map consists of Predicate keys and Transformer values. A transformer |
||||
* is called if its matching predicate returns true. Each predicate is evaluated |
||||
* until one returns true. If no predicates evaluate to true, the default |
||||
* transformer is called. The default transformer is set in the map with a |
||||
* null key. If no default transformer is set, null will be returned in a default |
||||
* case. The ordering is that of the iterator() method on the entryset collection |
||||
* of the map. |
||||
* |
||||
* @param <I> the input type |
||||
* @param <O> the output type |
||||
* @param predicatesAndTransformers a map of predicates to transformers |
||||
* @return the transformer |
||||
* @throws NullPointerException if the map is null |
||||
* @throws NullPointerException if any transformer in the map is null |
||||
* @throws ClassCastException if the map elements are of the wrong type |
||||
* @see SwitchTransformer |
||||
*/ |
||||
public static <I, O> Transformer<I, O> switchTransformer( |
||||
final Map<Predicate<I>, Transformer<I, O>> predicatesAndTransformers) { |
||||
return SwitchTransformer.switchTransformer(predicatesAndTransformers); |
||||
} |
||||
|
||||
/** |
||||
* Create a new Transformer that uses the input object as a key to find the |
||||
* transformer to call. |
||||
* <p> |
||||
* The Map consists of object keys and Transformer values. A transformer |
||||
* is called if the input object equals the key. If there is no match, the |
||||
* default transformer is called. The default transformer is set in the map |
||||
* using a null key. If no default is set, null will be returned in a default case. |
||||
* |
||||
* @param <I> the input type |
||||
* @param <O> the output type |
||||
* @param objectsAndTransformers a map of objects to transformers |
||||
* @return the transformer |
||||
* @throws NullPointerException if the map is null |
||||
* @throws NullPointerException if any transformer in the map is null |
||||
* @see SwitchTransformer |
||||
*/ |
||||
@SuppressWarnings("unchecked") |
||||
public static <I, O> Transformer<I, O> switchMapTransformer( |
||||
final Map<I, Transformer<I, O>> objectsAndTransformers) { |
||||
|
||||
if (objectsAndTransformers == null) { |
||||
throw new NullPointerException("The object and transformer map must not be null"); |
||||
} |
||||
final Transformer<? super I, ? extends O> def = objectsAndTransformers.remove(null); |
||||
final int size = objectsAndTransformers.size(); |
||||
final Transformer<? super I, ? extends O>[] trs = new Transformer[size]; |
||||
final Predicate<I>[] preds = new Predicate[size]; |
||||
int i = 0; |
||||
for (final Map.Entry<I, Transformer<I, O>> entry : objectsAndTransformers.entrySet()) { |
||||
preds[i] = EqualPredicate.<I>equalPredicate(entry.getKey()); |
||||
trs[i++] = entry.getValue(); |
||||
} |
||||
return TransformerUtils.switchTransformer(preds, trs, def); |
||||
} |
||||
|
||||
/** |
||||
* Gets a Transformer that expects an input Class object that it will instantiate. |
||||
* |
||||
* @param <T> the output type |
||||
* @return the transformer |
||||
* @see InstantiateTransformer |
||||
*/ |
||||
public static <T> Transformer<Class<? extends T>, T> instantiateTransformer() { |
||||
return InstantiateTransformer.instantiateTransformer(); |
||||
} |
||||
|
||||
/** |
||||
* Creates a Transformer that expects an input Class object that it will |
||||
* instantiate. The constructor used is determined by the arguments specified |
||||
* to this method. |
||||
* |
||||
* @param <T> the output type |
||||
* @param paramTypes parameter types for the constructor, can be null |
||||
* @param args the arguments to pass to the constructor, can be null |
||||
* @return the transformer |
||||
* @throws IllegalArgumentException if the paramTypes and args don't match |
||||
* @see InstantiateTransformer |
||||
*/ |
||||
public static <T> Transformer<Class<? extends T>, T> instantiateTransformer( |
||||
final Class<?>[] paramTypes, final Object[] args) { |
||||
return InstantiateTransformer.instantiateTransformer(paramTypes, args); |
||||
} |
||||
|
||||
/** |
||||
* Creates a Transformer that uses the passed in Map to transform the input |
||||
* object (as a simple lookup). |
||||
* |
||||
* @param <I> the input type |
||||
* @param <O> the output type |
||||
* @param map the map to use to transform the objects |
||||
* @return the transformer, or {@link ConstantTransformer#nullTransformer()} if the |
||||
* {@code map} is {@code null} |
||||
* @see MapTransformer |
||||
*/ |
||||
public static <I, O> Transformer<I, O> mapTransformer(final Map<? super I, ? extends O> map) { |
||||
return MapTransformer.mapTransformer(map); |
||||
} |
||||
|
||||
/** |
||||
* Gets a Transformer that invokes a method on the input object. |
||||
* The method must have no parameters. If the input object is null, |
||||
* null is returned. |
||||
* <p> |
||||
* For example, <code>TransformerUtils.invokerTransformer("getName");</code> |
||||
* will call the <code>getName/code> method on the input object to |
||||
* determine the transformer result. |
||||
* |
||||
* @param <I> the input type |
||||
* @param <O> the output type |
||||
* @param methodName the method name to call on the input object, may not be null |
||||
* @return the transformer |
||||
* @throws NullPointerException if the methodName is null. |
||||
* @see InvokerTransformer |
||||
*/ |
||||
public static <I, O> Transformer<I, O> invokerTransformer(final String methodName) { |
||||
return InvokerTransformer.invokerTransformer(methodName, null, null); |
||||
} |
||||
|
||||
/** |
||||
* Gets a Transformer that invokes a method on the input object. |
||||
* The method parameters are specified. If the input object is {@code null}, |
||||
* {@code null} is returned. |
||||
* |
||||
* @param <I> the input type |
||||
* @param <O> the output type |
||||
* @param methodName the name of the method |
||||
* @param paramTypes the parameter types |
||||
* @param args the arguments |
||||
* @return the transformer |
||||
* @throws NullPointerException if the method name is null |
||||
* @throws IllegalArgumentException if the paramTypes and args don't match |
||||
* @see InvokerTransformer |
||||
*/ |
||||
public static <I, O> Transformer<I, O> invokerTransformer(final String methodName, final Class<?>[] paramTypes, |
||||
final Object[] args) { |
||||
return InvokerTransformer.invokerTransformer(methodName, paramTypes, args); |
||||
} |
||||
|
||||
/** |
||||
* Gets a transformer that returns a <code>java.lang.String</code> |
||||
* representation of the input object. This is achieved via the |
||||
* <code>toString</code> method, <code>null</code> returns 'null'. |
||||
* |
||||
* @param <T> the input type |
||||
* @return the transformer |
||||
* @see StringValueTransformer |
||||
*/ |
||||
public static <T> Transformer<T, String> stringValueTransformer() { |
||||
return StringValueTransformer.stringValueTransformer(); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,47 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package com.fr.third.org.apache.commons.collections4; |
||||
|
||||
import java.util.SortedMap; |
||||
|
||||
/** |
||||
* Defines the interface for a prefix tree, an ordered tree data structure. For |
||||
* more information, see <a href="http://en.wikipedia.org/wiki/Trie">Tries</a>. |
||||
* |
||||
* @since 4.0 |
||||
* @version $Id: Trie.java 1543279 2013-11-19 00:54:31Z ggregory $ |
||||
*/ |
||||
public interface Trie<K, V> extends IterableSortedMap<K, V> { |
||||
|
||||
/** |
||||
* Returns a view of this {@link Trie} of all elements that are prefixed |
||||
* by the given key. |
||||
* <p> |
||||
* In a {@link Trie} with fixed size keys, this is essentially a |
||||
* {@link #get(Object)} operation. |
||||
* <p> |
||||
* For example, if the {@link Trie} contains 'Anna', 'Anael', |
||||
* 'Analu', 'Andreas', 'Andrea', 'Andres', and 'Anatole', then |
||||
* a lookup of 'And' would return 'Andreas', 'Andrea', and 'Andres'. |
||||
* |
||||
* @param key the key used in the search |
||||
* @return a {@link SortedMap} view of this {@link Trie} with all elements whose |
||||
* key is prefixed by the search key |
||||
*/ |
||||
SortedMap<K, V> prefixMap(K key); |
||||
|
||||
} |
@ -0,0 +1,50 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package com.fr.third.org.apache.commons.collections4; |
||||
|
||||
import com.fr.third.org.apache.commons.collections4.trie.UnmodifiableTrie; |
||||
import com.fr.third.org.apache.commons.collections4.trie.UnmodifiableTrie; |
||||
|
||||
/** |
||||
* A collection of {@link Trie} utilities. |
||||
* |
||||
* @since 4.0 |
||||
* @version $Id: TrieUtils.java 1686855 2015-06-22 13:00:27Z tn $ |
||||
*/ |
||||
public class TrieUtils { |
||||
|
||||
/** |
||||
* {@link TrieUtils} should not normally be instantiated. |
||||
*/ |
||||
private TrieUtils() {} |
||||
|
||||
/** |
||||
* Returns an unmodifiable instance of a {@link Trie} |
||||
* |
||||
* @param <K> the key type |
||||
* @param <V> the value type |
||||
* @param trie the trie to make unmodifiable, must not be null |
||||
* @return an unmodifiable trie backed by the given trie |
||||
* @throws NullPointerException if trie is null |
||||
* |
||||
* @see java.util.Collections#unmodifiableMap(java.util.Map) |
||||
*/ |
||||
public static <K, V> Trie<K, V> unmodifiableTrie(final Trie<K, ? extends V> trie) { |
||||
return UnmodifiableTrie.unmodifiableTrie(trie); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,38 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package com.fr.third.org.apache.commons.collections4; |
||||
|
||||
/** |
||||
* Marker interface for collections, maps and iterators that are unmodifiable. |
||||
* <p> |
||||
* This interface enables testing such as: |
||||
* <pre> |
||||
* if (coll instanceof Unmodifiable) { |
||||
* coll = new ArrayList(coll); |
||||
* } |
||||
* // now we know coll is modifiable
|
||||
* </pre> |
||||
* Of course all this only works if you use the Unmodifiable classes defined |
||||
* in this library. If you use the JDK unmodifiable class via {@code java.util Collections} |
||||
* then the interface won't be there. |
||||
* |
||||
* @since 3.0 |
||||
* @version $Id: Unmodifiable.java 1477779 2013-04-30 18:55:24Z tn $ |
||||
*/ |
||||
public interface Unmodifiable { |
||||
// marker interface - no methods to implement
|
||||
} |
@ -0,0 +1,98 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package com.fr.third.org.apache.commons.collections4.bag; |
||||
|
||||
import java.util.Set; |
||||
|
||||
import com.fr.third.org.apache.commons.collections4.Bag; |
||||
import com.fr.third.org.apache.commons.collections4.collection.AbstractCollectionDecorator; |
||||
|
||||
/** |
||||
* Decorates another <code>Bag</code> to provide additional behaviour. |
||||
* <p> |
||||
* Methods are forwarded directly to the decorated bag. |
||||
* |
||||
* @since 3.0 |
||||
* @version $Id: AbstractBagDecorator.java 1686855 2015-06-22 13:00:27Z tn $ |
||||
*/ |
||||
public abstract class AbstractBagDecorator<E> |
||||
extends AbstractCollectionDecorator<E> implements Bag<E> { |
||||
|
||||
/** Serialization version */ |
||||
private static final long serialVersionUID = -3768146017343785417L; |
||||
|
||||
/** |
||||
* Constructor only used in deserialization, do not use otherwise. |
||||
* @since 3.1 |
||||
*/ |
||||
protected AbstractBagDecorator() { |
||||
super(); |
||||
} |
||||
|
||||
/** |
||||
* Constructor that wraps (not copies). |
||||
* |
||||
* @param bag the bag to decorate, must not be null |
||||
* @throws NullPointerException if bag is null |
||||
*/ |
||||
protected AbstractBagDecorator(final Bag<E> bag) { |
||||
super(bag); |
||||
} |
||||
|
||||
/** |
||||
* Gets the bag being decorated. |
||||
* |
||||
* @return the decorated bag |
||||
*/ |
||||
@Override |
||||
protected Bag<E> decorated() { |
||||
return (Bag<E>) super.decorated(); |
||||
} |
||||
|
||||
@Override |
||||
public boolean equals(final Object object) { |
||||
return object == this || decorated().equals(object); |
||||
} |
||||
|
||||
@Override |
||||
public int hashCode() { |
||||
return decorated().hashCode(); |
||||
} |
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
@Override |
||||
public int getCount(final Object object) { |
||||
return decorated().getCount(object); |
||||
} |
||||
|
||||
@Override |
||||
public boolean add(final E object, final int count) { |
||||
return decorated().add(object, count); |
||||
} |
||||
|
||||
@Override |
||||
public boolean remove(final Object object, final int count) { |
||||
return decorated().remove(object, count); |
||||
} |
||||
|
||||
@Override |
||||
public Set<E> uniqueSet() { |
||||
return decorated().uniqueSet(); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,625 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package com.fr.third.org.apache.commons.collections4.bag; |
||||
|
||||
import java.io.IOException; |
||||
import java.io.ObjectInputStream; |
||||
import java.io.ObjectOutputStream; |
||||
import java.lang.reflect.Array; |
||||
import java.util.Collection; |
||||
import java.util.ConcurrentModificationException; |
||||
import java.util.Iterator; |
||||
import java.util.Map; |
||||
import java.util.Map.Entry; |
||||
import java.util.Set; |
||||
|
||||
import com.fr.third.org.apache.commons.collections4.set.UnmodifiableSet; |
||||
import com.fr.third.org.apache.commons.collections4.Bag; |
||||
import com.fr.third.org.apache.commons.collections4.set.UnmodifiableSet; |
||||
|
||||
/** |
||||
* Abstract implementation of the {@link Bag} interface to simplify the creation |
||||
* of subclass implementations. |
||||
* <p> |
||||
* Subclasses specify a Map implementation to use as the internal storage. The |
||||
* map will be used to map bag elements to a number; the number represents the |
||||
* number of occurrences of that element in the bag. |
||||
* |
||||
* @since 3.0 (previously DefaultMapBag v2.0) |
||||
* @version $Id: AbstractMapBag.java 1684859 2015-06-11 11:57:24Z tn $ |
||||
*/ |
||||
public abstract class AbstractMapBag<E> implements Bag<E> { |
||||
|
||||
/** The map to use to store the data */ |
||||
private transient Map<E, MutableInteger> map; |
||||
/** The current total size of the bag */ |
||||
private int size; |
||||
/** The modification count for fail fast iterators */ |
||||
private transient int modCount; |
||||
/** Unique view of the elements */ |
||||
private transient Set<E> uniqueSet; |
||||
|
||||
/** |
||||
* Constructor needed for subclass serialisation. |
||||
*/ |
||||
protected AbstractMapBag() { |
||||
super(); |
||||
} |
||||
|
||||
/** |
||||
* Constructor that assigns the specified Map as the backing store. The map |
||||
* must be empty and non-null. |
||||
* |
||||
* @param map the map to assign |
||||
*/ |
||||
protected AbstractMapBag(final Map<E, MutableInteger> map) { |
||||
super(); |
||||
this.map = map; |
||||
} |
||||
|
||||
/** |
||||
* Utility method for implementations to access the map that backs this bag. |
||||
* Not intended for interactive use outside of subclasses. |
||||
* |
||||
* @return the map being used by the Bag |
||||
*/ |
||||
protected Map<E, MutableInteger> getMap() { |
||||
return map; |
||||
} |
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/** |
||||
* Returns the number of elements in this bag. |
||||
* |
||||
* @return current size of the bag |
||||
*/ |
||||
@Override |
||||
public int size() { |
||||
return size; |
||||
} |
||||
|
||||
/** |
||||
* Returns true if the underlying map is empty. |
||||
* |
||||
* @return true if bag is empty |
||||
*/ |
||||
@Override |
||||
public boolean isEmpty() { |
||||
return map.isEmpty(); |
||||
} |
||||
|
||||
/** |
||||
* Returns the number of occurrence of the given element in this bag by |
||||
* looking up its count in the underlying map. |
||||
* |
||||
* @param object the object to search for |
||||
* @return the number of occurrences of the object, zero if not found |
||||
*/ |
||||
@Override |
||||
public int getCount(final Object object) { |
||||
final MutableInteger count = map.get(object); |
||||
if (count != null) { |
||||
return count.value; |
||||
} |
||||
return 0; |
||||
} |
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/** |
||||
* Determines if the bag contains the given element by checking if the |
||||
* underlying map contains the element as a key. |
||||
* |
||||
* @param object the object to search for |
||||
* @return true if the bag contains the given element |
||||
*/ |
||||
@Override |
||||
public boolean contains(final Object object) { |
||||
return map.containsKey(object); |
||||
} |
||||
|
||||
/** |
||||
* Determines if the bag contains the given elements. |
||||
* |
||||
* @param coll the collection to check against |
||||
* @return <code>true</code> if the Bag contains all the collection |
||||
*/ |
||||
@Override |
||||
public boolean containsAll(final Collection<?> coll) { |
||||
if (coll instanceof Bag) { |
||||
return containsAll((Bag<?>) coll); |
||||
} |
||||
return containsAll(new HashBag<Object>(coll)); |
||||
} |
||||
|
||||
/** |
||||
* Returns <code>true</code> if the bag contains all elements in the given |
||||
* collection, respecting cardinality. |
||||
* |
||||
* @param other the bag to check against |
||||
* @return <code>true</code> if the Bag contains all the collection |
||||
*/ |
||||
boolean containsAll(final Bag<?> other) { |
||||
final Iterator<?> it = other.uniqueSet().iterator(); |
||||
while (it.hasNext()) { |
||||
final Object current = it.next(); |
||||
if (getCount(current) < other.getCount(current)) { |
||||
return false; |
||||
} |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/** |
||||
* Gets an iterator over the bag elements. Elements present in the Bag more |
||||
* than once will be returned repeatedly. |
||||
* |
||||
* @return the iterator |
||||
*/ |
||||
@Override |
||||
public Iterator<E> iterator() { |
||||
return new BagIterator<E>(this); |
||||
} |
||||
|
||||
/** |
||||
* Inner class iterator for the Bag. |
||||
*/ |
||||
static class BagIterator<E> implements Iterator<E> { |
||||
private final AbstractMapBag<E> parent; |
||||
private final Iterator<Map.Entry<E, MutableInteger>> entryIterator; |
||||
private Map.Entry<E, MutableInteger> current; |
||||
private int itemCount; |
||||
private final int mods; |
||||
private boolean canRemove; |
||||
|
||||
/** |
||||
* Constructor. |
||||
* |
||||
* @param parent the parent bag |
||||
*/ |
||||
public BagIterator(final AbstractMapBag<E> parent) { |
||||
this.parent = parent; |
||||
this.entryIterator = parent.map.entrySet().iterator(); |
||||
this.current = null; |
||||
this.mods = parent.modCount; |
||||
this.canRemove = false; |
||||
} |
||||
|
||||
/** {@inheritDoc} */ |
||||
@Override |
||||
public boolean hasNext() { |
||||
return itemCount > 0 || entryIterator.hasNext(); |
||||
} |
||||
|
||||
/** {@inheritDoc} */ |
||||
@Override |
||||
public E next() { |
||||
if (parent.modCount != mods) { |
||||
throw new ConcurrentModificationException(); |
||||
} |
||||
if (itemCount == 0) { |
||||
current = entryIterator.next(); |
||||
itemCount = current.getValue().value; |
||||
} |
||||
canRemove = true; |
||||
itemCount--; |
||||
return current.getKey(); |
||||
} |
||||
|
||||
/** {@inheritDoc} */ |
||||
@Override |
||||
public void remove() { |
||||
if (parent.modCount != mods) { |
||||
throw new ConcurrentModificationException(); |
||||
} |
||||
if (canRemove == false) { |
||||
throw new IllegalStateException(); |
||||
} |
||||
final MutableInteger mut = current.getValue(); |
||||
if (mut.value > 1) { |
||||
mut.value--; |
||||
} else { |
||||
entryIterator.remove(); |
||||
} |
||||
parent.size--; |
||||
canRemove = false; |
||||
} |
||||
} |
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/** |
||||
* Adds a new element to the bag, incrementing its count in the underlying map. |
||||
* |
||||
* @param object the object to add |
||||
* @return <code>true</code> if the object was not already in the <code>uniqueSet</code> |
||||
*/ |
||||
@Override |
||||
public boolean add(final E object) { |
||||
return add(object, 1); |
||||
} |
||||
|
||||
/** |
||||
* Adds a new element to the bag, incrementing its count in the map. |
||||
* |
||||
* @param object the object to search for |
||||
* @param nCopies the number of copies to add |
||||
* @return <code>true</code> if the object was not already in the <code>uniqueSet</code> |
||||
*/ |
||||
@Override |
||||
public boolean add(final E object, final int nCopies) { |
||||
modCount++; |
||||
if (nCopies > 0) { |
||||
final MutableInteger mut = map.get(object); |
||||
size += nCopies; |
||||
if (mut == null) { |
||||
map.put(object, new MutableInteger(nCopies)); |
||||
return true; |
||||
} |
||||
mut.value += nCopies; |
||||
return false; |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
/** |
||||
* Invokes {@link #add(Object)} for each element in the given collection. |
||||
* |
||||
* @param coll the collection to add |
||||
* @return <code>true</code> if this call changed the bag |
||||
*/ |
||||
@Override |
||||
public boolean addAll(final Collection<? extends E> coll) { |
||||
boolean changed = false; |
||||
final Iterator<? extends E> i = coll.iterator(); |
||||
while (i.hasNext()) { |
||||
final boolean added = add(i.next()); |
||||
changed = changed || added; |
||||
} |
||||
return changed; |
||||
} |
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/** |
||||
* Clears the bag by clearing the underlying map. |
||||
*/ |
||||
@Override |
||||
public void clear() { |
||||
modCount++; |
||||
map.clear(); |
||||
size = 0; |
||||
} |
||||
|
||||
/** |
||||
* Removes all copies of the specified object from the bag. |
||||
* |
||||
* @param object the object to remove |
||||
* @return true if the bag changed |
||||
*/ |
||||
@Override |
||||
public boolean remove(final Object object) { |
||||
final MutableInteger mut = map.get(object); |
||||
if (mut == null) { |
||||
return false; |
||||
} |
||||
modCount++; |
||||
map.remove(object); |
||||
size -= mut.value; |
||||
return true; |
||||
} |
||||
|
||||
/** |
||||
* Removes a specified number of copies of an object from the bag. |
||||
* |
||||
* @param object the object to remove |
||||
* @param nCopies the number of copies to remove |
||||
* @return true if the bag changed |
||||
*/ |
||||
@Override |
||||
public boolean remove(final Object object, final int nCopies) { |
||||
final MutableInteger mut = map.get(object); |
||||
if (mut == null) { |
||||
return false; |
||||
} |
||||
if (nCopies <= 0) { |
||||
return false; |
||||
} |
||||
modCount++; |
||||
if (nCopies < mut.value) { |
||||
mut.value -= nCopies; |
||||
size -= nCopies; |
||||
} else { |
||||
map.remove(object); |
||||
size -= mut.value; |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
/** |
||||
* Removes objects from the bag according to their count in the specified |
||||
* collection. |
||||
* |
||||
* @param coll the collection to use |
||||
* @return true if the bag changed |
||||
*/ |
||||
@Override |
||||
public boolean removeAll(final Collection<?> coll) { |
||||
boolean result = false; |
||||
if (coll != null) { |
||||
final Iterator<?> i = coll.iterator(); |
||||
while (i.hasNext()) { |
||||
final boolean changed = remove(i.next(), 1); |
||||
result = result || changed; |
||||
} |
||||
} |
||||
return result; |
||||
} |
||||
|
||||
/** |
||||
* Remove any members of the bag that are not in the given bag, respecting |
||||
* cardinality. |
||||
* |
||||
* @param coll the collection to retain |
||||
* @return true if this call changed the collection |
||||
*/ |
||||
@Override |
||||
public boolean retainAll(final Collection<?> coll) { |
||||
if (coll instanceof Bag) { |
||||
return retainAll((Bag<?>) coll); |
||||
} |
||||
return retainAll(new HashBag<Object>(coll)); |
||||
} |
||||
|
||||
/** |
||||
* Remove any members of the bag that are not in the given bag, respecting |
||||
* cardinality. |
||||
* @see #retainAll(Collection) |
||||
* |
||||
* @param other the bag to retain |
||||
* @return <code>true</code> if this call changed the collection |
||||
*/ |
||||
boolean retainAll(final Bag<?> other) { |
||||
boolean result = false; |
||||
final Bag<E> excess = new HashBag<E>(); |
||||
final Iterator<E> i = uniqueSet().iterator(); |
||||
while (i.hasNext()) { |
||||
final E current = i.next(); |
||||
final int myCount = getCount(current); |
||||
final int otherCount = other.getCount(current); |
||||
if (1 <= otherCount && otherCount <= myCount) { |
||||
excess.add(current, myCount - otherCount); |
||||
} else { |
||||
excess.add(current, myCount); |
||||
} |
||||
} |
||||
if (!excess.isEmpty()) { |
||||
result = removeAll(excess); |
||||
} |
||||
return result; |
||||
} |
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/** |
||||
* Mutable integer class for storing the data. |
||||
*/ |
||||
protected static class MutableInteger { |
||||
/** The value of this mutable. */ |
||||
protected int value; |
||||
|
||||
/** |
||||
* Constructor. |
||||
* @param value the initial value |
||||
*/ |
||||
MutableInteger(final int value) { |
||||
this.value = value; |
||||
} |
||||
|
||||
@Override |
||||
public boolean equals(final Object obj) { |
||||
if (obj instanceof MutableInteger == false) { |
||||
return false; |
||||
} |
||||
return ((MutableInteger) obj).value == value; |
||||
} |
||||
|
||||
@Override |
||||
public int hashCode() { |
||||
return value; |
||||
} |
||||
} |
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/** |
||||
* Returns an array of all of this bag's elements. |
||||
* |
||||
* @return an array of all of this bag's elements |
||||
*/ |
||||
@Override |
||||
public Object[] toArray() { |
||||
final Object[] result = new Object[size()]; |
||||
int i = 0; |
||||
final Iterator<E> it = map.keySet().iterator(); |
||||
while (it.hasNext()) { |
||||
final E current = it.next(); |
||||
for (int index = getCount(current); index > 0; index--) { |
||||
result[i++] = current; |
||||
} |
||||
} |
||||
return result; |
||||
} |
||||
|
||||
/** |
||||
* Returns an array of all of this bag's elements. |
||||
* If the input array has more elements than are in the bag, |
||||
* trailing elements will be set to null. |
||||
* |
||||
* @param <T> the type of the array elements |
||||
* @param array the array to populate |
||||
* @return an array of all of this bag's elements |
||||
* @throws ArrayStoreException if the runtime type of the specified array is not |
||||
* a supertype of the runtime type of the elements in this list |
||||
* @throws NullPointerException if the specified array is null |
||||
*/ |
||||
@Override |
||||
public <T> T[] toArray(T[] array) { |
||||
final int size = size(); |
||||
if (array.length < size) { |
||||
@SuppressWarnings("unchecked") // safe as both are of type T
|
||||
final T[] unchecked = (T[]) Array.newInstance(array.getClass().getComponentType(), size); |
||||
array = unchecked; |
||||
} |
||||
|
||||
int i = 0; |
||||
final Iterator<E> it = map.keySet().iterator(); |
||||
while (it.hasNext()) { |
||||
final E current = it.next(); |
||||
for (int index = getCount(current); index > 0; index--) { |
||||
// unsafe, will throw ArrayStoreException if types are not compatible, see javadoc
|
||||
@SuppressWarnings("unchecked") |
||||
final T unchecked = (T) current; |
||||
array[i++] = unchecked; |
||||
} |
||||
} |
||||
while (i < array.length) { |
||||
array[i++] = null; |
||||
} |
||||
return array; |
||||
} |
||||
|
||||
/** |
||||
* Returns an unmodifiable view of the underlying map's key set. |
||||
* |
||||
* @return the set of unique elements in this bag |
||||
*/ |
||||
@Override |
||||
public Set<E> uniqueSet() { |
||||
if (uniqueSet == null) { |
||||
uniqueSet = UnmodifiableSet.<E> unmodifiableSet(map.keySet()); |
||||
} |
||||
return uniqueSet; |
||||
} |
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/** |
||||
* Write the map out using a custom routine. |
||||
* @param out the output stream |
||||
* @throws IOException any of the usual I/O related exceptions |
||||
*/ |
||||
protected void doWriteObject(final ObjectOutputStream out) throws IOException { |
||||
out.writeInt(map.size()); |
||||
for (final Entry<E, MutableInteger> entry : map.entrySet()) { |
||||
out.writeObject(entry.getKey()); |
||||
out.writeInt(entry.getValue().value); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Read the map in using a custom routine. |
||||
* @param map the map to use |
||||
* @param in the input stream |
||||
* @throws IOException any of the usual I/O related exceptions |
||||
* @throws ClassNotFoundException if the stream contains an object which class can not be loaded |
||||
* @throws ClassCastException if the stream does not contain the correct objects |
||||
*/ |
||||
protected void doReadObject(final Map<E, MutableInteger> map, final ObjectInputStream in) |
||||
throws IOException, ClassNotFoundException { |
||||
this.map = map; |
||||
final int entrySize = in.readInt(); |
||||
for (int i = 0; i < entrySize; i++) { |
||||
@SuppressWarnings("unchecked") // This will fail at runtime if the stream is incorrect
|
||||
final E obj = (E) in.readObject(); |
||||
final int count = in.readInt(); |
||||
map.put(obj, new MutableInteger(count)); |
||||
size += count; |
||||
} |
||||
} |
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/** |
||||
* Compares this Bag to another. This Bag equals another Bag if it contains |
||||
* the same number of occurrences of the same elements. |
||||
* |
||||
* @param object the Bag to compare to |
||||
* @return true if equal |
||||
*/ |
||||
@Override |
||||
public boolean equals(final Object object) { |
||||
if (object == this) { |
||||
return true; |
||||
} |
||||
if (object instanceof Bag == false) { |
||||
return false; |
||||
} |
||||
final Bag<?> other = (Bag<?>) object; |
||||
if (other.size() != size()) { |
||||
return false; |
||||
} |
||||
for (final E element : map.keySet()) { |
||||
if (other.getCount(element) != getCount(element)) { |
||||
return false; |
||||
} |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
/** |
||||
* Gets a hash code for the Bag compatible with the definition of equals. |
||||
* The hash code is defined as the sum total of a hash code for each |
||||
* element. The per element hash code is defined as |
||||
* <code>(e==null ? 0 : e.hashCode()) ^ noOccurances)</code>. This hash code |
||||
* is compatible with the Set interface. |
||||
* |
||||
* @return the hash code of the Bag |
||||
*/ |
||||
@Override |
||||
public int hashCode() { |
||||
int total = 0; |
||||
for (final Entry<E, MutableInteger> entry : map.entrySet()) { |
||||
final E element = entry.getKey(); |
||||
final MutableInteger count = entry.getValue(); |
||||
total += (element == null ? 0 : element.hashCode()) ^ count.value; |
||||
} |
||||
return total; |
||||
} |
||||
|
||||
/** |
||||
* Implement a toString() method suitable for debugging. |
||||
* |
||||
* @return a debugging toString |
||||
*/ |
||||
@Override |
||||
public String toString() { |
||||
if (size() == 0) { |
||||
return "[]"; |
||||
} |
||||
final StringBuilder buf = new StringBuilder(); |
||||
buf.append('['); |
||||
final Iterator<E> it = uniqueSet().iterator(); |
||||
while (it.hasNext()) { |
||||
final Object current = it.next(); |
||||
final int count = getCount(current); |
||||
buf.append(count); |
||||
buf.append(':'); |
||||
buf.append(current); |
||||
if (it.hasNext()) { |
||||
buf.append(','); |
||||
} |
||||
} |
||||
buf.append(']'); |
||||
return buf.toString(); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,82 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package com.fr.third.org.apache.commons.collections4.bag; |
||||
|
||||
import java.util.Comparator; |
||||
|
||||
import com.fr.third.org.apache.commons.collections4.SortedBag; |
||||
|
||||
/** |
||||
* Decorates another <code>SortedBag</code> to provide additional behaviour. |
||||
* <p> |
||||
* Methods are forwarded directly to the decorated bag. |
||||
* |
||||
* @since 3.0 |
||||
* @version $Id: AbstractSortedBagDecorator.java 1686855 2015-06-22 13:00:27Z tn $ |
||||
*/ |
||||
public abstract class AbstractSortedBagDecorator<E> |
||||
extends AbstractBagDecorator<E> implements SortedBag<E> { |
||||
|
||||
/** Serialization version */ |
||||
private static final long serialVersionUID = -8223473624050467718L; |
||||
|
||||
/** |
||||
* Constructor only used in deserialization, do not use otherwise. |
||||
* @since 3.1 |
||||
*/ |
||||
protected AbstractSortedBagDecorator() { |
||||
super(); |
||||
} |
||||
|
||||
/** |
||||
* Constructor that wraps (not copies). |
||||
* |
||||
* @param bag the bag to decorate, must not be null |
||||
* @throws NullPointerException if bag is null |
||||
*/ |
||||
protected AbstractSortedBagDecorator(final SortedBag<E> bag) { |
||||
super(bag); |
||||
} |
||||
|
||||
/** |
||||
* Gets the bag being decorated. |
||||
* |
||||
* @return the decorated bag |
||||
*/ |
||||
@Override |
||||
protected SortedBag<E> decorated() { |
||||
return (SortedBag<E>) super.decorated(); |
||||
} |
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
@Override |
||||
public E first() { |
||||
return decorated().first(); |
||||
} |
||||
|
||||
@Override |
||||
public E last() { |
||||
return decorated().last(); |
||||
} |
||||
|
||||
@Override |
||||
public Comparator<? super E> comparator() { |
||||
return decorated().comparator(); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,243 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package com.fr.third.org.apache.commons.collections4.bag; |
||||
|
||||
import java.io.IOException; |
||||
import java.io.ObjectInputStream; |
||||
import java.io.ObjectOutputStream; |
||||
import java.util.Collection; |
||||
import java.util.Iterator; |
||||
|
||||
import com.fr.third.org.apache.commons.collections4.Bag; |
||||
|
||||
/** |
||||
* Decorates another {@link Bag} to comply with the Collection contract. |
||||
* <p> |
||||
* By decorating an existing {@link Bag} instance with a {@link CollectionBag}, |
||||
* it can be safely passed on to methods that require Collection types that |
||||
* are fully compliant with the Collection contract. |
||||
* <p> |
||||
* The method javadoc highlights the differences compared to the original Bag interface. |
||||
* |
||||
* @see Bag |
||||
* @param <E> the type held in the bag |
||||
* @since 4.0 |
||||
* @version $Id: CollectionBag.java 1686855 2015-06-22 13:00:27Z tn $ |
||||
*/ |
||||
public final class CollectionBag<E> extends AbstractBagDecorator<E> { |
||||
|
||||
/** Serialization version */ |
||||
private static final long serialVersionUID = -2560033712679053143L; |
||||
|
||||
/** |
||||
* Factory method to create a bag that complies to the Collection contract. |
||||
* |
||||
* @param <E> the type of the elements in the bag |
||||
* @param bag the bag to decorate, must not be null |
||||
* @return a Bag that complies to the Collection contract |
||||
* @throws NullPointerException if bag is null |
||||
*/ |
||||
public static <E> Bag<E> collectionBag(final Bag<E> bag) { |
||||
return new CollectionBag<E>(bag); |
||||
} |
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/** |
||||
* Constructor that wraps (not copies). |
||||
* |
||||
* @param bag the bag to decorate, must not be null |
||||
* @throws NullPointerException if bag is null |
||||
*/ |
||||
public CollectionBag(final Bag<E> bag) { |
||||
super(bag); |
||||
} |
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/** |
||||
* Write the collection out using a custom routine. |
||||
* |
||||
* @param out the output stream |
||||
* @throws IOException |
||||
*/ |
||||
private void writeObject(final ObjectOutputStream out) throws IOException { |
||||
out.defaultWriteObject(); |
||||
out.writeObject(decorated()); |
||||
} |
||||
|
||||
/** |
||||
* Read the collection in using a custom routine. |
||||
* |
||||
* @param in the input stream |
||||
* @throws IOException |
||||
* @throws ClassNotFoundException |
||||
* @throws ClassCastException if deserialised object has wrong type |
||||
*/ |
||||
@SuppressWarnings("unchecked") // will throw CCE, see Javadoc
|
||||
private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException { |
||||
in.defaultReadObject(); |
||||
setCollection((Collection<E>) in.readObject()); |
||||
} |
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// Collection interface
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
/** |
||||
* <i>(Change)</i> |
||||
* Returns <code>true</code> if the bag contains all elements in |
||||
* the given collection, <b>not</b> respecting cardinality. That is, |
||||
* if the given collection <code>coll</code> contains at least one of |
||||
* every object contained in this object. |
||||
* |
||||
* @param coll the collection to check against |
||||
* @return <code>true</code> if the Bag contains at least one of every object in the collection |
||||
*/ |
||||
@Override |
||||
public boolean containsAll(final Collection<?> coll) { |
||||
final Iterator<?> e = coll.iterator(); |
||||
while (e.hasNext()) { |
||||
if(!contains(e.next())) { |
||||
return false; |
||||
} |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
/** |
||||
* <i>(Change)</i> |
||||
* Adds one copy of the specified object to the Bag. |
||||
* <p> |
||||
* Since this method always increases the size of the bag, it |
||||
* will always return <code>true</code>. |
||||
* |
||||
* @param object the object to add |
||||
* @return <code>true</code>, always |
||||
*/ |
||||
@Override |
||||
public boolean add(final E object) { |
||||
return add(object, 1); |
||||
} |
||||
|
||||
@Override |
||||
public boolean addAll(final Collection<? extends E> coll) { |
||||
boolean changed = false; |
||||
final Iterator<? extends E> i = coll.iterator(); |
||||
while (i.hasNext()) { |
||||
final boolean added = add(i.next(), 1); |
||||
changed = changed || added; |
||||
} |
||||
return changed; |
||||
} |
||||
|
||||
/** |
||||
* <i>(Change)</i> |
||||
* Removes the first occurrence of the given object from the bag. |
||||
* <p> |
||||
* This will also remove the object from the {@link #uniqueSet()} if the |
||||
* bag contains no occurrence anymore of the object after this operation. |
||||
* |
||||
* @param object the object to remove |
||||
* @return <code>true</code> if this call changed the collection |
||||
*/ |
||||
@Override |
||||
public boolean remove(final Object object) { |
||||
return remove(object, 1); |
||||
} |
||||
|
||||
/** |
||||
* <i>(Change)</i> |
||||
* Remove all elements represented in the given collection, |
||||
* <b>not</b> respecting cardinality. That is, remove <i>all</i> |
||||
* occurrences of every object contained in the given collection. |
||||
* |
||||
* @param coll the collection to remove |
||||
* @return <code>true</code> if this call changed the collection |
||||
*/ |
||||
@Override |
||||
public boolean removeAll(final Collection<?> coll) { |
||||
if (coll != null) { |
||||
boolean result = false; |
||||
final Iterator<?> i = coll.iterator(); |
||||
while (i.hasNext()) { |
||||
final Object obj = i.next(); |
||||
final boolean changed = remove(obj, getCount(obj)); |
||||
result = result || changed; |
||||
} |
||||
return result; |
||||
} else { |
||||
// let the decorated bag handle the case of null argument
|
||||
return decorated().removeAll(null); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* <i>(Change)</i> |
||||
* Remove any members of the bag that are not in the given collection, |
||||
* <i>not</i> respecting cardinality. That is, any object in the given |
||||
* collection <code>coll</code> will be retained in the bag with the same |
||||
* number of copies prior to this operation. All other objects will be |
||||
* completely removed from this bag. |
||||
* <p> |
||||
* This implementation iterates over the elements of this bag, checking |
||||
* each element in turn to see if it's contained in <code>coll</code>. |
||||
* If it's not contained, it's removed from this bag. As a consequence, |
||||
* it is advised to use a collection type for <code>coll</code> that provides |
||||
* a fast (e.g. O(1)) implementation of {@link Collection#contains(Object)}. |
||||
* |
||||
* @param coll the collection to retain |
||||
* @return <code>true</code> if this call changed the collection |
||||
*/ |
||||
@Override |
||||
public boolean retainAll(final Collection<?> coll) { |
||||
if (coll != null) { |
||||
boolean modified = false; |
||||
final Iterator<E> e = iterator(); |
||||
while (e.hasNext()) { |
||||
if (!coll.contains(e.next())) { |
||||
e.remove(); |
||||
modified = true; |
||||
} |
||||
} |
||||
return modified; |
||||
} else { |
||||
// let the decorated bag handle the case of null argument
|
||||
return decorated().retainAll(null); |
||||
} |
||||
} |
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// Bag interface
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
/** |
||||
* <i>(Change)</i> |
||||
* Adds <code>count</code> copies of the specified object to the Bag. |
||||
* <p> |
||||
* Since this method always increases the size of the bag, it |
||||
* will always return <code>true</code>. |
||||
* |
||||
* @param object the object to add |
||||
* @param count the number of copies to add |
||||
* @return <code>true</code>, always |
||||
*/ |
||||
@Override |
||||
public boolean add(final E object, final int count) { |
||||
decorated().add(object, count); |
||||
return true; |
||||
} |
||||
|
||||
} |
@ -0,0 +1,168 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package com.fr.third.org.apache.commons.collections4.bag; |
||||
|
||||
import java.io.IOException; |
||||
import java.io.ObjectInputStream; |
||||
import java.io.ObjectOutputStream; |
||||
import java.util.Collection; |
||||
import java.util.Iterator; |
||||
|
||||
import com.fr.third.org.apache.commons.collections4.SortedBag; |
||||
|
||||
/** |
||||
* Decorates another {@link SortedBag} to comply with the Collection contract. |
||||
* |
||||
* @since 4.0 |
||||
* @version $Id: CollectionSortedBag.java 1686855 2015-06-22 13:00:27Z tn $ |
||||
*/ |
||||
public final class CollectionSortedBag<E> extends AbstractSortedBagDecorator<E> { |
||||
|
||||
/** Serialization version */ |
||||
private static final long serialVersionUID = -2560033712679053143L; |
||||
|
||||
/** |
||||
* Factory method to create a sorted bag that complies to the Collection contract. |
||||
* |
||||
* @param <E> the type of the elements in the bag |
||||
* @param bag the sorted bag to decorate, must not be null |
||||
* @return a SortedBag that complies to the Collection contract |
||||
* @throws NullPointerException if bag is null |
||||
*/ |
||||
public static <E> SortedBag<E> collectionSortedBag(final SortedBag<E> bag) { |
||||
return new CollectionSortedBag<E>(bag); |
||||
} |
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/** |
||||
* Constructor that wraps (not copies). |
||||
* |
||||
* @param bag the sorted bag to decorate, must not be null |
||||
* @throws NullPointerException if bag is null |
||||
*/ |
||||
public CollectionSortedBag(final SortedBag<E> bag) { |
||||
super(bag); |
||||
} |
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/** |
||||
* Write the collection out using a custom routine. |
||||
* |
||||
* @param out the output stream |
||||
* @throws IOException |
||||
*/ |
||||
private void writeObject(final ObjectOutputStream out) throws IOException { |
||||
out.defaultWriteObject(); |
||||
out.writeObject(decorated()); |
||||
} |
||||
|
||||
/** |
||||
* Read the collection in using a custom routine. |
||||
* |
||||
* @param in the input stream |
||||
* @throws IOException |
||||
* @throws ClassNotFoundException |
||||
* @throws ClassCastException if deserialised object has wrong type |
||||
*/ |
||||
@SuppressWarnings("unchecked") // will throw CCE, see Javadoc
|
||||
private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException { |
||||
in.defaultReadObject(); |
||||
setCollection((Collection<E>) in.readObject()); |
||||
} |
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// Collection interface
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
@Override |
||||
public boolean containsAll(final Collection<?> coll) { |
||||
final Iterator<?> e = coll.iterator(); |
||||
while (e.hasNext()) { |
||||
if(!contains(e.next())) { |
||||
return false; |
||||
} |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
@Override |
||||
public boolean add(final E object) { |
||||
return add(object, 1); |
||||
} |
||||
|
||||
@Override |
||||
public boolean addAll(final Collection<? extends E> coll) { |
||||
boolean changed = false; |
||||
final Iterator<? extends E> i = coll.iterator(); |
||||
while (i.hasNext()) { |
||||
final boolean added = add(i.next(), 1); |
||||
changed = changed || added; |
||||
} |
||||
return changed; |
||||
} |
||||
|
||||
@Override |
||||
public boolean remove(final Object object) { |
||||
return remove(object, 1); |
||||
} |
||||
|
||||
@Override |
||||
public boolean removeAll(final Collection<?> coll) { |
||||
if (coll != null) { |
||||
boolean result = false; |
||||
final Iterator<?> i = coll.iterator(); |
||||
while (i.hasNext()) { |
||||
final Object obj = i.next(); |
||||
final boolean changed = remove(obj, getCount(obj)); |
||||
result = result || changed; |
||||
} |
||||
return result; |
||||
} else { |
||||
// let the decorated bag handle the case of null argument
|
||||
return decorated().removeAll(null); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public boolean retainAll(final Collection<?> coll) { |
||||
if (coll != null) { |
||||
boolean modified = false; |
||||
final Iterator<E> e = iterator(); |
||||
while (e.hasNext()) { |
||||
if (!coll.contains(e.next())) { |
||||
e.remove(); |
||||
modified = true; |
||||
} |
||||
} |
||||
return modified; |
||||
} else { |
||||
// let the decorated bag handle the case of null argument
|
||||
return decorated().retainAll(null); |
||||
} |
||||
} |
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// Bag interface
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
@Override |
||||
public boolean add(final E object, final int count) { |
||||
decorated().add(object, count); |
||||
return true; |
||||
} |
||||
|
||||
} |
@ -0,0 +1,78 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package com.fr.third.org.apache.commons.collections4.bag; |
||||
|
||||
import java.io.IOException; |
||||
import java.io.ObjectInputStream; |
||||
import java.io.ObjectOutputStream; |
||||
import java.io.Serializable; |
||||
import java.util.Collection; |
||||
import java.util.HashMap; |
||||
|
||||
/** |
||||
* Implements {@code Bag}, using a {@link HashMap} to provide the |
||||
* data storage. This is the standard implementation of a bag. |
||||
* <p> |
||||
* A {@code Bag} stores each object in the collection together with a |
||||
* count of occurrences. Extra methods on the interface allow multiple copies |
||||
* of an object to be added or removed at once. It is important to read the |
||||
* interface javadoc carefully as several methods violate the |
||||
* {@link Collection} interface specification. |
||||
* |
||||
* @since 3.0 (previously in main package v2.0) |
||||
* @version $Id: HashBag.java 1685902 2015-06-16 20:13:13Z tn $ |
||||
*/ |
||||
public class HashBag<E> extends AbstractMapBag<E> implements Serializable { |
||||
|
||||
/** Serial version lock */ |
||||
private static final long serialVersionUID = -6561115435802554013L; |
||||
|
||||
/** |
||||
* Constructs an empty {@link HashBag}. |
||||
*/ |
||||
public HashBag() { |
||||
super(new HashMap<E, MutableInteger>()); |
||||
} |
||||
|
||||
/** |
||||
* Constructs a bag containing all the members of the given collection. |
||||
* |
||||
* @param coll a collection to copy into this bag |
||||
*/ |
||||
public HashBag(final Collection<? extends E> coll) { |
||||
this(); |
||||
addAll(coll); |
||||
} |
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/** |
||||
* Write the bag out using a custom routine. |
||||
*/ |
||||
private void writeObject(final ObjectOutputStream out) throws IOException { |
||||
out.defaultWriteObject(); |
||||
super.doWriteObject(out); |
||||
} |
||||
|
||||
/** |
||||
* Read the bag in using a custom routine. |
||||
*/ |
||||
private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException { |
||||
in.defaultReadObject(); |
||||
super.doReadObject(new HashMap<E, MutableInteger>(), in); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,126 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package com.fr.third.org.apache.commons.collections4.bag; |
||||
|
||||
import java.util.Set; |
||||
|
||||
import com.fr.third.org.apache.commons.collections4.Predicate; |
||||
import com.fr.third.org.apache.commons.collections4.Bag; |
||||
import com.fr.third.org.apache.commons.collections4.Predicate; |
||||
import com.fr.third.org.apache.commons.collections4.collection.PredicatedCollection; |
||||
|
||||
/** |
||||
* Decorates another {@link Bag} to validate that additions |
||||
* match a specified predicate. |
||||
* <p> |
||||
* This bag exists to provide validation for the decorated bag. |
||||
* It is normally created to decorate an empty bag. |
||||
* If an object cannot be added to the bag, an {@link IllegalArgumentException} is thrown. |
||||
* <p> |
||||
* One usage would be to ensure that no null entries are added to the bag. |
||||
* <pre> |
||||
* Bag bag = PredicatedBag.predicatedBag(new HashBag(), NotNullPredicate.INSTANCE); |
||||
* </pre> |
||||
* <p> |
||||
* This class is Serializable from Commons Collections 3.1. |
||||
* |
||||
* @since 3.0 |
||||
* @version $Id: PredicatedBag.java 1686855 2015-06-22 13:00:27Z tn $ |
||||
*/ |
||||
public class PredicatedBag<E> extends PredicatedCollection<E> implements Bag<E> { |
||||
|
||||
/** Serialization version */ |
||||
private static final long serialVersionUID = -2575833140344736876L; |
||||
|
||||
/** |
||||
* Factory method to create a predicated (validating) bag. |
||||
* <p> |
||||
* If there are any elements already in the bag being decorated, they |
||||
* are validated. |
||||
* |
||||
* @param <E> the type of the elements in the bag |
||||
* @param bag the bag to decorate, must not be null |
||||
* @param predicate the predicate to use for validation, must not be null |
||||
* @return a new predicated Bag |
||||
* @throws NullPointerException if bag or predicate is null |
||||
* @throws IllegalArgumentException if the bag contains invalid elements |
||||
* @since 4.0 |
||||
*/ |
||||
public static <E> PredicatedBag<E> predicatedBag(final Bag<E> bag, final Predicate<? super E> predicate) { |
||||
return new PredicatedBag<E>(bag, predicate); |
||||
} |
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/** |
||||
* Constructor that wraps (not copies). |
||||
* <p> |
||||
* If there are any elements already in the bag being decorated, they |
||||
* are validated. |
||||
* |
||||
* @param bag the bag to decorate, must not be null |
||||
* @param predicate the predicate to use for validation, must not be null |
||||
* @throws NullPointerException if bag or predicate is null |
||||
* @throws IllegalArgumentException if the bag contains invalid elements |
||||
*/ |
||||
protected PredicatedBag(final Bag<E> bag, final Predicate<? super E> predicate) { |
||||
super(bag, predicate); |
||||
} |
||||
|
||||
/** |
||||
* Gets the decorated bag. |
||||
* |
||||
* @return the decorated bag |
||||
*/ |
||||
@Override |
||||
protected Bag<E> decorated() { |
||||
return (Bag<E>) super.decorated(); |
||||
} |
||||
|
||||
@Override |
||||
public boolean equals(final Object object) { |
||||
return object == this || decorated().equals(object); |
||||
} |
||||
|
||||
@Override |
||||
public int hashCode() { |
||||
return decorated().hashCode(); |
||||
} |
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
@Override |
||||
public boolean add(final E object, final int count) { |
||||
validate(object); |
||||
return decorated().add(object, count); |
||||
} |
||||
|
||||
@Override |
||||
public boolean remove(final Object object, final int count) { |
||||
return decorated().remove(object, count); |
||||
} |
||||
|
||||
@Override |
||||
public Set<E> uniqueSet() { |
||||
return decorated().uniqueSet(); |
||||
} |
||||
|
||||
@Override |
||||
public int getCount(final Object object) { |
||||
return decorated().getCount(object); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,108 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package com.fr.third.org.apache.commons.collections4.bag; |
||||
|
||||
import java.util.Comparator; |
||||
|
||||
import com.fr.third.org.apache.commons.collections4.Predicate; |
||||
import com.fr.third.org.apache.commons.collections4.SortedBag; |
||||
|
||||
/** |
||||
* Decorates another {@link SortedBag} to validate that additions |
||||
* match a specified predicate. |
||||
* <p> |
||||
* This bag exists to provide validation for the decorated bag. |
||||
* It is normally created to decorate an empty bag. |
||||
* If an object cannot be added to the bag, an {@link IllegalArgumentException} is thrown. |
||||
* <p> |
||||
* One usage would be to ensure that no null entries are added to the bag. |
||||
* <pre> |
||||
* SortedBag bag = PredicatedSortedBag.predicatedSortedBag(new TreeBag(), NotNullPredicate.INSTANCE); |
||||
* </pre> |
||||
* <p> |
||||
* This class is Serializable from Commons Collections 3.1. |
||||
* |
||||
* @since 3.0 |
||||
* @version $Id: PredicatedSortedBag.java 1686855 2015-06-22 13:00:27Z tn $ |
||||
*/ |
||||
public class PredicatedSortedBag<E> extends PredicatedBag<E> implements SortedBag<E> { |
||||
|
||||
/** Serialization version */ |
||||
private static final long serialVersionUID = 3448581314086406616L; |
||||
|
||||
/** |
||||
* Factory method to create a predicated (validating) bag. |
||||
* <p> |
||||
* If there are any elements already in the bag being decorated, they |
||||
* are validated. |
||||
* |
||||
* @param <E> the type of the elements in the bag |
||||
* @param bag the bag to decorate, must not be null |
||||
* @param predicate the predicate to use for validation, must not be null |
||||
* @return a new predicated SortedBag |
||||
* @throws NullPointerException if bag or predicate is null |
||||
* @throws IllegalArgumentException if the bag contains invalid elements |
||||
* @since 4.0 |
||||
*/ |
||||
public static <E> PredicatedSortedBag<E> predicatedSortedBag(final SortedBag<E> bag, |
||||
final Predicate<? super E> predicate) { |
||||
return new PredicatedSortedBag<E>(bag, predicate); |
||||
} |
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/** |
||||
* Constructor that wraps (not copies). |
||||
* <p>If there are any elements already in the bag being decorated, they |
||||
* are validated. |
||||
* |
||||
* @param bag the bag to decorate, must not be null |
||||
* @param predicate the predicate to use for validation, must not be null |
||||
* @throws NullPointerException if bag or predicate is null |
||||
* @throws IllegalArgumentException if the bag contains invalid elements |
||||
*/ |
||||
protected PredicatedSortedBag(final SortedBag<E> bag, final Predicate<? super E> predicate) { |
||||
super(bag, predicate); |
||||
} |
||||
|
||||
/** |
||||
* Gets the decorated sorted bag. |
||||
* |
||||
* @return the decorated bag |
||||
*/ |
||||
@Override |
||||
protected SortedBag<E> decorated() { |
||||
return (SortedBag<E>) super.decorated(); |
||||
} |
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
@Override |
||||
public E first() { |
||||
return decorated().first(); |
||||
} |
||||
|
||||
@Override |
||||
public E last() { |
||||
return decorated().last(); |
||||
} |
||||
|
||||
@Override |
||||
public Comparator<? super E> comparator() { |
||||
return decorated().comparator(); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,151 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package com.fr.third.org.apache.commons.collections4.bag; |
||||
|
||||
import java.util.Set; |
||||
|
||||
import com.fr.third.org.apache.commons.collections4.Bag; |
||||
import com.fr.third.org.apache.commons.collections4.collection.SynchronizedCollection; |
||||
|
||||
/** |
||||
* Decorates another {@link Bag} to synchronize its behaviour |
||||
* for a multi-threaded environment. |
||||
* <p> |
||||
* Methods are synchronized, then forwarded to the decorated bag. |
||||
* Iterators must be separately synchronized around the loop. |
||||
* <p> |
||||
* This class is Serializable from Commons Collections 3.1. |
||||
* |
||||
* @since 3.0 |
||||
* @version $Id: SynchronizedBag.java 1686855 2015-06-22 13:00:27Z tn $ |
||||
*/ |
||||
public class SynchronizedBag<E> extends SynchronizedCollection<E> implements Bag<E> { |
||||
|
||||
/** Serialization version */ |
||||
private static final long serialVersionUID = 8084674570753837109L; |
||||
|
||||
/** |
||||
* Factory method to create a synchronized bag. |
||||
* |
||||
* @param <E> the type of the elements in the bag |
||||
* @param bag the bag to decorate, must not be null |
||||
* @return a new synchronized Bag |
||||
* @throws NullPointerException if bag is null |
||||
* @since 4.0 |
||||
*/ |
||||
public static <E> SynchronizedBag<E> synchronizedBag(final Bag<E> bag) { |
||||
return new SynchronizedBag<E>(bag); |
||||
} |
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/** |
||||
* Constructor that wraps (not copies). |
||||
* |
||||
* @param bag the bag to decorate, must not be null |
||||
* @throws NullPointerException if bag is null |
||||
*/ |
||||
protected SynchronizedBag(final Bag<E> bag) { |
||||
super(bag); |
||||
} |
||||
|
||||
/** |
||||
* Constructor that wraps (not copies). |
||||
* |
||||
* @param bag the bag to decorate, must not be null |
||||
* @param lock the lock to use, must not be null |
||||
* @throws NullPointerException if bag or lock is null |
||||
*/ |
||||
protected SynchronizedBag(final Bag<E> bag, final Object lock) { |
||||
super(bag, lock); |
||||
} |
||||
|
||||
/** |
||||
* Gets the bag being decorated. |
||||
* |
||||
* @return the decorated bag |
||||
*/ |
||||
protected Bag<E> getBag() { |
||||
return (Bag<E>) decorated(); |
||||
} |
||||
|
||||
@Override |
||||
public boolean equals(final Object object) { |
||||
if (object == this) { |
||||
return true; |
||||
} |
||||
synchronized (lock) { |
||||
return getBag().equals(object); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public int hashCode() { |
||||
synchronized (lock) { |
||||
return getBag().hashCode(); |
||||
} |
||||
} |
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
@Override |
||||
public boolean add(final E object, final int count) { |
||||
synchronized (lock) { |
||||
return getBag().add(object, count); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public boolean remove(final Object object, final int count) { |
||||
synchronized (lock) { |
||||
return getBag().remove(object, count); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public Set<E> uniqueSet() { |
||||
synchronized (lock) { |
||||
final Set<E> set = getBag().uniqueSet(); |
||||
return new SynchronizedBagSet(set, lock); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public int getCount(final Object object) { |
||||
synchronized (lock) { |
||||
return getBag().getCount(object); |
||||
} |
||||
} |
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/** |
||||
* Synchronized Set for the Bag class. |
||||
*/ |
||||
class SynchronizedBagSet extends SynchronizedCollection<E> implements Set<E> { |
||||
/** Serialization version */ |
||||
private static final long serialVersionUID = 2990565892366827855L; |
||||
|
||||
/** |
||||
* Constructor. |
||||
* @param set the set to decorate |
||||
* @param lock the lock to use, shared with the bag |
||||
*/ |
||||
SynchronizedBagSet(final Set<E> set, final Object lock) { |
||||
super(set, lock); |
||||
} |
||||
} |
||||
|
||||
} |
@ -0,0 +1,108 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package com.fr.third.org.apache.commons.collections4.bag; |
||||
|
||||
import java.util.Comparator; |
||||
|
||||
import com.fr.third.org.apache.commons.collections4.Bag; |
||||
import com.fr.third.org.apache.commons.collections4.SortedBag; |
||||
|
||||
/** |
||||
* Decorates another {@link SortedBag} to synchronize its behaviour |
||||
* for a multi-threaded environment. |
||||
* <p> |
||||
* Methods are synchronized, then forwarded to the decorated bag. |
||||
* Iterators must be separately synchronized around the loop. |
||||
* <p> |
||||
* This class is Serializable from Commons Collections 3.1. |
||||
* |
||||
* @since 3.0 |
||||
* @version $Id: SynchronizedSortedBag.java 1686855 2015-06-22 13:00:27Z tn $ |
||||
*/ |
||||
public class SynchronizedSortedBag<E> extends SynchronizedBag<E> implements SortedBag<E> { |
||||
|
||||
/** Serialization version */ |
||||
private static final long serialVersionUID = 722374056718497858L; |
||||
|
||||
/** |
||||
* Factory method to create a synchronized sorted bag. |
||||
* |
||||
* @param <E> the type of the elements in the bag |
||||
* @param bag the bag to decorate, must not be null |
||||
* @return a new synchronized SortedBag |
||||
* @throws NullPointerException if bag is null |
||||
* @since 4.0 |
||||
*/ |
||||
public static <E> SynchronizedSortedBag<E> synchronizedSortedBag(final SortedBag<E> bag) { |
||||
return new SynchronizedSortedBag<E>(bag); |
||||
} |
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/** |
||||
* Constructor that wraps (not copies). |
||||
* |
||||
* @param bag the bag to decorate, must not be null |
||||
* @throws NullPointerException if bag is null |
||||
*/ |
||||
protected SynchronizedSortedBag(final SortedBag<E> bag) { |
||||
super(bag); |
||||
} |
||||
|
||||
/** |
||||
* Constructor that wraps (not copies). |
||||
* |
||||
* @param bag the bag to decorate, must not be null |
||||
* @param lock the lock to use, must not be null |
||||
* @throws NullPointerException if bag or lock is null |
||||
*/ |
||||
protected SynchronizedSortedBag(final Bag<E> bag, final Object lock) { |
||||
super(bag, lock); |
||||
} |
||||
|
||||
/** |
||||
* Gets the bag being decorated. |
||||
* |
||||
* @return the decorated bag |
||||
*/ |
||||
protected SortedBag<E> getSortedBag() { |
||||
return (SortedBag<E>) decorated(); |
||||
} |
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
@Override |
||||
public synchronized E first() { |
||||
synchronized (lock) { |
||||
return getSortedBag().first(); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public synchronized E last() { |
||||
synchronized (lock) { |
||||
return getSortedBag().last(); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public synchronized Comparator<? super E> comparator() { |
||||
synchronized (lock) { |
||||
return getSortedBag().comparator(); |
||||
} |
||||
} |
||||
|
||||
} |
@ -0,0 +1,150 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package com.fr.third.org.apache.commons.collections4.bag; |
||||
|
||||
import java.util.Set; |
||||
|
||||
import com.fr.third.org.apache.commons.collections4.Transformer; |
||||
import com.fr.third.org.apache.commons.collections4.set.TransformedSet; |
||||
import com.fr.third.org.apache.commons.collections4.Bag; |
||||
import com.fr.third.org.apache.commons.collections4.Transformer; |
||||
import com.fr.third.org.apache.commons.collections4.collection.TransformedCollection; |
||||
import com.fr.third.org.apache.commons.collections4.set.TransformedSet; |
||||
|
||||
/** |
||||
* Decorates another {@link Bag} to transform objects that are added. |
||||
* <p> |
||||
* The add methods are affected by this class. |
||||
* Thus objects must be removed or searched for using their transformed form. |
||||
* For example, if the transformation converts Strings to Integers, you must |
||||
* use the Integer form to remove objects. |
||||
* <p> |
||||
* This class is Serializable from Commons Collections 3.1. |
||||
* |
||||
* @since 3.0 |
||||
* @version $Id: TransformedBag.java 1686855 2015-06-22 13:00:27Z tn $ |
||||
*/ |
||||
public class TransformedBag<E> extends TransformedCollection<E> implements Bag<E> { |
||||
|
||||
/** Serialization version */ |
||||
private static final long serialVersionUID = 5421170911299074185L; |
||||
|
||||
/** |
||||
* Factory method to create a transforming bag. |
||||
* <p> |
||||
* If there are any elements already in the bag being decorated, they |
||||
* are NOT transformed. Contrast this with {@link #transformedBag(Bag, Transformer)}. |
||||
* |
||||
* @param <E> the type of the elements in the bag |
||||
* @param bag the bag to decorate, must not be null |
||||
* @param transformer the transformer to use for conversion, must not be null |
||||
* @return a new transformed Bag |
||||
* @throws NullPointerException if bag or transformer is null |
||||
* @since 4.0 |
||||
*/ |
||||
public static <E> Bag<E> transformingBag(final Bag<E> bag, final Transformer<? super E, ? extends E> transformer) { |
||||
return new TransformedBag<E>(bag, transformer); |
||||
} |
||||
|
||||
/** |
||||
* Factory method to create a transforming bag that will transform |
||||
* existing contents of the specified bag. |
||||
* <p> |
||||
* If there are any elements already in the bag being decorated, they |
||||
* will be transformed by this method. |
||||
* Contrast this with {@link #transformingBag(Bag, Transformer)}. |
||||
* |
||||
* @param <E> the type of the elements in the bag |
||||
* @param bag the bag to decorate, must not be null |
||||
* @param transformer the transformer to use for conversion, must not be null |
||||
* @return a new transformed Bag |
||||
* @throws NullPointerException if bag or transformer is null |
||||
* @since 4.0 |
||||
*/ |
||||
public static <E> Bag<E> transformedBag(final Bag<E> bag, final Transformer<? super E, ? extends E> transformer) { |
||||
final TransformedBag<E> decorated = new TransformedBag<E>(bag, transformer); |
||||
if (bag.size() > 0) { |
||||
@SuppressWarnings("unchecked") // Bag is of type E
|
||||
final E[] values = (E[]) bag.toArray(); // NOPMD - false positive for generics
|
||||
bag.clear(); |
||||
for (final E value : values) { |
||||
decorated.decorated().add(transformer.transform(value)); |
||||
} |
||||
} |
||||
return decorated; |
||||
} |
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/** |
||||
* Constructor that wraps (not copies). |
||||
* <p> |
||||
* If there are any elements already in the bag being decorated, they |
||||
* are NOT transformed. |
||||
* |
||||
* @param bag the bag to decorate, must not be null |
||||
* @param transformer the transformer to use for conversion, must not be null |
||||
* @throws NullPointerException if bag or transformer is null |
||||
*/ |
||||
protected TransformedBag(final Bag<E> bag, final Transformer<? super E, ? extends E> transformer) { |
||||
super(bag, transformer); |
||||
} |
||||
|
||||
/** |
||||
* Gets the decorated bag. |
||||
* |
||||
* @return the decorated bag |
||||
*/ |
||||
protected Bag<E> getBag() { |
||||
return (Bag<E>) decorated(); |
||||
} |
||||
|
||||
@Override |
||||
public boolean equals(final Object object) { |
||||
return object == this || decorated().equals(object); |
||||
} |
||||
|
||||
@Override |
||||
public int hashCode() { |
||||
return decorated().hashCode(); |
||||
} |
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
@Override |
||||
public int getCount(final Object object) { |
||||
return getBag().getCount(object); |
||||
} |
||||
|
||||
@Override |
||||
public boolean remove(final Object object, final int nCopies) { |
||||
return getBag().remove(object, nCopies); |
||||
} |
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
@Override |
||||
public boolean add(final E object, final int nCopies) { |
||||
return getBag().add(transform(object), nCopies); |
||||
} |
||||
|
||||
@Override |
||||
public Set<E> uniqueSet() { |
||||
final Set<E> set = getBag().uniqueSet(); |
||||
return TransformedSet.<E>transformingSet(set, transformer); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,132 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package com.fr.third.org.apache.commons.collections4.bag; |
||||
|
||||
import java.util.Comparator; |
||||
|
||||
import com.fr.third.org.apache.commons.collections4.Transformer; |
||||
import com.fr.third.org.apache.commons.collections4.SortedBag; |
||||
import com.fr.third.org.apache.commons.collections4.Transformer; |
||||
|
||||
/** |
||||
* Decorates another {@link SortedBag} to transform objects that are added. |
||||
* <p> |
||||
* The add methods are affected by this class. |
||||
* Thus objects must be removed or searched for using their transformed form. |
||||
* For example, if the transformation converts Strings to Integers, you must |
||||
* use the Integer form to remove objects. |
||||
* <p> |
||||
* This class is Serializable from Commons Collections 3.1. |
||||
* |
||||
* @since 3.0 |
||||
* @version $Id: TransformedSortedBag.java 1686855 2015-06-22 13:00:27Z tn $ |
||||
*/ |
||||
public class TransformedSortedBag<E> extends TransformedBag<E> implements SortedBag<E> { |
||||
|
||||
/** Serialization version */ |
||||
private static final long serialVersionUID = -251737742649401930L; |
||||
|
||||
/** |
||||
* Factory method to create a transforming sorted bag. |
||||
* <p> |
||||
* If there are any elements already in the bag being decorated, they |
||||
* are NOT transformed. Contrast this with {@link #transformedSortedBag(SortedBag, Transformer)}. |
||||
* |
||||
* @param <E> the type of the elements in the bag |
||||
* @param bag the bag to decorate, must not be null |
||||
* @param transformer the transformer to use for conversion, must not be null |
||||
* @return a new transformed SortedBag |
||||
* @throws NullPointerException if bag or transformer is null |
||||
* @since 4.0 |
||||
*/ |
||||
public static <E> TransformedSortedBag<E> transformingSortedBag(final SortedBag<E> bag, |
||||
final Transformer<? super E, ? extends E> transformer) { |
||||
return new TransformedSortedBag<E>(bag, transformer); |
||||
} |
||||
|
||||
/** |
||||
* Factory method to create a transforming sorted bag that will transform |
||||
* existing contents of the specified sorted bag. |
||||
* <p> |
||||
* If there are any elements already in the bag being decorated, they |
||||
* will be transformed by this method. |
||||
* Contrast this with {@link #transformingSortedBag(SortedBag, Transformer)}. |
||||
* |
||||
* @param <E> the type of the elements in the bag |
||||
* @param bag the bag to decorate, must not be null |
||||
* @param transformer the transformer to use for conversion, must not be null |
||||
* @return a new transformed SortedBag |
||||
* @throws NullPointerException if bag or transformer is null |
||||
* @since 4.0 |
||||
*/ |
||||
public static <E> TransformedSortedBag<E> transformedSortedBag(final SortedBag<E> bag, |
||||
final Transformer<? super E, ? extends E> transformer) { |
||||
|
||||
final TransformedSortedBag<E> decorated = new TransformedSortedBag<E>(bag, transformer); |
||||
if (bag.size() > 0) { |
||||
@SuppressWarnings("unchecked") // bag is type E
|
||||
final E[] values = (E[]) bag.toArray(); // NOPMD - false positive for generics
|
||||
bag.clear(); |
||||
for (final E value : values) { |
||||
decorated.decorated().add(transformer.transform(value)); |
||||
} |
||||
} |
||||
return decorated; |
||||
} |
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/** |
||||
* Constructor that wraps (not copies). |
||||
* <p> |
||||
* If there are any elements already in the bag being decorated, they |
||||
* are NOT transformed. |
||||
* |
||||
* @param bag the bag to decorate, must not be null |
||||
* @param transformer the transformer to use for conversion, must not be null |
||||
* @throws NullPointerException if bag or transformer is null |
||||
*/ |
||||
protected TransformedSortedBag(final SortedBag<E> bag, final Transformer<? super E, ? extends E> transformer) { |
||||
super(bag, transformer); |
||||
} |
||||
|
||||
/** |
||||
* Gets the decorated bag. |
||||
* |
||||
* @return the decorated bag |
||||
*/ |
||||
protected SortedBag<E> getSortedBag() { |
||||
return (SortedBag<E>) decorated(); |
||||
} |
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
@Override |
||||
public E first() { |
||||
return getSortedBag().first(); |
||||
} |
||||
|
||||
@Override |
||||
public E last() { |
||||
return getSortedBag().last(); |
||||
} |
||||
|
||||
@Override |
||||
public Comparator<? super E> comparator() { |
||||
return getSortedBag().comparator(); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,140 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package com.fr.third.org.apache.commons.collections4.bag; |
||||
|
||||
import java.io.IOException; |
||||
import java.io.ObjectInputStream; |
||||
import java.io.ObjectOutputStream; |
||||
import java.io.Serializable; |
||||
import java.util.Collection; |
||||
import java.util.Comparator; |
||||
import java.util.SortedMap; |
||||
import java.util.TreeMap; |
||||
|
||||
import com.fr.third.org.apache.commons.collections4.SortedBag; |
||||
|
||||
/** |
||||
* Implements {@link SortedBag}, using a {@link TreeMap} to provide the data storage. |
||||
* This is the standard implementation of a sorted bag. |
||||
* <p> |
||||
* Order will be maintained among the bag members and can be viewed through the iterator. |
||||
* <p> |
||||
* A {@link org.apache.commons.collections4.Bag Bag} stores each object in the collection |
||||
* together with a count of occurrences. Extra methods on the interface allow multiple |
||||
* copies of an object to be added or removed at once. It is important to read the interface
|
||||
* javadoc carefully as several methods violate the {@link Collection} interface specification. |
||||
* |
||||
* @since 3.0 (previously in main package v2.0) |
||||
* @version $Id: TreeBag.java 1683951 2015-06-06 20:19:03Z tn $ |
||||
*/ |
||||
public class TreeBag<E> extends AbstractMapBag<E> implements SortedBag<E>, Serializable { |
||||
|
||||
/** Serial version lock */ |
||||
private static final long serialVersionUID = -7740146511091606676L; |
||||
|
||||
/** |
||||
* Constructs an empty {@link TreeBag}. |
||||
*/ |
||||
public TreeBag() { |
||||
super(new TreeMap<E, MutableInteger>()); |
||||
} |
||||
|
||||
/** |
||||
* Constructs an empty bag that maintains order on its unique representative |
||||
* members according to the given {@link Comparator}. |
||||
* |
||||
* @param comparator the comparator to use |
||||
*/ |
||||
public TreeBag(final Comparator<? super E> comparator) { |
||||
super(new TreeMap<E, MutableInteger>(comparator)); |
||||
} |
||||
|
||||
/** |
||||
* Constructs a {@link TreeBag} containing all the members of the |
||||
* specified collection. |
||||
* |
||||
* @param coll the collection to copy into the bag |
||||
*/ |
||||
public TreeBag(final Collection<? extends E> coll) { |
||||
this(); |
||||
addAll(coll); |
||||
} |
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/** |
||||
* {@inheritDoc} |
||||
* |
||||
* @throws IllegalArgumentException if the object to be added does not implement |
||||
* {@link Comparable} and the {@link TreeBag} is using natural ordering |
||||
* @throws NullPointerException if the specified key is null and this bag uses |
||||
* natural ordering, or its comparator does not permit null keys |
||||
*/ |
||||
@Override |
||||
public boolean add(final E object) { |
||||
if(comparator() == null && !(object instanceof Comparable)) { |
||||
if (object == null) { |
||||
throw new NullPointerException(); |
||||
} |
||||
throw new IllegalArgumentException("Objects of type " + object.getClass() + " cannot be added to " + |
||||
"a naturally ordered TreeBag as it does not implement Comparable"); |
||||
} |
||||
return super.add(object); |
||||
} |
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
@Override |
||||
public E first() { |
||||
return getMap().firstKey(); |
||||
} |
||||
|
||||
@Override |
||||
public E last() { |
||||
return getMap().lastKey(); |
||||
} |
||||
|
||||
@Override |
||||
public Comparator<? super E> comparator() { |
||||
return getMap().comparator(); |
||||
} |
||||
|
||||
@Override |
||||
protected SortedMap<E, AbstractMapBag.MutableInteger> getMap() { |
||||
return (SortedMap<E, AbstractMapBag.MutableInteger>) super.getMap(); |
||||
} |
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/** |
||||
* Write the bag out using a custom routine. |
||||
*/ |
||||
private void writeObject(final ObjectOutputStream out) throws IOException { |
||||
out.defaultWriteObject(); |
||||
out.writeObject(comparator()); |
||||
super.doWriteObject(out); |
||||
} |
||||
|
||||
/** |
||||
* Read the bag in using a custom routine. |
||||
*/ |
||||
private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException { |
||||
in.defaultReadObject(); |
||||
@SuppressWarnings("unchecked") // This will fail at runtime if the stream is incorrect
|
||||
final Comparator<? super E> comp = (Comparator<? super E>) in.readObject(); |
||||
super.doReadObject(new TreeMap<E, MutableInteger>(comp), in); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,159 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package com.fr.third.org.apache.commons.collections4.bag; |
||||
|
||||
import java.io.IOException; |
||||
import java.io.ObjectInputStream; |
||||
import java.io.ObjectOutputStream; |
||||
import java.util.Collection; |
||||
import java.util.Iterator; |
||||
import java.util.Set; |
||||
|
||||
import com.fr.third.org.apache.commons.collections4.set.UnmodifiableSet; |
||||
import com.fr.third.org.apache.commons.collections4.Bag; |
||||
import com.fr.third.org.apache.commons.collections4.Unmodifiable; |
||||
import com.fr.third.org.apache.commons.collections4.iterators.UnmodifiableIterator; |
||||
import com.fr.third.org.apache.commons.collections4.set.UnmodifiableSet; |
||||
|
||||
/** |
||||
* Decorates another {@link Bag} to ensure it can't be altered. |
||||
* <p> |
||||
* This class is Serializable from Commons Collections 3.1. |
||||
* <p> |
||||
* Attempts to modify it will result in an UnsupportedOperationException. |
||||
* |
||||
* @since 3.0 |
||||
* @version $Id: UnmodifiableBag.java 1686855 2015-06-22 13:00:27Z tn $ |
||||
*/ |
||||
public final class UnmodifiableBag<E> |
||||
extends AbstractBagDecorator<E> implements Unmodifiable { |
||||
|
||||
/** Serialization version */ |
||||
private static final long serialVersionUID = -1873799975157099624L; |
||||
|
||||
/** |
||||
* Factory method to create an unmodifiable bag. |
||||
* <p> |
||||
* If the bag passed in is already unmodifiable, it is returned. |
||||
* |
||||
* @param <E> the type of the elements in the bag |
||||
* @param bag the bag to decorate, must not be null |
||||
* @return an unmodifiable Bag |
||||
* @throws NullPointerException if bag is null |
||||
* @since 4.0 |
||||
*/ |
||||
public static <E> Bag<E> unmodifiableBag(final Bag<? extends E> bag) { |
||||
if (bag instanceof Unmodifiable) { |
||||
@SuppressWarnings("unchecked") // safe to upcast
|
||||
final Bag<E> tmpBag = (Bag<E>) bag; |
||||
return tmpBag; |
||||
} |
||||
return new UnmodifiableBag<E>(bag); |
||||
} |
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/** |
||||
* Constructor that wraps (not copies). |
||||
* |
||||
* @param bag the bag to decorate, must not be null |
||||
* @throws NullPointerException if bag is null |
||||
*/ |
||||
@SuppressWarnings("unchecked") // safe to upcast
|
||||
private UnmodifiableBag(final Bag<? extends E> bag) { |
||||
super((Bag<E>) bag); |
||||
} |
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/** |
||||
* Write the collection out using a custom routine. |
||||
* |
||||
* @param out the output stream |
||||
* @throws IOException |
||||
*/ |
||||
private void writeObject(final ObjectOutputStream out) throws IOException { |
||||
out.defaultWriteObject(); |
||||
out.writeObject(decorated()); |
||||
} |
||||
|
||||
/** |
||||
* Read the collection in using a custom routine. |
||||
* |
||||
* @param in the input stream |
||||
* @throws IOException |
||||
* @throws ClassNotFoundException |
||||
* @throws ClassCastException if deserialised object has wrong type |
||||
*/ |
||||
@SuppressWarnings("unchecked") // will throw CCE, see Javadoc
|
||||
private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException { |
||||
in.defaultReadObject(); |
||||
setCollection((Collection<E>) in.readObject()); |
||||
} |
||||
|
||||
//-----------------------------------------------------------------------
|
||||
@Override |
||||
public Iterator<E> iterator() { |
||||
return UnmodifiableIterator.<E> unmodifiableIterator(decorated().iterator()); |
||||
} |
||||
|
||||
@Override |
||||
public boolean add(final E object) { |
||||
throw new UnsupportedOperationException(); |
||||
} |
||||
|
||||
@Override |
||||
public boolean addAll(final Collection<? extends E> coll) { |
||||
throw new UnsupportedOperationException(); |
||||
} |
||||
|
||||
@Override |
||||
public void clear() { |
||||
throw new UnsupportedOperationException(); |
||||
} |
||||
|
||||
@Override |
||||
public boolean remove(final Object object) { |
||||
throw new UnsupportedOperationException(); |
||||
} |
||||
|
||||
@Override |
||||
public boolean removeAll(final Collection<?> coll) { |
||||
throw new UnsupportedOperationException(); |
||||
} |
||||
|
||||
@Override |
||||
public boolean retainAll(final Collection<?> coll) { |
||||
throw new UnsupportedOperationException(); |
||||
} |
||||
|
||||
//-----------------------------------------------------------------------
|
||||
@Override |
||||
public boolean add(final E object, final int count) { |
||||
throw new UnsupportedOperationException(); |
||||
} |
||||
|
||||
@Override |
||||
public boolean remove(final Object object, final int count) { |
||||
throw new UnsupportedOperationException(); |
||||
} |
||||
|
||||
@Override |
||||
public Set<E> uniqueSet() { |
||||
final Set<E> set = decorated().uniqueSet(); |
||||
return UnmodifiableSet.<E> unmodifiableSet(set); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,156 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package com.fr.third.org.apache.commons.collections4.bag; |
||||
|
||||
import java.io.IOException; |
||||
import java.io.ObjectInputStream; |
||||
import java.io.ObjectOutputStream; |
||||
import java.util.Collection; |
||||
import java.util.Iterator; |
||||
import java.util.Set; |
||||
|
||||
import com.fr.third.org.apache.commons.collections4.set.UnmodifiableSet; |
||||
import com.fr.third.org.apache.commons.collections4.SortedBag; |
||||
import com.fr.third.org.apache.commons.collections4.Unmodifiable; |
||||
import com.fr.third.org.apache.commons.collections4.iterators.UnmodifiableIterator; |
||||
import com.fr.third.org.apache.commons.collections4.set.UnmodifiableSet; |
||||
|
||||
/** |
||||
* Decorates another {@link SortedBag} to ensure it can't be altered. |
||||
* <p> |
||||
* This class is Serializable from Commons Collections 3.1. |
||||
* <p> |
||||
* Attempts to modify it will result in an UnsupportedOperationException. |
||||
* |
||||
* @since 3.0 |
||||
* @version $Id: UnmodifiableSortedBag.java 1686855 2015-06-22 13:00:27Z tn $ |
||||
*/ |
||||
public final class UnmodifiableSortedBag<E> |
||||
extends AbstractSortedBagDecorator<E> implements Unmodifiable { |
||||
|
||||
/** Serialization version */ |
||||
private static final long serialVersionUID = -3190437252665717841L; |
||||
|
||||
/** |
||||
* Factory method to create an unmodifiable bag. |
||||
* <p> |
||||
* If the bag passed in is already unmodifiable, it is returned. |
||||
* |
||||
* @param <E> the type of the elements in the bag |
||||
* @param bag the bag to decorate, must not be null |
||||
* @return an unmodifiable SortedBag |
||||
* @throws NullPointerException if bag is null |
||||
* @since 4.0 |
||||
*/ |
||||
public static <E> SortedBag<E> unmodifiableSortedBag(final SortedBag<E> bag) { |
||||
if (bag instanceof Unmodifiable) { |
||||
return bag; |
||||
} |
||||
return new UnmodifiableSortedBag<E>(bag); |
||||
} |
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/** |
||||
* Constructor that wraps (not copies). |
||||
* |
||||
* @param bag the bag to decorate, must not be null |
||||
* @throws NullPointerException if bag is null |
||||
*/ |
||||
private UnmodifiableSortedBag(final SortedBag<E> bag) { |
||||
super(bag); |
||||
} |
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/** |
||||
* Write the collection out using a custom routine. |
||||
* |
||||
* @param out the output stream |
||||
* @throws IOException |
||||
*/ |
||||
private void writeObject(final ObjectOutputStream out) throws IOException { |
||||
out.defaultWriteObject(); |
||||
out.writeObject(decorated()); |
||||
} |
||||
|
||||
/** |
||||
* Read the collection in using a custom routine. |
||||
* |
||||
* @param in the input stream |
||||
* @throws IOException |
||||
* @throws ClassNotFoundException |
||||
* @throws ClassCastException if deserialised object has wrong type |
||||
*/ |
||||
@SuppressWarnings("unchecked") // will throw CCE, see Javadoc
|
||||
private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException { |
||||
in.defaultReadObject(); |
||||
setCollection((Collection<E>) in.readObject()); |
||||
} |
||||
|
||||
//-----------------------------------------------------------------------
|
||||
@Override |
||||
public Iterator<E> iterator() { |
||||
return UnmodifiableIterator.unmodifiableIterator(decorated().iterator()); |
||||
} |
||||
|
||||
@Override |
||||
public boolean add(final E object) { |
||||
throw new UnsupportedOperationException(); |
||||
} |
||||
|
||||
@Override |
||||
public boolean addAll(final Collection<? extends E> coll) { |
||||
throw new UnsupportedOperationException(); |
||||
} |
||||
|
||||
@Override |
||||
public void clear() { |
||||
throw new UnsupportedOperationException(); |
||||
} |
||||
|
||||
@Override |
||||
public boolean remove(final Object object) { |
||||
throw new UnsupportedOperationException(); |
||||
} |
||||
|
||||
@Override |
||||
public boolean removeAll(final Collection<?> coll) { |
||||
throw new UnsupportedOperationException(); |
||||
} |
||||
|
||||
@Override |
||||
public boolean retainAll(final Collection<?> coll) { |
||||
throw new UnsupportedOperationException(); |
||||
} |
||||
|
||||
//-----------------------------------------------------------------------
|
||||
@Override |
||||
public boolean add(final E object, final int count) { |
||||
throw new UnsupportedOperationException(); |
||||
} |
||||
|
||||
@Override |
||||
public boolean remove(final Object object, final int count) { |
||||
throw new UnsupportedOperationException(); |
||||
} |
||||
|
||||
@Override |
||||
public Set<E> uniqueSet() { |
||||
final Set<E> set = decorated().uniqueSet(); |
||||
return UnmodifiableSet.unmodifiableSet(set); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,39 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
/** |
||||
* This package contains implementations of the {@link org.apache.commons.collections4.Bag Bag} and |
||||
* {@link org.apache.commons.collections4.SortedBag SortedBag} interfaces. |
||||
* A bag stores an object and a count of the number of occurrences of the object. |
||||
* <p> |
||||
* The following implementations are provided in the package: |
||||
* <ul> |
||||
* <li>HashBag - implementation that uses a HashMap to store the data |
||||
* <li>TreeBag - implementation that uses a TreeMap to store the data |
||||
* </ul> |
||||
* <p> |
||||
* The following decorators are provided in the package: |
||||
* <ul> |
||||
* <li>Synchronized - synchronizes method access for multi-threaded environments |
||||
* <li>Unmodifiable - ensures the bag cannot be altered |
||||
* <li>Predicated - ensures that only elements that are valid according to a predicate can be added |
||||
* <li>Transformed - transforms each element added to the bag |
||||
* <li>Collection - ensures compliance with the java.util.Collection contract |
||||
* </ul> |
||||
* |
||||
* @version $Id: package-info.java 1540804 2013-11-11 18:58:31Z tn $ |
||||
*/ |
||||
package com.fr.third.org.apache.commons.collections4.bag; |
@ -0,0 +1,89 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package com.fr.third.org.apache.commons.collections4.bidimap; |
||||
|
||||
import java.util.Set; |
||||
|
||||
import com.fr.third.org.apache.commons.collections4.BidiMap; |
||||
import com.fr.third.org.apache.commons.collections4.MapIterator; |
||||
import com.fr.third.org.apache.commons.collections4.map.AbstractMapDecorator; |
||||
|
||||
/** |
||||
* Provides a base decorator that enables additional functionality to be added |
||||
* to a BidiMap via decoration. |
||||
* <p> |
||||
* Methods are forwarded directly to the decorated map. |
||||
* <p> |
||||
* This implementation does not perform any special processing with the map views. |
||||
* Instead it simply returns the set/collection from the wrapped map. This may be |
||||
* undesirable, for example if you are trying to write a validating implementation |
||||
* it would provide a loophole around the validation. |
||||
* But, you might want that loophole, so this class is kept simple. |
||||
* |
||||
* @since 3.0 |
||||
* @version $Id: AbstractBidiMapDecorator.java 1686855 2015-06-22 13:00:27Z tn $ |
||||
*/ |
||||
public abstract class AbstractBidiMapDecorator<K, V> |
||||
extends AbstractMapDecorator<K, V> implements BidiMap<K, V> { |
||||
|
||||
/** |
||||
* Constructor that wraps (not copies). |
||||
* |
||||
* @param map the map to decorate, must not be null |
||||
* @throws NullPointerException if the collection is null |
||||
*/ |
||||
protected AbstractBidiMapDecorator(final BidiMap<K, V> map) { |
||||
super(map); |
||||
} |
||||
|
||||
/** |
||||
* Gets the map being decorated. |
||||
* |
||||
* @return the decorated map |
||||
*/ |
||||
@Override |
||||
protected BidiMap<K, V> decorated() { |
||||
return (BidiMap<K, V>) super.decorated(); |
||||
} |
||||
|
||||
//-----------------------------------------------------------------------
|
||||
@Override |
||||
public MapIterator<K, V> mapIterator() { |
||||
return decorated().mapIterator(); |
||||
} |
||||
|
||||
@Override |
||||
public K getKey(final Object value) { |
||||
return decorated().getKey(value); |
||||
} |
||||
|
||||
@Override |
||||
public K removeValue(final Object value) { |
||||
return decorated().removeValue(value); |
||||
} |
||||
|
||||
@Override |
||||
public BidiMap<V, K> inverseBidiMap() { |
||||
return decorated().inverseBidiMap(); |
||||
} |
||||
|
||||
@Override |
||||
public Set<V> values() { |
||||
return decorated().values(); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,806 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package com.fr.third.org.apache.commons.collections4.bidimap; |
||||
|
||||
import java.util.Collection; |
||||
import java.util.Iterator; |
||||
import java.util.Map; |
||||
import java.util.Set; |
||||
|
||||
import com.fr.third.org.apache.commons.collections4.keyvalue.AbstractMapEntryDecorator; |
||||
import com.fr.third.org.apache.commons.collections4.BidiMap; |
||||
import com.fr.third.org.apache.commons.collections4.MapIterator; |
||||
import com.fr.third.org.apache.commons.collections4.ResettableIterator; |
||||
import com.fr.third.org.apache.commons.collections4.collection.AbstractCollectionDecorator; |
||||
import com.fr.third.org.apache.commons.collections4.iterators.AbstractIteratorDecorator; |
||||
import com.fr.third.org.apache.commons.collections4.keyvalue.AbstractMapEntryDecorator; |
||||
|
||||
/** |
||||
* Abstract {@link BidiMap} implemented using two maps. |
||||
* <p> |
||||
* An implementation can be written simply by implementing the |
||||
* {@link #createBidiMap(Map, Map, BidiMap)} method. |
||||
* |
||||
* @see DualHashBidiMap |
||||
* @see DualTreeBidiMap |
||||
* @since 3.0 |
||||
* @version $Id: AbstractDualBidiMap.java 1683951 2015-06-06 20:19:03Z tn $ |
||||
*/ |
||||
public abstract class AbstractDualBidiMap<K, V> implements BidiMap<K, V> { |
||||
|
||||
/** |
||||
* Normal delegate map. |
||||
*/ |
||||
transient Map<K, V> normalMap; |
||||
|
||||
/** |
||||
* Reverse delegate map. |
||||
*/ |
||||
transient Map<V, K> reverseMap; |
||||
|
||||
/** |
||||
* Inverse view of this map. |
||||
*/ |
||||
transient BidiMap<V, K> inverseBidiMap = null; |
||||
|
||||
/** |
||||
* View of the keys. |
||||
*/ |
||||
transient Set<K> keySet = null; |
||||
|
||||
/** |
||||
* View of the values. |
||||
*/ |
||||
transient Set<V> values = null; |
||||
|
||||
/** |
||||
* View of the entries. |
||||
*/ |
||||
transient Set<Map.Entry<K, V>> entrySet = null; |
||||
|
||||
/** |
||||
* Creates an empty map, initialised by <code>createMap</code>. |
||||
* <p> |
||||
* This constructor remains in place for deserialization. |
||||
* All other usage is deprecated in favour of |
||||
* {@link #AbstractDualBidiMap(Map, Map)}. |
||||
*/ |
||||
protected AbstractDualBidiMap() { |
||||
super(); |
||||
} |
||||
|
||||
/** |
||||
* Creates an empty map using the two maps specified as storage. |
||||
* <p> |
||||
* The two maps must be a matching pair, normal and reverse. |
||||
* They will typically both be empty. |
||||
* <p> |
||||
* Neither map is validated, so nulls may be passed in. |
||||
* If you choose to do this then the subclass constructor must populate |
||||
* the <code>maps[]</code> instance variable itself. |
||||
* |
||||
* @param normalMap the normal direction map |
||||
* @param reverseMap the reverse direction map |
||||
* @since 3.1 |
||||
*/ |
||||
protected AbstractDualBidiMap(final Map<K, V> normalMap, final Map<V, K> reverseMap) { |
||||
super(); |
||||
this.normalMap = normalMap; |
||||
this.reverseMap = reverseMap; |
||||
} |
||||
|
||||
/** |
||||
* Constructs a map that decorates the specified maps, |
||||
* used by the subclass <code>createBidiMap</code> implementation. |
||||
* |
||||
* @param normalMap the normal direction map |
||||
* @param reverseMap the reverse direction map |
||||
* @param inverseBidiMap the inverse BidiMap |
||||
*/ |
||||
protected AbstractDualBidiMap(final Map<K, V> normalMap, final Map<V, K> reverseMap, |
||||
final BidiMap<V, K> inverseBidiMap) { |
||||
super(); |
||||
this.normalMap = normalMap; |
||||
this.reverseMap = reverseMap; |
||||
this.inverseBidiMap = inverseBidiMap; |
||||
} |
||||
|
||||
/** |
||||
* Creates a new instance of the subclass. |
||||
* |
||||
* @param normalMap the normal direction map |
||||
* @param reverseMap the reverse direction map |
||||
* @param inverseMap this map, which is the inverse in the new map |
||||
* @return the inverse map |
||||
*/ |
||||
protected abstract BidiMap<V, K> createBidiMap(Map<V, K> normalMap, Map<K, V> reverseMap, BidiMap<K, V> inverseMap); |
||||
|
||||
// Map delegation
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
@Override |
||||
public V get(final Object key) { |
||||
return normalMap.get(key); |
||||
} |
||||
|
||||
@Override |
||||
public int size() { |
||||
return normalMap.size(); |
||||
} |
||||
|
||||
@Override |
||||
public boolean isEmpty() { |
||||
return normalMap.isEmpty(); |
||||
} |
||||
|
||||
@Override |
||||
public boolean containsKey(final Object key) { |
||||
return normalMap.containsKey(key); |
||||
} |
||||
|
||||
@Override |
||||
public boolean equals(final Object obj) { |
||||
return normalMap.equals(obj); |
||||
} |
||||
|
||||
@Override |
||||
public int hashCode() { |
||||
return normalMap.hashCode(); |
||||
} |
||||
|
||||
@Override |
||||
public String toString() { |
||||
return normalMap.toString(); |
||||
} |
||||
|
||||
// BidiMap changes
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
@Override |
||||
public V put(final K key, final V value) { |
||||
if (normalMap.containsKey(key)) { |
||||
reverseMap.remove(normalMap.get(key)); |
||||
} |
||||
if (reverseMap.containsKey(value)) { |
||||
normalMap.remove(reverseMap.get(value)); |
||||
} |
||||
final V obj = normalMap.put(key, value); |
||||
reverseMap.put(value, key); |
||||
return obj; |
||||
} |
||||
|
||||
@Override |
||||
public void putAll(final Map<? extends K, ? extends V> map) { |
||||
for (final Map.Entry<? extends K, ? extends V> entry : map.entrySet()) { |
||||
put(entry.getKey(), entry.getValue()); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public V remove(final Object key) { |
||||
V value = null; |
||||
if (normalMap.containsKey(key)) { |
||||
value = normalMap.remove(key); |
||||
reverseMap.remove(value); |
||||
} |
||||
return value; |
||||
} |
||||
|
||||
@Override |
||||
public void clear() { |
||||
normalMap.clear(); |
||||
reverseMap.clear(); |
||||
} |
||||
|
||||
@Override |
||||
public boolean containsValue(final Object value) { |
||||
return reverseMap.containsKey(value); |
||||
} |
||||
|
||||
// BidiMap
|
||||
//-----------------------------------------------------------------------
|
||||
/** |
||||
* Obtains a <code>MapIterator</code> over the map. |
||||
* The iterator implements <code>ResetableMapIterator</code>. |
||||
* This implementation relies on the entrySet iterator. |
||||
* <p> |
||||
* The setValue() methods only allow a new value to be set. |
||||
* If the value being set is already in the map, an IllegalArgumentException |
||||
* is thrown (as setValue cannot change the size of the map). |
||||
* |
||||
* @return a map iterator |
||||
*/ |
||||
@Override |
||||
public MapIterator<K, V> mapIterator() { |
||||
return new BidiMapIterator<K, V>(this); |
||||
} |
||||
|
||||
@Override |
||||
public K getKey(final Object value) { |
||||
return reverseMap.get(value); |
||||
} |
||||
|
||||
@Override |
||||
public K removeValue(final Object value) { |
||||
K key = null; |
||||
if (reverseMap.containsKey(value)) { |
||||
key = reverseMap.remove(value); |
||||
normalMap.remove(key); |
||||
} |
||||
return key; |
||||
} |
||||
|
||||
@Override |
||||
public BidiMap<V, K> inverseBidiMap() { |
||||
if (inverseBidiMap == null) { |
||||
inverseBidiMap = createBidiMap(reverseMap, normalMap, this); |
||||
} |
||||
return inverseBidiMap; |
||||
} |
||||
|
||||
// Map views
|
||||
//-----------------------------------------------------------------------
|
||||
/** |
||||
* Gets a keySet view of the map. |
||||
* Changes made on the view are reflected in the map. |
||||
* The set supports remove and clear but not add. |
||||
* |
||||
* @return the keySet view |
||||
*/ |
||||
@Override |
||||
public Set<K> keySet() { |
||||
if (keySet == null) { |
||||
keySet = new KeySet<K>(this); |
||||
} |
||||
return keySet; |
||||
} |
||||
|
||||
/** |
||||
* Creates a key set iterator. |
||||
* Subclasses can override this to return iterators with different properties. |
||||
* |
||||
* @param iterator the iterator to decorate |
||||
* @return the keySet iterator |
||||
*/ |
||||
protected Iterator<K> createKeySetIterator(final Iterator<K> iterator) { |
||||
return new KeySetIterator<K>(iterator, this); |
||||
} |
||||
|
||||
/** |
||||
* Gets a values view of the map. |
||||
* Changes made on the view are reflected in the map. |
||||
* The set supports remove and clear but not add. |
||||
* |
||||
* @return the values view |
||||
*/ |
||||
@Override |
||||
public Set<V> values() { |
||||
if (values == null) { |
||||
values = new Values<V>(this); |
||||
} |
||||
return values; |
||||
} |
||||
|
||||
/** |
||||
* Creates a values iterator. |
||||
* Subclasses can override this to return iterators with different properties. |
||||
* |
||||
* @param iterator the iterator to decorate |
||||
* @return the values iterator |
||||
*/ |
||||
protected Iterator<V> createValuesIterator(final Iterator<V> iterator) { |
||||
return new ValuesIterator<V>(iterator, this); |
||||
} |
||||
|
||||
/** |
||||
* Gets an entrySet view of the map. |
||||
* Changes made on the set are reflected in the map. |
||||
* The set supports remove and clear but not add. |
||||
* <p> |
||||
* The Map Entry setValue() method only allow a new value to be set. |
||||
* If the value being set is already in the map, an IllegalArgumentException |
||||
* is thrown (as setValue cannot change the size of the map). |
||||
* |
||||
* @return the entrySet view |
||||
*/ |
||||
@Override |
||||
public Set<Map.Entry<K, V>> entrySet() { |
||||
if (entrySet == null) { |
||||
entrySet = new EntrySet<K, V>(this); |
||||
} |
||||
return entrySet; |
||||
} |
||||
|
||||
/** |
||||
* Creates an entry set iterator. |
||||
* Subclasses can override this to return iterators with different properties. |
||||
* |
||||
* @param iterator the iterator to decorate |
||||
* @return the entrySet iterator |
||||
*/ |
||||
protected Iterator<Map.Entry<K, V>> createEntrySetIterator(final Iterator<Map.Entry<K, V>> iterator) { |
||||
return new EntrySetIterator<K, V>(iterator, this); |
||||
} |
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/** |
||||
* Inner class View. |
||||
*/ |
||||
protected static abstract class View<K, V, E> extends AbstractCollectionDecorator<E> { |
||||
|
||||
/** Generated serial version ID. */ |
||||
private static final long serialVersionUID = 4621510560119690639L; |
||||
|
||||
/** The parent map */ |
||||
protected final AbstractDualBidiMap<K, V> parent; |
||||
|
||||
/** |
||||
* Constructs a new view of the BidiMap. |
||||
* |
||||
* @param coll the collection view being decorated |
||||
* @param parent the parent BidiMap |
||||
*/ |
||||
protected View(final Collection<E> coll, final AbstractDualBidiMap<K, V> parent) { |
||||
super(coll); |
||||
this.parent = parent; |
||||
} |
||||
|
||||
@Override |
||||
public boolean equals(final Object object) { |
||||
return object == this || decorated().equals(object); |
||||
} |
||||
|
||||
@Override |
||||
public int hashCode() { |
||||
return decorated().hashCode(); |
||||
} |
||||
|
||||
@Override |
||||
public boolean removeAll(final Collection<?> coll) { |
||||
if (parent.isEmpty() || coll.isEmpty()) { |
||||
return false; |
||||
} |
||||
boolean modified = false; |
||||
final Iterator<?> it = coll.iterator(); |
||||
while (it.hasNext()) { |
||||
modified |= remove(it.next()); |
||||
} |
||||
return modified; |
||||
} |
||||
|
||||
/** |
||||
* {@inheritDoc} |
||||
* <p> |
||||
* This implementation iterates over the elements of this bidi map, checking each element in |
||||
* turn to see if it's contained in <code>coll</code>. If it's not contained, it's removed |
||||
* from this bidi map. As a consequence, it is advised to use a collection type for |
||||
* <code>coll</code> that provides a fast (e.g. O(1)) implementation of |
||||
* {@link Collection#contains(Object)}. |
||||
*/ |
||||
@Override |
||||
public boolean retainAll(final Collection<?> coll) { |
||||
if (parent.isEmpty()) { |
||||
return false; |
||||
} |
||||
if (coll.isEmpty()) { |
||||
parent.clear(); |
||||
return true; |
||||
} |
||||
boolean modified = false; |
||||
final Iterator<E> it = iterator(); |
||||
while (it.hasNext()) { |
||||
if (coll.contains(it.next()) == false) { |
||||
it.remove(); |
||||
modified = true; |
||||
} |
||||
} |
||||
return modified; |
||||
} |
||||
|
||||
@Override |
||||
public void clear() { |
||||
parent.clear(); |
||||
} |
||||
} |
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/** |
||||
* Inner class KeySet. |
||||
*/ |
||||
protected static class KeySet<K> extends View<K, Object, K> implements Set<K> { |
||||
|
||||
/** Serialization version */ |
||||
private static final long serialVersionUID = -7107935777385040694L; |
||||
|
||||
/** |
||||
* Constructs a new view of the BidiMap. |
||||
* |
||||
* @param parent the parent BidiMap |
||||
*/ |
||||
@SuppressWarnings("unchecked") |
||||
protected KeySet(final AbstractDualBidiMap<K, ?> parent) { |
||||
super(parent.normalMap.keySet(), (AbstractDualBidiMap<K, Object>) parent); |
||||
} |
||||
|
||||
@Override |
||||
public Iterator<K> iterator() { |
||||
return parent.createKeySetIterator(super.iterator()); |
||||
} |
||||
|
||||
@Override |
||||
public boolean contains(final Object key) { |
||||
return parent.normalMap.containsKey(key); |
||||
} |
||||
|
||||
@Override |
||||
public boolean remove(final Object key) { |
||||
if (parent.normalMap.containsKey(key)) { |
||||
final Object value = parent.normalMap.remove(key); |
||||
parent.reverseMap.remove(value); |
||||
return true; |
||||
} |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Inner class KeySetIterator. |
||||
*/ |
||||
protected static class KeySetIterator<K> extends AbstractIteratorDecorator<K> { |
||||
|
||||
/** The parent map */ |
||||
protected final AbstractDualBidiMap<K, ?> parent; |
||||
|
||||
/** The last returned key */ |
||||
protected K lastKey = null; |
||||
|
||||
/** Whether remove is allowed at present */ |
||||
protected boolean canRemove = false; |
||||
|
||||
/** |
||||
* Constructor. |
||||
* @param iterator the iterator to decorate |
||||
* @param parent the parent map |
||||
*/ |
||||
protected KeySetIterator(final Iterator<K> iterator, final AbstractDualBidiMap<K, ?> parent) { |
||||
super(iterator); |
||||
this.parent = parent; |
||||
} |
||||
|
||||
@Override |
||||
public K next() { |
||||
lastKey = super.next(); |
||||
canRemove = true; |
||||
return lastKey; |
||||
} |
||||
|
||||
@Override |
||||
public void remove() { |
||||
if (canRemove == false) { |
||||
throw new IllegalStateException("Iterator remove() can only be called once after next()"); |
||||
} |
||||
final Object value = parent.normalMap.get(lastKey); |
||||
super.remove(); |
||||
parent.reverseMap.remove(value); |
||||
lastKey = null; |
||||
canRemove = false; |
||||
} |
||||
} |
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/** |
||||
* Inner class Values. |
||||
*/ |
||||
protected static class Values<V> extends View<Object, V, V> implements Set<V> { |
||||
|
||||
/** Serialization version */ |
||||
private static final long serialVersionUID = 4023777119829639864L; |
||||
|
||||
/** |
||||
* Constructs a new view of the BidiMap. |
||||
* |
||||
* @param parent the parent BidiMap |
||||
*/ |
||||
@SuppressWarnings("unchecked") |
||||
protected Values(final AbstractDualBidiMap<?, V> parent) { |
||||
super(parent.normalMap.values(), (AbstractDualBidiMap<Object, V>) parent); |
||||
} |
||||
|
||||
@Override |
||||
public Iterator<V> iterator() { |
||||
return parent.createValuesIterator(super.iterator()); |
||||
} |
||||
|
||||
@Override |
||||
public boolean contains(final Object value) { |
||||
return parent.reverseMap.containsKey(value); |
||||
} |
||||
|
||||
@Override |
||||
public boolean remove(final Object value) { |
||||
if (parent.reverseMap.containsKey(value)) { |
||||
final Object key = parent.reverseMap.remove(value); |
||||
parent.normalMap.remove(key); |
||||
return true; |
||||
} |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Inner class ValuesIterator. |
||||
*/ |
||||
protected static class ValuesIterator<V> extends AbstractIteratorDecorator<V> { |
||||
|
||||
/** The parent map */ |
||||
protected final AbstractDualBidiMap<Object, V> parent; |
||||
|
||||
/** The last returned value */ |
||||
protected V lastValue = null; |
||||
|
||||
/** Whether remove is allowed at present */ |
||||
protected boolean canRemove = false; |
||||
|
||||
/** |
||||
* Constructor. |
||||
* @param iterator the iterator to decorate |
||||
* @param parent the parent map |
||||
*/ |
||||
@SuppressWarnings("unchecked") |
||||
protected ValuesIterator(final Iterator<V> iterator, final AbstractDualBidiMap<?, V> parent) { |
||||
super(iterator); |
||||
this.parent = (AbstractDualBidiMap<Object, V>) parent; |
||||
} |
||||
|
||||
@Override |
||||
public V next() { |
||||
lastValue = super.next(); |
||||
canRemove = true; |
||||
return lastValue; |
||||
} |
||||
|
||||
@Override |
||||
public void remove() { |
||||
if (canRemove == false) { |
||||
throw new IllegalStateException("Iterator remove() can only be called once after next()"); |
||||
} |
||||
super.remove(); // removes from maps[0]
|
||||
parent.reverseMap.remove(lastValue); |
||||
lastValue = null; |
||||
canRemove = false; |
||||
} |
||||
} |
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/** |
||||
* Inner class EntrySet. |
||||
*/ |
||||
protected static class EntrySet<K, V> extends View<K, V, Map.Entry<K, V>> implements Set<Map.Entry<K, V>> { |
||||
|
||||
/** Serialization version */ |
||||
private static final long serialVersionUID = 4040410962603292348L; |
||||
|
||||
/** |
||||
* Constructs a new view of the BidiMap. |
||||
* |
||||
* @param parent the parent BidiMap |
||||
*/ |
||||
protected EntrySet(final AbstractDualBidiMap<K, V> parent) { |
||||
super(parent.normalMap.entrySet(), parent); |
||||
} |
||||
|
||||
@Override |
||||
public Iterator<Map.Entry<K, V>> iterator() { |
||||
return parent.createEntrySetIterator(super.iterator()); |
||||
} |
||||
|
||||
@Override |
||||
public boolean remove(final Object obj) { |
||||
if (obj instanceof Map.Entry == false) { |
||||
return false; |
||||
} |
||||
final Map.Entry<?, ?> entry = (Map.Entry<?, ?>) obj; |
||||
final Object key = entry.getKey(); |
||||
if (parent.containsKey(key)) { |
||||
final V value = parent.normalMap.get(key); |
||||
if (value == null ? entry.getValue() == null : value.equals(entry.getValue())) { |
||||
parent.normalMap.remove(key); |
||||
parent.reverseMap.remove(value); |
||||
return true; |
||||
} |
||||
} |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Inner class EntrySetIterator. |
||||
*/ |
||||
protected static class EntrySetIterator<K, V> extends AbstractIteratorDecorator<Map.Entry<K, V>> { |
||||
|
||||
/** The parent map */ |
||||
protected final AbstractDualBidiMap<K, V> parent; |
||||
|
||||
/** The last returned entry */ |
||||
protected Map.Entry<K, V> last = null; |
||||
|
||||
/** Whether remove is allowed at present */ |
||||
protected boolean canRemove = false; |
||||
|
||||
/** |
||||
* Constructor. |
||||
* @param iterator the iterator to decorate |
||||
* @param parent the parent map |
||||
*/ |
||||
protected EntrySetIterator(final Iterator<Map.Entry<K, V>> iterator, final AbstractDualBidiMap<K, V> parent) { |
||||
super(iterator); |
||||
this.parent = parent; |
||||
} |
||||
|
||||
@Override |
||||
public Map.Entry<K, V> next() { |
||||
last = new MapEntry<K, V>(super.next(), parent); |
||||
canRemove = true; |
||||
return last; |
||||
} |
||||
|
||||
@Override |
||||
public void remove() { |
||||
if (canRemove == false) { |
||||
throw new IllegalStateException("Iterator remove() can only be called once after next()"); |
||||
} |
||||
// store value as remove may change the entry in the decorator (eg.TreeMap)
|
||||
final Object value = last.getValue(); |
||||
super.remove(); |
||||
parent.reverseMap.remove(value); |
||||
last = null; |
||||
canRemove = false; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Inner class MapEntry. |
||||
*/ |
||||
protected static class MapEntry<K, V> extends AbstractMapEntryDecorator<K, V> { |
||||
|
||||
/** The parent map */ |
||||
protected final AbstractDualBidiMap<K, V> parent; |
||||
|
||||
/** |
||||
* Constructor. |
||||
* @param entry the entry to decorate |
||||
* @param parent the parent map |
||||
*/ |
||||
protected MapEntry(final Map.Entry<K, V> entry, final AbstractDualBidiMap<K, V> parent) { |
||||
super(entry); |
||||
this.parent = parent; |
||||
} |
||||
|
||||
@Override |
||||
public V setValue(final V value) { |
||||
final K key = MapEntry.this.getKey(); |
||||
if (parent.reverseMap.containsKey(value) && |
||||
parent.reverseMap.get(value) != key) { |
||||
throw new IllegalArgumentException( |
||||
"Cannot use setValue() when the object being set is already in the map"); |
||||
} |
||||
parent.put(key, value); |
||||
return super.setValue(value); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Inner class MapIterator. |
||||
*/ |
||||
protected static class BidiMapIterator<K, V> implements MapIterator<K, V>, ResettableIterator<K> { |
||||
|
||||
/** The parent map */ |
||||
protected final AbstractDualBidiMap<K, V> parent; |
||||
|
||||
/** The iterator being wrapped */ |
||||
protected Iterator<Map.Entry<K, V>> iterator; |
||||
|
||||
/** The last returned entry */ |
||||
protected Map.Entry<K, V> last = null; |
||||
|
||||
/** Whether remove is allowed at present */ |
||||
protected boolean canRemove = false; |
||||
|
||||
/** |
||||
* Constructor. |
||||
* @param parent the parent map |
||||
*/ |
||||
protected BidiMapIterator(final AbstractDualBidiMap<K, V> parent) { |
||||
super(); |
||||
this.parent = parent; |
||||
this.iterator = parent.normalMap.entrySet().iterator(); |
||||
} |
||||
|
||||
@Override |
||||
public boolean hasNext() { |
||||
return iterator.hasNext(); |
||||
} |
||||
|
||||
@Override |
||||
public K next() { |
||||
last = iterator.next(); |
||||
canRemove = true; |
||||
return last.getKey(); |
||||
} |
||||
|
||||
@Override |
||||
public void remove() { |
||||
if (canRemove == false) { |
||||
throw new IllegalStateException("Iterator remove() can only be called once after next()"); |
||||
} |
||||
// store value as remove may change the entry in the decorator (eg.TreeMap)
|
||||
final V value = last.getValue(); |
||||
iterator.remove(); |
||||
parent.reverseMap.remove(value); |
||||
last = null; |
||||
canRemove = false; |
||||
} |
||||
|
||||
@Override |
||||
public K getKey() { |
||||
if (last == null) { |
||||
throw new IllegalStateException( |
||||
"Iterator getKey() can only be called after next() and before remove()"); |
||||
} |
||||
return last.getKey(); |
||||
} |
||||
|
||||
@Override |
||||
public V getValue() { |
||||
if (last == null) { |
||||
throw new IllegalStateException( |
||||
"Iterator getValue() can only be called after next() and before remove()"); |
||||
} |
||||
return last.getValue(); |
||||
} |
||||
|
||||
@Override |
||||
public V setValue(final V value) { |
||||
if (last == null) { |
||||
throw new IllegalStateException( |
||||
"Iterator setValue() can only be called after next() and before remove()"); |
||||
} |
||||
if (parent.reverseMap.containsKey(value) && |
||||
parent.reverseMap.get(value) != last.getKey()) { |
||||
throw new IllegalArgumentException( |
||||
"Cannot use setValue() when the object being set is already in the map"); |
||||
} |
||||
return parent.put(last.getKey(), value); |
||||
} |
||||
|
||||
@Override |
||||
public void reset() { |
||||
iterator = parent.normalMap.entrySet().iterator(); |
||||
last = null; |
||||
canRemove = false; |
||||
} |
||||
|
||||
@Override |
||||
public String toString() { |
||||
if (last != null) { |
||||
return "MapIterator[" + getKey() + "=" + getValue() + "]"; |
||||
} |
||||
return "MapIterator[]"; |
||||
} |
||||
} |
||||
|
||||
} |
@ -0,0 +1,92 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package com.fr.third.org.apache.commons.collections4.bidimap; |
||||
|
||||
import com.fr.third.org.apache.commons.collections4.OrderedBidiMap; |
||||
import com.fr.third.org.apache.commons.collections4.OrderedMapIterator; |
||||
|
||||
/** |
||||
* Provides a base decorator that enables additional functionality to be added |
||||
* to an OrderedBidiMap via decoration. |
||||
* <p> |
||||
* Methods are forwarded directly to the decorated map. |
||||
* <p> |
||||
* This implementation does not perform any special processing with the map views. |
||||
* Instead it simply returns the inverse from the wrapped map. This may be |
||||
* undesirable, for example if you are trying to write a validating implementation |
||||
* it would provide a loophole around the validation. |
||||
* But, you might want that loophole, so this class is kept simple. |
||||
* |
||||
* @since 3.0 |
||||
* @version $Id: AbstractOrderedBidiMapDecorator.java 1686855 2015-06-22 13:00:27Z tn $ |
||||
*/ |
||||
public abstract class AbstractOrderedBidiMapDecorator<K, V> |
||||
extends AbstractBidiMapDecorator<K, V> |
||||
implements OrderedBidiMap<K, V> { |
||||
|
||||
/** |
||||
* Constructor that wraps (not copies). |
||||
* |
||||
* @param map the map to decorate, must not be null |
||||
* @throws NullPointerException if the collection is null |
||||
*/ |
||||
protected AbstractOrderedBidiMapDecorator(final OrderedBidiMap<K, V> map) { |
||||
super(map); |
||||
} |
||||
|
||||
/** |
||||
* Gets the map being decorated. |
||||
* |
||||
* @return the decorated map |
||||
*/ |
||||
@Override |
||||
protected OrderedBidiMap<K, V> decorated() { |
||||
return (OrderedBidiMap<K, V>) super.decorated(); |
||||
} |
||||
|
||||
//-----------------------------------------------------------------------
|
||||
@Override |
||||
public OrderedMapIterator<K, V> mapIterator() { |
||||
return decorated().mapIterator(); |
||||
} |
||||
|
||||
@Override |
||||
public K firstKey() { |
||||
return decorated().firstKey(); |
||||
} |
||||
|
||||
@Override |
||||
public K lastKey() { |
||||
return decorated().lastKey(); |
||||
} |
||||
|
||||
@Override |
||||
public K nextKey(final K key) { |
||||
return decorated().nextKey(key); |
||||
} |
||||
|
||||
@Override |
||||
public K previousKey(final K key) { |
||||
return decorated().previousKey(key); |
||||
} |
||||
|
||||
@Override |
||||
public OrderedBidiMap<V, K> inverseBidiMap() { |
||||
return decorated().inverseBidiMap(); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,93 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package com.fr.third.org.apache.commons.collections4.bidimap; |
||||
|
||||
import java.util.Comparator; |
||||
import java.util.SortedMap; |
||||
|
||||
import com.fr.third.org.apache.commons.collections4.SortedBidiMap; |
||||
|
||||
/** |
||||
* Provides a base decorator that enables additional functionality to be added |
||||
* to a SortedBidiMap via decoration. |
||||
* <p> |
||||
* Methods are forwarded directly to the decorated map. |
||||
* <p> |
||||
* This implementation does not perform any special processing with the map views. |
||||
* Instead it simply returns the inverse from the wrapped map. This may be |
||||
* undesirable, for example if you are trying to write a validating implementation |
||||
* it would provide a loophole around the validation. |
||||
* But, you might want that loophole, so this class is kept simple. |
||||
* |
||||
* @since 3.0 |
||||
* @version $Id: AbstractSortedBidiMapDecorator.java 1686855 2015-06-22 13:00:27Z tn $ |
||||
*/ |
||||
public abstract class AbstractSortedBidiMapDecorator<K, V> |
||||
extends AbstractOrderedBidiMapDecorator<K, V> implements SortedBidiMap<K, V> { |
||||
|
||||
/** |
||||
* Constructor that wraps (not copies). |
||||
* |
||||
* @param map the map to decorate, must not be null |
||||
* @throws NullPointerException if the collection is null |
||||
*/ |
||||
public AbstractSortedBidiMapDecorator(final SortedBidiMap<K, V> map) { |
||||
super(map); |
||||
} |
||||
|
||||
/** |
||||
* Gets the map being decorated. |
||||
* |
||||
* @return the decorated map |
||||
*/ |
||||
@Override |
||||
protected SortedBidiMap<K, V> decorated() { |
||||
return (SortedBidiMap<K, V>) super.decorated(); |
||||
} |
||||
|
||||
//-----------------------------------------------------------------------
|
||||
@Override |
||||
public SortedBidiMap<V, K> inverseBidiMap() { |
||||
return decorated().inverseBidiMap(); |
||||
} |
||||
|
||||
@Override |
||||
public Comparator<? super K> comparator() { |
||||
return decorated().comparator(); |
||||
} |
||||
|
||||
@Override |
||||
public Comparator<? super V> valueComparator() { |
||||
return decorated().valueComparator(); |
||||
} |
||||
|
||||
@Override |
||||
public SortedMap<K, V> subMap(final K fromKey, final K toKey) { |
||||
return decorated().subMap(fromKey, toKey); |
||||
} |
||||
|
||||
@Override |
||||
public SortedMap<K, V> headMap(final K toKey) { |
||||
return decorated().headMap(toKey); |
||||
} |
||||
|
||||
@Override |
||||
public SortedMap<K, V> tailMap(final K fromKey) { |
||||
return decorated().tailMap(fromKey); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,107 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package com.fr.third.org.apache.commons.collections4.bidimap; |
||||
|
||||
import java.io.IOException; |
||||
import java.io.ObjectInputStream; |
||||
import java.io.ObjectOutputStream; |
||||
import java.io.Serializable; |
||||
import java.util.HashMap; |
||||
import java.util.Map; |
||||
|
||||
import com.fr.third.org.apache.commons.collections4.BidiMap; |
||||
|
||||
/** |
||||
* Implementation of {@link BidiMap} that uses two {@link HashMap} instances. |
||||
* <p> |
||||
* Two {@link HashMap} instances are used in this class. |
||||
* This provides fast lookups at the expense of storing two sets of map entries. |
||||
* Commons Collections would welcome the addition of a direct hash-based |
||||
* implementation of the {@link BidiMap} interface. |
||||
* <p> |
||||
* NOTE: From Commons Collections 3.1, all subclasses will use {@link HashMap} |
||||
* and the flawed <code>createMap</code> method is ignored. |
||||
* |
||||
* @since 3.0 |
||||
* @version $Id: DualHashBidiMap.java 1533984 2013-10-20 21:12:51Z tn $ |
||||
*/ |
||||
public class DualHashBidiMap<K, V> extends AbstractDualBidiMap<K, V> implements Serializable { |
||||
|
||||
/** Ensure serialization compatibility */ |
||||
private static final long serialVersionUID = 721969328361808L; |
||||
|
||||
/** |
||||
* Creates an empty <code>HashBidiMap</code>. |
||||
*/ |
||||
public DualHashBidiMap() { |
||||
super(new HashMap<K, V>(), new HashMap<V, K>()); |
||||
} |
||||
|
||||
/** |
||||
* Constructs a <code>HashBidiMap</code> and copies the mappings from |
||||
* specified <code>Map</code>. |
||||
* |
||||
* @param map the map whose mappings are to be placed in this map |
||||
*/ |
||||
public DualHashBidiMap(final Map<? extends K, ? extends V> map) { |
||||
super(new HashMap<K, V>(), new HashMap<V, K>()); |
||||
putAll(map); |
||||
} |
||||
|
||||
/** |
||||
* Constructs a <code>HashBidiMap</code> that decorates the specified maps. |
||||
* |
||||
* @param normalMap the normal direction map |
||||
* @param reverseMap the reverse direction map |
||||
* @param inverseBidiMap the inverse BidiMap |
||||
*/ |
||||
protected DualHashBidiMap(final Map<K, V> normalMap, final Map<V, K> reverseMap, |
||||
final BidiMap<V, K> inverseBidiMap) { |
||||
super(normalMap, reverseMap, inverseBidiMap); |
||||
} |
||||
|
||||
/** |
||||
* Creates a new instance of this object. |
||||
* |
||||
* @param normalMap the normal direction map |
||||
* @param reverseMap the reverse direction map |
||||
* @param inverseBidiMap the inverse BidiMap |
||||
* @return new bidi map |
||||
*/ |
||||
@Override |
||||
protected BidiMap<V, K> createBidiMap(final Map<V, K> normalMap, final Map<K, V> reverseMap, |
||||
final BidiMap<K, V> inverseBidiMap) { |
||||
return new DualHashBidiMap<V, K>(normalMap, reverseMap, inverseBidiMap); |
||||
} |
||||
|
||||
// Serialization
|
||||
//-----------------------------------------------------------------------
|
||||
private void writeObject(final ObjectOutputStream out) throws IOException { |
||||
out.defaultWriteObject(); |
||||
out.writeObject(normalMap); |
||||
} |
||||
|
||||
private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException { |
||||
in.defaultReadObject(); |
||||
normalMap = new HashMap<K, V>(); |
||||
reverseMap = new HashMap<V, K>(); |
||||
@SuppressWarnings("unchecked") // will fail at runtime if stream is incorrect
|
||||
final Map<K, V> map = (Map<K, V>) in.readObject(); |
||||
putAll(map); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,101 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package com.fr.third.org.apache.commons.collections4.bidimap; |
||||
|
||||
import java.io.IOException; |
||||
import java.io.ObjectInputStream; |
||||
import java.io.ObjectOutputStream; |
||||
import java.io.Serializable; |
||||
import java.util.LinkedHashMap; |
||||
import java.util.Map; |
||||
|
||||
import com.fr.third.org.apache.commons.collections4.BidiMap; |
||||
|
||||
/** |
||||
* Implementation of <code>BidiMap</code> that uses two <code>LinkedHashMap</code> instances. |
||||
* <p> |
||||
* Two <code>LinkedHashMap</code> instances are used in this class. |
||||
* This provides fast lookups at the expense of storing two sets of map entries and two linked lists. |
||||
* |
||||
* @version $Id: DualLinkedHashBidiMap.java 1533984 2013-10-20 21:12:51Z tn $ |
||||
* @since 4.0 |
||||
*/ |
||||
public class DualLinkedHashBidiMap<K, V> extends AbstractDualBidiMap<K, V> implements Serializable { |
||||
|
||||
/** Ensure serialization compatibility */ |
||||
private static final long serialVersionUID = 721969328361810L; |
||||
|
||||
/** |
||||
* Creates an empty <code>HashBidiMap</code>. |
||||
*/ |
||||
public DualLinkedHashBidiMap() { |
||||
super(new LinkedHashMap<K, V>(), new LinkedHashMap<V, K>()); |
||||
} |
||||
|
||||
/** |
||||
* Constructs a <code>LinkedHashBidiMap</code> and copies the mappings from |
||||
* specified <code>Map</code>. |
||||
* |
||||
* @param map the map whose mappings are to be placed in this map |
||||
*/ |
||||
public DualLinkedHashBidiMap(final Map<? extends K, ? extends V> map) { |
||||
super(new LinkedHashMap<K, V>(), new LinkedHashMap<V, K>()); |
||||
putAll(map); |
||||
} |
||||
|
||||
/** |
||||
* Constructs a <code>LinkedHashBidiMap</code> that decorates the specified maps. |
||||
* |
||||
* @param normalMap the normal direction map |
||||
* @param reverseMap the reverse direction map |
||||
* @param inverseBidiMap the inverse BidiMap |
||||
*/ |
||||
protected DualLinkedHashBidiMap(final Map<K, V> normalMap, final Map<V, K> reverseMap, |
||||
final BidiMap<V, K> inverseBidiMap) { |
||||
super(normalMap, reverseMap, inverseBidiMap); |
||||
} |
||||
|
||||
/** |
||||
* Creates a new instance of this object. |
||||
* |
||||
* @param normalMap the normal direction map |
||||
* @param reverseMap the reverse direction map |
||||
* @param inverseBidiMap the inverse BidiMap |
||||
* @return new bidi map |
||||
*/ |
||||
@Override |
||||
protected BidiMap<V, K> createBidiMap(final Map<V, K> normalMap, final Map<K, V> reverseMap, |
||||
final BidiMap<K, V> inverseBidiMap) { |
||||
return new DualLinkedHashBidiMap<V, K>(normalMap, reverseMap, inverseBidiMap); |
||||
} |
||||
|
||||
// Serialization
|
||||
//-----------------------------------------------------------------------
|
||||
private void writeObject(final ObjectOutputStream out) throws IOException { |
||||
out.defaultWriteObject(); |
||||
out.writeObject(normalMap); |
||||
} |
||||
|
||||
private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException { |
||||
in.defaultReadObject(); |
||||
normalMap = new LinkedHashMap<K, V>(); |
||||
reverseMap = new LinkedHashMap<V, K>(); |
||||
@SuppressWarnings("unchecked") // will fail at runtime if stream is incorrect
|
||||
final Map<K, V> map = (Map<K, V>) in.readObject(); |
||||
putAll(map); |
||||
} |
||||
} |
@ -0,0 +1,416 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package com.fr.third.org.apache.commons.collections4.bidimap; |
||||
|
||||
import java.io.IOException; |
||||
import java.io.ObjectInputStream; |
||||
import java.io.ObjectOutputStream; |
||||
import java.io.Serializable; |
||||
import java.util.ArrayList; |
||||
import java.util.Comparator; |
||||
import java.util.Iterator; |
||||
import java.util.ListIterator; |
||||
import java.util.Map; |
||||
import java.util.SortedMap; |
||||
import java.util.TreeMap; |
||||
|
||||
import com.fr.third.org.apache.commons.collections4.BidiMap; |
||||
import com.fr.third.org.apache.commons.collections4.OrderedBidiMap; |
||||
import com.fr.third.org.apache.commons.collections4.OrderedMap; |
||||
import com.fr.third.org.apache.commons.collections4.OrderedMapIterator; |
||||
import com.fr.third.org.apache.commons.collections4.ResettableIterator; |
||||
import com.fr.third.org.apache.commons.collections4.SortedBidiMap; |
||||
import com.fr.third.org.apache.commons.collections4.map.AbstractSortedMapDecorator; |
||||
|
||||
/** |
||||
* Implementation of {@link BidiMap} that uses two {@link TreeMap} instances. |
||||
* <p> |
||||
* The setValue() method on iterators will succeed only if the new value being set is |
||||
* not already in the bidimap. |
||||
* <p> |
||||
* When considering whether to use this class, the {@link TreeBidiMap} class should |
||||
* also be considered. It implements the interface using a dedicated design, and does |
||||
* not store each object twice, which can save on memory use. |
||||
* <p> |
||||
* NOTE: From Commons Collections 3.1, all subclasses will use {@link TreeMap} |
||||
* and the flawed <code>createMap</code> method is ignored. |
||||
* |
||||
* @since 3.0 |
||||
* @version $Id: DualTreeBidiMap.java 1683951 2015-06-06 20:19:03Z tn $ |
||||
*/ |
||||
public class DualTreeBidiMap<K, V> extends AbstractDualBidiMap<K, V> |
||||
implements SortedBidiMap<K, V>, Serializable { |
||||
|
||||
/** Ensure serialization compatibility */ |
||||
private static final long serialVersionUID = 721969328361809L; |
||||
|
||||
/** The key comparator to use */ |
||||
private final Comparator<? super K> comparator; |
||||
|
||||
/** The value comparator to use */ |
||||
private final Comparator<? super V> valueComparator; |
||||
|
||||
/** |
||||
* Creates an empty <code>DualTreeBidiMap</code> |
||||
*/ |
||||
public DualTreeBidiMap() { |
||||
super(new TreeMap<K, V>(), new TreeMap<V, K>()); |
||||
this.comparator = null; |
||||
this.valueComparator = null; |
||||
} |
||||
|
||||
/** |
||||
* Constructs a <code>DualTreeBidiMap</code> and copies the mappings from |
||||
* specified <code>Map</code>. |
||||
* |
||||
* @param map the map whose mappings are to be placed in this map |
||||
*/ |
||||
public DualTreeBidiMap(final Map<? extends K, ? extends V> map) { |
||||
super(new TreeMap<K, V>(), new TreeMap<V, K>()); |
||||
putAll(map); |
||||
this.comparator = null; |
||||
this.valueComparator = null; |
||||
} |
||||
|
||||
/** |
||||
* Constructs a {@link DualTreeBidiMap} using the specified {@link Comparator}. |
||||
* |
||||
* @param keyComparator the comparator |
||||
* @param valueComparator the values comparator to use |
||||
*/ |
||||
public DualTreeBidiMap(final Comparator<? super K> keyComparator, final Comparator<? super V> valueComparator) { |
||||
super(new TreeMap<K, V>(keyComparator), new TreeMap<V, K>(valueComparator)); |
||||
this.comparator = keyComparator; |
||||
this.valueComparator = valueComparator; |
||||
} |
||||
|
||||
/** |
||||
* Constructs a {@link DualTreeBidiMap} that decorates the specified maps. |
||||
* |
||||
* @param normalMap the normal direction map |
||||
* @param reverseMap the reverse direction map |
||||
* @param inverseBidiMap the inverse BidiMap |
||||
*/ |
||||
protected DualTreeBidiMap(final Map<K, V> normalMap, final Map<V, K> reverseMap, |
||||
final BidiMap<V, K> inverseBidiMap) { |
||||
super(normalMap, reverseMap, inverseBidiMap); |
||||
this.comparator = ((SortedMap<K, V>) normalMap).comparator(); |
||||
this.valueComparator = ((SortedMap<V, K>) reverseMap).comparator(); |
||||
} |
||||
|
||||
/** |
||||
* Creates a new instance of this object. |
||||
* |
||||
* @param normalMap the normal direction map |
||||
* @param reverseMap the reverse direction map |
||||
* @param inverseMap the inverse BidiMap |
||||
* @return new bidi map |
||||
*/ |
||||
@Override |
||||
protected DualTreeBidiMap<V, K> createBidiMap(final Map<V, K> normalMap, final Map<K, V> reverseMap, |
||||
final BidiMap<K, V> inverseMap) { |
||||
return new DualTreeBidiMap<V, K>(normalMap, reverseMap, inverseMap); |
||||
} |
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
@Override |
||||
public Comparator<? super K> comparator() { |
||||
return ((SortedMap<K, V>) normalMap).comparator(); |
||||
} |
||||
|
||||
@Override |
||||
public Comparator<? super V> valueComparator() { |
||||
return ((SortedMap<V, K>) reverseMap).comparator(); |
||||
} |
||||
|
||||
@Override |
||||
public K firstKey() { |
||||
return ((SortedMap<K, V>) normalMap).firstKey(); |
||||
} |
||||
|
||||
@Override |
||||
public K lastKey() { |
||||
return ((SortedMap<K, V>) normalMap).lastKey(); |
||||
} |
||||
|
||||
@Override |
||||
public K nextKey(final K key) { |
||||
if (isEmpty()) { |
||||
return null; |
||||
} |
||||
if (normalMap instanceof OrderedMap) { |
||||
return ((OrderedMap<K, ?>) normalMap).nextKey(key); |
||||
} |
||||
final SortedMap<K, V> sm = (SortedMap<K, V>) normalMap; |
||||
final Iterator<K> it = sm.tailMap(key).keySet().iterator(); |
||||
it.next(); |
||||
if (it.hasNext()) { |
||||
return it.next(); |
||||
} |
||||
return null; |
||||
} |
||||
|
||||
@Override |
||||
public K previousKey(final K key) { |
||||
if (isEmpty()) { |
||||
return null; |
||||
} |
||||
if (normalMap instanceof OrderedMap) { |
||||
return ((OrderedMap<K, V>) normalMap).previousKey(key); |
||||
} |
||||
final SortedMap<K, V> sm = (SortedMap<K, V>) normalMap; |
||||
final SortedMap<K, V> hm = sm.headMap(key); |
||||
if (hm.isEmpty()) { |
||||
return null; |
||||
} |
||||
return hm.lastKey(); |
||||
} |
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/** |
||||
* Obtains an ordered map iterator. |
||||
* <p> |
||||
* This implementation copies the elements to an ArrayList in order to |
||||
* provide the forward/backward behaviour. |
||||
* |
||||
* @return a new ordered map iterator |
||||
*/ |
||||
@Override |
||||
public OrderedMapIterator<K, V> mapIterator() { |
||||
return new BidiOrderedMapIterator<K, V>(this); |
||||
} |
||||
|
||||
public SortedBidiMap<V, K> inverseSortedBidiMap() { |
||||
return inverseBidiMap(); |
||||
} |
||||
|
||||
public OrderedBidiMap<V, K> inverseOrderedBidiMap() { |
||||
return inverseBidiMap(); |
||||
} |
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
@Override |
||||
public SortedMap<K, V> headMap(final K toKey) { |
||||
final SortedMap<K, V> sub = ((SortedMap<K, V>) normalMap).headMap(toKey); |
||||
return new ViewMap<K, V>(this, sub); |
||||
} |
||||
|
||||
@Override |
||||
public SortedMap<K, V> tailMap(final K fromKey) { |
||||
final SortedMap<K, V> sub = ((SortedMap<K, V>) normalMap).tailMap(fromKey); |
||||
return new ViewMap<K, V>(this, sub); |
||||
} |
||||
|
||||
@Override |
||||
public SortedMap<K, V> subMap(final K fromKey, final K toKey) { |
||||
final SortedMap<K, V> sub = ((SortedMap<K, V>) normalMap).subMap(fromKey, toKey); |
||||
return new ViewMap<K, V>(this, sub); |
||||
} |
||||
|
||||
@Override |
||||
public SortedBidiMap<V, K> inverseBidiMap() { |
||||
return (SortedBidiMap<V, K>) super.inverseBidiMap(); |
||||
} |
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/** |
||||
* Internal sorted map view. |
||||
*/ |
||||
protected static class ViewMap<K, V> extends AbstractSortedMapDecorator<K, V> { |
||||
/** |
||||
* Constructor. |
||||
* @param bidi the parent bidi map |
||||
* @param sm the subMap sorted map |
||||
*/ |
||||
protected ViewMap(final DualTreeBidiMap<K, V> bidi, final SortedMap<K, V> sm) { |
||||
// the implementation is not great here...
|
||||
// use the normalMap as the filtered map, but reverseMap as the full map
|
||||
// this forces containsValue and clear to be overridden
|
||||
super(new DualTreeBidiMap<K, V>(sm, bidi.reverseMap, bidi.inverseBidiMap)); |
||||
} |
||||
|
||||
@Override |
||||
public boolean containsValue(final Object value) { |
||||
// override as default implementation uses reverseMap
|
||||
return decorated().normalMap.containsValue(value); |
||||
} |
||||
|
||||
@Override |
||||
public void clear() { |
||||
// override as default implementation uses reverseMap
|
||||
for (final Iterator<K> it = keySet().iterator(); it.hasNext();) { |
||||
it.next(); |
||||
it.remove(); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public SortedMap<K, V> headMap(final K toKey) { |
||||
return new ViewMap<K, V>(decorated(), super.headMap(toKey)); |
||||
} |
||||
|
||||
@Override |
||||
public SortedMap<K, V> tailMap(final K fromKey) { |
||||
return new ViewMap<K, V>(decorated(), super.tailMap(fromKey)); |
||||
} |
||||
|
||||
@Override |
||||
public SortedMap<K, V> subMap(final K fromKey, final K toKey) { |
||||
return new ViewMap<K, V>(decorated(), super.subMap(fromKey, toKey)); |
||||
} |
||||
|
||||
@Override |
||||
protected DualTreeBidiMap<K, V> decorated() { |
||||
return (DualTreeBidiMap<K, V>) super.decorated(); |
||||
} |
||||
|
||||
@Override |
||||
public K previousKey(final K key) { |
||||
return decorated().previousKey(key); |
||||
} |
||||
|
||||
@Override |
||||
public K nextKey(final K key) { |
||||
return decorated().nextKey(key); |
||||
} |
||||
} |
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/** |
||||
* Inner class MapIterator. |
||||
*/ |
||||
protected static class BidiOrderedMapIterator<K, V> implements OrderedMapIterator<K, V>, ResettableIterator<K> { |
||||
|
||||
/** The parent map */ |
||||
private final AbstractDualBidiMap<K, V> parent; |
||||
|
||||
/** The iterator being decorated */ |
||||
private ListIterator<Map.Entry<K, V>> iterator; |
||||
|
||||
/** The last returned entry */ |
||||
private Map.Entry<K, V> last = null; |
||||
|
||||
/** |
||||
* Constructor. |
||||
* @param parent the parent map |
||||
*/ |
||||
protected BidiOrderedMapIterator(final AbstractDualBidiMap<K, V> parent) { |
||||
super(); |
||||
this.parent = parent; |
||||
iterator = new ArrayList<Map.Entry<K, V>>(parent.entrySet()).listIterator(); |
||||
} |
||||
|
||||
@Override |
||||
public boolean hasNext() { |
||||
return iterator.hasNext(); |
||||
} |
||||
|
||||
@Override |
||||
public K next() { |
||||
last = iterator.next(); |
||||
return last.getKey(); |
||||
} |
||||
|
||||
@Override |
||||
public boolean hasPrevious() { |
||||
return iterator.hasPrevious(); |
||||
} |
||||
|
||||
@Override |
||||
public K previous() { |
||||
last = iterator.previous(); |
||||
return last.getKey(); |
||||
} |
||||
|
||||
@Override |
||||
public void remove() { |
||||
iterator.remove(); |
||||
parent.remove(last.getKey()); |
||||
last = null; |
||||
} |
||||
|
||||
@Override |
||||
public K getKey() { |
||||
if (last == null) { |
||||
throw new IllegalStateException( |
||||
"Iterator getKey() can only be called after next() and before remove()"); |
||||
} |
||||
return last.getKey(); |
||||
} |
||||
|
||||
@Override |
||||
public V getValue() { |
||||
if (last == null) { |
||||
throw new IllegalStateException( |
||||
"Iterator getValue() can only be called after next() and before remove()"); |
||||
} |
||||
return last.getValue(); |
||||
} |
||||
|
||||
@Override |
||||
public V setValue(final V value) { |
||||
if (last == null) { |
||||
throw new IllegalStateException( |
||||
"Iterator setValue() can only be called after next() and before remove()"); |
||||
} |
||||
if (parent.reverseMap.containsKey(value) && |
||||
parent.reverseMap.get(value) != last.getKey()) { |
||||
throw new IllegalArgumentException( |
||||
"Cannot use setValue() when the object being set is already in the map"); |
||||
} |
||||
final V oldValue = parent.put(last.getKey(), value); |
||||
// Map.Entry specifies that the behavior is undefined when the backing map
|
||||
// has been modified (as we did with the put), so we also set the value
|
||||
// (especially needed for IBM JDK)
|
||||
last.setValue(value); |
||||
return oldValue; |
||||
} |
||||
|
||||
@Override |
||||
public void reset() { |
||||
iterator = new ArrayList<Map.Entry<K, V>>(parent.entrySet()).listIterator(); |
||||
last = null; |
||||
} |
||||
|
||||
@Override |
||||
public String toString() { |
||||
if (last != null) { |
||||
return "MapIterator[" + getKey() + "=" + getValue() + "]"; |
||||
} |
||||
return "MapIterator[]"; |
||||
} |
||||
} |
||||
|
||||
// Serialization
|
||||
//-----------------------------------------------------------------------
|
||||
private void writeObject(final ObjectOutputStream out) throws IOException { |
||||
out.defaultWriteObject(); |
||||
out.writeObject(normalMap); |
||||
} |
||||
|
||||
private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException { |
||||
in.defaultReadObject(); |
||||
normalMap = new TreeMap<K, V>(comparator); |
||||
reverseMap = new TreeMap<V, K>(valueComparator); |
||||
@SuppressWarnings("unchecked") // will fail at runtime if the stream is incorrect
|
||||
final Map<K, V> map = (Map<K, V>) in.readObject(); |
||||
putAll(map); |
||||
} |
||||
|
||||
} |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,136 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package com.fr.third.org.apache.commons.collections4.bidimap; |
||||
|
||||
import java.util.Map; |
||||
import java.util.Set; |
||||
|
||||
import com.fr.third.org.apache.commons.collections4.BidiMap; |
||||
import com.fr.third.org.apache.commons.collections4.MapIterator; |
||||
import com.fr.third.org.apache.commons.collections4.Unmodifiable; |
||||
import com.fr.third.org.apache.commons.collections4.iterators.UnmodifiableMapIterator; |
||||
import com.fr.third.org.apache.commons.collections4.map.UnmodifiableEntrySet; |
||||
import com.fr.third.org.apache.commons.collections4.set.UnmodifiableSet; |
||||
|
||||
/** |
||||
* Decorates another {@link BidiMap} to ensure it can't be altered. |
||||
* <p> |
||||
* Attempts to modify it will result in an UnsupportedOperationException. |
||||
* |
||||
* @since 3.0 |
||||
* @version $Id: UnmodifiableBidiMap.java 1686855 2015-06-22 13:00:27Z tn $ |
||||
*/ |
||||
public final class UnmodifiableBidiMap<K, V> |
||||
extends AbstractBidiMapDecorator<K, V> implements Unmodifiable { |
||||
|
||||
/** The inverse unmodifiable map */ |
||||
private UnmodifiableBidiMap<V, K> inverse; |
||||
|
||||
/** |
||||
* Factory method to create an unmodifiable map. |
||||
* <p> |
||||
* If the map passed in is already unmodifiable, it is returned. |
||||
* |
||||
* @param <K> the key type |
||||
* @param <V> the value type |
||||
* @param map the map to decorate, must not be null |
||||
* @return an unmodifiable BidiMap |
||||
* @throws NullPointerException if map is null |
||||
* @since 4.0 |
||||
*/ |
||||
public static <K, V> BidiMap<K, V> unmodifiableBidiMap(final BidiMap<? extends K, ? extends V> map) { |
||||
if (map instanceof Unmodifiable) { |
||||
@SuppressWarnings("unchecked") // safe to upcast
|
||||
final BidiMap<K, V> tmpMap = (BidiMap<K, V>) map; |
||||
return tmpMap; |
||||
} |
||||
return new UnmodifiableBidiMap<K, V>(map); |
||||
} |
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/** |
||||
* Constructor that wraps (not copies). |
||||
* |
||||
* @param map the map to decorate, must not be null |
||||
* @throws NullPointerException if map is null |
||||
*/ |
||||
@SuppressWarnings("unchecked") // safe to upcast
|
||||
private UnmodifiableBidiMap(final BidiMap<? extends K, ? extends V> map) { |
||||
super((BidiMap<K, V>) map); |
||||
} |
||||
|
||||
//-----------------------------------------------------------------------
|
||||
@Override |
||||
public void clear() { |
||||
throw new UnsupportedOperationException(); |
||||
} |
||||
|
||||
@Override |
||||
public V put(final K key, final V value) { |
||||
throw new UnsupportedOperationException(); |
||||
} |
||||
|
||||
@Override |
||||
public void putAll(final Map<? extends K, ? extends V> mapToCopy) { |
||||
throw new UnsupportedOperationException(); |
||||
} |
||||
|
||||
@Override |
||||
public V remove(final Object key) { |
||||
throw new UnsupportedOperationException(); |
||||
} |
||||
|
||||
@Override |
||||
public Set<Map.Entry<K, V>> entrySet() { |
||||
final Set<Map.Entry<K, V>> set = super.entrySet(); |
||||
return UnmodifiableEntrySet.unmodifiableEntrySet(set); |
||||
} |
||||
|
||||
@Override |
||||
public Set<K> keySet() { |
||||
final Set<K> set = super.keySet(); |
||||
return UnmodifiableSet.unmodifiableSet(set); |
||||
} |
||||
|
||||
@Override |
||||
public Set<V> values() { |
||||
final Set<V> set = super.values(); |
||||
return UnmodifiableSet.unmodifiableSet(set); |
||||
} |
||||
|
||||
//-----------------------------------------------------------------------
|
||||
@Override |
||||
public K removeValue(final Object value) { |
||||
throw new UnsupportedOperationException(); |
||||
} |
||||
|
||||
@Override |
||||
public MapIterator<K, V> mapIterator() { |
||||
final MapIterator<K, V> it = decorated().mapIterator(); |
||||
return UnmodifiableMapIterator.unmodifiableMapIterator(it); |
||||
} |
||||
|
||||
@Override |
||||
public synchronized BidiMap<V, K> inverseBidiMap() { |
||||
if (inverse == null) { |
||||
inverse = new UnmodifiableBidiMap<V, K>(decorated().inverseBidiMap()); |
||||
inverse.inverse = this; |
||||
} |
||||
return inverse; |
||||
} |
||||
|
||||
} |
@ -0,0 +1,147 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package com.fr.third.org.apache.commons.collections4.bidimap; |
||||
|
||||
import java.util.Map; |
||||
import java.util.Set; |
||||
|
||||
import com.fr.third.org.apache.commons.collections4.OrderedBidiMap; |
||||
import com.fr.third.org.apache.commons.collections4.OrderedMapIterator; |
||||
import com.fr.third.org.apache.commons.collections4.Unmodifiable; |
||||
import com.fr.third.org.apache.commons.collections4.iterators.UnmodifiableOrderedMapIterator; |
||||
import com.fr.third.org.apache.commons.collections4.map.UnmodifiableEntrySet; |
||||
import com.fr.third.org.apache.commons.collections4.set.UnmodifiableSet; |
||||
|
||||
/** |
||||
* Decorates another {@link OrderedBidiMap} to ensure it can't be altered. |
||||
* <p> |
||||
* Attempts to modify it will result in an UnsupportedOperationException. |
||||
* |
||||
* @since 3.0 |
||||
* @version $Id: UnmodifiableOrderedBidiMap.java 1686855 2015-06-22 13:00:27Z tn $ |
||||
*/ |
||||
public final class UnmodifiableOrderedBidiMap<K, V> |
||||
extends AbstractOrderedBidiMapDecorator<K, V> implements Unmodifiable { |
||||
|
||||
/** The inverse unmodifiable map */ |
||||
private UnmodifiableOrderedBidiMap<V, K> inverse; |
||||
|
||||
/** |
||||
* Factory method to create an unmodifiable map. |
||||
* <p> |
||||
* If the map passed in is already unmodifiable, it is returned. |
||||
* |
||||
* @param <K> the key type |
||||
* @param <V> the value type |
||||
* @param map the map to decorate, must not be null |
||||
* @return an unmodifiable OrderedBidiMap |
||||
* @throws NullPointerException if map is null |
||||
* @since 4.0 |
||||
*/ |
||||
public static <K, V> OrderedBidiMap<K, V> unmodifiableOrderedBidiMap( |
||||
final OrderedBidiMap<? extends K, ? extends V> map) { |
||||
if (map instanceof Unmodifiable) { |
||||
@SuppressWarnings("unchecked") // safe to upcast
|
||||
final OrderedBidiMap<K, V> tmpMap = (OrderedBidiMap<K, V>) map; |
||||
return tmpMap; |
||||
} |
||||
return new UnmodifiableOrderedBidiMap<K, V>(map); |
||||
} |
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/** |
||||
* Constructor that wraps (not copies). |
||||
* |
||||
* @param map the map to decorate, must not be null |
||||
* @throws NullPointerException if map is null |
||||
*/ |
||||
@SuppressWarnings("unchecked") // safe to upcast
|
||||
private UnmodifiableOrderedBidiMap(final OrderedBidiMap<? extends K, ? extends V> map) { |
||||
super((OrderedBidiMap<K, V>) map); |
||||
} |
||||
|
||||
//-----------------------------------------------------------------------
|
||||
@Override |
||||
public void clear() { |
||||
throw new UnsupportedOperationException(); |
||||
} |
||||
|
||||
@Override |
||||
public V put(final K key, final V value) { |
||||
throw new UnsupportedOperationException(); |
||||
} |
||||
|
||||
@Override |
||||
public void putAll(final Map<? extends K, ? extends V> mapToCopy) { |
||||
throw new UnsupportedOperationException(); |
||||
} |
||||
|
||||
@Override |
||||
public V remove(final Object key) { |
||||
throw new UnsupportedOperationException(); |
||||
} |
||||
|
||||
@Override |
||||
public Set<Map.Entry<K, V>> entrySet() { |
||||
final Set<Map.Entry<K, V>> set = super.entrySet(); |
||||
return UnmodifiableEntrySet.unmodifiableEntrySet(set); |
||||
} |
||||
|
||||
@Override |
||||
public Set<K> keySet() { |
||||
final Set<K> set = super.keySet(); |
||||
return UnmodifiableSet.unmodifiableSet(set); |
||||
} |
||||
|
||||
@Override |
||||
public Set<V> values() { |
||||
final Set<V> set = super.values(); |
||||
return UnmodifiableSet.unmodifiableSet(set); |
||||
} |
||||
|
||||
//-----------------------------------------------------------------------
|
||||
@Override |
||||
public K removeValue(final Object value) { |
||||
throw new UnsupportedOperationException(); |
||||
} |
||||
|
||||
@Override |
||||
public OrderedBidiMap<V, K> inverseBidiMap() { |
||||
return inverseOrderedBidiMap(); |
||||
} |
||||
|
||||
//-----------------------------------------------------------------------
|
||||
@Override |
||||
public OrderedMapIterator<K, V> mapIterator() { |
||||
final OrderedMapIterator<K, V> it = decorated().mapIterator(); |
||||
return UnmodifiableOrderedMapIterator.unmodifiableOrderedMapIterator(it); |
||||
} |
||||
|
||||
/** |
||||
* Gets an unmodifiable view of this map where the keys and values are reversed. |
||||
* |
||||
* @return an inverted unmodifiable bidirectional map |
||||
*/ |
||||
public OrderedBidiMap<V, K> inverseOrderedBidiMap() { |
||||
if (inverse == null) { |
||||
inverse = new UnmodifiableOrderedBidiMap<V, K>(decorated().inverseBidiMap()); |
||||
inverse.inverse = this; |
||||
} |
||||
return inverse; |
||||
} |
||||
|
||||
} |
@ -0,0 +1,158 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package com.fr.third.org.apache.commons.collections4.bidimap; |
||||
|
||||
import java.util.Map; |
||||
import java.util.Set; |
||||
import java.util.SortedMap; |
||||
|
||||
import com.fr.third.org.apache.commons.collections4.OrderedMapIterator; |
||||
import com.fr.third.org.apache.commons.collections4.SortedBidiMap; |
||||
import com.fr.third.org.apache.commons.collections4.Unmodifiable; |
||||
import com.fr.third.org.apache.commons.collections4.iterators.UnmodifiableOrderedMapIterator; |
||||
import com.fr.third.org.apache.commons.collections4.map.UnmodifiableEntrySet; |
||||
import com.fr.third.org.apache.commons.collections4.map.UnmodifiableSortedMap; |
||||
import com.fr.third.org.apache.commons.collections4.set.UnmodifiableSet; |
||||
|
||||
/** |
||||
* Decorates another {@link SortedBidiMap} to ensure it can't be altered. |
||||
* <p> |
||||
* Attempts to modify it will result in an {@link UnsupportedOperationException}. |
||||
* |
||||
* @since 3.0 |
||||
* @version $Id: UnmodifiableSortedBidiMap.java 1686855 2015-06-22 13:00:27Z tn $ |
||||
*/ |
||||
public final class UnmodifiableSortedBidiMap<K, V> |
||||
extends AbstractSortedBidiMapDecorator<K, V> implements Unmodifiable { |
||||
|
||||
/** The inverse unmodifiable map */ |
||||
private UnmodifiableSortedBidiMap<V, K> inverse; |
||||
|
||||
/** |
||||
* Factory method to create an unmodifiable map. |
||||
* <p> |
||||
* If the map passed in is already unmodifiable, it is returned. |
||||
* |
||||
* @param <K> the key type |
||||
* @param <V> the value type |
||||
* @param map the map to decorate, must not be null |
||||
* @return an unmodifiable SortedBidiMap |
||||
* @throws NullPointerException if map is null |
||||
* @since 4.0 |
||||
*/ |
||||
public static <K, V> SortedBidiMap<K, V> unmodifiableSortedBidiMap(final SortedBidiMap<K, ? extends V> map) { |
||||
if (map instanceof Unmodifiable) { |
||||
@SuppressWarnings("unchecked") // safe to upcast
|
||||
final SortedBidiMap<K, V> tmpMap = (SortedBidiMap<K, V>) map; |
||||
return tmpMap; |
||||
} |
||||
return new UnmodifiableSortedBidiMap<K, V>(map); |
||||
} |
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/** |
||||
* Constructor that wraps (not copies). |
||||
* |
||||
* @param map the map to decorate, must not be null |
||||
* @throws NullPointerException if map is null |
||||
*/ |
||||
@SuppressWarnings("unchecked") // safe to upcast
|
||||
private UnmodifiableSortedBidiMap(final SortedBidiMap<K, ? extends V> map) { |
||||
super((SortedBidiMap<K, V>) map); |
||||
} |
||||
|
||||
//-----------------------------------------------------------------------
|
||||
@Override |
||||
public void clear() { |
||||
throw new UnsupportedOperationException(); |
||||
} |
||||
|
||||
@Override |
||||
public V put(final K key, final V value) { |
||||
throw new UnsupportedOperationException(); |
||||
} |
||||
|
||||
@Override |
||||
public void putAll(final Map<? extends K, ? extends V> mapToCopy) { |
||||
throw new UnsupportedOperationException(); |
||||
} |
||||
|
||||
@Override |
||||
public V remove(final Object key) { |
||||
throw new UnsupportedOperationException(); |
||||
} |
||||
|
||||
@Override |
||||
public Set<Map.Entry<K, V>> entrySet() { |
||||
final Set<Map.Entry<K, V>> set = super.entrySet(); |
||||
return UnmodifiableEntrySet.unmodifiableEntrySet(set); |
||||
} |
||||
|
||||
@Override |
||||
public Set<K> keySet() { |
||||
final Set<K> set = super.keySet(); |
||||
return UnmodifiableSet.unmodifiableSet(set); |
||||
} |
||||
|
||||
@Override |
||||
public Set<V> values() { |
||||
final Set<V> set = super.values(); |
||||
return UnmodifiableSet.unmodifiableSet(set); |
||||
} |
||||
|
||||
//-----------------------------------------------------------------------
|
||||
@Override |
||||
public K removeValue(final Object value) { |
||||
throw new UnsupportedOperationException(); |
||||
} |
||||
|
||||
//-----------------------------------------------------------------------
|
||||
@Override |
||||
public OrderedMapIterator<K, V> mapIterator() { |
||||
final OrderedMapIterator<K, V> it = decorated().mapIterator(); |
||||
return UnmodifiableOrderedMapIterator.unmodifiableOrderedMapIterator(it); |
||||
} |
||||
|
||||
//-----------------------------------------------------------------------
|
||||
@Override |
||||
public SortedBidiMap<V, K> inverseBidiMap() { |
||||
if (inverse == null) { |
||||
inverse = new UnmodifiableSortedBidiMap<V, K>(decorated().inverseBidiMap()); |
||||
inverse.inverse = this; |
||||
} |
||||
return inverse; |
||||
} |
||||
|
||||
@Override |
||||
public SortedMap<K, V> subMap(final K fromKey, final K toKey) { |
||||
final SortedMap<K, V> sm = decorated().subMap(fromKey, toKey); |
||||
return UnmodifiableSortedMap.unmodifiableSortedMap(sm); |
||||
} |
||||
|
||||
@Override |
||||
public SortedMap<K, V> headMap(final K toKey) { |
||||
final SortedMap<K, V> sm = decorated().headMap(toKey); |
||||
return UnmodifiableSortedMap.unmodifiableSortedMap(sm); |
||||
} |
||||
|
||||
@Override |
||||
public SortedMap<K, V> tailMap(final K fromKey) { |
||||
final SortedMap<K, V> sm = decorated().tailMap(fromKey); |
||||
return UnmodifiableSortedMap.unmodifiableSortedMap(sm); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,41 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
/** |
||||
* This package contains implementations of the |
||||
* {@link org.apache.commons.collections4.BidiMap BidiMap}, |
||||
* {@link org.apache.commons.collections4.OrderedBidiMap OrderedBidiMap} and |
||||
* {@link org.apache.commons.collections4.SortedBidiMap SortedBidiMap} interfaces. |
||||
* A BidiMap is an extension to Map that allows keys and values to be looked up with equal ease. |
||||
* One example usage is a system communicating to a legacy datasource that must convert codes |
||||
* from the new format to the old format and vice versa. |
||||
* <p> |
||||
* The following implementations are provided in the package: |
||||
* <ul> |
||||
* <li>DualHashBidiMap - uses two HashMaps to implement BidiMap |
||||
* <li>DualLinkedHashBidiMap - uses two LinkedHashMaps to implement BidiMap |
||||
* <li>DualTreeBidiMap - uses two TreeMaps to implement SortedBidiMap |
||||
* <li>TreeBidiMap - red-black tree implementation of OrderedBidiMap |
||||
* </ul> |
||||
* <p> |
||||
* The following decorators are provided in the package: |
||||
* <ul> |
||||
* <li>Unmodifiable - ensures the map cannot be altered |
||||
* </ul> |
||||
* |
||||
* @version $Id: package-info.java 1477745 2013-04-30 18:08:32Z tn $ |
||||
*/ |
||||
package com.fr.third.org.apache.commons.collections4.bidimap; |
@ -0,0 +1,178 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package com.fr.third.org.apache.commons.collections4.collection; |
||||
|
||||
import java.io.Serializable; |
||||
import java.util.Collection; |
||||
import java.util.Iterator; |
||||
|
||||
/** |
||||
* Decorates another <code>Collection</code> to provide additional behaviour. |
||||
* <p> |
||||
* Each method call made on this <code>Collection</code> is forwarded to the |
||||
* decorated <code>Collection</code>. This class is used as a framework on which |
||||
* to build to extensions such as synchronized and unmodifiable behaviour. The |
||||
* main advantage of decoration is that one decorator can wrap any implementation |
||||
* of <code>Collection</code>, whereas sub-classing requires a new class to be |
||||
* written for each implementation. |
||||
* <p> |
||||
* This implementation does not perform any special processing with |
||||
* {@link #iterator()}. Instead it simply returns the value from the |
||||
* wrapped collection. This may be undesirable, for example if you are trying |
||||
* to write an unmodifiable implementation it might provide a loophole. |
||||
* <p> |
||||
* This implementation does not forward the hashCode and equals methods through |
||||
* to the backing object, but relies on Object's implementation. This is necessary |
||||
* to preserve the symmetry of equals. Custom definitions of equality are usually |
||||
* based on an interface, such as Set or List, so that the implementation of equals |
||||
* can cast the object being tested for equality to the custom interface. |
||||
* AbstractCollectionDecorator does not implement such custom interfaces directly; |
||||
* they are implemented only in subclasses. Therefore, forwarding equals would break |
||||
* symmetry, as the forwarding object might consider itself equal to the object being |
||||
* tested, but the reverse could not be true. This behavior is consistent with the |
||||
* JDK's collection wrappers, such as {@link java.util.Collections#unmodifiableCollection(Collection)}. |
||||
* Use an interface-specific subclass of AbstractCollectionDecorator, such as |
||||
* AbstractListDecorator, to preserve equality behavior, or override equals directly. |
||||
* |
||||
* @param <E> the type of the elements in the collection |
||||
* @since 3.0 |
||||
* @version $Id: AbstractCollectionDecorator.java 1686855 2015-06-22 13:00:27Z tn $ |
||||
*/ |
||||
public abstract class AbstractCollectionDecorator<E> |
||||
implements Collection<E>, Serializable { |
||||
|
||||
/** Serialization version */ |
||||
private static final long serialVersionUID = 6249888059822088500L; |
||||
|
||||
/** The collection being decorated */ |
||||
private Collection<E> collection; |
||||
|
||||
/** |
||||
* Constructor only used in deserialization, do not use otherwise. |
||||
* @since 3.1 |
||||
*/ |
||||
protected AbstractCollectionDecorator() { |
||||
super(); |
||||
} |
||||
|
||||
/** |
||||
* Constructor that wraps (not copies). |
||||
* |
||||
* @param coll the collection to decorate, must not be null |
||||
* @throws NullPointerException if the collection is null |
||||
*/ |
||||
protected AbstractCollectionDecorator(final Collection<E> coll) { |
||||
if (coll == null) { |
||||
throw new NullPointerException("Collection must not be null."); |
||||
} |
||||
this.collection = coll; |
||||
} |
||||
|
||||
/** |
||||
* Gets the collection being decorated. |
||||
* All access to the decorated collection goes via this method. |
||||
* |
||||
* @return the decorated collection |
||||
*/ |
||||
protected Collection<E> decorated() { |
||||
return collection; |
||||
} |
||||
|
||||
/** |
||||
* Sets the collection being decorated. |
||||
* <p> |
||||
* <b>NOTE:</b> this method should only be used during deserialization |
||||
* |
||||
* @param coll the decorated collection |
||||
*/ |
||||
protected void setCollection(final Collection<E> coll) { |
||||
this.collection = coll; |
||||
} |
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
@Override |
||||
public boolean add(final E object) { |
||||
return decorated().add(object); |
||||
} |
||||
|
||||
@Override |
||||
public boolean addAll(final Collection<? extends E> coll) { |
||||
return decorated().addAll(coll); |
||||
} |
||||
|
||||
@Override |
||||
public void clear() { |
||||
decorated().clear(); |
||||
} |
||||
|
||||
@Override |
||||
public boolean contains(final Object object) { |
||||
return decorated().contains(object); |
||||
} |
||||
|
||||
@Override |
||||
public boolean isEmpty() { |
||||
return decorated().isEmpty(); |
||||
} |
||||
|
||||
@Override |
||||
public Iterator<E> iterator() { |
||||
return decorated().iterator(); |
||||
} |
||||
|
||||
@Override |
||||
public boolean remove(final Object object) { |
||||
return decorated().remove(object); |
||||
} |
||||
|
||||
@Override |
||||
public int size() { |
||||
return decorated().size(); |
||||
} |
||||
|
||||
@Override |
||||
public Object[] toArray() { |
||||
return decorated().toArray(); |
||||
} |
||||
|
||||
@Override |
||||
public <T> T[] toArray(final T[] object) { |
||||
return decorated().toArray(object); |
||||
} |
||||
|
||||
@Override |
||||
public boolean containsAll(final Collection<?> coll) { |
||||
return decorated().containsAll(coll); |
||||
} |
||||
|
||||
@Override |
||||
public boolean removeAll(final Collection<?> coll) { |
||||
return decorated().removeAll(coll); |
||||
} |
||||
|
||||
@Override |
||||
public boolean retainAll(final Collection<?> coll) { |
||||
return decorated().retainAll(coll); |
||||
} |
||||
|
||||
@Override |
||||
public String toString() { |
||||
return decorated().toString(); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,483 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package com.fr.third.org.apache.commons.collections4.collection; |
||||
|
||||
import java.io.Serializable; |
||||
import java.lang.reflect.Array; |
||||
import java.util.ArrayList; |
||||
import java.util.Arrays; |
||||
import java.util.Collection; |
||||
import java.util.Iterator; |
||||
import java.util.List; |
||||
|
||||
import com.fr.third.org.apache.commons.collections4.iterators.EmptyIterator; |
||||
import com.fr.third.org.apache.commons.collections4.list.UnmodifiableList; |
||||
import com.fr.third.org.apache.commons.collections4.iterators.EmptyIterator; |
||||
import com.fr.third.org.apache.commons.collections4.iterators.IteratorChain; |
||||
import com.fr.third.org.apache.commons.collections4.list.UnmodifiableList; |
||||
|
||||
/** |
||||
* Decorates a collection of other collections to provide a single unified view. |
||||
* <p> |
||||
* Changes made to this collection will actually be made on the decorated collection. |
||||
* Add and remove operations require the use of a pluggable strategy. If no |
||||
* strategy is provided then add and remove are unsupported. |
||||
* |
||||
* @param <E> the type of the elements in the collection |
||||
* @since 3.0 |
||||
* @version $Id: CompositeCollection.java 1683951 2015-06-06 20:19:03Z tn $ |
||||
*/ |
||||
public class CompositeCollection<E> implements Collection<E>, Serializable { |
||||
|
||||
/** Serialization version */ |
||||
private static final long serialVersionUID = 8417515734108306801L; |
||||
|
||||
/** CollectionMutator to handle changes to the collection */ |
||||
private CollectionMutator<E> mutator; |
||||
|
||||
/** Collections in the composite */ |
||||
private final List<Collection<E>> all = new ArrayList<Collection<E>>(); |
||||
|
||||
/** |
||||
* Create an empty CompositeCollection. |
||||
*/ |
||||
public CompositeCollection() { |
||||
super(); |
||||
} |
||||
|
||||
/** |
||||
* Create a Composite Collection with one collection. |
||||
* |
||||
* @param compositeCollection the Collection to be appended to the composite |
||||
*/ |
||||
public CompositeCollection(final Collection<E> compositeCollection) { |
||||
super(); |
||||
addComposited(compositeCollection); |
||||
} |
||||
|
||||
/** |
||||
* Create a Composite Collection with two collections. |
||||
* |
||||
* @param compositeCollection1 the Collection to be appended to the composite |
||||
* @param compositeCollection2 the Collection to be appended to the composite |
||||
*/ |
||||
public CompositeCollection(final Collection<E> compositeCollection1, |
||||
final Collection<E> compositeCollection2) { |
||||
super(); |
||||
addComposited(compositeCollection1, compositeCollection2); |
||||
} |
||||
|
||||
/** |
||||
* Create a Composite Collection with an array of collections. |
||||
* |
||||
* @param compositeCollections the collections to composite |
||||
*/ |
||||
public CompositeCollection(final Collection<E>... compositeCollections) { |
||||
super(); |
||||
addComposited(compositeCollections); |
||||
} |
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/** |
||||
* Gets the size of this composite collection. |
||||
* <p> |
||||
* This implementation calls <code>size()</code> on each collection. |
||||
* |
||||
* @return total number of elements in all contained containers |
||||
*/ |
||||
@Override |
||||
public int size() { |
||||
int size = 0; |
||||
for (final Collection<E> item : all) { |
||||
size += item.size(); |
||||
} |
||||
return size; |
||||
} |
||||
|
||||
/** |
||||
* Checks whether this composite collection is empty. |
||||
* <p> |
||||
* This implementation calls <code>isEmpty()</code> on each collection. |
||||
* |
||||
* @return true if all of the contained collections are empty |
||||
*/ |
||||
@Override |
||||
public boolean isEmpty() { |
||||
for (final Collection<E> item : all) { |
||||
if (item.isEmpty() == false) { |
||||
return false; |
||||
} |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
/** |
||||
* Checks whether this composite collection contains the object. |
||||
* <p> |
||||
* This implementation calls <code>contains()</code> on each collection. |
||||
* |
||||
* @param obj the object to search for |
||||
* @return true if obj is contained in any of the contained collections |
||||
*/ |
||||
@Override |
||||
public boolean contains(final Object obj) { |
||||
for (final Collection<E> item : all) { |
||||
if (item.contains(obj)) { |
||||
return true; |
||||
} |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
/** |
||||
* Gets an iterator over all the collections in this composite. |
||||
* <p> |
||||
* This implementation uses an <code>IteratorChain</code>. |
||||
* |
||||
* @return an <code>IteratorChain</code> instance which supports |
||||
* <code>remove()</code>. Iteration occurs over contained collections in |
||||
* the order they were added, but this behavior should not be relied upon. |
||||
* @see IteratorChain |
||||
*/ |
||||
@Override |
||||
public Iterator<E> iterator() { |
||||
if (all.isEmpty()) { |
||||
return EmptyIterator.<E>emptyIterator(); |
||||
} |
||||
final IteratorChain<E> chain = new IteratorChain<E>(); |
||||
for (final Collection<E> item : all) { |
||||
chain.addIterator(item.iterator()); |
||||
} |
||||
return chain; |
||||
} |
||||
|
||||
/** |
||||
* Returns an array containing all of the elements in this composite. |
||||
* |
||||
* @return an object array of all the elements in the collection |
||||
*/ |
||||
@Override |
||||
public Object[] toArray() { |
||||
final Object[] result = new Object[size()]; |
||||
int i = 0; |
||||
for (final Iterator<E> it = iterator(); it.hasNext(); i++) { |
||||
result[i] = it.next(); |
||||
} |
||||
return result; |
||||
} |
||||
|
||||
/** |
||||
* Returns an object array, populating the supplied array if possible. |
||||
* See <code>Collection</code> interface for full details. |
||||
* |
||||
* @param <T> the type of the elements in the collection |
||||
* @param array the array to use, populating if possible |
||||
* @return an array of all the elements in the collection |
||||
*/ |
||||
@Override |
||||
@SuppressWarnings("unchecked") |
||||
public <T> T[] toArray(final T[] array) { |
||||
final int size = size(); |
||||
Object[] result = null; |
||||
if (array.length >= size) { |
||||
result = array; |
||||
} else { |
||||
result = (Object[]) Array.newInstance(array.getClass().getComponentType(), size); |
||||
} |
||||
|
||||
int offset = 0; |
||||
for (final Collection<E> item : all) { |
||||
for (final E e : item) { |
||||
result[offset++] = e; |
||||
} |
||||
} |
||||
if (result.length > size) { |
||||
result[size] = null; |
||||
} |
||||
return (T[]) result; |
||||
} |
||||
|
||||
/** |
||||
* Adds an object to the collection, throwing UnsupportedOperationException |
||||
* unless a CollectionMutator strategy is specified. |
||||
* |
||||
* @param obj the object to add |
||||
* @return {@code true} if the collection was modified |
||||
* @throws UnsupportedOperationException if CollectionMutator hasn't been set |
||||
* @throws UnsupportedOperationException if add is unsupported |
||||
* @throws ClassCastException if the object cannot be added due to its type |
||||
* @throws NullPointerException if the object cannot be added because its null |
||||
* @throws IllegalArgumentException if the object cannot be added |
||||
*/ |
||||
@Override |
||||
public boolean add(final E obj) { |
||||
if (mutator == null) { |
||||
throw new UnsupportedOperationException( |
||||
"add() is not supported on CompositeCollection without a CollectionMutator strategy"); |
||||
} |
||||
return mutator.add(this, all, obj); |
||||
} |
||||
|
||||
/** |
||||
* Removes an object from the collection, throwing UnsupportedOperationException |
||||
* unless a CollectionMutator strategy is specified. |
||||
* |
||||
* @param obj the object being removed |
||||
* @return true if the collection is changed |
||||
* @throws UnsupportedOperationException if removed is unsupported |
||||
* @throws ClassCastException if the object cannot be removed due to its type |
||||
* @throws NullPointerException if the object cannot be removed because its null |
||||
* @throws IllegalArgumentException if the object cannot be removed |
||||
*/ |
||||
@Override |
||||
public boolean remove(final Object obj) { |
||||
if (mutator == null) { |
||||
throw new UnsupportedOperationException( |
||||
"remove() is not supported on CompositeCollection without a CollectionMutator strategy"); |
||||
} |
||||
return mutator.remove(this, all, obj); |
||||
} |
||||
|
||||
/** |
||||
* Checks whether this composite contains all the elements in the specified collection. |
||||
* <p> |
||||
* This implementation calls <code>contains()</code> for each element in the |
||||
* specified collection. |
||||
* |
||||
* @param coll the collection to check for |
||||
* @return true if all elements contained |
||||
*/ |
||||
@Override |
||||
public boolean containsAll(final Collection<?> coll) { |
||||
for (final Object item : coll) { |
||||
if (contains(item) == false) { |
||||
return false; |
||||
} |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
/** |
||||
* Adds a collection of elements to this collection, throwing |
||||
* UnsupportedOperationException unless a CollectionMutator strategy is specified. |
||||
* |
||||
* @param coll the collection to add |
||||
* @return true if the collection was modified |
||||
* @throws UnsupportedOperationException if CollectionMutator hasn't been set |
||||
* @throws UnsupportedOperationException if add is unsupported |
||||
* @throws ClassCastException if the object cannot be added due to its type |
||||
* @throws NullPointerException if the object cannot be added because its null |
||||
* @throws IllegalArgumentException if the object cannot be added |
||||
*/ |
||||
@Override |
||||
public boolean addAll(final Collection<? extends E> coll) { |
||||
if (mutator == null) { |
||||
throw new UnsupportedOperationException( |
||||
"addAll() is not supported on CompositeCollection without a CollectionMutator strategy"); |
||||
} |
||||
return mutator.addAll(this, all, coll); |
||||
} |
||||
|
||||
/** |
||||
* Removes the elements in the specified collection from this composite collection. |
||||
* <p> |
||||
* This implementation calls <code>removeAll</code> on each collection. |
||||
* |
||||
* @param coll the collection to remove |
||||
* @return true if the collection was modified |
||||
* @throws UnsupportedOperationException if removeAll is unsupported |
||||
*/ |
||||
@Override |
||||
public boolean removeAll(final Collection<?> coll) { |
||||
if (coll.size() == 0) { |
||||
return false; |
||||
} |
||||
boolean changed = false; |
||||
for (final Collection<E> item : all) { |
||||
changed |= item.removeAll(coll); |
||||
} |
||||
return changed; |
||||
} |
||||
|
||||
/** |
||||
* Retains all the elements in the specified collection in this composite collection, |
||||
* removing all others. |
||||
* <p> |
||||
* This implementation calls <code>retainAll()</code> on each collection. |
||||
* |
||||
* @param coll the collection to remove |
||||
* @return true if the collection was modified |
||||
* @throws UnsupportedOperationException if retainAll is unsupported |
||||
*/ |
||||
@Override |
||||
public boolean retainAll(final Collection<?> coll) { |
||||
boolean changed = false; |
||||
for (final Collection<E> item : all) { |
||||
changed |= item.retainAll(coll); |
||||
} |
||||
return changed; |
||||
} |
||||
|
||||
/** |
||||
* Removes all of the elements from this collection . |
||||
* <p> |
||||
* This implementation calls <code>clear()</code> on each collection. |
||||
* |
||||
* @throws UnsupportedOperationException if clear is unsupported |
||||
*/ |
||||
@Override |
||||
public void clear() { |
||||
for (final Collection<E> coll : all) { |
||||
coll.clear(); |
||||
} |
||||
} |
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/** |
||||
* Specify a CollectionMutator strategy instance to handle changes. |
||||
* |
||||
* @param mutator the mutator to use |
||||
*/ |
||||
public void setMutator(final CollectionMutator<E> mutator) { |
||||
this.mutator = mutator; |
||||
} |
||||
|
||||
/** |
||||
* Add these Collections to the list of collections in this composite |
||||
* |
||||
* @param compositeCollection the Collection to be appended to the composite |
||||
*/ |
||||
public void addComposited(final Collection<E> compositeCollection) { |
||||
all.add(compositeCollection); |
||||
} |
||||
|
||||
/** |
||||
* Add these Collections to the list of collections in this composite |
||||
* |
||||
* @param compositeCollection1 the Collection to be appended to the composite |
||||
* @param compositeCollection2 the Collection to be appended to the composite |
||||
*/ |
||||
public void addComposited(final Collection<E> compositeCollection1, |
||||
final Collection<E> compositeCollection2) { |
||||
all.add(compositeCollection1); |
||||
all.add(compositeCollection2); |
||||
} |
||||
|
||||
/** |
||||
* Add these Collections to the list of collections in this composite |
||||
* |
||||
* @param compositeCollections the Collections to be appended to the composite |
||||
*/ |
||||
public void addComposited(final Collection<E>... compositeCollections) { |
||||
all.addAll(Arrays.asList(compositeCollections)); |
||||
} |
||||
|
||||
/** |
||||
* Removes a collection from the those being decorated in this composite. |
||||
* |
||||
* @param coll collection to be removed |
||||
*/ |
||||
public void removeComposited(final Collection<E> coll) { |
||||
all.remove(coll); |
||||
} |
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/** |
||||
* Returns a new collection containing all of the elements |
||||
* |
||||
* @return A new ArrayList containing all of the elements in this composite. |
||||
* The new collection is <i>not</i> backed by this composite. |
||||
*/ |
||||
public Collection<E> toCollection() { |
||||
return new ArrayList<E>(this); |
||||
} |
||||
|
||||
/** |
||||
* Gets the collections being decorated. |
||||
* |
||||
* @return Unmodifiable list of all collections in this composite. |
||||
*/ |
||||
public List<Collection<E>> getCollections() { |
||||
return UnmodifiableList.unmodifiableList(all); |
||||
} |
||||
|
||||
/** |
||||
* Get the collection mutator to be used for this CompositeCollection. |
||||
* @return CollectionMutator<E> |
||||
*/ |
||||
protected CollectionMutator<E> getMutator() { |
||||
return mutator; |
||||
} |
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/** |
||||
* Pluggable strategy to handle changes to the composite. |
||||
* |
||||
* @param <E> the element being held in the collection |
||||
*/ |
||||
public interface CollectionMutator<E> extends Serializable { |
||||
|
||||
/** |
||||
* Called when an object is to be added to the composite. |
||||
* |
||||
* @param composite the CompositeCollection being changed |
||||
* @param collections all of the Collection instances in this CompositeCollection |
||||
* @param obj the object being added |
||||
* @return true if the collection is changed |
||||
* @throws UnsupportedOperationException if add is unsupported |
||||
* @throws ClassCastException if the object cannot be added due to its type |
||||
* @throws NullPointerException if the object cannot be added because its null |
||||
* @throws IllegalArgumentException if the object cannot be added |
||||
*/ |
||||
boolean add(CompositeCollection<E> composite, List<Collection<E>> collections, E obj); |
||||
|
||||
/** |
||||
* Called when a collection is to be added to the composite. |
||||
* |
||||
* @param composite the CompositeCollection being changed |
||||
* @param collections all of the Collection instances in this CompositeCollection |
||||
* @param coll the collection being added |
||||
* @return true if the collection is changed |
||||
* @throws UnsupportedOperationException if add is unsupported |
||||
* @throws ClassCastException if the object cannot be added due to its type |
||||
* @throws NullPointerException if the object cannot be added because its null |
||||
* @throws IllegalArgumentException if the object cannot be added |
||||
*/ |
||||
boolean addAll(CompositeCollection<E> composite, |
||||
List<Collection<E>> collections, |
||||
Collection<? extends E> coll); |
||||
|
||||
/** |
||||
* Called when an object is to be removed to the composite. |
||||
* |
||||
* @param composite the CompositeCollection being changed |
||||
* @param collections all of the Collection instances in this CompositeCollection |
||||
* @param obj the object being removed |
||||
* @return true if the collection is changed |
||||
* @throws UnsupportedOperationException if removed is unsupported |
||||
* @throws ClassCastException if the object cannot be removed due to its type |
||||
* @throws NullPointerException if the object cannot be removed because its null |
||||
* @throws IllegalArgumentException if the object cannot be removed |
||||
*/ |
||||
boolean remove(CompositeCollection<E> composite, |
||||
List<Collection<E>> collections, |
||||
Object obj); |
||||
|
||||
} |
||||
|
||||
} |
||||
|
@ -0,0 +1,263 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package com.fr.third.org.apache.commons.collections4.collection; |
||||
|
||||
import java.util.Collection; |
||||
import java.util.HashMap; |
||||
|
||||
import com.fr.third.org.apache.commons.collections4.MultiMap; |
||||
import com.fr.third.org.apache.commons.collections4.Transformer; |
||||
import com.fr.third.org.apache.commons.collections4.map.MultiValueMap; |
||||
import com.fr.third.org.apache.commons.collections4.MultiMap; |
||||
import com.fr.third.org.apache.commons.collections4.Transformer; |
||||
import com.fr.third.org.apache.commons.collections4.map.MultiValueMap; |
||||
|
||||
/** |
||||
* An IndexedCollection is a Map-like view onto a Collection. It accepts a |
||||
* keyTransformer to define how the keys are converted from the values. |
||||
* <p> |
||||
* Modifications made to this decorator modify the index as well as the |
||||
* decorated {@link Collection}. However, modifications to the underlying |
||||
* {@link Collection} will not update the index and it will get out of sync. |
||||
* <p> |
||||
* If modification of the decorated {@link Collection} is unavoidable, then a |
||||
* call to {@link #reindex()} will update the index to the current contents of |
||||
* the {@link Collection}. |
||||
* |
||||
* @param <K> the type of object in the index. |
||||
* @param <C> the type of object in the collection. |
||||
* |
||||
* @since 4.0 |
||||
* @version $Id: IndexedCollection.java 1683018 2015-06-01 22:41:31Z tn $ |
||||
*/ |
||||
public class IndexedCollection<K, C> extends AbstractCollectionDecorator<C> { |
||||
|
||||
// TODO: replace with MultiValuedMap
|
||||
|
||||
/** Serialization version */ |
||||
private static final long serialVersionUID = -5512610452568370038L; |
||||
|
||||
/** The {@link Transformer} for generating index keys. */ |
||||
private final Transformer<C, K> keyTransformer; |
||||
|
||||
/** The map of indexes to collected objects. */ |
||||
private final MultiMap<K, C> index; |
||||
|
||||
/** The uniqueness constraint for the index. */ |
||||
private final boolean uniqueIndex; |
||||
|
||||
/** |
||||
* Create an {@link IndexedCollection} for a unique index. |
||||
* <p> |
||||
* If an element is added, which maps to an existing key, an {@link IllegalArgumentException} |
||||
* will be thrown. |
||||
* |
||||
* @param <K> the index object type. |
||||
* @param <C> the collection type. |
||||
* @param coll the decorated {@link Collection}. |
||||
* @param keyTransformer the {@link Transformer} for generating index keys. |
||||
* @return the created {@link IndexedCollection}. |
||||
*/ |
||||
public static <K, C> IndexedCollection<K, C> uniqueIndexedCollection(final Collection<C> coll, |
||||
final Transformer<C, K> keyTransformer) { |
||||
return new IndexedCollection<K, C>(coll, keyTransformer, |
||||
MultiValueMap.<K, C>multiValueMap(new HashMap<K, Collection<C>>()), |
||||
true); |
||||
} |
||||
|
||||
/** |
||||
* Create an {@link IndexedCollection} for a non-unique index. |
||||
* |
||||
* @param <K> the index object type. |
||||
* @param <C> the collection type. |
||||
* @param coll the decorated {@link Collection}. |
||||
* @param keyTransformer the {@link Transformer} for generating index keys. |
||||
* @return the created {@link IndexedCollection}. |
||||
*/ |
||||
public static <K, C> IndexedCollection<K, C> nonUniqueIndexedCollection(final Collection<C> coll, |
||||
final Transformer<C, K> keyTransformer) { |
||||
return new IndexedCollection<K, C>(coll, keyTransformer, |
||||
MultiValueMap.<K, C>multiValueMap(new HashMap<K, Collection<C>>()), |
||||
false); |
||||
} |
||||
|
||||
/** |
||||
* Create a {@link IndexedCollection}. |
||||
* |
||||
* @param coll decorated {@link Collection} |
||||
* @param keyTransformer {@link Transformer} for generating index keys |
||||
* @param map map to use as index |
||||
* @param uniqueIndex if the index shall enforce uniqueness of index keys |
||||
*/ |
||||
public IndexedCollection(final Collection<C> coll, final Transformer<C, K> keyTransformer, |
||||
final MultiMap<K, C> map, final boolean uniqueIndex) { |
||||
super(coll); |
||||
this.keyTransformer = keyTransformer; |
||||
this.index = map; |
||||
this.uniqueIndex = uniqueIndex; |
||||
reindex(); |
||||
} |
||||
|
||||
/** |
||||
* {@inheritDoc} |
||||
* |
||||
* @throws IllegalArgumentException if the object maps to an existing key and the index |
||||
* enforces a uniqueness constraint |
||||
*/ |
||||
@Override |
||||
public boolean add(final C object) { |
||||
final boolean added = super.add(object); |
||||
if (added) { |
||||
addToIndex(object); |
||||
} |
||||
return added; |
||||
} |
||||
|
||||
@Override |
||||
public boolean addAll(final Collection<? extends C> coll) { |
||||
boolean changed = false; |
||||
for (final C c: coll) { |
||||
changed |= add(c); |
||||
} |
||||
return changed; |
||||
} |
||||
|
||||
@Override |
||||
public void clear() { |
||||
super.clear(); |
||||
index.clear(); |
||||
} |
||||
|
||||
/** |
||||
* {@inheritDoc} |
||||
* <p> |
||||
* Note: uses the index for fast lookup |
||||
*/ |
||||
@SuppressWarnings("unchecked") |
||||
@Override |
||||
public boolean contains(final Object object) { |
||||
return index.containsKey(keyTransformer.transform((C) object)); |
||||
} |
||||
|
||||
/** |
||||
* {@inheritDoc} |
||||
* <p> |
||||
* Note: uses the index for fast lookup |
||||
*/ |
||||
@Override |
||||
public boolean containsAll(final Collection<?> coll) { |
||||
for (final Object o : coll) { |
||||
if (!contains(o)) { |
||||
return false; |
||||
} |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
/** |
||||
* Get the element associated with the given key. |
||||
* <p> |
||||
* In case of a non-unique index, this method will return the first |
||||
* value associated with the given key. To retrieve all elements associated |
||||
* with a key, use {@link #values(Object)}. |
||||
* |
||||
* @param key key to look up |
||||
* @return element found |
||||
* @see #values(Object) |
||||
*/ |
||||
public C get(final K key) { |
||||
@SuppressWarnings("unchecked") // index is a MultiMap which returns a Collection
|
||||
final Collection<C> coll = (Collection<C>) index.get(key); |
||||
return coll == null ? null : coll.iterator().next(); |
||||
} |
||||
|
||||
/** |
||||
* Get all elements associated with the given key. |
||||
* |
||||
* @param key key to look up |
||||
* @return a collection of elements found, or null if {@code contains(key) == false} |
||||
*/ |
||||
@SuppressWarnings("unchecked") // index is a MultiMap which returns a Collection
|
||||
public Collection<C> values(final K key) { |
||||
return (Collection<C>) index.get(key); |
||||
} |
||||
|
||||
/** |
||||
* Clears the index and re-indexes the entire decorated {@link Collection}. |
||||
*/ |
||||
public void reindex() { |
||||
index.clear(); |
||||
for (final C c : decorated()) { |
||||
addToIndex(c); |
||||
} |
||||
} |
||||
|
||||
@SuppressWarnings("unchecked") |
||||
@Override |
||||
public boolean remove(final Object object) { |
||||
final boolean removed = super.remove(object); |
||||
if (removed) { |
||||
removeFromIndex((C) object); |
||||
} |
||||
return removed; |
||||
} |
||||
|
||||
@Override |
||||
public boolean removeAll(final Collection<?> coll) { |
||||
boolean changed = false; |
||||
for (final Object o : coll) { |
||||
changed |= remove(o); |
||||
} |
||||
return changed; |
||||
} |
||||
|
||||
@Override |
||||
public boolean retainAll(final Collection<?> coll) { |
||||
final boolean changed = super.retainAll(coll); |
||||
if (changed) { |
||||
reindex(); |
||||
} |
||||
return changed; |
||||
} |
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
/** |
||||
* Provides checking for adding the index. |
||||
* |
||||
* @param object the object to index |
||||
* @throws IllegalArgumentException if the object maps to an existing key and the index |
||||
* enforces a uniqueness constraint |
||||
*/ |
||||
private void addToIndex(final C object) { |
||||
final K key = keyTransformer.transform(object); |
||||
if (uniqueIndex && index.containsKey(key)) { |
||||
throw new IllegalArgumentException("Duplicate key in uniquely indexed collection."); |
||||
} |
||||
index.put(key, object); |
||||
} |
||||
|
||||
/** |
||||
* Removes an object from the index. |
||||
* |
||||
* @param object the object to remove |
||||
*/ |
||||
private void removeFromIndex(final C object) { |
||||
index.remove(keyTransformer.transform(object)); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,455 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package com.fr.third.org.apache.commons.collections4.collection; |
||||
|
||||
import java.util.ArrayList; |
||||
import java.util.Collection; |
||||
import java.util.Collections; |
||||
import java.util.HashSet; |
||||
import java.util.LinkedList; |
||||
import java.util.List; |
||||
import java.util.Queue; |
||||
import java.util.Set; |
||||
|
||||
import com.fr.third.org.apache.commons.collections4.Bag; |
||||
import com.fr.third.org.apache.commons.collections4.MultiSet; |
||||
import com.fr.third.org.apache.commons.collections4.Predicate; |
||||
import com.fr.third.org.apache.commons.collections4.bag.HashBag; |
||||
import com.fr.third.org.apache.commons.collections4.bag.PredicatedBag; |
||||
import com.fr.third.org.apache.commons.collections4.functors.NotNullPredicate; |
||||
import com.fr.third.org.apache.commons.collections4.list.PredicatedList; |
||||
import com.fr.third.org.apache.commons.collections4.multiset.HashMultiSet; |
||||
import com.fr.third.org.apache.commons.collections4.multiset.PredicatedMultiSet; |
||||
import com.fr.third.org.apache.commons.collections4.queue.PredicatedQueue; |
||||
import com.fr.third.org.apache.commons.collections4.set.PredicatedSet; |
||||
import com.fr.third.org.apache.commons.collections4.Bag; |
||||
import com.fr.third.org.apache.commons.collections4.MultiSet; |
||||
import com.fr.third.org.apache.commons.collections4.Predicate; |
||||
import com.fr.third.org.apache.commons.collections4.bag.HashBag; |
||||
import com.fr.third.org.apache.commons.collections4.bag.PredicatedBag; |
||||
import com.fr.third.org.apache.commons.collections4.functors.NotNullPredicate; |
||||
import com.fr.third.org.apache.commons.collections4.list.PredicatedList; |
||||
import com.fr.third.org.apache.commons.collections4.multiset.HashMultiSet; |
||||
import com.fr.third.org.apache.commons.collections4.multiset.PredicatedMultiSet; |
||||
import com.fr.third.org.apache.commons.collections4.queue.PredicatedQueue; |
||||
import com.fr.third.org.apache.commons.collections4.set.PredicatedSet; |
||||
|
||||
/** |
||||
* Decorates another {@link Collection} to validate that additions |
||||
* match a specified predicate. |
||||
* <p> |
||||
* This collection exists to provide validation for the decorated collection. |
||||
* It is normally created to decorate an empty collection. |
||||
* If an object cannot be added to the collection, an IllegalArgumentException is thrown. |
||||
* <p> |
||||
* One usage would be to ensure that no null entries are added to the collection: |
||||
* <pre> |
||||
* Collection coll = PredicatedCollection.predicatedCollection(new ArrayList(), NotNullPredicate.INSTANCE); |
||||
* </pre> |
||||
* <p> |
||||
* This class is Serializable from Commons Collections 3.1. |
||||
* |
||||
* @param <E> the type of the elements in the collection |
||||
* @since 3.0 |
||||
* @version $Id: PredicatedCollection.java 1714484 2015-11-15 18:20:41Z tn $ |
||||
*/ |
||||
public class PredicatedCollection<E> extends AbstractCollectionDecorator<E> { |
||||
|
||||
/** Serialization version */ |
||||
private static final long serialVersionUID = -5259182142076705162L; |
||||
|
||||
/** The predicate to use */ |
||||
protected final Predicate<? super E> predicate; |
||||
|
||||
/** |
||||
* Returns a Builder with the given predicate. |
||||
* |
||||
* @param <E> the element type |
||||
* @param predicate the predicate to use |
||||
* @return a new Builder for predicated collections |
||||
* @since 4.1 |
||||
*/ |
||||
public static <E> Builder<E> builder(final Predicate<? super E> predicate) { |
||||
return new Builder<E>(predicate); |
||||
} |
||||
|
||||
/** |
||||
* Returns a Builder with a NotNullPredicate. |
||||
* |
||||
* @param <E> the element type |
||||
* @return a new Builder for predicated collections that ignores null values. |
||||
* @since 4.1 |
||||
*/ |
||||
public static <E> Builder<E> notNullBuilder() { |
||||
return new Builder<E>(NotNullPredicate.<E>notNullPredicate()); |
||||
} |
||||
|
||||
/** |
||||
* Factory method to create a predicated (validating) collection. |
||||
* <p> |
||||
* If there are any elements already in the collection being decorated, they |
||||
* are validated. |
||||
* |
||||
* @param <T> the type of the elements in the collection |
||||
* @param coll the collection to decorate, must not be null |
||||
* @param predicate the predicate to use for validation, must not be null |
||||
* @return a new predicated collection |
||||
* @throws NullPointerException if collection or predicate is null |
||||
* @throws IllegalArgumentException if the collection contains invalid elements |
||||
* @since 4.0 |
||||
*/ |
||||
public static <T> PredicatedCollection<T> predicatedCollection(final Collection<T> coll, |
||||
final Predicate<? super T> predicate) { |
||||
return new PredicatedCollection<T>(coll, predicate); |
||||
} |
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/** |
||||
* Constructor that wraps (not copies). |
||||
* <p> |
||||
* If there are any elements already in the collection being decorated, they |
||||
* are validated. |
||||
* |
||||
* @param coll the collection to decorate, must not be null |
||||
* @param predicate the predicate to use for validation, must not be null |
||||
* @throws NullPointerException if collection or predicate is null |
||||
* @throws IllegalArgumentException if the collection contains invalid elements |
||||
*/ |
||||
protected PredicatedCollection(final Collection<E> coll, final Predicate<? super E> predicate) { |
||||
super(coll); |
||||
if (predicate == null) { |
||||
throw new NullPointerException("Predicate must not be null."); |
||||
} |
||||
this.predicate = predicate; |
||||
for (final E item : coll) { |
||||
validate(item); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Validates the object being added to ensure it matches the predicate. |
||||
* <p> |
||||
* The predicate itself should not throw an exception, but return false to |
||||
* indicate that the object cannot be added. |
||||
* |
||||
* @param object the object being added |
||||
* @throws IllegalArgumentException if the add is invalid |
||||
*/ |
||||
protected void validate(final E object) { |
||||
if (predicate.evaluate(object) == false) { |
||||
throw new IllegalArgumentException("Cannot add Object '" + object + "' - Predicate '" + |
||||
predicate + "' rejected it"); |
||||
} |
||||
} |
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/** |
||||
* Override to validate the object being added to ensure it matches |
||||
* the predicate. |
||||
* |
||||
* @param object the object being added |
||||
* @return the result of adding to the underlying collection |
||||
* @throws IllegalArgumentException if the add is invalid |
||||
*/ |
||||
@Override |
||||
public boolean add(final E object) { |
||||
validate(object); |
||||
return decorated().add(object); |
||||
} |
||||
|
||||
/** |
||||
* Override to validate the objects being added to ensure they match |
||||
* the predicate. If any one fails, no update is made to the underlying |
||||
* collection. |
||||
* |
||||
* @param coll the collection being added |
||||
* @return the result of adding to the underlying collection |
||||
* @throws IllegalArgumentException if the add is invalid |
||||
*/ |
||||
@Override |
||||
public boolean addAll(final Collection<? extends E> coll) { |
||||
for (final E item : coll) { |
||||
validate(item); |
||||
} |
||||
return decorated().addAll(coll); |
||||
} |
||||
|
||||
/** |
||||
* Builder for creating predicated collections. |
||||
* <p> |
||||
* Create a Builder with a predicate to validate elements against, then add any elements |
||||
* to the builder. Elements that fail the predicate will be added to a rejected list. |
||||
* Finally create or decorate a collection using the createPredicated[List,Set,Bag,Queue] methods. |
||||
* <p> |
||||
* An example: |
||||
* <pre> |
||||
* Predicate<String> predicate = NotNullPredicate.notNullPredicate(); |
||||
* PredicatedCollectionBuilder<String> builder = PredicatedCollection.builder(predicate); |
||||
* builder.add("item1"); |
||||
* builder.add(null); |
||||
* builder.add("item2"); |
||||
* List<String> predicatedList = builder.createPredicatedList(); |
||||
* </pre> |
||||
* <p> |
||||
* At the end of the code fragment above predicatedList is protected by the predicate supplied |
||||
* to the builder and it contains item1 and item2. |
||||
* <p> |
||||
* More elements can be added to the builder once a predicated collection has been created, |
||||
* but these elements will not be reflected in already created collections. |
||||
* |
||||
* @param <E> the element type |
||||
* @since 4.1 |
||||
*/ |
||||
public static class Builder<E> { |
||||
|
||||
/** The predicate to use. */ |
||||
private final Predicate<? super E> predicate; |
||||
|
||||
/** The buffer containing valid elements. */ |
||||
private final List<E> accepted = new ArrayList<E>(); |
||||
|
||||
/** The buffer containing rejected elements. */ |
||||
private final List<E> rejected = new ArrayList<E>(); |
||||
|
||||
// -----------------------------------------------------------------------
|
||||
/** |
||||
* Constructs a PredicatedCollectionBuilder with the specified Predicate. |
||||
* |
||||
* @param predicate the predicate to use |
||||
* @throws NullPointerException if predicate is null |
||||
*/ |
||||
public Builder(final Predicate<? super E> predicate) { |
||||
if (predicate == null) { |
||||
throw new NullPointerException("Predicate must not be null"); |
||||
} |
||||
this.predicate = predicate; |
||||
} |
||||
|
||||
/** |
||||
* Adds the item to the builder. |
||||
* <p> |
||||
* If the predicate is true, it is added to the list of accepted elements, |
||||
* otherwise it is added to the rejected list. |
||||
* |
||||
* @param item the element to add |
||||
* @return the PredicatedCollectionBuilder. |
||||
*/ |
||||
public Builder<E> add(final E item) { |
||||
if (predicate.evaluate(item)) { |
||||
accepted.add(item); |
||||
} else { |
||||
rejected.add(item); |
||||
} |
||||
return this; |
||||
} |
||||
|
||||
/** |
||||
* Adds all elements from the given collection to the builder. |
||||
* <p> |
||||
* All elements for which the predicate evaluates to true will be added to the |
||||
* list of accepted elements, otherwise they are added to the rejected list. |
||||
* |
||||
* @param items the elements to add to the builder |
||||
* @return the PredicatedCollectionBuilder. |
||||
*/ |
||||
public Builder<E> addAll(final Collection<? extends E> items) { |
||||
if (items != null) { |
||||
for (E item : items) { |
||||
add(item); |
||||
} |
||||
} |
||||
return this; |
||||
} |
||||
|
||||
/** |
||||
* Create a new predicated list filled with the accepted elements. |
||||
* <p> |
||||
* The builder is not modified by this method, so it is possible to create more collections |
||||
* or add more elements afterwards. Further changes will not propagate to the returned list. |
||||
* |
||||
* @return a new predicated list. |
||||
*/ |
||||
public List<E> createPredicatedList() { |
||||
return createPredicatedList(new ArrayList<E>()); |
||||
} |
||||
|
||||
/** |
||||
* Decorates the given list with validating behavior using the predicate. All accepted elements |
||||
* are appended to the list. If the list already contains elements, they are validated. |
||||
* <p> |
||||
* The builder is not modified by this method, so it is possible to create more collections |
||||
* or add more elements afterwards. Further changes will not propagate to the returned list. |
||||
* |
||||
* @param list the List to decorate, must not be null |
||||
* @return the decorated list. |
||||
* @throws NullPointerException if list is null |
||||
* @throws IllegalArgumentException if list contains invalid elements |
||||
*/ |
||||
public List<E> createPredicatedList(final List<E> list) { |
||||
if (list == null) { |
||||
throw new NullPointerException("List must not be null."); |
||||
} |
||||
final List<E> predicatedList = PredicatedList.predicatedList(list, predicate); |
||||
predicatedList.addAll(accepted); |
||||
return predicatedList; |
||||
} |
||||
|
||||
/** |
||||
* Create a new predicated set filled with the accepted elements. |
||||
* <p> |
||||
* The builder is not modified by this method, so it is possible to create more collections |
||||
* or add more elements afterwards. Further changes will not propagate to the returned set. |
||||
* |
||||
* @return a new predicated set. |
||||
*/ |
||||
public Set<E> createPredicatedSet() { |
||||
return createPredicatedSet(new HashSet<E>()); |
||||
} |
||||
|
||||
/** |
||||
* Decorates the given list with validating behavior using the predicate. All accepted elements |
||||
* are appended to the set. If the set already contains elements, they are validated. |
||||
* <p> |
||||
* The builder is not modified by this method, so it is possible to create more collections |
||||
* or add more elements afterwards. Further changes will not propagate to the returned set. |
||||
* |
||||
* @param set the set to decorate, must not be null |
||||
* @return the decorated set. |
||||
* @throws NullPointerException if set is null |
||||
* @throws IllegalArgumentException if set contains invalid elements |
||||
*/ |
||||
public Set<E> createPredicatedSet(final Set<E> set) { |
||||
if (set == null) { |
||||
throw new NullPointerException("Set must not be null."); |
||||
} |
||||
final PredicatedSet<E> predicatedSet = PredicatedSet.predicatedSet(set, predicate); |
||||
predicatedSet.addAll(accepted); |
||||
return predicatedSet; |
||||
} |
||||
|
||||
/** |
||||
* Create a new predicated multiset filled with the accepted elements. |
||||
* <p> |
||||
* The builder is not modified by this method, so it is possible to create more collections |
||||
* or add more elements afterwards. Further changes will not propagate to the returned multiset. |
||||
* |
||||
* @return a new predicated multiset. |
||||
*/ |
||||
public MultiSet<E> createPredicatedMultiSet() { |
||||
return createPredicatedMultiSet(new HashMultiSet<E>()); |
||||
} |
||||
|
||||
/** |
||||
* Decorates the given multiset with validating behavior using the predicate. All accepted elements |
||||
* are appended to the multiset. If the multiset already contains elements, they are validated. |
||||
* <p> |
||||
* The builder is not modified by this method, so it is possible to create more collections |
||||
* or add more elements afterwards. Further changes will not propagate to the returned multiset. |
||||
* |
||||
* @param multiset the multiset to decorate, must not be null |
||||
* @return the decorated multiset. |
||||
* @throws NullPointerException if multiset is null |
||||
* @throws IllegalArgumentException if multiset contains invalid elements |
||||
*/ |
||||
public MultiSet<E> createPredicatedMultiSet(final MultiSet<E> multiset) { |
||||
if (multiset == null) { |
||||
throw new NullPointerException("MultiSet must not be null."); |
||||
} |
||||
final PredicatedMultiSet<E> predicatedMultiSet = |
||||
PredicatedMultiSet.predicatedMultiSet(multiset, predicate); |
||||
predicatedMultiSet.addAll(accepted); |
||||
return predicatedMultiSet; |
||||
} |
||||
|
||||
/** |
||||
* Create a new predicated bag filled with the accepted elements. |
||||
* <p> |
||||
* The builder is not modified by this method, so it is possible to create more collections |
||||
* or add more elements afterwards. Further changes will not propagate to the returned bag. |
||||
* |
||||
* @return a new predicated bag. |
||||
*/ |
||||
public Bag<E> createPredicatedBag() { |
||||
return createPredicatedBag(new HashBag<E>()); |
||||
} |
||||
|
||||
/** |
||||
* Decorates the given bag with validating behavior using the predicate. All accepted elements |
||||
* are appended to the bag. If the bag already contains elements, they are validated. |
||||
* <p> |
||||
* The builder is not modified by this method, so it is possible to create more collections |
||||
* or add more elements afterwards. Further changes will not propagate to the returned bag. |
||||
* |
||||
* @param bag the bag to decorate, must not be null |
||||
* @return the decorated bag. |
||||
* @throws NullPointerException if bag is null |
||||
* @throws IllegalArgumentException if bag contains invalid elements |
||||
*/ |
||||
public Bag<E> createPredicatedBag(final Bag<E> bag) { |
||||
if (bag == null) { |
||||
throw new NullPointerException("Bag must not be null."); |
||||
} |
||||
final PredicatedBag<E> predicatedBag = PredicatedBag.predicatedBag(bag, predicate); |
||||
predicatedBag.addAll(accepted); |
||||
return predicatedBag; |
||||
} |
||||
|
||||
/** |
||||
* Create a new predicated queue filled with the accepted elements. |
||||
* <p> |
||||
* The builder is not modified by this method, so it is possible to create more collections |
||||
* or add more elements afterwards. Further changes will not propagate to the returned queue. |
||||
* |
||||
* @return a new predicated queue. |
||||
*/ |
||||
public Queue<E> createPredicatedQueue() { |
||||
return createPredicatedQueue(new LinkedList<E>()); |
||||
} |
||||
|
||||
/** |
||||
* Decorates the given queue with validating behavior using the predicate. All accepted elements |
||||
* are appended to the queue. If the queue already contains elements, they are validated. |
||||
* <p> |
||||
* The builder is not modified by this method, so it is possible to create more collections |
||||
* or add more elements afterwards. Further changes will not propagate to the returned queue. |
||||
* |
||||
* @param queue the queue to decorate, must not be null |
||||
* @return the decorated queue. |
||||
* @throws NullPointerException if queue is null |
||||
* @throws IllegalArgumentException if queue contains invalid elements |
||||
*/ |
||||
public Queue<E> createPredicatedQueue(final Queue<E> queue) { |
||||
if (queue == null) { |
||||
throw new NullPointerException("queue must not be null"); |
||||
} |
||||
final PredicatedQueue<E> predicatedQueue = PredicatedQueue.predicatedQueue(queue, predicate); |
||||
predicatedQueue.addAll(accepted); |
||||
return predicatedQueue; |
||||
} |
||||
|
||||
/** |
||||
* Returns an unmodifiable collection containing all rejected elements. |
||||
* |
||||
* @return an unmodifiable collection |
||||
*/ |
||||
public Collection<E> rejectedElements() { |
||||
return Collections.unmodifiableCollection(rejected); |
||||
} |
||||
|
||||
} |
||||
|
||||
} |
@ -0,0 +1,232 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package com.fr.third.org.apache.commons.collections4.collection; |
||||
|
||||
import java.io.Serializable; |
||||
import java.util.Collection; |
||||
import java.util.Iterator; |
||||
|
||||
/** |
||||
* Decorates another {@link Collection} to synchronize its behaviour |
||||
* for a multi-threaded environment. |
||||
* <p> |
||||
* Iterators must be manually synchronized: |
||||
* <pre> |
||||
* synchronized (coll) { |
||||
* Iterator it = coll.iterator(); |
||||
* // do stuff with iterator
|
||||
* } |
||||
* </pre> |
||||
* <p> |
||||
* This class is Serializable from Commons Collections 3.1. |
||||
* |
||||
* @param <E> the type of the elements in the collection |
||||
* @since 3.0 |
||||
* @version $Id: SynchronizedCollection.java 1686855 2015-06-22 13:00:27Z tn $ |
||||
*/ |
||||
public class SynchronizedCollection<E> implements Collection<E>, Serializable { |
||||
|
||||
/** Serialization version */ |
||||
private static final long serialVersionUID = 2412805092710877986L; |
||||
|
||||
/** The collection to decorate */ |
||||
private final Collection<E> collection; |
||||
/** The object to lock on, needed for List/SortedSet views */ |
||||
protected final Object lock; |
||||
|
||||
/** |
||||
* Factory method to create a synchronized collection. |
||||
* |
||||
* @param <T> the type of the elements in the collection |
||||
* @param coll the collection to decorate, must not be null |
||||
* @return a new synchronized collection |
||||
* @throws NullPointerException if collection is null |
||||
* @since 4.0 |
||||
*/ |
||||
public static <T> SynchronizedCollection<T> synchronizedCollection(final Collection<T> coll) { |
||||
return new SynchronizedCollection<T>(coll); |
||||
} |
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/** |
||||
* Constructor that wraps (not copies). |
||||
* |
||||
* @param collection the collection to decorate, must not be null |
||||
* @throws NullPointerException if the collection is null |
||||
*/ |
||||
protected SynchronizedCollection(final Collection<E> collection) { |
||||
if (collection == null) { |
||||
throw new NullPointerException("Collection must not be null."); |
||||
} |
||||
this.collection = collection; |
||||
this.lock = this; |
||||
} |
||||
|
||||
/** |
||||
* Constructor that wraps (not copies). |
||||
* |
||||
* @param collection the collection to decorate, must not be null |
||||
* @param lock the lock object to use, must not be null |
||||
* @throws NullPointerException if the collection or lock is null |
||||
*/ |
||||
protected SynchronizedCollection(final Collection<E> collection, final Object lock) { |
||||
if (collection == null) { |
||||
throw new NullPointerException("Collection must not be null."); |
||||
} |
||||
if (lock == null) { |
||||
throw new NullPointerException("Lock must not be null."); |
||||
} |
||||
this.collection = collection; |
||||
this.lock = lock; |
||||
} |
||||
|
||||
/** |
||||
* Gets the collection being decorated. |
||||
* |
||||
* @return the decorated collection |
||||
*/ |
||||
protected Collection<E> decorated() { |
||||
return collection; |
||||
} |
||||
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
@Override |
||||
public boolean add(final E object) { |
||||
synchronized (lock) { |
||||
return decorated().add(object); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public boolean addAll(final Collection<? extends E> coll) { |
||||
synchronized (lock) { |
||||
return decorated().addAll(coll); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public void clear() { |
||||
synchronized (lock) { |
||||
decorated().clear(); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public boolean contains(final Object object) { |
||||
synchronized (lock) { |
||||
return decorated().contains(object); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public boolean containsAll(final Collection<?> coll) { |
||||
synchronized (lock) { |
||||
return decorated().containsAll(coll); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public boolean isEmpty() { |
||||
synchronized (lock) { |
||||
return decorated().isEmpty(); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Iterators must be manually synchronized. |
||||
* <pre> |
||||
* synchronized (coll) { |
||||
* Iterator it = coll.iterator(); |
||||
* // do stuff with iterator
|
||||
* } |
||||
* </pre> |
||||
* |
||||
* @return an iterator that must be manually synchronized on the collection |
||||
*/ |
||||
@Override |
||||
public Iterator<E> iterator() { |
||||
return decorated().iterator(); |
||||
} |
||||
|
||||
@Override |
||||
public Object[] toArray() { |
||||
synchronized (lock) { |
||||
return decorated().toArray(); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public <T> T[] toArray(final T[] object) { |
||||
synchronized (lock) { |
||||
return decorated().toArray(object); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public boolean remove(final Object object) { |
||||
synchronized (lock) { |
||||
return decorated().remove(object); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public boolean removeAll(final Collection<?> coll) { |
||||
synchronized (lock) { |
||||
return decorated().removeAll(coll); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public boolean retainAll(final Collection<?> coll) { |
||||
synchronized (lock) { |
||||
return decorated().retainAll(coll); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public int size() { |
||||
synchronized (lock) { |
||||
return decorated().size(); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public boolean equals(final Object object) { |
||||
synchronized (lock) { |
||||
if (object == this) { |
||||
return true; |
||||
} |
||||
return object == this || decorated().equals(object); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public int hashCode() { |
||||
synchronized (lock) { |
||||
return decorated().hashCode(); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public String toString() { |
||||
synchronized (lock) { |
||||
return decorated().toString(); |
||||
} |
||||
} |
||||
|
||||
} |
@ -0,0 +1,156 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package com.fr.third.org.apache.commons.collections4.collection; |
||||
|
||||
import java.util.ArrayList; |
||||
import java.util.Collection; |
||||
import java.util.List; |
||||
|
||||
import com.fr.third.org.apache.commons.collections4.Transformer; |
||||
import com.fr.third.org.apache.commons.collections4.Transformer; |
||||
|
||||
/** |
||||
* Decorates another {@link Collection} to transform objects that are added. |
||||
* <p> |
||||
* The add methods are affected by this class. |
||||
* Thus objects must be removed or searched for using their transformed form. |
||||
* For example, if the transformation converts Strings to Integers, you must |
||||
* use the Integer form to remove objects. |
||||
* <p> |
||||
* This class is Serializable from Commons Collections 3.1. |
||||
* |
||||
* @param <E> the type of the elements in the collection |
||||
* @since 3.0 |
||||
* @version $Id: TransformedCollection.java 1686855 2015-06-22 13:00:27Z tn $ |
||||
*/ |
||||
public class TransformedCollection<E> extends AbstractCollectionDecorator<E> { |
||||
|
||||
/** Serialization version */ |
||||
private static final long serialVersionUID = 8692300188161871514L; |
||||
|
||||
/** The transformer to use */ |
||||
protected final Transformer<? super E, ? extends E> transformer; |
||||
|
||||
/** |
||||
* Factory method to create a transforming collection. |
||||
* <p> |
||||
* If there are any elements already in the collection being decorated, they |
||||
* are NOT transformed. |
||||
* Contrast this with {@link #transformedCollection(Collection, Transformer)}. |
||||
* |
||||
* @param <E> the type of the elements in the collection |
||||
* @param coll the collection to decorate, must not be null |
||||
* @param transformer the transformer to use for conversion, must not be null |
||||
* @return a new transformed collection |
||||
* @throws NullPointerException if collection or transformer is null |
||||
* @since 4.0 |
||||
*/ |
||||
public static <E> TransformedCollection<E> transformingCollection(final Collection<E> coll, |
||||
final Transformer<? super E, ? extends E> transformer) { |
||||
return new TransformedCollection<E>(coll, transformer); |
||||
} |
||||
|
||||
/** |
||||
* Factory method to create a transforming collection that will transform |
||||
* existing contents of the specified collection. |
||||
* <p> |
||||
* If there are any elements already in the collection being decorated, they |
||||
* will be transformed by this method. |
||||
* Contrast this with {@link #transformingCollection(Collection, Transformer)}. |
||||
* |
||||
* @param <E> the type of the elements in the collection |
||||
* @param collection the collection to decorate, must not be null |
||||
* @param transformer the transformer to use for conversion, must not be null |
||||
* @return a new transformed Collection |
||||
* @throws NullPointerException if collection or transformer is null |
||||
* @since 4.0 |
||||
*/ |
||||
public static <E> TransformedCollection<E> transformedCollection(final Collection<E> collection, |
||||
final Transformer<? super E, ? extends E> transformer) { |
||||
|
||||
final TransformedCollection<E> decorated = new TransformedCollection<E>(collection, transformer); |
||||
// null collection & transformer are disallowed by the constructor call above
|
||||
if (collection.size() > 0) { |
||||
@SuppressWarnings("unchecked") // collection is of type E
|
||||
final E[] values = (E[]) collection.toArray(); // NOPMD - false positive for generics
|
||||
collection.clear(); |
||||
for (final E value : values) { |
||||
decorated.decorated().add(transformer.transform(value)); |
||||
} |
||||
} |
||||
return decorated; |
||||
} |
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/** |
||||
* Constructor that wraps (not copies). |
||||
* <p> |
||||
* If there are any elements already in the collection being decorated, they |
||||
* are NOT transformed. |
||||
* |
||||
* @param coll the collection to decorate, must not be null |
||||
* @param transformer the transformer to use for conversion, must not be null |
||||
* @throws NullPointerException if collection or transformer is null |
||||
*/ |
||||
protected TransformedCollection(final Collection<E> coll, final Transformer<? super E, ? extends E> transformer) { |
||||
super(coll); |
||||
if (transformer == null) { |
||||
throw new NullPointerException("Transformer must not be null"); |
||||
} |
||||
this.transformer = transformer; |
||||
} |
||||
|
||||
/** |
||||
* Transforms an object. |
||||
* <p> |
||||
* The transformer itself may throw an exception if necessary. |
||||
* |
||||
* @param object the object to transform |
||||
* @return a transformed object |
||||
*/ |
||||
protected E transform(final E object) { |
||||
return transformer.transform(object); |
||||
} |
||||
|
||||
/** |
||||
* Transforms a collection. |
||||
* <p> |
||||
* The transformer itself may throw an exception if necessary. |
||||
* |
||||
* @param coll the collection to transform |
||||
* @return a transformed object |
||||
*/ |
||||
protected Collection<E> transform(final Collection<? extends E> coll) { |
||||
final List<E> list = new ArrayList<E>(coll.size()); |
||||
for (final E item : coll) { |
||||
list.add(transform(item)); |
||||
} |
||||
return list; |
||||
} |
||||
|
||||
//-----------------------------------------------------------------------
|
||||
@Override |
||||
public boolean add(final E object) { |
||||
return decorated().add(transform(object)); |
||||
} |
||||
|
||||
@Override |
||||
public boolean addAll(final Collection<? extends E> coll) { |
||||
return decorated().addAll(transform(coll)); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,168 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package com.fr.third.org.apache.commons.collections4.collection; |
||||
|
||||
import java.util.Collection; |
||||
import java.util.Iterator; |
||||
|
||||
import com.fr.third.org.apache.commons.collections4.BoundedCollection; |
||||
import com.fr.third.org.apache.commons.collections4.Unmodifiable; |
||||
import com.fr.third.org.apache.commons.collections4.BoundedCollection; |
||||
import com.fr.third.org.apache.commons.collections4.Unmodifiable; |
||||
import com.fr.third.org.apache.commons.collections4.iterators.UnmodifiableIterator; |
||||
|
||||
/** |
||||
* {@link UnmodifiableBoundedCollection} decorates another |
||||
* {@link BoundedCollection} to ensure it can't be altered. |
||||
* <p> |
||||
* If a BoundedCollection is first wrapped in some other collection decorator, |
||||
* such as synchronized or predicated, the BoundedCollection methods are no |
||||
* longer accessible. |
||||
* The factory on this class will attempt to retrieve the bounded nature by |
||||
* examining the package scope variables. |
||||
* <p> |
||||
* This class is Serializable from Commons Collections 3.1. |
||||
* <p> |
||||
* Attempts to modify it will result in an UnsupportedOperationException. |
||||
* |
||||
* @since 3.0 |
||||
* @version $Id: UnmodifiableBoundedCollection.java 1686855 2015-06-22 13:00:27Z tn $ |
||||
*/ |
||||
public final class UnmodifiableBoundedCollection<E> extends AbstractCollectionDecorator<E> |
||||
implements BoundedCollection<E>, Unmodifiable { |
||||
|
||||
/** Serialization version */ |
||||
private static final long serialVersionUID = -7112672385450340330L; |
||||
|
||||
/** |
||||
* Factory method to create an unmodifiable bounded collection. |
||||
* |
||||
* @param <E> the type of the elements in the collection |
||||
* @param coll the <code>BoundedCollection</code> to decorate, must not be null |
||||
* @return a new unmodifiable bounded collection |
||||
* @throws NullPointerException if {@code coll} is {@code null} |
||||
* @since 4.0 |
||||
*/ |
||||
public static <E> BoundedCollection<E> unmodifiableBoundedCollection(final BoundedCollection<? extends E> coll) { |
||||
if (coll instanceof Unmodifiable) { |
||||
@SuppressWarnings("unchecked") // safe to upcast
|
||||
final BoundedCollection<E> tmpColl = (BoundedCollection<E>) coll; |
||||
return tmpColl; |
||||
} |
||||
return new UnmodifiableBoundedCollection<E>(coll); |
||||
} |
||||
|
||||
/** |
||||
* Factory method to create an unmodifiable bounded collection. |
||||
* <p> |
||||
* This method is capable of drilling down through up to 1000 other decorators |
||||
* to find a suitable BoundedCollection. |
||||
* |
||||
* @param <E> the type of the elements in the collection |
||||
* @param coll the <code>BoundedCollection</code> to decorate, must not be null |
||||
* @return a new unmodifiable bounded collection |
||||
* @throws NullPointerException if coll is null |
||||
* @throws IllegalArgumentException if coll is not a {@code BoundedCollection} |
||||
* @since 4.0 |
||||
*/ |
||||
@SuppressWarnings("unchecked") |
||||
public static <E> BoundedCollection<E> unmodifiableBoundedCollection(Collection<? extends E> coll) { |
||||
if (coll == null) { |
||||
throw new NullPointerException("Collection must not be null."); |
||||
} |
||||
|
||||
// handle decorators
|
||||
for (int i = 0; i < 1000; i++) { // counter to prevent infinite looping
|
||||
if (coll instanceof BoundedCollection) { |
||||
break; // normal loop exit
|
||||
} |
||||
if (coll instanceof AbstractCollectionDecorator) { |
||||
coll = ((AbstractCollectionDecorator<E>) coll).decorated(); |
||||
} else if (coll instanceof SynchronizedCollection) { |
||||
coll = ((SynchronizedCollection<E>) coll).decorated(); |
||||
} |
||||
} |
||||
|
||||
if (coll instanceof BoundedCollection == false) { |
||||
throw new IllegalArgumentException("Collection is not a bounded collection."); |
||||
} |
||||
return new UnmodifiableBoundedCollection<E>((BoundedCollection<E>) coll); |
||||
} |
||||
|
||||
/** |
||||
* Constructor that wraps (not copies). |
||||
* |
||||
* @param coll the collection to decorate, must not be null |
||||
* @throws NullPointerException if coll is null |
||||
*/ |
||||
@SuppressWarnings("unchecked") // safe to upcast
|
||||
private UnmodifiableBoundedCollection(final BoundedCollection<? extends E> coll) { |
||||
super((BoundedCollection<E>) coll); |
||||
} |
||||
|
||||
//-----------------------------------------------------------------------
|
||||
@Override |
||||
public Iterator<E> iterator() { |
||||
return UnmodifiableIterator.unmodifiableIterator(decorated().iterator()); |
||||
} |
||||
|
||||
@Override |
||||
public boolean add(final E object) { |
||||
throw new UnsupportedOperationException(); |
||||
} |
||||
|
||||
@Override |
||||
public boolean addAll(final Collection<? extends E> coll) { |
||||
throw new UnsupportedOperationException(); |
||||
} |
||||
|
||||
@Override |
||||
public void clear() { |
||||
throw new UnsupportedOperationException(); |
||||
} |
||||
|
||||
@Override |
||||
public boolean remove(final Object object) { |
||||
throw new UnsupportedOperationException(); |
||||
} |
||||
|
||||
@Override |
||||
public boolean removeAll(final Collection<?> coll) { |
||||
throw new UnsupportedOperationException(); |
||||
} |
||||
|
||||
@Override |
||||
public boolean retainAll(final Collection<?> coll) { |
||||
throw new UnsupportedOperationException(); |
||||
} |
||||
|
||||
//-----------------------------------------------------------------------
|
||||
@Override |
||||
public boolean isFull() { |
||||
return decorated().isFull(); |
||||
} |
||||
|
||||
@Override |
||||
public int maxSize() { |
||||
return decorated().maxSize(); |
||||
} |
||||
|
||||
@Override |
||||
protected BoundedCollection<E> decorated() { |
||||
return (BoundedCollection<E>) super.decorated(); |
||||
} |
||||
} |
@ -0,0 +1,112 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package com.fr.third.org.apache.commons.collections4.collection; |
||||
|
||||
import java.util.Collection; |
||||
import java.util.Iterator; |
||||
|
||||
import com.fr.third.org.apache.commons.collections4.Unmodifiable; |
||||
import com.fr.third.org.apache.commons.collections4.Unmodifiable; |
||||
import com.fr.third.org.apache.commons.collections4.iterators.UnmodifiableIterator; |
||||
|
||||
/** |
||||
* Decorates another {@link Collection} to ensure it can't be altered. |
||||
* <p> |
||||
* This class is Serializable from Commons Collections 3.1. |
||||
* <p> |
||||
* Attempts to modify it will result in an UnsupportedOperationException. |
||||
* |
||||
* @param <E> the type of the elements in the collection |
||||
* @since 3.0 |
||||
* @version $Id: UnmodifiableCollection.java 1686855 2015-06-22 13:00:27Z tn $ |
||||
*/ |
||||
public final class UnmodifiableCollection<E> |
||||
extends AbstractCollectionDecorator<E> |
||||
implements Unmodifiable { |
||||
|
||||
/** Serialization version */ |
||||
private static final long serialVersionUID = -239892006883819945L; |
||||
|
||||
/** |
||||
* Factory method to create an unmodifiable collection. |
||||
* <p> |
||||
* If the collection passed in is already unmodifiable, it is returned. |
||||
* |
||||
* @param <T> the type of the elements in the collection |
||||
* @param coll the collection to decorate, must not be null |
||||
* @return an unmodifiable collection |
||||
* @throws NullPointerException if collection is null |
||||
* @since 4.0 |
||||
*/ |
||||
public static <T> Collection<T> unmodifiableCollection(final Collection<? extends T> coll) { |
||||
if (coll instanceof Unmodifiable) { |
||||
@SuppressWarnings("unchecked") // safe to upcast
|
||||
final Collection<T> tmpColl = (Collection<T>) coll; |
||||
return tmpColl; |
||||
} |
||||
return new UnmodifiableCollection<T>(coll); |
||||
} |
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/** |
||||
* Constructor that wraps (not copies). |
||||
* |
||||
* @param coll the collection to decorate, must not be null |
||||
* @throws NullPointerException if collection is null |
||||
*/ |
||||
@SuppressWarnings("unchecked") // safe to upcast
|
||||
private UnmodifiableCollection(final Collection<? extends E> coll) { |
||||
super((Collection<E>) coll); |
||||
} |
||||
|
||||
//-----------------------------------------------------------------------
|
||||
@Override |
||||
public Iterator<E> iterator() { |
||||
return UnmodifiableIterator.unmodifiableIterator(decorated().iterator()); |
||||
} |
||||
|
||||
@Override |
||||
public boolean add(final E object) { |
||||
throw new UnsupportedOperationException(); |
||||
} |
||||
|
||||
@Override |
||||
public boolean addAll(final Collection<? extends E> coll) { |
||||
throw new UnsupportedOperationException(); |
||||
} |
||||
|
||||
@Override |
||||
public void clear() { |
||||
throw new UnsupportedOperationException(); |
||||
} |
||||
|
||||
@Override |
||||
public boolean remove(final Object object) { |
||||
throw new UnsupportedOperationException(); |
||||
} |
||||
|
||||
@Override |
||||
public boolean removeAll(final Collection<?> coll) { |
||||
throw new UnsupportedOperationException(); |
||||
} |
||||
|
||||
@Override |
||||
public boolean retainAll(final Collection<?> coll) { |
||||
throw new UnsupportedOperationException(); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,36 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
/** |
||||
* This package contains implementations of the |
||||
* {@link java.util.Collection Collection} interface. |
||||
* <p> |
||||
* The following implementations are provided in the package: |
||||
* <ul> |
||||
* <li>CompositeCollection - a collection that combines multiple collections into one |
||||
* </ul> |
||||
* The following decorators are provided in the package: |
||||
* <ul> |
||||
* <li>Synchronized - synchronizes method access for multi-threaded environments |
||||
* <li>Unmodifiable - ensures the collection cannot be altered |
||||
* <li>Predicated - ensures that only elements that are valid according to a predicate can be added |
||||
* <li>Transformed - transforms elements as they are added |
||||
* <li>Indexed - provides a map-like view onto another collection |
||||
* </ul> |
||||
* |
||||
* @version $Id: package-info.java 1477746 2013-04-30 18:11:20Z tn $ |
||||
*/ |
||||
package com.fr.third.org.apache.commons.collections4.collection; |
@ -0,0 +1,192 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package com.fr.third.org.apache.commons.collections4.comparators; |
||||
|
||||
import java.io.Serializable; |
||||
import java.util.Comparator; |
||||
|
||||
/** |
||||
* A {@link Comparator} for {@link Boolean} objects that can sort either |
||||
* true or false first. |
||||
* <p> |
||||
* @see #getTrueFirstComparator() |
||||
* @see #getFalseFirstComparator() |
||||
* @see #booleanComparator(boolean) |
||||
* |
||||
* @since 3.0 |
||||
* @version $Id: BooleanComparator.java 1683951 2015-06-06 20:19:03Z tn $ |
||||
*/ |
||||
public final class BooleanComparator implements Comparator<Boolean>, Serializable { |
||||
|
||||
/** Serialization version. */ |
||||
private static final long serialVersionUID = 1830042991606340609L; |
||||
|
||||
/** Constant "true first" reference. */ |
||||
private static final BooleanComparator TRUE_FIRST = new BooleanComparator(true); |
||||
|
||||
/** Constant "false first" reference. */ |
||||
private static final BooleanComparator FALSE_FIRST = new BooleanComparator(false); |
||||
|
||||
/** <code>true</code> iff <code>true</code> values sort before <code>false</code> values. */ |
||||
private boolean trueFirst = false; |
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/** |
||||
* Returns a BooleanComparator instance that sorts |
||||
* <code>true</code> values before <code>false</code> values. |
||||
* <p /> |
||||
* Clients are encouraged to use the value returned from |
||||
* this method instead of constructing a new instance |
||||
* to reduce allocation and garbage collection overhead when |
||||
* multiple BooleanComparators may be used in the same |
||||
* virtual machine. |
||||
* |
||||
* @return the true first singleton BooleanComparator |
||||
*/ |
||||
public static BooleanComparator getTrueFirstComparator() { |
||||
return TRUE_FIRST; |
||||
} |
||||
|
||||
/** |
||||
* Returns a BooleanComparator instance that sorts |
||||
* <code>false</code> values before <code>true</code> values. |
||||
* <p /> |
||||
* Clients are encouraged to use the value returned from |
||||
* this method instead of constructing a new instance |
||||
* to reduce allocation and garbage collection overhead when |
||||
* multiple BooleanComparators may be used in the same |
||||
* virtual machine. |
||||
* |
||||
* @return the false first singleton BooleanComparator |
||||
*/ |
||||
public static BooleanComparator getFalseFirstComparator() { |
||||
return FALSE_FIRST; |
||||
} |
||||
|
||||
/** |
||||
* Returns a BooleanComparator instance that sorts |
||||
* <code><i>trueFirst</i></code> values before |
||||
* <code>!<i>trueFirst</i></code> values. |
||||
* <p /> |
||||
* Clients are encouraged to use the value returned from |
||||
* this method instead of constructing a new instance |
||||
* to reduce allocation and garbage collection overhead when |
||||
* multiple BooleanComparators may be used in the same |
||||
* virtual machine. |
||||
* |
||||
* @param trueFirst when <code>true</code>, sort |
||||
* <code>true</code> <code>Boolean</code>s before <code>false</code> |
||||
* @return a singleton BooleanComparator instance |
||||
* @since 4.0 |
||||
*/ |
||||
public static BooleanComparator booleanComparator(final boolean trueFirst) { |
||||
return trueFirst ? TRUE_FIRST : FALSE_FIRST; |
||||
} |
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/** |
||||
* Creates a <code>BooleanComparator</code> that sorts |
||||
* <code>false</code> values before <code>true</code> values. |
||||
* <p> |
||||
* Equivalent to {@link #BooleanComparator(boolean) BooleanComparator(false)}. |
||||
* <p> |
||||
* Please use the static factory instead whenever possible. |
||||
*/ |
||||
public BooleanComparator() { |
||||
this(false); |
||||
} |
||||
|
||||
/** |
||||
* Creates a <code>BooleanComparator</code> that sorts |
||||
* <code><i>trueFirst</i></code> values before |
||||
* <code>!<i>trueFirst</i></code> values. |
||||
* <p> |
||||
* Please use the static factories instead whenever possible. |
||||
* |
||||
* @param trueFirst when <code>true</code>, sort |
||||
* <code>true</code> boolean values before <code>false</code> |
||||
*/ |
||||
public BooleanComparator(final boolean trueFirst) { |
||||
this.trueFirst = trueFirst; |
||||
} |
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/** |
||||
* Compares two non-<code>null</code> <code>Boolean</code> objects |
||||
* according to the value of {@link #sortsTrueFirst()}. |
||||
* |
||||
* @param b1 the first boolean to compare |
||||
* @param b2 the second boolean to compare |
||||
* @return negative if obj1 is less, positive if greater, zero if equal |
||||
* @throws NullPointerException when either argument <code>null</code> |
||||
*/ |
||||
@Override |
||||
public int compare(final Boolean b1, final Boolean b2) { |
||||
final boolean v1 = b1.booleanValue(); |
||||
final boolean v2 = b2.booleanValue(); |
||||
|
||||
return (v1 ^ v2) ? ( (v1 ^ trueFirst) ? 1 : -1 ) : 0; |
||||
} |
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/** |
||||
* Implement a hash code for this comparator that is consistent with |
||||
* {@link #equals(Object) equals}. |
||||
* |
||||
* @return a hash code for this comparator. |
||||
*/ |
||||
@Override |
||||
public int hashCode() { |
||||
final int hash = "BooleanComparator".hashCode(); |
||||
return trueFirst ? -1 * hash : hash; |
||||
} |
||||
|
||||
/** |
||||
* Returns <code>true</code> iff <i>that</i> Object is |
||||
* is a {@link Comparator} whose ordering is known to be |
||||
* equivalent to mine. |
||||
* <p> |
||||
* This implementation returns <code>true</code> |
||||
* iff <code><i>that</i></code> is a {@link BooleanComparator} |
||||
* whose value of {@link #sortsTrueFirst()} is equal to mine. |
||||
* |
||||
* @param object the object to compare to |
||||
* @return true if equal |
||||
*/ |
||||
@Override |
||||
public boolean equals(final Object object) { |
||||
return (this == object) || |
||||
((object instanceof BooleanComparator) && |
||||
(this.trueFirst == ((BooleanComparator)object).trueFirst)); |
||||
} |
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/** |
||||
* Returns <code>true</code> iff |
||||
* I sort <code>true</code> values before |
||||
* <code>false</code> values. In other words, |
||||
* returns <code>true</code> iff |
||||
* {@link #compare(Boolean,Boolean) compare(Boolean.FALSE,Boolean.TRUE)} |
||||
* returns a positive value. |
||||
* |
||||
* @return the trueFirst flag |
||||
*/ |
||||
public boolean sortsTrueFirst() { |
||||
return trueFirst; |
||||
} |
||||
|
||||
} |
@ -0,0 +1,130 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package com.fr.third.org.apache.commons.collections4.comparators; |
||||
|
||||
import java.io.Serializable; |
||||
import java.util.Comparator; |
||||
|
||||
/** |
||||
* A {@link Comparator Comparator} that compares {@link Comparable Comparable} |
||||
* objects. |
||||
* <p> |
||||
* This Comparator is useful, for example, for enforcing the natural order in |
||||
* custom implementations of {@link java.util.SortedSet SortedSet} and |
||||
* {@link java.util.SortedMap SortedMap}. |
||||
* <p> |
||||
* Note: In the 2.0 and 2.1 releases of Commons Collections, this class would |
||||
* throw a {@link ClassCastException} if either of the arguments to |
||||
* {@link #compare(Object, Object) compare} were <code>null</code>, not |
||||
* {@link Comparable Comparable}, or for which |
||||
* {@link Comparable#compareTo(Object) compareTo} gave inconsistent results. |
||||
* This is no longer the case. See {@link #compare(Object, Object) compare} for |
||||
* details. |
||||
* |
||||
* @since 2.0 |
||||
* @version $Id: ComparableComparator.java 1683951 2015-06-06 20:19:03Z tn $ |
||||
* |
||||
* @see java.util.Collections#reverseOrder() |
||||
*/ |
||||
public class ComparableComparator<E extends Comparable<? super E>> implements Comparator<E>, Serializable { |
||||
|
||||
/** Serialization version. */ |
||||
private static final long serialVersionUID=-291439688585137865L; |
||||
|
||||
/** The singleton instance. */ |
||||
@SuppressWarnings("rawtypes") |
||||
public static final ComparableComparator INSTANCE = new ComparableComparator(); |
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/** |
||||
* Gets the singleton instance of a ComparableComparator. |
||||
* <p> |
||||
* Developers are encouraged to use the comparator returned from this method |
||||
* instead of constructing a new instance to reduce allocation and GC overhead |
||||
* when multiple comparable comparators may be used in the same VM. |
||||
* |
||||
* @param <E> the element type |
||||
* @return the singleton ComparableComparator |
||||
* @since 4.0 |
||||
*/ |
||||
@SuppressWarnings("unchecked") |
||||
public static <E extends Comparable<? super E>> ComparableComparator<E> comparableComparator() { |
||||
return INSTANCE; |
||||
} |
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/** |
||||
* Constructor whose use should be avoided. |
||||
* <p> |
||||
* Please use the {@link #comparableComparator()} method whenever possible. |
||||
*/ |
||||
public ComparableComparator() { |
||||
super(); |
||||
} |
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/** |
||||
* Compare the two {@link Comparable Comparable} arguments. |
||||
* This method is equivalent to: |
||||
* <pre>((Comparable)obj1).compareTo(obj2)</pre> |
||||
* |
||||
* @param obj1 the first object to compare |
||||
* @param obj2 the second object to compare |
||||
* @return negative if obj1 is less, positive if greater, zero if equal |
||||
* @throws NullPointerException if <i>obj1</i> is <code>null</code>, |
||||
* or when <code>((Comparable)obj1).compareTo(obj2)</code> does |
||||
* @throws ClassCastException if <i>obj1</i> is not a <code>Comparable</code>, |
||||
* or when <code>((Comparable)obj1).compareTo(obj2)</code> does |
||||
*/ |
||||
@Override |
||||
public int compare(final E obj1, final E obj2) { |
||||
return obj1.compareTo(obj2); |
||||
} |
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/** |
||||
* Implement a hash code for this comparator that is consistent with |
||||
* {@link #equals(Object) equals}. |
||||
* |
||||
* @return a hash code for this comparator. |
||||
* @since 3.0 |
||||
*/ |
||||
@Override |
||||
public int hashCode() { |
||||
return "ComparableComparator".hashCode(); |
||||
} |
||||
|
||||
/** |
||||
* Returns {@code true} iff <i>that</i> Object is is a {@link Comparator Comparator} |
||||
* whose ordering is known to be equivalent to mine. |
||||
* <p> |
||||
* This implementation returns {@code true} iff |
||||
* <code><i>object</i>.{@link Object#getClass() getClass()}</code> equals |
||||
* <code>this.getClass()</code>. Subclasses may want to override this behavior to remain |
||||
* consistent with the {@link Comparator#equals(Object)} contract. |
||||
* |
||||
* @param object the object to compare with |
||||
* @return {@code true} if equal |
||||
* @since 3.0 |
||||
*/ |
||||
@Override |
||||
public boolean equals(final Object object) { |
||||
return this == object || |
||||
null != object && object.getClass().equals(this.getClass()); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,349 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package com.fr.third.org.apache.commons.collections4.comparators; |
||||
|
||||
import java.io.Serializable; |
||||
import java.util.ArrayList; |
||||
import java.util.BitSet; |
||||
import java.util.Comparator; |
||||
import java.util.Iterator; |
||||
import java.util.List; |
||||
|
||||
/** |
||||
* A ComparatorChain is a Comparator that wraps one or more Comparators in |
||||
* sequence. The ComparatorChain calls each Comparator in sequence until either |
||||
* 1) any single Comparator returns a non-zero result (and that result is then |
||||
* returned), or 2) the ComparatorChain is exhausted (and zero is returned). |
||||
* This type of sorting is very similar to multi-column sorting in SQL, and this |
||||
* class allows Java classes to emulate that kind of behaviour when sorting a |
||||
* List. |
||||
* <p> |
||||
* To further facilitate SQL-like sorting, the order of any single Comparator in |
||||
* the list can be reversed. |
||||
* <p> |
||||
* Calling a method that adds new Comparators or changes the ascend/descend sort |
||||
* <i>after compare(Object, Object) has been called</i> will result in an |
||||
* UnsupportedOperationException. However, <i>take care</i> to not alter the |
||||
* underlying List of Comparators or the BitSet that defines the sort order. |
||||
* <p> |
||||
* Instances of ComparatorChain are not synchronized. The class is not |
||||
* thread-safe at construction time, but it <i>is</i> thread-safe to perform |
||||
* multiple comparisons after all the setup operations are complete. |
||||
* |
||||
* @since 2.0 |
||||
* @version $Id: ComparatorChain.java 1683951 2015-06-06 20:19:03Z tn $ |
||||
*/ |
||||
public class ComparatorChain<E> implements Comparator<E>, Serializable { |
||||
|
||||
/** Serialization version from Collections 2.0. */ |
||||
private static final long serialVersionUID = -721644942746081630L; |
||||
|
||||
/** The list of comparators in the chain. */ |
||||
private final List<Comparator<E>> comparatorChain; |
||||
/** Order - false (clear) = ascend; true (set) = descend. */ |
||||
private BitSet orderingBits = null; |
||||
/** Whether the chain has been "locked". */ |
||||
private boolean isLocked = false; |
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/** |
||||
* Construct a ComparatorChain with no Comparators. |
||||
* You must add at least one Comparator before calling |
||||
* the compare(Object,Object) method, or an |
||||
* UnsupportedOperationException is thrown |
||||
*/ |
||||
public ComparatorChain() { |
||||
this(new ArrayList<Comparator<E>>(), new BitSet()); |
||||
} |
||||
|
||||
/** |
||||
* Construct a ComparatorChain with a single Comparator, |
||||
* sorting in the forward order |
||||
* |
||||
* @param comparator First comparator in the Comparator chain |
||||
*/ |
||||
public ComparatorChain(final Comparator<E> comparator) { |
||||
this(comparator, false); |
||||
} |
||||
|
||||
/** |
||||
* Construct a Comparator chain with a single Comparator, |
||||
* sorting in the given order |
||||
* |
||||
* @param comparator First Comparator in the ComparatorChain |
||||
* @param reverse false = forward sort; true = reverse sort |
||||
*/ |
||||
public ComparatorChain(final Comparator<E> comparator, final boolean reverse) { |
||||
comparatorChain = new ArrayList<Comparator<E>>(1); |
||||
comparatorChain.add(comparator); |
||||
orderingBits = new BitSet(1); |
||||
if (reverse == true) { |
||||
orderingBits.set(0); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Construct a ComparatorChain from the Comparators in the |
||||
* List. All Comparators will default to the forward |
||||
* sort order. |
||||
* |
||||
* @param list List of Comparators |
||||
* @see #ComparatorChain(List,BitSet) |
||||
*/ |
||||
public ComparatorChain(final List<Comparator<E>> list) { |
||||
this(list, new BitSet(list.size())); |
||||
} |
||||
|
||||
/** |
||||
* Construct a ComparatorChain from the Comparators in the |
||||
* given List. The sort order of each column will be |
||||
* drawn from the given BitSet. When determining the sort |
||||
* order for Comparator at index <i>i</i> in the List, |
||||
* the ComparatorChain will call BitSet.get(<i>i</i>). |
||||
* If that method returns <i>false</i>, the forward |
||||
* sort order is used; a return value of <i>true</i> |
||||
* indicates reverse sort order. |
||||
* |
||||
* @param list List of Comparators. NOTE: This constructor does not perform a |
||||
* defensive copy of the list |
||||
* @param bits Sort order for each Comparator. Extra bits are ignored, |
||||
* unless extra Comparators are added by another method. |
||||
*/ |
||||
public ComparatorChain(final List<Comparator<E>> list, final BitSet bits) { |
||||
comparatorChain = list; |
||||
orderingBits = bits; |
||||
} |
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/** |
||||
* Add a Comparator to the end of the chain using the |
||||
* forward sort order |
||||
* |
||||
* @param comparator Comparator with the forward sort order |
||||
*/ |
||||
public void addComparator(final Comparator<E> comparator) { |
||||
addComparator(comparator, false); |
||||
} |
||||
|
||||
/** |
||||
* Add a Comparator to the end of the chain using the |
||||
* given sort order |
||||
* |
||||
* @param comparator Comparator to add to the end of the chain |
||||
* @param reverse false = forward sort order; true = reverse sort order |
||||
*/ |
||||
public void addComparator(final Comparator<E> comparator, final boolean reverse) { |
||||
checkLocked(); |
||||
|
||||
comparatorChain.add(comparator); |
||||
if (reverse == true) { |
||||
orderingBits.set(comparatorChain.size() - 1); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Replace the Comparator at the given index, maintaining |
||||
* the existing sort order. |
||||
* |
||||
* @param index index of the Comparator to replace |
||||
* @param comparator Comparator to place at the given index |
||||
* @exception IndexOutOfBoundsException |
||||
* if index < 0 or index >= size() |
||||
*/ |
||||
public void setComparator(final int index, final Comparator<E> comparator) throws IndexOutOfBoundsException { |
||||
setComparator(index, comparator, false); |
||||
} |
||||
|
||||
/** |
||||
* Replace the Comparator at the given index in the |
||||
* ComparatorChain, using the given sort order |
||||
* |
||||
* @param index index of the Comparator to replace |
||||
* @param comparator Comparator to set |
||||
* @param reverse false = forward sort order; true = reverse sort order |
||||
*/ |
||||
public void setComparator(final int index, final Comparator<E> comparator, final boolean reverse) { |
||||
checkLocked(); |
||||
|
||||
comparatorChain.set(index,comparator); |
||||
if (reverse == true) { |
||||
orderingBits.set(index); |
||||
} else { |
||||
orderingBits.clear(index); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Change the sort order at the given index in the |
||||
* ComparatorChain to a forward sort. |
||||
* |
||||
* @param index Index of the ComparatorChain |
||||
*/ |
||||
public void setForwardSort(final int index) { |
||||
checkLocked(); |
||||
orderingBits.clear(index); |
||||
} |
||||
|
||||
/** |
||||
* Change the sort order at the given index in the |
||||
* ComparatorChain to a reverse sort. |
||||
* |
||||
* @param index Index of the ComparatorChain |
||||
*/ |
||||
public void setReverseSort(final int index) { |
||||
checkLocked(); |
||||
orderingBits.set(index); |
||||
} |
||||
|
||||
/** |
||||
* Number of Comparators in the current ComparatorChain. |
||||
* |
||||
* @return Comparator count |
||||
*/ |
||||
public int size() { |
||||
return comparatorChain.size(); |
||||
} |
||||
|
||||
/** |
||||
* Determine if modifications can still be made to the |
||||
* ComparatorChain. ComparatorChains cannot be modified |
||||
* once they have performed a comparison. |
||||
* |
||||
* @return true = ComparatorChain cannot be modified; false = |
||||
* ComparatorChain can still be modified. |
||||
*/ |
||||
public boolean isLocked() { |
||||
return isLocked; |
||||
} |
||||
|
||||
/** |
||||
* Throws an exception if the {@link ComparatorChain} is locked. |
||||
* |
||||
* @throws UnsupportedOperationException if the {@link ComparatorChain} is locked |
||||
*/ |
||||
private void checkLocked() { |
||||
if (isLocked == true) { |
||||
throw new UnsupportedOperationException( |
||||
"Comparator ordering cannot be changed after the first comparison is performed"); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Throws an exception if the {@link ComparatorChain} is empty. |
||||
* |
||||
* @throws UnsupportedOperationException if the {@link ComparatorChain} is empty |
||||
*/ |
||||
private void checkChainIntegrity() { |
||||
if (comparatorChain.size() == 0) { |
||||
throw new UnsupportedOperationException("ComparatorChains must contain at least one Comparator"); |
||||
} |
||||
} |
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/** |
||||
* Perform comparisons on the Objects as per |
||||
* Comparator.compare(o1,o2). |
||||
* |
||||
* @param o1 the first object to compare |
||||
* @param o2 the second object to compare |
||||
* @return -1, 0, or 1 |
||||
* @throws UnsupportedOperationException if the ComparatorChain does not contain at least one Comparator |
||||
*/ |
||||
@Override |
||||
public int compare(final E o1, final E o2) throws UnsupportedOperationException { |
||||
if (isLocked == false) { |
||||
checkChainIntegrity(); |
||||
isLocked = true; |
||||
} |
||||
|
||||
// iterate over all comparators in the chain
|
||||
final Iterator<Comparator<E>> comparators = comparatorChain.iterator(); |
||||
for (int comparatorIndex = 0; comparators.hasNext(); ++comparatorIndex) { |
||||
|
||||
final Comparator<? super E> comparator = comparators.next(); |
||||
int retval = comparator.compare(o1,o2); |
||||
if (retval != 0) { |
||||
// invert the order if it is a reverse sort
|
||||
if (orderingBits.get(comparatorIndex) == true) { |
||||
if (retval > 0) { |
||||
retval = -1; |
||||
} else { |
||||
retval = 1; |
||||
} |
||||
} |
||||
return retval; |
||||
} |
||||
} |
||||
|
||||
// if comparators are exhausted, return 0
|
||||
return 0; |
||||
} |
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/** |
||||
* Implement a hash code for this comparator that is consistent with |
||||
* {@link #equals(Object) equals}. |
||||
* |
||||
* @return a suitable hash code |
||||
* @since 3.0 |
||||
*/ |
||||
@Override |
||||
public int hashCode() { |
||||
int hash = 0; |
||||
if (null != comparatorChain) { |
||||
hash ^= comparatorChain.hashCode(); |
||||
} |
||||
if (null != orderingBits) { |
||||
hash ^= orderingBits.hashCode(); |
||||
} |
||||
return hash; |
||||
} |
||||
|
||||
/** |
||||
* Returns <code>true</code> iff <i>that</i> Object is |
||||
* is a {@link Comparator} whose ordering is known to be |
||||
* equivalent to mine. |
||||
* <p> |
||||
* This implementation returns <code>true</code> |
||||
* iff <code><i>object</i>.{@link Object#getClass() getClass()}</code> |
||||
* equals <code>this.getClass()</code>, and the underlying |
||||
* comparators and order bits are equal. |
||||
* Subclasses may want to override this behavior to remain consistent |
||||
* with the {@link Comparator#equals(Object)} contract. |
||||
* |
||||
* @param object the object to compare with |
||||
* @return true if equal |
||||
* @since 3.0 |
||||
*/ |
||||
@Override |
||||
public boolean equals(final Object object) { |
||||
if (this == object) { |
||||
return true; |
||||
} |
||||
if (null == object) { |
||||
return false; |
||||
} |
||||
if (object.getClass().equals(this.getClass())) { |
||||
final ComparatorChain<?> chain = (ComparatorChain<?>) object; |
||||
return (null == orderingBits ? null == chain.orderingBits : orderingBits.equals(chain.orderingBits)) && |
||||
(null == comparatorChain ? null == chain.comparatorChain : |
||||
comparatorChain.equals(chain.comparatorChain)); |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
} |
@ -0,0 +1,299 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package com.fr.third.org.apache.commons.collections4.comparators; |
||||
|
||||
import java.io.Serializable; |
||||
import java.util.Comparator; |
||||
import java.util.HashMap; |
||||
import java.util.List; |
||||
import java.util.Map; |
||||
|
||||
/** |
||||
* A Comparator which imposes a specific order on a specific set of Objects. |
||||
* Objects are presented to the FixedOrderComparator in a specified order and |
||||
* subsequent calls to {@link #compare(Object, Object) compare} yield that order. |
||||
* For example: |
||||
* <pre> |
||||
* String[] planets = {"Mercury", "Venus", "Earth", "Mars"}; |
||||
* FixedOrderComparator distanceFromSun = new FixedOrderComparator(planets); |
||||
* Arrays.sort(planets); // Sort to alphabetical order
|
||||
* Arrays.sort(planets, distanceFromSun); // Back to original order
|
||||
* </pre> |
||||
* <p> |
||||
* Once <code>compare</code> has been called, the FixedOrderComparator is locked |
||||
* and attempts to modify it yield an UnsupportedOperationException. |
||||
* <p> |
||||
* Instances of FixedOrderComparator are not synchronized. The class is not |
||||
* thread-safe at construction time, but it is thread-safe to perform |
||||
* multiple comparisons after all the setup operations are complete. |
||||
* <p> |
||||
* This class is Serializable from Commons Collections 4.0. |
||||
* |
||||
* @since 3.0 |
||||
* @version $Id: FixedOrderComparator.java 1686855 2015-06-22 13:00:27Z tn $ |
||||
*/ |
||||
public class FixedOrderComparator<T> implements Comparator<T>, Serializable { |
||||
|
||||
/** Serialization version from Collections 4.0. */ |
||||
private static final long serialVersionUID = 82794675842863201L; |
||||
|
||||
/** |
||||
* Unknown object behavior enum. |
||||
* @since 4.0 |
||||
*/ |
||||
public static enum UnknownObjectBehavior { |
||||
BEFORE, AFTER, EXCEPTION; |
||||
} |
||||
|
||||
/** Internal map of object to position */ |
||||
private final Map<T, Integer> map = new HashMap<T, Integer>(); |
||||
|
||||
/** Counter used in determining the position in the map */ |
||||
private int counter = 0; |
||||
|
||||
/** Is the comparator locked against further change */ |
||||
private boolean isLocked = false; |
||||
|
||||
/** The behaviour in the case of an unknown object */ |
||||
private UnknownObjectBehavior unknownObjectBehavior = UnknownObjectBehavior.EXCEPTION; |
||||
|
||||
// Constructors
|
||||
//-----------------------------------------------------------------------
|
||||
/** |
||||
* Constructs an empty FixedOrderComparator. |
||||
*/ |
||||
public FixedOrderComparator() { |
||||
super(); |
||||
} |
||||
|
||||
/** |
||||
* Constructs a FixedOrderComparator which uses the order of the given array |
||||
* to compare the objects. |
||||
* <p> |
||||
* The array is copied, so later changes will not affect the comparator. |
||||
* |
||||
* @param items the items that the comparator can compare in order |
||||
* @throws NullPointerException if the array is null |
||||
*/ |
||||
public FixedOrderComparator(final T... items) { |
||||
super(); |
||||
if (items == null) { |
||||
throw new NullPointerException("The list of items must not be null"); |
||||
} |
||||
for (final T item : items) { |
||||
add(item); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Constructs a FixedOrderComparator which uses the order of the given list |
||||
* to compare the objects. |
||||
* <p> |
||||
* The list is copied, so later changes will not affect the comparator. |
||||
* |
||||
* @param items the items that the comparator can compare in order |
||||
* @throws NullPointerException if the list is null |
||||
*/ |
||||
public FixedOrderComparator(final List<T> items) { |
||||
super(); |
||||
if (items == null) { |
||||
throw new NullPointerException("The list of items must not be null"); |
||||
} |
||||
for (final T t : items) { |
||||
add(t); |
||||
} |
||||
} |
||||
|
||||
// Bean methods / state querying methods
|
||||
//-----------------------------------------------------------------------
|
||||
/** |
||||
* Returns true if modifications cannot be made to the FixedOrderComparator. |
||||
* FixedOrderComparators cannot be modified once they have performed a comparison. |
||||
* |
||||
* @return true if attempts to change the FixedOrderComparator yield an |
||||
* UnsupportedOperationException, false if it can be changed. |
||||
*/ |
||||
public boolean isLocked() { |
||||
return isLocked; |
||||
} |
||||
|
||||
/** |
||||
* Checks to see whether the comparator is now locked against further changes. |
||||
* |
||||
* @throws UnsupportedOperationException if the comparator is locked |
||||
*/ |
||||
protected void checkLocked() { |
||||
if (isLocked()) { |
||||
throw new UnsupportedOperationException("Cannot modify a FixedOrderComparator after a comparison"); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Gets the behavior for comparing unknown objects. |
||||
* |
||||
* @return {@link UnknownObjectBehavior} |
||||
*/ |
||||
public UnknownObjectBehavior getUnknownObjectBehavior() { |
||||
return unknownObjectBehavior; |
||||
} |
||||
|
||||
/** |
||||
* Sets the behavior for comparing unknown objects. |
||||
* |
||||
* @param unknownObjectBehavior the flag for unknown behaviour - |
||||
* UNKNOWN_AFTER, UNKNOWN_BEFORE or UNKNOWN_THROW_EXCEPTION |
||||
* @throws UnsupportedOperationException if a comparison has been performed |
||||
* @throws NullPointerException if unknownObjectBehavior is null |
||||
*/ |
||||
public void setUnknownObjectBehavior(final UnknownObjectBehavior unknownObjectBehavior) { |
||||
checkLocked(); |
||||
if (unknownObjectBehavior == null) { |
||||
throw new NullPointerException("Unknown object behavior must not be null"); |
||||
} |
||||
this.unknownObjectBehavior = unknownObjectBehavior; |
||||
} |
||||
|
||||
// Methods for adding items
|
||||
//-----------------------------------------------------------------------
|
||||
/** |
||||
* Adds an item, which compares as after all items known to the Comparator. |
||||
* If the item is already known to the Comparator, its old position is |
||||
* replaced with the new position. |
||||
* |
||||
* @param obj the item to be added to the Comparator. |
||||
* @return true if obj has been added for the first time, false if |
||||
* it was already known to the Comparator. |
||||
* @throws UnsupportedOperationException if a comparison has already been made |
||||
*/ |
||||
public boolean add(final T obj) { |
||||
checkLocked(); |
||||
final Integer position = map.put(obj, Integer.valueOf(counter++)); |
||||
return position == null; |
||||
} |
||||
|
||||
/** |
||||
* Adds a new item, which compares as equal to the given existing item. |
||||
* |
||||
* @param existingObj an item already in the Comparator's set of |
||||
* known objects |
||||
* @param newObj an item to be added to the Comparator's set of |
||||
* known objects |
||||
* @return true if newObj has been added for the first time, false if |
||||
* it was already known to the Comparator. |
||||
* @throws IllegalArgumentException if existingObject is not in the |
||||
* Comparator's set of known objects. |
||||
* @throws UnsupportedOperationException if a comparison has already been made |
||||
*/ |
||||
public boolean addAsEqual(final T existingObj, final T newObj) { |
||||
checkLocked(); |
||||
final Integer position = map.get(existingObj); |
||||
if (position == null) { |
||||
throw new IllegalArgumentException(existingObj + " not known to " + this); |
||||
} |
||||
final Integer result = map.put(newObj, position); |
||||
return result == null; |
||||
} |
||||
|
||||
// Comparator methods
|
||||
//-----------------------------------------------------------------------
|
||||
/** |
||||
* Compares two objects according to the order of this Comparator. |
||||
* <p> |
||||
* It is important to note that this class will throw an IllegalArgumentException |
||||
* in the case of an unrecognised object. This is not specified in the |
||||
* Comparator interface, but is the most appropriate exception. |
||||
* |
||||
* @param obj1 the first object to compare |
||||
* @param obj2 the second object to compare |
||||
* @return negative if obj1 is less, positive if greater, zero if equal |
||||
* @throws IllegalArgumentException if obj1 or obj2 are not known |
||||
* to this Comparator and an alternative behavior has not been set |
||||
* via {@link #setUnknownObjectBehavior(UnknownObjectBehavior)}. |
||||
*/ |
||||
@Override |
||||
public int compare(final T obj1, final T obj2) { |
||||
isLocked = true; |
||||
final Integer position1 = map.get(obj1); |
||||
final Integer position2 = map.get(obj2); |
||||
if (position1 == null || position2 == null) { |
||||
switch (unknownObjectBehavior) { |
||||
case BEFORE: |
||||
return position1 == null ? position2 == null ? 0 : -1 : 1; |
||||
case AFTER: |
||||
return position1 == null ? position2 == null ? 0 : 1 : -1; |
||||
case EXCEPTION: |
||||
final Object unknownObj = position1 == null ? obj1 : obj2; |
||||
throw new IllegalArgumentException("Attempting to compare unknown object " |
||||
+ unknownObj); |
||||
default: //could be null
|
||||
throw new UnsupportedOperationException("Unknown unknownObjectBehavior: " |
||||
+ unknownObjectBehavior); |
||||
} |
||||
} |
||||
return position1.compareTo(position2); |
||||
} |
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/** |
||||
* Implement a hash code for this comparator that is consistent with |
||||
* {@link #equals(Object) equals}. |
||||
* |
||||
* @return a hash code for this comparator. |
||||
*/ |
||||
@Override |
||||
public int hashCode() { |
||||
int total = 17; |
||||
total = total*37 + (map == null ? 0 : map.hashCode()); |
||||
total = total*37 + (unknownObjectBehavior == null ? 0 : unknownObjectBehavior.hashCode()); |
||||
total = total*37 + counter; |
||||
total = total*37 + (isLocked ? 0 : 1); |
||||
return total; |
||||
} |
||||
|
||||
/** |
||||
* Returns <code>true</code> iff <i>that</i> Object is |
||||
* is a {@link Comparator} whose ordering is known to be |
||||
* equivalent to mine. |
||||
* <p> |
||||
* This implementation returns <code>true</code> |
||||
* iff <code><i>that</i></code> is a {@link FixedOrderComparator} |
||||
* whose attributes are equal to mine. |
||||
* |
||||
* @param object the object to compare to |
||||
* @return true if equal |
||||
*/ |
||||
@Override |
||||
public boolean equals(final Object object) { |
||||
if (this == object) { |
||||
return true; |
||||
} |
||||
if (null == object) { |
||||
return false; |
||||
} |
||||
if (object.getClass().equals(this.getClass())) { |
||||
final FixedOrderComparator<?> comp = (FixedOrderComparator<?>) object; |
||||
return (null == map ? null == comp.map : map.equals(comp.map)) && |
||||
(null == unknownObjectBehavior ? null == comp.unknownObjectBehavior : |
||||
unknownObjectBehavior == comp.unknownObjectBehavior && |
||||
counter == comp.counter && |
||||
isLocked == comp.isLocked && |
||||
unknownObjectBehavior == comp.unknownObjectBehavior); |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
} |
@ -0,0 +1,182 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package com.fr.third.org.apache.commons.collections4.comparators; |
||||
|
||||
import java.io.Serializable; |
||||
import java.util.Comparator; |
||||
|
||||
import com.fr.third.org.apache.commons.collections4.ComparatorUtils; |
||||
import com.fr.third.org.apache.commons.collections4.ComparatorUtils; |
||||
|
||||
/** |
||||
* A Comparator that will compare nulls to be either lower or higher than |
||||
* other objects. |
||||
* |
||||
* @since 2.0 |
||||
* @version $Id: NullComparator.java 1683951 2015-06-06 20:19:03Z tn $ |
||||
*/ |
||||
public class NullComparator<E> implements Comparator<E>, Serializable { |
||||
|
||||
/** Serialization version. */ |
||||
private static final long serialVersionUID = -5820772575483504339L; |
||||
|
||||
/** |
||||
* The comparator to use when comparing two non-<code>null</code> objects. |
||||
**/ |
||||
private final Comparator<? super E> nonNullComparator; |
||||
|
||||
/** |
||||
* Specifies whether a <code>null</code> are compared as higher than |
||||
* non-<code>null</code> objects. |
||||
**/ |
||||
private final boolean nullsAreHigh; |
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/** |
||||
* Construct an instance that sorts <code>null</code> higher than any |
||||
* non-<code>null</code> object it is compared with. When comparing two |
||||
* non-<code>null</code> objects, the {@link ComparableComparator} is |
||||
* used. |
||||
**/ |
||||
@SuppressWarnings("unchecked") |
||||
public NullComparator() { |
||||
this(ComparatorUtils.NATURAL_COMPARATOR, true); |
||||
} |
||||
|
||||
/** |
||||
* Construct an instance that sorts <code>null</code> higher than any |
||||
* non-<code>null</code> object it is compared with. When comparing two |
||||
* non-<code>null</code> objects, the specified {@link Comparator} is |
||||
* used. |
||||
* |
||||
* @param nonNullComparator the comparator to use when comparing two |
||||
* non-<code>null</code> objects. This argument cannot be |
||||
* <code>null</code> |
||||
* |
||||
* @exception NullPointerException if <code>nonNullComparator</code> is |
||||
* <code>null</code> |
||||
**/ |
||||
public NullComparator(final Comparator<? super E> nonNullComparator) { |
||||
this(nonNullComparator, true); |
||||
} |
||||
|
||||
/** |
||||
* Construct an instance that sorts <code>null</code> higher or lower than |
||||
* any non-<code>null</code> object it is compared with. When comparing |
||||
* two non-<code>null</code> objects, the {@link ComparableComparator} is |
||||
* used. |
||||
* |
||||
* @param nullsAreHigh a <code>true</code> value indicates that |
||||
* <code>null</code> should be compared as higher than a |
||||
* non-<code>null</code> object. A <code>false</code> value indicates |
||||
* that <code>null</code> should be compared as lower than a |
||||
* non-<code>null</code> object. |
||||
**/ |
||||
@SuppressWarnings("unchecked") |
||||
public NullComparator(final boolean nullsAreHigh) { |
||||
this(ComparatorUtils.NATURAL_COMPARATOR, nullsAreHigh); |
||||
} |
||||
|
||||
/** |
||||
* Construct an instance that sorts <code>null</code> higher or lower than |
||||
* any non-<code>null</code> object it is compared with. When comparing |
||||
* two non-<code>null</code> objects, the specified {@link Comparator} is |
||||
* used. |
||||
* |
||||
* @param nonNullComparator the comparator to use when comparing two |
||||
* non-<code>null</code> objects. This argument cannot be |
||||
* <code>null</code> |
||||
* |
||||
* @param nullsAreHigh a <code>true</code> value indicates that |
||||
* <code>null</code> should be compared as higher than a |
||||
* non-<code>null</code> object. A <code>false</code> value indicates |
||||
* that <code>null</code> should be compared as lower than a |
||||
* non-<code>null</code> object. |
||||
* |
||||
* @exception NullPointerException if <code>nonNullComparator</code> is |
||||
* <code>null</code> |
||||
**/ |
||||
public NullComparator(final Comparator<? super E> nonNullComparator, final boolean nullsAreHigh) { |
||||
this.nonNullComparator = nonNullComparator; |
||||
this.nullsAreHigh = nullsAreHigh; |
||||
|
||||
if (nonNullComparator == null) { |
||||
throw new NullPointerException("null nonNullComparator"); |
||||
} |
||||
} |
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/** |
||||
* Perform a comparison between two objects. If both objects are |
||||
* <code>null</code>, a <code>0</code> value is returned. If one object |
||||
* is <code>null</code> and the other is not, the result is determined on |
||||
* whether the Comparator was constructed to have nulls as higher or lower |
||||
* than other objects. If neither object is <code>null</code>, an |
||||
* underlying comparator specified in the constructor (or the default) is |
||||
* used to compare the non-<code>null</code> objects. |
||||
* |
||||
* @param o1 the first object to compare |
||||
* @param o2 the object to compare it to. |
||||
* @return <code>-1</code> if <code>o1</code> is "lower" than (less than, |
||||
* before, etc.) <code>o2</code>; <code>1</code> if <code>o1</code> is |
||||
* "higher" than (greater than, after, etc.) <code>o2</code>; or |
||||
* <code>0</code> if <code>o1</code> and <code>o2</code> are equal. |
||||
**/ |
||||
@Override |
||||
public int compare(final E o1, final E o2) { |
||||
if(o1 == o2) { return 0; } |
||||
if(o1 == null) { return this.nullsAreHigh ? 1 : -1; } |
||||
if(o2 == null) { return this.nullsAreHigh ? -1 : 1; } |
||||
return this.nonNullComparator.compare(o1, o2); |
||||
} |
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/** |
||||
* Implement a hash code for this comparator that is consistent with |
||||
* {@link #equals(Object)}. |
||||
* |
||||
* @return a hash code for this comparator. |
||||
**/ |
||||
@Override |
||||
public int hashCode() { |
||||
return (nullsAreHigh ? -1 : 1) * nonNullComparator.hashCode(); |
||||
} |
||||
|
||||
/** |
||||
* Determines whether the specified object represents a comparator that is |
||||
* equal to this comparator. |
||||
* |
||||
* @param obj the object to compare this comparator with. |
||||
* |
||||
* @return <code>true</code> if the specified object is a NullComparator |
||||
* with equivalent <code>null</code> comparison behavior |
||||
* (i.e. <code>null</code> high or low) and with equivalent underlying |
||||
* non-<code>null</code> object comparators. |
||||
**/ |
||||
@Override |
||||
public boolean equals(final Object obj) { |
||||
if(obj == null) { return false; } |
||||
if(obj == this) { return true; } |
||||
if(!obj.getClass().equals(this.getClass())) { return false; } |
||||
|
||||
final NullComparator<?> other = (NullComparator<?>) obj; |
||||
|
||||
return this.nullsAreHigh == other.nullsAreHigh && |
||||
this.nonNullComparator.equals(other.nonNullComparator); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,125 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package com.fr.third.org.apache.commons.collections4.comparators; |
||||
|
||||
import java.io.Serializable; |
||||
import java.util.Comparator; |
||||
|
||||
import com.fr.third.org.apache.commons.collections4.ComparatorUtils; |
||||
import com.fr.third.org.apache.commons.collections4.ComparatorUtils; |
||||
|
||||
/** |
||||
* Reverses the order of another comparator by reversing the arguments |
||||
* to its {@link #compare(Object, Object) compare} method. |
||||
* |
||||
* @since 2.0 |
||||
* @version $Id: ReverseComparator.java 1683951 2015-06-06 20:19:03Z tn $ |
||||
* |
||||
* @see java.util.Collections#reverseOrder() |
||||
*/ |
||||
public class ReverseComparator<E> implements Comparator<E>, Serializable { |
||||
|
||||
/** Serialization version from Collections 2.0. */ |
||||
private static final long serialVersionUID = 2858887242028539265L; |
||||
|
||||
/** The comparator being decorated. */ |
||||
private final Comparator<? super E> comparator; |
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/** |
||||
* Creates a comparator that compares objects based on the inverse of their |
||||
* natural ordering. Using this Constructor will create a ReverseComparator |
||||
* that is functionally identical to the Comparator returned by |
||||
* java.util.Collections.<b>reverseOrder()</b>. |
||||
* |
||||
* @see java.util.Collections#reverseOrder() |
||||
*/ |
||||
public ReverseComparator() { |
||||
this(null); |
||||
} |
||||
|
||||
/** |
||||
* Creates a comparator that inverts the comparison |
||||
* of the given comparator. If you pass in <code>null</code>, |
||||
* the ReverseComparator defaults to reversing the |
||||
* natural order, as per {@link java.util.Collections#reverseOrder()}. |
||||
* |
||||
* @param comparator Comparator to reverse |
||||
*/ |
||||
@SuppressWarnings("unchecked") |
||||
public ReverseComparator(final Comparator<? super E> comparator) { |
||||
this.comparator = comparator == null ? ComparatorUtils.NATURAL_COMPARATOR : comparator; |
||||
} |
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/** |
||||
* Compares two objects in reverse order. |
||||
* |
||||
* @param obj1 the first object to compare |
||||
* @param obj2 the second object to compare |
||||
* @return negative if obj1 is less, positive if greater, zero if equal |
||||
*/ |
||||
@Override |
||||
public int compare(final E obj1, final E obj2) { |
||||
return comparator.compare(obj2, obj1); |
||||
} |
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/** |
||||
* Implement a hash code for this comparator that is consistent with |
||||
* {@link #equals(Object) equals}. |
||||
* |
||||
* @return a suitable hash code |
||||
* @since 3.0 |
||||
*/ |
||||
@Override |
||||
public int hashCode() { |
||||
return "ReverseComparator".hashCode() ^ comparator.hashCode(); |
||||
} |
||||
|
||||
/** |
||||
* Returns <code>true</code> iff <i>that</i> Object is |
||||
* is a {@link Comparator} whose ordering is known to be |
||||
* equivalent to mine. |
||||
* <p> |
||||
* This implementation returns <code>true</code> |
||||
* iff <code><i>object</i>.{@link Object#getClass() getClass()}</code> |
||||
* equals <code>this.getClass()</code>, and the underlying |
||||
* comparators are equal. |
||||
* Subclasses may want to override this behavior to remain consistent |
||||
* with the {@link Comparator#equals(Object) equals} contract. |
||||
* |
||||
* @param object the object to compare to |
||||
* @return true if equal |
||||
* @since 3.0 |
||||
*/ |
||||
@Override |
||||
public boolean equals(final Object object) { |
||||
if (this == object) { |
||||
return true; |
||||
} |
||||
if (null == object) { |
||||
return false; |
||||
} |
||||
if (object.getClass().equals(this.getClass())) { |
||||
final ReverseComparator<?> thatrc = (ReverseComparator<?>) object; |
||||
return comparator.equals(thatrc.comparator); |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
} |
@ -0,0 +1,133 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package com.fr.third.org.apache.commons.collections4.comparators; |
||||
|
||||
import java.io.Serializable; |
||||
import java.util.Comparator; |
||||
|
||||
import com.fr.third.org.apache.commons.collections4.ComparatorUtils; |
||||
import com.fr.third.org.apache.commons.collections4.Transformer; |
||||
import com.fr.third.org.apache.commons.collections4.ComparatorUtils; |
||||
import com.fr.third.org.apache.commons.collections4.Transformer; |
||||
|
||||
/** |
||||
* Decorates another Comparator with transformation behavior. That is, the |
||||
* return value from the transform operation will be passed to the decorated |
||||
* {@link Comparator#compare(Object,Object) compare} method. |
||||
* <p> |
||||
* This class is Serializable from Commons Collections 4.0. |
||||
* |
||||
* @since 2.1 |
||||
* @version $Id: TransformingComparator.java 1683951 2015-06-06 20:19:03Z tn $ |
||||
* |
||||
* @see Transformer |
||||
* @see org.apache.commons.collections4.comparators.ComparableComparator |
||||
*/ |
||||
public class TransformingComparator<I, O> implements Comparator<I>, Serializable { |
||||
|
||||
/** Serialization version from Collections 4.0. */ |
||||
private static final long serialVersionUID = 3456940356043606220L; |
||||
|
||||
/** The decorated comparator. */ |
||||
private final Comparator<O> decorated; |
||||
/** The transformer being used. */ |
||||
private final Transformer<? super I, ? extends O> transformer; |
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/** |
||||
* Constructs an instance with the given Transformer and a |
||||
* {@link ComparableComparator ComparableComparator}. |
||||
* |
||||
* @param transformer what will transform the arguments to <code>compare</code> |
||||
*/ |
||||
@SuppressWarnings("unchecked") |
||||
public TransformingComparator(final Transformer<? super I, ? extends O> transformer) { |
||||
this(transformer, ComparatorUtils.NATURAL_COMPARATOR); |
||||
} |
||||
|
||||
/** |
||||
* Constructs an instance with the given Transformer and Comparator. |
||||
* |
||||
* @param transformer what will transform the arguments to <code>compare</code> |
||||
* @param decorated the decorated Comparator |
||||
*/ |
||||
public TransformingComparator(final Transformer<? super I, ? extends O> transformer, |
||||
final Comparator<O> decorated) { |
||||
this.decorated = decorated; |
||||
this.transformer = transformer; |
||||
} |
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/** |
||||
* Returns the result of comparing the values from the transform operation. |
||||
* |
||||
* @param obj1 the first object to transform then compare |
||||
* @param obj2 the second object to transform then compare |
||||
* @return negative if obj1 is less, positive if greater, zero if equal |
||||
*/ |
||||
@Override |
||||
public int compare(final I obj1, final I obj2) { |
||||
final O value1 = this.transformer.transform(obj1); |
||||
final O value2 = this.transformer.transform(obj2); |
||||
return this.decorated.compare(value1, value2); |
||||
} |
||||
|
||||
//-----------------------------------------------------------------------
|
||||
/** |
||||
* Implement a hash code for this comparator that is consistent with |
||||
* {@link #equals(Object) equals}. |
||||
* |
||||
* @return a hash code for this comparator. |
||||
*/ |
||||
@Override |
||||
public int hashCode() { |
||||
int total = 17; |
||||
total = total*37 + (decorated == null ? 0 : decorated.hashCode()); |
||||
total = total*37 + (transformer == null ? 0 : transformer.hashCode()); |
||||
return total; |
||||
} |
||||
|
||||
/** |
||||
* Returns <code>true</code> iff <i>that</i> Object is |
||||
* is a {@link Comparator} whose ordering is known to be |
||||
* equivalent to mine. |
||||
* <p> |
||||
* This implementation returns <code>true</code> |
||||
* iff <code><i>that</i></code> is a {@link TransformingComparator} |
||||
* whose attributes are equal to mine. |
||||
* |
||||
* @param object the object to compare to |
||||
* @return true if equal |
||||
*/ |
||||
@Override |
||||
public boolean equals(final Object object) { |
||||
if (this == object) { |
||||
return true; |
||||
} |
||||
if (null == object) { |
||||
return false; |
||||
} |
||||
if (object.getClass().equals(this.getClass())) { |
||||
final TransformingComparator<?, ?> comp = (TransformingComparator<?, ?>) object; |
||||
return (null == decorated ? null == comp.decorated : decorated.equals(comp.decorated)) && |
||||
(null == transformer ? null == comp.transformer : transformer.equals(comp.transformer)); |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
} |
||||
|
@ -0,0 +1,28 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
/** |
||||
* This package contains implementations of the |
||||
* {@link java.util.Comparator Comparator} interface. |
||||
* <p> |
||||
* You may also consider using |
||||
* {@link com.fr.third.org.apache.commons.collections4.ComparatorUtils ComparatorUtils}, |
||||
* which is a single class that uses static methods to construct instances |
||||
* of the classes in this package. |
||||
* |
||||
* @version $Id: package-info.java 1477747 2013-04-30 18:16:48Z tn $ |
||||
*/ |
||||
package com.fr.third.org.apache.commons.collections4.comparators; |
@ -0,0 +1,56 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package com.fr.third.org.apache.commons.collections4.functors; |
||||
|
||||
import java.io.Serializable; |
||||
|
||||
import com.fr.third.org.apache.commons.collections4.Predicate; |
||||
|
||||
/** |
||||
* Abstract base class for quantification predicates, e.g. All, Any, None. |
||||
* |
||||
* @since 4.0 |
||||
* @version $Id: AbstractQuantifierPredicate.java 1543167 2013-11-18 21:21:32Z ggregory $ |
||||
*/ |
||||
public abstract class AbstractQuantifierPredicate<T> implements PredicateDecorator<T>, Serializable { |
||||
|
||||
/** Serial version UID */ |
||||
private static final long serialVersionUID = -3094696765038308799L; |
||||
|
||||
/** The array of predicates to call */ |
||||
protected final Predicate<? super T>[] iPredicates; |
||||
|
||||
/** |
||||
* Constructor that performs no validation. |
||||
* |
||||
* @param predicates the predicates to check, not cloned, not null |
||||
*/ |
||||
public AbstractQuantifierPredicate(final Predicate<? super T>... predicates) { |
||||
iPredicates = predicates; |
||||
} |
||||
|
||||
/** |
||||
* Gets the predicates. |
||||
* |
||||
* @return a copy of the predicates |
||||
* @since 3.1 |
||||
*/ |
||||
public Predicate<? super T>[] getPredicates() { |
||||
return FunctorUtils.<T>copy(iPredicates); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,115 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
package com.fr.third.org.apache.commons.collections4.functors; |
||||
|
||||
import static com.fr.third.org.apache.commons.collections4.functors.FunctorUtils.coerce; |
||||
import static com.fr.third.org.apache.commons.collections4.functors.FunctorUtils.validate; |
||||
import static com.fr.third.org.apache.commons.collections4.functors.TruePredicate.truePredicate; |
||||
|
||||
import java.util.Collection; |
||||
|
||||
import com.fr.third.org.apache.commons.collections4.Predicate; |
||||
|
||||
/** |
||||
* Predicate implementation that returns true if all the |
||||
* predicates return true. |
||||
* If the array of predicates is empty, then this predicate returns true. |
||||
* <p> |
||||
* NOTE: In versions prior to 3.2 an array size of zero or one |
||||
* threw an exception. |
||||
* |
||||
* @since 3.0 |
||||
* @version $Id: AllPredicate.java 1686855 2015-06-22 13:00:27Z tn $ |
||||
*/ |
||||
public final class AllPredicate<T> extends AbstractQuantifierPredicate<T> { |
||||
|
||||
/** Serial version UID */ |
||||
private static final long serialVersionUID = -3094696765038308799L; |
||||
|
||||
/** |
||||
* Factory to create the predicate. |
||||
* <p> |
||||
* If the array is size zero, the predicate always returns true. |
||||
* If the array is size one, then that predicate is returned. |
||||
* |
||||
* @param <T> the type that the predicate queries |
||||
* @param predicates the predicates to check, cloned, not null |
||||
* @return the <code>all</code> predicate |
||||
* @throws NullPointerException if the predicates array is null |
||||
* @throws NullPointerException if any predicate in the array is null |
||||
*/ |
||||
public static <T> Predicate<T> allPredicate(final Predicate<? super T>... predicates) { |
||||
FunctorUtils.validate(predicates); |
||||
if (predicates.length == 0) { |
||||
return TruePredicate.truePredicate(); |
||||
} |
||||
if (predicates.length == 1) { |
||||
return coerce(predicates[0]); |
||||
} |
||||
|
||||
return new AllPredicate<T>(FunctorUtils.copy(predicates)); |
||||
} |
||||
|
||||
/** |
||||
* Factory to create the predicate. |
||||
* <p> |
||||
* If the collection is size zero, the predicate always returns true. |
||||
* If the collection is size one, then that predicate is returned. |
||||
* |
||||
* @param <T> the type that the predicate queries |
||||
* @param predicates the predicates to check, cloned, not null |
||||
* @return the <code>all</code> predicate |
||||
* @throws NullPointerException if the predicates array is null |
||||
* @throws NullPointerException if any predicate in the array is null |
||||
*/ |
||||
public static <T> Predicate<T> allPredicate(final Collection<? extends Predicate<? super T>> predicates) { |
||||
final Predicate<? super T>[] preds = validate(predicates); |
||||
if (preds.length == 0) { |
||||
return TruePredicate.truePredicate(); |
||||
} |
||||
if (preds.length == 1) { |
||||
return coerce(preds[0]); |
||||
} |
||||
return new AllPredicate<T>(preds); |
||||
} |
||||
|
||||
/** |
||||
* Constructor that performs no validation. |
||||
* Use <code>allPredicate</code> if you want that. |
||||
* |
||||
* @param predicates the predicates to check, not cloned, not null |
||||
*/ |
||||
public AllPredicate(final Predicate<? super T>... predicates) { |
||||
super(predicates); |
||||
} |
||||
|
||||
/** |
||||
* Evaluates the predicate returning true if all predicates return true. |
||||
* |
||||
* @param object the input object |
||||
* @return true if all decorated predicates return true |
||||
*/ |
||||
public boolean evaluate(final T object) { |
||||
for (final Predicate<? super T> iPredicate : iPredicates) { |
||||
if (!iPredicate.evaluate(object)) { |
||||
return false; |
||||
} |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
} |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue