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

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


// 
// $Log: LazySet.h,v $
// Revision 1.2  1994/10/03  19:25:53  thoth
// Fix the const ref version of the Predicate set.
//
// Revision 1.1  1994/09/20  17:30:41  thoth
// Initial revision
//
//

#ifndef LazySet_h_
#define LazySet_h_

/* This file contains the implementation of most comprehensive sets.
   A comprehensive set is a set that we can not iterate over (because
   we can not guarantee that the set is finite).  The only simple
   operation you can perform on a comprehensive set is to ask whether
   a value is a member or not. */

#include "BaseSet.h"

#include "Set.h"

// This implementation is used by the IntPointSet container when
// the programmer provides us with a predicate function that tells us
// if a point is contained in the pointset or not.
template <class T>
class IA_PredicateSet_V: public IA_BaseSet<T> {
private:
    static char type_;
protected:
    int (*pred)(T);
public:
    IA_PredicateSet_V(int(*f)(T)) :IA_BaseSet<T>() {pred=f;}

    unsigned hash_self(unsigned mod) const {
	return ((unsigned long)pred)%mod;
    }

    static IA::Type s_type() { return &type_; }
    IA::Type type() const { return &type_; }
    int contains (T ip) const { return 0!=(*pred)(ip); }
    int extensive() const { return 0; }
};

// Same as above, but the function takes a slightly different argument
// (the calling syntax is identical though).
template <class T>
class IA_PredicateSet_CR: public IA_BaseSet<T> {
private:
    static char type_;
protected:
    int (*pred)(const T &);
public:
    IA_PredicateSet_CR(int(*f)(const T &)) :IA_BaseSet<T>() {pred=f;}

    static IA::Type s_type() { return &type_; }
    IA::Type type() const { return &type_; }
    int contains (T ip) const { return 0!=(*pred)(ip); }
    int extensive() const { return 0; }
};

//
//
//

//  The following comprehensive pointsets are formed by non-simple
// operations on comprehensive pointsets.  They are termed Lazy because
// we can not compute an extensive result and we don\'t compute
// containedness unless the user asks us.

template <class T>
class IA_LazyBinarySet: public IA_BaseSet<T> {
    // this class is still abstract.  It just seemed like a good place to
    // express the commonality of all the binary Sets.
protected:
    IA_BaseSet<T>	*lhs,*rhs;
public:
    IA_LazyBinarySet(IA_BaseSet<T> * lhs_, IA_BaseSet<T> * rhs_)
	:lhs(lhs_), rhs(rhs_) {
	lhs->incr_ref();
	rhs->incr_ref();
    }

    ~IA_LazyBinarySet() {
	if (lhs->decr_ref()<=0)
	    delete lhs;
	if (rhs->decr_ref()<=0)
	    delete rhs;
    }

    int extensive() const { return 0; }

    // the following virtual functions are still abstract:
    // type, contains, output
};

// The union of a comprehensive pointset with any sort of pointset
template <class T>
class IA_LazyUnionSet: public IA_LazyBinarySet<T> {
private:
    static char type_;
public:
    IA_LazyUnionSet(IA_BaseSet<T> * l, IA_BaseSet<T> * r)
	:IA_LazyBinarySet<T>(l,r) {}
    static IA::Type s_type() { return &type_; }
    IA::Type type() const { return &type_; }
    int contains(T ip) const {
	return rhs->contains(ip) || lhs->contains(ip);
    }
};

// The intersection of two comprehensive pointsets (if one were extensive
// we could compute an extensive result industriously).
template <class T>
class IA_LazyIntersectionSet: public IA_LazyBinarySet<T> {
private:
    static char type_;
public:
    IA_LazyIntersectionSet(IA_BaseSet<T> * l, IA_BaseSet<T> * r)
	:IA_LazyBinarySet<T>(l,r) {}
    static IA::Type s_type() { return &type_; }
    IA::Type type() const { return &type_; }
    int contains(T ip) const {
	return rhs->contains(ip) && lhs->contains(ip);
    }
};

// The symmetric difference of a comprehensive pointset with any sort
// of pointset
template <class T>
class IA_LazyXORSet: public IA_LazyBinarySet<T> {
private:
    static char type_;
public:
    IA_LazyXORSet(IA_BaseSet<T> * l, IA_BaseSet<T> * r)
	:IA_LazyBinarySet<T>(l,r) {}
    static IA::Type s_type() { return &type_; }
    IA::Type type() const { return &type_; }
    int contains(T ip) const {
	return (0==rhs->contains(ip)) == (0!=lhs->contains(ip));
    }
};

// The asymmetric difference between a comprehensive pointset and any
// sort of pointset (if the first argument were extensive, we could
// compute an extensive result industriously).
template <class T>
class IA_LazyMinusSet: public IA_LazyBinarySet<T> {
private:
    static char type_;
public:
    IA_LazyMinusSet(IA_BaseSet<T> * l, IA_BaseSet<T> * r)
	:IA_LazyBinarySet<T>(l,r) {}
    static IA::Type s_type() { return &type_; }
    IA::Type type() const { return &type_; }

    int contains(T ip) const {
	return lhs->contains(ip) && !rhs->contains(ip);
    }
};

//
//

template <class T>
class IA_LazyUnarySet: public IA_BaseSet<T> {
    // this class is still abstract.  It just seemed like a good place to
    // express the commonality of all the unary Sets.
protected:
    IA_BaseSet<T>	*arg;
public:
    IA_LazyUnarySet(IA_BaseSet<T> * Set)
	:arg(Set) { arg->incr_ref(); }

    ~IA_LazyUnarySet() {
	if (arg->decr_ref()<=0) { delete arg; }
    }

    int extensive() const { return 0; }

    // the following virtual functions are still abstract:
    // type, contains, output
};

// The inversion of the set membership predicate.  The argument can be
// any kind of pointset.
template <class T>
class IA_LazyNotSet: public IA_LazyUnarySet<T> {
private:
    static char type_;
public:
    IA_LazyNotSet(IA_BaseSet<T> * x) :IA_LazyUnarySet<T>(x) {}
    static IA::Type s_type() { return &type_; }
    IA::Type type() const { return &type_; }
    int contains(T ip) const { return ! arg->contains(ip); }
};

#endif
