2021-12-03 16:46:40 +00:00
|
|
|
// Copyright 2021-2022, Collabora, Ltd.
|
|
|
|
//
|
2021-09-03 01:49:56 +00:00
|
|
|
// SPDX-License-Identifier: BSL-1.0
|
|
|
|
/*!
|
|
|
|
* @file
|
2021-09-15 07:11:10 +00:00
|
|
|
* @brief Ringbuffer implementation for keeping track of the past state of things
|
2021-11-23 20:34:24 +00:00
|
|
|
* @author Ryan Pavlik <ryan.pavlik@collabora.com>
|
2021-12-03 16:46:40 +00:00
|
|
|
* @author Moses Turner <moses@collabora.com>
|
2021-11-23 20:34:24 +00:00
|
|
|
* @ingroup aux_util
|
2021-09-03 01:49:56 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
#pragma once
|
|
|
|
|
2021-12-03 16:46:40 +00:00
|
|
|
#include "u_template_historybuf_impl_helpers.hpp"
|
|
|
|
#include "u_iterator_base.hpp"
|
2021-09-03 01:49:56 +00:00
|
|
|
|
2021-12-03 16:46:40 +00:00
|
|
|
#include <limits>
|
|
|
|
#include <array>
|
2021-09-03 01:49:56 +00:00
|
|
|
|
2021-09-15 07:11:10 +00:00
|
|
|
namespace xrt::auxiliary::util {
|
2021-09-03 01:49:56 +00:00
|
|
|
|
2021-11-23 20:34:24 +00:00
|
|
|
namespace detail {
|
2021-12-03 16:46:40 +00:00
|
|
|
template <typename T, size_t MaxSize> class HistoryBufConstIterator;
|
2021-11-23 20:34:24 +00:00
|
|
|
template <typename T, size_t MaxSize> class HistoryBufIterator;
|
|
|
|
} // namespace detail
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* @brief Stores some number of values in a ring buffer, overwriting the earliest-pushed-remaining element if out of
|
|
|
|
* room.
|
|
|
|
*
|
|
|
|
* Note this should only store value types, since there's no way to destroy elements other than overwriting them, and
|
|
|
|
* all elements are default-initialized upon construction of the container.
|
|
|
|
*/
|
|
|
|
template <typename T, size_t MaxSize> class HistoryBuffer
|
2021-09-03 01:49:56 +00:00
|
|
|
{
|
2021-09-20 09:54:04 +00:00
|
|
|
public:
|
2021-11-23 20:34:24 +00:00
|
|
|
//! Is the buffer empty?
|
|
|
|
bool
|
2021-12-03 16:46:40 +00:00
|
|
|
empty() const noexcept;
|
|
|
|
|
2021-11-23 20:34:24 +00:00
|
|
|
//! How many elements are in the buffer?
|
|
|
|
size_t
|
2021-12-03 16:46:40 +00:00
|
|
|
size() const noexcept;
|
2021-11-23 20:34:24 +00:00
|
|
|
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* @brief Put something at the back, overwriting whatever was at the front if necessary.
|
|
|
|
*
|
|
|
|
* This is permitted to invalidate iterators. They won't be poisoned, but they will return something you don't
|
|
|
|
* expect.
|
|
|
|
*/
|
|
|
|
void
|
2021-12-03 16:46:40 +00:00
|
|
|
push_back(const T &element);
|
2021-11-23 20:34:24 +00:00
|
|
|
|
2022-04-26 21:10:18 +00:00
|
|
|
/*!
|
|
|
|
* @brief Logically remove the newest element from the buffer.
|
|
|
|
*
|
|
|
|
* This is permitted to invalidate iterators. They won't be poisoned,
|
|
|
|
* but they will return something you don't expect.
|
|
|
|
*
|
|
|
|
* @return true if there was something to pop.
|
|
|
|
*/
|
|
|
|
bool
|
|
|
|
pop_back() noexcept
|
|
|
|
{
|
|
|
|
return helper_.pop_back();
|
|
|
|
}
|
|
|
|
|
2021-11-23 20:34:24 +00:00
|
|
|
/*!
|
|
|
|
* @brief Logically remove the oldest element from the buffer.
|
|
|
|
*
|
2022-05-17 20:28:47 +00:00
|
|
|
* The value still remains in the backing container until overwritten, but it isn't accessible anymore.
|
2021-11-23 20:34:24 +00:00
|
|
|
*
|
|
|
|
* This invalidates iterators. They won't be poisoned, but they will return something you don't expect.
|
|
|
|
*/
|
|
|
|
void
|
2021-12-03 16:46:40 +00:00
|
|
|
pop_front() noexcept
|
2021-11-23 20:34:24 +00:00
|
|
|
{
|
|
|
|
helper_.pop_front();
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
2022-05-17 20:28:47 +00:00
|
|
|
* @brief Use a value at a given age, where age 0 is the most recent value, age 1 precedes it, etc.
|
2021-12-03 16:46:40 +00:00
|
|
|
* (reverse chronological order)
|
2021-11-23 20:34:24 +00:00
|
|
|
*
|
|
|
|
* Out of bounds accesses will return nullptr.
|
|
|
|
*/
|
|
|
|
T *
|
2021-12-03 16:46:40 +00:00
|
|
|
get_at_age(size_t age) noexcept;
|
2021-11-23 20:34:24 +00:00
|
|
|
|
|
|
|
//! @overload
|
|
|
|
const T *
|
2021-12-03 16:46:40 +00:00
|
|
|
get_at_age(size_t age) const noexcept;
|
2021-09-03 01:49:56 +00:00
|
|
|
|
2022-01-05 19:34:47 +00:00
|
|
|
/*!
|
|
|
|
* @brief Like get_at_age() but values larger than the oldest age are clamped.
|
|
|
|
*/
|
|
|
|
T *
|
|
|
|
get_at_clamped_age(size_t age) noexcept
|
|
|
|
{
|
|
|
|
size_t inner_index = 0;
|
|
|
|
if (helper_.clamped_age_to_inner_index(age, inner_index)) {
|
|
|
|
return &internalBuffer[inner_index];
|
|
|
|
}
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
//! @overload
|
|
|
|
const T *
|
|
|
|
get_at_clamped_age(size_t age) const noexcept
|
|
|
|
{
|
|
|
|
size_t inner_index = 0;
|
|
|
|
if (helper_.clamped_age_to_inner_index(age, inner_index)) {
|
|
|
|
return &internalBuffer[inner_index];
|
|
|
|
}
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2021-11-23 20:34:24 +00:00
|
|
|
/*!
|
2022-05-17 20:28:47 +00:00
|
|
|
* @brief Use a value at a given index, where 0 is the least-recent value still stored, index 1 follows it,
|
2021-12-03 16:46:40 +00:00
|
|
|
* etc. (chronological order)
|
2021-11-23 20:34:24 +00:00
|
|
|
*
|
|
|
|
* Out of bounds accesses will return nullptr.
|
|
|
|
*/
|
|
|
|
T *
|
2021-12-03 16:46:40 +00:00
|
|
|
get_at_index(size_t index) noexcept;
|
2021-09-03 01:49:56 +00:00
|
|
|
|
2021-11-23 20:34:24 +00:00
|
|
|
//! @overload
|
|
|
|
const T *
|
2021-12-03 16:46:40 +00:00
|
|
|
get_at_index(size_t index) const noexcept;
|
2021-11-23 20:34:24 +00:00
|
|
|
|
|
|
|
using iterator = detail::HistoryBufIterator<T, MaxSize>;
|
|
|
|
using const_iterator = detail::HistoryBufConstIterator<T, MaxSize>;
|
2021-09-03 01:49:56 +00:00
|
|
|
|
2021-12-03 16:46:40 +00:00
|
|
|
//! Get a const iterator for the oldest element.
|
2021-11-23 20:34:24 +00:00
|
|
|
const_iterator
|
2021-12-03 16:46:40 +00:00
|
|
|
cbegin() const noexcept;
|
2021-11-23 20:34:24 +00:00
|
|
|
|
2021-12-03 16:46:40 +00:00
|
|
|
//! Get a "past the end" (past the newest) const iterator
|
2021-11-23 20:34:24 +00:00
|
|
|
const_iterator
|
2021-12-03 16:46:40 +00:00
|
|
|
cend() const noexcept;
|
2021-11-23 20:34:24 +00:00
|
|
|
|
2021-12-03 16:46:40 +00:00
|
|
|
//! Get a const iterator for the oldest element.
|
2021-11-23 20:34:24 +00:00
|
|
|
const_iterator
|
2021-12-03 16:46:40 +00:00
|
|
|
begin() const noexcept;
|
2021-11-23 20:34:24 +00:00
|
|
|
|
2021-12-03 16:46:40 +00:00
|
|
|
//! Get a "past the end" (past the newest) const iterator
|
2021-11-23 20:34:24 +00:00
|
|
|
const_iterator
|
2021-12-03 16:46:40 +00:00
|
|
|
end() const noexcept;
|
|
|
|
|
|
|
|
//! Get an iterator for the oldest element.
|
|
|
|
iterator
|
|
|
|
begin() noexcept;
|
|
|
|
|
|
|
|
//! Get a "past the end" (past the newest) iterator
|
|
|
|
iterator
|
|
|
|
end() noexcept;
|
2021-11-23 20:34:24 +00:00
|
|
|
|
|
|
|
/*!
|
2021-12-03 16:46:40 +00:00
|
|
|
* @brief Gets a reference to the front (oldest) element in the buffer.
|
2021-11-23 20:34:24 +00:00
|
|
|
* @throws std::logic_error if buffer is empty
|
|
|
|
*/
|
|
|
|
T &
|
2021-12-03 16:46:40 +00:00
|
|
|
front();
|
|
|
|
|
2021-11-23 20:34:24 +00:00
|
|
|
//! @overload
|
|
|
|
const T &
|
2021-12-03 16:46:40 +00:00
|
|
|
front() const;
|
2021-11-23 20:34:24 +00:00
|
|
|
|
|
|
|
/*!
|
2021-12-03 16:46:40 +00:00
|
|
|
* @brief Gets a reference to the back (newest) element in the buffer.
|
2021-11-23 20:34:24 +00:00
|
|
|
* @throws std::logic_error if buffer is empty
|
|
|
|
*/
|
|
|
|
T &
|
2021-12-03 16:46:40 +00:00
|
|
|
back();
|
2021-09-03 01:49:56 +00:00
|
|
|
|
2021-11-23 20:34:24 +00:00
|
|
|
//! @overload
|
|
|
|
const T &
|
2021-12-03 16:46:40 +00:00
|
|
|
back() const;
|
|
|
|
|
2022-06-14 11:22:12 +00:00
|
|
|
void
|
|
|
|
clear();
|
|
|
|
|
2021-12-03 16:46:40 +00:00
|
|
|
private:
|
|
|
|
// Make sure all valid indices can be represented in a signed integer of the same size
|
|
|
|
static_assert(MaxSize < (std::numeric_limits<size_t>::max() >> 1), "Cannot use most significant bit");
|
|
|
|
|
|
|
|
using container_t = std::array<T, MaxSize>;
|
|
|
|
container_t internalBuffer{};
|
2022-02-08 18:17:35 +00:00
|
|
|
detail::RingBufferHelper helper_{MaxSize};
|
2021-09-20 09:54:04 +00:00
|
|
|
};
|
2021-09-03 01:49:56 +00:00
|
|
|
|
2022-06-14 11:22:12 +00:00
|
|
|
|
|
|
|
template <typename T, size_t MaxSize>
|
|
|
|
void
|
|
|
|
HistoryBuffer<T, MaxSize>::clear()
|
|
|
|
{
|
|
|
|
helper_.clear();
|
|
|
|
}
|
|
|
|
|
2021-12-03 16:46:40 +00:00
|
|
|
template <typename T, size_t MaxSize>
|
|
|
|
inline bool
|
|
|
|
HistoryBuffer<T, MaxSize>::empty() const noexcept
|
|
|
|
{
|
|
|
|
return helper_.empty();
|
|
|
|
}
|
2021-11-23 20:34:24 +00:00
|
|
|
|
2021-12-03 16:46:40 +00:00
|
|
|
template <typename T, size_t MaxSize>
|
|
|
|
inline size_t
|
|
|
|
HistoryBuffer<T, MaxSize>::size() const noexcept
|
|
|
|
{
|
|
|
|
return helper_.size();
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T, size_t MaxSize>
|
|
|
|
inline void
|
|
|
|
HistoryBuffer<T, MaxSize>::push_back(const T &element)
|
|
|
|
{
|
|
|
|
auto inner_index = helper_.push_back_location();
|
|
|
|
internalBuffer[inner_index] = element;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T, size_t MaxSize>
|
|
|
|
inline T *
|
|
|
|
HistoryBuffer<T, MaxSize>::get_at_age(size_t age) noexcept
|
|
|
|
{
|
|
|
|
size_t inner_index = 0;
|
|
|
|
if (helper_.age_to_inner_index(age, inner_index)) {
|
|
|
|
return &internalBuffer[inner_index];
|
|
|
|
}
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
template <typename T, size_t MaxSize>
|
|
|
|
inline const T *
|
|
|
|
HistoryBuffer<T, MaxSize>::get_at_age(size_t age) const noexcept
|
|
|
|
{
|
|
|
|
size_t inner_index = 0;
|
|
|
|
if (helper_.age_to_inner_index(age, inner_index)) {
|
|
|
|
return &internalBuffer[inner_index];
|
2021-11-23 20:34:24 +00:00
|
|
|
}
|
2021-12-03 16:46:40 +00:00
|
|
|
return nullptr;
|
|
|
|
}
|
2021-11-23 20:34:24 +00:00
|
|
|
|
2021-12-03 16:46:40 +00:00
|
|
|
template <typename T, size_t MaxSize>
|
|
|
|
inline T *
|
|
|
|
HistoryBuffer<T, MaxSize>::get_at_index(size_t index) noexcept
|
|
|
|
{
|
|
|
|
size_t inner_index = 0;
|
|
|
|
if (helper_.index_to_inner_index(index, inner_index)) {
|
|
|
|
return &internalBuffer[inner_index];
|
2021-11-23 20:34:24 +00:00
|
|
|
}
|
2021-12-03 16:46:40 +00:00
|
|
|
return nullptr;
|
|
|
|
}
|
2021-11-23 20:34:24 +00:00
|
|
|
|
2021-12-03 16:46:40 +00:00
|
|
|
template <typename T, size_t MaxSize>
|
|
|
|
inline const T *
|
|
|
|
HistoryBuffer<T, MaxSize>::get_at_index(size_t index) const noexcept
|
|
|
|
{
|
|
|
|
size_t inner_index = 0;
|
|
|
|
if (helper_.index_to_inner_index(index, inner_index)) {
|
|
|
|
return &internalBuffer[inner_index];
|
|
|
|
}
|
|
|
|
return nullptr;
|
|
|
|
}
|
2021-11-23 20:34:24 +00:00
|
|
|
|
2021-12-03 16:46:40 +00:00
|
|
|
template <typename T, size_t MaxSize>
|
|
|
|
inline T &
|
|
|
|
HistoryBuffer<T, MaxSize>::front()
|
|
|
|
{
|
|
|
|
if (empty()) {
|
|
|
|
throw std::logic_error("Cannot get the front of an empty buffer");
|
2021-11-23 20:34:24 +00:00
|
|
|
}
|
2021-12-03 16:46:40 +00:00
|
|
|
return internalBuffer[helper_.front_inner_index()];
|
|
|
|
}
|
2021-11-23 20:34:24 +00:00
|
|
|
|
2021-12-03 16:46:40 +00:00
|
|
|
template <typename T, size_t MaxSize>
|
|
|
|
inline const T &
|
|
|
|
HistoryBuffer<T, MaxSize>::front() const
|
|
|
|
{
|
|
|
|
if (empty()) {
|
|
|
|
throw std::logic_error("Cannot get the front of an empty buffer");
|
2021-11-23 20:34:24 +00:00
|
|
|
}
|
2021-12-03 16:46:40 +00:00
|
|
|
return internalBuffer[helper_.front_inner_index()];
|
|
|
|
}
|
2021-11-23 20:34:24 +00:00
|
|
|
|
2021-12-03 16:46:40 +00:00
|
|
|
template <typename T, size_t MaxSize>
|
|
|
|
inline T &
|
|
|
|
HistoryBuffer<T, MaxSize>::back()
|
|
|
|
{
|
|
|
|
if (empty()) {
|
|
|
|
throw std::logic_error("Cannot get the back of an empty buffer");
|
2021-11-23 20:34:24 +00:00
|
|
|
}
|
2021-12-03 16:46:40 +00:00
|
|
|
return internalBuffer[helper_.back_inner_index()];
|
|
|
|
}
|
2021-11-23 20:34:24 +00:00
|
|
|
|
2021-12-03 16:46:40 +00:00
|
|
|
template <typename T, size_t MaxSize>
|
|
|
|
inline const T &
|
|
|
|
HistoryBuffer<T, MaxSize>::back() const
|
|
|
|
{
|
|
|
|
if (empty()) {
|
|
|
|
throw std::logic_error("Cannot get the back of an empty buffer");
|
2021-11-23 20:34:24 +00:00
|
|
|
}
|
2021-12-03 16:46:40 +00:00
|
|
|
return internalBuffer[helper_.back_inner_index()];
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-09-20 09:54:04 +00:00
|
|
|
} // namespace xrt::auxiliary::util
|
2021-12-03 16:46:40 +00:00
|
|
|
|
|
|
|
#include "u_template_historybuf_const_iterator.inl"
|
|
|
|
#include "u_template_historybuf_iterator.inl"
|