@@ -9,8 +9,14 @@ struct Node {
99 std::unique_ptr<Node> next;
1010 Node* prev;
1111
12- Node (const T& a_value, Node* a_prev, std::unique_ptr<Node> a_next)
13- : value(a_value), prev(a_prev), next(std::move(a_next)) {}
12+ template <typename U>
13+ Node (U&& a_value, Node* a_prev, std::unique_ptr<Node> a_next)
14+ : value(std::forward<U>(a_value)), prev(a_prev), next(std::move(a_next)) {}
15+
16+ template <typename ... Args>
17+ Node (Node* p, std::unique_ptr<Node> n, Args&&... args)
18+ : value(std::forward<Args>(args)...), prev(p), next(std::move(n)) {}
19+
1420};
1521
1622template <typename T>
@@ -20,8 +26,98 @@ class DoublyLinkedList {
2026 Node<T>* tail;
2127 int _size;
2228
29+ void link_new_back_node (std::unique_ptr<Node<T>> new_node) {
30+ if (!head) {
31+ head = std::move (new_node);
32+ tail = head.get ();
33+ } else {
34+ tail->next = std::move (new_node);
35+ tail->next ->prev = tail;
36+ tail = tail->next .get ();
37+ }
38+ ++_size;
39+ }
40+
41+ template <typename U>
42+ void push_back_internal (U&& value) {
43+ auto new_node = std::make_unique<Node<T>>(std::forward<U>(value), tail, nullptr );
44+ link_new_back_node (std::move (new_node));
45+ }
46+
47+ template <typename U>
48+ void push_front_internal (U&& value) {
49+ auto new_node = std::make_unique<Node<T>>(std::forward<U>(value), nullptr , std::move (head));
50+ if (new_node->next ) {
51+ new_node->next ->prev = new_node.get ();
52+ }
53+ else {
54+ tail = new_node.get ();
55+ }
56+ head = std::move (new_node);
57+ _size++;
58+ }
59+
60+ T erase_middle_node (Node<T>* node) {
61+ T value = std::move (node->value );
62+ node->next ->prev = node->prev ;
63+ node->prev ->next = std::move (node->next );
64+ _size--;
65+ return value;
66+ }
67+
68+ std::unique_ptr<Node<T>> extract_node_and_link_prev_with_next (Node<T>* node) {
69+ std::unique_ptr<Node<T>> extracted;
70+
71+ if (node->next ) {
72+ node->next ->prev = node->prev ;
73+ } else {
74+ tail = node->prev ;
75+ }
76+
77+ if (node->prev ) {
78+ extracted = std::move (node->prev ->next );
79+ node->prev ->next = std::move (node->next );
80+ } else {
81+ extracted = std::move (head);
82+ head = std::move (node->next );
83+ }
84+
85+ return extracted;
86+ }
87+
88+ void emplace_node_before (std::unique_ptr<Node<T>> node, Node<T>* position) {
89+ if (position == head.get ()) {
90+ node->next = std::move (head);
91+ if (node->next ) node->next ->prev = node.get ();
92+ head = std::move (node);
93+ }
94+ else if (position == nullptr ) {
95+ node->prev = tail;
96+ tail = node.get ();
97+ node->prev ->next = std::move (node);
98+ }
99+ else {
100+ node->prev = position->prev ;
101+ node->next = std::move (position->prev ->next );
102+ position->prev = node.get ();
103+ node->prev ->next = std::move (node);
104+ }
105+ }
106+
23107public:
24108 DoublyLinkedList () : head(nullptr ), tail(nullptr ), _size(0 ) {}
109+
110+ DoublyLinkedList (std::initializer_list<T> init_list) : DoublyLinkedList() {
111+ for (const auto & value : init_list) push_back (value);
112+ }
113+
114+ template <typename ParamIterator>
115+ DoublyLinkedList (ParamIterator begin, ParamIterator end) : DoublyLinkedList() {
116+ for (auto it = begin; it != end; it++) {
117+ push_back (*it);
118+ }
119+ }
120+
25121 ~DoublyLinkedList () {
26122 clear ();
27123 }
@@ -45,23 +141,22 @@ class DoublyLinkedList {
45141 return tail->value ;
46142 }
47143
144+
145+
146+ void push_back (T&& value) {
147+ push_back_internal (std::move (value));
148+ }
149+
48150 void push_back (const T& value) {
49- if (!head) {
50- head = std::make_unique<Node<T>>(value, nullptr , nullptr );
51- tail = head.get ();
52- } else {
53- tail->next = std::make_unique<Node<T>>(value, tail, nullptr );
54- tail = tail->next .get ();
55- }
56- _size++;
151+ push_back_internal (value);
57152 }
58153
59154 T pop_back () {
60155 if (!head) {
61156 throw std::out_of_range (" List is empty" );
62157 }
63158
64- T popped_value = tail->value ;
159+ T popped_value = std::move ( tail->value ) ;
65160
66161 if (tail == head.get ()) {
67162 head.reset ();
@@ -76,24 +171,20 @@ class DoublyLinkedList {
76171 return popped_value;
77172 }
78173
174+ void push_front (T&& value) {
175+ push_front_internal (std::move (value));
176+ }
177+
79178 void push_front (const T& value) {
80- if (!head) {
81- head = std::make_unique<Node<T>>(value, nullptr , nullptr );
82- tail = head.get ();
83- } else {
84- auto new_node = std::make_unique<Node<T>>(value, nullptr , std::move (head));
85- new_node->next ->prev = new_node.get ();
86- head = std::move (new_node);
87- }
88- _size++;
179+ push_front_internal (value);
89180 }
90181
91182 T pop_front () {
92183 if (!head) {
93184 throw std::out_of_range (" List is empty" );
94185 }
95186
96- T popped_value = head->value ;
187+ T popped_value = std::move ( head->value ) ;
97188 head = std::move (head->next );
98189
99190 if (!head)
@@ -104,7 +195,7 @@ class DoublyLinkedList {
104195 }
105196
106197 void clear () {
107- while (size () > 0 ) {
198+ while (head ) {
108199 pop_back ();
109200 }
110201 }
@@ -115,13 +206,14 @@ class DoublyLinkedList {
115206
116207 class Iterator {
117208 Node<T>* current_node_ptr;
209+ DoublyLinkedList<T>* list_ptr;
118210
119- Iterator (Node<T>* a_current) : current_node_ptr(a_current) {}
211+ Iterator (Node<T>* a_current, DoublyLinkedList<T>* a_list_ptr ) : current_node_ptr(a_current), list_ptr(a_list_ptr ) {}
120212
121213 friend class DoublyLinkedList <T>;
122214
123215 public:
124- Iterator () : current_node_ptr(nullptr ) {}
216+ Iterator () : current_node_ptr(nullptr ), list_ptr( nullptr ) {}
125217
126218 bool operator ==(const Iterator& other) const {
127219 return current_node_ptr == other.current_node_ptr ;
@@ -149,22 +241,56 @@ class DoublyLinkedList {
149241 }
150242
151243 Iterator& operator --() {
152- if (current_node_ptr) {
244+ if (current_node_ptr == nullptr ) {
245+ current_node_ptr = list_ptr->tail ;
246+ }
247+ else if (current_node_ptr) {
153248 current_node_ptr = current_node_ptr->prev ;
154249 }
155250 return *this ;
156251 }
157252 };
158253
159254 Iterator begin () {
160- return Iterator (head.get ());
255+ return Iterator (head.get (), this );
161256 }
162257
163258 Iterator end () {
164- return Iterator (nullptr );
259+ return Iterator (nullptr , this );
165260 }
166261
167262 Iterator back_iterator () {
168- return Iterator (tail);
263+ return Iterator (tail, this );
264+ }
265+
266+
267+ Iterator erase (Iterator it) {
268+ if (empty ()) throw std::out_of_range (" List is empty" );
269+ if (it == end ()) throw std::out_of_range (" Invalid iterator" );
270+
271+ Iterator target_it = it++;
272+
273+ target_it == begin () ? pop_front () :
274+ target_it == back_iterator () ? pop_back () :
275+ erase_middle_node (target_it.current_node_ptr );
276+
277+ return it;
278+ }
279+
280+ void move_to_begin (Iterator it) {
281+ if (empty ()) throw std::out_of_range (" List is empty" );
282+ if (it == end ()) throw std::out_of_range (" Invalid iterator" );
283+ if (it == begin ()) return ;
284+
285+ auto extracted = extract_node_and_link_prev_with_next (it.current_node_ptr );
286+ emplace_node_before (std::move (extracted), head.get ());
169287 }
288+
289+ template <typename ... Args>
290+ void emplace_back (Args&&... args) {
291+ auto new_node = std::make_unique<Node<T>>(tail, nullptr , std::forward<Args>(args)...);
292+ link_new_back_node (std::move (new_node));
293+ }
294+
295+
170296};
0 commit comments