#include "cshared.h"
//#include "cexception.h"
//#include "csource.h"

#include <iostream>

using namespace std;

cSharedData *cSharedData::construct (size_t len) {
	cSharedData *ret = (cSharedData*)new char[sizeof(cSharedData) + len];

	if (ret == NULL)
		//throwMemoryException(sizeof(cSharedData) + len);
		cerr << "Error: Out of Memory while trying to allocate " << len 
			 << " bytes" << endl;

	ret->BufferLen = len;
	ret->NumRefs   = 0;
	
	return ret;
}

cShared::cShared ():
		Buffer(0) {
}

cShared::cShared (const cShared &src):
		Buffer(src.Buffer) {
	if (Buffer)
		++*Buffer;
}

cShared::~cShared () {
	if (Buffer)
		release();
}

void cShared::clear () {
	if (Buffer)
		release();
	Buffer = 0;
}

void cShared::Set (const cShared &src) {
	if (Buffer)
		release();

	Buffer = src.Buffer;
	if (Buffer)
		++*Buffer;
}

void cShared::release () {
	CHECK_PTR(Buffer);

	if (--*Buffer == 0)
		delete[] (char*)Buffer;

	Buffer = 0;
}

void cShared::release(uint newsize) {
	CHECK_PTR(Buffer);

	allocate(newsize, true);
}

void cShared::exclusive () {
	CHECK_PTR(Buffer);

	if (Buffer->refs() == 1)
		return;

	cSharedData *copy = cSharedData::construct(Buffer->size());
	memcpy(*copy, *Buffer, Buffer->size());

	release();

	Buffer = copy;
	++*Buffer;
}

void cShared::allocate (size_t len, bool keep /* = false */) {
	if (Buffer && (Buffer->refs() == 1) && (Buffer->size() == len))
		return;

	cSharedData *newBuffer = cSharedData::construct(len);
	if (Buffer) {
		if (keep)
			memcpy(*newBuffer, *Buffer, len < Buffer->size() ? len : Buffer->size());

		release();
	}
	Buffer = newBuffer;
	++*Buffer;
}

/*cSource &operator>> (cSource &dest, cShared &str) {
	long dataLen = dest.peekInternal();
	if (dataLen) {
		str.buffer(dataLen + 1);
		dest.readInternal(str);
		str.release(dataLen);
	}
	return dest;
}*/

