mirror of
https://github.com/JulianGro/overte.git
synced 2025-04-14 03:46:34 +02:00
223 lines
5.8 KiB
C++
223 lines
5.8 KiB
C++
//
|
|
// RingBufferHistory.h
|
|
// libraries/shared/src
|
|
//
|
|
// Created by Yixin Wang on 7/9/2014
|
|
// Copyright 2014 High Fidelity, Inc.
|
|
//
|
|
// Distributed under the Apache License, Version 2.0.
|
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
|
//
|
|
|
|
#ifndef hifi_RingBufferHistory_h
|
|
#define hifi_RingBufferHistory_h
|
|
|
|
#include <stdlib.h>
|
|
#include <iterator>
|
|
|
|
#include <qvector.h>
|
|
|
|
template <typename T>
|
|
class RingBufferHistory {
|
|
|
|
public:
|
|
|
|
RingBufferHistory(int capacity = 10)
|
|
: _size(capacity + 1),
|
|
_capacity(capacity),
|
|
_newestEntryAtIndex(0),
|
|
_numEntries(0),
|
|
_buffer(capacity + 1)
|
|
{
|
|
}
|
|
|
|
void clear() {
|
|
_numEntries = 0;
|
|
}
|
|
|
|
void setCapacity(int capacity) {
|
|
_size = capacity + 1;
|
|
_capacity = capacity;
|
|
_newestEntryAtIndex = 0;
|
|
_numEntries = 0;
|
|
_buffer.resize(_size);
|
|
}
|
|
|
|
void insert(const T& entry) {
|
|
// increment newest entry index cyclically
|
|
_newestEntryAtIndex = (_newestEntryAtIndex + 1) % _size;
|
|
|
|
// insert new entry
|
|
_buffer[_newestEntryAtIndex] = entry;
|
|
if (_numEntries < _capacity) {
|
|
_numEntries++;
|
|
}
|
|
}
|
|
|
|
// std::unique_ptr need to be passed as an rvalue ref and moved into the vector
|
|
void insert(T&& entry) {
|
|
// increment newest entry index cyclically
|
|
_newestEntryAtIndex = (_newestEntryAtIndex + 1) % _size;
|
|
|
|
// insert new entry
|
|
_buffer[_newestEntryAtIndex] = std::move(entry);
|
|
if (_numEntries < _capacity) {
|
|
_numEntries++;
|
|
}
|
|
}
|
|
|
|
// 0 retrieves the most recent entry, _numEntries - 1 retrieves the oldest.
|
|
// returns NULL if entryAge not within [0, _numEntries-1]
|
|
const T* get(int entryAge) const {
|
|
if (!(entryAge >= 0 && entryAge < _numEntries)) {
|
|
return NULL;
|
|
}
|
|
int entryAt = _newestEntryAtIndex - entryAge;
|
|
if (entryAt < 0) {
|
|
entryAt += _size;
|
|
}
|
|
return &_buffer[entryAt];
|
|
}
|
|
|
|
T* get(int entryAge) {
|
|
return const_cast<T*>((static_cast<const RingBufferHistory*>(this))->get(entryAge));
|
|
}
|
|
|
|
const T* getNewestEntry() const {
|
|
return _numEntries == 0 ? NULL : &_buffer[_newestEntryAtIndex];
|
|
}
|
|
|
|
T* getNewestEntry() {
|
|
return _numEntries == 0 ? NULL : &_buffer[_newestEntryAtIndex];
|
|
}
|
|
|
|
int getCapacity() const { return _capacity; }
|
|
int getNumEntries() const { return _numEntries; }
|
|
bool isFilled() const { return _numEntries == _capacity; }
|
|
|
|
private:
|
|
int _size;
|
|
int _capacity;
|
|
int _newestEntryAtIndex;
|
|
int _numEntries;
|
|
std::vector<T> _buffer;
|
|
|
|
public:
|
|
class Iterator : public std::iterator < std::random_access_iterator_tag, T > {
|
|
public:
|
|
Iterator(T* bufferFirst, T* bufferLast, T* newestAt, T* at)
|
|
: _bufferFirst(bufferFirst),
|
|
_bufferLast(bufferLast),
|
|
_bufferLength(bufferLast - bufferFirst + 1),
|
|
_newestAt(newestAt),
|
|
_at(at) {}
|
|
|
|
bool operator==(const Iterator& rhs) { return _at == rhs._at; }
|
|
bool operator!=(const Iterator& rhs) { return _at != rhs._at; }
|
|
T& operator*() { return *_at; }
|
|
T* operator->() { return _at; }
|
|
|
|
Iterator& operator++() {
|
|
_at = (_at == _bufferFirst) ? _bufferLast : _at - 1;
|
|
return *this;
|
|
}
|
|
|
|
Iterator operator++(int) {
|
|
Iterator tmp(*this);
|
|
++(*this);
|
|
return tmp;
|
|
}
|
|
|
|
Iterator& operator--() {
|
|
_at = (_at == _bufferLast) ? _bufferFirst : _at + 1;
|
|
return *this;
|
|
}
|
|
|
|
Iterator operator--(int) {
|
|
Iterator tmp(*this);
|
|
--(*this);
|
|
return tmp;
|
|
}
|
|
|
|
Iterator operator+(int add) {
|
|
Iterator sum(*this);
|
|
sum._at = atShiftedBy(add);
|
|
return sum;
|
|
}
|
|
|
|
Iterator operator-(int sub) {
|
|
Iterator sum(*this);
|
|
sum._at = atShiftedBy(-sub);
|
|
return sum;
|
|
}
|
|
|
|
Iterator& operator+=(int add) {
|
|
_at = atShiftedBy(add);
|
|
return *this;
|
|
}
|
|
|
|
Iterator& operator-=(int sub) {
|
|
_at = atShiftedBy(-sub);
|
|
return *this;
|
|
}
|
|
|
|
T& operator[](int i) {
|
|
return *(atShiftedBy(i));
|
|
}
|
|
|
|
bool operator<(const Iterator& rhs) {
|
|
return age() < rhs.age();
|
|
}
|
|
|
|
bool operator>(const Iterator& rhs) {
|
|
return age() > rhs.age();
|
|
}
|
|
|
|
bool operator<=(const Iterator& rhs) {
|
|
return age() <= rhs.age();
|
|
}
|
|
|
|
bool operator>=(const Iterator& rhs) {
|
|
return age() >= rhs.age();
|
|
}
|
|
|
|
int operator-(const Iterator& rhs) {
|
|
return age() - rhs.age();
|
|
}
|
|
|
|
private:
|
|
T* atShiftedBy(int i) { // shifts i places towards _bufferFirst (towards older entries)
|
|
i = (_at - _bufferFirst - i) % _bufferLength;
|
|
if (i < 0) {
|
|
i += _bufferLength;
|
|
}
|
|
return _bufferFirst + i;
|
|
}
|
|
|
|
int age() {
|
|
int age = _newestAt - _at;
|
|
if (age < 0) {
|
|
age += _bufferLength;
|
|
}
|
|
return age;
|
|
}
|
|
|
|
T* _bufferFirst;
|
|
T* _bufferLast;
|
|
int _bufferLength;
|
|
T* _newestAt;
|
|
T* _at;
|
|
};
|
|
|
|
Iterator begin() { return Iterator(&_buffer.front(), &_buffer.back(), &_buffer[_newestEntryAtIndex], &_buffer[_newestEntryAtIndex]); }
|
|
|
|
Iterator end() {
|
|
int endAtIndex = _newestEntryAtIndex - _numEntries;
|
|
if (endAtIndex < 0) {
|
|
endAtIndex += _size;
|
|
}
|
|
return Iterator(&_buffer.front(), &_buffer.back(), &_buffer[_newestEntryAtIndex], &_buffer[endAtIndex]);
|
|
}
|
|
};
|
|
|
|
#endif // hifi_RingBufferHistory_h
|