Jamba C++ API 8.0.0
Loading...
Searching...
No Matches
CircularBuffer.h
Go to the documentation of this file.
1/*
2 * Copyright (c) 2018-2019 pongasoft
3 *
4 * Licensed under the Apache License, Version 2.0 or the MIT license,
5 * at your option. You may not use this file except in compliance with
6 * one of these licenses. You may obtain copies of the licenses at:
7 *
8 * https://www.apache.org/licenses/LICENSE-2.0
9 * https://opensource.org/licenses/MIT
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, WITHOUT
13 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14 * License for the specific language governing permissions and limitations under
15 * the License.
16 *
17 * @author Yan Pujante
18 */
19#ifndef __PONGASOFT_UTILS_COLLECTION_CIRCULAR_BUFFER_H__
20#define __PONGASOFT_UTILS_COLLECTION_CIRCULAR_BUFFER_H__
21
22#include <cassert>
23#include <memory>
24#include <concepts>
25
26namespace pongasoft {
27namespace Utils {
28namespace Collection {
29
34template<typename Op, typename U, typename T>
35concept FoldOp =
36 std::invocable<Op, U const&, T const&> &&
37 std::same_as<std::invoke_result_t<Op, U const&, T const&>, U>;
38
43template<typename Op, typename U, typename T>
45 std::invocable<Op, int, U const&, T const&> &&
46 std::same_as<std::invoke_result_t<Op, int, U const&, T const&>, U>;
47
48template<typename T>
50{
51public:
52 explicit CircularBuffer(int iSize) : fSize(iSize), fStart(0)
53 {
54 assert(fSize > 0);
55
56 fBuf = new T[iSize];
57 };
58
59 CircularBuffer(CircularBuffer const& iOther) : fSize(iOther.fSize), fStart(iOther.fStart)
60 {
61 fBuf = new T[fSize];
62 memcpy(fBuf, iOther.fBuf, fSize * sizeof(T));
63 }
64
66 {
67 delete[] fBuf;
68 }
69
70 // handle negative offsets as well
71 int getSize() const
72 {
73 return fSize;
74 }
75
76 T getAt(int offset) const
77 {
78 return fBuf[adjustIndexFromOffset(offset)];
79 }
80
81 void setAt(int offset, T e)
82 {
83 fBuf[adjustIndexFromOffset(offset)] = e;
84 }
85
87 {
89 }
90
91 void push(T e)
92 {
93 setAt(0, e);
95 }
96
97 void init(T initValue)
98 {
99 for(int i = 0; i < fSize; ++i)
100 {
101 fBuf[i] = initValue;
102 }
103 }
104
105 void copyToBuffer(int startOffset, T *oBuffer, int iSize)
106 {
107 int adjStartOffset = adjustIndexFromOffset(startOffset);
108
109 if(adjStartOffset + iSize < fSize)
110 {
111 memcpy(oBuffer, &fBuf[adjStartOffset], iSize * sizeof(T));
112 }
113 else
114 {
115 int i = adjStartOffset;
116 for(int k = 0; k < iSize; k++)
117 {
118 oBuffer[k] = fBuf[i];
119 i++;
120 if(i == fSize)
121 i = 0;
122 }
123 }
124 }
125
126
143 template<typename U, FoldOp<U, T> Op>
144 U fold(int startOffset, int endOffsetNotIncluded, U initValue, Op &op) const
145 {
146 if(startOffset == endOffsetNotIncluded)
147 return initValue;
148
149 U resultValue = initValue;
150
151 int i = adjustIndexFromOffset(startOffset);
152
153 if(startOffset < endOffsetNotIncluded)
154 {
155 int size = endOffsetNotIncluded - startOffset;
156 while(size > 0)
157 {
158 resultValue = std::invoke(op, resultValue, fBuf[i]);
159 ++i;
160 if(i == fSize)
161 i = 0;
162 size--;
163 }
164 }
165 else
166 {
167 int size = startOffset - endOffsetNotIncluded;
168 while(size > 0)
169 {
170 resultValue = std::invoke(op, resultValue, fBuf[i]);
171 --i;
172 if(i == -1)
173 i = fSize - 1;
174 size--;
175 }
176 }
177
178 return resultValue;
179 }
180
184 template<typename U, FoldOp<U, T> Op>
185 U fold(int endOffsetNotIncluded, U initValue, Op &op) const
186 {
187 return fold(0, endOffsetNotIncluded, initValue, op);
188 }
189
193 template<typename U, FoldOp<U, T> Op>
194 U fold(U initValue, Op &op) const
195 {
196 return fold(0, fSize, initValue, op);
197 }
198
204 template<typename U, FoldOpWithIndex<U, T> Op>
205 U foldWithIndex(int startOffset, int endOffsetNotIncluded, U initValue, Op &op) const
206 {
207 if(startOffset == endOffsetNotIncluded)
208 return initValue;
209
210 U resultValue = initValue;
211
212 int i = adjustIndexFromOffset(startOffset);
213 int index = startOffset;
214
215 if(startOffset < endOffsetNotIncluded)
216 {
217 int size = endOffsetNotIncluded - startOffset;
218 while(size > 0)
219 {
220 resultValue = std::invoke(op, index, resultValue, fBuf[i]);
221 ++i;
222 if(i == fSize)
223 i = 0;
224 size--;
225 index++;
226 }
227 }
228 else
229 {
230 int size = startOffset - endOffsetNotIncluded;
231 while(size > 0)
232 {
233 resultValue = std::invoke(op, index, resultValue, fBuf[i]);
234 --i;
235 if(i == -1)
236 i = fSize - 1;
237 size--;
238 index--;
239 }
240 }
241
242 return resultValue;
243 }
244
248 template<typename U, FoldOpWithIndex<U, T> Op>
249 U foldWithIndex(int endOffsetNotIncluded, U initValue, Op &op) const
250 {
251 return foldWithIndex(0, endOffsetNotIncluded, initValue, op);
252 }
253
257 template<typename U, FoldOpWithIndex<U, T> Op>
258 U foldWithIndex(U initValue, Op &op) const
259 {
260 return foldWithIndex(0, fSize, initValue, op);
261 }
262
263private:
264 int adjustIndexFromOffset(int offset) const
265 {
266 if(offset == 0)
267 return fStart;
268
269 return adjustIndex(fStart + offset);
270 }
271
272 int adjustIndex(int index) const
273 {
274 // shortcut since this is a frequent use case
275 if(index == fSize)
276 return 0;
277
278 while(index < 0)
279 index += fSize;
280
281 while(index >= fSize)
282 index -= fSize;
283
284 return index;
285 }
286
287 int fSize;
290};
291
292}
293}
294}
295
296#endif // __PONGASOFT_UTILS_COLLECTION_CIRCULAR_BUFFER_H__
int fStart
Definition CircularBuffer.h:289
U foldWithIndex(int endOffsetNotIncluded, U initValue, Op &op) const
Shortcut with startOffset = 0.
Definition CircularBuffer.h:249
U foldWithIndex(int startOffset, int endOffsetNotIncluded, U initValue, Op &op) const
Similar to fold but Op is also provided the index (starting at startOffset).
Definition CircularBuffer.h:205
int adjustIndexFromOffset(int offset) const
Definition CircularBuffer.h:264
void setAt(int offset, T e)
Definition CircularBuffer.h:81
void copyToBuffer(int startOffset, T *oBuffer, int iSize)
Definition CircularBuffer.h:105
T getAt(int offset) const
Definition CircularBuffer.h:76
int getSize() const
Definition CircularBuffer.h:71
void push(T e)
Definition CircularBuffer.h:91
int adjustIndex(int index) const
Definition CircularBuffer.h:272
U fold(int endOffsetNotIncluded, U initValue, Op &op) const
Shortcut with startOffset 0.
Definition CircularBuffer.h:185
CircularBuffer(CircularBuffer const &iOther)
Definition CircularBuffer.h:59
void incrementHead()
Definition CircularBuffer.h:86
int fSize
Definition CircularBuffer.h:287
U foldWithIndex(U initValue, Op &op) const
Shortcut for entire buffer (starting at startOffset 0).
Definition CircularBuffer.h:258
void init(T initValue)
Definition CircularBuffer.h:97
~CircularBuffer()
Definition CircularBuffer.h:65
U fold(int startOffset, int endOffsetNotIncluded, U initValue, Op &op) const
"standard" implementation of the fold algorithm starting at startOffset and ending at endOffsetNotInc...
Definition CircularBuffer.h:144
CircularBuffer(int iSize)
Definition CircularBuffer.h:52
U fold(U initValue, Op &op) const
Shortcut for entire buffer (starting at startOffset 0).
Definition CircularBuffer.h:194
T * fBuf
Definition CircularBuffer.h:288
Defines the FoldOp concept which is a binary operation that takes two arguments of type U and T and r...
Definition CircularBuffer.h:35
Similar to the FoldOp concept but with an additional index argument.
Definition CircularBuffer.h:44
Definition CircularBuffer.h:28
Definition CircularBuffer.h:27
Definition Clock.h:23