Added stack container class

This commit is contained in:
jwellbelove 2014-10-27 11:30:30 +00:00
parent dc5ab85e28
commit 670c8c7463
4 changed files with 700 additions and 0 deletions

161
istack.h Normal file
View File

@ -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 <cstddef>
#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<int, 10> myQueue;
/// etl::istack<int>& 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 <typename T>
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.<br>
/// 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.<br>
/// If ETL_USE_EXCEPTIONS is defined, throws an etl::stack_empty_exception if the stack is empty.<br>
/// 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.<br>
/// If ETL_USE_EXCEPTIONS is defined, throws an etl::stack_empty_exception if the stack is empty.<br>
/// 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

71
stack.h Normal file
View File

@ -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 <cstddef>
#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 <typename T, const size_t SIZE>
class stack : public istack<T>
{
public:
//*************************************************************************
/// Default constructor.
//*************************************************************************
stack()
: istack<T>(buffer, SIZE)
{
}
private:
T buffer[SIZE]; ///< The internal buffer.
};
}
#endif

178
stack_base.h Normal file
View File

@ -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 <cstddef>
#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 <b>true</b> if the stack is empty, otherwise <b>false</b>
//*************************************************************************
bool empty() const
{
return current_size == 0;
}
//*************************************************************************
/// Checks to see if the stack is full.
/// \return <b>true</b> if the stack is full, otherwise <b>false</b>
//*************************************************************************
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

290
test/test_stack.cpp Normal file
View File

@ -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 <UnitTest++/UnitTest++.h>
#include "../stack.h"
namespace
{
SUITE(TestStack)
{
//*************************************************************************
TEST(Size)
{
etl::stack<int, 4> stack;
stack.push(1);
stack.push(2);
stack.push(3);
CHECK_EQUAL(3, stack.size());
}
//*************************************************************************
TEST(Capacity)
{
etl::stack<int, 4> stack;
CHECK_EQUAL(4, stack.capacity());
}
//*************************************************************************
TEST(Clear)
{
etl::stack<int, 4> stack;
stack.push(1);
stack.push(2);
stack.clear();
CHECK_EQUAL(0, stack.size());
}
//*************************************************************************
TEST(Empty)
{
etl::stack<int, 4> stack;
CHECK(stack.empty());
stack.push(1);
CHECK(!stack.empty());
}
//*************************************************************************
TEST(Full)
{
etl::stack<int, 4> stack;
CHECK(!stack.full());
stack.push(1);
stack.push(2);
stack.push(3);
stack.push(4);
CHECK(stack.full());
}
//*************************************************************************
TEST(Push)
{
etl::stack<int, 4> 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<int, 4> 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<int, 4> 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<int, 4> stack;
stack.push(1);
stack.push(2);
stack.pop();
CHECK_EQUAL(1, stack.size());
}
//*************************************************************************
TEST(Top)
{
etl::stack<int, 4> 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<int, 4> stack;
const etl::stack<int, 4>& 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<int, 4> stack;
bool gotException = false;
try
{
stack.top();
}
catch (etl::stack_empty_exception&)
{
gotException = true;
}
catch (...)
{
CHECK(false);
}
CHECK(gotException);
}
//*************************************************************************
TEST(CheckMultiplePush)
{
etl::stack<int, 4> 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<int, 4> 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);
}
};
}