Skip to content

Instantly share code, notes, and snippets.

@xstherrera1987
Created July 29, 2012 07:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save xstherrera1987/3196485 to your computer and use it in GitHub Desktop.
Save xstherrera1987/3196485 to your computer and use it in GitHub Desktop.
Generic Circular Buffer and tests, C++
#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;
}
}
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.
FLAGS = -g -ansi -pedantic-errors -Wfatal-errors
all:
g++ $(FLAGS) tests.cpp -o test
clean:
rm -rf test
#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;
}
@nistath
Copy link

nistath commented Jun 12, 2018

Nasty bug in line 55 of CircBuf.h. It should be front = (front == size - 1) ? 0 : front + 1;. Very good class though!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment