Where Online Learning is simpler!
The C and C++ Include Header Files
cat -n /usr/include/c++/15/bits/forward_list.tcc
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 33 namespace std _GLIBCXX_VISIBILITY(default) 34 { 35 _GLIBCXX_BEGIN_NAMESPACE_VERSION 36 _GLIBCXX_BEGIN_NAMESPACE_CONTAINER 37 38 template<typename _Tp, typename _Alloc> 39 _Fwd_list_base<_Tp, _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>& 134 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 158 forward_list<_Tp, _Alloc>:: 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 176 forward_list<_Tp, _Alloc>:: 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 195 forward_list<_Tp, _Alloc>:: 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 214 forward_list<_Tp, _Alloc>:: 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 233 forward_list<_Tp, _Alloc>:: 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 250 forward_list<_Tp, _Alloc>:: 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 265 forward_list<_Tp, _Alloc>:: 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 284 forward_list<_Tp, _Alloc>:: 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 307 forward_list<_Tp, _Alloc>:: 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 362 forward_list<_Tp, _Alloc>:: 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 412 forward_list<_Tp, _Alloc>:: 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 */