Avionics
Core avionics package for CURE flight computers
Loading...
Searching...
No Matches
CircularArray.h
Go to the documentation of this file.
1#ifndef CIRCULARARRAY_H
2#define CIRCULARARRAY_H
3
4#include <algorithm>
5#include <array>
6#include <assert.h>
7#include <cstdint>
8
9constexpr std::size_t kMaxCircularArrayCapacity = 255;
10
11template<typename T, std::size_t N>
12std::size_t partition(std::array<T, N>& array, std::size_t left, std::size_t right, std::size_t pivotIndex) {
13 T pivotValue = array[pivotIndex];
14 std::swap(array[pivotIndex], array[right]); // Move pivot to end
15 std::size_t storeIndex = left;
16 for (std::size_t i = left; i < right; ++i) {
17 if (array[i] < pivotValue) {
18 std::swap(array[i], array[storeIndex]);
19 ++storeIndex;
20 }
21 }
22 std::swap(array[storeIndex], array[right]); // Move pivot to its final place
23 return storeIndex;
24}
25
26// Quick select implementation
27// Returns the kth smallest element in the array
28// left and right are the bounds of the array
29// O(n) average time complexity
30// O(n^2) worst case time complexity
31// If we were to just use bubble sort, that would be O(n^2) time complexity
32template<typename T, std::size_t N>
33T quickSelect(std::array<T, N>& array, std::size_t left, std::size_t right, std::size_t k) {
34 while (left < right){
35 const std::size_t pivotIndex = left + (right - left) / 2;
36 const std::size_t pivotNewIndex = partition(array, left, right, pivotIndex);
37 if (pivotNewIndex == k){
38 return array[k];
39 } else if (k < pivotNewIndex){
40 if (pivotNewIndex == 0U) {
41 break;
42 }
43 right = pivotNewIndex - 1;
44 } else {
45 left = pivotNewIndex + 1;
46 }
47 }
48 return array[k];
49}
50
51
52template<typename T, std::size_t Capacity>
59 protected:
60 std::array<T, Capacity> array;
61 std::array<T, Capacity> scratchArray; // For median calculation
62 uint8_t maxSize; // 0 to 255
63 uint8_t head; // 0 to 255
64 uint8_t currentSize; // 0 to 255
65
66 public:
67 CircularArray(uint8_t maxSize_in = static_cast<uint8_t>(Capacity)) : maxSize(maxSize_in) {
68 static_assert(Capacity > 0, "CircularArray capacity must be greater than 0");
69 static_assert(Capacity <= kMaxCircularArrayCapacity, "CircularArray capacity must be less than or equal to 255 b/c of head being uint8_t");
70 assert(maxSize_in > 0 && maxSize_in <= Capacity);
71 this->head = 0;
72 this->currentSize = 0; // How full is the circular buffer?
73 }
74
75 void push(T data){
76 // After the first push, start moving the head
77 if (currentSize) {
78 const uint16_t nextHead = static_cast<uint16_t>(head) + 1U;
79 head = static_cast<uint8_t>(nextHead % maxSize);
80 }
81 array[static_cast<std::size_t>(head)] = data;
82
83 // Cap current size at maxSize
84 if (currentSize < maxSize){
86 }
87 }
88
89 T pop(){
90 if (currentSize == 0){
91 return T();
92 }
93 T data = array[static_cast<std::size_t>(head)];
94 const uint16_t headStep = static_cast<uint16_t>(head) + static_cast<uint16_t>(maxSize) - 1U;
95 head = static_cast<uint8_t>(headStep % maxSize);
97 return data;
98 }
99
100 // How many indexes back from the head
101 T getFromHead(uint8_t index){
102 const std::size_t headIndex = static_cast<std::size_t>(head);
103 const std::size_t maxSizeIndex = static_cast<std::size_t>(maxSize);
104 const std::size_t offset = static_cast<std::size_t>(index);
105 return array[(headIndex + maxSizeIndex - offset) % maxSizeIndex];
106 }
107
108 // Has the circular array been filled
109 bool isFull(){
110 return currentSize >= maxSize;
111 }
112
113 bool isEmpty(){
114 return currentSize == 0;
115 }
116
117 uint8_t getHead(){
118 return head;
119 }
120
121 uint8_t getMaxSize(){
122 return maxSize;
123 }
124
126 if (currentSize == 0) {
127 // Handle the case when the array is empty
128 return T();
129 }
130
131 size_t count = std::min(static_cast<size_t>(currentSize), static_cast<size_t>(maxSize));
132
133 // Collect the valid elements from the circular array
134 for (size_t i = 0; i < count; ++i) {
135 scratchArray[i] = array[(head + maxSize - i) % maxSize];
136 }
137
138 // Find the median
139 return quickSelect(scratchArray, 0U, count - 1U, count / 2U);
140 }
141
142 void clear(){
143 head = 0;
144 currentSize = 0;
145 for (uint8_t i = 0; i < maxSize; i++){
146 array[static_cast<std::size_t>(i)] = T();
147 }
148 }
149
150};
151
152
153
154#endif
std::size_t partition(std::array< T, N > &array, std::size_t left, std::size_t right, std::size_t pivotIndex)
T quickSelect(std::array< T, N > &array, std::size_t left, std::size_t right, std::size_t k)
constexpr std::size_t kMaxCircularArrayCapacity
uint8_t getHead()
uint8_t getMaxSize()
T getFromHead(uint8_t index)
uint8_t currentSize
std::array< T, Capacity > scratchArray
void push(T data)
CircularArray(uint8_t maxSize_in=static_cast< uint8_t >(Capacity))
std::array< T, Capacity > array