Extra2D/Extra2D/include/extra2d/core/ring_buffer.h

104 lines
2.8 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#pragma once
#include <extra2d/core/types.h>
#include <atomic>
#include <array>
namespace extra2d {
/**
* @brief 无锁环形缓冲区(单生产者单消费者)
* @tparam T 元素类型
* @tparam Size 缓冲区大小必须是2的幂
*/
template <typename T, size_t Size>
class RingBuffer {
static_assert((Size & (Size - 1)) == 0, "Size must be a power of 2");
public:
RingBuffer() = default;
/**
* @brief 入队
* @param item 元素
* @return 成功返回true缓冲区满返回false
*/
bool push(const T& item) {
const size_t currentHead = head_.load(std::memory_order_relaxed);
const size_t currentTail = tail_.load(std::memory_order_acquire);
if ((currentHead - currentTail) >= Size) {
return false; // 缓冲区满
}
buffer_[currentHead & mask_] = item;
head_.store(currentHead + 1, std::memory_order_release);
return true;
}
/**
* @brief 入队(移动语义)
* @param item 元素
* @return 成功返回true缓冲区满返回false
*/
bool push(T&& item) {
const size_t currentHead = head_.load(std::memory_order_relaxed);
const size_t currentTail = tail_.load(std::memory_order_acquire);
if ((currentHead - currentTail) >= Size) {
return false; // 缓冲区满
}
buffer_[currentHead & mask_] = std::move(item);
head_.store(currentHead + 1, std::memory_order_release);
return true;
}
/**
* @brief 出队
* @param item 输出元素
* @return 成功返回true缓冲区空返回false
*/
bool pop(T& item) {
const size_t currentTail = tail_.load(std::memory_order_relaxed);
const size_t currentHead = head_.load(std::memory_order_acquire);
if (currentTail == currentHead) {
return false; // 缓冲区空
}
item = std::move(buffer_[currentTail & mask_]);
tail_.store(currentTail + 1, std::memory_order_release);
return true;
}
/**
* @brief 检查是否为空
*/
bool empty() const {
return head_.load(std::memory_order_acquire) ==
tail_.load(std::memory_order_acquire);
}
/**
* @brief 获取当前大小
*/
size_t size() const {
return head_.load(std::memory_order_acquire) -
tail_.load(std::memory_order_acquire);
}
/**
* @brief 获取容量
*/
static constexpr size_t capacity() { return Size; }
private:
static constexpr size_t mask_ = Size - 1;
alignas(64) std::array<T, Size> buffer_;
alignas(64) std::atomic<size_t> head_{0};
alignas(64) std::atomic<size_t> tail_{0};
};
} // namespace extra2d