/* ZReferenceBuffer.hpp Author: James Russell Purpose : Acts as a means of storing arbitrary types of values in an array which gives back index-based references to pointers of those types of values. Handles, internally, the Buffer overflowing and looping back around the end of the storage array. Changelog : 2/11/10 - Creation (jcr2) 2/13/10 - Should be working as advertised (jcr) 3/04/10 - NOW working as advertised (jcr) */ #ifndef _ZREFERENCEBUFFER_H #define _ZREFERENCEBUFFER_H #include #include #include #include #define ZRB_DEFAULT_BUFFER_SIZE (10) #define ZRB_INVALID_HANDLE (-1) typedef int ZReferenceBufferHandle; template class ZReferenceBuffer { protected: //The Current Index Value (next value to be assigned) int CurrentIndex; //The Current Size of the Buffer (Storage Capacity) int BufferSize; //The Current Number of Items contained in the Buffer int ItemCount; //Indicator array used to indicate which indices of the Buffer are valid ZArray Indicator; //Buffer of T* Values ZArray Buffer; //Checks if a given reference is valid inline bool IsValid(int index); //Checks if a given reference is invalid inline bool IsInvalid(int index); //Sets the Indicator of an index to valid inline void SetValid(int index); //Sets the Indicator of an index to invalid inline void SetInvalid(int index); public: /* Default constructor. */ ZReferenceBuffer(); /* Constructor. @param _size - The starting size of the reference buffer. */ ZReferenceBuffer(int _size); /* Constructor. @param _allocator - the allocator to use for allocations / deallocations in the reference buffer */ ZReferenceBuffer(ZArrayAllocator *_allocator); /* Constructor. @param _size - The starting size of the reference buffer. @param _allocator - the allocator to use for allocations / deallocations in the reference buffer */ ZReferenceBuffer( int _size, ZArrayAllocator *_allocator); /* Destructor. */ ~ZReferenceBuffer(); /* public ZReferenceBuffer::AddItem Adds the item to the reference Buffer, returning a handle. Resizes the Buffer automatically to increase the size of the buffer if full. @param _item - the item to add to the buffer @return (ZReferenceBufferHandle) - a ZReferenceBufferHandle which can be used to reference item, Will never return NULL. */ ZReferenceBufferHandle AddItem(T _item); /* public ZReferenceBuffer::GetItem Gets an item in the Buffer given a reference handle. @param _ref - the reference handle to the item you wish to get @return (T&) - the item the handle refers to */ T& GetItem(ZReferenceBufferHandle _ref); /* public ZReferenceBuffer::SetItem Attempts to set the reference to map to the provided item. Used for updating references. @param _ref - a valid reference handle to update. If NULL, will set the null handle, allowing a NULL reference to be valid. @param _item - the item to update the reference to @return (T) - the overwritten value that ref pointed to */ T SetItem(ZReferenceBufferHandle _ref, T _item); /* public ZReferenceBuffer::RemoveItem Removes an item from the Buffer given a reference handle and invalidates the handle (until reassigned). @param _ref - the reference handle to the item you wish to remove @return (T) - the item removed */ T RemoveItem(ZReferenceBufferHandle _ref); /* public ZReferenceBuffer::Remove Removes all occurrences of an item from the Buffer given a pointer to the item. @param _item - the item you wish to remove @return (void) */ void Remove(T _item); /* public ZReferenceBuffer::Size Gets the current size of the buffer. @return (int) - the size (capacity) of the buffer */ int Size(); /* public ZReferenceBuffer::Count Returns the number of elements currently stored in the Buffer @return (int) - the count (number of items) in the buffer */ int Count(); /* public ZReferenceBuffer::Items Returns a ZList containing the elements of the reference Buffer. @return (ZList) - a list containing all the values currently in the buffer */ ZList Items(); /* inline public ZReferenceBuffer::IsFull Returns true if the Buffer is full, false otherwise. @return (bool) - boolean indicating the buffer is full */ inline bool IsFull(); /* public ZReferenceBuffer::Resize Resizes the Buffer to store _newSize number of elements. Already existing references remain valid. Returns true on success, false otherwise. Newsize must be greater than the current size of the reference Buffer. @param _newSize - the ZNew capacity of the buffer @return (bool) - boolean indicating success or failure */ bool Resize( int _newSize); }; template ZReferenceBuffer::ZReferenceBuffer( int _size, ZArrayAllocator* _allocator) : CurrentIndex(1), BufferSize(_size+1), ItemCount(0), Allocator(_allocator) { this->Buffer.Resize(BufferSize); this->Indicator.Resize(this->BufferSize, false); } template ZReferenceBuffer::ZReferenceBuffer( int _size) : CurrentIndex(1), BufferSize(_size+1), ItemCount(0) { this->Buffer.Resize(BufferSize); this->Indicator.Resize(this->BufferSize, false); } template ZReferenceBuffer::ZReferenceBuffer(ZArrayAllocator* _allocator) : CurrentIndex(1), BufferSize(ZRB_DEFAULT_BUFFER_SIZE+1), ItemCount(0), Allocator(_allocator) { this->Buffer.Resize(BufferSize); this->Indicator.Resize(this->BufferSize, false); } template ZReferenceBuffer::ZReferenceBuffer() : CurrentIndex(1), BufferSize(ZRB_DEFAULT_BUFFER_SIZE+1), ItemCount(0) { this->Buffer.Resize(BufferSize); this->Indicator.Resize(this->BufferSize, false); } template ZReferenceBuffer::~ZReferenceBuffer() { } template bool ZReferenceBuffer::IsValid(int _index) { if (_index >= 0) return this->Indicator[_index] != 0; return false; } template bool ZReferenceBuffer::IsInvalid(int _index) { return !IsValid(_index); } template void ZReferenceBuffer::SetValid( int _index) { this->Indicator[_index] = 1; } template void ZReferenceBuffer::SetInvalid( int _index) { this->Indicator[_index] = 0; } template ZReferenceBufferHandle ZReferenceBuffer::AddItem(T _item) { int startIndex; int ref; //CurrentIndex should only be zero if Buffer is full if (this->CurrentIndex == 0) return this->CurrentIndex; ref = startIndex = this->CurrentIndex; while (this->IsValid(this->CurrentIndex)) { this->CurrentIndex++; ref = this->CurrentIndex; if (this->CurrentIndex == startIndex) this->Resize(this->BufferSize * 2); if (this->CurrentIndex >= this->BufferSize) ref = this->CurrentIndex = 1; } if (ref != -1) { this->Buffer[ref] = _item; this->SetValid(ref); this->ItemCount++; } return ref; } template T& ZReferenceBuffer::GetItem(ZReferenceBufferHandle _ref) { ZASSERT(this->IsValid(_ref), "ERROR: ZReferenceBuffer::GetItemRef passed invalid reference!"); return this->Buffer[_ref]; } template T ZReferenceBuffer::RemoveItem(ZReferenceBufferHandle _ref) { T item; ZASSERT( this->IsValid(_ref) , "ERROR: ZReferenceBuffer::RemoveItem passed invalid reference!" ); this->ItemCount--; this->SetInvalid(_ref); item = this->Buffer[_ref]; return item; } template void ZReferenceBuffer::Remove(T _item) { for ( int i = 0; i < this->BufferSize; i++) if (this->Buffer[i] == _item) this->RemoveItem(i); } template T ZReferenceBuffer::SetItem(int _ref, T _item) { T ret; ret = this->Buffer[_ref]; this->Buffer[_ref] = _item; this->SetValid(_ref); this->ItemCount++; return ret; } template int ZReferenceBuffer::Size() { return this->BufferSize; } template int ZReferenceBuffer::Count() { return this->ItemCount; } template bool ZReferenceBuffer::IsFull() { return (!this->CurrentIndex); } template bool ZReferenceBuffer::Resize( int _newSize) { if (_newSize < this->BufferSize) return false; this->BufferSize = _newSize + 1; ZArray newBuffer; newBuffer.Resize(this->BufferSize); for ( int i = 0; i < this->BufferSize; i++) newBuffer[i] = this->Buffer[i]; this->Indicator.Resize(this->BufferSize, false); this->Buffer = newBuffer; return true; } template ZList ZReferenceBuffer::Items() { int i; ZList items; for (i = 1; i < this->BufferSize; i++) { if (this->IsValid(i)) items.PushBack(this->Buffer[i]); } return items; } #endif