Skip to content

Instantly share code, notes, and snippets.

@engelmarkus
Created April 21, 2016 00:04
Show Gist options
  • Save engelmarkus/a06c4ad432e1ef2ba6b134f9bb5cd06a to your computer and use it in GitHub Desktop.
Save engelmarkus/a06c4ad432e1ef2ba6b134f9bb5cd06a to your computer and use it in GitHub Desktop.
Example implementation for a simple ring buffer.
#include <array>
#include <cstdint>
#include <iostream>
#include <stdexcept>
using namespace std;
template <unsigned long long n>
constexpr auto count_set_bits = (n & 1) + count_set_bits<(n >> 1)>;
template <>
constexpr auto count_set_bits<0ull> = 0;
template <unsigned long long n>
constexpr auto is_power_of_two = count_set_bits<n> == 1;
namespace BufferBehavior {
template <typename Buffer>
struct Throw {
Throw(Buffer& buffer) : buffer{buffer} {}
Buffer& buffer;
typename Buffer::value_type operator()() {
throw runtime_error {
string("Error accessing buffer: Capacity: ") +
to_string(buffer.capacity()) + "; Size: " + to_string(buffer.size())
};
return typename Buffer::value_type{};
}
};
template <typename Buffer>
struct RemoveOldestElement {
RemoveOldestElement(Buffer& buffer) : buffer{buffer} {}
void operator()() {
buffer.pop();
}
Buffer& buffer;
};
template <typename Buffer>
struct ReturnDefault {
ReturnDefault(Buffer&) {}
typename Buffer::value_type operator()() {
return typename Buffer::value_type();
}
};
}
template <
typename T, size_t Capacity = 16,
template <typename> typename EmptyBehavior = BufferBehavior::Throw,
template <typename> typename FullBehavior = EmptyBehavior
>
class Buffer {
public:
using value_type = T;
using reference = T&;
using this_type = Buffer<T, Capacity, EmptyBehavior, FullBehavior>;
Buffer()
: buf { 0 }
, first { 0 }
, last { 0 }
, emptyBehavior { *this }
, fullBehavior { *this }
{
static_assert(is_power_of_two<Capacity>, "Capacity of type Buffer must be a power of two.");
}
bool isFull() const {
return last == (first ^ Capacity);
}
bool isEmpty() const {
return last == first;
}
value_type pop() {
if (isEmpty()) {
return emptyBehavior();
}
reference r = buf[first % Capacity];
incrementIterator(first);
return r;
}
void push(value_type elem) {
if (isFull()) {
fullBehavior();
}
buf[last % Capacity] = elem;
incrementIterator(last);
}
size_t size() const {
return last - first;
}
static constexpr size_t capacity() {
return Capacity;
}
private:
array<T, Capacity> buf;
size_t first, last;
EmptyBehavior<this_type> emptyBehavior;
FullBehavior<this_type> fullBehavior;
inline void incrementIterator(size_t& it) {
it = (it + 1) % (2 * Capacity);
}
};
int main() {
Buffer<
uint32_t, 16,
BufferBehavior::Throw, BufferBehavior::RemoveOldestElement
> buffer;
cout << "Size: " << buffer.size() << endl;
buffer.push(13);
cout << "Size: " << buffer.size() << endl;
buffer.push(37);
cout << "Size: " << buffer.size() << endl;
cout << buffer.pop() << "; "; cout << buffer.pop() << endl;
cout << "Size: " << buffer.size() << endl;
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment