GrowingCircularBuffer added and tested.

This commit is contained in:
miha_vitorovic
2010-11-11 14:03:53 +01:00
parent 5379cd638a
commit b53db4c792
5 changed files with 208 additions and 2 deletions
+1 -1
View File
@@ -25,7 +25,7 @@ TEMPLATE_TOP=$(EPICS_BASE)/templates/makeBaseApp/top
#SNCSEQ=$(EPICS_BASE)/../modules/soft/seq
# EPICS_BASE usually appears last so other apps can override stuff:
EPICS_BASE=/Users/msekoranja/Work/EPICS/base-3.14.11
EPICS_BASE=/opt/epics/base
# Set RULES here if you want to take build rules from somewhere
# other than EPICS_BASE:
+3
View File
@@ -14,6 +14,9 @@ PROD_HOST += arrayFIFOTest
arrayFIFOTest_SRCS += arrayFIFOTest.cpp
arrayFIFOTest_LIBS += pvAccUtils Com
PROD_HOST += growingCircularBufferTest
growingCircularBufferTest_SRCS += growingCircularBufferTest.cpp
growingCircularBufferTest_LIBS += pvAccUtils Com
include $(TOP)/configure/RULES
#----------------------------------------
@@ -0,0 +1,50 @@
/*
* growingCircularBufferTest.cpp
*
* Created on: Nov 11, 2010
* Author: Miha Vitorovic
*/
#include "growingCircularBuffer.h"
#include <iostream>
#include <epicsAssert.h>
using namespace epics::pvAccess;
using std::cout;
using std::endl;
const int CAPACITY = 10;
int main(int argc, char *argv[]) {
GrowingCircularBuffer<int> cb(CAPACITY);
cout<<"Testing circular buffer."<<endl;
assert(cb.capacity()==CAPACITY);
assert(cb.size()==0);
// insert, get test
bool first = cb.insert(1);
assert(cb.size()==1);
assert(cb.extract()==1);
assert(first);
assert(cb.size()==0);
for(int i = 0; i<2*CAPACITY; i++) {
first = cb.insert(i);
assert(cb.size()==i+1);
assert((cb.size() == 1)==first);
}
assert(cb.size()==2*CAPACITY);
for(int i = 0; i<2*CAPACITY; i++) {
assert(cb.extract()==i);
assert(cb.size()==2*CAPACITY-i-1);
}
assert(cb.size()==0);
cout<<"\nPASSED!\n";
return 0;
}
+2 -1
View File
@@ -5,13 +5,14 @@ include $(TOP)/configure/CONFIG
INC += hexDump.h
INC += wildcharMatcher.h
INC += arrayFIFO.h
INC += growingCircularBuffer.h
LIBSRCS += hexDump.cpp
LIBSRCS += wildcharMatcher.cpp
LIBRARY = pvAccUtils
#pvAccess_LIBS += Com
#pvAccUtils_LIBS += Com
include $(TOP)/configure/RULES
#----------------------------------------
+152
View File
@@ -0,0 +1,152 @@
/*
* growingCircularBuffer.h
*
* Created on: Nov 11, 2010
* Author: Miha Vitorovic
*/
#ifndef GROWINGCIRCULARBUFFER_H_
#define GROWINGCIRCULARBUFFER_H_
#include <epicsException.h>
using epics::pvData::BaseException;
namespace epics {
namespace pvAccess {
/**
* Implementation of circular FIFO unbouded buffer.
* Instance is not thread safe.
* @author Miha Vitorovic
*/
template<class T>
class GrowingCircularBuffer {
public:
/**
* Create a GrowingCircularBuffer with the given capacity.
**/
GrowingCircularBuffer(size_t capacity = 16) :
_takePointer(0), _putPointer(0), _count(0), _size(capacity),
_elements(new T[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] = x;
if (++_putPointer >= _size) _putPointer = 0;
return _count == 1;
}
template<class T>
T GrowingCircularBuffer<T>::extract() {
if(_count==0) THROW_BASE_EXCEPTION("Buffer empty.");
_count--;
T old = _elements[_takePointer];
if(++_takePointer>=_size) _takePointer = 0;
return old;
}
}
}
#endif /* GROWINGCIRCULARBUFFER_H_ */