///\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 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::difference_type difference_type; //************************************************************************* /// Iterator iterating through the circular buffer. //************************************************************************* class iterator : public etl::iterator { 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* picb_, size_type current_) : picb(picb_) , current(current_) { } private: const icircular_buffer* picb; size_type current; }; //************************************************************************* /// Iterator iterating through the circular buffer. //************************************************************************* class const_iterator : public etl::iterator { 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* picb_, size_type current_) : picb(picb_) , current(current_) { } private: const icircular_buffer* picb; size_type current; }; friend class iterator; friend class const_iterator; typedef etl::reverse_iterator reverse_iterator; typedef etl::reverse_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 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::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 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 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 class circular_buffer : public icircular_buffer { public: ETL_STATIC_ASSERT((MAX_SIZE_ > 0U), "Zero capacity etl::circular_buffer is not valid"); static ETL_CONSTANT typename icircular_buffer::size_type MAX_SIZE = typename icircular_buffer::size_type(MAX_SIZE_); //************************************************************************* /// Constructor. //************************************************************************* circular_buffer() : icircular_buffer(reinterpret_cast(buffer.raw), MAX_SIZE) { } //************************************************************************* /// Constructor. /// Constructs a buffer from an iterator range. //************************************************************************* template circular_buffer(TIterator first, const TIterator& last, typename etl::enable_if::value, int>::type = 0) : icircular_buffer(reinterpret_cast(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 init) : icircular_buffer(reinterpret_cast(buffer.raw), MAX_SIZE) { this->push(init.begin(), init.end()); } #endif //************************************************************************* /// Copy Constructor. //************************************************************************* circular_buffer(const circular_buffer& other) : icircular_buffer(reinterpret_cast(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(reinterpret_cast(buffer.raw), MAX_SIZE) { if (this != &other) { typename etl::icircular_buffer::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::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::value, ETL_ERROR(etl::circular_buffer_incompatible_type)); etl::icircular_buffer::repair_buffer(buffer); } private: /// The uninitialised storage. etl::uninitialized_buffer_of buffer; }; template ETL_CONSTANT typename icircular_buffer::size_type circular_buffer::MAX_SIZE; //*************************************************************************** /// A fixed capacity circular buffer. /// External buffer. //*************************************************************************** template class circular_buffer_ext : public icircular_buffer { public: //************************************************************************* /// Constructor. //************************************************************************* circular_buffer_ext(void* buffer, size_t max_size) : icircular_buffer(reinterpret_cast(buffer), max_size) { } //************************************************************************* /// Constructor. /// Null buffer. //************************************************************************* circular_buffer_ext(size_t max_size) : icircular_buffer(ETL_NULLPTR, max_size) { } //************************************************************************* /// Constructor. /// Constructs a buffer from an iterator range. //************************************************************************* template circular_buffer_ext(TIterator first, const TIterator& last, void* buffer, size_t max_size, typename etl::enable_if::value, int>::type = 0) : icircular_buffer(reinterpret_cast(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 init, void* buffer, size_t max_size) : icircular_buffer(reinterpret_cast(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(reinterpret_cast(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(reinterpret_cast(buffer), max_size) { if (this != &other) { typename etl::icircular_buffer::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::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(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 circular_buffer(T, Ts...) ->circular_buffer && ...), T>, 1U + sizeof...(Ts)>; #endif //************************************************************************* /// Overloaded swap for etl::circular_buffer_ext //************************************************************************* template void swap(etl::circular_buffer_ext& lhs, etl::circular_buffer_ext& rhs) { lhs.swap(rhs); } //************************************************************************* /// Equality operator //************************************************************************* template bool operator ==(const icircular_buffer& lhs, const icircular_buffer& rhs) { return (lhs.size() == rhs.size()) && etl::equal(lhs.begin(), lhs.end(), rhs.begin()); } //************************************************************************* /// Inequality operator //************************************************************************* template bool operator !=(const icircular_buffer& lhs, const icircular_buffer& rhs) { return !(lhs == rhs); } } #endif