/**************************************************************************** * * Stack Buffer - Fast buffer which allocates memory on stack instead of heap. * Copyright (c) 2007 Antrix Team * * This file may be distributed under the terms of the Q Public License * as defined by Trolltech ASA of Norway and appearing in the file * COPYING included in the packaging of this file. * * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. * */ #ifndef _STACKBUFFER_H #define _STACKBUFFER_H #include "Common.h" #include "WoWGuid.h" #include "LocationVector.h" template class StackBuffer { protected: uint8 m_stackBuffer[Size]; uint8 * m_bufferPointer; uint8 * m_heapBuffer; uint32 m_readPos; uint32 m_writePos; uint32 m_space; public: /** Constructor, sets buffer pointers and zeros write/read positions. */ StackBuffer() : m_readPos(0), m_writePos(0), m_bufferPointer(&m_stackBuffer[0]), m_heapBuffer(0), m_space(Size) {} /** Destructor, frees heap buffer if it exists */ ~StackBuffer() { if(m_heapBuffer) free(m_heapBuffer); } /** Re-allocates the buffer on the heap. This allows it to expand past the original specified size. * This is only a failsafe and should be avoided at all costs, as it is quite heavy. */ void ReallocateOnHeap() { if(m_heapBuffer) // Reallocate with 200 bytes larger size m_heapBuffer = (uint8*)realloc(m_heapBuffer, 200); else { m_heapBuffer = (uint8*)malloc(m_space + 200); memcpy(m_heapBuffer, m_stackBuffer, m_writePos); m_space += 200; m_bufferPointer = m_heapBuffer; } } /** Reads sizeof(T) bytes from the buffer * @return the bytes read */ template T Read() { if(m_readPos + sizeof(T) <= m_writePos) return (T)0; T ret = *(T*)&m_bufferPointer[m_readPos]; m_readPos += sizeof(T); return ret; } /** Writes sizeof(T) bytes to the buffer, while checking for overflows. * @param T data The data to be written */ template void Write(T data) { if(m_writePos + sizeof(T) > m_space) { // Whoooops. We have to reallocate on the heap. ReallocateOnHeap(); } *(T*)&m_bufferPointer[m_writePos] = data; m_writePos += sizeof(T); } /** Ensures the buffer is big enough to fit the specified number of bytes. * @param bytes number of bytes to fit */ inline void EnsureBufferSize(uint32 Bytes) { if(m_writePos + Bytes > m_space) ReallocateOnHeap(); } /** These are the default read/write operators. */ #define DEFINE_BUFFER_READ_OPERATOR(type) void operator >> (type& dest) { dest = Read(); } #define DEFINE_BUFFER_WRITE_OPERATOR(type) void operator << (type src) { Write(src); } /** Fast read/write operators without using the templated read/write functions. */ #define DEFINE_FAST_READ_OPERATOR(type, size) void operator >> (type& dest) { if(m_readPos + size > m_writePos) { dest = (type)0; } else { dest = *(type*)&m_bufferPointer[m_readPos]; m_readPos += size; } } #define DEFINE_FAST_WRITE_OPERATOR(type, size) void operator << (type src) { if(m_writePos + size > m_space) { ReallocateOnHeap(); } *(type*)&m_bufferPointer[m_writePos] = src; m_writePos += size; } /** Integer/float r/w operators */ DEFINE_FAST_READ_OPERATOR(uint64, 8); DEFINE_FAST_READ_OPERATOR(uint32, 4); DEFINE_FAST_READ_OPERATOR(uint16, 2); DEFINE_FAST_READ_OPERATOR(uint8, 1); DEFINE_FAST_READ_OPERATOR(float, 4); DEFINE_FAST_READ_OPERATOR(double, 8); DEFINE_FAST_WRITE_OPERATOR(uint64, 8); DEFINE_FAST_WRITE_OPERATOR(uint32, 4); DEFINE_FAST_WRITE_OPERATOR(uint16, 2); DEFINE_FAST_WRITE_OPERATOR(uint8, 1); DEFINE_FAST_WRITE_OPERATOR(float, 4); DEFINE_FAST_WRITE_OPERATOR(double, 8); /** boolean (1-byte) read/write operators */ DEFINE_FAST_WRITE_OPERATOR(bool, 1); void operator >> (bool & dst) { dst = (Read() > 0 ? true : false); } /** string (null-terminated) operators */ void operator << (std::string & value) { EnsureBufferSize(value.length() + 1); memcpy(&m_bufferPointer[m_writePos], value.c_str(), value.length()+1); m_writePos += (value.length() + 1); } void operator >> (std::string & dest) { dest.clear(); char c; for(;;) { c = Read(); if(c == 0) break; dest += c; } } /** WoWGuid read/write operators */ void operator << (WoWGuid & value) { EnsureBufferSize(value.GetNewGuidLen() + 1); Write(value.GetNewGuidMask()); memcpy(&m_bufferPointer[m_writePos], value.GetNewGuid(), value.GetNewGuidLen()); m_writePos += value.GetNewGuidLen(); } void operator >> (WoWGuid & value) { uint8 mask = Read(); value.Init(mask); for(uint32 i = 0; i < BitCount8(mask); ++i) value.AppendField(Read()); } /** LocationVector read/write operators */ void operator << (LocationVector & val) { // espire: I would've done this as one memcpy.. but we don't know how the struct alignment is gonna come out :/ Write(val.x); Write(val.y); Write(val.z); } void operator >> (LocationVector & dst) { dst.x = Read(); dst.y = Read(); dst.z = Read(); } }; #endif