Created
September 3, 2011 20:02
-
-
Save afeinberg/1191700 to your computer and use it in GitHub Desktop.
This file contains hidden or 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> | |
#include <iostream> | |
#include "circular_buffer.h" | |
/* | |
Valgrind output: | |
alex@mars:~/dev/circular-buffer$ valgrind --leak-check=yes ./circular_buffer_test | |
==21141== Memcheck, a memory error detector | |
==21141== Copyright (C) 2002-2010, and GNU GPL'd, by Julian Seward et al. | |
==21141== Using Valgrind-3.6.1 and LibVEX; rerun with -h for copyright info | |
==21141== Command: ./circular_buffer_test | |
==21141== | |
TestEmpty...Passed! | |
TestBuffer...Passed! | |
==21141== | |
==21141== HEAP SUMMARY: | |
==21141== in use at exit: 0 bytes in 0 blocks | |
==21141== total heap usage: 4 allocs, 4 frees, 208 bytes allocated | |
==21141== | |
==21141== All heap blocks were freed -- no leaks are possible | |
==21141== | |
==21141== For counts of detected and suppressed errors, rerun with: -v | |
==21141== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 4 from 4) | |
*/ | |
using af::CircularBuffer; | |
static const int capacity_ = 16; | |
static CircularBuffer<int>* buff_; | |
struct AssertionFailed: std::exception { | |
char const* what() const throw() { | |
return "assertion failed!"; | |
} | |
}; | |
#define TEST_ASSERT TestAssert | |
static inline void TestAssert(bool assertion, const char *msg) { | |
if (!assertion) { | |
std::cerr << msg << std::endl; | |
throw AssertionFailed(); | |
} | |
} | |
static inline void Setup() { | |
buff_ = new CircularBuffer<int>(capacity_); | |
} | |
static inline void Teardown() { | |
delete buff_; | |
} | |
static inline void RunTest(const char *name, void (*test) (void)) { | |
std::cout << name << "..."; | |
Setup(); | |
try { | |
test(); | |
std::cout << "Passed!"; | |
} catch (AssertionFailed const& e) { | |
std::cout << "Failed!"; | |
} | |
std::cout << std::endl; | |
Teardown(); | |
} | |
void TestEmpty() { | |
TEST_ASSERT(buff_->IsEmpty(), "empty buffer is empty"); | |
buff_->PushBack(1); | |
TEST_ASSERT(buff_->IsEmpty() == false, "not empty buffer is not empty"); | |
} | |
void TestBuffer() { | |
int front; | |
int i; | |
// Basic Tests | |
TEST_ASSERT(buff_->Front(front) == false, "Front() on an empty buffer is false"); | |
buff_->PushBack(123); | |
TEST_ASSERT(buff_->Front(front) == true, "Front() on buffer with elt is true"); | |
TEST_ASSERT(front == 123, "front is correct"); | |
TEST_ASSERT(buff_->PopFront() == true, "PopFront() is true when buffer has elts"); | |
TEST_ASSERT(buff_->PopFront() == false, "PopFront() is false when buffer empty"); | |
// Fill the buffer | |
for (i = 0; i < capacity_ + capacity_ / 2; ++i) { | |
buff_->PushBack(i); | |
} | |
TEST_ASSERT(buff_->Front(front) == true, "buffer overflows #1"); | |
TEST_ASSERT(front == capacity_, "buffer overflows #2"); | |
} | |
int main(int argc, char **argv) { | |
RunTest("TestEmpty", TestEmpty); | |
RunTest("TestBuffer", TestBuffer); | |
return 0; | |
} |
This file contains hidden or 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
#ifndef CIRCULAR_BUFFER_H_ | |
#define CIRCULAR_BUFFER_H_ | |
#include <cstdlib> | |
#include <cassert> | |
namespace af { | |
template<typename T> | |
class CircularBuffer { | |
public: | |
explicit CircularBuffer(size_t size); | |
virtual ~CircularBuffer(); | |
void PushBack(const T& t); | |
bool IsEmpty() const; | |
bool PopFront(); | |
bool Front(T& t) const; | |
private: | |
size_t write_idx_; | |
size_t read_idx_; | |
size_t size_; | |
T* buffer_; | |
}; | |
template<typename T> | |
CircularBuffer<T>::CircularBuffer(size_t size) | |
: write_idx_(0), | |
read_idx_(0), | |
size_(size) { | |
buffer_ = static_cast<T*>(calloc(size_, sizeof(T))); | |
assert(buffer_ != NULL); | |
} | |
template<typename T> | |
CircularBuffer<T>::~CircularBuffer() { | |
free(buffer_); | |
} | |
template<typename T> | |
void CircularBuffer<T>::PushBack(const T& t) { | |
T* new_t = new (&buffer_[write_idx_]) T; | |
*new_t = t; | |
write_idx_++; | |
write_idx_ %= size_; | |
} | |
template<typename T> | |
inline bool CircularBuffer<T>::IsEmpty() const { | |
return read_idx_ == write_idx_; | |
} | |
template<typename T> | |
bool CircularBuffer<T>::PopFront() { | |
bool ret = false; | |
if (!IsEmpty()) { | |
ret = true; | |
read_idx_++; | |
read_idx_ %= size_; | |
} | |
return ret; | |
} | |
template<typename T> | |
bool CircularBuffer<T>::Front(T &t) const { | |
bool ret = false; | |
if (!IsEmpty()) { | |
ret = true; | |
t = buffer_[read_idx_]; | |
} | |
return ret; | |
} | |
} | |
#endif // CIRCULAR_BUFFER_H_ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment