#include <Block.h>
# include <assert.h>

template<class T>
void Block<T>::check(int i) const
{
 assert(i>=0);
 assert(i<n);
}

template<class T>
unsigned Block<T>::size(unsigned k)
{
	if (k != n)
		move(new T[k], k);
	return n;
}

template<class T>
Block<T>::~Block()
{
	delete[] p;
}

template<class T>
Block<T>& Block<T>::operator=(const Block<T>& b)
{
	delete[] p;
	copy(b);
	return *this;
}

/* Clear k elements starting at v */
template<class T>
void Block<T>::clear(T* v, unsigned k)
{
	register T* p = v;
	register T* lim = v + k;
	T* valptr = default_value();
	while (p < lim-4) {
		*p++ = *valptr;
		*p++ = *valptr;
		*p++ = *valptr;
		*p++ = *valptr;
		}
	while (p < lim)
		*p++ = *valptr;
}

void Block<char>::clear(char *v, unsigned k) {bzero(v, k);}

/* Make this a copy of b */
template<class T>
void Block<T>::copy(const Block<T>& b)
{
	// assert (p is 0 or garbage)
	p = new T[b.n];
	if (p) {
		n = b.n;
		transfer(b.p, n);
	} else
		n = 0;
}

/* Grow this Block by 1.5 until it can contain at least k+1 */
template<class T>
unsigned Block<T>::grow(unsigned k)
{
	unsigned nn = n;
	if (nn == 0)
		nn++;
	while (nn <= k)
		nn += (nn >> 1) + 1;
	T* np = new T[nn];
	if (!np) {
		nn = k+1;
		np = new T[nn];
	}
	move(np, nn);
	return n;
}

/* Transfer len (or fewer) elements into this Block. */
template<class T>
void Block<T>::transfer(T* source, unsigned len)
{
	register T* plim;
	register T* pp = p;
	register T* q = source;

	if (n > len) {
		plim = p + len;
		clear(plim, n - len);
	} else
		plim = p + n;

	while (pp < plim-4)	{
		*pp++ = *q++;
		*pp++ = *q++;
		*pp++ = *q++;
		*pp++ = *q++;
		}
	while (pp < plim)
		*pp++ = *q++;
}

void Block<char>::transfer(char *source, unsigned len)
{ if(n>len)	bzero(p+len, n-len); bcopy(source, p, n);}
/*
 * The contents of this Block now live in memory starting at np
 * If np is 0, null out this Block.
 */
template<class T>
void Block<T>::move(T* np, unsigned nn)
{
	T* oldp = p;
	unsigned oldn = n;
	p = np;
	if (np) {
		n = nn;
		transfer(oldp, oldn);
	} else
		n = 0;
	delete[] oldp;
}

/* Exchange the contents of this Block with another Block */
template<class T>
void Block<T>::swap(Block<T>& b)
{
	T* bp = b.p;
	unsigned bn = b.n;
	b.p = p;
	b.n = n;
	p = bp;
	n = bn;
}

template<class T>
T* Block<T>::default_value() {
	static T default_item;
	return(&default_item);
}
