Home | History | Annotate | Download | only in debug
      1 // Debugging list implementation -*- C++ -*-
      2 
      3 // Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009
      4 // Free Software Foundation, Inc.
      5 //
      6 // This file is part of the GNU ISO C++ Library.  This library is free
      7 // software; you can redistribute it and/or modify it under the
      8 // terms of the GNU General Public License as published by the
      9 // Free Software Foundation; either version 3, or (at your option)
     10 // any later version.
     11 
     12 // This library is distributed in the hope that it will be useful,
     13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
     14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15 // GNU General Public License for more details.
     16 
     17 // Under Section 7 of GPL version 3, you are granted additional
     18 // permissions described in the GCC Runtime Library Exception, version
     19 // 3.1, as published by the Free Software Foundation.
     20 
     21 // You should have received a copy of the GNU General Public License and
     22 // a copy of the GCC Runtime Library Exception along with this program;
     23 // see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
     24 // <http://www.gnu.org/licenses/>.
     25 
     26 /** @file debug/list
     27  *  This file is a GNU debug extension to the Standard C++ Library.
     28  */
     29 
     30 #ifndef _GLIBCXX_DEBUG_LIST
     31 #define _GLIBCXX_DEBUG_LIST 1
     32 
     33 #include <list>
     34 #include <bits/stl_algo.h>
     35 #include <debug/safe_sequence.h>
     36 #include <debug/safe_iterator.h>
     37 
     38 namespace std
     39 {
     40 namespace __debug
     41 {
     42   template<typename _Tp, typename _Allocator = std::allocator<_Tp> >
     43     class list
     44     : public _GLIBCXX_STD_D::list<_Tp, _Allocator>,
     45       public __gnu_debug::_Safe_sequence<list<_Tp, _Allocator> >
     46     {
     47       typedef _GLIBCXX_STD_D::list<_Tp, _Allocator> _Base;
     48       typedef __gnu_debug::_Safe_sequence<list>  _Safe_base;
     49 
     50     public:
     51       typedef typename _Base::reference             reference;
     52       typedef typename _Base::const_reference       const_reference;
     53 
     54       typedef __gnu_debug::_Safe_iterator<typename _Base::iterator, list>
     55 						    iterator;
     56       typedef __gnu_debug::_Safe_iterator<typename _Base::const_iterator, list>
     57 						    const_iterator;
     58 
     59       typedef typename _Base::size_type             size_type;
     60       typedef typename _Base::difference_type       difference_type;
     61 
     62       typedef _Tp				    value_type;
     63       typedef _Allocator			    allocator_type;
     64       typedef typename _Base::pointer               pointer;
     65       typedef typename _Base::const_pointer         const_pointer;
     66       typedef std::reverse_iterator<iterator>       reverse_iterator;
     67       typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
     68 
     69       // 23.2.2.1 construct/copy/destroy:
     70       explicit list(const _Allocator& __a = _Allocator())
     71       : _Base(__a) { }
     72 
     73       explicit list(size_type __n, const _Tp& __value = _Tp(),
     74 		    const _Allocator& __a = _Allocator())
     75       : _Base(__n, __value, __a) { }
     76 
     77       template<class _InputIterator>
     78       list(_InputIterator __first, _InputIterator __last,
     79 	   const _Allocator& __a = _Allocator())
     80       : _Base(__gnu_debug::__check_valid_range(__first, __last), __last, __a)
     81       { }
     82 
     83 
     84       list(const list& __x)
     85       : _Base(__x), _Safe_base() { }
     86 
     87       list(const _Base& __x)
     88       : _Base(__x), _Safe_base() { }
     89 
     90 #ifdef __GXX_EXPERIMENTAL_CXX0X__
     91       list(list&& __x)
     92       : _Base(std::forward<list>(__x)), _Safe_base()
     93       { this->_M_swap(__x); }
     94 
     95       list(initializer_list<value_type> __l,
     96            const allocator_type& __a = allocator_type())
     97         : _Base(__l, __a), _Safe_base() { }
     98 #endif
     99 
    100       ~list() { }
    101 
    102       list&
    103       operator=(const list& __x)
    104       {
    105 	static_cast<_Base&>(*this) = __x;
    106 	this->_M_invalidate_all();
    107 	return *this;
    108       }
    109 
    110 #ifdef __GXX_EXPERIMENTAL_CXX0X__
    111       list&
    112       operator=(list&& __x)
    113       {
    114         // NB: DR 675.
    115 	clear();
    116 	swap(__x);
    117 	return *this;
    118       }
    119 
    120       list&
    121       operator=(initializer_list<value_type> __l)
    122       {
    123 	static_cast<_Base&>(*this) = __l;
    124 	this->_M_invalidate_all();
    125 	return *this;
    126       }
    127 
    128       void
    129       assign(initializer_list<value_type> __l)
    130       {
    131 	_Base::assign(__l);
    132 	this->_M_invalidate_all();
    133       }
    134 #endif
    135 
    136       template<class _InputIterator>
    137         void
    138         assign(_InputIterator __first, _InputIterator __last)
    139         {
    140 	  __glibcxx_check_valid_range(__first, __last);
    141 	  _Base::assign(__first, __last);
    142 	  this->_M_invalidate_all();
    143 	}
    144 
    145       void
    146       assign(size_type __n, const _Tp& __t)
    147       {
    148 	_Base::assign(__n, __t);
    149 	this->_M_invalidate_all();
    150       }
    151 
    152       using _Base::get_allocator;
    153 
    154       // iterators:
    155       iterator
    156       begin()
    157       { return iterator(_Base::begin(), this); }
    158 
    159       const_iterator
    160       begin() const
    161       { return const_iterator(_Base::begin(), this); }
    162 
    163       iterator
    164       end()
    165       { return iterator(_Base::end(), this); }
    166 
    167       const_iterator
    168       end() const
    169       { return const_iterator(_Base::end(), this); }
    170 
    171       reverse_iterator
    172       rbegin()
    173       { return reverse_iterator(end()); }
    174 
    175       const_reverse_iterator
    176       rbegin() const
    177       { return const_reverse_iterator(end()); }
    178 
    179       reverse_iterator
    180       rend()
    181       { return reverse_iterator(begin()); }
    182 
    183       const_reverse_iterator
    184       rend() const
    185       { return const_reverse_iterator(begin()); }
    186 
    187 #ifdef __GXX_EXPERIMENTAL_CXX0X__
    188       const_iterator
    189       cbegin() const
    190       { return const_iterator(_Base::begin(), this); }
    191 
    192       const_iterator
    193       cend() const
    194       { return const_iterator(_Base::end(), this); }
    195 
    196       const_reverse_iterator
    197       crbegin() const
    198       { return const_reverse_iterator(end()); }
    199 
    200       const_reverse_iterator
    201       crend() const
    202       { return const_reverse_iterator(begin()); }
    203 #endif
    204 
    205       // 23.2.2.2 capacity:
    206       using _Base::empty;
    207       using _Base::size;
    208       using _Base::max_size;
    209 
    210       void
    211       resize(size_type __sz, _Tp __c = _Tp())
    212       {
    213 	this->_M_detach_singular();
    214 
    215 	// if __sz < size(), invalidate all iterators in [begin+__sz, end())
    216 	iterator __victim = begin();
    217 	iterator __end = end();
    218 	for (size_type __i = __sz; __victim != __end && __i > 0; --__i)
    219 	  ++__victim;
    220 
    221 	while (__victim != __end)
    222 	  {
    223 	    iterator __real_victim = __victim++;
    224 	    __real_victim._M_invalidate();
    225 	  }
    226 
    227 	__try
    228 	  {
    229 	    _Base::resize(__sz, __c);
    230 	  }
    231 	__catch(...)
    232 	  {
    233 	    this->_M_revalidate_singular();
    234 	    __throw_exception_again;
    235 	  }
    236       }
    237 
    238       // element access:
    239       reference
    240       front()
    241       {
    242 	__glibcxx_check_nonempty();
    243 	return _Base::front();
    244       }
    245 
    246       const_reference
    247       front() const
    248       {
    249 	__glibcxx_check_nonempty();
    250 	return _Base::front();
    251       }
    252 
    253       reference
    254       back()
    255       {
    256 	__glibcxx_check_nonempty();
    257 	return _Base::back();
    258       }
    259 
    260       const_reference
    261       back() const
    262       {
    263 	__glibcxx_check_nonempty();
    264 	return _Base::back();
    265       }
    266 
    267       // 23.2.2.3 modifiers:
    268       using _Base::push_front;
    269 
    270 #ifdef __GXX_EXPERIMENTAL_CXX0X__
    271       using _Base::emplace_front;
    272 #endif
    273 
    274       void
    275       pop_front()
    276       {
    277 	__glibcxx_check_nonempty();
    278 	iterator __victim = begin();
    279 	__victim._M_invalidate();
    280 	_Base::pop_front();
    281       }
    282 
    283       using _Base::push_back;
    284 
    285 #ifdef __GXX_EXPERIMENTAL_CXX0X__
    286       using _Base::emplace_back;
    287 #endif
    288 
    289       void
    290       pop_back()
    291       {
    292 	__glibcxx_check_nonempty();
    293 	iterator __victim = end();
    294 	--__victim;
    295 	__victim._M_invalidate();
    296 	_Base::pop_back();
    297       }
    298 
    299 #ifdef __GXX_EXPERIMENTAL_CXX0X__
    300       template<typename... _Args>
    301         iterator
    302         emplace(iterator __position, _Args&&... __args)
    303 	{
    304 	  __glibcxx_check_insert(__position);
    305 	  return iterator(_Base::emplace(__position.base(),
    306 					std::forward<_Args>(__args)...), this);
    307 	}
    308 #endif
    309 
    310       iterator
    311       insert(iterator __position, const _Tp& __x)
    312       {
    313 	__glibcxx_check_insert(__position);
    314 	return iterator(_Base::insert(__position.base(), __x), this);
    315       }
    316 
    317 #ifdef __GXX_EXPERIMENTAL_CXX0X__
    318       iterator
    319       insert(iterator __position, _Tp&& __x)
    320       { return emplace(__position, std::move(__x)); }
    321 
    322       void
    323       insert(iterator __p, initializer_list<value_type> __l)
    324       {
    325 	__glibcxx_check_insert(__p);
    326 	_Base::insert(__p, __l);
    327       }
    328 #endif
    329 
    330       void
    331       insert(iterator __position, size_type __n, const _Tp& __x)
    332       {
    333 	__glibcxx_check_insert(__position);
    334 	_Base::insert(__position.base(), __n, __x);
    335       }
    336 
    337       template<class _InputIterator>
    338         void
    339         insert(iterator __position, _InputIterator __first,
    340 	       _InputIterator __last)
    341         {
    342 	  __glibcxx_check_insert_range(__position, __first, __last);
    343 	  _Base::insert(__position.base(), __first, __last);
    344 	}
    345 
    346       iterator
    347       erase(iterator __position)
    348       {
    349 	__glibcxx_check_erase(__position);
    350 	__position._M_invalidate();
    351 	return iterator(_Base::erase(__position.base()), this);
    352       }
    353 
    354       iterator
    355       erase(iterator __position, iterator __last)
    356       {
    357 	// _GLIBCXX_RESOLVE_LIB_DEFECTS
    358 	// 151. can't currently clear() empty container
    359 	__glibcxx_check_erase_range(__position, __last);
    360 	for (iterator __victim = __position; __victim != __last; )
    361 	  {
    362 	    iterator __old = __victim;
    363 	    ++__victim;
    364 	    __old._M_invalidate();
    365 	  }
    366 	return iterator(_Base::erase(__position.base(), __last.base()), this);
    367       }
    368 
    369       void
    370 #ifdef __GXX_EXPERIMENTAL_CXX0X__
    371       swap(list&& __x)
    372 #else
    373       swap(list& __x)
    374 #endif
    375       {
    376 	_Base::swap(__x);
    377 	this->_M_swap(__x);
    378       }
    379 
    380       void
    381       clear()
    382       {
    383 	_Base::clear();
    384 	this->_M_invalidate_all();
    385       }
    386 
    387       // 23.2.2.4 list operations:
    388       void
    389 #ifdef __GXX_EXPERIMENTAL_CXX0X__
    390       splice(iterator __position, list&& __x)
    391 #else
    392       splice(iterator __position, list& __x)
    393 #endif
    394       {
    395 	_GLIBCXX_DEBUG_VERIFY(&__x != this,
    396 			      _M_message(__gnu_debug::__msg_self_splice)
    397 			      ._M_sequence(*this, "this"));
    398 	this->splice(__position, _GLIBCXX_MOVE(__x), __x.begin(), __x.end());
    399       }
    400 
    401       void
    402 #ifdef __GXX_EXPERIMENTAL_CXX0X__
    403       splice(iterator __position, list&& __x, iterator __i)
    404 #else
    405       splice(iterator __position, list& __x, iterator __i)
    406 #endif
    407       {
    408 	__glibcxx_check_insert(__position);
    409 
    410 	// We used to perform the splice_alloc check:  not anymore, redundant
    411 	// after implementing the relevant bits of N1599.
    412 
    413 	_GLIBCXX_DEBUG_VERIFY(__i._M_dereferenceable(),
    414 			      _M_message(__gnu_debug::__msg_splice_bad)
    415 			      ._M_iterator(__i, "__i"));
    416 	_GLIBCXX_DEBUG_VERIFY(__i._M_attached_to(&__x),
    417 			      _M_message(__gnu_debug::__msg_splice_other)
    418 			     ._M_iterator(__i, "__i")._M_sequence(__x, "__x"));
    419 
    420 	// _GLIBCXX_RESOLVE_LIB_DEFECTS
    421 	// 250. splicing invalidates iterators
    422 	this->_M_transfer_iter(__i);
    423 	_Base::splice(__position.base(), _GLIBCXX_MOVE(__x._M_base()),
    424 		      __i.base());
    425       }
    426 
    427       void
    428 #ifdef __GXX_EXPERIMENTAL_CXX0X__
    429       splice(iterator __position, list&& __x, iterator __first,
    430 	     iterator __last)
    431 #else
    432       splice(iterator __position, list& __x, iterator __first,
    433 	     iterator __last)
    434 #endif
    435       {
    436 	__glibcxx_check_insert(__position);
    437 	__glibcxx_check_valid_range(__first, __last);
    438 	_GLIBCXX_DEBUG_VERIFY(__first._M_attached_to(&__x),
    439 			      _M_message(__gnu_debug::__msg_splice_other)
    440 			      ._M_sequence(__x, "x")
    441 			      ._M_iterator(__first, "first"));
    442 
    443 	// We used to perform the splice_alloc check:  not anymore, redundant
    444 	// after implementing the relevant bits of N1599.
    445 
    446 	for (iterator __tmp = __first; __tmp != __last; )
    447 	  {
    448 	    _GLIBCXX_DEBUG_VERIFY(&__x != this || __tmp != __position,
    449 				_M_message(__gnu_debug::__msg_splice_overlap)
    450 				  ._M_iterator(__tmp, "position")
    451 				  ._M_iterator(__first, "first")
    452 				  ._M_iterator(__last, "last"));
    453 	    iterator __victim = __tmp++;
    454 	    // _GLIBCXX_RESOLVE_LIB_DEFECTS
    455 	    // 250. splicing invalidates iterators
    456 	    this->_M_transfer_iter(__victim);
    457 	  }
    458 
    459 	_Base::splice(__position.base(), _GLIBCXX_MOVE(__x._M_base()),
    460 		      __first.base(), __last.base());
    461       }
    462 
    463       void
    464       remove(const _Tp& __value)
    465       {
    466 	for (iterator __x = begin(); __x.base() != _Base::end(); )
    467 	  {
    468 	    if (*__x == __value)
    469 	      __x = erase(__x);
    470 	    else
    471 	      ++__x;
    472 	  }
    473       }
    474 
    475       template<class _Predicate>
    476         void
    477         remove_if(_Predicate __pred)
    478         {
    479 	  for (iterator __x = begin(); __x.base() != _Base::end(); )
    480 	    {
    481 	      if (__pred(*__x))
    482 		__x = erase(__x);
    483 	      else
    484 		++__x;
    485 	    }
    486 	}
    487 
    488       void
    489       unique()
    490       {
    491 	iterator __first = begin();
    492 	iterator __last = end();
    493 	if (__first == __last)
    494 	  return;
    495 	iterator __next = __first;
    496 	while (++__next != __last)
    497 	  {
    498 	    if (*__first == *__next)
    499 	      erase(__next);
    500 	    else
    501 	      __first = __next;
    502 	    __next = __first;
    503 	  }
    504       }
    505 
    506       template<class _BinaryPredicate>
    507         void
    508         unique(_BinaryPredicate __binary_pred)
    509         {
    510 	  iterator __first = begin();
    511 	  iterator __last = end();
    512 	  if (__first == __last)
    513 	    return;
    514 	  iterator __next = __first;
    515 	  while (++__next != __last)
    516 	    {
    517 	      if (__binary_pred(*__first, *__next))
    518 		erase(__next);
    519 	      else
    520 		__first = __next;
    521 	      __next = __first;
    522 	    }
    523 	}
    524 
    525       void
    526 #ifdef __GXX_EXPERIMENTAL_CXX0X__
    527       merge(list&& __x)
    528 #else
    529       merge(list& __x)
    530 #endif
    531       {
    532 	// _GLIBCXX_RESOLVE_LIB_DEFECTS
    533 	// 300. list::merge() specification incomplete
    534 	if (this != &__x)
    535 	  {
    536 	    __glibcxx_check_sorted(_Base::begin(), _Base::end());
    537 	    __glibcxx_check_sorted(__x.begin().base(), __x.end().base());
    538 	    for (iterator __tmp = __x.begin(); __tmp != __x.end();)
    539 	      {
    540 		iterator __victim = __tmp++;
    541 		this->_M_transfer_iter(__victim);
    542 	      }
    543 	    _Base::merge(_GLIBCXX_MOVE(__x._M_base()));
    544 	  }
    545       }
    546 
    547       template<class _Compare>
    548         void
    549 #ifdef __GXX_EXPERIMENTAL_CXX0X__
    550         merge(list&& __x, _Compare __comp)
    551 #else
    552         merge(list& __x, _Compare __comp)
    553 #endif
    554         {
    555 	  // _GLIBCXX_RESOLVE_LIB_DEFECTS
    556 	  // 300. list::merge() specification incomplete
    557 	  if (this != &__x)
    558 	    {
    559 	      __glibcxx_check_sorted_pred(_Base::begin(), _Base::end(),
    560 					  __comp);
    561 	      __glibcxx_check_sorted_pred(__x.begin().base(), __x.end().base(),
    562 					  __comp);
    563 	      for (iterator __tmp = __x.begin(); __tmp != __x.end();)
    564 		{
    565 		  iterator __victim = __tmp++;
    566 		  this->_M_transfer_iter(__victim);
    567 		}
    568 	      _Base::merge(_GLIBCXX_MOVE(__x._M_base()), __comp);
    569 	    }
    570 	}
    571 
    572       void
    573       sort() { _Base::sort(); }
    574 
    575       template<typename _StrictWeakOrdering>
    576         void
    577         sort(_StrictWeakOrdering __pred) { _Base::sort(__pred); }
    578 
    579       using _Base::reverse;
    580 
    581       _Base&
    582       _M_base()       { return *this; }
    583 
    584       const _Base&
    585       _M_base() const { return *this; }
    586 
    587     private:
    588       void
    589       _M_invalidate_all()
    590       {
    591 	typedef typename _Base::const_iterator _Base_const_iterator;
    592 	typedef __gnu_debug::_Not_equal_to<_Base_const_iterator> _Not_equal;
    593 	this->_M_invalidate_if(_Not_equal(_M_base().end()));
    594       }
    595     };
    596 
    597   template<typename _Tp, typename _Alloc>
    598     inline bool
    599     operator==(const list<_Tp, _Alloc>& __lhs,
    600 	       const list<_Tp, _Alloc>& __rhs)
    601     { return __lhs._M_base() == __rhs._M_base(); }
    602 
    603   template<typename _Tp, typename _Alloc>
    604     inline bool
    605     operator!=(const list<_Tp, _Alloc>& __lhs,
    606 	       const list<_Tp, _Alloc>& __rhs)
    607     { return __lhs._M_base() != __rhs._M_base(); }
    608 
    609   template<typename _Tp, typename _Alloc>
    610     inline bool
    611     operator<(const list<_Tp, _Alloc>& __lhs,
    612 	      const list<_Tp, _Alloc>& __rhs)
    613     { return __lhs._M_base() < __rhs._M_base(); }
    614 
    615   template<typename _Tp, typename _Alloc>
    616     inline bool
    617     operator<=(const list<_Tp, _Alloc>& __lhs,
    618 	       const list<_Tp, _Alloc>& __rhs)
    619     { return __lhs._M_base() <= __rhs._M_base(); }
    620 
    621   template<typename _Tp, typename _Alloc>
    622     inline bool
    623     operator>=(const list<_Tp, _Alloc>& __lhs,
    624 	       const list<_Tp, _Alloc>& __rhs)
    625     { return __lhs._M_base() >= __rhs._M_base(); }
    626 
    627   template<typename _Tp, typename _Alloc>
    628     inline bool
    629     operator>(const list<_Tp, _Alloc>& __lhs,
    630 	      const list<_Tp, _Alloc>& __rhs)
    631     { return __lhs._M_base() > __rhs._M_base(); }
    632 
    633   template<typename _Tp, typename _Alloc>
    634     inline void
    635     swap(list<_Tp, _Alloc>& __lhs, list<_Tp, _Alloc>& __rhs)
    636     { __lhs.swap(__rhs); }
    637 
    638 #ifdef __GXX_EXPERIMENTAL_CXX0X__
    639   template<typename _Tp, typename _Alloc>
    640     inline void
    641     swap(list<_Tp, _Alloc>&& __lhs, list<_Tp, _Alloc>& __rhs)
    642     { __lhs.swap(__rhs); }
    643 
    644   template<typename _Tp, typename _Alloc>
    645     inline void
    646     swap(list<_Tp, _Alloc>& __lhs, list<_Tp, _Alloc>&& __rhs)
    647     { __lhs.swap(__rhs); }
    648 #endif
    649 
    650 } // namespace __debug
    651 } // namespace std
    652 
    653 #endif
    654