Toolbox snapshot
The Reactive C++ Toolbox
Loading...
Searching...
No Matches
RingBuffer.hpp
Go to the documentation of this file.
1// The Reactive C++ Toolbox.
2// Copyright (C) 2013-2019 Swirly Cloud Limited
3// Copyright (C) 2021 Reactive Markets Limited
4//
5// Licensed under the Apache License, Version 2.0 (the "License");
6// you may not use this file except in compliance with the License.
7// You may obtain a copy of the License at
8//
9// http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing, software
12// distributed under the License is distributed on an "AS IS" BASIS,
13// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14// See the License for the specific language governing permissions and
15// limitations under the License.
16
17#ifndef TOOLBOX_UTIL_RINGBUFFER_HPP
18#define TOOLBOX_UTIL_RINGBUFFER_HPP
19
20#include <toolbox/util/Math.hpp>
21
22#include <memory>
23
24namespace toolbox {
25inline namespace util {
26
27template <typename ValueT>
29 public:
30 explicit RingBuffer(std::size_t capacity)
31 : capacity_{next_pow2(capacity)}
32 , mask_{capacity_ - 1}
33 , buf_{new ValueT[capacity_]}
34 {
35 }
36 ~RingBuffer() = default;
37
38 // Copy.
39 RingBuffer(const RingBuffer&) = delete;
40 RingBuffer& operator=(const RingBuffer&) = delete;
41
42 // Move.
45
47 bool empty() const noexcept { return rpos_ == wpos_; }
49 bool full() const noexcept { return size() == capacity_; }
51 std::size_t available() const noexcept { return capacity_ - size(); }
54 std::size_t capacity() const noexcept { return wpos_ - rpos_; }
57 std::size_t max_size() const noexcept { return capacity(); }
59 std::size_t size() const noexcept { return wpos_ - rpos_; }
60 const ValueT& front() const noexcept { return buf_[rpos_ & mask_]; }
61 const ValueT& back() const noexcept { return buf_[(wpos_ - 1) & mask_]; }
62
63 ValueT& front() noexcept { return buf_[rpos_ & mask_]; }
64 ValueT& back() noexcept { return buf_[(wpos_ - 1) & mask_]; }
65 void clear() noexcept { rpos_ = wpos_ = 0; }
66 void pop() noexcept { ++rpos_; }
67 void push(const ValueT& val)
68 {
69 auto& ref = buf_[wpos_ & mask_];
70 ref = val;
71 if (full()) {
72 ++rpos_;
73 }
74 ++wpos_;
75 }
76 template <typename FnT>
77 void fetch(FnT fn)
78 {
79 const auto& ref = buf_[rpos_ & mask_];
80 fn(ref);
81 ++rpos_;
82 }
83 template <typename FnT>
84 void write(FnT fn)
85 {
86 auto& ref = buf_[wpos_ & mask_];
87 fn(ref);
88 if (full()) {
89 ++rpos_;
90 }
91 ++wpos_;
92 }
93
94 private:
95 // Ensure that read and write positions are in different cache-lines.
96 struct alignas(64) {
97 std::size_t capacity_;
98 std::size_t mask_;
99 uint64_t rpos_{0};
100 };
101 uint64_t wpos_{0};
102 std::unique_ptr<ValueT[]> buf_;
103};
104
105} // namespace util
106} // namespace toolbox
107
108#endif // TOOLBOX_UTIL_RINGBUFFER_HPP
RingBuffer(RingBuffer &&) noexcept=default
std::size_t max_size() const noexcept
RingBuffer & operator=(const RingBuffer &)=delete
const ValueT & back() const noexcept
bool full() const noexcept
Returns true if the container is full.
void push(const ValueT &val)
RingBuffer(std::size_t capacity)
ValueT & front() noexcept
std::size_t size() const noexcept
Returns true if the number of elements in the container.
ValueT & back() noexcept
std::size_t capacity() const noexcept
const ValueT & front() const noexcept
RingBuffer(const RingBuffer &)=delete
bool empty() const noexcept
Returns true if the container is empty.
std::size_t available() const noexcept
Returns the number of available elements.
unsigned next_pow2(unsigned n) noexcept
Definition Math.hpp:35
constexpr auto bind() noexcept
Definition Slot.hpp:92