Skyward boardcore
Loading...
Searching...
No Matches
CircularBuffer.h
Go to the documentation of this file.
1/* Copyright (c) 2015-2018 Skyward Experimental Rocketry
2 * Authors: Luca Erbetta, Davide Mor
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to deal
6 * in the Software without restriction, including without limitation the rights
7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 * copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 * THE SOFTWARE.
21 */
22
23#pragma once
24
25#include <cstring>
26#include <stdexcept>
27#include <type_traits>
28
29using std::range_error;
30
31namespace Boardcore
32{
33
37template <typename T, unsigned int Size>
39{
40 static_assert(Size > 0, "Circular buffer size must be greater than 0!");
41
42public:
44
45 virtual ~CircularBuffer() {}
46
53 T& put(const T& elem)
54 {
55 buffer[writePtr] = elem;
56 T& added = buffer[writePtr];
57
58 // Advance the read pointer if the two pointers match
59 if (!empty && writePtr == readPtr)
60 readPtr = (readPtr + 1) % Size;
61
62 // Advance the write pointer
63 writePtr = (writePtr + 1) % Size;
64
65 empty = false;
66
67 return added;
68 }
69
81 T& get(unsigned int i = 0)
82 {
83 // Here we need to explicitly specify the name of this class because we
84 // DO NOT want to call the version of count() overridden by a derived
85 // class: this is done to avoid deadlocks, as a derived class may
86 // synchronize get() and count() with a mutex: calling count() from
87 // get() would thus require locking the same mutex twice, causing a
88 // deadlock.
90 {
91 int ptr = (readPtr + i) % Size;
92 return buffer[ptr];
93 }
94 else
95 {
96 throw range_error("Circular buffer index out of range");
97 }
98 }
99
107 T& last() { return get(count() - 1); }
108
116 const T& pop()
117 {
118 if (!empty)
119 {
120 size_t ptr = readPtr;
121 readPtr = (readPtr + 1) % Size;
122
124
125 return buffer[ptr];
126 }
127 else
128 {
129 throw range_error("Circular buffer is empty!");
130 }
131 }
132
138 size_t count() const
139 {
140 if (empty)
141 return 0;
142 if (writePtr > readPtr)
143 return writePtr - readPtr;
144 else
145 return Size - readPtr + writePtr;
146 }
147
148 bool isEmpty() const { return empty; }
149
150 bool isFull() const
151 {
152 // Same as in get(): explicitly specify the name of the class to avoid
153 // deadlocks!
155 }
162 size_t getSize() const { return Size; }
163
164protected:
166
167 size_t writePtr = 0;
168 size_t readPtr = 0;
169 bool empty = true;
170};
171
172} // namespace Boardcore
T & put(const T &elem)
Puts a copy of the element in the buffer.
size_t getSize() const
Returns the maximum number of elements that can be stored in the buffer.
T & last()
Returns the last element added in the buffer.
size_t count() const
Counts the elements in the buffer.
const T & pop()
Pops the first element in the buffer.
T & get(unsigned int i=0)
Gets an element from the buffer, without removing it.
This file includes all the types the logdecoder script will decode.