fsfw/contrib/fsfw_contrib/etl-20.39.4/include/etl/circular_buffer.h

1462 lines
47 KiB
C
Raw Permalink Normal View History

2024-10-29 10:49:46 +01:00
///\file
/******************************************************************************
The MIT License(MIT)
Embedded Template Library.
https://github.com/ETLCPP/etl
https://www.etlcpp.com
Copyright(c) 2020 John Wellbelove
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files(the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions :
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
******************************************************************************/
#ifndef ETL_CIRCULAR_BUFFER_INCLUDED
#define ETL_CIRCULAR_BUFFER_INCLUDED
#include "platform.h"
#include "vector.h"
#include "exception.h"
#include "error_handler.h"
#include "memory.h"
#include "memory_model.h"
#include "type_traits.h"
#include "iterator.h"
#include "static_assert.h"
#include "initializer_list.h"
namespace etl
{
//***************************************************************************
/// Exception for the circular_buffer.
//***************************************************************************
class circular_buffer_exception : public etl::exception
{
public:
circular_buffer_exception(string_type reason_, string_type file_name_, numeric_type line_number_)
: exception(reason_, file_name_, line_number_)
{
}
};
//***************************************************************************
/// Empty exception for the circular_buffer.
//***************************************************************************
class circular_buffer_empty : public etl::circular_buffer_exception
{
public:
circular_buffer_empty(string_type file_name_, numeric_type line_number_)
: etl::circular_buffer_exception(ETL_ERROR_TEXT("circular_buffer:empty", ETL_CIRCULAR_BUFFER_FILE_ID"A"), file_name_, line_number_)
{
}
};
//***************************************************************************
/// Incompatible type exception.
//***************************************************************************
class circular_buffer_incompatible_type : public circular_buffer_exception
{
public:
circular_buffer_incompatible_type(string_type file_name_, numeric_type line_number_)
: circular_buffer_exception(ETL_ERROR_TEXT("circular_buffer:type", ETL_CIRCULAR_BUFFER_FILE_ID"B"), file_name_, line_number_)
{
}
};
//***************************************************************************
///
//***************************************************************************
class circular_buffer_base
{
public:
/// The type used for determining the size of queue.
typedef size_t size_type;
//*************************************************************************
size_type size() const
{
return (in >= out) ? in - out : buffer_size - (out - in);
}
//*************************************************************************
bool empty() const
{
return in == out;
}
//*************************************************************************
bool full() const
{
size_t i = in;
++i;
if (i == buffer_size) ETL_UNLIKELY
{
i = 0U;
}
return i == out;
}
//*************************************************************************
size_type available() const
{
return max_size() - size();
}
//*************************************************************************
size_type max_size() const
{
return buffer_size - 1U;
}
//*************************************************************************
size_type capacity() const
{
return buffer_size - 1U;
}
protected:
//*************************************************************************
circular_buffer_base(size_type buffer_size_)
: buffer_size(buffer_size_)
, in(0U)
, out(0U)
{
}
//*************************************************************************
void increment_in()
{
++in;
if (in == buffer_size) ETL_UNLIKELY
{
in = 0U;
}
}
//*************************************************************************
void increment_out()
{
++out;
if (out == buffer_size) ETL_UNLIKELY
{
out = 0U;
}
}
size_type buffer_size;
size_type in; ///< Index to the next write.
size_type out; ///< Index to the next read.
ETL_DECLARE_DEBUG_COUNT; ///< Internal debugging.
};
//***************************************************************************
///
//***************************************************************************
template <typename T>
class icircular_buffer : public circular_buffer_base
{
public:
typedef T value_type;
typedef T& reference;
typedef const T& const_reference;
#if ETL_USING_CPP11
typedef T&& rvalue_reference;
#endif
typedef T* pointer;
typedef const T* const_pointer;
typedef typename etl::iterator_traits<pointer>::difference_type difference_type;
//*************************************************************************
/// Iterator iterating through the circular buffer.
//*************************************************************************
class iterator : public etl::iterator<ETL_OR_STD::random_access_iterator_tag, T>
{
public:
friend class icircular_buffer;
//*************************************************************************
/// Constructor
//*************************************************************************
iterator()
: picb(ETL_NULLPTR)
, current(0U)
{
}
//*************************************************************************
/// Copy Constructor
//*************************************************************************
iterator(const iterator& other)
: picb(other.picb)
, current(other.current)
{
}
//*************************************************************************
/// Assignment operator.
//*************************************************************************
iterator& operator =(const iterator& other)
{
picb = other.picb;
current = other.current;
return *this;
}
//*************************************************************************
/// * operator
//*************************************************************************
reference operator *() const
{
return picb->pbuffer[current];
}
//*************************************************************************
/// -> operator
//*************************************************************************
pointer operator ->() const
{
return &picb->pbuffer[current];
}
//*************************************************************************
/// [] operator
//*************************************************************************
reference operator [](size_t index)
{
return pbuffer[(current + index) % picb->buffer_size];
}
//*************************************************************************
/// [] operator
//*************************************************************************
const_reference operator [](size_t index) const
{
return pbuffer[(current + index) % picb->buffer_size];
}
//*************************************************************************
/// Pre-increment.
//*************************************************************************
iterator& operator ++()
{
++current;
// Did we reach the end of the buffer?
if (current == picb->buffer_size)
{
current = 0U;
}
return (*this);
}
//*************************************************************************
/// Post increment.
//*************************************************************************
iterator operator ++(int)
{
iterator original(*this);
++(*this);
return (original);
}
//*************************************************************************
/// Pre-decrement.
//*************************************************************************
iterator& operator --()
{
// Are we at the end of the buffer?
if (current == 0U)
{
current = picb->buffer_size - 1;
}
else
{
--current;
}
return (*this);
}
//*************************************************************************
/// Post increment.
//*************************************************************************
iterator operator --(int)
{
iterator original(*this);
--(*this);
return (original);
}
//*************************************************************************
/// Add offset.
//*************************************************************************
iterator& operator +=(int n)
{
current += size_type(picb->buffer_size + n);
current %= picb->buffer_size;
return (*this);
}
//*************************************************************************
/// Subtract offset.
//*************************************************************************
iterator& operator -=(int n)
{
return (this->operator+=(-n));
}
//*************************************************************************
/// Add offset.
//*************************************************************************
friend iterator operator +(const iterator& lhs, int n)
{
iterator temp = lhs;
temp += n;
return temp;
}
//*************************************************************************
/// Add offset.
//*************************************************************************
friend iterator operator +(int n, const iterator& rhs)
{
iterator temp = rhs;
temp += n;
return temp;
}
//*************************************************************************
/// Subtract offset.
//*************************************************************************
friend iterator operator -(const iterator& lhs, int n)
{
iterator temp = lhs;
temp -= n;
return temp;
}
//*************************************************************************
/// Equality operator
//*************************************************************************
friend bool operator == (const iterator& lhs, const iterator& rhs)
{
return (lhs.current == rhs.current);
}
//*************************************************************************
/// Inequality operator
//*************************************************************************
friend bool operator != (const iterator& lhs, const iterator& rhs)
{
return !(lhs == rhs);
}
//***************************************************
friend bool operator < (const iterator& lhs, const iterator& rhs)
{
const difference_type lhs_index = lhs.get_index();
const difference_type rhs_index = rhs.get_index();
const difference_type reference_index = lhs.container().begin().get_index();
const size_t buffer_size = lhs.container().max_size() + 1UL;
const difference_type lhs_distance = (lhs_index < reference_index) ? buffer_size + lhs_index - reference_index : lhs_index - reference_index;
const difference_type rhs_distance = (rhs_index < reference_index) ? buffer_size + rhs_index - reference_index : rhs_index - reference_index;
return lhs_distance < rhs_distance;
}
//***************************************************
friend bool operator <= (const iterator& lhs, const iterator& rhs)
{
return !(lhs > rhs);
}
//***************************************************
friend bool operator > (const iterator& lhs, const iterator& rhs)
{
return (rhs < lhs);
}
//***************************************************
friend bool operator >= (const iterator& lhs, const iterator& rhs)
{
return !(lhs < rhs);
}
//***************************************************
difference_type get_index() const
{
return current;
}
//***************************************************
const icircular_buffer& container() const
{
return *picb;
}
//***************************************************
pointer get_buffer() const
{
return pbuffer;
}
protected:
//***************************************************
difference_type distance(difference_type firstIndex, difference_type index) const
{
if (index < firstIndex)
{
return picb->buffer_size + current - firstIndex;
}
else
{
return index - firstIndex;
}
}
//*************************************************************************
/// Protected constructor. Only icircular_buffer can create one.
//*************************************************************************
iterator(const icircular_buffer<T>* picb_, size_type current_)
: picb(picb_)
, current(current_)
{
}
private:
const icircular_buffer<T>* picb;
size_type current;
};
//*************************************************************************
/// Iterator iterating through the circular buffer.
//*************************************************************************
class const_iterator : public etl::iterator<ETL_OR_STD::random_access_iterator_tag, const T>
{
public:
friend class icircular_buffer;
//*************************************************************************
/// Constructor
//*************************************************************************
const_iterator()
: picb(ETL_NULLPTR)
, current(0U)
{
}
//*************************************************************************
/// Copy Constructor from iterator
//*************************************************************************
const_iterator(const typename icircular_buffer::iterator& other)
: picb(other.picb)
, current(other.current)
{
}
//*************************************************************************
/// Copy Constructor from const iterator
//*************************************************************************
const_iterator(const const_iterator& other)
: picb(other.picb)
, current(other.current)
{
}
//*************************************************************************
/// Assignment operator.
//*************************************************************************
const_iterator& operator =(const typename icircular_buffer::iterator& other)
{
picb = other.picb;
current = other.current;
return *this;
}
//*************************************************************************
/// Assignment operator.
//*************************************************************************
const_iterator& operator =(const const_iterator& other)
{
picb = other.picb;
current = other.current;
return *this;
}
//*************************************************************************
/// * operator
//*************************************************************************
const_reference operator *() const
{
return picb->pbuffer[current];
}
//*************************************************************************
/// -> operator
//*************************************************************************
const_pointer operator ->() const
{
return &(picb->pbuffer[current]);
}
//*************************************************************************
/// [] operator
//*************************************************************************
const_reference operator [](size_t index) const
{
return pbuffer[(current + index) % picb->buffer_size];
}
//*************************************************************************
/// Pre-increment.
//*************************************************************************
const_iterator& operator ++()
{
++current;
// Did we reach the end of the buffer?
if (current == picb->buffer_size)
{
current = 0U;
}
return (*this);
}
//*************************************************************************
/// Post increment.
//*************************************************************************
const_iterator operator ++(int)
{
const_iterator original(*this);
++(*this);
return (original);
}
//*************************************************************************
/// Pre-decrement.
//*************************************************************************
const_iterator& operator --()
{
// Are we at the end of the buffer?
if (current == 0U)
{
current = picb->buffer_size - 1;
}
else
{
--current;
}
return (*this);
}
//*************************************************************************
/// Post increment.
//*************************************************************************
const_iterator operator --(int)
{
const_iterator original(*this);
--(*this);
return (original);
}
//*************************************************************************
/// Add offset.
//*************************************************************************
const_iterator& operator +=(int n)
{
current += size_type(picb->buffer_size + n);
current %= picb->buffer_size;
return (*this);
}
//*************************************************************************
/// Subtract offset.
//*************************************************************************
const_iterator& operator -=(int n)
{
return (this->operator+=(-n));
}
//*************************************************************************
/// Add offset.
//*************************************************************************
friend const_iterator operator +(const const_iterator& lhs, int n)
{
const_iterator temp = lhs;
temp += n;
return temp;
}
//*************************************************************************
/// Subtract offset.
//*************************************************************************
friend const_iterator operator -(const const_iterator& lhs, int n)
{
const_iterator temp = lhs;
temp -= n;
return temp;
}
//*************************************************************************
/// Equality operator
//*************************************************************************
friend bool operator == (const const_iterator& lhs, const const_iterator& rhs)
{
return (lhs.current == rhs.current);
}
//*************************************************************************
/// Inequality operator
//*************************************************************************
friend bool operator != (const const_iterator& lhs, const const_iterator& rhs)
{
return !(lhs == rhs);
}
//***************************************************
friend bool operator < (const const_iterator& lhs, const const_iterator& rhs)
{
const difference_type lhs_index = lhs.get_index();
const difference_type rhs_index = rhs.get_index();
const difference_type reference_index = lhs.container().begin().get_index();
const size_t buffer_size = lhs.container().max_size() + 1UL;
const difference_type lhs_distance = (lhs_index < reference_index) ? buffer_size + lhs_index - reference_index : lhs_index - reference_index;
const difference_type rhs_distance = (rhs_index < reference_index) ? buffer_size + rhs_index - reference_index : rhs_index - reference_index;
return lhs_distance < rhs_distance;
}
//***************************************************
friend bool operator <= (const const_iterator& lhs, const const_iterator& rhs)
{
return !(lhs > rhs);
}
//***************************************************
friend bool operator > (const const_iterator& lhs, const const_iterator& rhs)
{
return (rhs < lhs);
}
//***************************************************
friend bool operator >= (const const_iterator& lhs, const const_iterator& rhs)
{
return !(lhs < rhs);
}
//***************************************************
difference_type get_index() const
{
return current;
}
//***************************************************
const icircular_buffer& container() const
{
return *picb;
}
//***************************************************
pointer get_buffer() const
{
return pbuffer;
}
protected:
//*************************************************************************
/// Protected constructor. Only icircular_buffer can create one.
//*************************************************************************
const_iterator(const icircular_buffer<T>* picb_, size_type current_)
: picb(picb_)
, current(current_)
{
}
private:
const icircular_buffer<T>* picb;
size_type current;
};
friend class iterator;
friend class const_iterator;
typedef etl::reverse_iterator<iterator> reverse_iterator;
typedef etl::reverse_iterator<const_iterator> const_reverse_iterator;
//*************************************************************************
/// Gets an iterator to the start of the buffer.
//*************************************************************************
iterator begin()
{
return iterator(this, out);
}
//*************************************************************************
/// Gets a const iterator to the start of the buffer.
//*************************************************************************
const_iterator begin() const
{
return const_iterator(this, out);
}
//*************************************************************************
/// Gets a const iterator to the start of the buffer.
//*************************************************************************
const_iterator cbegin() const
{
return const_iterator(this, out);
}
//*************************************************************************
/// Gets an iterator to the end of the buffer.
//*************************************************************************
iterator end()
{
return iterator(this, in);
}
//*************************************************************************
/// Gets a const iterator to the end of the buffer.
//*************************************************************************
const_iterator end() const
{
return const_iterator(this, in);
}
//*************************************************************************
/// Gets a const iterator to the end of the buffer.
//*************************************************************************
const_iterator cend() const
{
return const_iterator(this, in);
}
//*************************************************************************
/// Gets a reverse iterator to the start of the buffer.
//*************************************************************************
reverse_iterator rbegin()
{
return reverse_iterator(end());
}
//*************************************************************************
/// Gets a const reverse iterator to the start of the buffer.
//*************************************************************************
const_reverse_iterator rbegin() const
{
return const_reverse_iterator(end());
}
//*************************************************************************
/// Gets a const reverse iterator to the start of the buffer.
//*************************************************************************
const_reverse_iterator crbegin() const
{
return const_reverse_iterator(end());
}
//*************************************************************************
/// Gets a reverse iterator to the end of the buffer.
//*************************************************************************
reverse_iterator rend()
{
return reverse_iterator(begin());
}
//*************************************************************************
/// Gets a const reverse iterator to the end of the buffer.
//*************************************************************************
const_reverse_iterator rend() const
{
return const_reverse_iterator(begin());
}
//*************************************************************************
/// Gets a const reverse iterator to the end of the buffer.
//*************************************************************************
const_reverse_iterator crend() const
{
return const_reverse_iterator(begin());
}
//*************************************************************************
/// Get a const reference to the item at the front of the buffer.
/// Asserts an error if the buffer is empty.
//*************************************************************************
reference front()
{
ETL_ASSERT(!empty(), ETL_ERROR(circular_buffer_empty));
return pbuffer[out];
}
//*************************************************************************
/// Get a const reference to the item at the front of the buffer.
/// Asserts an error if the buffer is empty.
//*************************************************************************
const_reference front() const
{
ETL_ASSERT(!empty(), ETL_ERROR(circular_buffer_empty));
return pbuffer[out];
}
//*************************************************************************
/// Get a reference to the item at the back of the buffer.
/// Asserts an error if the buffer is empty.
//*************************************************************************
reference back()
{
ETL_ASSERT(!empty(), ETL_ERROR(circular_buffer_empty));
return pbuffer[in == 0U ? buffer_size - 1 : in - 1U];
}
//*************************************************************************
/// Get a const reference to the item at the back of the buffer.
/// Asserts an error if the buffer is empty.
//*************************************************************************
const_reference back() const
{
ETL_ASSERT(!empty(), ETL_ERROR(circular_buffer_empty));
return pbuffer[in == 0U ? buffer_size - 1 : in - 1U];
}
//*************************************************************************
/// Get a reference to the item.
//*************************************************************************
reference operator [](size_t index)
{
return pbuffer[(out + index) % buffer_size];
}
//*************************************************************************
/// Get a const reference to the item at the back of the buffer.
/// Asserts an error if the buffer is empty.
//*************************************************************************
const_reference operator [](size_t index) const
{
return pbuffer[(out + index) % buffer_size];
}
//*************************************************************************
/// push.
/// Adds an item to the buffer.
/// If the buffer is filled then the oldest item is overwritten.
//*************************************************************************
void push(const_reference item)
{
::new (&pbuffer[in]) T(item);
increment_in();
// Did we catch up with the 'out' index?
if (in == out)
{
// Forget about the oldest one.
pbuffer[out].~T();
this->increment_out();
}
else
{
ETL_INCREMENT_DEBUG_COUNT;
}
}
#if ETL_USING_CPP11
//*************************************************************************
/// push.
/// Adds an item to the buffer.
/// If the buffer is filled then the oldest item is overwritten.
//*************************************************************************
void push(rvalue_reference item)
{
::new (&pbuffer[in]) T(etl::move(item));
increment_in();
// Did we catch up with the 'out' index?
if (in == out)
{
// Forget about the oldest item.
pbuffer[out].~T();
increment_out();
}
else
{
ETL_INCREMENT_DEBUG_COUNT;
}
}
#endif
//*************************************************************************
/// Push a buffer from an iterator range.
//*************************************************************************
template <typename TIterator>
void push(TIterator first, const TIterator& last)
{
while (first != last)
{
push(*first);
++first;
}
}
//*************************************************************************
/// pop
//*************************************************************************
void pop()
{
ETL_ASSERT(!empty(), ETL_ERROR(circular_buffer_empty));
pbuffer[out].~T();
increment_out();
ETL_DECREMENT_DEBUG_COUNT;
}
//*************************************************************************
/// pop(n)
//*************************************************************************
void pop(size_type n)
{
while (n-- != 0U)
{
pop();
}
}
//*************************************************************************
/// Clears the buffer.
//*************************************************************************
void clear()
{
if ETL_IF_CONSTEXPR(etl::is_trivially_destructible<T>::value)
{
in = 0U;
out = 0U;
ETL_RESET_DEBUG_COUNT;
}
else
{
while (!empty())
{
pop();
}
}
}
//*************************************************************************
/// Fills the buffer.
//*************************************************************************
void fill(const T& value)
{
etl::fill(begin(), end(), value);
}
#ifdef ETL_ICIRCULAR_BUFFER_REPAIR_ENABLE
//*************************************************************************
/// Fix the internal pointers after a low level memory copy.
//*************************************************************************
virtual void repair() = 0;
#endif
//*************************************************************************
/// - operator for iterator
//*************************************************************************
friend difference_type operator -(const iterator& lhs, const iterator& rhs)
{
return distance(rhs, lhs);
}
//*************************************************************************
/// - operator for const_iterator
//*************************************************************************
friend difference_type operator -(const const_iterator& lhs, const const_iterator& rhs)
{
return distance(rhs, lhs);
}
protected:
//*************************************************************************
/// Protected constructor.
//*************************************************************************
icircular_buffer(pointer pbuffer_, size_type max_length)
: circular_buffer_base(max_length + 1U)
, pbuffer(pbuffer_)
{
}
//*************************************************************************
/// Measures the distance between two iterators.
//*************************************************************************
template <typename TIterator1, typename TIterator2>
static difference_type distance(const TIterator1& range_begin, const TIterator2& range_end)
{
difference_type distance1 = distance(range_begin);
difference_type distance2 = distance(range_end);
return distance2 - distance1;
}
//*************************************************************************
/// Measures the distance from the _begin iterator to the specified iterator.
//*************************************************************************
template <typename TIterator>
static difference_type distance(const TIterator& other)
{
const difference_type index = other.get_index();
const difference_type reference_index = other.container().out;
const size_t buffer_size = other.container().buffer_size;
if (index < reference_index)
{
return buffer_size + index - reference_index;
}
else
{
return index - reference_index;
}
}
//*************************************************************************
/// Fix the internal pointers after a low level memory copy.
//*************************************************************************
void repair_buffer(T* pbuffer_)
{
pbuffer = pbuffer_;
}
pointer pbuffer;
private:
//*************************************************************************
/// Destructor.
//*************************************************************************
#if defined(ETL_POLYMORPHIC_CIRCULAR_BUFFER) || defined(ETL_POLYMORPHIC_CONTAINERS)
public:
virtual ~icircular_buffer()
{
}
#else
protected:
~icircular_buffer()
{
}
#endif
};
//***************************************************************************
/// A fixed capacity circular buffer.
/// Internal buffer.
//***************************************************************************
template <typename T, size_t MAX_SIZE_>
class circular_buffer : public icircular_buffer<T>
{
public:
ETL_STATIC_ASSERT((MAX_SIZE_ > 0U), "Zero capacity etl::circular_buffer is not valid");
static ETL_CONSTANT typename icircular_buffer<T>::size_type MAX_SIZE = typename icircular_buffer<T>::size_type(MAX_SIZE_);
//*************************************************************************
/// Constructor.
//*************************************************************************
circular_buffer()
: icircular_buffer<T>(reinterpret_cast<T*>(buffer.raw), MAX_SIZE)
{
}
//*************************************************************************
/// Constructor.
/// Constructs a buffer from an iterator range.
//*************************************************************************
template <typename TIterator>
circular_buffer(TIterator first, const TIterator& last, typename etl::enable_if<!etl::is_integral<TIterator>::value, int>::type = 0)
: icircular_buffer<T>(reinterpret_cast<T*>(buffer.raw), MAX_SIZE)
{
while (first != last)
{
this->push(*first);
++first;
}
}
#if ETL_HAS_INITIALIZER_LIST
//*************************************************************************
/// Construct from initializer_list.
//*************************************************************************
circular_buffer(std::initializer_list<T> init)
: icircular_buffer<T>(reinterpret_cast<T*>(buffer.raw), MAX_SIZE)
{
this->push(init.begin(), init.end());
}
#endif
//*************************************************************************
/// Copy Constructor.
//*************************************************************************
circular_buffer(const circular_buffer& other)
: icircular_buffer<T>(reinterpret_cast<T*>(buffer.raw), MAX_SIZE)
{
if (this != &other)
{
this->push(other.begin(), other.end());
}
}
//*************************************************************************
/// Assignment operator
//*************************************************************************
circular_buffer& operator =(const circular_buffer& other)
{
if (this != &other)
{
this->clear();
this->push(other.begin(), other.end());
}
return *this;
}
#if ETL_USING_CPP11
//*************************************************************************
/// Move Constructor.
//*************************************************************************
circular_buffer(circular_buffer&& other)
: icircular_buffer<T>(reinterpret_cast<T*>(buffer.raw), MAX_SIZE)
{
if (this != &other)
{
typename etl::icircular_buffer<T>::iterator itr = other.begin();
while (itr != other.end())
{
this->push(etl::move(*itr));
++itr;
}
}
}
//*************************************************************************
/// Move Assignment operator
//*************************************************************************
circular_buffer& operator =(circular_buffer&& other)
{
if (this != &other)
{
this->clear();
for (typename etl::icircular_buffer<T>::const_iterator itr = other.begin(); itr != other.end(); ++itr)
{
this->push(etl::move(*itr));
}
}
return *this;
}
#endif
//*************************************************************************
/// Destructor.
//*************************************************************************
~circular_buffer()
{
this->clear();
}
//*************************************************************************
/// Fix the internal pointers after a low level memory copy.
//*************************************************************************
#ifdef ETL_ICIRCULAR_BUFFER_REPAIR_ENABLE
virtual void repair() ETL_OVERRIDE
#else
void repair()
#endif
{
ETL_ASSERT(etl::is_trivially_copyable<T>::value, ETL_ERROR(etl::circular_buffer_incompatible_type));
etl::icircular_buffer<T>::repair_buffer(buffer);
}
private:
/// The uninitialised storage.
etl::uninitialized_buffer_of<T, MAX_SIZE + 1> buffer;
};
template <typename T, size_t MAX_SIZE_>
ETL_CONSTANT typename icircular_buffer<T>::size_type circular_buffer<T, MAX_SIZE_>::MAX_SIZE;
//***************************************************************************
/// A fixed capacity circular buffer.
/// External buffer.
//***************************************************************************
template <typename T>
class circular_buffer_ext : public icircular_buffer<T>
{
public:
//*************************************************************************
/// Constructor.
//*************************************************************************
circular_buffer_ext(void* buffer, size_t max_size)
: icircular_buffer<T>(reinterpret_cast<T*>(buffer), max_size)
{
}
//*************************************************************************
/// Constructor.
/// Null buffer.
//*************************************************************************
circular_buffer_ext(size_t max_size)
: icircular_buffer<T>(ETL_NULLPTR, max_size)
{
}
//*************************************************************************
/// Constructor.
/// Constructs a buffer from an iterator range.
//*************************************************************************
template <typename TIterator>
circular_buffer_ext(TIterator first, const TIterator& last, void* buffer, size_t max_size, typename etl::enable_if<!etl::is_integral<TIterator>::value, int>::type = 0)
: icircular_buffer<T>(reinterpret_cast<T*>(buffer), max_size)
{
while (first != last)
{
this->push(*first);
++first;
}
}
#if ETL_HAS_INITIALIZER_LIST
//*************************************************************************
/// Construct from initializer_list.
//*************************************************************************
circular_buffer_ext(std::initializer_list<T> init, void* buffer, size_t max_size)
: icircular_buffer<T>(reinterpret_cast<T*>(buffer), max_size)
{
this->push(init.begin(), init.end());
}
#endif
//*************************************************************************
/// Construct a copy.
//*************************************************************************
circular_buffer_ext(const circular_buffer_ext& other, void* buffer, size_t max_size)
: icircular_buffer<T>(reinterpret_cast<T*>(buffer), max_size)
{
if (this != &other)
{
this->push(other.begin(), other.end());
}
}
//*************************************************************************
/// Copy Constructor (Deleted)
//*************************************************************************
circular_buffer_ext(const circular_buffer_ext& other) ETL_DELETE;
//*************************************************************************
/// Assignment operator
//*************************************************************************
circular_buffer_ext& operator =(const circular_buffer_ext& other)
{
if (this != &other)
{
this->clear();
this->push(other.begin(), other.end());
}
return *this;
}
#if ETL_USING_CPP11
//*************************************************************************
/// Move Constructor.
//*************************************************************************
circular_buffer_ext(circular_buffer_ext&& other, void* buffer, size_t max_size)
: icircular_buffer<T>(reinterpret_cast<T*>(buffer), max_size)
{
if (this != &other)
{
typename etl::icircular_buffer<T>::iterator itr = other.begin();
while (itr != other.end())
{
this->push(etl::move(*itr));
++itr;
}
}
}
//*************************************************************************
/// Move Assignment operator
//*************************************************************************
circular_buffer_ext& operator =(circular_buffer_ext&& other)
{
if (this != &other)
{
this->clear();
for (typename etl::icircular_buffer<T>::iterator itr = other.begin(); itr != other.end(); ++itr)
{
this->push(etl::move(*itr));
}
}
return *this;
}
#endif
//*************************************************************************
/// Swap with another circular buffer
//*************************************************************************
void swap(circular_buffer_ext& other) ETL_NOEXCEPT
{
using ETL_OR_STD::swap; // Allow ADL
swap(this->in, other.in);
swap(this->out, other.out);
swap(this->pbuffer, other.pbuffer);
swap(this->buffer_size, other.buffer_size);
#if defined(ETL_DEBUG_COUNT)
this->etl_debug_count.swap(other.etl_debug_count);
#endif
}
//*************************************************************************
/// set_buffer
//*************************************************************************
void set_buffer(void* buffer)
{
this->pbuffer = reinterpret_cast<T*>(buffer);
}
//*************************************************************************
/// set_buffer
//*************************************************************************
bool is_valid() const
{
return this->pbuffer != ETL_NULLPTR;
}
//*************************************************************************
/// Destructor.
//*************************************************************************
~circular_buffer_ext()
{
this->clear();
}
//*************************************************************************
/// Fix the internal pointers after a low level memory copy.
//*************************************************************************
#ifdef ETL_ICIRCULAR_BUFFER_REPAIR_ENABLE
virtual void repair() ETL_OVERRIDE
#else
void repair()
#endif
{
}
};
//*************************************************************************
/// Template deduction guides.
//*************************************************************************
#if ETL_USING_CPP17 && ETL_HAS_INITIALIZER_LIST
template <typename T, typename... Ts>
circular_buffer(T, Ts...)
->circular_buffer<etl::enable_if_t<(etl::is_same_v<T, Ts> && ...), T>, 1U + sizeof...(Ts)>;
#endif
//*************************************************************************
/// Overloaded swap for etl::circular_buffer_ext<T, 0>
//*************************************************************************
template <typename T>
void swap(etl::circular_buffer_ext<T>& lhs, etl::circular_buffer_ext<T>& rhs)
{
lhs.swap(rhs);
}
//*************************************************************************
/// Equality operator
//*************************************************************************
template <typename T>
bool operator ==(const icircular_buffer<T>& lhs, const icircular_buffer<T>& rhs)
{
return (lhs.size() == rhs.size()) && etl::equal(lhs.begin(), lhs.end(), rhs.begin());
}
//*************************************************************************
/// Inequality operator
//*************************************************************************
template <typename T>
bool operator !=(const icircular_buffer<T>& lhs, const icircular_buffer<T>& rhs)
{
return !(lhs == rhs);
}
}
#endif