// Emacs -*- C++ -*-

//
//	Copyright 1993, Center for Computer Vision and Visualization,
//	University of Florida.  All rights reserved.
//

/* $RCSfile: ValueSet.h,v $
   $Log: ValueSet.h,v $
 * Revision 1.28.1.1  1994/12/08  14:48:55  thoth
 * new extensive() method.
 * Conversion to throws of class objects.
 * choice is now random.
 *
 * Revision 1.28  1994/10/06  15:51:07  fjsoria
 * removed value-range, g++ gets buggy
 *
 * Revision 1.27  1994/10/03  17:54:28  thoth
 * Added iterators.
 * changed ValueType to T.
 * removed the binary ops between Sets and scalars since they were
 * inaccessible to users and unused by the IA_Set class.
 *
 * Revision 1.26  1994/09/27  02:57:24  gmt
 * Hack to fix screwed up complex.h .
 *
 * Revision 1.25  1994/07/08  16:12:39  thoth
 * Fix segvs caused by unexepected returns from ia_throw.
 *
 * Revision 1.24  1994/03/14  15:35:40  thoth
 * ValueSet is now derived from BaseSet.
 *
 * Revision 1.23  1994/01/31  16:34:30  thoth
 * added the ability to reset a ValueSetIter.
 *
 * Revision 1.22  1993/11/17  17:57:51  thoth
 * added choice() member to valueset.
 *
 * Revision 1.21  1993/06/10  17:09:49  thoth
 * Fix array constructor.
 *
 * Revision 1.20  93/05/26  16:32:07  thoth
 * Copyright Notices
 * 
 * Revision 1.19  93/02/20  15:23:13  thoth
 * The LatticeRelation that was causing a compiler bug is now
 * used from IA instead of IA_ValueSet<T>.
 * 
 * Revision 1.18  93/02/08  19:57:51  thoth
 * added output method for testing.
 * added workaround for 3.0.2 bug.
 * 
 * Revision 1.17  92/12/14  16:18:10  jm
 * Renamed class ValueSet to IA_ValueSet
 * 
 * Revision 1.16  92/10/22  14:05:13  jm
 * *** empty log message ***
 * 
 * Revision 1.15  92/09/29  15:26:54  jm
 * *** empty log message ***
 * 
 * Revision 1.14  92/09/25  14:47:01  jm
 * *** empty log message ***
 * 
 * Revision 1.13  92/09/16  17:06:33  jm
 * added spec for value_range function
 * 
 * Revision 1.12  92/09/16  16:36:33  jm
 * Added commnet to compare function
 * changed NULL to 0.
 * 
 * Revision 1.11  92/09/16  14:38:59  jm
 * Added the class ValueSetIter to provide an iterator for ValueSet
 * Rearranged the different operators for esthetic purposes
 * Added keyword 'const' to all member operators
 * Added LatticeRelation enum type, used by the compare function
 * Added declaration for compare function
 * added operators '>' and '<' for proper superset and proper subset
 * added keyword 'const' to private function count_dup
 * Moved function value_range outside the class as an independent function
 *   that takes only integer parameters
 * 
 * Revision 1.10  92/09/08  14:37:04  jm
 * removed code that had been commented out before.
 * 
 * Revision 1.9  92/09/08  14:30:47  jm
 * the operators have been redefined to be class members in the case of
 * valueset op element, and valueset op valueset. The combination 
 * element op valueset remains as a friend.
 * the function make_set does not take parameters anymore. It operates on
 * the internal value_array and size.
 * function value_range has been changed from class member to independent. It
 * will only work with integer arguments.
 * predicate operators now return an int instead of a char, in order to be
 * able to print the result.
 * 
Revision 1.1  92/09/01  14:02:25  jm
Initial revision

*/

#ifndef ValueSet_h_
#define ValueSet_h_

#ifndef __SC__
#include <search.h>
#endif

#include <iostream.h>
#include "ia.h"
#include "BaseSet.h"
#include "set_errors.h"

// This class is created to provide a "default" comparator function
// for ValueType. If the user of ValueSet does not like this comparator,
// a new one can be provided.
// Notice the use of void parameters; this is because the return type and
// the argument types must match exactly to the specification needed by
// the "bsearch" and "qsort" routines used in the "contains" and "make_set"
// functions, respectively.

template <class T>
class IA_ValueSetComparator {
public:
    static int value_type_compare(const void *, const void *); 
};

template <class T> class IA_ValueSetIter;
template <class T> class IA_ValueSet;

template <class T> ostream& operator<< (ostream&, const IA_ValueSet<T>&);

template <class T>
class IA_ValueSet: public IA_BaseSet<T>,
	public IA_ValueSetComparator<T> {
  private:
    unsigned int size;
    T *value_array;

    static char dummy;
  public:
    IA_ValueSet() {size = 0; value_array = 0;}
    IA_ValueSet(const IA_ValueSet&);
    IA_ValueSet& operator= (const IA_ValueSet&);
    ~IA_ValueSet() {if (this->value_array != 0) delete [] value_array;}
    
    IA_ValueSet(T);
    IA_ValueSet(T, T);
    IA_ValueSet(T, T, T);
    IA_ValueSet(T, T, T, T);
    IA_ValueSet(T, T, T, T, T);
    IA_ValueSet( const T*, unsigned int);

    static IA::Type s_type() { return &dummy; }
    IA::Type type() const { return &dummy; }

    int extensive() const { return 1; }

    // card: cardinality, number of elements in the set
    unsigned int card() const {return this->size;}
    
    // contains: predicate for testing membership of an element in a set
    
    int contains(T) const;
    
    // min: minimum element of the set
    
    T min() const {
	if (this->size == 0) {
	    ia_throw(Set_Empty_Exception(__FILE__, __LINE__));    
	    return T();
	} else 
	    return this->value_array[0];
    }
    
    // max: maximum element of the set
    
    T max() const {
	if (this->size == 0)  {
	    ia_throw(Set_Empty_Exception(__FILE__, __LINE__));    
	    return T();
	} else   
	    return this->value_array[this->size-1];
    }

    // choice: some element from the set, we don't care which one
    T choice() const {
	if (this->size == 0)  {
	    ia_throw(Set_Empty_Exception(__FILE__, __LINE__));    
	    return T();
	} else   
	    return value_array[IA::rand_mod(size)];
    }
    
    // empty: predicate for testing emptiness of a set 
    
    int empty() const {return (this->size == 0);}

    IA_BaseSetIter<T> *iterator() const;
    
    IA_ValueSet<T> operator|  (const IA_ValueSet<T>&) const;
    IA_ValueSet<T> operator&  (const IA_ValueSet<T>&) const;
    IA_ValueSet<T> operator/  (const IA_ValueSet<T>&) const;
    IA_ValueSet<T> operator^  (const IA_ValueSet<T>&) const;

#if 0
    IA_ValueSet<T> operator|  (const T&) const;
    IA_ValueSet<T> operator&  (const T&) const;
    IA_ValueSet<T> operator/  (const T&) const;
    IA_ValueSet<T> operator^  (const T&) const;
    
    friend IA_ValueSet<T>	
    operator|  (const T&, const IA_ValueSet<T>&);
    friend IA_ValueSet<T>	
    operator&  (const T&, const IA_ValueSet<T>&);
    friend IA_ValueSet<T>	
    operator/  (const T&, const IA_ValueSet<T>&);
    friend IA_ValueSet<T>	
    operator^  (const T&, const IA_ValueSet<T>&);
#endif

    // The range of return values for this compare function does not include
    // all the enumerated values.
    
#if 0
    int operator<= (const IA_ValueSet<T>&) const;
    int operator>= (const IA_ValueSet<T>&) const;
    int operator<  (const IA_ValueSet<T>&) const;
    int operator>  (const IA_ValueSet<T>&) const;
    int	operator== (const IA_ValueSet<T>&) const;
    int	operator!= (const IA_ValueSet<T>&) const;

    int operator<= (const T&) const;
    int operator>= (const T&) const;
    int operator<  (const T&) const;
    int operator>  (const T&) const;
    int	operator== (const T&) const;
    int operator!= (const T&) const;
    
    friend int operator<= (const T&, const IA_ValueSet<T>&);
    friend int operator>= (const T&, const IA_ValueSet<T>&);
    friend int operator<  (const T&, const IA_ValueSet<T>&);
    friend int operator>  (const T&, const IA_ValueSet<T>&);
    friend int operator== (const T&, const IA_ValueSet<T>&);
    friend int operator!= (const T&, const IA_ValueSet<T>&);
#endif

    friend IA::LatticeRelation
    compare(const IA_ValueSet<T>&,
	    const IA_ValueSet<T>&);
   
#ifndef WORKAROUND_CFRONT_FRIEND_MANGLING_BUG
    friend ostream& operator<< (ostream&, const IA_ValueSet<T>&);
#endif
    friend class IA_ValueSetIter<T>;
    
  private:
#if 0
    // Set_Nth procedure, note:  indices start at 0
    void set_nth (unsigned int index, T value) {
	if (index >= this->size) {
	    ia_throw(IA::POINT_INDEX_MISMATCH, __FILE__, __LINE__);
	} else
	    this->value_array[index] = value;
	// problem? need promotion to proper type?
    }
#endif
    int count_dup() const;
    void make_set();
    void remove_dup();
    
};

#if 0
template <class T>
class IA_ValueSetIter {
    const IA_ValueSet<T>* vsp;
    int i;
public:
    IA_ValueSetIter(const IA_ValueSet<T> &vs) { vsp = &vs; i = 0;}
    int operator()(T& vt) {
	int ret = 1;
	if (i < vsp->size) vt = vsp->value_array[i++];
	else ret = 0;
	return ret;
    }
    void reset() {
	i=0;
    }
};
#endif



#endif
