diff --git a/istack.h b/istack.h new file mode 100644 index 00000000..db1720ff --- /dev/null +++ b/istack.h @@ -0,0 +1,161 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. + +Copyright(c) 2014 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_istack__ +#define __etl_istack__ +#define __etl_in_istack_h__ + +#include + +#include "stack_base.h" + +namespace etl +{ + //*************************************************************************** + ///\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 item that the stack holds. + //*************************************************************************** + template + class istack : public stack_base + { + public: + + typedef stack_base::size_type size_type; ///< The type used for determining the size of the stack. + 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. + + //************************************************************************* + /// Adds an item to the stack. + /// If ETL_USE_EXCEPTIONS is defined, throws an etl::stack_full_exception is the stack is already full, + /// otherwise does nothing if full. + ///\param item The item to push to the stack. + //************************************************************************* + void push(const_reference item) + { + if (!full()) + { + top_index = current_size++; + buffer[top_index] = item; + } +#ifdef ETL_USE_EXCEPTIONS + else + { + throw stack_full_exception(); + } +#endif + } + + //************************************************************************* + /// Allows a possibly more efficient 'push' by moving to the next input item + /// and returning a reference to it. + /// This may eliminate a copy by allowing direct construction in-place.
+ /// If ETL_USE_EXCEPTIONS is defined, throws an etl::stack_full_exception is the stack is already full, + /// otherwise does nothing if full. + /// \return A reference to the position to 'push' to. + //************************************************************************* + reference push() + { + if (!full()) + { + top_index = current_size++; + } +#ifdef ETL_USE_EXCEPTIONS + else + { + throw stack_full_exception(); + } +#endif + + return buffer[top_index]; + } + + //************************************************************************* + /// Gets a reference to the item at the top of the stack.
+ /// If ETL_USE_EXCEPTIONS is defined, throws an etl::stack_empty_exception if the stack is empty.
+ /// If ETL_USE_EXCEPTIONS is not defined and the stack is empty, the return value is undefined. + /// \return A reference to the item at the top of the stack. + //************************************************************************* + reference top() + { +#ifdef ETL_USE_EXCEPTIONS + if (empty()) + { + throw stack_empty_exception(); + } +#endif + + return buffer[top_index]; + } + + //************************************************************************* + /// Gets a const reference to the item at the top of the stack.
+ /// If ETL_USE_EXCEPTIONS is defined, throws an etl::stack_empty_exception if the stack is empty.
+ /// If ETL_USE_EXCEPTIONS is not defined and the stack is empty, the return value is undefined. + /// \return A const reference to the item at the top of the stack. + //************************************************************************* + const_reference top() const + { +#ifdef ETL_USE_EXCEPTIONS + if (empty()) + { + throw stack_empty_exception(); + } +#endif + + return buffer[top_index]; + } + + protected: + + //************************************************************************* + /// The constructor that is called from derived classes. + //************************************************************************* + istack(T* buffer, size_type max_size) + : stack_base(max_size), + buffer(buffer) + { + } + + private: + + T* buffer; ///< The internal buffer. + }; +} + +#undef __etl_in_istack_h__ +#endif diff --git a/stack.h b/stack.h new file mode 100644 index 00000000..b99ae161 --- /dev/null +++ b/stack.h @@ -0,0 +1,71 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. + +Copyright(c) 2014 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_stack__ +#define __etl_stack__ + +#include + +#include "istack.h" + +//***************************************************************************** +///\defgroup stack stack +/// A First-in / first-out stack with the capacity defined at compile time, +/// written in the STL style. +///\ingroup Containers +//***************************************************************************** + +namespace etl +{ + //*************************************************************************** + ///\ingroup stack + /// A fixed capacity stack. + /// This stack does not support concurrent access by different threads. + /// \tparam T The type this stack should support. + /// \tparam SIZE The maximum capacity of the stack. + //*************************************************************************** + template + class stack : public istack + { + public: + + //************************************************************************* + /// Default constructor. + //************************************************************************* + stack() + : istack(buffer, SIZE) + { + } + + private: + + T buffer[SIZE]; ///< The internal buffer. + }; +} + +#endif diff --git a/stack_base.h b/stack_base.h new file mode 100644 index 00000000..45c18269 --- /dev/null +++ b/stack_base.h @@ -0,0 +1,178 @@ +///\file + +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. + +Copyright(c) 2014 jwellbelove + +Permission is hereby granted, free of charge, to any person obtatoptopg a copy +of this software and associated documentation files(the "Software"), to deal +top the Software withtop restriction, topcludtopg withtop 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 followtopg conditions : + +The above copyright notice and this permission notice shall be included top 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_in_istack_h__ +#error This header is a private element of etl::stack & etl::istack +#endif + +#ifndef __etl_stack_base__ +#define __etl_stack_base__ + +#include + +#include "exception.h" + +namespace etl +{ +#ifdef ETL_USE_EXCEPTIONS + //*************************************************************************** + ///\ingroup stack + /// The base class for stack exceptions. + //*************************************************************************** + class stack_exception : public exception + { + public: + + stack_exception(const char* what) + : exception(what) + { + } + }; + + //*************************************************************************** + ///\ingroup stack + /// The exception thrown when the stack is full. + //*************************************************************************** + class stack_full_exception : public stack_exception + { + public: + + stack_full_exception() + : stack_exception("stack full") + { + } + }; + + //*************************************************************************** + ///\ingroup stack + /// The exception thrown when the stack is empty. + //*************************************************************************** + class stack_empty_exception : public stack_exception + { + public: + + stack_empty_exception() + : stack_exception("stack empty") + { + } + }; +#endif + + //*************************************************************************** + ///\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. + + //************************************************************************* + /// 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 capacity() const + { + return MAX_SIZE; + } + + //************************************************************************* + /// Returns the maximum number of items that can be stacked. + //************************************************************************* + size_type max_size() const + { + return MAX_SIZE; + } + + //************************************************************************* + /// Clears the stack to the empty state. + //************************************************************************* + void clear() + { + top_index = 0; + current_size = 0; + } + + //************************************************************************* + /// 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; + } + + //************************************************************************* + /// Removes the oldest item from the top of the stack. + /// Does nothing if the stack is already empty. + //************************************************************************* + void pop() + { + if (!empty()) + { + --top_index; + --current_size; + } + } + + protected: + + //************************************************************************* + /// The constructor that is called from derived classes. + //************************************************************************* + stack_base(size_type max_size) + : MAX_SIZE(max_size) + { + clear(); + } + + 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. + }; +} + +#endif diff --git a/test/test_stack.cpp b/test/test_stack.cpp new file mode 100644 index 00000000..d4d1420b --- /dev/null +++ b/test/test_stack.cpp @@ -0,0 +1,290 @@ +/****************************************************************************** +The MIT License(MIT) + +Embedded Template Library. + +Copyright(c) 2014 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. +******************************************************************************/ + +#include + +#include "../stack.h" + +namespace +{ + SUITE(TestStack) + { + //************************************************************************* + TEST(Size) + { + etl::stack stack; + + stack.push(1); + stack.push(2); + stack.push(3); + + CHECK_EQUAL(3, stack.size()); + } + + //************************************************************************* + TEST(Capacity) + { + etl::stack stack; + + CHECK_EQUAL(4, stack.capacity()); + } + + //************************************************************************* + TEST(Clear) + { + etl::stack stack; + + stack.push(1); + stack.push(2); + stack.clear(); + CHECK_EQUAL(0, stack.size()); + } + + //************************************************************************* + TEST(Empty) + { + etl::stack stack; + + CHECK(stack.empty()); + + stack.push(1); + + CHECK(!stack.empty()); + } + + //************************************************************************* + TEST(Full) + { + etl::stack stack; + + CHECK(!stack.full()); + + stack.push(1); + stack.push(2); + stack.push(3); + stack.push(4); + + CHECK(stack.full()); + } + + //************************************************************************* + TEST(Push) + { + etl::stack stack; + + stack.push(1); + CHECK_EQUAL(1, stack.size()); + + stack.push(2); + CHECK_EQUAL(2, stack.size()); + + CHECK_EQUAL(2, stack.top()); + + stack.pop(); + CHECK_EQUAL(1, stack.top()); + } + + //************************************************************************* + TEST(PushVoid) + { + etl::stack stack; + + stack.push() = 1; + CHECK_EQUAL(1, stack.size()); + + stack.push() = 2; + CHECK_EQUAL(2, stack.size()); + + CHECK_EQUAL(2, stack.top()); + + stack.pop(); + CHECK_EQUAL(1, stack.top()); + } + + //************************************************************************* + TEST(PushExcess) + { + etl::stack stack; + + bool gotException = false; + + try + { + for (size_t i = 0; i < stack.capacity() + 1; ++i) + { + stack.push(1); + } + } + catch (etl::stack_full_exception&) + { + gotException = true; + } + catch (...) + { + CHECK(false); + } + + CHECK(gotException); + } + + //************************************************************************* + TEST(Pop) + { + etl::stack stack; + + stack.push(1); + stack.push(2); + stack.pop(); + CHECK_EQUAL(1, stack.size()); + } + + //************************************************************************* + TEST(Top) + { + etl::stack stack; + + stack.push(1); + stack.push(2); + stack.push(3); + + CHECK_EQUAL(3, stack.top()); + + stack.pop(); + CHECK_EQUAL(2, stack.top()); + + stack.pop(); + CHECK_EQUAL(1, stack.top()); + } + + //************************************************************************* + TEST(TopConst) + { + etl::stack stack; + const etl::stack& constQueue = stack; + + stack.push(1); + stack.push(2); + stack.push(3); + + CHECK_EQUAL(3, constQueue.top()); + + stack.pop(); + CHECK_EQUAL(2, constQueue.top()); + + stack.pop(); + CHECK_EQUAL(1, constQueue.top()); + } + + //************************************************************************* + TEST(TopException) + { + etl::stack stack; + + bool gotException = false; + + try + { + stack.top(); + } + catch (etl::stack_empty_exception&) + { + gotException = true; + } + catch (...) + { + CHECK(false); + } + + CHECK(gotException); + } + + //************************************************************************* + TEST(CheckMultiplePush) + { + etl::stack stack; + + stack.push(1); + stack.push(2); + stack.push(3); + + bool pass = true; + + if (stack.top() != 3) + { + pass = false; + } + + stack.pop(); + + if (stack.top() != 2) + { + pass = false; + } + + stack.pop(); + + if (stack.top() != 1) + { + pass = false; + } + + CHECK(pass); + } + + //************************************************************************* + TEST(CheckMultiplePushVoid) + { + etl::stack stack; + + stack.push() = 1; + stack.push() = 2; + stack.push() = 3; + + bool pass = true; + + if (stack.top() != 3) + { + pass = false; + } + + stack.pop(); + + if (stack.top() != 2) + { + pass = false; + } + + stack.pop(); + + if (stack.top() != 1) + { + pass = false; + } + + CHECK(pass); + } + }; +} \ No newline at end of file