Some useful stuff
Dependents: FtEncoder FtControlSet
Revision 2:8882925900db, committed 2013-03-29
- Comitter:
- humlet
- Date:
- Fri Mar 29 09:55:05 2013 +0000
- Parent:
- 1:bf8fc4455615
- Commit message:
- Buffers tested and fixed
Changed in this revision
Buffer.h | Show annotated file Show diff for this revision Revisions of this file |
BufferTest.h | Show annotated file Show diff for this revision Revisions of this file |
diff -r bf8fc4455615 -r 8882925900db Buffer.h --- a/Buffer.h Thu Mar 28 00:07:10 2013 +0000 +++ b/Buffer.h Fri Mar 29 09:55:05 2013 +0000 @@ -1,46 +1,60 @@ -#include<cstdint> - +#ifndef BUFFER_H +#define BUFFER_H -/// a template for a simple buffer class holding at max N elements of type T +#include "stdint.h" +#include "string.h" + +/// A template for a simple buffer class holding at max N elements of type T. /// Can be used as stack, queue or ring buffer -/// There is heap and a stack based implemenation -template<class T, uint32_t N> +/// This is kind of an abstract base class. There are heap and a stack based based concrete specializations. +template<typename T, uint32_t N> class Buffer { protected: - - static const T outOfBoundsAccessDefaultReturn=T(); - /// the buffer for the stored elements, initialized in the concrete specializations + /// The buffer for the stored elements, initialized in the concrete specializations. T* elements; - /// points to the oldest element (if not empty; equal to the latest if only one element stored) + + /// Guess what: a constructor! But this class is kind of abstract, + /// so it has been declared protected to remove it from the public interface. + /// Called by the ctor of concrete specializations. + Buffer():elements(0),startCsr(0),endCsr(0),nElements(0) {}; + +private: + /// Points to the oldest element (if not empty; equal to the latest if only one element stored) uint32_t startCsr; - /// points one element behind the latest + /// Points one element behind the latest uint32_t endCsr; - /// number of elements currently stored in the Buffer + /// Number of elements currently stored in the Buffer uint32_t nElements; - /// private helper that increments revolving cursors + /// Private helper that increments revolving cursors inline void incrCsr(uint32_t& csr) { if(++csr>=N) csr=0; } - /// private helper that decrements revolving cursors + /// Private helper that decrements revolving cursors inline void decrCsr(uint32_t& csr) { if(--csr>=N) csr=N-1; // will get quite large on underlow since csr is unsigned } - /// guess what: a constructor! But this class is kind of abtract, - /// so it has been declared protected to remove it from the public interface - Buffer():elements(0),startCsr(0),endCsr(0),nElements(0) {}; + /// Provides default T() return value for out of bounds access. + const T& outOfBoundsDefaultReturn()const { + static const T honk=T(); + return honk; + } + + /// copy ctor: This class is kind of abtract, + /// so it has been declared protected to remove it from the public interface. + /// Not even called by the concrete specialization, since they use the assignment op. + /// That's why it has become private just to get informed whenever it will be needed again + /// and to prevent a silent implicit creation by the compiler. + Buffer(const Buffer& buf):elements(0),startCsr(buf.startCsr),endCsr(buf.endCsr),nElements(buf.nElements) {}; public: - /// virtual destructor - virtual ~Buffer() {}; - - /// if used as queue or stack, use this function to insert new element to the buffer - /// returns true on success and false if full + /// If used as queue or stack, use this function to insert new element to the buffer. + /// Returns true on success and false if Buffer is full inline bool push(const T& element) { - bool ok = !isFull(); + bool ok = !full(); if(ok) { elements[endCsr]=element; incrCsr(endCsr); @@ -49,42 +63,46 @@ return ok; } - /// if used as ring buffer, use this function to insert new elements to the buffer + /// If used as ring buffer, use this function to insert new elements to the Buffer. + /// If buffer is full, this function overwrites the oldest element. inline void pushCircular(const T& element) { - elements[endPos]=element; + elements[endCsr]=element; incrCsr(endCsr); - if(isFull())incrCsr(startCsr); - ++nElements; + if(full()) { + incrCsr(startCsr); + } else { + ++nElements; + } } - /// pop the latest element from buffer. Returns a default instance of type T if empty + /// Pop the latest element from buffer. Returns a default instance of type T if empty. inline const T& popLatest() { - if(isEmpty())return outOfBoundsAccessDefaultReturn; + if(empty())return outOfBoundsDefaultReturn(); decrCsr(endCsr); --nElements; return elements[endCsr]; } - /// pop the oldest element from buffer. Returns a default instance of type T if empty + /// Pop the oldest element from buffer. Returns a default instance of type T if empty. inline const T& popOldest() { - if(isEmpty())return outOfBoundsAccessDefaultReturn; + if(empty())return outOfBoundsDefaultReturn(); T& oldest = elements[startCsr]; incrCsr(startCsr); --nElements; return oldest; } - /// returns true if buffer is empty - inline bool isEmpty() const { + /// Returns true if buffer is empty. + inline bool empty() const { return nElements==0; } - /// returns true if buffer is full - inline bool isFull() const { + /// Returns true if buffer is full. + inline bool full() const { return nElements==N; } - /// retuns number of currently stored elements + /// Retuns number of currently stored elements. inline uint32_t size() const { return nElements; } @@ -94,54 +112,95 @@ return N; } - /// read only access operator: Element with index 0 is the oldest and the one with index size()-1 the latest - inline const T& operator[](uint32_t idx)const { - return operator[](idx); + /// Clear the Buffer + inline void clear() { + startCsr=0; + endCsr=0; + nElements=0; } - /// read/write access operator: Element with index 0 is the oldest and the one with index size()-1 the latest - inline T& operator[](uint32_t idx) { - if(idx>=nElements())return outOfBoundsAccessDefaultReturn; + /// Read only access operator: Element with index 0 is the oldest and the one with index size()-1 the latest + inline const T& operator[](uint32_t idx) { + if(idx>=nElements)return outOfBoundsDefaultReturn(); idx+=startCsr; if(idx>=N)idx-=N; return elements[idx]; } + + /// assignment operator ... does not care about the concrete type of the source Buffer + /// as long as T and N template parameters are identical. + Buffer& operator=(const Buffer& buf) { + if(&buf!=this) { + startCsr=buf.startCsr; + endCsr=buf.endCsr; + nElements=buf.nElements; + memcpy(elements,buf.elements,N*sizeof(T)); + } + return *this; + } + + /// virtual destructor + virtual ~Buffer() {}; }; -/// concrete Buffer class template that implements the elements storage as simple C-array -/// this baby can be copied using default implicit operator and copy ctors -template<class T, uint32_t N> +/// Concrete Buffer class template that implements the element's storage as simple C-array on stack or global memory. +template<typename T, uint32_t N> class BufferOnStack : public Buffer<T,N> { +private: + /// A simple C-array that stores the elements T storage[N]; public: - /// create a Buffe class with storage on stack, static or global. + /// Creates a Buffer class with storage on stack, static or global memory. BufferOnStack():Buffer<T,N>() { Buffer<T,N>::elements=storage; } + /// generic "copy constructor" that does not care about the concrete type of the source Buffer + /// as long as T and N template parameters are identical. + /// Utilizes the assignment operator of the base class. + BufferOnStack(const Buffer<T,N>& buf):Buffer<T,N>() { + Buffer<T,N>::elements=storage; + Buffer<T,N>::operator=(buf); + } + /// The real copy constructor. If this is not defined the compiler rather creates a non working + /// implicit one than using the generic one. + /// Utilizes the assignment operator of the base class. + BufferOnStack(const BufferOnStack& buf):Buffer<T,N>() { + Buffer<T,N>::elements=storage; + Buffer<T,N>::operator=(buf); + } }; -/// concrete Buffer class template that allocates the elements storage on the heap -/// This cannot be copied unless you implement the needed ctor and assignment op -template<class T, uint32_t N> +/// Concrete Buffer class template that allocates the elements storage on the heap. +template<typename T, uint32_t N> class BufferOnHeap : public Buffer<T,N> { public: - /// constructor + /// Creates Buffer with a storage allocated on heap memory BufferOnHeap():Buffer<T,N>() { Buffer<T,N>::elements=new T[N]; } + /// Generic "copy constructor" that does not care about the concrete type of the source Buffer + /// as long as T and N template parameters are identical. + /// Utilizes the assignment operator of the base class. + BufferOnHeap(const Buffer<T,N>& buf):Buffer<T,N>() { + Buffer<T,N>::elements=new T[N]; + Buffer<T,N>::operator=(buf); + } + /// The real copy constructor. If this is not defined the compiler rather creates a non working + /// implicit one than using the generic one. + /// Utilizes the assignment operator of the base class. + BufferOnHeap(const BufferOnHeap& buf):Buffer<T,N>() { + Buffer<T,N>::elements=new T[N]; + Buffer<T,N>::operator=(buf); + } /// destructor virtual ~BufferOnHeap() { delete[] Buffer<T,N>::elements; } +}; -protected: - /// no copy ctor - BufferOnHeap(BufferOnHeap&) {}; - ///no assignment - BufferOnHeap& operator=(BufferOnHeap&) {} -}; +#endif @@ -151,5 +210,3 @@ - -
diff -r bf8fc4455615 -r 8882925900db BufferTest.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/BufferTest.h Fri Mar 29 09:55:05 2013 +0000 @@ -0,0 +1,157 @@ + +#include "Buffer.h" +#include "Serial.h" +using namespace mbed; + +Serial pc(USBTX, USBRX); + +const uint32_t maxSize = 5; + +typedef Buffer<int,maxSize> TstBufB; +typedef BufferOnStack<int,maxSize> TstBufS; +typedef BufferOnHeap<int,maxSize> TstBufH; + +typedef BufferOnHeap<int,maxSize+1> BahBuf; + +void chkBuffer(TstBufB& buf); + +int doit() +{ + pc.baud(115200); + + TstBufS bufs1; + TstBufH bufh1; + + /* + // the following should not even compile + BahBuf bah; + bufs1=bah; + TstBufH no(bah); + + bufs1.push(23); + const TstBufB& cbuf=bufs1; + int& e=cbuf[0]; + + */ + + chkBuffer(bufs1); + pc.printf("happyhappyjoyjoy 1\n"); + chkBuffer(bufh1); + pc.printf("happyhappyjoyjoy 2\n"); + + // copy ctor and assignment + TstBufS bufs; + for(int i=1; i<=23; ++i) bufs.pushCircular(i); + bufs1=bufs; + TstBufS bufs2(bufs1); + bufh1=bufs2; + TstBufH bufh2(bufh1); + TstBufS bufs3(bufh2); + TstBufH bufh3(bufs2); + TstBufS bufs4; + TstBufH bufh4; + bufs4.push(23); + bufh4.push(42); + bufs4=bufh3; + bufh4=bufs3; + + TstBufB* bufA[8]; + bufA[0]=&bufs1; + bufA[1]=&bufs2; + bufA[2]=&bufs3; + bufA[3]=&bufs4; + bufA[4]=&bufh1; + bufA[5]=&bufh2; + bufA[6]=&bufh3; + bufA[7]=&bufh4; + + for(int i=0; i<maxSize; ++i) + for(int j=0; j<8; ++j) { + int v=(*(bufA[j]))[maxSize-1-i]; + if(v!=23-i) pc.printf("copy ouch %d %d %d\n", i,j,v); + } + pc.printf("happyhappyjoyjoy 3\n"); + pc.printf("Test ready!\n"); + + return 0; +} + +void chkBuffer(TstBufB& buf) +{ + + buf.clear(); + // empty buffer checks + if(buf.size()!=0) pc.printf("ouch01\n"); + if(buf.maxSize()!=maxSize) pc.printf("ouch02\n"); + + // fill until full + for(int i=0; i<maxSize; ++i) { + if(!buf.push(i+1)) pc.printf("ouch03\n"); + if(buf.size()!=i+1) pc.printf("ouch04\n"); + } + + // overfill + if(buf.push(12)) pc.printf("ouch05\n"); + if(buf.push(13)) pc.printf("ouch05\n"); + if(buf.size()!=maxSize) pc.printf("ouch06\n"); + + // content check + for(int i=0; i<maxSize; ++i) + if(buf[i]!=i+1)pc.printf("ouch07\n"); + + // pops + if(buf.popLatest()!=maxSize)pc.printf("ouch08\n"); + if(buf.popLatest()!=maxSize-1)pc.printf("ouch09\n"); + if(buf.popOldest()!=1)pc.printf("ouch10\n"); + if(buf.popOldest()!=2)pc.printf("ouch11\n"); + + if(buf.size()!=1) pc.printf("ouch12\n"); + if(buf.popLatest()!=maxSize-2)pc.printf("ouch14\n"); + if(buf.popOldest()!=0)pc.printf("ouch15\n"); + if(buf.popLatest()!=0)pc.printf("ouch16\n"); + if(buf.size()!=0) pc.printf("ouch17\n"); + + // fill until full + for(int i=0; i<maxSize; ++i) { + buf.pushCircular(i+1); + if(buf.size()!=i+1) pc.printf("ouch19\n"); + } + // clear check + buf.clear(); + if(buf.size()!=0) pc.printf("ouch20\n"); + + // fill again + for(int i=0; i<maxSize+1; ++i) { + buf.pushCircular(i+1); + } + if(buf.size()!=maxSize) pc.printf("ouch22\n"); + + if(buf.popOldest()!=2)pc.printf("ouch23\n"); + if(buf.popLatest()!=maxSize+1)pc.printf("ouch24\n"); + if(buf.popLatest()!=maxSize)pc.printf("ouch25\n"); + if(buf.popLatest()!=maxSize-1)pc.printf("ouch26\n"); + + if(buf.size()!=maxSize-4) pc.printf("ouch27\n"); + + // fill revolving + for(int i=maxSize-1; i<=maxSize+3; ++i) { + buf.pushCircular(i); + } + + if(buf.size()!=maxSize) pc.printf("ouch28\n"); + + // content check + for(int i=0; i<maxSize; ++i) + if(buf[maxSize-i-1]!=maxSize+3-i)pc.printf("ouch29\n"); + + // out of bounds + if(buf[4223]!=0)pc.printf("ouch30\n"); + if(buf[maxSize]!=0)pc.printf("ouch33\n"); + + // empty/full + if(!buf.full())pc.printf("ouch34\n"); + if(buf.empty())pc.printf("ouch35\n"); + buf.clear(); + if(buf.full())pc.printf("ouch36\n"); + if(!buf.empty())pc.printf("ouch37\n"); +}