Files
tactileipc3d/src/ringbuffer.h

82 lines
2.1 KiB
C++

#ifndef RINGBUFFER_H
#define RINGBUFFER_H
#include <cstddef>
#include <iostream>
#include <vector>
#include <atomic>
#include <algorithm>
#include <cstdint>
#include <type_traits>
template<typename T>
class RingBuffer {
public:
explicit RingBuffer(size_t capacity, T initValue = T{})
: m_capacity(capacity)
, m_data(capacity, initValue) {}
inline void push(const T& v) {
const uint64_t w = m_write.fetch_add(1, std::memory_order_relaxed);
m_data[w % m_capacity] = v;
const uint64_t newSize = std::min<uint64_t>(w + 1, m_capacity);
m_size.store(newSize, std::memory_order_release);
}
inline uint64_t size() const {
return m_size.load(std::memory_order_acquire);
}
inline uint64_t capacity() const {
return m_capacity;
}
inline uint64_t oldestGlobalIndex() const {
const uint64_t w = m_write.load(std::memory_order_acquire);
const uint64_t s = size();
return (w >= s) ? (w - s) : 0;
}
inline uint64_t newestGlobalIndex() const {
const uint64_t w = m_write.load(std::memory_order_acquire);
return (w > 0) ? (w - 1) : 0;
}
inline bool readByGlobalIndex(uint64_t gidx, T& out) const {
const uint64_t oldest = oldestGlobalIndex();
const uint64_t newest = newestGlobalIndex();
if (gidx < oldest || gidx > newest)
return false;
out = m_data[gidx % m_capacity];
return true;
}
inline void reset() {
m_write.store(0, std::memory_order_release);
m_size.store(0, std::memory_order_release);
}
inline void readRange(uint64_t gidx, uint64_t count, std::vector<T>& out) const {
out.clear();
out.reserve(count);
for (size_t i = 0; i < count; i++) {
T v{};
if (readByGlobalIndex(gidx, v)) {
out.push_back(v);
}
else {
}
}
}
private:
uint64_t m_capacity;
std::vector<T> m_data;
std::atomic<uint64_t> m_write{0};
std::atomic<uint64_t> m_size{0};
};
#endif