GrowingCircularBuffer added and tested.
This commit is contained in:
+1
-1
@@ -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:
|
||||
|
||||
@@ -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;
|
||||
|
||||
}
|
||||
@@ -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
|
||||
#----------------------------------------
|
||||
|
||||
@@ -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_ */
|
||||
Reference in New Issue
Block a user