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

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

//
// $Log: Set.c,v $
// Revision 1.8.1.2  1994/12/08  14:43:38  thoth
// Comparison rework to handle more computable cases.
//
// Revision 1.8.1.1  1994/10/12  17:20:06  thoth
// Added ClosureSets.
// Removed the binary operations to let the operations table work.
//
// Revision 1.8  1994/10/04  05:38:18  gmt
// Addes some "return 0"'s for those compilers that cannot deal with
// volatile functions.
//
// Revision 1.7  1994/10/03  19:38:09  thoth
// Get rid of redundant scalar-set operations in preparation for operator
// table.
//
// Revision 1.6  1994/10/03  17:48:35  thoth
// Added predicate sets.
//
// Revision 1.5  1994/09/29  15:46:14  gmt
// Put wrapper IA_NO_VOLATILE_FUNCTIONS ifdef blocks where appropriate.
// Also commented out the slack function at the end of the file.
//
// Revision 1.4  1994/09/28  19:43:07  gmt
// SC++ doesn't deal with volatile correctly. . .
//
// Revision 1.4  1994/09/27  03:36:13  gmt
// The "not yet implemented" cases for some of the set operations
// did not return an IA_Set, and the Mac compiler didn't like it, so. . .
//
// Revision 1.3  1994/09/26  21:44:20  gmt
// Changed IA::LatticeRelation to IA_LatticeRelation so that the
// Symantec compiler will like it.
//
// Revision 1.2  1994/04/26  18:08:17  thoth
// Added compare function between Sets.
//
// Revision 1.1  1994/03/21  23:06:53  thoth
// Initial revision
//

#define SUPPRESS_INCLUDE
#include "Set.h"
#include "SetIter.h"
#include "ValueSet.h"
#include "LazySet.h"
#include "ClosureSet.h"

template <class T>
void IA_Set<T>::set_and_reference(IA_BaseSet<T> *p)
{
    bsp = p;
    p->incr_ref();
}

template <class T>
void IA_Set<T>::disassociate()
{
    if (bsp->decr_ref()<=0) {
	delete bsp;
    }
    bsp=0;
}

template <class T>
IA_Set<T>::IA_Set() {
    set_and_reference(new IA_ValueSet<T>);
}

template <class T>
IA_Set<T>::IA_Set(const IA_Set<T>& s) {
    set_and_reference(s.bsp);
}

template <class T>
IA_Set<T>::~IA_Set() {
    disassociate();
}

template <class T>
IA_Set<T> & IA_Set<T>::operator=(const IA_Set<T>& s)
{
    IA_BaseSet<T>	*temp = s.bsp;

    temp->incr_ref();

    disassociate();
    
    bsp = temp;
    return *this;
}

template <class T>
IA_Set<T>::IA_Set(T t1) {
    set_and_reference(new IA_ValueSet<T>(t1));
}

template <class T>
IA_Set<T>::IA_Set(T t1, T t2) {
    set_and_reference(new IA_ValueSet<T>(t1, t2));
}

template <class T>
IA_Set<T>::IA_Set(T t1, T t2, T t3) {
    set_and_reference(new IA_ValueSet<T>(t1, t2, t3));
}

template <class T>
IA_Set<T>::IA_Set(T t1, T t2, T t3, T t4) {
    set_and_reference(new IA_ValueSet<T>(t1, t2, t3, t4));
}

template <class T>
IA_Set<T>::IA_Set(T t1, T t2, T t3, T t4, T t5) {
    set_and_reference(new IA_ValueSet<T>(t1, t2, t3, t4, t5));
}

template <class T>
IA_Set<T>::IA_Set(const T *t, unsigned int len) {
    set_and_reference(new IA_ValueSet<T>(t, len));
}

template <class T>
IA_Set<T>::IA_Set(int (*f)(T)) {
    set_and_reference(new IA_PredicateSet_V<T>(f));
}

template <class T>
IA_Set<T>::IA_Set(int (*f)(const T&)) {
    set_and_reference(new IA_PredicateSet_CR<T>(f));
}

template <class T>
IA_Set<T>::IA_Set(const IA_ClosureSet<T> & set)
{
    set_and_reference(set.clone_self());
}

//
//

#if 0

// comparisons go here

#define STUBBY

template <class T>
int operator<(const IA_Set<T> &lhs, const IA_Set<T> &rhs)
{
#ifdef STUBBY
    if (lhs.bsp->type()==IA_ValueSet<T>::s_type() &&
	rhs.bsp->type()==IA_ValueSet<T>::s_type()) {
	IA_ValueSet<T>	*lhs_ = (IA_ValueSet<T>*)lhs.bsp;
	IA_ValueSet<T>	*rhs_ = (IA_ValueSet<T>*)rhs.bsp;
	return *lhs_ < *rhs_;
    } else {
	IA::not_yet_implemented(__FILE__,__LINE__);
#ifdef IA_NO_VOLATILE_FUNCTIONS
	return 0;
#endif
    }
#endif
}

template <class T>
int operator<=(const IA_Set<T> &lhs, const IA_Set<T> &rhs)
{
#ifdef STUBBY
    if (lhs.bsp->type()==IA_ValueSet<T>::s_type() &&
	rhs.bsp->type()==IA_ValueSet<T>::s_type()) {
	IA_ValueSet<T>	*lhs_ = (IA_ValueSet<T>*)lhs.bsp;
	IA_ValueSet<T>	*rhs_ = (IA_ValueSet<T>*)rhs.bsp;
	return *lhs_ <= *rhs_;
    } else {
	IA::not_yet_implemented(__FILE__,__LINE__);
#ifdef IA_NO_VOLATILE_FUNCTIONS
	return 0;
#endif
    }
#endif
}

template <class T>
int operator==(const IA_Set<T> &lhs, const IA_Set<T> &rhs)
{
#ifdef STUBBY
    if (lhs.bsp->type()==IA_ValueSet<T>::s_type() &&
	rhs.bsp->type()==IA_ValueSet<T>::s_type()) {
	IA_ValueSet<T>	*lhs_ = (IA_ValueSet<T>*)lhs.bsp;
	IA_ValueSet<T>	*rhs_ = (IA_ValueSet<T>*)rhs.bsp;
	return *lhs_ == *rhs_;
    } else {
	IA::not_yet_implemented(__FILE__,__LINE__);
#ifdef IA_NO_VOLATILE_FUNCTIONS
	return 0;
#endif
    }
#endif
}

#if 0
template <class T>
int operator>=(const IA_Set<T> &lhs, const IA_Set<T> &rhs)
{
#ifdef STUBBY
    if (bsp->type()==IA_ValueSet<T>::s_type() &&
	rhs.bsp->type()==IA_ValueSet<T>::s_type()) {
	IA_ValueSet<T>	*lhs_ = (IA_ValueSet<T>*)bsp;
	IA_ValueSet<T>	*rhs_ = (IA_ValueSet<T>*)rhs.bsp;
	return *lhs_ >= *rhs_;
    } else {
	IA::not_yet_implemented(__FILE__,__LINE__);
#ifdef IA_NO_VOLATILE_FUNCTIONS
	return 0;
#endif
    }
#endif
}

template <class T>
int operator>=(const IA_Set<T> &lhs, const IA_Set<T> &rhs)
{
#ifdef STUBBY
    if (bsp->type()==IA_ValueSet<T>::s_type() &&
	rhs.bsp->type()==IA_ValueSet<T>::s_type()) {
	IA_ValueSet<T>	*lhs_ = (IA_ValueSet<T>*)bsp;
	IA_ValueSet<T>	*rhs_ = (IA_ValueSet<T>*)rhs.bsp;
	return *lhs_ >= *rhs_;
    } else {
	IA::not_yet_implemented(__FILE__,__LINE__);
#ifdef IA_NO_VOLATILE_FUNCTIONS
	return 0;
#endif
    }
#endif
}

template <class T>
int disjoint(const IA_Set<T> &lhs, const IA_Set<T> &rhs)
{
#ifdef STUBBY
    if (bsp->type()==IA_ValueSet<T>::s_type() &&
	rhs.bsp->type()==IA_ValueSet<T>::s_type()) {
	IA_ValueSet<T>	*lhs_ = (IA_ValueSet<T>*)bsp;
	IA_ValueSet<T>	*rhs_ = (IA_ValueSet<T>*)rhs.bsp;
	return disjoint(*lhs_,*rhs_);
    } else {
	IA::not_yet_implemented(__FILE__,__LINE__);
#ifdef IA_NO_VOLATILE_FUNCTIONS
	return 0;
#endif
    }
#endif
}
#endif

#endif

template <class T>
#ifdef IA_NO_NESTED_ENUMS
IA_LatticeRelation
#else
IA::LatticeRelation
#endif
compare(const IA_Set<T>&lhs,
	const IA_Set<T>&rhs)
{
   if (lhs.extensive()) {
       if (rhs.extensive()) {
	   if (lhs.bsp->type()==IA_ValueSet<T>::s_type() &&
	       rhs.bsp->type()==IA_ValueSet<T>::s_type()) {
	       IA_ValueSet<T>	*lhs_ = (IA_ValueSet<T>*)lhs.bsp;
	       IA_ValueSet<T>	*rhs_ = (IA_ValueSet<T>*)rhs.bsp;
	       return compare(*lhs_,*rhs_);
	   } else {
	       IA_SetIter<T>	liter(lhs), riter(rhs);
	       T	lv, rv;
	       IA::LatticeRelation	rval=IA::EQUAL;
	       if (!liter.done() && !riter.done()) {
		   liter.curr(lv);
		   riter.curr(rv);
		   while (!liter.done() && !riter.done()) {
		       int cmp = IA_ValueSet<T>::value_type_compare(&lv, &rv);
		       if (cmp<0) {
			   if (rval==IA::P_SUBSET)
			       return IA::NO_REL;
			   liter();
			   liter.curr(lv);
			   rval = IA::P_SUPERSET;
		       } else if (cmp==0) {
			   liter();
			   liter.curr(lv);
			   riter();
			   riter.curr(rv);
		       } else /* cmp>0 */ {
			   if (rval==IA::P_SUPERSET)
			       return IA::NO_REL;
			   riter();
			   riter.curr(rv);
			   rval = IA::P_SUBSET;
		       }
		   }
	       }
	       if (!liter.done()) {
		   if (rval==IA::P_SUBSET)
		       return IA::NO_REL;
		   return IA::P_SUPERSET;
	       } else if (!riter.done()) {
		   if (rval==IA::P_SUPERSET)
		       return IA::NO_REL;
		   return IA::P_SUBSET;
	       } else {
		   return rval;
	       }
	       
	   }
       } else /* !rhs.extensive() */ {
	   IA_SetIter<T>	liter(lhs);
	   int	contained=1;
	   T	val;
	   while (liter(val)) {
	       if (!rhs.contains(val)) {
		   contained=0;
		   break;
	       }
	   }
	   return contained ? IA::MP_SUBSET : IA::UNKNOWN;
       }
   } else /* ! lhs.extensive() */ {
       if (rhs.extensive()) {
	   IA_SetIter<T>	riter(rhs);
	   int	contained=1;
	   T	val;
	   while (riter(val)) {
	       if (!lhs.contains(val)) {
		   contained=0;
		   break;
	       }
	   }
	   return contained ? IA::MP_SUPERSET : IA::UNKNOWN;
       } else /* !rhs.extensive() */ {
	   return IA::UNKNOWN;
       }
   }

}

//
//
//
