diff --git a/src/stack.h b/src/stack.h index 98624010..a19dfb4f 100644 --- a/src/stack.h +++ b/src/stack.h @@ -35,10 +35,16 @@ SOFTWARE. #include #include -#include "istack.h" #include "container.h" #include "alignment.h" #include "array.h" +#include "exception.h" +#include "error_handler.h" +#include "debug_count.h" +#include "type_traits.h" +#include "parameter_type.h" + +#define ETL_FILE "15" //***************************************************************************** ///\defgroup stack stack @@ -49,6 +55,275 @@ SOFTWARE. namespace etl { + //*************************************************************************** + ///\ingroup stack + /// The base class for stack exceptions. + //*************************************************************************** + class stack_exception : public exception + { + public: + + stack_exception(string_type what, string_type file_name, numeric_type line_number) + : exception(what, file_name, line_number) + { + } + }; + + //*************************************************************************** + ///\ingroup stack + /// The exception thrown when the stack is full. + //*************************************************************************** + class stack_full : public stack_exception + { + public: + + stack_full(string_type file_name, numeric_type line_number) + : stack_exception(ETL_ERROR_TEXT("stack:full", ETL_FILE"A"), file_name, line_number) + { + } + }; + + //*************************************************************************** + ///\ingroup stack + /// The exception thrown when the stack is empty. + //*************************************************************************** + class stack_empty : public stack_exception + { + public: + + stack_empty(string_type file_name, numeric_type line_number) + : stack_exception(ETL_ERROR_TEXT("stack:empty", ETL_FILE"B"), file_name, line_number) + { + } + }; + + //*************************************************************************** + ///\ingroup stack + /// A fixed capacity stack written in the STL style. + /// \warntopg This stack cannot be used for concurrent access from multiple threads. + //*************************************************************************** + class stack_base + { + public: + + typedef size_t size_type; ///< The type used for determining the size of stack. + + //************************************************************************* + /// Checks to see if the stack is empty. + /// \return true if the stack is empty, otherwise false + //************************************************************************* + bool empty() const + { + return current_size == 0; + } + + //************************************************************************* + /// Checks to see if the stack is full. + /// \return true if the stack is full, otherwise false + //************************************************************************* + bool full() const + { + return current_size == MAX_SIZE; + } + + //************************************************************************* + /// Returns the current number of items top the stack. + //************************************************************************* + size_type size() const + { + return current_size; + } + + //************************************************************************* + /// Returns the maximum number of items that can be stacked. + //************************************************************************* + size_type max_size() const + { + return MAX_SIZE; + } + + //************************************************************************* + /// Returns the remaining capacity. + ///\return The remaining capacity. + //************************************************************************* + size_t available() const + { + return max_size() - size(); + } + + protected: + + //************************************************************************* + /// The constructor that is called from derived classes. + //************************************************************************* + stack_base(size_type max_size) + : top_index(0), + current_size(0), + MAX_SIZE(max_size) + { + } + + size_type top_index; ///< The index of the top of the stack. + size_type current_size; ///< The number of items in the stack. + const size_type MAX_SIZE; ///< The maximum number of items in the stack. + etl::debug_count construct_count; ///< For internal debugging purposes. + }; + + //*************************************************************************** + ///\ingroup stack + ///\brief This is the base for all stacks that contain a particular type. + ///\details Normally a reference to this type will be taken from a derived stack. + ///\code + /// etl::stack myQueue; + /// etl::istack& iQueue = myQueue; + ///\endcode + /// \warning This stack cannot be used for concurrent access from multiple threads. + /// \tparam T The type of value that the stack holds. + //*************************************************************************** + template + class istack : public etl::stack_base + { + public: + + typedef T value_type; ///< The type stored in the stack. + typedef T& reference; ///< A reference to the type used in the stack. + typedef const T& const_reference; ///< A const reference to the type used in the stack. + typedef T* pointer; ///< A pointer to the type used in the stack. + typedef const T* const_pointer; ///< A const pointer to the type used in the stack. + typedef stack_base::size_type size_type; ///< The type used for determining the size of the stack. + + private: + + typedef typename parameter_type::type parameter_t; + + public: + + //************************************************************************* + /// Gets a reference to the value at the top of the stack.
+ /// \return A reference to the value at the top of the stack. + //************************************************************************* + reference top() + { + return p_buffer[top_index]; + } + + //************************************************************************* + /// Adds a value to the stack. + /// If asserts or exceptions are enabled, throws an etl::stack_full if the stack is already full. + ///\param value The value to push to the stack. + //************************************************************************* + void push(parameter_t value) + { +#if defined(ETL_CHECK_PUSH_POP) + ETL_ASSERT(!full(), ETL_ERROR(stack_full)); +#endif + top_index = current_size++; + ::new (&p_buffer[top_index]) T(value); + ++construct_count; + } + + //************************************************************************* + /// Allows a possibly more efficient 'push' by moving to the next input value + /// and returning a reference to it. + /// This may eliminate a copy by allowing direct construction in-place.
+ /// If asserts or exceptions are enabled, throws an etl::stack_full if the stack is already full. + /// \return A reference to the position to 'push' to. + //************************************************************************* + reference push() + { +#if defined(ETL_CHECK_PUSH_POP) + ETL_ASSERT(!full(), ETL_ERROR(stack_full)); +#endif + top_index = current_size++; + ::new (&p_buffer[top_index]) T(); + ++construct_count; + + return p_buffer[top_index]; + } + + //************************************************************************* + /// Gets a const reference to the value at the top of the stack.
+ /// \return A const reference to the value at the top of the stack. + //************************************************************************* + const_reference top() const + { + return p_buffer[top_index]; + } + + //************************************************************************* + /// Clears the stack to the empty state. + //************************************************************************* + void clear() + { + while (current_size > 0) + { + p_buffer[top_index].~T(); + --top_index; + --current_size; + --construct_count; + } + } + + //************************************************************************* + /// Removes the oldest item from the top of the stack. + /// Does nothing if the stack is already empty. + //************************************************************************* + void pop() + { +#if defined(ETL_CHECK_PUSH_POP) + ETL_ASSERT(!empty(), ETL_ERROR(stack_empty)); +#endif + p_buffer[top_index].~T(); + --top_index; + --current_size; + --construct_count; + } + + //************************************************************************* + /// Assignment operator. + //************************************************************************* + istack& operator = (const istack& rhs) + { + if (&rhs != this) + { + clone(rhs); + } + + return *this; + } + + protected: + + //************************************************************************* + /// Make this a clone of the supplied stack + //************************************************************************* + void clone(const istack& other) + { + size_t index = 0; + + for (size_t i = 0; i < other.size(); ++i) + { + push(other.p_buffer[index++]); + } + } + + //************************************************************************* + /// The constructor that is called from derived classes. + //************************************************************************* + istack(T* p_buffer, size_type max_size) + : stack_base(max_size), + p_buffer(p_buffer) + { + } + + private: + + // Disable copy construction. + istack(const istack&); + + T* p_buffer; ///< The internal buffer. + }; + //*************************************************************************** ///\ingroup stack /// A fixed capacity stack. @@ -57,7 +332,7 @@ namespace etl /// \tparam MAX_SIZE The maximum capacity of the stack. //*************************************************************************** template - class stack : public istack + class stack : public etl::istack { public: @@ -65,7 +340,7 @@ namespace etl /// Default constructor. //************************************************************************* stack() - : istack(reinterpret_cast(&buffer[0]), SIZE) + : etl::istack(reinterpret_cast(&buffer[0]), SIZE) { } @@ -73,9 +348,9 @@ namespace etl /// Copy constructor //************************************************************************* stack(const stack& rhs) - : istack(reinterpret_cast(&buffer[0]), SIZE) + : etl::istack(reinterpret_cast(&buffer[0]), SIZE) { - istack::clone(rhs); + etl::istack::clone(rhs); } //************************************************************************* @@ -83,7 +358,7 @@ namespace etl //************************************************************************* ~stack() { - istack::clear(); + etl::istack::clear(); } //************************************************************************* @@ -93,7 +368,7 @@ namespace etl { if (&rhs != this) { - istack::clone(rhs); + etl::istack::clone(rhs); } return *this; @@ -101,9 +376,11 @@ namespace etl private: - /// The unititialised buffer of T used in the stack. + /// The unintitialised buffer of T used in the stack. typename etl::aligned_storage::value>::type buffer[SIZE]; }; } +#undef ETL_FILE + #endif