Created
July 29, 2012 07:09
-
-
Save xstherrera1987/3196485 to your computer and use it in GitHub Desktop.
Generic Circular Buffer and tests, C++
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdexcept> | |
/* | |
T must implement operator=, copy ctor | |
*/ | |
template<typename T> class CircBuf { | |
// don't use default ctor | |
CircBuf(); | |
const int size; | |
T *data; | |
int front; | |
int count; | |
public: | |
CircBuf(int); | |
~CircBuf(); | |
bool empty() { return count == 0; } | |
bool full() { return count == size; } | |
bool add(const T&); | |
bool remove(T*); | |
}; | |
template<typename T> CircBuf<T>::CircBuf(int sz): size(sz) { | |
if (sz==0) throw std::invalid_argument("size cannot be zero"); | |
data = new T[sz]; | |
front = 0; | |
count = 0; | |
} | |
template<typename T> CircBuf<T>::~CircBuf() { | |
delete data; | |
} | |
// returns true if add was successful, false if the buffer is already full | |
template<typename T> bool CircBuf<T>::add(const T &t) { | |
if ( full() ) { | |
return false; | |
} else { | |
// find index where insert will occur | |
int end = (front + count) % size; | |
data[end] = t; | |
count++; | |
return true; | |
} | |
} | |
// returns true if there is something to remove, false otherwise | |
template<typename T> bool CircBuf<T>::remove(T *t) { | |
if ( empty() ) { | |
return false; | |
} else { | |
*t = data[front]; | |
front = front == size ? 0 : front + 1; | |
count--; | |
return true; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
opaque rcv(); | |
for (int i=0; i<size; i++) { | |
if ( c.remove(&rcv)) { | |
.... | |
.... | |
tests.cpp: In function ‘bool opaque_fill_test(int)’: | |
tests.cpp:97:23: error: no matching function for call to ‘CircBuf<opaque>::remove(opaque (*)())’ | |
compilation terminated due to -Wfatal-errors. | |
opaque rcv(); | |
opaque* p = &rcv; | |
for (int i=0; i<size; i++) { | |
if ( c.remove(p)) { | |
... | |
... | |
tests.cpp: In function ‘bool opaque_fill_test(int)’: | |
tests.cpp:96:16: error: cannot convert ‘opaque (*)()’ to ‘opaque*’ in initialization | |
compilation terminated due to -Wfatal-errors. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
FLAGS = -g -ansi -pedantic-errors -Wfatal-errors | |
all: | |
g++ $(FLAGS) tests.cpp -o test | |
clean: | |
rm -rf test |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "CircBuf.h" | |
#include <iostream> | |
#include <stdexcept> | |
#include <vector> | |
#include <cstdlib> | |
using namespace std; | |
// top-level tests | |
bool TEST_fill(); | |
// test utils | |
template <typename T> bool fill_test(int size); | |
int main() { | |
TEST_fill(); | |
return EXIT_SUCCESS; | |
} | |
// OPQSIZE >= sizeof(int) + 1; | |
// 64 bytes is typical cache line size in x86 | |
const int OPQSIZE = 64; | |
struct opaque { | |
int id; | |
char data[OPQSIZE - sizeof(int)]; | |
// not copying data[] should speed up copying many opaque | |
opaque(int n): id(n) {} | |
opaque operator=(const opaque &o) { this->id = o.id; } | |
}; | |
bool TEST_fill() { | |
try { | |
CircBuf<int> inv(0); | |
cout << "fill_test(0) should throw invalid_argument" << endl; | |
return false; | |
} catch (invalid_argument &e) { | |
// do nothing, fill_test(0) should throw invalid_argument | |
} | |
const int increments[] = {64, 32768, 200000, 100000000}; | |
int sz = sizeof(increments) / sizeof(int); | |
for (int i=0; i < sz; i++) { | |
if ( !fill_test<int>( increments[i] ) ) { | |
cout << "fill_test<int>(" << increments[i] << ") failed" << endl; | |
return false; | |
} | |
} | |
for (int i=0; i < sz; i++) { | |
if ( !fill_test<opaque>( increments[i] ) ) { | |
cout << "fill_test<opaque>(" << increments[i] << ") failed" << endl; | |
return false; | |
} | |
} | |
return true; | |
} | |
bool int_fill_test(int size) { | |
CircBuf<int> c(size); | |
for (int i=0; i<size; i++) { | |
if ( !c.add(i) ) { | |
cout << "add fail at i=" << i << endl; | |
return false; | |
} | |
} | |
int rcv = 0; | |
for (int i=0; i<size; i++) { | |
if ( c.remove(&rcv)) { | |
if (rcv != i ) { | |
cout << "wrong value: " << rcv << " " | |
<< "should be: " << i << endl; | |
return false; | |
} | |
} else { | |
cout << "remove fail at i=" << rcv << endl; | |
return false; | |
} | |
} | |
return true; | |
} | |
bool opaque_fill_test(int size) { | |
CircBuf<opaque> c(size); | |
for (int i=0; i<size; i++) { | |
if ( !c.add( opaque(i))) { | |
cout << "add fail at i=" << i << endl; | |
return false; | |
} | |
} | |
opaque rcv(); | |
for (int i=0; i<size; i++) { | |
if ( c.remove(&rcv)) { | |
if (rcv.id != i ) { | |
cout << "wrong value: " << rcv << " " | |
<< "should be: " << i << endl; | |
return false; | |
} | |
} else { | |
cout << "remove fail at i=" << rcv << endl; | |
return false; | |
} | |
} | |
return true; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Nasty bug in line 55 of CircBuf.h. It should be
front = (front ==
size - 1
) ? 0 : front + 1;
. Very good class though!