/*
* 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.rincliu.library.common.persistence.afinal.core;
import java.lang.reflect.Array;
import java.util.Collection;
import java.util.Iterator;
/**
* Class {@code AbstractCollection} is an abstract implementation of the
* {@code Collection} interface. A subclass must implement the abstract
* methods {@code iterator()} and {@code size()} to create an immutable
* collection. To create a modifiable collection it's necessary to override
* the {@code add()} method that currently throws an
* {@code UnsupportedOperationException}.
*
* @since 1.2
*/
public abstract class AbstractCollection<E> implements Collection<E> {
/**
* Constructs a new instance of this AbstractCollection.
*/
protected AbstractCollection() {}
@Override
public boolean add(E object) {
throw new UnsupportedOperationException();
}
/**
* Attempts to add all of the objects contained in {@code collection} to
* the contents of this {@code Collection} (optional). This implementation
* iterates over the given {@code Collection} and calls {@code add} for
* each element. If any of these calls return {@code true}, then
* {@code true} is returned as result of this method call, {@code false}
* otherwise. If this {@code Collection} does not support adding elements,
* an {@code UnsupportedOperationException} is thrown.
* <p>
* If the passed {@code Collection} is changed during the process of
* adding elements to this {@code Collection}, the behavior depends on the
* behavior of the passed {@code Collection}.
*
* @param collection the collection of objects.
* @return {@code true} if this {@code Collection} is modified,
* {@code false} otherwise.
* @throws UnsupportedOperationException if adding to this
* {@code Collection} is not supported.
* @throws ClassCastException if the class of an object is inappropriate
* for this {@code Collection}.
* @throws IllegalArgumentException if an object cannot be added to this
* {@code Collection}.
* @throws NullPointerException if {@code collection} is {@code null}, or
* if it contains {@code null} elements and this
* {@code Collection} does not support such elements.
*/
@Override
public boolean addAll(Collection<? extends E> collection) {
boolean result = false;
Iterator<? extends E> it = collection.iterator();
while (it.hasNext()) {
if (add(it.next())) {
result = true;
}
}
return result;
}
/**
* Removes all elements from this {@code Collection}, leaving it empty
* (optional). This implementation iterates over this {@code Collection}
* and calls the {@code remove} method on each element. If the iterator
* does not support removal of elements, an
* {@code UnsupportedOperationException} is thrown.
* <p>
* Concrete implementations usually can clear a {@code Collection} more
* efficiently and should therefore overwrite this method.
*
* @throws UnsupportedOperationException it the iterator does not support
* removing elements from this {@code Collection}
* @see #iterator
* @see #isEmpty
* @see #size
*/
@Override
public void clear() {
Iterator<E> it = iterator();
while (it.hasNext()) {
it.next();
it.remove();
}
}
/**
* Tests whether this {@code Collection} contains the specified object.
* This implementation iterates over this {@code Collection} and tests,
* whether any element is equal to the given object. If
* {@code object != null} then {@code object.equals(e)} is called for each
* element {@code e} returned by the iterator until the element is found.
* If {@code object == null} then each element {@code e} returned by the
* iterator is compared with the test {@code e == null}.
*
* @param object the object to search for.
* @return {@code true} if object is an element of this {@code Collection}
* , {@code false} otherwise.
* @throws ClassCastException if the object to look for isn't of the
* correct type.
* @throws NullPointerException if the object to look for is {@code null}
* and this {@code Collection} doesn't support {@code null}
* elements.
*/
@Override
public boolean contains(Object object) {
Iterator<E> it = iterator();
if (object != null) {
while (it.hasNext()) {
if (object.equals(it.next())) {
return true;
}
}
} else {
while (it.hasNext()) {
if (it.next() == null) {
return true;
}
}
}
return false;
}
/**
* Tests whether this {@code Collection} contains all objects contained in
* the specified {@code Collection}. This implementation iterates over the
* specified {@code Collection}. If one element returned by the iterator
* is not contained in this {@code Collection}, then {@code false} is
* returned; {@code true} otherwise.
*
* @param collection the collection of objects.
* @return {@code true} if all objects in the specified {@code Collection}
* are elements of this {@code Collection}, {@code false}
* otherwise.
* @throws ClassCastException if one or more elements of
* {@code collection} isn't of the correct type.
* @throws NullPointerException if {@code collection} contains at least
* one {@code null} element and this {@code Collection}
* doesn't support {@code null} elements.
* @throws NullPointerException if {@code collection} is {@code null}.
*/
@Override
public boolean containsAll(Collection<?> collection) {
Iterator<?> it = collection.iterator();
while (it.hasNext()) {
if (!contains(it.next())) {
return false;
}
}
return true;
}
/**
* Returns if this {@code Collection} contains no elements. This
* implementation tests, whether {@code size} returns 0.
*
* @return {@code true} if this {@code Collection} has no elements,
* {@code false} otherwise.
* @see #size
*/
@Override
public boolean isEmpty() {
return size() == 0;
}
/**
* Returns an instance of {@link Iterator} that may be used to access the
* objects contained by this {@code Collection}. The order in which the
* elements are returned by the {@link Iterator} is not defined unless the
* instance of the {@code Collection} has a defined order. In that case,
* the elements are returned in that order.
* <p>
* In this class this method is declared abstract and has to be
* implemented by concrete {@code Collection} implementations.
*
* @return an iterator for accessing the {@code Collection} contents.
*/
@Override
public abstract Iterator<E> iterator();
/**
* Removes one instance of the specified object from this
* {@code Collection} if one is contained (optional). This implementation
* iterates over this {@code Collection} and tests for each element
* {@code e} returned by the iterator, whether {@code e} is equal to the
* given object. If {@code object != null} then this test is performed
* using {@code object.equals(e)}, otherwise using {@code object == null}.
* If an element equal to the given object is found, then the
* {@code remove} method is called on the iterator and {@code true} is
* returned, {@code false} otherwise. If the iterator does not support
* removing elements, an {@code UnsupportedOperationException} is thrown.
*
* @param object the object to remove.
* @return {@code true} if this {@code Collection} is modified,
* {@code false} otherwise.
* @throws UnsupportedOperationException if removing from this
* {@code Collection} is not supported.
* @throws ClassCastException if the object passed is not of the correct
* type.
* @throws NullPointerException if {@code object} is {@code null} and this
* {@code Collection} doesn't support {@code null} elements.
*/
@Override
public boolean remove(Object object) {
Iterator<?> it = iterator();
if (object != null) {
while (it.hasNext()) {
if (object.equals(it.next())) {
it.remove();
return true;
}
}
} else {
while (it.hasNext()) {
if (it.next() == null) {
it.remove();
return true;
}
}
}
return false;
}
/**
* Removes all occurrences in this {@code Collection} of each object in
* the specified {@code Collection} (optional). After this method returns
* none of the elements in the passed {@code Collection} can be found in
* this {@code Collection} anymore.
* <p>
* This implementation iterates over this {@code Collection} and tests for
* each element {@code e} returned by the iterator, whether it is
* contained in the specified {@code Collection}. If this test is
* positive, then the {@code remove} method is called on the iterator. If
* the iterator does not support removing elements, an
* {@code UnsupportedOperationException} is thrown.
*
* @param collection the collection of objects to remove.
* @return {@code true} if this {@code Collection} is modified,
* {@code false} otherwise.
* @throws UnsupportedOperationException if removing from this
* {@code Collection} is not supported.
* @throws ClassCastException if one or more elements of
* {@code collection} isn't of the correct type.
* @throws NullPointerException if {@code collection} contains at least
* one {@code null} element and this {@code Collection}
* doesn't support {@code null} elements.
* @throws NullPointerException if {@code collection} is {@code null}.
*/
@Override
public boolean removeAll(Collection<?> collection) {
boolean result = false;
Iterator<?> it = iterator();
while (it.hasNext()) {
if (collection.contains(it.next())) {
it.remove();
result = true;
}
}
return result;
}
/**
* Removes all objects from this {@code Collection} that are not also
* found in the {@code Collection} passed (optional). After this method
* returns this {@code Collection} will only contain elements that also
* can be found in the {@code Collection} passed to this method.
* <p>
* This implementation iterates over this {@code Collection} and tests for
* each element {@code e} returned by the iterator, whether it is
* contained in the specified {@code Collection}. If this test is
* negative, then the {@code remove} method is called on the iterator. If
* the iterator does not support removing elements, an
* {@code UnsupportedOperationException} is thrown.
*
* @param collection the collection of objects to retain.
* @return {@code true} if this {@code Collection} is modified,
* {@code false} otherwise.
* @throws UnsupportedOperationException if removing from this
* {@code Collection} is not supported.
* @throws ClassCastException if one or more elements of
* {@code collection} isn't of the correct type.
* @throws NullPointerException if {@code collection} contains at least
* one {@code null} element and this {@code Collection}
* doesn't support {@code null} elements.
* @throws NullPointerException if {@code collection} is {@code null}.
*/
@Override
public boolean retainAll(Collection<?> collection) {
boolean result = false;
Iterator<?> it = iterator();
while (it.hasNext()) {
if (!collection.contains(it.next())) {
it.remove();
result = true;
}
}
return result;
}
/**
* Returns a count of how many objects this {@code Collection} contains.
* <p>
* In this class this method is declared abstract and has to be
* implemented by concrete {@code Collection} implementations.
*
* @return how many objects this {@code Collection} contains, or
* {@code Integer.MAX_VALUE} if there are more than
* {@code Integer.MAX_VALUE} elements in this {@code Collection}.
*/
@Override
public abstract int size();
@Override
public Object[] toArray() {
int size = size(), index = 0;
Iterator<?> it = iterator();
Object[] array = new Object[size];
while (index < size) {
array[index++] = it.next();
}
return array;
}
@Override
@SuppressWarnings("unchecked")
public <T> T[] toArray(T[] contents) {
int size = size(), index = 0;
if (size > contents.length) {
Class<?> ct = contents.getClass().getComponentType();
contents = (T[]) Array.newInstance(ct, size);
}
for (E entry : this) {
contents[index++] = (T) entry;
}
if (index < contents.length) {
contents[index] = null;
}
return contents;
}
/**
* Returns the string representation of this {@code Collection}. The
* presentation has a specific format. It is enclosed by square brackets
* ("[]"). Elements are separated by ', ' (comma and space).
*
* @return the string representation of this {@code Collection}.
*/
@Override
public String toString() {
if (isEmpty()) {
return "[]";
}
StringBuilder buffer = new StringBuilder(size() * 16);
buffer.append('[');
Iterator<?> it = iterator();
while (it.hasNext()) {
Object next = it.next();
if (next != this) {
buffer.append(next);
} else {
buffer.append("(this Collection)");
}
if (it.hasNext()) {
buffer.append(", ");
}
}
buffer.append(']');
return buffer.toString();
}
}