Easy Navigation
Loading...
Searching...
No Matches
CircularBuffer.hpp
Go to the documentation of this file.
1// Copyright 2025 Intelligent Robotics Lab
2//
3// This file is part of the project Easy Navigation (EasyNav in short)
4// licensed under the GNU General Public License v3.0.
5// See <http://www.gnu.org/licenses/> for details.
6//
7// Easy Navigation program is free software: you can redistribute it and/or modify
8// it under the terms of the GNU General Public License as published by
9// the Free Software Foundation, either version 3 of the License, or
10// (at your option) any later version.
11//
12// This program is distributed in the hope that it will be useful,
13// but WITHOUT ANY WARRANTY; without even the implied warranty of
14// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15// GNU General Public License for more details.
16//
17// You should have received a copy of the GNU General Public License
18// along with this program. If not, see <http://www.gnu.org/licenses/>.
19
20#ifndef EASYNAV_COMMON__CIRCULARBUFFER_HPP_
21#define EASYNAV_COMMON__CIRCULARBUFFER_HPP_
22
23#include <vector>
24#include <mutex>
25#include <cstddef>
26
27namespace easynav
28{
29
36template<typename T>
38{
39public:
41 explicit CircularBuffer(std::size_t capacity)
42 : buffer_(capacity),
43 capacity_(capacity),
44 head_(0),
45 tail_(0),
46 size_(0)
47 {
48 }
49
55 : buffer_(other.capacity_),
56 capacity_(other.capacity_),
57 head_(0),
58 tail_(0),
59 size_(0)
60 {
61 std::lock_guard<std::mutex> lock(other.mutex_);
62 buffer_ = other.buffer_;
63 head_ = other.head_;
64 tail_ = other.tail_;
65 size_ = other.size_;
66 }
67
70 {
71 if (this == &other) {
72 return *this;
73 }
74
75 // Lock both mutexes in a deadlock-safe way.
76 std::scoped_lock<std::mutex, std::mutex> lock(mutex_, other.mutex_);
77
78 capacity_ = other.capacity_;
79 buffer_ = other.buffer_;
80 head_ = other.head_;
81 tail_ = other.tail_;
82 size_ = other.size_;
83 return *this;
84 }
85
90
92 std::size_t capacity() const noexcept
93 {
94 return capacity_;
95 }
96
98 std::size_t size() const noexcept
99 {
100 std::lock_guard<std::mutex> lock(mutex_);
101 return size_;
102 }
103
105 bool empty() const noexcept
106 {
107 std::lock_guard<std::mutex> lock(mutex_);
108 return size_ == 0;
109 }
110
112 bool full() const noexcept
113 {
114 std::lock_guard<std::mutex> lock(mutex_);
115 return size_ == capacity_;
116 }
117
119 void clear() noexcept
120 {
121 std::lock_guard<std::mutex> lock(mutex_);
122 head_ = 0;
123 tail_ = 0;
124 size_ = 0;
125 }
126
128 void push(const T & value)
129 {
130 std::lock_guard<std::mutex> lock(mutex_);
131 buffer_[head_] = value;
132 advance_head_();
133 }
134
136 void push(T && value)
137 {
138 std::lock_guard<std::mutex> lock(mutex_);
139 buffer_[head_] = std::move(value);
140 advance_head_();
141 }
142
147 bool pop(T & out)
148 {
149 std::lock_guard<std::mutex> lock(mutex_);
150 if (size_ == 0) {
151 return false;
152 }
153
154 out = buffer_[tail_];
155 tail_ = (tail_ + 1) % capacity_;
156 --size_;
157 return true;
158 }
159
164 bool latest(T & out) const
165 {
166 std::lock_guard<std::mutex> lock(mutex_);
167 if (size_ == 0) {
168 return false;
169 }
170
171 const std::size_t newest_index =
172 (head_ + capacity_ - 1) % capacity_;
173 out = buffer_[newest_index];
174 return true;
175 }
176
178 const T & latest_ref() const
179 {
180 std::lock_guard<std::mutex> lock(mutex_);
181
182 const std::size_t newest_index =
183 (head_ + capacity_ - 1) % capacity_;
184 return buffer_[newest_index];
185 }
186
187 // DEBUG ONLY: raw access to slots
189 {
191 const T & value;
192 };
193
194 DebugSlotView raw_slot(std::size_t idx) const
195 {
196 if (!buffer_[idx].engaged) {
197 // dummy static empty
198 static T dummy{};
199 static const DebugSlotView empty{false, dummy};
200 return empty;
201 }
202 return DebugSlotView{true, buffer_[idx].storage};
203 }
204
205private:
207 void advance_head_()
208 {
209 head_ = (head_ + 1) % capacity_;
210 if (size_ < capacity_) {
211 ++size_;
212 } else {
213 // Buffer is full, we overwrite the oldest element.
214 tail_ = (tail_ + 1) % capacity_;
215 }
216 }
217
218 mutable std::mutex mutex_;
219 std::vector<T> buffer_;
220 std::size_t capacity_;
221 std::size_t head_; // next position to write
222 std::size_t tail_; // next position to read
223 std::size_t size_; // number of valid elements
224};
225
226} // namespace easynav
227
228#endif // EASYNAV_COMMON__CIRCULARBUFFER_HPP_
void clear() noexcept
Remove all elements, keeping the allocated storage.
Definition CircularBuffer.hpp:119
void push(T &&value)
Push a new element (move). Overwrites the oldest if the buffer is full.
Definition CircularBuffer.hpp:136
const T & latest_ref() const
Get a const reference to the newest element without removing it.
Definition CircularBuffer.hpp:178
bool empty() const noexcept
True if the buffer is empty.
Definition CircularBuffer.hpp:105
std::size_t size() const noexcept
Current number of valid elements.
Definition CircularBuffer.hpp:98
CircularBuffer(std::size_t capacity)
Construct a buffer with the given capacity.
Definition CircularBuffer.hpp:41
void push(const T &value)
Push a new element (copy). Overwrites the oldest if the buffer is full.
Definition CircularBuffer.hpp:128
DebugSlotView raw_slot(std::size_t idx) const
Definition CircularBuffer.hpp:194
bool latest(T &out) const
Get a copy of the newest element without removing it.
Definition CircularBuffer.hpp:164
bool pop(T &out)
Pop the oldest element.
Definition CircularBuffer.hpp:147
CircularBuffer & operator=(CircularBuffer &&)=delete
CircularBuffer & operator=(const CircularBuffer &other)
Copy assignment.
Definition CircularBuffer.hpp:69
std::size_t capacity() const noexcept
Maximum number of elements that can be stored.
Definition CircularBuffer.hpp:92
bool full() const noexcept
True if the buffer is full.
Definition CircularBuffer.hpp:112
CircularBuffer(CircularBuffer &&)=delete
Move operations are optional.
CircularBuffer(const CircularBuffer &other)
Copy constructor.
Definition CircularBuffer.hpp:54
Definition CircularBuffer.hpp:28
Definition CircularBuffer.hpp:189
const T & value
Definition CircularBuffer.hpp:191
bool has_value
Definition CircularBuffer.hpp:190