/*
 * Jakelib2 - General purpose C++ library
 * Copyright (C) 2001 Florian Wolff  (florian@donuz.de)
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 * $Id: Set.h,v 1.6 2003/03/05 11:01:58 florian Exp $
 */

#ifndef INCLUDE_JAKELIB2_UTIL_SET_H
# define INCLUDE_JAKELIB2_UTIL_SET_H
#include "Collection.h"

namespace jakelib {
  namespace util {
    class Iterator;

    /**
     * @brief A collection that contains no duplicates. In other words, for two set
     * elements e1 and e2, <code>e1.equals(e2)</code> returns false. There
     * are additional stipulations on <code>add</code>, <code>equals</code>
     * and <code>hashCode</code>, as well as the requirements that constructors
     * do not permit duplicate elements. The Set interface is incompatible with
     * List; you cannot implement both simultaneously.
     *
     * Note: Be careful about using mutable objects in sets.  In particular,
     * if a mutable object changes to become equal to another set element, you
     * have violated the contract.  As a special case of this, a Set is not
     * allowed to be an element of itself, without risking undefined behavior.
     *
     * @class Set
     * @version $Id: Set.h,v 1.6 2003/03/05 11:01:58 florian Exp $
     * @author Eric Blake <ebb9@email.byu.edu>
     * @author Florian 'Overflo' Wolff (florian@donuz.de)
     */
    class Set : public Collection
      {
      public:

	/**
	 * @brief Adds the specified element to the set if it is not already present
	 * (optional operation). In particular, the comparison algorithm is
	 * <code>o == null ? e == null : o.equals(e)</code>. Sets need not permit
	 * all values, and may document what exceptions will be thrown if
	 * a value is not permitted.
	 *
	 * @param o the object to add
	 * @return \c true if the object was not previously in the set
	 * @throws UnsupportedOperationException if this operation is not allowed
	 * @throws ClassCastException if the class of o prevents it from being added
	 * @throws IllegalArgumentException if some aspect of o prevents it from
	 *         being added
	 * @throws NullPointerException if null is not permitted in this set
	 */
	virtual jboolean add(jakelib::lang::Object* o) = 0;

	/**
	 * @brief Adds all of the elements of the given collection to this set (optional
	 * operation). If the argument is also a Set, this returns the mathematical
	 * <i>union</i> of the two. The behavior is unspecified if the set is
	 * modified while this is taking place.
	 *
	 * @param c the collection to add
	 * @return \c true if the set changed as a result
	 * @throws UnsupportedOperationException if this operation is not allowed
	 * @throws ClassCastException if the class of an element prevents it from
	 *         being added
	 * @throws IllegalArgumentException if something about an element prevents
	 *         it from being added
	 * @throws NullPointerException if null is not permitted in this set, or
	 *         if the argument c is null
	 * @see #add(Object)
	 */
	virtual jboolean addAll(Collection* c) = 0;

	/**
	 * @brief Removes all elements from this set (optional operation). This set will
	 * be empty afterwords, unless an exception occurs.
	 *
	 * @throws UnsupportedOperationException if this operation is not allowed
	 */
	virtual void clear() = 0;

	/**
	 * @brief Returns true if the set contains the specified element. In other words,
	 * this looks for <code>o == null ? e == null : o.equals(e)</code>.
	 *
	 * @param o the object to look for
	 * @return \c true if it is found in the set
	 */
	virtual jboolean contains(jakelib::lang::Object* o) = 0;

	/**
	 * @brief Returns true if this set contains all elements in the specified
	 * collection. If the argument is also a set, this is the <i>subset</i>
	 * relationship.
	 *
	 * @param c the collection to check membership in
	 * @return \c true if all elements in this set are in c
	 * @throws NullPointerException if c is null
	 * @see #contains(Object)
	 */
	virtual jboolean containsAll(Collection* c) = 0;

	/**
	 * @brief Compares the specified object to this for equality. For sets, the object
	 * must be a set, the two must have the same size, and every element in
	 * one must be in the other.
	 *
	 * @param o the object to compare to
	 * @return \c true if it is an equal set
	 */
	virtual jboolean equals(jakelib::lang::Object* o) = 0;

	/**
	 * @brief Returns the hash code for this set. In order to satisfy the contract of
	 * equals, this is the sum of the hashcode of all elements in the set.
	 *
	 * @return the sum of the hashcodes of all set elements
	 */
	virtual int hashCode() = 0;

	/**
	 * @brief Returns true if the set contains no elements.
	 *
	 * @return \c true if the set is empty
	 */
	virtual jboolean isEmpty() = 0;

	/**
	 * @brief Returns an iterator over the set.  The iterator has no specific order,
	 * unless further specified.
	 *
	 * @return a set iterator
	 */
	virtual Iterator* iterator() = 0;

	/**
	 * @brief Removes the specified element from this set (optional operation). If
	 * an element e exists, <code>o == null ? e == null : o.equals(e)</code>,
	 * it is removed from the set.
	 *
	 * @param o the object to remove
	 * @return \c true if the set changed (an object was removed)
	 * @throws UnsupportedOperationException if this operation is not allowed
	 */
	virtual jboolean remove(jakelib::lang::Object* o) = 0;

	/**
	 * @brief Removes from this set all elements contained in the specified collection
	 * (optional operation). If the argument is a set, this returns the
	 * <i>asymmetric set difference</i> of the two sets.
	 *
	 * @param c the collection to remove from this set
	 * @return \c true if this set changed as a result
	 * @throws UnsupportedOperationException if this operation is not allowed
	 * @throws NullPointerException if c is \c null
	 * @see #remove(Object)
	 */
	virtual jboolean removeAll(Collection* c) = 0;

	/**
	 * @brief Retains only the elements in this set that are also in the specified
	 * collection (optional operation). If the argument is also a set, this
	 * performs the <i>intersection</i> of the two sets.
	 *
	 * @param c the collection to keep
	 * @return \c true if this set was modified
	 * @throws UnsupportedOperationException if this operation is not allowed
	 * @throws NullPointerException if c is \c null
	 * @see #remove(Object)
	 */
	virtual jboolean retainAll(Collection* c) = 0;

	/**
	 * @brief Returns the number of elements in the set. If there are more
	 * than Integer.MAX_VALUE mappings, return Integer.MAX_VALUE. This is
	 * the <i>cardinality</i> of the set.
	 *
	 * @return the number of elements
	 */
	virtual int size() = 0;

	/**
	 * @brief Returns an array containing the elements of this set. If the set
	 * makes a guarantee about iteration order, the array has the same
	 * order. The array is distinct from the set; modifying one does not
	 * affect the other.
	 *
	 * @return an array of this set's elements
	 * @see #toArray(Object[])
	 */
	virtual jakelib::lang::Objects* toArray() = 0;

	/**
	 * @brief Returns an array containing the elements of this set, of the same runtime
	 * type of the argument. If the given set is large enough, it is reused,
	 * and null is inserted in the first unused slot. Otherwise, reflection
	 * is used to build a new array. If the set makes a guarantee about iteration
	 * order, the array has the same order. The array is distinct from the set;
	 * modifying one does not affect the other.
	 *
	 * @param a the array to determine the return type; if it is big enough
	 *        it is used and returned
	 * @return an array holding the elements of the set
	 * @throws ArrayStoreException if the runtime type of a is not a supertype
	 *         of all elements in the set
	 * @throws NullPointerException if a is null
	 * @see #toArray()
	 */
	virtual jakelib::lang::Objects* toArray(jakelib::lang::Objects* a) = 0;

        JAKELIB_DECLARE_INTERFACE(Set);
      };
  }
}
#endif

