Line data Source code
1 : #pragma once
2 :
3 : #include <functional>
4 : #include <initializer_list>
5 : #include <limits>
6 : #include <optional>
7 : #include <ostream>
8 :
9 : namespace containers {
10 :
11 : template <typename T>
12 : class list {
13 : private:
14 : template <typename N>
15 : struct node {
16 : N data;
17 : node* next;
18 : };
19 :
20 : public:
21 : using size_type = size_t;
22 : using iterator = node<T>*;
23 : using const_iterator = const node<T>*;
24 : using value_type = T;
25 : using reference_type = std::reference_wrapper<T>;
26 :
27 45 : list() = default;
28 :
29 : list(const list<T>& other) {
30 : iterator temp = other.m_head;
31 : while (temp) {
32 : push_back(temp->data);
33 : temp = temp->next;
34 : }
35 : }
36 :
37 : list(const list<T>&& other) {
38 : m_head = std::move(other.m_head);
39 : m_tail = std::move(other.m_tail);
40 : m_size = std::move(other.m_size);
41 : }
42 :
43 : list(const std::initializer_list<T>& args) {
44 : auto temp = args.begin();
45 : while (temp != args.end()) {
46 : push_back(*temp);
47 : temp++;
48 : }
49 : }
50 :
51 25 : list<T>& operator=(const list<T>& other) {
52 25 : iterator temp = other.m_head;
53 275 : while (temp) {
54 250 : push_back(temp->data);
55 250 : temp = temp->next;
56 : }
57 :
58 25 : return *this;
59 : }
60 :
61 96 : ~list() { remove_all_elements(); }
62 :
63 30 : friend bool operator==(const list<T>& lhs, const list<T>& rhs) {
64 30 : if (lhs.m_size != rhs.m_size) {
65 0 : return false;
66 : }
67 :
68 30 : iterator lhsTemp = lhs.m_head;
69 30 : iterator rhsTemp = rhs.m_head;
70 :
71 185 : while (lhsTemp and rhsTemp) {
72 155 : if (lhsTemp->data != rhsTemp->data) {
73 0 : return false;
74 : }
75 :
76 155 : lhsTemp = lhsTemp->next;
77 155 : rhsTemp = rhsTemp->next;
78 : }
79 :
80 30 : return true;
81 : }
82 :
83 : friend bool operator!=(const list<T>& lhs, const list<T>& rhs) {
84 : return not(lhs==rhs);
85 : }
86 :
87 : friend std::ostream& operator<<(std::ostream& os, const list<T>& list) {
88 : iterator temp = list.m_head;
89 : while (temp) {
90 : os << temp->data << " ";
91 : temp = temp->next;
92 : }
93 : os << std::endl;
94 :
95 : return os;
96 : }
97 :
98 2 : void assign(size_type count, const T& value) {
99 2 : remove_all_elements();
100 12 : for (size_type i = 0; i < count; ++i) {
101 10 : push_back(value);
102 : }
103 2 : }
104 :
105 2 : void assign(const std::initializer_list<T>& args) {
106 2 : remove_all_elements();
107 :
108 12 : for (const auto& arg : args) {
109 10 : push_back(arg);
110 : }
111 2 : }
112 :
113 : // definition of elemnets access
114 5 : std::optional<reference_type> front() const {
115 5 : if (not m_head) {
116 1 : return std::nullopt;
117 : }
118 :
119 4 : return m_head->data;
120 : }
121 :
122 4 : std::optional<reference_type> back() const {
123 4 : if (not m_head) {
124 1 : return std::nullopt;
125 : }
126 :
127 3 : return m_tail->data;
128 : }
129 :
130 : // definition of iterators
131 2 : iterator begin() const {
132 2 : if (not m_head) {
133 1 : return nullptr;
134 : }
135 :
136 1 : return m_head;
137 : }
138 :
139 2 : const_iterator cbegin() const {
140 2 : if (not m_head) {
141 1 : return nullptr;
142 : }
143 :
144 1 : return m_head;
145 : }
146 :
147 2 : iterator end() const {
148 2 : if (not m_tail) {
149 1 : return nullptr;
150 : }
151 :
152 1 : return m_tail;
153 : }
154 :
155 2 : const_iterator cend() const {
156 2 : if (not m_tail) {
157 1 : return nullptr;
158 : }
159 :
160 1 : return m_tail;
161 : }
162 :
163 : // definition of modifiers
164 709 : void push_back(const T& value) {
165 709 : m_size++;
166 :
167 709 : if (not m_head) {
168 79 : m_head = m_tail = new node<T>();
169 79 : m_head->data = value;
170 79 : return;
171 : }
172 :
173 630 : iterator temp = new node<T>();
174 630 : temp->data = value;
175 :
176 630 : m_tail->next = temp;
177 630 : m_tail = temp;
178 : }
179 :
180 2 : void pop_back() {
181 2 : if (not m_head) {
182 1 : return;
183 : }
184 :
185 1 : iterator temp = m_head;
186 9 : while (temp and temp->next != m_tail) {
187 8 : temp = temp->next;
188 : }
189 :
190 1 : temp->next = nullptr;
191 1 : delete m_tail;
192 1 : m_size--;
193 1 : m_tail = temp;
194 : }
195 :
196 2 : void push_front(const T& value) {
197 2 : iterator temp = new node<T>();
198 2 : temp->data = value;
199 2 : temp->next = m_head;
200 2 : m_size++;
201 :
202 2 : m_head = temp;
203 2 : }
204 :
205 2 : void pop_front() {
206 2 : if (not m_head) {
207 1 : return;
208 : }
209 :
210 1 : m_size--;
211 1 : iterator temp = m_head->next;
212 1 : delete m_head;
213 1 : m_head = temp;
214 : }
215 :
216 2 : void clear() { remove_all_elements(); }
217 :
218 14 : size_type size() const { return m_size; }
219 :
220 2 : bool empty() const { return m_size == 0; }
221 :
222 2 : size_type max_size() const { return std::numeric_limits<size_t>::max(); }
223 :
224 4 : void resize(size_type count) {
225 4 : if (count > m_size) {
226 2 : size_type size = count - m_size;
227 8 : for (size_type i = 0; i < size; ++i) {
228 6 : push_back(0);
229 : }
230 :
231 2 : return;
232 : }
233 :
234 2 : iterator temp = m_head;
235 21 : for (size_type i = 0; i < count; ++i) {
236 19 : temp = temp->next;
237 : }
238 :
239 2 : iterator toDelete = temp;
240 2 : while (toDelete and toDelete != m_tail) {
241 0 : iterator next = toDelete->next;
242 0 : delete toDelete;
243 0 : toDelete = next;
244 : }
245 :
246 2 : m_tail = temp;
247 2 : m_size = count;
248 : }
249 :
250 4 : void resize(size_type count, const T& value) {
251 4 : if (count > m_size) {
252 2 : size_type size = count - m_size;
253 8 : for (size_type i = 0; i < size; ++i) {
254 6 : push_back(value);
255 : }
256 :
257 2 : return;
258 : }
259 :
260 2 : iterator temp = m_head;
261 21 : for (size_type i = 0; i < count; ++i) {
262 19 : temp = temp->next;
263 : }
264 :
265 2 : iterator toDelete = temp;
266 2 : while (toDelete and toDelete != m_tail) {
267 0 : iterator next = toDelete->next;
268 0 : delete toDelete;
269 0 : toDelete = next;
270 : }
271 :
272 2 : m_tail = temp;
273 2 : m_size = count;
274 : }
275 :
276 5 : void swap(list<T>& other) {
277 5 : iterator tempHead = other.m_head;
278 5 : iterator tempTail = other.m_tail;
279 5 : size_type size = other.m_size;
280 :
281 5 : other.m_head = m_head;
282 5 : other.m_tail = m_tail;
283 5 : other.m_size = m_size;
284 :
285 5 : m_head = tempHead;
286 5 : m_tail = tempTail;
287 5 : m_size = size;
288 5 : }
289 :
290 : private:
291 102 : void remove_all_elements() {
292 811 : while (m_head) {
293 709 : iterator temp = m_head->next;
294 709 : delete m_head;
295 709 : m_head = temp;
296 : }
297 102 : m_size = 0;
298 102 : }
299 :
300 : iterator m_head = nullptr;
301 : iterator m_tail = nullptr;
302 : size_type m_size{0};
303 : };
304 :
305 : } // namespace containers
|