forked from GPUOpen-Tools/gpu_performance_api
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcircular_buffer.h
404 lines (352 loc) · 10.5 KB
/
circular_buffer.h
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
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
//==============================================================================
// Copyright (c) 2016-2021 Advanced Micro Devices, Inc. All rights reserved.
/// @author AMD Developer Tools Team
/// @file
/// @brief A circular buffer that can store objects of a templated type.
//==============================================================================
#ifndef GPU_PERF_API_COMMON_CIRCULAR_BUFFER_H_
#define GPU_PERF_API_COMMON_CIRCULAR_BUFFER_H_
#include <assert.h>
#ifdef _LINUX
#include <cstddef>
#endif
/// @brief A circular buffer that can store objects of a templated type.
template <class T>
class CircularBuffer
{
public:
/// @brief Initializes a new instance of the CircularBuffer<T> class.
CircularBuffer()
{
array_ = nullptr;
Initialize();
}
/// @brief Deletes the underlying array.
~CircularBuffer()
{
delete[] array_;
}
/// @brief Constructor which initializes its members from another circular buffer.
///
/// @param [in] obj The circular buffer to copy.
CircularBuffer(const CircularBuffer<T>& obj)
{
if (obj.GetSize() == 0)
{
array_ = nullptr;
}
else
{
array_ = new (std::nothrow) T[obj.GetSize()];
if (nullptr != array_)
{
for (int i = 0; i < static_cast<int>(obj.GetSize()); i++)
{
array_[i] = obj.get(i);
}
}
}
head_index_ = obj.GetHeadIndex();
tail_index_ = obj.GetTailIndex();
size_ = obj.GetSize(); // Maximum number of elements in the buffer at any one time.
count_ = obj.GetCount(); // Current number of elements in the buffer.
}
/// @brief Equal operator.
///
/// @param [in] obj The source circular buffer.
///
/// @return This object is updated based on the values of the source buffer.
CircularBuffer<T>& operator=(const CircularBuffer<T>& obj)
{
// Assignment means data copy of array.
delete[] array_;
array_ = new (std::nothrow) T[obj.GetSize()];
if (nullptr != array_)
{
for (int i = 0; i < static_cast<int>(obj.GetSize()); i++)
{
array_[i] = obj.get(i);
}
}
return (*this);
}
/// @brief Clears the circular buffer.
void Clear()
{
delete[] array_;
array_ = nullptr;
Initialize();
}
/// @brief Initializes the buffer.
void Initialize()
{
head_index_ = 0;
tail_index_ = 0;
size_ = 0;
count_ = 0;
}
/// @brief Sets the size of the circular buffer.
///
/// Needs to be called before using the buffer.
///
/// @param [in] size The number of objects this circular buffer should be capable of holding.
///
/// @return True if the size could be set, false otherwise.
bool SetSize(unsigned int size)
{
bool ret_val = false;
Initialize();
delete[] array_;
array_ = new (std::nothrow) T[size];
if (nullptr != array_)
{
ret_val = true;
size_ = size;
}
return ret_val;
}
/// @brief Indicates whether or not this buffer has been Initialized.
///
/// @return True if the buffer was Initialized; false otherwise.
inline bool Initialized() const
{
if (nullptr != array_)
{
return true;
}
return false;
}
/// @brief Allows direct access to next item ( avoids copying ).
///
/// AddLockedItem should be called once it's filled in.
///
/// @param [out] success Flag indicating if function is successfully returning the next item.
///
/// @return The next item.
T& LockNext(bool& success)
{
success = true;
assert(Initialized());
if (Full())
{
// Full, so remove one.
success = Erase();
}
return array_[tail_index_];
}
/// @brief Add a new item to the front (tail) of the buffer.
///
/// @return True if the item can be added; false if the buffer has no size.
bool AddLockedItem()
{
// Add to tail then increment.
if (size_ == 0)
{
return false;
}
CircularIncrement(tail_index_);
count_++;
return true;
}
/// @brief Gets the number of items in the circular buffer.
///
/// @return The number of items currently in the buffer.
unsigned int GetCount() const
{
return count_;
}
/// @brief Gets the size of the circular buffer.
///
/// @return The maximum number of items this circular buffer can hold.
unsigned int GetSize() const
{
return size_;
}
/// @brief Indicates whether or not the buffer is full.
///
/// @return True if the buffer is full; false if it is not.
bool Full() const
{
if (count_ == size_ && size_ != 0)
{
return true;
}
else
{
return false;
}
}
/// @brief Indicates whether or not the circular buffer is empty.
///
/// @return True if the buffer is empty; false if it has at least one element in it.
bool Empty() const
{
if (count_ == 0)
{
return true;
}
else
{
return false;
}
}
/// @brief Adds an item to the tail of the circular buffer.
///
/// If the buffer is full, the item at the head will be removed,
/// then the item will be added to the tail.
///
/// @param [in] item The object to add to the circular buffer.
///
/// @return True if the item could be added; false if the buffer is not Initialized.
bool Add(T& item)
{
// Add to tail then increment.
if (!Initialized())
{
return false;
}
if (Full())
{
// Need to remove from head first.
Erase();
}
array_[tail_index_] = item;
CircularIncrement(tail_index_);
count_++;
return true;
}
/// @brief Gets a reference to the item at the head of the buffer.
///
/// The item is not removed.
///
/// @return A reference to the item at the head of the buffer.
T& GetHead()
{
assert(Initialized());
return array_[head_index_];
}
/// @brief Removes the item from the head of the buffer and passes back a reference to the item.
///
/// @param [out] item A reference to the item at the head of the buffer.
///
/// @return True if an item could be returned; false if the buffer is empty.
bool Remove(T& item)
{
assert(Initialized());
if (Empty())
{
// Buffer empty.
return false;
}
// Return head item.
item = array_[head_index_];
CircularIncrement(head_index_);
count_--;
return true;
}
/// @brief Removes the item from the head of the buffer.
///
/// @return True if an item was removed from the head of the buffer; false if the buffer was empty.
bool Erase()
{
assert(Initialized());
if (Empty())
{
// Buffer empty.
return false;
}
// Increment head, decrement count.
CircularIncrement(head_index_);
count_--;
return true;
}
/// @brief Gets the item at a specified index of the buffer.
///
/// @param [in] index An index into the buffer. Must be smaller than the buffer's size.
///
/// @return The item at the specified index of the buffer.
T& Get(unsigned int index) const
{
assert(index < size_);
return array_[index];
}
/// @brief Gets the most recently added item from the buffer.
///
/// @return A reference to the item most recently added to the buffer.
T& GetLastAdded()
{
unsigned int index_of_last_added = tail_index_;
CircularDecrement(index_of_last_added);
return array_[index_of_last_added];
}
/// @brief Gets the item at an index in the circular buffer, relative to the head index.
///
/// Zero is the oldest element in the array, up to count-1.
///
/// @param [in] index The index of the item to get.
///
/// @return A reference to the item at head + index in the buffer.
T& GetRelative(unsigned int index)
{
unsigned int adjusted_index = ((index % size_) + head_index_) % size_;
return array_[adjusted_index];
}
/// @brief Calculates an adjusted index relative to the head index.
///
/// Zero is the oldest element in the array, up to count-1.
///
/// @param [in] index The offset from the head index that needs to be adjusted.
///
/// @return An adjusted index based on the head index and size of the buffer.
unsigned int GetRelativeIndex(unsigned int index)
{
unsigned int adjusted_index = ((index % size_) + head_index_) % size_;
return adjusted_index;
}
/// @brief Increments an index, ensuring that it stays within the size of the circular buffer.
///
/// @param [in] index The index to increment.
void CircularIncrement(unsigned int& index)
{
index++;
if (index == size_)
{
index = 0;
}
}
/// @brief Decrements an index, ensuring that it stays within the size of the circular buffer.
///
/// @param [in] index The index to decrement.
void CircularDecrement(unsigned int& index)
{
if (index == 0)
{
index = size_ - 1;
}
else
{
index--;
}
}
protected:
/// @brief Gets the head index of the circular buffer.
///
/// @return The index of the head of the buffer.
unsigned int GetHeadIndex() const
{
return head_index_;
}
/// @brief Gets the tail index of the circular buffer.
///
/// @return The index of the tail of the buffer.
unsigned int GetTailIndex() const
{
return tail_index_;
}
T* array_; ///< Underlying array of this circular buffer.
unsigned int head_index_; ///< Index of the head.
unsigned int tail_index_; ///< Index of the tail (insertion index).
unsigned int size_; ///< Maximum number of elements in the buffer at any one time.
unsigned int count_; ///< Current number of elements in the buffer.
};
#endif // GPU_PERF_API_COMMON_CIRCULAR_BUFFER_H_