Line data Source code
1 : #pragma once
2 :
3 : #include <optional>
4 : #include <ostream>
5 :
6 : namespace containers {
7 :
8 : static constexpr size_t DEFAULT_STACK_SIZE = 0;
9 : static constexpr size_t EMPTY = 0;
10 :
11 : template <typename T>
12 : class stack {
13 : public:
14 13 : stack() noexcept = default;
15 :
16 1 : stack(const stack<T>& other) { CopyData(other); }
17 :
18 19 : virtual ~stack() { delete[] m_data; }
19 :
20 1 : void operator=(const stack<T>& other) {
21 1 : m_size = other.m_size;
22 1 : m_data = new T[m_size];
23 :
24 6 : for (size_t i = 0; i < m_size; ++i) {
25 5 : m_data[i] = other.m_data[i];
26 : }
27 1 : }
28 :
29 0 : friend std::ostream& operator<<(std::ostream& os, const stack<T>& data) {
30 0 : os << "size: " << data.size() << ", elements: ";
31 0 : for (size_t i = 0; i < data.size(); ++i) {
32 0 : os << data.m_data[i] << " ";
33 : }
34 0 : return os;
35 : }
36 :
37 4 : friend bool operator==(const stack<T>& lhs, const stack<T>& rhs) {
38 4 : if (rhs.m_size != lhs.m_size) {
39 1 : return false;
40 : }
41 :
42 18 : for (size_t i = 0; i < lhs.m_size; ++i) {
43 16 : if (lhs.m_data[i] != rhs.m_data[i]) {
44 1 : return false;
45 : }
46 : }
47 2 : return true;
48 : }
49 :
50 2 : friend bool operator!=(const stack<T>& lhs, const stack<T>& rhs) {
51 2 : return not(lhs == rhs);
52 : }
53 :
54 13 : void push(const T& value) {
55 13 : if (not m_data) {
56 3 : InsertWhenStackIsEmpty(value);
57 : } else {
58 10 : InsertWhenStackInNotEmpty(value);
59 : }
60 13 : }
61 :
62 87 : void emplace(const T&& value) {
63 87 : if (not m_data) {
64 11 : InsertWhenStackIsEmpty(value);
65 : } else {
66 76 : InsertWhenStackInNotEmpty(value);
67 : }
68 87 : }
69 :
70 6 : std::optional<std::reference_wrapper<T>> top() const {
71 6 : if (not m_data) {
72 1 : return std::nullopt;
73 : }
74 :
75 5 : return m_data[m_size - 1];
76 : }
77 :
78 2 : void swap(stack<T>& other) {
79 2 : if (not m_data) {
80 1 : m_size = other.m_size;
81 1 : m_data = other.m_data;
82 :
83 1 : other.m_size = EMPTY;
84 1 : other.m_data = nullptr;
85 : } else {
86 1 : T* temp = other.m_data;
87 1 : size_t temp_size = other.m_size;
88 :
89 1 : other.m_data = m_data;
90 1 : other.m_size = m_size;
91 :
92 1 : m_data = temp;
93 1 : m_size = temp_size;
94 : }
95 2 : }
96 :
97 14 : bool empty() const { return m_size == EMPTY; }
98 :
99 10 : size_t size() const { return m_size; }
100 :
101 : private:
102 1 : void CopyData(const stack<T>& other) {
103 1 : m_size = other.m_size;
104 1 : m_data = new T[m_size];
105 :
106 11 : for (size_t i = 0; i < m_size; ++i) {
107 10 : m_data[i] = other.m_data[i];
108 : }
109 1 : }
110 :
111 14 : void InsertWhenStackIsEmpty(const T& value) {
112 14 : m_size++;
113 14 : m_data = new T[m_size];
114 14 : m_data[0] = value;
115 14 : }
116 :
117 86 : void InsertWhenStackInNotEmpty(const T& value) {
118 86 : T* temp = new T[m_size + 1];
119 496 : for (size_t i = 0; i < m_size; ++i) {
120 410 : temp[i] = m_data[i];
121 : }
122 86 : temp[m_size] = value;
123 86 : m_size++;
124 :
125 86 : delete[] m_data;
126 86 : m_data = temp;
127 86 : }
128 :
129 : T* m_data{nullptr};
130 : size_t m_size{DEFAULT_STACK_SIZE};
131 : };
132 :
133 : } // namespace containers
|