package java.util;

import ej.annotation.Nullable;

/**
 * A collection that contains no duplicate elements. More formally, sets contain no pair of elements
 * <code>e1</code> and <code>e2</code> such that <code>e1.equals(e2)</code>, and at most one null
 * element. As implied by its name, this interface models the mathematical <i>set</i> abstraction.
 *
 * <p>
 * The <code>Set</code> interface places additional stipulations, beyond those inherited from the
 * <code>Collection</code> interface, on the contracts of all constructors and on the contracts of the
 * <code>add</code>, <code>equals</code> and <code>hashCode</code> methods. Declarations for other inherited
 * methods are also included here for convenience. (The specifications accompanying these
 * declarations have been tailored to the <code>Set</code> interface, but they do not contain any
 * additional stipulations.)
 *
 * <p>
 * The additional stipulation on constructors is, not surprisingly, that all constructors must
 * create a set that contains no duplicate elements (as defined above).
 *
 * <p>
 * Note: Great care must be exercised if mutable objects are used as set elements. The behavior of a
 * set is not specified if the value of an object is changed in a manner that affects
 * <code>equals</code> comparisons while the object is an element in the set. A special case of this
 * prohibition is that it is not permissible for a set to contain itself as an element.
 *
 * <p>
 * Some set implementations have restrictions on the elements that they may contain. For example,
 * some implementations prohibit null elements, and some have restrictions on the types of their
 * elements. Attempting to add an ineligible element throws an unchecked exception, typically
 * <code>NullPointerException</code> or <code>ClassCastException</code>. Attempting to query the presence of
 * an ineligible element may throw an exception, or it may simply return false; some implementations
 * will exhibit the former behavior and some will exhibit the latter. More generally, attempting an
 * operation on an ineligible element whose completion would not result in the insertion of an
 * ineligible element into the set may throw an exception or it may succeed, at the option of the
 * implementation. Such exceptions are marked as "optional" in the specification for this interface.
 *
 * <p>
 * This interface is a member of the Java Collections Framework
 *
 * @param <E>
 *        the type of elements maintained by this set
 *
 * @see Collection
 * @see List
 * @see AbstractSet
 */

public interface Set<E> extends Collection<E> {
	/**
	 * Adds the specified element to this set if it is not already present (optional operation). More
	 * formally, adds the specified element <code>e</code> to this set if the set contains no element
	 * <code>e2</code> such that <code>(e==null&nbsp;?&nbsp;e2==null&nbsp;:&nbsp;e.equals(e2))</code>. If this
	 * set already contains the element, the call leaves the set unchanged and returns <code>false</code>.
	 * In combination with the restriction on constructors, this ensures that sets never contain
	 * duplicate elements.
	 *
	 * <p>
	 * The stipulation above does not imply that sets must accept all elements; sets may refuse to add
	 * any particular element, including <code>null</code>, and throw an exception, as described in the
	 * specification for {@link Collection#add Collection.add}. Individual set implementations should
	 * clearly document any restrictions on the elements that they may contain.
	 *
	 * @param e
	 *        element to be added to this set
	 * @return <code>true</code> if this set did not already contain the specified element
	 * @throws UnsupportedOperationException
	 *         if the <code>add</code> operation is not supported by this set
	 * @throws ClassCastException
	 *         if the class of the specified element prevents it from being added to this set
	 * @throws NullPointerException
	 *         if the specified element is null and this set does not permit null elements
	 * @throws IllegalArgumentException
	 *         if some property of the specified element prevents it from being added to this set
	 */
	@Override
	boolean add(E e);

	/**
	 * Adds all of the elements in the specified collection to this set if they're not already present
	 * (optional operation). If the specified collection is also a set, the <code>addAll</code> operation
	 * effectively modifies this set so that its value is the <i>union</i> of the two sets. The behavior
	 * of this operation is undefined if the specified collection is modified while the operation is in
	 * progress.
	 *
	 * @param c
	 *        collection containing elements to be added to this set
	 * @return <code>true</code> if this set changed as a result of the call
	 *
	 * @throws UnsupportedOperationException
	 *         if the <code>addAll</code> operation is not supported by this set
	 * @throws ClassCastException
	 *         if the class of an element of the specified collection prevents it from being added to
	 *         this set
	 * @throws NullPointerException
	 *         if the specified collection contains one or more null elements and this set does not
	 *         permit null elements, or if the specified collection is null
	 * @throws IllegalArgumentException
	 *         if some property of an element of the specified collection prevents it from being added
	 *         to this set
	 * @see #add(Object)
	 */
	@Override
	boolean addAll(Collection<? extends E> c);

	/**
	 * Removes all of the elements from this set (optional operation). The set will be empty after this
	 * call returns.
	 *
	 * @throws UnsupportedOperationException
	 *         if the <code>clear</code> method is not supported by this set
	 */
	@Override
	void clear();

	/**
	 * Returns <code>true</code> if this set contains the specified element. More formally, returns
	 * <code>true</code> if and only if this set contains an element <code>e</code> such that
	 * <code>(o==null&nbsp;?&nbsp;e==null&nbsp;:&nbsp;o.equals(e))</code>.
	 *
	 * @param o
	 *        element whose presence in this set is to be tested
	 * @return <code>true</code> if this set contains the specified element
	 * @throws ClassCastException
	 *         if the type of the specified element is incompatible with this set
	 *         (<a href="Collection.html#optional-restrictions">optional</a>)
	 * @throws NullPointerException
	 *         if the specified element is null and this set does not permit null elements
	 *         (<a href="Collection.html#optional-restrictions">optional</a>)
	 */
	@Override
	boolean contains(Object o);

	/**
	 * Returns <code>true</code> if this set contains all of the elements of the specified collection. If
	 * the specified collection is also a set, this method returns <code>true</code> if it is a
	 * <i>subset</i> of this set.
	 *
	 * @param c
	 *        collection to be checked for containment in this set
	 * @return <code>true</code> if this set contains all of the elements of the specified collection
	 * @throws ClassCastException
	 *         if the types of one or more elements in the specified collection are incompatible with
	 *         this set (<a href="Collection.html#optional-restrictions">optional</a>)
	 * @throws NullPointerException
	 *         if the specified collection contains one or more null elements and this set does not
	 *         permit null elements (<a href="Collection.html#optional-restrictions">optional</a>), or
	 *         if the specified collection is null
	 * @see #contains(Object)
	 */
	@Override
	boolean containsAll(Collection<?> c);

	/**
	 * Compares the specified object with this set for equality. Returns <code>true</code> if the specified
	 * object is also a set, the two sets have the same size, and every member of the specified set is
	 * contained in this set (or equivalently, every member of this set is contained in the specified
	 * set). This definition ensures that the equals method works properly across different
	 * implementations of the set interface.
	 *
	 * @param o
	 *        object to be compared for equality with this set
	 * @return <code>true</code> if the specified object is equal to this set
	 */
	@Override
	boolean equals(@Nullable Object o);

	/**
	 * Returns the hash code value for this set. The hash code of a set is defined to be the sum of the
	 * hash codes of the elements in the set, where the hash code of a <code>null</code> element is defined
	 * to be zero. This ensures that <code>s1.equals(s2)</code> implies that
	 * <code>s1.hashCode()==s2.hashCode()</code> for any two sets <code>s1</code> and <code>s2</code>, as required
	 * by the general contract of {@link Object#hashCode}.
	 *
	 * @return the hash code value for this set
	 * @see Object#equals(Object)
	 * @see Set#equals(Object)
	 */
	@Override
	int hashCode();

	/**
	 * Returns <code>true</code> if this set contains no elements.
	 *
	 * @return <code>true</code> if this set contains no elements
	 */
	@Override
	boolean isEmpty();

	/**
	 * Returns an iterator over the elements in this set. The elements are returned in no particular
	 * order (unless this set is an instance of some class that provides a guarantee).
	 *
	 * @return an iterator over the elements in this set
	 */
	@Override
	Iterator<E> iterator();

	/**
	 * Removes the specified element from this set if it is present (optional operation). More formally,
	 * removes an element <code>e</code> such that
	 * <code>(o==null&nbsp;?&nbsp;e==null&nbsp;:&nbsp;o.equals(e))</code>, if this set contains such an
	 * element. Returns <code>true</code> if this set contained the element (or equivalently, if this set
	 * changed as a result of the call). (This set will not contain the element once the call returns.)
	 *
	 * @param o
	 *        object to be removed from this set, if present
	 * @return <code>true</code> if this set contained the specified element
	 * @throws ClassCastException
	 *         if the type of the specified element is incompatible with this set
	 *         (<a href="Collection.html#optional-restrictions">optional</a>)
	 * @throws NullPointerException
	 *         if the specified element is null and this set does not permit null elements
	 *         (<a href="Collection.html#optional-restrictions">optional</a>)
	 * @throws UnsupportedOperationException
	 *         if the <code>remove</code> operation is not supported by this set
	 */
	@Override
	boolean remove(Object o);

	/**
	 * Removes from this set all of its elements that are contained in the specified collection
	 * (optional operation). If the specified collection is also a set, this operation effectively
	 * modifies this set so that its value is the <i>asymmetric set difference</i> of the two sets.
	 *
	 * @param c
	 *        collection containing elements to be removed from this set
	 * @return <code>true</code> if this set changed as a result of the call
	 * @throws UnsupportedOperationException
	 *         if the <code>removeAll</code> operation is not supported by this set
	 * @throws ClassCastException
	 *         if the class of an element of this set is incompatible with the specified collection
	 *         (<a href="Collection.html#optional-restrictions">optional</a>)
	 * @throws NullPointerException
	 *         if this set contains a null element and the specified collection does not permit null
	 *         elements (<a href="Collection.html#optional-restrictions">optional</a>), or if the
	 *         specified collection is null
	 * @see #remove(Object)
	 * @see #contains(Object)
	 */
	@Override
	boolean removeAll(Collection<?> c);

	/**
	 * Retains only the elements in this set that are contained in the specified collection (optional
	 * operation). In other words, removes from this set all of its elements that are not contained in
	 * the specified collection. If the specified collection is also a set, this operation effectively
	 * modifies this set so that its value is the <i>intersection</i> of the two sets.
	 *
	 * @param c
	 *        collection containing elements to be retained in this set
	 * @return <code>true</code> if this set changed as a result of the call
	 * @throws UnsupportedOperationException
	 *         if the <code>retainAll</code> operation is not supported by this set
	 * @throws ClassCastException
	 *         if the class of an element of this set is incompatible with the specified collection
	 *         (<a href="Collection.html#optional-restrictions">optional</a>)
	 * @throws NullPointerException
	 *         if this set contains a null element and the specified collection does not permit null
	 *         elements (<a href="Collection.html#optional-restrictions">optional</a>), or if the
	 *         specified collection is null
	 * @see #remove(Object)
	 */
	@Override
	boolean retainAll(Collection<?> c);

	/**
	 * Returns the number of elements in this set (its cardinality). If this set contains more than
	 * <code>Integer.MAX_VALUE</code> elements, returns <code>Integer.MAX_VALUE</code>.
	 *
	 * @return the number of elements in this set (its cardinality)
	 */
	@Override
	int size();

	/**
	 * Returns an array containing all of the elements in this set. If this set makes any guarantees as
	 * to what order its elements are returned by its iterator, this method must return the elements in
	 * the same order.
	 *
	 * <p>
	 * The returned array will be "safe" in that no references to it are maintained by this set. (In
	 * other words, this method must allocate a new array even if this set is backed by an array). The
	 * caller is thus free to modify the returned array.
	 *
	 * <p>
	 * This method acts as bridge between array-based and collection-based APIs.
	 *
	 * @return an array containing all the elements in this set
	 */
	@Override
	Object[] toArray();

	/**
	 * Returns an array containing all of the elements in this set; the runtime type of the returned
	 * array is that of the specified array. If the set fits in the specified array, it is returned
	 * therein. Otherwise, a new array is allocated with the runtime type of the specified array and the
	 * size of this set.
	 *
	 * <p>
	 * If this set fits in the specified array with room to spare (i.e., the array has more elements
	 * than this set), the element in the array immediately following the end of the set is set to
	 * <code>null</code>. (This is useful in determining the length of this set <i>only</i> if the caller
	 * knows that this set does not contain any null elements.)
	 *
	 * <p>
	 * If this set makes any guarantees as to what order its elements are returned by its iterator, this
	 * method must return the elements in the same order.
	 *
	 * <p>
	 * Like the {@link #toArray()} method, this method acts as bridge between array-based and
	 * collection-based APIs. Further, this method allows precise control over the runtime type of the
	 * output array, and may, under certain circumstances, be used to save allocation costs.
	 *
	 * <p>
	 * Suppose <code>x</code> is a set known to contain only strings. The following code can be used to dump
	 * the set into a newly allocated array of <code>String</code>:
	 *
	 * <pre>
	 * String[] y = x.toArray(new String[0]);
	 * </pre>
	 *
	 * Note that <code>toArray(new Object[0])</code> is identical in function to <code>toArray()</code>.
	 *
	 * @param a
	 *        the array into which the elements of this set are to be stored, if it is big enough;
	 *        otherwise, a new array of the same runtime type is allocated for this purpose.
	 * @return an array containing all the elements in this set
	 * @throws ArrayStoreException
	 *         if the runtime type of the specified array is not a supertype of the runtime type of
	 *         every element in this set
	 * @throws NullPointerException
	 *         if the specified array is null
	 */
	@Override
	<T> T[] toArray(T[] a);
}
