libstdc++
forward_list.tcc
Go to the documentation of this file.
1// <forward_list.tcc> -*- C++ -*-
2
3// Copyright (C) 2008-2025 Free Software Foundation, Inc.
4//
5// This file is part of the GNU ISO C++ Library. This library is free
6// software; you can redistribute it and/or modify it under the
7// terms of the GNU General Public License as published by the
8// Free Software Foundation; either version 3, or (at your option)
9// any later version.
10
11// This library is distributed in the hope that it will be useful,
12// but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14// GNU General Public License for more details.
15
16// Under Section 7 of GPL version 3, you are granted additional
17// permissions described in the GCC Runtime Library Exception, version
18// 3.1, as published by the Free Software Foundation.
19
20// You should have received a copy of the GNU General Public License and
21// a copy of the GCC Runtime Library Exception along with this program;
22// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
23// <http://www.gnu.org/licenses/>.
24
25/** @file bits/forward_list.tcc
26 * This is an internal header file, included by other library headers.
27 * Do not attempt to use it directly. @headername{forward_list}
28 */
29
30#ifndef _FORWARD_LIST_TCC
31#define _FORWARD_LIST_TCC 1
32
33namespace std _GLIBCXX_VISIBILITY(default)
34{
35_GLIBCXX_BEGIN_NAMESPACE_VERSION
36_GLIBCXX_BEGIN_NAMESPACE_CONTAINER
37
38 template<typename _Tp, typename _Alloc>
40 _Fwd_list_base(_Fwd_list_base&& __lst, _Node_alloc_type&& __a)
41 : _M_impl(std::move(__a))
42 {
43 if (__lst._M_get_Node_allocator() == _M_get_Node_allocator())
44 this->_M_impl._M_head = std::move(__lst._M_impl._M_head);
45 }
46
47 template<typename _Tp, typename _Alloc>
48 template<typename... _Args>
49 auto
50 _Fwd_list_base<_Tp, _Alloc>::
51 _M_insert_after(const_iterator __pos, _Args&&... __args)
52 -> _Base_ptr
53 {
54 auto __to = __pos._M_const_cast()._M_node;
55 _Node_ptr __thing = _M_create_node(std::forward<_Args>(__args)...);
56 __thing->_M_next = __to->_M_next;
57 __to->_M_next = __thing->_M_base_ptr();
58 return __to->_M_next;
59 }
60
61 template<typename _Tp, typename _Alloc>
62 auto
63 _Fwd_list_base<_Tp, _Alloc>::
64 _M_erase_after(_Base_ptr __pos)
65 -> _Base_ptr
66 {
67 auto& __curr = static_cast<_Node&>(*__pos->_M_next);
68 __pos->_M_next = __curr._M_next;
69 _M_destroy_node(__curr._M_node_ptr());
70 return __pos->_M_next;
71 }
72
73 template<typename _Tp, typename _Alloc>
74 auto
75 _Fwd_list_base<_Tp, _Alloc>::
76 _M_erase_after(_Base_ptr __pos, _Base_ptr __last)
77 -> _Base_ptr
78 {
79 _Base_ptr __curr = __pos->_M_next;
80 while (__curr != __last)
81 {
82 auto& __node = static_cast<_Node&>(*__curr);
83 __curr = __curr->_M_next;
84 _M_destroy_node(__node._M_node_ptr());
85 }
86 __pos->_M_next = __last;
87 return __last;
88 }
89
90 // Called by the range constructor to implement [23.3.4.2]/9
91 template<typename _Tp, typename _Alloc>
92 template<typename _InputIterator>
93 void
94 forward_list<_Tp, _Alloc>::
95 _M_range_initialize(_InputIterator __first, _InputIterator __last)
96 {
97 auto __to = this->_M_impl._M_head._M_base_ptr();
98 for (; __first != __last; ++__first)
99 {
100 __to->_M_next = this->_M_create_node(*__first)->_M_base_ptr();
101 __to = __to->_M_next;
102 }
103 }
104
105 // Called by forward_list(n,v,a).
106 template<typename _Tp, typename _Alloc>
107 void
108 forward_list<_Tp, _Alloc>::
109 _M_fill_initialize(size_type __n, const value_type& __value)
110 {
111 auto __to = this->_M_impl._M_head._M_base_ptr();
112 for (; __n; --__n)
113 {
114 __to->_M_next = this->_M_create_node(__value)->_M_base_ptr();
115 __to = __to->_M_next;
116 }
117 }
118
119 template<typename _Tp, typename _Alloc>
120 void
121 forward_list<_Tp, _Alloc>::
122 _M_default_initialize(size_type __n)
123 {
124 auto __to = this->_M_impl._M_head._M_base_ptr();
125 for (; __n; --__n)
126 {
127 __to->_M_next = this->_M_create_node()->_M_base_ptr();
128 __to = __to->_M_next;
129 }
130 }
131
132 template<typename _Tp, typename _Alloc>
133 forward_list<_Tp, _Alloc>&
135 operator=(const forward_list& __list)
136 {
137 if (std::__addressof(__list) != this)
138 {
139 if (_Node_alloc_traits::_S_propagate_on_copy_assign())
140 {
141 auto& __this_alloc = this->_M_get_Node_allocator();
142 auto& __that_alloc = __list._M_get_Node_allocator();
143 if (!_Node_alloc_traits::_S_always_equal()
144 && __this_alloc != __that_alloc)
145 {
146 // replacement allocator cannot free existing storage
147 clear();
148 }
149 std::__alloc_on_copy(__this_alloc, __that_alloc);
150 }
151 assign(__list.cbegin(), __list.cend());
152 }
153 return *this;
154 }
155
156 template<typename _Tp, typename _Alloc>
157 void
159 _M_default_insert_after(const_iterator __pos, size_type __n)
160 {
161 const_iterator __saved_pos = __pos;
162 __try
163 {
164 for (; __n; --__n)
165 __pos = emplace_after(__pos);
166 }
167 __catch(...)
168 {
169 erase_after(__saved_pos, ++__pos);
170 __throw_exception_again;
171 }
172 }
173
174 template<typename _Tp, typename _Alloc>
175 void
177 resize(size_type __sz)
178 {
179 iterator __k = before_begin();
180
181 size_type __len = 0;
182 while (__k._M_next() != end() && __len < __sz)
183 {
184 ++__k;
185 ++__len;
186 }
187 if (__len == __sz)
188 erase_after(__k, end());
189 else
190 _M_default_insert_after(__k, __sz - __len);
191 }
192
193 template<typename _Tp, typename _Alloc>
194 void
196 resize(size_type __sz, const value_type& __val)
197 {
198 iterator __k = before_begin();
199
200 size_type __len = 0;
201 while (__k._M_next() != end() && __len < __sz)
202 {
203 ++__k;
204 ++__len;
205 }
206 if (__len == __sz)
207 erase_after(__k, end());
208 else
209 insert_after(__k, __sz - __len, __val);
210 }
211
212 template<typename _Tp, typename _Alloc>
213 typename forward_list<_Tp, _Alloc>::iterator
215 _M_splice_after(const_iterator __pos,
216 const_iterator __before, const_iterator __last)
217 {
218 auto __tmp = __pos._M_const_cast()._M_node;
219 auto __b = __before._M_const_cast()._M_node;
220 auto __end = __b;
221
222 while (__end && __end->_M_next != __last._M_node)
223 __end = __end->_M_next;
224
225 if (__b != __end)
226 return iterator(__tmp->_M_transfer_after(__b, __end));
227 else
228 return iterator(__tmp);
229 }
230
231 template<typename _Tp, typename _Alloc>
232 void
234 splice_after(const_iterator __pos, forward_list&&,
235 const_iterator __i) noexcept
236 {
237 const_iterator __j = __i;
238 ++__j;
239
240 if (__pos == __i || __pos == __j)
241 return;
242
243 auto __tmp = __pos._M_const_cast()._M_node;
244 __tmp->_M_transfer_after(__i._M_const_cast()._M_node,
245 __j._M_const_cast()._M_node);
246 }
247
248 template<typename _Tp, typename _Alloc>
249 typename forward_list<_Tp, _Alloc>::iterator
251 insert_after(const_iterator __pos, size_type __n, const _Tp& __val)
252 {
253 if (__n)
254 {
255 forward_list __tmp(__n, __val, get_allocator());
256 return _M_splice_after(__pos, __tmp.before_begin(), __tmp.end());
257 }
258 else
259 return __pos._M_const_cast();
260 }
261
262 template<typename _Tp, typename _Alloc>
263 template<typename _InputIterator, typename>
264 typename forward_list<_Tp, _Alloc>::iterator
266 insert_after(const_iterator __pos,
267 _InputIterator __first, _InputIterator __last)
268 {
269 forward_list __tmp(__first, __last, get_allocator());
270 if (!__tmp.empty())
271 return _M_splice_after(__pos, __tmp.before_begin(), __tmp.end());
272 else
273 return __pos._M_const_cast();
274 }
275
276#if __cplusplus > 201703L
277# define _GLIBCXX20_ONLY(__expr) __expr
278#else
279# define _GLIBCXX20_ONLY(__expr)
280#endif
281
282 template<typename _Tp, typename _Alloc>
283 auto
285 remove(const _Tp& __val) -> __remove_return_type
286 {
287 size_type __removed __attribute__((__unused__)) = 0;
288 forward_list __to_destroy(get_allocator());
289
290 auto __prev_it = cbefore_begin();
291 while (auto __tmp = __prev_it._M_node->_M_next)
292 if (*static_cast<_Node&>(*__tmp)._M_valptr() == __val)
293 {
294 __to_destroy.splice_after(__to_destroy.cbefore_begin(),
295 *this, __prev_it);
296 _GLIBCXX20_ONLY( __removed++ );
297 }
298 else
299 ++__prev_it;
300
301 return _GLIBCXX20_ONLY( __removed );
302 }
303
304 template<typename _Tp, typename _Alloc>
305 template<typename _Pred>
306 auto
308 remove_if(_Pred __pred) -> __remove_return_type
309 {
310 size_type __removed __attribute__((__unused__)) = 0;
311 forward_list __to_destroy(get_allocator());
312
313 auto __prev_it = cbefore_begin();
314 while (auto __tmp = __prev_it._M_node->_M_next)
315 if (__pred(*static_cast<_Node&>(*__tmp)._M_valptr()))
316 {
317 __to_destroy.splice_after(__to_destroy.cbefore_begin(),
318 *this, __prev_it);
319 _GLIBCXX20_ONLY( __removed++ );
320 }
321 else
322 ++__prev_it;
323
324 return _GLIBCXX20_ONLY( __removed );
325 }
326
327 template<typename _Tp, typename _Alloc>
328 template<typename _BinPred>
329 auto
330 forward_list<_Tp, _Alloc>::
331 unique(_BinPred __binary_pred) -> __remove_return_type
332 {
333 iterator __first = begin();
334 iterator __last = end();
335 if (__first == __last)
336 return _GLIBCXX20_ONLY(0);
337
338 forward_list __to_destroy(get_allocator());
339 size_type __removed __attribute__((__unused__)) = 0;
340 iterator __next = __first;
341 while (++__next != __last)
342 {
343 if (__binary_pred(*__first, *__next))
344 {
345 __to_destroy.splice_after(__to_destroy.cbefore_begin(),
346 *this, __first);
347 _GLIBCXX20_ONLY( __removed++ );
348 }
349 else
350 __first = __next;
351 __next = __first;
352 }
353
354 return _GLIBCXX20_ONLY( __removed );
355 }
356
357#undef _GLIBCXX20_ONLY
358
359 template<typename _Tp, typename _Alloc>
360 template<typename _Comp>
361 void
363 merge(forward_list&& __list, _Comp __comp)
364 {
365 // _GLIBCXX_RESOLVE_LIB_DEFECTS
366 // 3088. forward_list::merge behavior unclear when passed *this
367 if (std::__addressof(__list) == this)
368 return;
369
370 using _Base_ptr = typename _Node::_Base_ptr;
371
372 _Base_ptr __node = this->_M_impl._M_head._M_base_ptr();
373 _Base_ptr __other = __list._M_impl._M_head._M_base_ptr();
374 while (__node->_M_next && __other->_M_next)
375 {
376 auto& __l = static_cast<_Node&>(*__other->_M_next);
377 auto& __r = static_cast<_Node&>(*__node->_M_next);
378 if (__comp(*__l._M_valptr(), *__r._M_valptr()))
379 __node->_M_transfer_after(__other, __other->_M_next);
380 __node = __node->_M_next;
381 }
382
383 if (__list._M_impl._M_head._M_next)
384 *__node = std::move(__list._M_impl._M_head);
385 }
386
387 template<typename _Tp, typename _Alloc>
388 bool
389 operator==(const forward_list<_Tp, _Alloc>& __lx,
390 const forward_list<_Tp, _Alloc>& __ly)
391 {
392 // We don't have size() so we need to walk through both lists
393 // making sure both iterators are valid.
394 auto __ix = __lx.cbegin();
395 auto __iy = __ly.cbegin();
396 while (__ix != __lx.cend() && __iy != __ly.cend())
397 {
398 if (!(*__ix == *__iy))
399 return false;
400 ++__ix;
401 ++__iy;
402 }
403 if (__ix == __lx.cend() && __iy == __ly.cend())
404 return true;
405 else
406 return false;
407 }
408
409 template<typename _Tp, class _Alloc>
410 template<typename _Comp>
411 void
413 sort(_Comp __comp)
414 {
415 if (empty())
416 return;
417
418 using _Base_ptr = typename _Node::_Base_ptr;
419
420 // If `next' is nullptr, return immediately.
421 _Base_ptr __list = this->_M_impl._M_head._M_next;
422
423 unsigned long __insize = 1;
424
425 while (1)
426 {
427 _Base_ptr __p = __list;
428 __list = nullptr;
429 _Base_ptr __tail = nullptr;
430
431 // Count number of merges we do in this pass.
432 unsigned long __nmerges = 0;
433
434 while (__p)
435 {
436 ++__nmerges;
437 // There exists a merge to be done.
438 // Step `insize' places along from p.
439 _Base_ptr __q = __p;
440 unsigned long __psize = 0;
441 for (unsigned long __i = 0; __i < __insize; ++__i)
442 {
443 ++__psize;
444 __q = __q->_M_next;
445 if (!__q)
446 break;
447 }
448
449 // If q hasn't fallen off end, we have two lists to merge.
450 unsigned long __qsize = __insize;
451
452 // Now we have two lists; merge them.
453 while (__psize > 0 || (__qsize > 0 && __q))
454 {
455 // Decide whether next node of merge comes from p or q.
456 _Base_ptr __e;
457 if (__psize == 0)
458 {
459 // p is empty; e must come from q.
460 __e = __q;
461 __q = __q->_M_next;
462 --__qsize;
463 }
464 else if (__qsize == 0 || !__q)
465 {
466 // q is empty; e must come from p.
467 __e = __p;
468 __p = __p->_M_next;
469 --__psize;
470 }
471 else if (!__comp(*static_cast<_Node&>(*__q)._M_valptr(),
472 *static_cast<_Node&>(*__p)._M_valptr()))
473 {
474 // First node of q is not lower; e must come from p.
475 __e = __p;
476 __p = __p->_M_next;
477 --__psize;
478 }
479 else
480 {
481 // First node of q is lower; e must come from q.
482 __e = __q;
483 __q = __q->_M_next;
484 --__qsize;
485 }
486
487 // Add the next node to the merged list.
488 if (__tail)
489 __tail->_M_next = __e;
490 else
491 __list = __e;
492 __tail = __e;
493 }
494
495 // Now p has stepped `insize' places along, and q has too.
496 __p = __q;
497 }
498 __tail->_M_next = nullptr;
499
500 // If we have done only one merge, we're finished.
501 // Allow for nmerges == 0, the empty list case.
502 if (__nmerges <= 1)
503 {
504 this->_M_impl._M_head._M_next = __list;
505 return;
506 }
507
508 // Otherwise repeat, merging lists twice the size.
509 __insize *= 2;
510 }
511 }
512
513_GLIBCXX_END_NAMESPACE_CONTAINER
514_GLIBCXX_END_NAMESPACE_VERSION
515} // namespace std
516
517#endif /* _FORWARD_LIST_TCC */
constexpr std::remove_reference< _Tp >::type && move(_Tp &&__t) noexcept
Convert a value to an rvalue.
Definition move.h:138
constexpr _Tp * __addressof(_Tp &__r) noexcept
Same as C++11 std::addressof.
Definition move.h:52
constexpr _Tp && forward(typename std::remove_reference< _Tp >::type &__t) noexcept
Forward an lvalue.
Definition move.h:72
_Tp * end(valarray< _Tp > &__va) noexcept
Return an iterator pointing to one past the last element of the valarray.
Definition valarray:1251
_Tp * begin(valarray< _Tp > &__va) noexcept
Return an iterator pointing to the first element of the valarray.
Definition valarray:1229
ISO C++ entities toplevel namespace is std.
A standard container with linear time access to elements, and fixed time insertion/deletion at any po...
forward_list()=default
Creates a forward_list with no elements.
iterator erase_after(const_iterator __pos)
Removes the element pointed to by the iterator following pos.
iterator before_begin() noexcept
iterator insert_after(const_iterator __pos, const _Tp &__val)
Inserts given value into forward_list after specified iterator.
iterator end() noexcept
void splice_after(const_iterator __pos, forward_list &&__list) noexcept
Insert contents of another forward_list.
const_iterator cbefore_begin() const noexcept
void clear() noexcept
Erases all the elements.
const_iterator cend() const noexcept
void assign(_InputIterator __first, _InputIterator __last)
Assigns a range to a forward_list.
bool empty() const noexcept
allocator_type get_allocator() const noexcept
Get a copy of the memory allocation object.
const_iterator cbegin() const noexcept
Base class for forward_list.
Common iterator class.