/* $RCS$
   $Log: ValueSet.cc,v $
Revision 1.8  1992/08/28  10:03:56  jm
added RCS keywords "RCS" and "Log"

*/


#include "ValueSet.h"


ValueSet::ValueSet(const ValueSet& vs) {
    this->size = vs.size;
    if (this->size == 0)
	this->value_array = NULL;
    else {
	this->value_array = new ValueType[this->size];
	for (unsigned int i = 0; i < this->size; i++)
	    this->value_array[i] = vs.value_array[i];
    }
}


ValueSet::ValueSet(ValueType v0) {
    this->value_array = new ValueType[this->size = 1];

    this->value_array[0] = v0;
}


ValueSet::ValueSet(ValueType v0, ValueType v1) {
    ValueType *ret_array = new ValueType[this->size = 2];

    ret_array[0] = v0;
    ret_array[1] = v1;
    
    this->value_array = make_set(ret_array, this->size);
    delete [] ret_array;
}


ValueSet::ValueSet(ValueType v0, ValueType v1, ValueType v2) {
    ValueType *ret_array = new ValueType[this->size = 3];

    ret_array[0] = v0;
    ret_array[1] = v1;
    ret_array[2] = v2;
    
    this->value_array = make_set(ret_array, this->size);
    delete [] ret_array;
}


ValueSet::ValueSet(ValueType v0, ValueType v1, ValueType v2, ValueType v3) {
    ValueType *ret_array = new ValueType[this->size = 4];

    ret_array[0] = v0;
    ret_array[1] = v1;
    ret_array[2] = v2;
    ret_array[3] = v3;
    
    this->value_array = make_set(ret_array, this->size);
    delete [] ret_array;
}


ValueSet::ValueSet(ValueType v0, ValueType v1, ValueType v2, ValueType v3, 
                   ValueType v4) {
    ValueType *ret_array = new ValueType[this->size = 5];

    ret_array[0] = v0;
    ret_array[1] = v1;
    ret_array[2] = v2;
    ret_array[3] = v3;
    ret_array[4] = v4;
    
    this->value_array = make_set(ret_array, this->size);
    delete [] ret_array;
}


ValueSet::ValueSet(const ValueType* ar, unsigned int sz) {
    this->value_array = make_set(ar, sz);
    this->size = sz;
}


ValueType* ValueSet::make_set(const ValueType* a, unsigned int &sz){
    ValueType *ar1 = new ValueType[sz];
    
    if (sz == 0)
	return NULL;
    
    ar1 = new ValueType[sz]; 
    
    
    for (unsigned int i=0; i<sz; i++)
	ar1[i] = a[i];
    
    qsort(ar1, sz, sizeof(ValueType), value_type_compare);
    remove_dup(ar1,sz);
    
    return ar1;
}

void ValueSet::remove_dup(ValueType* &a, unsigned int &sz) {

    ValueType *ret_array = new ValueType[sz-count_dup(a,sz)];
    
    unsigned int di = 0;
    
    for (unsigned int i=0; i < sz-1; i++)
	if (a[i] != a[i+1])
	    ret_array[di++] = a[i];
    
    ret_array[di++] = a[sz-1];
    
    delete [] a;
    a = ret_array;
    sz = di;
}

int ValueSet::count_dup(ValueType* a, unsigned int sz) {
    int count = 0;
    for (unsigned int i=0; i < sz-1; i++)
	if (a[i] == a[i+1])
	    count++;
    return count;
}

ostream& operator << (ostream& stream, ValueSet& vs) {
    int last_index = vs.size-1;
    stream << "<";
    if (vs.size > 0) {
	for (int i=0; i < last_index; i++)
	    stream << vs.value_array[i] << " ";
	if (vs.size > 0)
	    stream << vs.value_array[last_index];
    }
    stream << ">" << '\n';
    return stream;
}

ValueSet& ValueSet::operator=(const ValueSet& vs) {
    if (this == &vs) 
	return *this;

    // handle empty set possibility

    if (vs.size == 0) {

	delete[] this->value_array;  // OK even if value_array already NULL
	this->value_array = NULL;
	this->size = 0;
	return *this;
    }

    // handle the typical case

    if (vs.size != this->size) {
	delete[] this->value_array;
	this->value_array = new ValueType[vs.size];
	this->size = vs.size;
    }

    for (unsigned int i = 0; i < this->size; i++)
	this->value_array[i] = vs.value_array[i];
    
    return *this;
}

ValueSet operator| (const ValueSet &left, const ValueSet &right) {
    ValueType* temp = new ValueType[left.size + right.size];

    unsigned int li = 0, ri = 0, ci = 0;

    if (&left == &right) return ValueSet(left);
    while ((li < left.size) && (ri < right.size))
	if (left.value_array[li] < right.value_array[ri])
	    temp[ci++] = left.value_array[li++];
	else {
	    temp[ci++] = right.value_array[ri];
	    if (left.value_array[li] == right.value_array[ri++])
		li++;
	}

    if (li == left.size)
	for (;ri < right.size;ri++)
	    temp[ci++] = right.value_array[ri];
    else
	for (;li < left.size;li++)
	    temp[ci++] = left.value_array[li];

    return ValueSet(temp, ci);
}

ValueSet operator& (const ValueSet &left, const ValueSet &right) {
    ValueType* temp = new ValueType[left.card() < right.card() 
				    ? left.size : right.size];

    unsigned int li = 0, ri = 0, ci = 0;

    if ((left.empty()) || (right.empty()))
	return ValueSet();

    if ((left.max() < right.min()) || (left.min() > right.max()))
	return ValueSet();

    if (&left == &right) return ValueSet(left);

    while ((li < left.size) && (ri < right.size))
	if (left.value_array[li] < right.value_array[ri])
	    li++;
	else {
	    if (left.value_array[li] == right.value_array[ri]) {
		temp[ci++] = right.value_array[ri];
		li++;
	    }
	    ri++;
	}

    return ValueSet(temp, ci);
}

ValueSet operator- (const ValueSet &left, const ValueSet &right) {
    ValueType* temp = new ValueType[left.size];

    unsigned int li = 0, ri = 0, ci = 0;

    if (left.empty())
	return ValueSet();
    if (right.empty())
	return ValueSet(left);

    if (&left == &right) return ValueSet();

    while ((li < left.size) && (ri < right.size))
	if (left.value_array[li] < right.value_array[ri])
	    temp[ci++] = left.value_array[li++];
	else {
	    if (left.value_array[li] == right.value_array[ri]) {
		li++;
	    }
	    ri++;
	}

    if (ri == right.size)
	for (;li<left.size;li++)
	    temp[ci++] = left.value_array[li];

    return ValueSet(temp, ci);
}

ValueSet operator^ (const ValueSet &left, const ValueSet &right) {
    ValueType* temp = new ValueType[left.size + right.size];

    unsigned int li = 0, ri = 0, ci = 0;

    if (left.empty())
	return ValueSet(right);

    if (right.empty())
	return ValueSet(left);

    if (&left == &right) return ValueSet();

    while ((li < left.size) && (ri < right.size)) 
	if (left.value_array[li] < right.value_array[ri])
	    temp[ci++] = left.value_array[li++];
	else
	    if (left.value_array[li] > right.value_array[ri])
		temp[ci++] = right.value_array[ri++];
	    else { 
		li++;
		ri++;
	    }

    if (ri == right.size)
	for (;li<left.size;li++)
	    temp[ci++] = left.value_array[li];

    if (li == left.size)
	for (;ri<right.size;ri++)
	    temp[ci++] = right.value_array[ri];

    return ValueSet(temp, ci);
}

char operator<= (const ValueSet &left, const ValueSet &right){

    unsigned int li = 0, ri = 0;

    if (left.empty())
	return 1;

    if (right.empty())
	return 0;

    if (&left == &right) return 1;

    while ((li < left.size) && (ri < right.size)) {
	while (left.value_array[li] > right.value_array[ri])
	    ri++;
	if (left.value_array[li] < right.value_array[ri])
	    return 0;
	li++;
	ri++;
    }
    return 1;
}

char operator>= (const ValueSet &left, const ValueSet &right){

    unsigned int li = 0, ri = 0;

    if (right.empty())
	return 1;

    if (left.empty())
	return 0;

    if (&left == &right) return 1;

    while ((ri < right.size) && (li < left.size)) {
	while (right.value_array[ri] > left.value_array[li])
	    li++;
	if (right.value_array[ri] < left.value_array[li])
	    return 0;
	li++;
	ri++;
    }
    return 1;
}

char operator== (const ValueSet &left, const ValueSet &right){

    if (left.size != right.size)
	return 0;

    for (unsigned int i = 0; i < left.size; i++)
       if (left.value_array[i] != right.value_array[i])
	   return 0;

    return 1;
}

char operator!= (const ValueSet &left, const ValueSet &right){
    return !(left == right);
}

ValueSet value_range(ValueType v0, ValueType v1) {
    ValueSet vs;
    int sz = v1-v0;

    if (sz < 0)
	return ValueSet();
    if (sz == 0)
	return ValueSet(v0);
	    
    ValueType *ret_array = new ValueType[++sz];

    for (int i = 0; i < sz; i++)
	ret_array[i] = v0+i;

    vs.value_array = ret_array;
    vs.size = sz;

    return vs;
}




