/* * growingCircularBuffer.h * * Created on: Nov 11, 2010 * Author: Miha Vitorovic */ #ifndef GROWINGCIRCULARBUFFER_H_ #define GROWINGCIRCULARBUFFER_H_ // TODO remove exception throwing !!! #include namespace epics { namespace pvAccess { /** * Implementation of circular FIFO unbouded buffer. * Instance is not thread safe. * @author Miha Vitorovic */ template class GrowingCircularBuffer { public: /** * Create a GrowingCircularBuffer with the given capacity. **/ GrowingCircularBuffer(size_t capacity = 16) : _elements(new T[capacity]), _takePointer(0), _putPointer(0), _count(0), _size(capacity) { } ~GrowingCircularBuffer() { delete[] _elements; } /** * Get number of elements in the buffer. * @return number of elements in the buffer. */ inline size_t size() { return _count; } /** * Get current buffer capacity. * @return buffer current capacity. */ inline size_t capacity() { return _size; } /** * Insert a new element in to the buffer. * If buffer full the buffer is doubled. * * @param x element to insert. * @return true if first element. */ bool insert(const T x); /** * Extract the oldest element from the buffer. * @return the oldest element from the buffer. */ T extract(); private: /** * Array (circular buffer) of elements. */ T* _elements; /** * Take (read) pointer. */ size_t _takePointer; /** * Put (write) pointer. */ size_t _putPointer; /** * Number of elements in the buffer. */ size_t _count; size_t _size; void arraycopy(T* src, size_t srcPos, T* dest, size_t destPos, size_t length); }; template void GrowingCircularBuffer::arraycopy(T* src, size_t srcPos, T* dest, size_t destPos, size_t length) { if(srcPos=0; i--) dest[destPos+i] = src[srcPos+i]; else for(size_t i = 0; i bool GrowingCircularBuffer::insert(const T x) { if(_count==_size) { // we are full, grow by factor 2 T* newElements = new T[_size*2]; // invariant: _takePointer < _size size_t split = _size-_takePointer; if(split>0) arraycopy(_elements, _takePointer, newElements, 0, split); if(_takePointer!=0) arraycopy(_elements, 0, newElements, split, _putPointer); _takePointer = 0; _putPointer = _size; _size *= 2; delete[] _elements; _elements = newElements; } _count++; _elements[_putPointer] = x; if(++_putPointer>=_size) _putPointer = 0; return _count==1; } template T GrowingCircularBuffer::extract() { if(_count==0) THROW_BASE_EXCEPTION("Buffer empty."); _count--; T old = _elements[_takePointer]; if(++_takePointer>=_size) _takePointer = 0; return old; } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /** * Template specialization for pointers. * Implementation of circular FIFO unbouded buffer. * Instance is not thread safe. * @author Miha Vitorovic */ template class GrowingCircularBuffer { public: /** * Create a GrowingCircularBuffer with the given capacity. **/ GrowingCircularBuffer(size_t capacity = 16) : _elements(new T*[capacity]), _takePointer(0), _putPointer(0), _count(0), _size(capacity) { } ~GrowingCircularBuffer() { delete[] _elements; } /** * Get number of elements in the buffer. * @return number of elements in the buffer. */ inline size_t size() { return _count; } /** * Get current buffer capacity. * @return buffer current capacity. */ inline size_t capacity() { return _size; } /** * Insert a new element in to the buffer. * If buffer full the buffer is doubled. * * @param x element to insert. * @return true if first element. */ bool insert(const T* x); /** * Extract the oldest element from the buffer. * @return the oldest element from the buffer. */ T* extract(); private: /** * Array (circular buffer) of elements. */ T** _elements; /** * Take (read) pointer. */ size_t _takePointer; /** * Put (write) pointer. */ size_t _putPointer; /** * Number of elements in the buffer. */ size_t _count; size_t _size; void arraycopy(T** src, size_t srcPos, T** dest, size_t destPos, size_t length); }; /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * g++ requires template definition inside a header file. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ template void GrowingCircularBuffer::arraycopy(T** src, size_t srcPos, T** dest, size_t destPos, size_t length) { if(srcPos=0; i--) dest[destPos+i] = src[srcPos+i]; else for(size_t i = 0; i bool GrowingCircularBuffer::insert(const T* x) { if(_count==_size) { // we are full, grow by factor 2 T** newElements = new T*[_size*2]; // invariant: _takePointer < _size size_t split = _size-_takePointer; if(split>0) arraycopy(_elements, _takePointer, newElements, 0, split); if(_takePointer!=0) arraycopy(_elements, 0, newElements, split, _putPointer); _takePointer = 0; _putPointer = _size; _size *= 2; delete[] _elements; _elements = newElements; } _count++; _elements[_putPointer] = const_cast(x); if(++_putPointer>=_size) _putPointer = 0; return _count==1; } template T* GrowingCircularBuffer::extract() { if(_count==0) return NULL; _count--; T* old = _elements[_takePointer]; if(++_takePointer>=_size) _takePointer = 0; return old; } } } #endif /* GROWINGCIRCULARBUFFER_H_ */