Containers (STL-compatible) StateMachines MessageBus and more for Embedded Systems. See www.etlcpp.com
Diff: intrusive_stack.h
- Revision:
- 0:b47c2a7920c2
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/intrusive_stack.h Fri Mar 16 16:34:18 2018 +0000 @@ -0,0 +1,257 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. +https://github.com/ETLCPP/etl +http://www.etlcpp.com + +Copyright(c) 2016 jwellbelove + +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_INTRUSIVE_STACK__ +#define __ETL_INTRUSIVE_STACK__ + +#include <stddef.h> + +#include "platform.h" +#include "type_traits.h" +#include "error_handler.h" +#include "intrusive_links.h" + +#define ETL_FILE "28" + +namespace etl +{ + //*************************************************************************** + /// Exception base for intrusive stack + ///\ingroup intrusive_stack + //*************************************************************************** + class intrusive_stack_exception : public etl::exception + { + public: + + intrusive_stack_exception(string_type reason_, string_type file_name_, numeric_type line_number_) + : exception(reason_, file_name_, line_number_) + { + } + }; + + //*************************************************************************** + /// intrusive_stack empty exception. + ///\ingroup intrusive_stack + //*************************************************************************** + class intrusive_stack_empty : public intrusive_stack_exception + { + public: + + intrusive_stack_empty(string_type file_name_, numeric_type line_number_) + : intrusive_stack_exception(ETL_ERROR_TEXT("intrusive_stack:empty", ETL_FILE"A"), file_name_, line_number_) + { + } + }; + + //*************************************************************************** + ///\ingroup stack + /// Base for intrusive stack. Stores elements derived any type that supports an 'etl_next' pointer member. + /// \tparam TLink The link type that the value is derived from. + //*************************************************************************** + template <typename TLink> + class intrusive_stack_base + { + public: + + // Node typedef. + typedef TLink link_type; + + //************************************************************************* + /// Adds a value to the stack. + ///\param value The value to push to the stack. + //************************************************************************* + void push(link_type& value) + { + value.clear(); + + if (p_top != std::nullptr) + { + etl::link(value, p_top); + } + + p_top = &value; + + ++current_size; + } + + //************************************************************************* + /// Removes the oldest item from the top of the stack. + /// Undefined behaviour if the stack is already empty. + //************************************************************************* + void pop() + { +#if defined(ETL_CHECK_PUSH_POP) + ETL_ASSERT(!empty(), ETL_ERROR(intrusive_stack_empty)); +#endif + link_type* p_next = p_top->etl_next; + p_top = p_next; + --current_size; + } + + //************************************************************************* + /// Removes the oldest item from the queue and pushes it to the destination. + /// Undefined behaviour if the queue is already empty. + /// NOTE: The destination must be an intrusize container that supports a push(TLink) member function. + //************************************************************************* + template <typename TContainer> + void pop_into(TContainer& destination) + { + link_type* p_link = p_top; + pop(); + destination.push(*p_link); + } + + //************************************************************************* + /// Reverses the stack order. + //************************************************************************* + void reverse() + { + link_type* previous = std::nullptr; + link_type* current = p_top; + link_type* next; + + while (current != std::nullptr) + { + next = current->etl_next; + current->etl_next = previous; + previous = current; + current = next; + } + + p_top = previous; + } + + //************************************************************************* + /// Clears the stack to the empty state. + //************************************************************************* + void clear() + { + while (!empty()) + { + pop(); + } + + current_size = 0; + } + + //************************************************************************* + /// Checks if the stack is in the empty state. + //************************************************************************* + bool empty() const + { + return current_size == 0; + } + + //************************************************************************* + /// Returns the number of elements. + //************************************************************************* + size_t size() const + { + return current_size; + } + + protected: + + //************************************************************************* + /// Constructor + //************************************************************************* + intrusive_stack_base() + : p_top(std::nullptr), + current_size(0) + { + } + + link_type* p_top; ///< The current top of the stack. + + size_t current_size; ///< Counts the number of elements in the list. + }; + + //*************************************************************************** + ///\ingroup stack + /// An intrusive stack. Stores elements derived from any type that supports an 'etl_next' pointer member. + /// \warning This stack cannot be used for concurrent access from multiple threads. + /// \tparam TValue The type of value that the stack holds. + /// \tparam TLink The link type that the value is derived from. + //*************************************************************************** + template <typename TValue, typename TLink> + class intrusive_stack : public etl::intrusive_stack_base<TLink> + { + public: + + // Node typedef. + typedef typename etl::intrusive_stack_base<TLink>::link_type link_type; + + // STL style typedefs. + typedef TValue value_type; + typedef value_type* pointer; + typedef const value_type* const_pointer; + typedef value_type& reference; + typedef const value_type& const_reference; + typedef size_t size_type; + + //************************************************************************* + /// Constructor + //************************************************************************* + intrusive_stack() + : intrusive_stack_base<TLink>() + { + } + + //************************************************************************* + /// Gets a reference to the value at the top of the stack. + /// Undefined behaviour if the stack is empty. + /// \return A reference to the value at the top of the stack. + //************************************************************************* + reference top() + { + return *static_cast<TValue*>(this->p_top); + } + + //************************************************************************* + /// Gets a const reference to the value at the top of the stack.<br> + /// \return A const reference to the value at the top of the stack. + //************************************************************************* + const_reference top() const + { + return *static_cast<const TValue*>(this->p_top); + } + + private: + + // Disable copy construction and assignment. + intrusive_stack(const intrusive_stack&); + intrusive_stack& operator = (const intrusive_stack& rhs); + }; +} + +#undef ETL_FILE + +#endif +