Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
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 |
--- 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");
+}