diff --git a/modules/borisov_s_stack/CMakeLists.txt b/modules/borisov_s_stack/CMakeLists.txt new file mode 100644 index 000000000..c54b3d08b --- /dev/null +++ b/modules/borisov_s_stack/CMakeLists.txt @@ -0,0 +1,12 @@ +# Declare variables for binaries' names +get_filename_component(DIR_NAME ${CMAKE_CURRENT_LIST_DIR} NAME) +set(MODULE "${DIR_NAME}") +set(LIBRARY "lib_${MODULE}") +set(TESTS "test_${MODULE}") + +# Include directory with public headers +include_directories(${CMAKE_CURRENT_SOURCE_DIR}) + +# Add all submodules +add_subdirectory(src) +add_subdirectory(test) diff --git a/modules/borisov_s_stack/include/stack.h b/modules/borisov_s_stack/include/stack.h new file mode 100644 index 000000000..a9e85de31 --- /dev/null +++ b/modules/borisov_s_stack/include/stack.h @@ -0,0 +1,128 @@ +// Copyright 2024 Borisov Saveliy + +#pragma once + +#include +#include +#include + +template +class Stack { + private: + int top = -1; + T* pMem; + int size; + + void oversize() { + T* tmpMem = new T[size * 2]; + std::copy(pMem, pMem + size, tmpMem); + delete[] pMem; + this->pMem = tmpMem; + size *= 2; + } + + public: + explicit Stack(int sz = 1) { + size = sz; + + if (sz <= 0) { + throw std::invalid_argument("Invalid stack size"); + } else { + pMem = new T[size]; + } + } + + Stack(const Stack& other) { + top = other.top; + size = other.size; + pMem = new T[size]; + std::copy(other.pMem, other.pMem + size, pMem); + } + + Stack& operator=(const Stack& other) { + if (this != &other) { + delete[] pMem; + top = other.top; + size = other.size; + pMem = new T[size]; + std::copy(other.pMem, other.pMem + size, pMem); + } + return *this; + } + + Stack(Stack&& other) noexcept { + pMem = nullptr; + size = 0; + swap(*this, other); + } + + Stack& operator=(Stack&& other) noexcept { + if (this != &other) { + delete[] pMem; + pMem = nullptr; + size = 0; + swap(*this, other); + } + return *this; + } + + int current_size() const { + return top + 1; + } + + void clear() { + top = -1; + } + + bool isEmpty() const { + return top == -1; + } + + bool isFull() const { + return top == size - 1; + } + + void push(const T& value) { + if (isFull()) + oversize(); + pMem[++top] = value; + } + + T pop() { + if (isEmpty()) + throw std::logic_error("Stack is empty"); + return pMem[top--]; + } + + T show_top() const { + if (isEmpty()) + throw std::logic_error("Stack is empty"); + return pMem[top]; + } + + bool operator==(const Stack& other) const { + if (top != other.top) + return false; + if (show_top() != other.show_top()) + return false; + for (int i = 0; i <= top; ++i) { + if (pMem[i] != other.pMem[i]) + return false; + } + return true; + } + + bool operator!=(const Stack& other) const { + return !(*this == other); + } + + friend void swap(Stack& lhs, Stack& rhs) noexcept { + std::swap(lhs.top, rhs.top); + std::swap(lhs.size, rhs.size); + std::swap(lhs.pMem, rhs.pMem); + } + + ~Stack() { + delete[] pMem; + } +}; diff --git a/modules/borisov_s_stack/src/CMakeLists.txt b/modules/borisov_s_stack/src/CMakeLists.txt new file mode 100644 index 000000000..b1dc57b01 --- /dev/null +++ b/modules/borisov_s_stack/src/CMakeLists.txt @@ -0,0 +1,18 @@ +set(target ${LIBRARY}) + +file(GLOB srcs "*.cpp") +file(GLOB hdrs "../include/*.h") +set_source_files_properties(${srcs} ${hdrs} PROPERTIES + LABELS "${MODULE};Library") + +add_library(${target} STATIC ${srcs} ${hdrs}) +set_target_properties(${target} PROPERTIES + OUTPUT_NAME ${MODULE} + LABELS "${MODULE};Library") + +if (UNIX) + target_link_libraries(${target} ${CMAKE_THREAD_LIBS_INIT}) +endif (UNIX) +target_link_libraries(${target} ${LIBRARY_DEPS}) + +set(LIBRARY_DEPS "${LIBRARY_DEPS};${target}" PARENT_SCOPE) diff --git a/modules/borisov_s_stack/src/stack.cpp b/modules/borisov_s_stack/src/stack.cpp new file mode 100644 index 000000000..da4c78b31 --- /dev/null +++ b/modules/borisov_s_stack/src/stack.cpp @@ -0,0 +1,3 @@ +// Copyright 2024 Borisov Saveliy + +#include "include/stack.h" diff --git a/modules/borisov_s_stack/test/CMakeLists.txt b/modules/borisov_s_stack/test/CMakeLists.txt new file mode 100644 index 000000000..cd06c57bb --- /dev/null +++ b/modules/borisov_s_stack/test/CMakeLists.txt @@ -0,0 +1,27 @@ +set(target ${TESTS}) + +file(GLOB srcs "*.cpp") +set_source_files_properties(${srcs} PROPERTIES + LABELS "${MODULE};Test") + +add_executable(${target} ${srcs} ${hdrs}) +set_target_properties(${target} PROPERTIES + LABELS "${MODULE};Test") + +if (UNIX) + target_link_libraries(${target} gtest ${CMAKE_THREAD_LIBS_INIT} pthread) +endif (UNIX) +target_link_libraries(${target} gtest ${LIBRARY}) + +# VS2012 doesn't support correctly the tuples yet, +# see http://code.google.com/p/googletest/issues/detail?id=412 +if(MSVC) + target_compile_definitions(${target} PUBLIC _VARIADIC_MAX=10) +endif() + +add_test( + NAME ${MODULE}_gtest + COMMAND ${target} +) +set_tests_properties (${MODULE}_gtest PROPERTIES + LABELS "${MODULE}") diff --git a/modules/borisov_s_stack/test/test_main.cpp b/modules/borisov_s_stack/test/test_main.cpp new file mode 100644 index 000000000..8e954596e --- /dev/null +++ b/modules/borisov_s_stack/test/test_main.cpp @@ -0,0 +1,8 @@ +// Copyright 2024 Borisov Saveliy + +#include + +int main(int argc, char **argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/modules/borisov_s_stack/test/test_stack.cpp b/modules/borisov_s_stack/test/test_stack.cpp new file mode 100644 index 000000000..4352473ff --- /dev/null +++ b/modules/borisov_s_stack/test/test_stack.cpp @@ -0,0 +1,197 @@ +// Copyright 2024 Borisov Saveliy + +#include + +#include + +#include "include/stack.h" + +TEST(Borisov_StackTest, can_create_stack_with_positive_length) { + ASSERT_NO_THROW(Stack stack(3)); +} + +TEST(Borisov_StackTest, throws_when_create_stack_with_negative_length) { + ASSERT_ANY_THROW(Stack stack(-3)); +} + +TEST(Borisov_StackTest, throws_when_create_stack_with_zero_length) { + ASSERT_ANY_THROW(Stack stack(0)); +} + +TEST(Borisov_StackTest, can_show_stack_top) { + Stack stack(3); + + stack.push(5); + + EXPECT_EQ(5, stack.show_top()); + EXPECT_EQ(false, stack.isEmpty()); +} + +TEST(Borisov_StackTest, throws_when_show_empty_stack_top) { + Stack stack(3); + EXPECT_EQ(true, stack.isEmpty()); + ASSERT_ANY_THROW(stack.show_top()); +} + +TEST(Borisov_StackTest, can_push_int_elem) { + Stack stack(3); + + stack.push(5); + + EXPECT_EQ(5, stack.show_top()); +} + +TEST(Borisov_StackTest, can_push_double_elem) { + Stack stack(3); + + stack.push(3.14); + + ASSERT_DOUBLE_EQ(stack.show_top(), 3.14); +} + +TEST(Borisov_StackTest, can_push_elem_into_full_stack) { + Stack stack(1); + stack.push(1); + EXPECT_EQ(true, stack.isFull()); + stack.push(2); + EXPECT_EQ(2, stack.show_top()); +} + +TEST(Borisov_StackTest, can_pop_elem) { + Stack stack(2); + + stack.push(1); + stack.push(2); + + EXPECT_EQ(2, stack.pop()); + EXPECT_EQ(1, stack.show_top()); + EXPECT_EQ(1, stack.pop()); + EXPECT_EQ(true, stack.isEmpty()); +} + +TEST(Borisov_StackTest, throws_when_pop_elem_from_empty_stack) { + Stack stack(3); + EXPECT_EQ(true, stack.isEmpty()); + ASSERT_ANY_THROW(stack.pop()); +} + +TEST(Borisov_StackTest, can_check_stack_is_empty) { + Stack stack(3); + EXPECT_EQ(true, stack.isEmpty()); + stack.push(1); + EXPECT_EQ(false, stack.isEmpty()); +} + +TEST(Borisov_StackTest, can_check_stack_is_full) { + Stack stack(1); + EXPECT_EQ(false, stack.isFull()); + stack.push(1); + EXPECT_EQ(true, stack.isFull()); +} + +TEST(Borisov_StackTest, can_get_current_stack_size) { + Stack stack(3); + EXPECT_EQ(0, stack.current_size()); + stack.push(1); + EXPECT_EQ(1, stack.current_size()); +} + +TEST(Borisov_StackTest, can_clear_stack) { + Stack stack(3); + stack.push(1); + EXPECT_EQ(false, stack.isEmpty()); + stack.clear(); + EXPECT_EQ(true, stack.isEmpty()); +} + +TEST(Borisov_StackTest, can_copy_stack) { + Stack stack1(3); + stack1.push(1); + stack1.push(2); + + Stack stack2 = stack1; + + EXPECT_EQ(stack1.pop(), stack2.pop()); + EXPECT_EQ(stack1.pop(), stack2.pop()); +} + +TEST(Borisov_StackTest, can_assign_stack) { + Stack stack1(3); + stack1.push(1); + stack1.push(2); + + Stack stack2(5); + stack2 = stack1; + + EXPECT_EQ(stack1.pop(), stack2.pop()); + EXPECT_EQ(stack1.pop(), stack2.pop()); +} + +TEST(Borisov_StackTest, can_move_stack) { + Stack stack1(3); + stack1.push(1); + stack1.push(2); + + Stack stack2(std::move(stack1)); + + EXPECT_EQ(true, stack1.isEmpty()); + EXPECT_EQ(2, stack2.pop()); + EXPECT_EQ(1, stack2.pop()); +} + +TEST(Borisov_StackTest, can_assign_move_stack) { + Stack stack1(3); + stack1.push(1); + stack1.push(2); + + Stack stack2(5); + stack2 = std::move(stack1); + + EXPECT_EQ(true, stack1.isEmpty()); + EXPECT_EQ(2, stack2.pop()); + EXPECT_EQ(1, stack2.pop()); +} + +TEST(Borisov_StackTest, eq_oper_returns_true_for_eq_stacks) { + Stack stack1(3); + stack1.push(1); + stack1.push(2); + + Stack stack2 = stack1; + + EXPECT_TRUE(stack1 == stack2); +} + +TEST(Borisov_StackTest, eq_oper_returns_false_for_uneq_stacks) { + Stack stack1(3); + stack1.push(1); + stack1.push(2); + + Stack stack2(3); + stack2.push(1); + stack2.push(3); + + EXPECT_FALSE(stack1 == stack2); +} + +TEST(Borisov_StackTest, ineq_oper_returns_true_for_uneq_stacks) { + Stack stack1(3); + stack1.push(1); + stack1.push(2); + + Stack stack2(3); + stack2.push(1); + stack2.push(3); + + EXPECT_TRUE(stack1 != stack2); +} + +TEST(Borisov_StackTest, ineq_oper_returns_false_for_eq_stacks) { + Stack stack1(3); + stack1.push(1); + stack1.push(2); + + Stack stack2 = stack1; + + EXPECT_FALSE(stack1 != stack2); +}