GrowingCircularBuffer template specialization for pointers done.

This commit is contained in:
miha_vitorovic
2011-01-10 15:37:25 +01:00
parent 4e96a20766
commit 44516e8a40
3 changed files with 261 additions and 92 deletions

View File

@@ -28,8 +28,8 @@ namespace epics {
* Create a GrowingCircularBuffer with the given capacity.
**/
GrowingCircularBuffer(size_t capacity = 16) :
_elements(new T[capacity]), _takePointer(0), _putPointer(0), _count(0), _size(capacity)
{
_elements(new T[capacity]), _takePointer(0), _putPointer(0),
_count(0), _size(capacity) {
}
~GrowingCircularBuffer() {
@@ -94,13 +94,9 @@ namespace epics {
size_t length);
};
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* g++ requires template definition inside a header file.
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
template<class T>
void GrowingCircularBuffer<T>::arraycopy(T* src, size_t srcPos, T* dest,
size_t destPos, size_t length) {
void GrowingCircularBuffer<T>::arraycopy(T* src, size_t srcPos,
T* dest, size_t destPos, size_t length) {
if(srcPos<destPos) // this takes care of same-buffer copy
for(int i = length-1; i>=0; i--)
dest[destPos+i] = src[srcPos+i];
@@ -111,17 +107,16 @@ namespace epics {
template<class T>
bool GrowingCircularBuffer<T>::insert(const T x) {
if (_count == _size)
{
if(_count==_size) {
// we are full, grow by factor 2
T* newElements = new T[_size * 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);
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;
@@ -132,8 +127,8 @@ namespace epics {
_count++;
_elements[_putPointer] = x;
if (++_putPointer >= _size) _putPointer = 0;
return _count == 1;
if(++_putPointer>=_size) _putPointer = 0;
return _count==1;
}
template<class T>
@@ -146,6 +141,141 @@ namespace epics {
return old;
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/**
* Template specialization for pointers.
* Implementation of circular FIFO unbouded buffer.
* Instance is not thread safe.
* @author Miha Vitorovic
*/
template<class T>
class GrowingCircularBuffer<T*> {
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 <code>true</code> 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<class T>
void GrowingCircularBuffer<T*>::arraycopy(T** src, size_t srcPos,
T** dest, size_t destPos, size_t length) {
if(srcPos<destPos) // this takes care of same-buffer copy
for(int i = length-1; i>=0; i--)
dest[destPos+i] = src[srcPos+i];
else
for(size_t i = 0; i<length; i++)
dest[destPos++] = src[srcPos++];
}
template<class T>
bool GrowingCircularBuffer<T*>::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<T*>(x);
if(++_putPointer>=_size) _putPointer = 0;
return _count==1;
}
template<class T>
T* GrowingCircularBuffer<T*>::extract() {
if(_count==0) return NULL;
_count--;
T* old = _elements[_takePointer];
if(++_takePointer>=_size) _takePointer = 0;
return old;
}
}
}
#endif /* GROWINGCIRCULARBUFFER_H_ */

View File

@@ -140,7 +140,7 @@ void testSimpleType() {
void testPointerType() {
cout<<"\nTests for pointer type template."<<endl;
int buffer[] = {0,1,2,3,4,5,6,7,8,9,11,12,13,14,15,16,17,18,19,20};
int testVals[] = {0,1,2,3,4,5,6,7,8,9,11,12,13,14,15,16,17,18,19,20};
ArrayFIFO<int*> fifoInt;
@@ -148,110 +148,110 @@ void testPointerType() {
assert(fifoInt.isEmpty());
cout<<"Testing clear."<<endl;
fifoInt.push(&buffer[3]);
fifoInt.push(&testVals[3]);
assert(fifoInt.size()==1);
fifoInt.clear();
assert(fifoInt.isEmpty());
cout<<"Testing push/pop."<<endl;
fifoInt.push(&buffer[5]);
fifoInt.push(&buffer[6]);
fifoInt.push(&buffer[7]);
fifoInt.push(&testVals[5]);
fifoInt.push(&testVals[6]);
fifoInt.push(&testVals[7]);
assert(fifoInt.size()==3);
assert(fifoInt.pop()==&buffer[7]);
assert(fifoInt.pop()==&testVals[7]);
assert(fifoInt.size()==2);
assert(fifoInt.pop()==&buffer[6]);
assert(fifoInt.pop()==&testVals[6]);
assert(fifoInt.size()==1);
assert(fifoInt.pop()==&buffer[5]);
assert(fifoInt.pop()==&testVals[5]);
assert(fifoInt.size()==0);
cout<<"Testing FIFO ops (first/last)."<<endl;
fifoInt.addFirst(&buffer[1]);
fifoInt.addFirst(&buffer[2]);
fifoInt.addFirst(&buffer[3]);
fifoInt.addFirst(&buffer[4]);
fifoInt.addFirst(&buffer[5]);
fifoInt.addFirst(&testVals[1]);
fifoInt.addFirst(&testVals[2]);
fifoInt.addFirst(&testVals[3]);
fifoInt.addFirst(&testVals[4]);
fifoInt.addFirst(&testVals[5]);
assert(fifoInt.size()==5);
assert(fifoInt.pollLast()==&buffer[1]);
assert(fifoInt.pollLast()==&buffer[2]);
assert(fifoInt.pollLast()==&buffer[3]);
assert(fifoInt.pollLast()==&buffer[4]);
assert(fifoInt.pollLast()==&buffer[5]);
assert(fifoInt.pollLast()==&testVals[1]);
assert(fifoInt.pollLast()==&testVals[2]);
assert(fifoInt.pollLast()==&testVals[3]);
assert(fifoInt.pollLast()==&testVals[4]);
assert(fifoInt.pollLast()==&testVals[5]);
assert(fifoInt.isEmpty());
cout<<"Testing FIFO ops (last/first)."<<endl;
fifoInt.addLast(&buffer[7]);
fifoInt.addLast(&buffer[8]);
fifoInt.addLast(&buffer[9]);
fifoInt.addLast(&buffer[10]);
fifoInt.addLast(&buffer[11]);
fifoInt.addLast(&testVals[7]);
fifoInt.addLast(&testVals[8]);
fifoInt.addLast(&testVals[9]);
fifoInt.addLast(&testVals[10]);
fifoInt.addLast(&testVals[11]);
assert(fifoInt.size()==5);
assert(fifoInt.pollFirst()==&buffer[7]);
assert(fifoInt.pollFirst()==&buffer[8]);
assert(fifoInt.pollFirst()==&buffer[9]);
assert(fifoInt.pollFirst()==&buffer[10]);
assert(fifoInt.pollFirst()==&buffer[11]);
assert(fifoInt.pollFirst()==&testVals[7]);
assert(fifoInt.pollFirst()==&testVals[8]);
assert(fifoInt.pollFirst()==&testVals[9]);
assert(fifoInt.pollFirst()==&testVals[10]);
assert(fifoInt.pollFirst()==&testVals[11]);
assert(fifoInt.isEmpty());
cout<<"Testing remove, peek."<<endl;
fifoInt.addFirst(&buffer[1]);
fifoInt.addFirst(&buffer[2]);
fifoInt.addFirst(&buffer[3]);
fifoInt.addFirst(&buffer[4]);
fifoInt.addFirst(&buffer[5]);
fifoInt.addFirst(&buffer[6]);
fifoInt.addFirst(&buffer[7]);
fifoInt.addFirst(&testVals[1]);
fifoInt.addFirst(&testVals[2]);
fifoInt.addFirst(&testVals[3]);
fifoInt.addFirst(&testVals[4]);
fifoInt.addFirst(&testVals[5]);
fifoInt.addFirst(&testVals[6]);
fifoInt.addFirst(&testVals[7]);
// - - - - - - - - - - - -
fifoInt.addFirst(&buffer[8]);
fifoInt.addFirst(&buffer[9]);
fifoInt.addFirst(&buffer[10]);
fifoInt.addFirst(&testVals[8]);
fifoInt.addFirst(&testVals[9]);
fifoInt.addFirst(&testVals[10]);
assert(fifoInt.peekFirst()==&buffer[10]);
assert(fifoInt.peekLast()==&buffer[1]);
assert(fifoInt.peekFirst()==&testVals[10]);
assert(fifoInt.peekLast()==&testVals[1]);
assert(fifoInt.size()==10);
assert(fifoInt.remove(&buffer[9]));
assert(fifoInt.remove(&testVals[9]));
assert(fifoInt.size()==9);
assert(!fifoInt.remove(&buffer[15]));
assert(!fifoInt.remove(&testVals[15]));
assert(fifoInt.size()==9);
assert(fifoInt.pollLast()==&buffer[1]);
assert(fifoInt.pollLast()==&buffer[2]);
assert(fifoInt.pollLast()==&buffer[3]);
assert(fifoInt.pollLast()==&buffer[4]);
assert(fifoInt.pollLast()==&buffer[5]);
assert(fifoInt.pollLast()==&buffer[6]);
assert(fifoInt.pollLast()==&buffer[7]);
assert(fifoInt.pollLast()==&buffer[8]);
assert(fifoInt.pollLast()==&testVals[1]);
assert(fifoInt.pollLast()==&testVals[2]);
assert(fifoInt.pollLast()==&testVals[3]);
assert(fifoInt.pollLast()==&testVals[4]);
assert(fifoInt.pollLast()==&testVals[5]);
assert(fifoInt.pollLast()==&testVals[6]);
assert(fifoInt.pollLast()==&testVals[7]);
assert(fifoInt.pollLast()==&testVals[8]);
// - - - - - - - - - - - -
assert(fifoInt.pollLast()==&buffer[10]);
assert(fifoInt.pollLast()==&testVals[10]);
assert(fifoInt.isEmpty());
cout<<"Testing increase buffer."<<endl;
fifoInt.addLast(&buffer[2]);
fifoInt.addLast(&buffer[3]);
fifoInt.addLast(&buffer[4]);
fifoInt.addLast(&buffer[5]);
fifoInt.addLast(&buffer[6]);
fifoInt.addLast(&buffer[7]);
fifoInt.addLast(&buffer[8]);
fifoInt.addLast(&buffer[9]);
fifoInt.addLast(&buffer[10]);
fifoInt.addLast(&buffer[11]);
fifoInt.addLast(&buffer[12]);
fifoInt.addLast(&buffer[13]);
fifoInt.addLast(&buffer[14]);
fifoInt.addLast(&buffer[15]);
fifoInt.addLast(&buffer[16]);
fifoInt.addLast(&buffer[17]);
fifoInt.addLast(&buffer[18]);
fifoInt.addLast(&buffer[19]);
fifoInt.addLast(&testVals[2]);
fifoInt.addLast(&testVals[3]);
fifoInt.addLast(&testVals[4]);
fifoInt.addLast(&testVals[5]);
fifoInt.addLast(&testVals[6]);
fifoInt.addLast(&testVals[7]);
fifoInt.addLast(&testVals[8]);
fifoInt.addLast(&testVals[9]);
fifoInt.addLast(&testVals[10]);
fifoInt.addLast(&testVals[11]);
fifoInt.addLast(&testVals[12]);
fifoInt.addLast(&testVals[13]);
fifoInt.addLast(&testVals[14]);
fifoInt.addLast(&testVals[15]);
fifoInt.addLast(&testVals[16]);
fifoInt.addLast(&testVals[17]);
fifoInt.addLast(&testVals[18]);
fifoInt.addLast(&testVals[19]);
assert(fifoInt.size()==18);
fifoInt.debugState();

View File

@@ -16,19 +16,19 @@ using std::endl;
const size_t CAPACITY = 10;
int main(int argc, char *argv[]) {
void testSimpleType() {
GrowingCircularBuffer<int> cb(CAPACITY);
cout<<"Testing circular buffer."<<endl;
cout<<"Testing circular buffer simple type."<<endl;
assert(cb.capacity()==CAPACITY);
assert(cb.size()==0);
// insert, get test
bool first = cb.insert(1);
assert(first);
assert(cb.size()==1);
assert(cb.extract()==1);
assert(first);
assert(cb.size()==0);
for(size_t i = 0; i<2*CAPACITY; i++) {
@@ -45,6 +45,45 @@ int main(int argc, char *argv[]) {
assert(cb.size()==0);
cout<<"\nPASSED!\n";
return 0;
}
void testPointerType() {
GrowingCircularBuffer<int*> cb(CAPACITY);
int testVals[] = {0,1,2,3,4,5,6,7,8,9,11,12,13,14,15,16,17,18,19,20};
cout<<"Testing circular buffer pointer type."<<endl;
assert(cb.capacity()==CAPACITY);
assert(cb.size()==0);
// insert, get test
bool first = cb.insert(&testVals[1]);
assert(first);
assert(cb.size()==1);
assert(cb.extract()==&testVals[1]);
assert(cb.size()==0);
for(size_t i = 0; i<2*CAPACITY; i++) {
first = cb.insert(&testVals[i]);
assert(cb.size()==i+1);
assert((cb.size() == 1)==first);
}
assert(cb.size()==2*CAPACITY);
for(size_t i = 0; i<2*CAPACITY; i++) {
assert(cb.extract()==&testVals[i]);
assert(cb.size()==2*CAPACITY-i-1);
}
assert(cb.size()==0);
cout<<"\nPASSED!\n";
}
int main(int argc, char *argv[]) {
testSimpleType();
cout<<endl;
testPointerType();
return 0;
}