#include "stdafx.h"

#ifdef _MSC_VER
#pragma hdrstop
#endif

using namespace std;

#include "myExcept.h"
#include "bitvector.h"

bitvector::bitvector(const bitvector& _vector) {
	bitsize = _vector.bitsize;
	data = (DATATYPE *) malloc(_vector.items() * sizeof(DATATYPE));
	memcpy(data, _vector.data, _vector.items() * sizeof(DATATYPE));
}

bitvector& bitvector::operator=(const bitvector &_vector) {
	if (this != &_vector) {
		free(data);
		bitsize = _vector.bitsize;
		data = (DATATYPE *) malloc(_vector.items() * sizeof(DATATYPE));
		memcpy(data, _vector.data, _vector.items() * sizeof(DATATYPE));
	}
	return *this;
}

bitvector::bitvector(void)
{
	bitsize = 0;
	data = NULL;
}

bitvector::bitvector( const unsigned int _size )
{
	if ( _size == 0 ) throw RuntimeException( "bitvector:: Zero vector size" );
	bitsize = _size;
	//data.resize(items(), DATATYPE(0));
	data = (DATATYPE *) calloc(items(), sizeof(DATATYPE));
}

bitvector::~bitvector(void)
{
	free(data);
}

void bitvector::resize( const unsigned int _size )
{
	unsigned int olditems = items();
	if ( _size == 0 ) throw RuntimeException( "bitvector:: Zero vector size" );
	bitsize = _size;
	//data.resize(items(), 0);
	data = (DATATYPE *) realloc(data, items() * sizeof(DATATYPE));
	if (items() > olditems)
		memset(&data[olditems], 0, (items() - olditems) * sizeof(DATATYPE));
}

void bitvector::resize( const unsigned int _size, const bool val )
// resizes the vector and assignes a value to new vector items
{
	//DATATYPE d_val;
	unsigned int olditems = items();
	if ( _size == 0 ) throw RuntimeException( "bitvector:: Zero vector size" );
	bitsize = _size;
	//d_val = val ? ONEMASK : DATATYPE(0);
	//data.resize(items(), d_val);
	data = (DATATYPE *) realloc(data, items() * sizeof(DATATYPE));
	if (items() > olditems)
		memset(&data[olditems], val ? ONEMASK : DATATYPE(0), (items() - olditems) * sizeof(DATATYPE));
}

void bitvector::assign( const unsigned int _size, const Literal val )
// assignes a value to all vector items
{
	DATATYPE d_val;

	if ( _size == 0 ) throw RuntimeException( "bitvector:: Zero vector size" );
	bitsize = _size;
	//d_val = (val)?ALL_ONE:0;
	switch (val) {
	case ZERO:
		d_val = DATATYPE(0);
		break;
	case ONE:
		d_val = ONEMASK;
		break;
	case DC:
		d_val = DCMASK;
		break;
	default:
		d_val = ALL_ONE;
	}
	//data.assign(items(), d_val);
	data = (DATATYPE *) realloc(data, items() * sizeof(DATATYPE));
	memset(data, d_val, items() * sizeof(DATATYPE));
}

inline void bitvector::GetPosition( const unsigned int & pos, position & result ) const
{
	result.index = (pos >> SHIFT);
	result.bit = (pos & MASK) << 1;
}

void bitvector::push_back( const bool bit )
{
	position p;

	GetPosition( bitsize, p );
	if ( p.bit == 0 ) {//data.resize(data.size()+1, 0);
		data = (DATATYPE *) realloc(data, (items() + 1) * sizeof(DATATYPE));
		data[items()] = DATATYPE(0);
	}
	//if ( bit ) data[p.index] |= (DATATYPE(1) << p.bit);
	//else data[p.index] &= ~(DATATYPE(1) << p.bit);
	bitsize++;
	data[p.index] = (data[p.index] & ~(DATATYPE(3) << p.bit)) | (DATATYPE(bit) << p.bit);
}

Literal bitvector::operator[] ( const unsigned int pos ) const
{
	position p;

	//if ( pos >= bitsize ) throw RuntimeException( "bitvector:: index out of range" );
	GetPosition(pos, p);
	//return( (data[p.index] & (DATATYPE(1) << p.bit)) != 0 );
	return Literal((data[p.index] >> p.bit) & DATATYPE(3));
}

bool bitvector::operator== ( const bitvector &_vector ) const
{
	unsigned int i;
	position p;
	DATATYPE mask;

	if ( this->bitsize != _vector.bitsize ) return false;
	else {
		for ( i = 0; i < this->items()-1; i++ )
			if ( this->data[i] != _vector.data[i] ) return false;
		GetPosition(bitsize-1, p);
		mask = ~(ALL_ONE << (p.bit+1));
		if ( (this->data[i] & mask) != (_vector.data[i] & mask) ) return false;
	}
	return true;
}

void bitvector::clear(void)
{
	//data.clear();
	//free(data);
	//data = NULL;
	bitsize = 0;
}

void bitvector::setbit( const unsigned int pos, const Literal val )
{
	position p;

	//if ( pos > bitsize-1 ) throw RuntimeException( "bitvector:: index out of range" );
	GetPosition( pos, p);
	//if ( !val ) data[p.index] &= ~(DATATYPE(1) << p.bit);
	//else data[p.index] |= (DATATYPE(1) << p.bit);
	data[p.index] = (data[p.index] & ~(DATATYPE(3) << p.bit)) | (DATATYPE(val) << p.bit);
}

bitvector bitvector::operator& ( const bitvector &_vector ) const
{
	bitvector vector;
	unsigned int i;

	if ( this->size() != _vector.size() ) throw RuntimeException( "bitvector:: & operator between vectors of different sizes" );
	vector.resize(this->size());
	for ( i = 0; i < this->items(); i++ ) vector.data[i] = this->data[i] & _vector.data[i];
	return vector;
}

bitvector bitvector::operator| ( const bitvector &_vector ) const
{
	bitvector vector;
	unsigned int i;

	if ( this->size() != _vector.size() ) throw RuntimeException( "bitvector:: & operator between vectors of different sizes" );
	vector.resize(this->size());
	for ( i = 0; i < this->items(); i++ ) vector.data[i] = this->data[i] | _vector.data[i];
	return vector;
}

bitvector bitvector::operator^ ( const bitvector &_vector ) const
{
	bitvector vector;
	unsigned int i;

	if ( this->size() != _vector.size() ) throw RuntimeException( "bitvector:: & operator between vectors of different sizes" );
	vector.resize(this->size());
	for ( i = 0; i < this->items(); i++ ) vector.data[i] = this->data[i] ^ _vector.data[i];
	return vector;
}

bitvector bitvector::operator~(void) const
{
	bitvector vector;
	unsigned int i;

	vector.resize(this->size());
	for ( i = 0; i < this->items(); i++ ) vector.data[i] = ~this->data[i];
	return vector;
}

bool bitvector::contains( const bitvector &_vector ) const
// returns true, if this contains _vector
// i.e., _vector does not have a true value, where this has
{
	unsigned int i;
	position p;
	DATATYPE mask;

	if ( this->size() != _vector.size() ) throw RuntimeException( "bitvector::contains: comparing vectors of different sizes" );
	for ( i = 0; i < this->items()-1; i++ )
		if ( (this->data[i] | _vector.data[i]) != this->data[i] ) return false;
	GetPosition(bitsize-1, p);
	mask = ~(ALL_ONE << (p.bit+1));
	if ( ((this->data[i] & mask) | _vector.data[i]) != (this->data[i] & mask) ) return false;
	return true;
}

/*bool bitvector::contains2( const bitvector &_vector ) const
	// returns true, if this contains _vector
	// i.e., _vector does not have a true value, where this has
{
	unsigned int i;
	position p;
	DATATYPE mask;

	if ( this->size() != _vector.size() ) throw RuntimeException( "bitvector::contains: comparing vectors of different sizes" );
	for ( i = 0; i < this->items()-1; i++ )
		if ( (((data[i] ^ _vector.data[i]) & data[i]) | DCMASK) != DCMASK ) return false;
	GetPosition(bitsize-1, p);
	mask = ~(ALL_ONE << (p.bit+1));
	if ( ((this->data[i] & mask) | _vector.data[i]) != (this->data[i] & mask) ) return false;
	return true;
}*/

bool bitvector::isNull(void) const
{
	unsigned int i;
	position p;
	DATATYPE mask;

	for ( i = 0; i < this->items()-1; i++ )
		if ( data[i] != DATATYPE(0) ) return false;
	GetPosition(bitsize-1, p);
	mask = ~(ALL_ONE << (p.bit+1));
	if ( (this->data[i] & mask) != 0 ) return false;
	return true;
}

bool bitvector::isOne(void) const
{
	unsigned int i;
	position p;
	DATATYPE mask;

	for ( i = 0; i < this->items()-1; i++ )
		if ( data[i] != ONEMASK) return false;
	GetPosition(bitsize-1, p);
	mask = ~(ONEMASK << (p.bit+1));
	if ( (this->data[i] & mask) != mask ) return false;
	return true;
}

void bitvector::operator&= ( const bitvector &_vector )
{
	unsigned int i;

	if ( this->size() != _vector.size() ) throw RuntimeException( "bitvector:: & operator between vectors of different sizes" );
	for ( i = 0; i < this->items(); i++ ) this->data[i] &= _vector.data[i];
}

void bitvector::operator|= ( const bitvector &_vector )
{
	unsigned int i;

	if ( this->size() != _vector.size() ) throw RuntimeException( "bitvector:: & operator between vectors of different sizes" );
	for ( i = 0; i < this->items(); i++ ) this->data[i] |= _vector.data[i];
}

void bitvector::operator^= ( const bitvector &_vector )
{
	unsigned int i;

	if ( this->size() != _vector.size() ) throw RuntimeException( "bitvector:: & operator between vectors of different sizes" );
	for ( i = 0; i < this->items(); i++ ) this->data[i] ^= _vector.data[i];
}

ostream& operator<<(ostream& o, const bitvector& bv) {
	for (unsigned int i = 0; i < bv.bitsize; i++) {
		switch (bv[i]) {
		case ZERO:
			o << '0';
			break;
		case ONE:
			o << '1';
			break;
		case DC:
			o << '-';
			break;
		case UNDEF:
			o << '~';
		}
	}
	o << endl;
	return o;
}
