-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcircularbuffer.hpp
184 lines (158 loc) · 5.26 KB
/
circularbuffer.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
/*
* MIT License (MIT)
*
* Copyright (c) 2019 Kristian Kinderlöv
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/**
* @addtogroup CIRCULARBUFFER
* @ingroup MISC
* @{
*
* @file circularbuffer.hpp
*
* @brief A Circular buffer template class.
*
* The implementation uses std::unique_ptr for automatically delete the
* allocated dynamic memory when it not used anymore. For thread safety
* std::mutex is used. Its require C++ latest revison 2011.
*/
#ifndef CIRCULARBUFFER_H_
#define CIRCULARBUFFER_H_
#include <memory>
#include <mutex>
template <class T>
class circular_buffer {
public:
/**
* @brief The circular buffer constructor.
*
* @param[in] num Total number of elements that the circular buffer
* can hold.
*/
explicit circular_buffer(size_t num) : buf_(std::unique_ptr<T[]>(new T[num])), max_(num) {
// Do nothing.
}
/**
* @brief The circular buffer destructor.
*/
virtual ~circular_buffer() {
// Do nothing.
}
/**
* @brief Removes all elements from the circular buffer.
*/
void clear(void) {
std::lock_guard<std::mutex> lock(mutex_);
write_pos_ = 0;
read_pos_ = 0;
count_ = 0;
}
/**
* @brief Adds a new element at the end of the buffer. The "val" content is
* copied to the element.
*
* @param[in] val Const reference to the source to be copied.
* @return True if success, false if the buffer is full.
*/
bool push_back(const T &val) {
std::lock_guard<std::mutex> lock(mutex_);
// Check if buffer is full
if (count_ == max_) {
return false;
}
buf_[write_pos_] = val;
write_pos_ = (write_pos_ + 1) % max_;
++count_;
return true;
};
/**
* @brief Removes the first element from the buffer. Copies the element
* content to the "val" destination.
*
* @param[out] val Reference to the destination where the data is to be
* stored.
* @return True if success, false if the buffer is
* empty.
*/
bool pop_front(T &val) {
std::lock_guard<std::mutex> lock(mutex_);
// Check if empty buffer
if (count_ == 0) {
return false;
}
val = buf_[read_pos_];
read_pos_ = (read_pos_ + 1) % max_;
--count_;
return true;
};
/**
* @brief Peeks the "num" element from the buffer.
*
* The "num" argument shall be less than the number of elements added to
* the buffer.
*
* @param[in] num The number of the element to peek.
* @param[out] elem Pointer to reference to the "num" element.
* @return True if success, false if the buffer is empty or the
* "num" is out of bound.
*/
bool peek(size_t num, T *&elem) {
std::lock_guard<std::mutex> lock(mutex_);
// Check if empty buffer
if (count_ == 0) {
return false;
}
// Check if index is out of bounds
if (num >= count_) {
return false;
}
auto peek_pos = (read_pos_ + num) % max_;
elem = (buf_.get() + peek_pos);
return true;
};
/**
* @brief Gets the number of added elements in the buffer.
*
* @return The number of added elements.
*/
size_t count() const { return count_; };
/**
* @brief Gets the number of free elements in the buffer.
*
* @return The number of free elements.
*/
size_t space() const { return (max_ - count_); };
/**
* @brief Checks if the buffer is empty.
*
* @return True if the buffer is empty otherwise false.
*/
bool empty() const { return (count_ == 0); };
private:
std::mutex mutex_;
std::unique_ptr<T[]> buf_; // Pointer to the buffer
size_t write_pos_ = 0; // Write pointer
size_t read_pos_ = 0; // Read pointer
size_t count_ = 0; // Number of added elements in the buffer
const size_t max_; // Max Number of elements in the buffer
};
#endif /* CIRCULARBUFFER_H_ */
/** @} */