I'm working on a modern C++20 solution that does two things:
- It accumulates a sliding window of input data points; the sliding window's size is fixed and known beforehand. Data has strict ordering and it should be kept.
- Feeds the current sliding window into some C-like interface, which requires contiguous memory. There is a catch - the interface expects a pointer, starting index, and number of items to read.
Known to me options:
- Use
std::dequefor keeping a sliding window, since it allows cheap pushes and pops at the ends. However, it's not contiguous and would require data copy to, let's say,std::vector. std::vector+std::rotate. Rotate the current vector, overwrite the last element with the current data point, and feed it into the interface. Requires O(N) rotation for each input.- Allocate a memory buffer significantly larger than the window size, like 1024 buffer elements for a sliding window of 5-10 elements. Write inputs to this buffer until you reach the end, copy the current sliding window to the beginning of the buffer, and continue. The same as 2), but performs O(N) copy only when we reach the buffer's end.
Currently, I stick to the last one, similar to this simplified snippet:
#include <iostream>
#include <vector>
class SlidingWindowBuffer {
public:
SlidingWindowBuffer(size_t bufferSize, size_t windowSize)
: buffer(bufferSize), windowSize(windowSize), writeIndex(0) {}
void addElement(int element) {
buffer[writeIndex] = element;
writeIndex = (writeIndex + 1) % buffer.size();
if (writeIndex == 0) {
// Perform O(N) copy when we reach the end of the buffer
for (size_t i = 0; i < windowSize; ++i) {
buffer[i] = buffer[buffer.size() - windowSize + i];
}
writeIndex = windowSize;
}
}
void printBuffer() const {
for (size_t i = 0; i < buffer.size(); ++i) {
std::cout << buffer[i] << " ";
}
std::cout << std::endl;
}
private:
std::vector<int> buffer;
size_t windowSize;
size_t writeIndex;
};
int main() {
size_t bufferSize = 1024;
size_t windowSize = 10;
SlidingWindowBuffer swb(bufferSize, windowSize);
// Example usage
for (int i = 0; i < 1050; ++i) {
swb.addElement(i);
}
swb.printBuffer();
return 0;
}
The snippet itself is only for illustration purposes so it could be incorrect for some corner cases, it's not used anywhere.
My question is the following - are there any other alternatives I'm missing? Are there any considerations when you choose between alternatives?
std::size_t, unnecessary flushing withstd::endl, inability toprintBuffer()to any stream other thanstd::cout, redundant return frommain(). \$\endgroup\$