libstdc++
debug/forward_list
Go to the documentation of this file.
1 // <forward_list> -*- C++ -*-
2 
3 // Copyright (C) 2010 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 debug/forward_list
26  * This file is a GNU debug extension to the Standard C++ Library.
27  */
28 
29 #ifndef _GLIBCXX_DEBUG_FORWARD_LIST
30 #define _GLIBCXX_DEBUG_FORWARD_LIST 1
31 
32 #pragma GCC system_header
33 
34 #include <forward_list>
35 #include <debug/safe_sequence.h>
36 #include <debug/safe_iterator.h>
37 
38 namespace std _GLIBCXX_VISIBILITY(default)
39 {
40 namespace __debug
41 {
42  /// Class std::forward_list with safety/checking/debug instrumentation.
43  template<typename _Tp, typename _Alloc = std::allocator<_Tp> >
45  : public _GLIBCXX_STD_C::forward_list<_Tp, _Alloc>,
46  public __gnu_debug::_Safe_sequence<forward_list<_Tp, _Alloc> >
47  {
48  typedef _GLIBCXX_STD_C::forward_list<_Tp, _Alloc> _Base;
49 
50  typedef typename _Base::iterator _Base_iterator;
52  public:
53  typedef typename _Base::reference reference;
54  typedef typename _Base::const_reference const_reference;
55 
60 
61  typedef typename _Base::size_type size_type;
62  typedef typename _Base::difference_type difference_type;
63 
64  typedef _Tp value_type;
65  typedef _Alloc allocator_type;
66  typedef typename _Base::pointer pointer;
67  typedef typename _Base::const_pointer const_pointer;
68 
69  // 23.2.3.1 construct/copy/destroy:
70  explicit
71  forward_list(const _Alloc& __al = _Alloc())
72  : _Base(__al) { }
73 
74  forward_list(const forward_list& __list, const _Alloc& __al)
75  : _Base(__list, __al)
76  { }
77 
78  forward_list(forward_list&& __list, const _Alloc& __al)
79  : _Base(std::move(__list._M_base()), __al)
80  {
81  this->_M_swap(__list);
82  }
83 
84  explicit
85  forward_list(size_type __n)
86  : _Base(__n)
87  { }
88 
89  forward_list(size_type __n, const _Tp& __value,
90  const _Alloc& __al = _Alloc())
91  : _Base(__n, __value, __al)
92  { }
93 
94  template<typename _InputIterator>
95  forward_list(_InputIterator __first, _InputIterator __last,
96  const _Alloc& __al = _Alloc())
97  : _Base(__gnu_debug::__base(__gnu_debug::__check_valid_range(__first,
98  __last)),
99  __gnu_debug::__base(__last), __al)
100  { }
101 
102  forward_list(const forward_list& __list)
103  : _Base(__list)
104  { }
105 
106  forward_list(forward_list&& __list) noexcept
107  : _Base(std::move(__list._M_base()))
108  {
109  this->_M_swap(__list);
110  }
111 
113  const _Alloc& __al = _Alloc())
114  : _Base(__il, __al)
115  { }
116 
117  ~forward_list() noexcept
118  { }
119 
120  forward_list&
121  operator=(const forward_list& __list)
122  {
123  static_cast<_Base&>(*this) = __list;
124  this->_M_invalidate_all();
125  return *this;
126  }
127 
128  forward_list&
129  operator=(forward_list&& __list)
130  {
131  // NB: DR 1204.
132  // NB: DR 675.
133  clear();
134  swap(__list);
135  return *this;
136  }
137 
138  forward_list&
139  operator=(std::initializer_list<_Tp> __il)
140  {
141  static_cast<_Base&>(*this) = __il;
142  this->_M_invalidate_all();
143  return *this;
144  }
145 
146  template<typename _InputIterator>
147  void
148  assign(_InputIterator __first, _InputIterator __last)
149  {
150  __glibcxx_check_valid_range(__first, __last);
151  _Base::assign(__gnu_debug::__base(__first),
152  __gnu_debug::__base(__last));
153  this->_M_invalidate_all();
154  }
155 
156  void
157  assign(size_type __n, const _Tp& __val)
158  {
159  _Base::assign(__n, __val);
160  this->_M_invalidate_all();
161  }
162 
163  void
164  assign(std::initializer_list<_Tp> __il)
165  {
166  _Base::assign(__il);
167  this->_M_invalidate_all();
168  }
169 
170  using _Base::get_allocator;
171 
172  // iterators:
173 
174  iterator
175  before_begin() noexcept
176  { return iterator(_Base::before_begin(), this); }
177 
179  before_begin() const noexcept
180  { return const_iterator(_Base::before_begin(), this); }
181 
182  iterator
183  begin() noexcept
184  { return iterator(_Base::begin(), this); }
185 
187  begin() const noexcept
188  { return const_iterator(_Base::begin(), this); }
189 
190  iterator
191  end() noexcept
192  { return iterator(_Base::end(), this); }
193 
195  end() const noexcept
196  { return const_iterator(_Base::end(), this); }
197 
199  cbegin() const noexcept
200  { return const_iterator(_Base::cbegin(), this); }
201 
203  cbefore_begin() const noexcept
204  { return const_iterator(_Base::cbefore_begin(), this); }
205 
207  cend() const noexcept
208  { return const_iterator(_Base::cend(), this); }
209 
210  using _Base::empty;
211  using _Base::max_size;
212 
213  // element access:
214 
215  reference
216  front()
217  {
218  __glibcxx_check_nonempty();
219  return _Base::front();
220  }
221 
222  const_reference
223  front() const
224  {
225  __glibcxx_check_nonempty();
226  return _Base::front();
227  }
228 
229  // modiļ¬ers:
230 
231  using _Base::emplace_front;
232  using _Base::push_front;
233 
234  void
235  pop_front()
236  {
237  __glibcxx_check_nonempty();
238  this->_M_invalidate_if([this](_Base_const_iterator __it)
239  { return __it == this->_M_base().cbegin(); });
240  _Base::pop_front();
241  }
242 
243  template<typename... _Args>
244  iterator
245  emplace_after(const_iterator __pos, _Args&&... __args)
246  {
248  return iterator(_Base::emplace_after(__pos.base(),
249  std::forward<_Args>(__args)...),
250  this);
251  }
252 
253  iterator
254  insert_after(const_iterator __pos, const _Tp& __val)
255  {
257  return iterator(_Base::insert_after(__pos.base(), __val), this);
258  }
259 
260  iterator
261  insert_after(const_iterator __pos, _Tp&& __val)
262  {
264  return iterator(_Base::insert_after(__pos.base(), std::move(__val)),
265  this);
266  }
267 
268  iterator
269  insert_after(const_iterator __pos, size_type __n, const _Tp& __val)
270  {
272  return iterator(_Base::insert_after(__pos.base(), __n, __val),
273  this);
274  }
275 
276  template<typename _InputIterator>
277  iterator
278  insert_after(const_iterator __pos,
279  _InputIterator __first, _InputIterator __last)
280  {
281  __glibcxx_check_insert_range_after(__pos, __first, __last);
282  return iterator(_Base::insert_after(__pos.base(),
283  __gnu_debug::__base(__first),
284  __gnu_debug::__base(__last)),
285  this);
286  }
287 
288  iterator
289  insert_after(const_iterator __pos, std::initializer_list<_Tp> __il)
290  {
292  return iterator(_Base::insert_after(__pos.base(), __il), this);
293  }
294 
295  private:
297  _M_erase_after(_Base_const_iterator __pos)
298  {
299  _Base_const_iterator __next = std::next(__pos);
300  this->_M_invalidate_if([__next](_Base_const_iterator __it)
301  { return __it == __next; });
302  return _Base::erase_after(__pos);
303  }
304  public:
305  iterator
306  erase_after(const_iterator __pos)
307  {
309  return iterator(_M_erase_after(__pos.base()), this);
310  }
311 
312  iterator
313  erase_after(const_iterator __pos, const_iterator __last)
314  {
315  __glibcxx_check_erase_range_after(__pos, __last);
316  for (_Base_const_iterator __victim = std::next(__pos.base());
317  __victim != __last.base(); ++__victim)
318  {
319  _GLIBCXX_DEBUG_VERIFY(__victim != _Base::end(),
320  _M_message(__gnu_debug::__msg_valid_range2)
321  ._M_sequence(*this, "this")
322  ._M_iterator(__pos, "pos")
323  ._M_iterator(__last, "last"));
324  this->_M_invalidate_if([__victim](_Base_const_iterator __it)
325  { return __it == __victim; });
326  }
327  return iterator(_Base::erase_after(__pos.base(), __last.base()), this);
328  }
329 
330  void
331  swap(forward_list& __list)
332  {
333  _Base::swap(__list);
334  this->_M_swap(__list);
335  }
336 
337  void
338  resize(size_type __sz)
339  {
340  this->_M_detach_singular();
341 
342  // if __sz < size(), invalidate all iterators in [begin+__sz, end()
343  _Base_iterator __victim = _Base::begin();
344  _Base_iterator __end = _Base::end();
345  for (size_type __i = __sz; __victim != __end && __i > 0; --__i)
346  ++__victim;
347 
348  for (; __victim != __end; ++__victim)
349  {
350  this->_M_invalidate_if([__victim](_Base_const_iterator __it)
351  { return __it == __victim; });
352  }
353 
354  __try
355  {
356  _Base::resize(__sz);
357  }
358  __catch(...)
359  {
360  this->_M_revalidate_singular();
361  __throw_exception_again;
362  }
363  }
364 
365  void
366  resize(size_type __sz, const value_type& __val)
367  {
368  this->_M_detach_singular();
369 
370  // if __sz < size(), invalidate all iterators in [begin+__sz, end())
371  _Base_iterator __victim = _Base::begin();
372  _Base_iterator __end = _Base::end();
373  for (size_type __i = __sz; __victim != __end && __i > 0; --__i)
374  ++__victim;
375 
376  for (; __victim != __end; ++__victim)
377  {
378  this->_M_invalidate_if([__victim](_Base_const_iterator __it)
379  { return __it == __victim; });
380  }
381 
382  __try
383  {
384  _Base::resize(__sz, __val);
385  }
386  __catch(...)
387  {
388  this->_M_revalidate_singular();
389  __throw_exception_again;
390  }
391  }
392 
393  void
394  clear() noexcept
395  {
396  _Base::clear();
397  this->_M_invalidate_all();
398  }
399 
400  // 23.2.3.5 forward_list operations:
401  void
402  splice_after(const_iterator __pos, forward_list&& __list)
403  {
405  _GLIBCXX_DEBUG_VERIFY(&__list != this,
406  _M_message(__gnu_debug::__msg_self_splice)
407  ._M_sequence(*this, "this"));
408  this->_M_transfer_from_if(__list, [&__list](_Base_const_iterator __it)
409  {
410  return __it != __list._M_base().cbefore_begin()
411  && __it != __list._M_base().end();
412  });
413  _Base::splice_after(__pos.base(), std::move(__list._M_base()));
414  }
415 
416  void
417  splice_after(const_iterator __pos, forward_list& __list)
418  { splice_after(__pos, std::move(__list)); }
419 
420  void
421  splice_after(const_iterator __pos, forward_list&& __list,
422  const_iterator __i)
423  {
425  _GLIBCXX_DEBUG_VERIFY(__i._M_before_dereferenceable(),
426  _M_message(__gnu_debug::__msg_splice_bad)
427  ._M_iterator(__i, "__i"));
428  _GLIBCXX_DEBUG_VERIFY(__i._M_attached_to(&__list),
429  _M_message(__gnu_debug::__msg_splice_other)
430  ._M_iterator(__i, "__i")
431  ._M_sequence(__list, "__list"));
432 
433  // _GLIBCXX_RESOLVE_LIB_DEFECTS
434  // 250. splicing invalidates iterators
435  _Base_const_iterator __next = std::next(__i.base());
436  this->_M_transfer_from_if(__list, [__next](_Base_const_iterator __it)
437  { return __it == __next; });
438  _Base::splice_after(__pos.base(), std::move(__list._M_base()),
439  __i.base());
440  }
441 
442  void
443  splice_after(const_iterator __pos, forward_list& __list,
444  const_iterator __i)
445  { splice_after(__pos, std::move(__list), __i); }
446 
447  void
448  splice_after(const_iterator __pos, forward_list&& __list,
449  const_iterator __before, const_iterator __last)
450  {
452  __glibcxx_check_valid_range(__before, __last);
453  _GLIBCXX_DEBUG_VERIFY(__before._M_attached_to(&__list),
454  _M_message(__gnu_debug::__msg_splice_other)
455  ._M_sequence(__list, "list")
456  ._M_iterator(__before, "before"));
457  _GLIBCXX_DEBUG_VERIFY(__before._M_dereferenceable()
458  || __before._M_is_before_begin(),
459  _M_message(__gnu_debug::__msg_valid_range2)
460  ._M_sequence(__list, "list")
461  ._M_iterator(__before, "before")
462  ._M_iterator(__last, "last"));
463  _GLIBCXX_DEBUG_VERIFY(__before != __last,
464  _M_message(__gnu_debug::__msg_valid_range2)
465  ._M_sequence(__list, "list")
466  ._M_iterator(__before, "before")
467  ._M_iterator(__last, "last"));
468 
469  for (_Base_const_iterator __tmp = std::next(__before.base());
470  __tmp != __last.base(); ++__tmp)
471  {
472  _GLIBCXX_DEBUG_VERIFY(__tmp != __list._M_base().end(),
473  _M_message(__gnu_debug::__msg_valid_range2)
474  ._M_sequence(__list, "list")
475  ._M_iterator(__before, "before")
476  ._M_iterator(__last, "last"));
477  _GLIBCXX_DEBUG_VERIFY(&__list != this || __tmp != __pos.base(),
478  _M_message(__gnu_debug::__msg_splice_overlap)
479  ._M_iterator(__tmp, "position")
480  ._M_iterator(__before, "before")
481  ._M_iterator(__last, "last"));
482  // _GLIBCXX_RESOLVE_LIB_DEFECTS
483  // 250. splicing invalidates iterators
484  this->_M_transfer_from_if(__list, [__tmp](_Base_const_iterator __it)
485  { return __it == __tmp; });
486  }
487 
488  _Base::splice_after(__pos.base(), std::move(__list._M_base()),
489  __before.base(), __last.base());
490  }
491 
492  void
493  splice_after(const_iterator __pos, forward_list& __list,
494  const_iterator __before, const_iterator __last)
495  { splice_after(__pos, std::move(__list), __before, __last); }
496 
497  void
498  remove(const _Tp& __val)
499  {
500  _Base_iterator __x = _Base::before_begin();
501  _Base_iterator __old = __x++;
502  while (__x != _Base::end())
503  {
504  if (*__x == __val)
505  __x = _M_erase_after(__old);
506  else
507  __old = __x++;
508  }
509  }
510 
511  template<typename _Pred>
512  void
513  remove_if(_Pred __pred)
514  {
515  _Base_iterator __x = _Base::before_begin();
516  _Base_iterator __old = __x++;
517  while (__x != _Base::end())
518  {
519  if (__pred(*__x))
520  __x = _M_erase_after(__old);
521  else
522  __old = __x++;
523  }
524  }
525 
526  void
527  unique()
528  {
529  _Base_iterator __first = _Base::begin();
530  _Base_iterator __last = _Base::end();
531  if (__first == __last)
532  return;
533  _Base_iterator __next = std::next(__first);
534  while (__next != __last)
535  {
536  if (*__first == *__next)
537  __next = _M_erase_after(__first);
538  else
539  __first = __next++;
540  }
541  }
542 
543  template<typename _BinPred>
544  void
545  unique(_BinPred __binary_pred)
546  {
547  _Base_iterator __first = _Base::begin();
548  _Base_iterator __last = _Base::end();
549  if (__first == __last)
550  return;
551  _Base_iterator __next = std::next(__first);
552  while (__next != __last)
553  {
554  if (__binary_pred(*__first, *__next))
555  __next = _M_erase_after(__first);
556  else
557  __first = __next++;
558  }
559  }
560 
561  void
562  merge(forward_list&& __list)
563  {
564  if (this != &__list)
565  {
566  __glibcxx_check_sorted(_Base::begin(), _Base::end());
567  __glibcxx_check_sorted(__list._M_base().begin(),
568  __list._M_base().end());
569  this->_M_transfer_from_if(__list, [&__list](_Base_const_iterator __it)
570  {
571  return __it != __list._M_base().cbefore_begin()
572  && __it != __list._M_base().cend();
573  });
574  _Base::merge(std::move(__list._M_base()));
575  }
576  }
577 
578  void
579  merge(forward_list& __list)
580  { merge(std::move(__list)); }
581 
582  template<typename _Comp>
583  void
584  merge(forward_list&& __list, _Comp __comp)
585  {
586  if (this != &__list)
587  {
588  __glibcxx_check_sorted_pred(_Base::begin(), _Base::end(), __comp);
589  __glibcxx_check_sorted_pred(__list._M_base().begin(),
590  __list._M_base().end(), __comp);
591  this->_M_transfer_from_if(__list,
592  [&__list](_Base_const_iterator __it)
593  {
594  return __it != __list._M_base().cbefore_begin()
595  && __it != __list._M_base().cend();
596  });
597  _Base::merge(std::move(__list._M_base()), __comp);
598  }
599  }
600 
601  template<typename _Comp>
602  void
603  merge(forward_list& __list, _Comp __comp)
604  { merge(std::move(__list), __comp); }
605 
606  using _Base::sort;
607  using _Base::reverse;
608 
609  _Base&
610  _M_base() noexcept { return *this; }
611 
612  const _Base&
613  _M_base() const noexcept { return *this; }
614 
615  private:
616  void
617  _M_invalidate_all()
618  {
619  this->_M_invalidate_if([this](_Base_const_iterator __it)
620  {
621  return __it != this->_M_base().cbefore_begin()
622  && __it != this->_M_base().cend();
623  });
624  }
626  static void
627  _M_swap_aux(forward_list& __lhs,
628  _Safe_iterator_base*& __lhs_iterators,
629  forward_list& __rhs,
630  _Safe_iterator_base*& __rhs_iterators);
631  void _M_swap(forward_list& __list);
632  };
633 
634  template<typename _Tp, typename _Alloc>
635  void
638  __gnu_debug::_Safe_iterator_base*& __lhs_iterators,
640  __gnu_debug::_Safe_iterator_base*& __rhs_iterators)
641  {
643  _Safe_iterator_base* __bbegin_its = 0;
644  _Safe_iterator_base* __last_bbegin = 0;
645  for (_Safe_iterator_base* __iter = __lhs_iterators; __iter;)
646  {
647  // Even iterator are casted to const_iterator, not a problem.
648  const_iterator* __victim = static_cast<const_iterator*>(__iter);
649  __iter = __iter->_M_next;
650  if (__victim->base() == __rhs._M_base().cbefore_begin())
651  {
652  __victim->_M_unlink();
653  if (__lhs_iterators == __victim)
654  __lhs_iterators = __victim->_M_next;
655  if (__bbegin_its)
656  {
657  __victim->_M_next = __bbegin_its;
658  __bbegin_its->_M_prior = __victim;
659  }
660  else
661  __last_bbegin = __victim;
662  __bbegin_its = __victim;
663  }
664  else
665  __victim->_M_sequence = &__lhs;
666  }
667 
668  if (__bbegin_its)
669  {
670  if (__rhs_iterators)
671  {
672  __rhs_iterators->_M_prior = __last_bbegin;
673  __last_bbegin->_M_next = __rhs_iterators;
674  }
675  __rhs_iterators = __bbegin_its;
676  }
677  }
678 
679  /* Special forward_list _M_swap version that do not swap the
680  * before-begin ownership.*/
681  template<typename _Tp, typename _Alloc>
682  void
683  forward_list<_Tp, _Alloc>::
684  _M_swap(forward_list<_Tp, _Alloc>& __list)
685  {
686  __gnu_cxx::__scoped_lock sentry(this->_M_get_mutex());
687  std::swap(this->_M_iterators, __list._M_iterators);
688  std::swap(this->_M_const_iterators, __list._M_const_iterators);
689  // Useless, always 1 on forward_list
690  //std::swap(this->_M_version, __list._M_version);
691  _Safe_iterator_base* __this_its = this->_M_iterators;
692  _M_swap_aux(__list, __list._M_iterators, *this, this->_M_iterators);
693  _Safe_iterator_base* __this_const_its = this->_M_const_iterators;
694  _M_swap_aux(__list, __list._M_const_iterators, *this,
695  this->_M_const_iterators);
696  _M_swap_aux(*this, __this_its, __list, __list._M_iterators);
697  _M_swap_aux(*this, __this_const_its, __list, __list._M_const_iterators);
698  }
699 
700  template<typename _Tp, typename _Alloc>
701  bool
702  operator==(const forward_list<_Tp, _Alloc>& __lx,
703  const forward_list<_Tp, _Alloc>& __ly)
704  { return __lx._M_base() == __ly._M_base(); }
705 
706  template<typename _Tp, typename _Alloc>
707  inline bool
708  operator<(const forward_list<_Tp, _Alloc>& __lx,
709  const forward_list<_Tp, _Alloc>& __ly)
710  { return __lx._M_base() < __ly._M_base(); }
711 
712  template<typename _Tp, typename _Alloc>
713  inline bool
714  operator!=(const forward_list<_Tp, _Alloc>& __lx,
715  const forward_list<_Tp, _Alloc>& __ly)
716  { return !(__lx == __ly); }
717 
718  /// Based on operator<
719  template<typename _Tp, typename _Alloc>
720  inline bool
721  operator>(const forward_list<_Tp, _Alloc>& __lx,
722  const forward_list<_Tp, _Alloc>& __ly)
723  { return (__ly < __lx); }
724 
725  /// Based on operator<
726  template<typename _Tp, typename _Alloc>
727  inline bool
728  operator>=(const forward_list<_Tp, _Alloc>& __lx,
729  const forward_list<_Tp, _Alloc>& __ly)
730  { return !(__lx < __ly); }
731 
732  /// Based on operator<
733  template<typename _Tp, typename _Alloc>
734  inline bool
735  operator<=(const forward_list<_Tp, _Alloc>& __lx,
736  const forward_list<_Tp, _Alloc>& __ly)
737  { return !(__ly < __lx); }
738 
739  /// See std::forward_list::swap().
740  template<typename _Tp, typename _Alloc>
741  inline void
744  { __lx.swap(__ly); }
745 
746 } // namespace __debug
747 } // namespace std
748 
749 namespace __gnu_debug
750 {
751  template<class _Tp, class _Alloc>
752  struct _BeforeBeginHelper<std::__debug::forward_list<_Tp, _Alloc> >
753  {
754  typedef std::__debug::forward_list<_Tp, _Alloc> _Sequence;
755  typedef typename _Sequence::const_iterator _It;
756  typedef typename _It::iterator_type _BaseIt;
757 
758  static bool
759  _S_Is(_BaseIt __it, const _Sequence* __seq)
760  { return __it == __seq->_M_base().cbefore_begin(); }
761 
762  static bool
763  _S_Is_Beginnest(_BaseIt __it, const _Sequence* __seq)
764  { return _S_Is(__it, __seq); }
765  };
766 }
767 
768 #endif