33 lines
1.2 KiB
C++
33 lines
1.2 KiB
C++
#pragma once
|
|
#include <array>
|
|
#include <atomic>
|
|
#include <cstddef>
|
|
#include <optional>
|
|
|
|
namespace lumi {
|
|
template <typename T, std::size_t Capacity> class bounded_spsc_queue {
|
|
static_assert(Capacity > 1);
|
|
std::array<T, Capacity> values_{};
|
|
alignas(64) std::atomic<std::size_t> head_{0};
|
|
alignas(64) std::atomic<std::size_t> tail_{0};
|
|
std::atomic<std::uint64_t> dropped_{0};
|
|
public:
|
|
bool try_push(T value) noexcept {
|
|
const auto head = head_.load(std::memory_order_relaxed);
|
|
const auto next = (head + 1) % Capacity;
|
|
if (next == tail_.load(std::memory_order_acquire)) { dropped_.fetch_add(1, std::memory_order_relaxed); return false; }
|
|
values_[head] = std::move(value);
|
|
head_.store(next, std::memory_order_release);
|
|
return true;
|
|
}
|
|
std::optional<T> try_pop() noexcept {
|
|
const auto tail = tail_.load(std::memory_order_relaxed);
|
|
if (tail == head_.load(std::memory_order_acquire)) return std::nullopt;
|
|
T value = std::move(values_[tail]);
|
|
tail_.store((tail + 1) % Capacity, std::memory_order_release);
|
|
return value;
|
|
}
|
|
std::uint64_t dropped() const noexcept { return dropped_.load(std::memory_order_relaxed); }
|
|
};
|
|
}
|