- /*
- * Copyright 2001-2004 The Apache Software Foundation
- *
- * Licensed 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 org.apache.commons.collections.list;
-
- import java.util.ArrayList;
- import java.util.Collection;
- import java.util.HashSet;
- import java.util.Iterator;
- import java.util.List;
- import java.util.ListIterator;
- import java.util.Set;
-
- import org.apache.commons.collections.iterators.AbstractIteratorDecorator;
- import org.apache.commons.collections.iterators.AbstractListIteratorDecorator;
- import org.apache.commons.collections.set.UnmodifiableSet;
-
- /**
- * Decorates a <code>List</code> to ensure that no duplicates are present
- * much like a <code>Set</code>.
- * <p>
- * The <code>List</code> interface makes certain assumptions/requirements.
- * This implementation breaks these in certain ways, but this is merely the
- * result of rejecting duplicates.
- * Each violation is explained in the method, but it should not affect you.
- * <p>
- * The {@link org.apache.commons.collections.set.ListOrderedSet ListOrderedSet}
- * class provides an alternative approach, by wrapping an existing Set and
- * retaining insertion order in the iterator.
- * <p>
- * This class is Serializable from Commons Collections 3.1.
- *
- * @since Commons Collections 3.0
- * @version $Revision: 1.8 $ $Date: 2004/06/03 22:02:13 $
- *
- * @author Matthew Hawthorne
- * @author Stephen Colebourne
- */
- public class SetUniqueList extends AbstractSerializableListDecorator {
-
- /** Serialization version */
- private static final long serialVersionUID = 7196982186153478694L;
-
- /**
- * Internal Set to maintain uniqueness.
- */
- protected final Set set;
-
- /**
- * Factory method to create a SetList using the supplied list to retain order.
- * <p>
- * If the list contains duplicates, these are removed (first indexed one kept).
- * A <code>HashSet</code> is used for the set behaviour.
- *
- * @param list the list to decorate, must not be null
- * @throws IllegalArgumentException if list is null
- */
- public static SetUniqueList decorate(List list) {
- if (list == null) {
- throw new IllegalArgumentException("List must not be null");
- }
- if (list.isEmpty()) {
- return new SetUniqueList(list, new HashSet());
- } else {
- List temp = new ArrayList(list);
- list.clear();
- SetUniqueList sl = new SetUniqueList(list, new HashSet());
- sl.addAll(temp);
- return sl;
- }
- }
-
- //-----------------------------------------------------------------------
- /**
- * Constructor that wraps (not copies) the List and specifies the set to use.
- * <p>
- * The set and list must both be correctly initialised to the same elements.
- *
- * @param set the set to decorate, must not be null
- * @param list the list to decorate, must not be null
- * @throws IllegalArgumentException if set or list is null
- */
- protected SetUniqueList(List list, Set set) {
- super(list);
- if (set == null) {
- throw new IllegalArgumentException("Set must not be null");
- }
- this.set = set;
- }
-
- //-----------------------------------------------------------------------
- /**
- * Gets an unmodifiable view as a Set.
- *
- * @return an unmodifiable set view
- */
- public Set asSet() {
- return UnmodifiableSet.decorate(set);
- }
-
- //-----------------------------------------------------------------------
- /**
- * Adds an element to the list if it is not already present.
- * <p>
- * <i>(Violation)</i>
- * The <code>List</code> interface requires that this method returns
- * <code>true</code> always. However this class may return <code>false</code>
- * because of the <code>Set</code> behaviour.
- *
- * @param object the object to add
- * @return true if object was added
- */
- public boolean add(Object object) {
- // gets initial size
- final int sizeBefore = size();
-
- // adds element if unique
- add(size(), object);
-
- // compares sizes to detect if collection changed
- return (sizeBefore != size());
- }
-
- /**
- * Adds an element to a specific index in the list if it is not already present.
- * <p>
- * <i>(Violation)</i>
- * The <code>List</code> interface makes the assumption that the element is
- * always inserted. This may not happen with this implementation.
- *
- * @param index the index to insert at
- * @param object the object to add
- */
- public void add(int index, Object object) {
- // adds element if it is not contained already
- if (set.contains(object) == false) {
- super.add(index, object);
- set.add(object);
- }
- }
-
- /**
- * Adds an element to the end of the list if it is not already present.
- * <p>
- * <i>(Violation)</i>
- * The <code>List</code> interface makes the assumption that the element is
- * always inserted. This may not happen with this implementation.
- *
- * @param coll the collection to add
- */
- public boolean addAll(Collection coll) {
- return addAll(size(), coll);
- }
-
- /**
- * Adds a collection of objects to the end of the list avoiding duplicates.
- * <p>
- * Only elements that are not already in this list will be added, and
- * duplicates from the specified collection will be ignored.
- * <p>
- * <i>(Violation)</i>
- * The <code>List</code> interface makes the assumption that the elements
- * are always inserted. This may not happen with this implementation.
- *
- * @param index the index to insert at
- * @param coll the collection to add in iterator order
- * @return true if this collection changed
- */
- public boolean addAll(int index, Collection coll) {
- // gets initial size
- final int sizeBefore = size();
-
- // adds all elements
- for (final Iterator it = coll.iterator(); it.hasNext();) {
- add(it.next());
- }
-
- // compares sizes to detect if collection changed
- return sizeBefore != size();
- }
-
- //-----------------------------------------------------------------------
- /**
- * Sets the value at the specified index avoiding duplicates.
- * <p>
- * The object is set into the specified index.
- * Afterwards, any previous duplicate is removed
- * If the object is not already in the list then a normal set occurs.
- * If it is present, then the old version is removed and re-added at this index
- *
- * @param index the index to insert at
- * @param object the object to set
- * @return the previous object
- */
- public Object set(int index, Object object) {
- int pos = indexOf(object);
- Object result = super.set(index, object);
- if (pos == -1 || pos == index) {
- return result;
- }
- return remove(pos);
- }
-
- public boolean remove(Object object) {
- boolean result = super.remove(object);
- set.remove(object);
- return result;
- }
-
- public Object remove(int index) {
- Object result = super.remove(index);
- set.remove(result);
- return result;
- }
-
- public boolean removeAll(Collection coll) {
- boolean result = super.removeAll(coll);
- set.removeAll(coll);
- return result;
- }
-
- public boolean retainAll(Collection coll) {
- boolean result = super.retainAll(coll);
- set.retainAll(coll);
- return result;
- }
-
- public void clear() {
- super.clear();
- set.clear();
- }
-
- public boolean contains(Object object) {
- return set.contains(object);
- }
-
- public boolean containsAll(Collection coll) {
- return set.containsAll(coll);
- }
-
- public Iterator iterator() {
- return new SetListIterator(super.iterator(), set);
- }
-
- public ListIterator listIterator() {
- return new SetListListIterator(super.listIterator(), set);
- }
-
- public ListIterator listIterator(int index) {
- return new SetListListIterator(super.listIterator(index), set);
- }
-
- public List subList(int fromIndex, int toIndex) {
- return new SetUniqueList(super.subList(fromIndex, toIndex), set);
- }
-
- //-----------------------------------------------------------------------
- /**
- * Inner class iterator.
- */
- static class SetListIterator extends AbstractIteratorDecorator {
-
- protected final Set set;
- protected Object last = null;
-
- protected SetListIterator(Iterator it, Set set) {
- super(it);
- this.set = set;
- }
-
- public Object next() {
- last = super.next();
- return last;
- }
-
- public void remove() {
- super.remove();
- set.remove(last);
- last = null;
- }
- }
-
- /**
- * Inner class iterator.
- */
- static class SetListListIterator extends AbstractListIteratorDecorator {
-
- protected final Set set;
- protected Object last = null;
-
- protected SetListListIterator(ListIterator it, Set set) {
- super(it);
- this.set = set;
- }
-
- public Object next() {
- last = super.next();
- return last;
- }
-
- public Object previous() {
- last = super.previous();
- return last;
- }
-
- public void remove() {
- super.remove();
- set.remove(last);
- last = null;
- }
-
- public void add(Object object) {
- if (set.contains(object) == false) {
- super.add(object);
- set.add(object);
- }
- }
-
- public void set(Object object) {
- throw new UnsupportedOperationException("ListIterator does not support set");
- }
- }
-
- }