Skip to content

Commit

Permalink
Refactor Stack utility class
Browse files Browse the repository at this point in the history
  • Loading branch information
chfast committed Sep 2, 2020
1 parent 3dbd671 commit c990a1a
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 161 deletions.
38 changes: 15 additions & 23 deletions lib/fizzy/stack.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,47 +13,39 @@
namespace fizzy
{
template <typename T>
class Stack : public std::vector<T>
class Stack
{
public:
using difference_type = typename std::vector<T>::difference_type;

using std::vector<T>::vector;

using std::vector<T>::back;
using std::vector<T>::emplace_back;
using std::vector<T>::pop_back;
using std::vector<T>::resize;
using std::vector<T>::size;
std::vector<T> m_container;

// Also used: size(), resize(), clear(), empty(), end()

void push(T val) { emplace_back(val); }
public:
void push(T val) { m_container.emplace_back(val); }

template <typename... Args>
void emplace(Args&&... args)
{
std::vector<T>::emplace_back(std::forward<Args>(args)...);
m_container.emplace_back(std::forward<Args>(args)...);
}

T pop()
T pop() noexcept
{
const auto res = back();
pop_back();
assert(!m_container.empty());
const auto res = m_container.back();
m_container.pop_back();
return res;
}

T& operator[](size_t index) noexcept { return std::vector<T>::operator[](size() - index - 1); }
bool empty() const noexcept { return m_container.empty(); }

size_t size() const noexcept { return m_container.size(); }

T& top() noexcept { return (*this)[0]; }
T& operator[](size_t index) noexcept { return m_container[size() - index - 1]; }

/// Drops @a num_elements elements from the top of the stack.
void drop(size_t num_elements = 1) noexcept { resize(size() - num_elements); }
T& top() noexcept { return m_container.back(); }

void shrink(size_t new_size) noexcept
{
assert(new_size <= size());
resize(new_size);
m_container.resize(new_size);
}
};

Expand Down
178 changes: 40 additions & 138 deletions test/unittests/stack_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ TEST(stack, push_and_pop)
stack.push('b');
stack.push('c');

EXPECT_FALSE(stack.empty());
EXPECT_EQ(stack.size(), 3);

EXPECT_EQ(stack.pop(), 'c');
Expand All @@ -40,6 +41,7 @@ TEST(stack, emplace)
stack.emplace('b');
stack.emplace('c');

EXPECT_FALSE(stack.empty());
EXPECT_EQ(stack.size(), 3);

EXPECT_EQ(stack.pop(), 'c');
Expand All @@ -50,124 +52,67 @@ TEST(stack, emplace)
EXPECT_TRUE(stack.empty());
}

TEST(stack, drop_and_peek)
{
Stack<char> stack;
stack.push('w');
stack.push('x');
stack.push('y');
stack.push('z');

EXPECT_FALSE(stack.empty());
EXPECT_EQ(stack.size(), 4);
EXPECT_EQ(stack.top(), 'z');
EXPECT_EQ(stack[0], 'z');
EXPECT_EQ(stack[1], 'y');
EXPECT_EQ(stack[2], 'x');
EXPECT_EQ(stack[3], 'w');
EXPECT_EQ(stack.size(), 4);

stack.drop();
EXPECT_EQ(stack.size(), 3);
EXPECT_EQ(stack.top(), 'y');

stack.drop(2);
EXPECT_EQ(stack.size(), 1);
EXPECT_EQ(stack.top(), 'w');

stack.drop();
EXPECT_EQ(stack.size(), 0);
EXPECT_TRUE(stack.empty());
}

TEST(stack, clear)
{
Stack<char> stack;
stack.push('a');
stack.push('b');

EXPECT_FALSE(stack.empty());
EXPECT_EQ(stack.size(), 2);

stack.drop(0);
EXPECT_FALSE(stack.empty());
EXPECT_EQ(stack.size(), 2);

stack.clear();
EXPECT_TRUE(stack.empty());
EXPECT_EQ(stack.size(), 0);
}

TEST(stack, resize)
TEST(stack, shrink)
{
Stack<char> stack;
stack.push('a');
stack.push('b');

EXPECT_FALSE(stack.empty());
EXPECT_EQ(stack.size(), 2);

// grow stack
stack.resize(4);
EXPECT_FALSE(stack.empty());
EXPECT_EQ(stack.top(), 0);
EXPECT_EQ(stack[1], 0);
EXPECT_EQ(stack[2], 'b');
EXPECT_EQ(stack[3], 'a');
stack.push('c');
stack.push('d');
EXPECT_EQ(stack.top(), 'd');
EXPECT_EQ(stack.size(), 4);

stack.drop();
EXPECT_FALSE(stack.empty());
EXPECT_EQ(stack.size(), 3);

// shrink stack
stack.resize(1);
EXPECT_FALSE(stack.empty());
EXPECT_EQ(stack.size(), 1);

stack.clear();
EXPECT_TRUE(stack.empty());
EXPECT_EQ(stack.size(), 0);

// resize and shrink
stack.resize(4);
stack.shrink(4);
EXPECT_EQ(stack.top(), 'd');
EXPECT_EQ(stack.size(), 4);

stack.shrink(2);
EXPECT_EQ(stack.top(), 'b');
EXPECT_EQ(stack.size(), 2);

stack.shrink(0);
EXPECT_TRUE(stack.empty());
EXPECT_EQ(stack.size(), 0);
}

TEST(stack, iterator)
TEST(stack, struct_item)
{
Stack<char> stack;
stack.push('a');
stack.push('b');
stack.push('c');
struct StackItem
{
char a, b, c;
StackItem() = default; // required for drop() (which calls resize())
StackItem(char _a, char _b, char _c) : a(_a), b(_b), c(_c) {}
};

EXPECT_FALSE(stack.empty());
EXPECT_EQ(stack.size(), 3);
Stack<StackItem> stack;

auto bottom_item = stack.begin();
EXPECT_EQ(*bottom_item, 'a');
stack.emplace('a', 'b', 'c');
stack.emplace('d', 'e', 'f');
stack.emplace('g', 'h', 'i');

auto top_item = stack.end() - 1;
EXPECT_EQ(*top_item, 'c');
EXPECT_EQ(stack.size(), 3);

for (auto it = stack.begin(); it < stack.end(); it++)
*it = 'x';
EXPECT_EQ(stack.top().a, 'g');
EXPECT_EQ(stack.top().b, 'h');
EXPECT_EQ(stack.top().c, 'i');
EXPECT_EQ(stack[1].a, 'd');
EXPECT_EQ(stack[1].b, 'e');
EXPECT_EQ(stack[1].c, 'f');
EXPECT_EQ(stack[2].a, 'a');
EXPECT_EQ(stack[2].b, 'b');
EXPECT_EQ(stack[2].c, 'c');

for (unsigned item = 0; item < stack.size(); item++)
EXPECT_EQ(stack[item], 'x');
}
EXPECT_EQ(stack.pop().a, 'g');

TEST(stack, clear_on_empty)
{
Stack<char> stack;
stack.clear();
EXPECT_EQ(stack.top().a, 'd');
EXPECT_EQ(stack.top().b, 'e');
EXPECT_EQ(stack.top().c, 'f');
EXPECT_EQ(stack[1].a, 'a');
EXPECT_EQ(stack[1].b, 'b');
EXPECT_EQ(stack[1].c, 'c');
}


TEST(operand_stack, construct)
{
OperandStack stack(0);
Expand Down Expand Up @@ -287,46 +232,3 @@ TEST(operand_stack, to_vector)
EXPECT_EQ(result[1].i64, 2);
EXPECT_EQ(result[2].i64, 3);
}

TEST(stack, struct_item)
{
struct StackItem
{
char a, b, c;
StackItem() = default; // required for drop() (which calls resize())
StackItem(char _a, char _b, char _c) : a(_a), b(_b), c(_c) {}
};

Stack<StackItem> stack;

stack.emplace('a', 'b', 'c');
stack.emplace('d', 'e', 'f');
stack.emplace('g', 'h', 'i');

EXPECT_EQ(stack.size(), 3);

EXPECT_EQ(stack.top().a, 'g');
EXPECT_EQ(stack.top().b, 'h');
EXPECT_EQ(stack.top().c, 'i');
EXPECT_EQ(stack[1].a, 'd');
EXPECT_EQ(stack[1].b, 'e');
EXPECT_EQ(stack[1].c, 'f');
EXPECT_EQ(stack[2].a, 'a');
EXPECT_EQ(stack[2].b, 'b');
EXPECT_EQ(stack[2].c, 'c');

EXPECT_EQ(stack.pop().a, 'g');

EXPECT_EQ(stack.top().a, 'd');
EXPECT_EQ(stack.top().b, 'e');
EXPECT_EQ(stack.top().c, 'f');
EXPECT_EQ(stack[1].a, 'a');
EXPECT_EQ(stack[1].b, 'b');
EXPECT_EQ(stack[1].c, 'c');

stack.drop();

EXPECT_EQ(stack.top().a, 'a');
EXPECT_EQ(stack.top().b, 'b');
EXPECT_EQ(stack.top().c, 'c');
}

0 comments on commit c990a1a

Please sign in to comment.