From 4e96a20766d5230757b7120573196145f5a60be5 Mon Sep 17 00:00:00 2001 From: miha_vitorovic Date: Mon, 10 Jan 2011 15:18:15 +0100 Subject: [PATCH] ArrayFIFO template specialization for pointers done. --- pvAccessApp/utils/arrayFIFO.h | 367 +++++++++++++++++++++++++++++++- testApp/utils/arrayFIFOTest.cpp | 136 +++++++++++- 2 files changed, 494 insertions(+), 9 deletions(-) diff --git a/pvAccessApp/utils/arrayFIFO.h b/pvAccessApp/utils/arrayFIFO.h index d449c56..c96e7c5 100644 --- a/pvAccessApp/utils/arrayFIFO.h +++ b/pvAccessApp/utils/arrayFIFO.h @@ -118,11 +118,11 @@ namespace epics { #ifdef ARRAY_FIFO_DEBUG void debugState() { //size_t mask = _size-1; - std::cout<<"h:"<<_head<<",t:"<<_tail<<",c:"<<_size; + std::cout<<"Simple, h:"<<_head<<",t:"<<_tail<<",c:"<<_size; std::cout<<",s:"< - int ArrayFIFO::MIN_INITIAL_CAPACITY = 8; + /* * * * * * * * * * * template implementation * * * * * * * * * * */ template void ArrayFIFO::arraycopy(T* src, size_t srcPos, T* dest, @@ -374,6 +370,361 @@ namespace epics { return false; } + /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + + /** + * Template specialization for pointers + */ + template + class ArrayFIFO { + public: + /** + * Constructs an empty array deque with an initial capacity + * sufficient to hold the specified number of elements. Array FIFO + * is designed to hold objects allocated on the heap. + * + * @param[in] numElements lower bound on initial capacity of the + * deque. Default value is 16 elements. + */ + ArrayFIFO(size_t numElements = 16); + ~ArrayFIFO(); + + /** + * Inserts the specified element at the front of this deque. + * + * @param[in] e the element to add. + */ + void addFirst(const T* e); + + /** + * Inserts the specified element at the end of this deque. + * @param[in] e the element to add + */ + void addLast(const T* e); + + T* pollFirst(); + T* pollLast(); + T* peekFirst(); + T* peekLast(); + + /** + * Pushes an element onto the stack represented by this deque. In other + * words, inserts the element at the front of this deque. + * + * @param[in] e the element to push + */ + void push(const T* e); + + /** + * Pops an element from the stack represented by this deque. In other + * words, removes and returns the first element of this deque. + * + * @return the element at the front of this deque (which is the top + * of the stack represented by this deque), null if no element available. + */ + T* pop(); + + /** + * Looks at the object at the top of this stack without removing it + * from the stack. + * @return the object at the top of this stack (the last item + * of the Vector object). + */ + T* peek(); + + /** + * Returns the number of elements in this deque. + * @return the number of elements in this deque + */ + size_t size(); + + /** + * Returns true if this deque contains no elements. + * + * @return true if this deque contains no elements + */ + bool isEmpty(); + + /** + * Removes all of the elements from this deque. + * The deque will be empty after this call returns. + * + * @param freeElements tells the methods to automatically free + * the memory of all the elments in the FIFO. Default is {@code true} + */ + void clear(); + + /** + * Removes the first occurrence of the specified element in this + * deque (when traversing the deque from head to tail). + * If the deque does not contain the element, it is unchanged. + * More formally, removes the first element e such that + * o.equals(e) (if such an element exists). + * Returns true if this deque contained the specified element + * (or equivalently, if this deque changed as a result of the call). + * + * @param o element to be removed from this deque, if present + * @return true if the deque contained the specified element + */ + bool remove(const T* e); + +#ifdef ARRAY_FIFO_DEBUG + void debugState() { + //size_t mask = _size-1; + std::cout<<"Pointer, h:"<<_head<<",t:"<<_tail<<",c:"<<_size; + std::cout<<",s:"<This method is called delete rather than remove to emphasize + * that its semantics differ from those of {@link List#remove(int)}. + * + * @return true if elements moved backwards + */ + bool del(const size_t i); + + }; + + /* * * * * * * * * * * template implementation * * * * * * * * * * */ + + template + void ArrayFIFO::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 + void ArrayFIFO::allocateElements(size_t numElements) { + _size = MIN_INITIAL_CAPACITY; + // Find the best power of two to hold elements. + // Tests "<=" because arrays aren't kept full. + if(numElements>=_size) { + _size = numElements; + _size |= (_size>>1); + _size |= (_size>>2); + _size |= (_size>>4); + _size |= (_size>>8); + _size |= (_size>>16); + _size++; + } + _elements = new T*[_size]; + } + + template + void ArrayFIFO::doubleCapacity() { + size_t p = _head; + size_t n = _size; + size_t r = n-p; // number of elements to the right of p + size_t newCapacity = n<<1; + T** a = new T*[newCapacity]; + arraycopy(_elements, p, a, 0, r); + arraycopy(_elements, 0, a, r, p); + delete[] _elements; + _elements = a; + _size = newCapacity; + _head = 0; + _tail = n; + + } + + template + ArrayFIFO::ArrayFIFO(size_t numElements) : + _head(0), _tail(0), _mutex() { + allocateElements(numElements); + } + + template + ArrayFIFO::~ArrayFIFO() { + delete[] _elements; + } + + template + void ArrayFIFO::addFirst(const T* e) { + Lock lock(&_mutex); + + _elements[_head = (_head-1)&(_size-1)] = const_cast(e); + if(_head==_tail) doubleCapacity(); + } + + template + void ArrayFIFO::addLast(const T* e) { + Lock lock(&_mutex); + + _elements[_tail] = const_cast(e); + if((_tail = (_tail+1)&(_size-1))==_head) doubleCapacity(); + } + + template + T* ArrayFIFO::pollFirst() { + Lock lock(&_mutex); + + if(isEmpty()) return NULL; + + T* result = _elements[_head]; // Element is null if deque empty + _head = (_head+1)&(_size-1); + return result; + } + + template + T* ArrayFIFO::pollLast() { + Lock lock(&_mutex); + + if(isEmpty()) return NULL; + + _tail = (_tail-1)&(_size-1); + return _elements[_tail]; + } + + template + T* ArrayFIFO::peekFirst() { + Lock lock(&_mutex); + + if(isEmpty()) return NULL; + + return _elements[_head]; + } + + template + T* ArrayFIFO::peekLast() { + Lock lock(&_mutex); + + if(isEmpty()) return NULL; + + return _elements[(_tail-1)&(_size-1)]; + } + + template + void ArrayFIFO::push(const T* e) { + addLast(e); + } + + template + T* ArrayFIFO::pop() { + return pollLast(); + } + + template + T* ArrayFIFO::peek() { + return peekFirst(); + } + + template + size_t ArrayFIFO::size() { + Lock lock(&_mutex); + + return (_tail-_head)&(_size-1); + } + + template + bool ArrayFIFO::isEmpty() { + Lock lock(&_mutex); + + return _head==_tail; + } + + template + void ArrayFIFO::clear() { + Lock lock(&_mutex); + + _head = _tail = 0; + } + + template + bool ArrayFIFO::del(const size_t i) { + // i is absolute index in the array + size_t mask = _size-1; + size_t h = _head; + size_t t = _tail; + size_t front = (i-h)&mask; + size_t back = (t-i)&mask; + + // Invariant: head <= i < tail mod circularity + if(front>=((t-h)&mask)) THROW_BASE_EXCEPTION( + "Illegal State Exception"); // concurrency problem!!! + + // Optimize for least element motion + if(front0) _elements[0] = _elements[mask]; + arraycopy(_elements, h, _elements, h+1, mask-h); + } + _head = (h+1)&mask; + + return false; + } + else { + if(i + bool ArrayFIFO::remove(const T* e) { + Lock lock(&_mutex); + + if(isEmpty()) return false; // nothing to do + + size_t mask = _size-1; + size_t i = _head; + while(i!=_tail) { + if(e==_elements[i]) { + del(i); + return true; + } + i = (i+1)&mask; + } + return false; + } + } } diff --git a/testApp/utils/arrayFIFOTest.cpp b/testApp/utils/arrayFIFOTest.cpp index 61cbfc7..88617e1 100644 --- a/testApp/utils/arrayFIFOTest.cpp +++ b/testApp/utils/arrayFIFOTest.cpp @@ -15,7 +15,9 @@ using namespace epics::pvAccess; using std::cout; using std::endl; -int main(int argc, char *argv[]) { +void testSimpleType() { + cout<<"\nTests for simple type template."< fifoInt; assert(fifoInt.size()==0); @@ -133,5 +135,137 @@ int main(int argc, char *argv[]) { assert(fifoInt.isEmpty()); cout<<"\nPASSED!\n"; +} + +void testPointerType() { + cout<<"\nTests for pointer type template."< fifoInt; + + assert(fifoInt.size()==0); + assert(fifoInt.isEmpty()); + + cout<<"Testing clear."<