Some useful stuff

Dependents:   FtEncoder FtControlSet

Files at this revision

API Documentation at this revision

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
--- 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 @@
 
 
 
-
-
--- /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");
+}