Home | History | Annotate | Download | only in debug
      1 // Debugging vector 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/vector
     27  *  This file is a GNU debug extension to the Standard C++ Library.
     28  */
     29 
     30 #ifndef _GLIBCXX_DEBUG_VECTOR
     31 #define _GLIBCXX_DEBUG_VECTOR 1
     32 
     33 #include <vector>
     34 #include <utility>
     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,
     43 	   typename _Allocator = std::allocator<_Tp> >
     44     class vector
     45     : public _GLIBCXX_STD_D::vector<_Tp, _Allocator>,
     46       public __gnu_debug::_Safe_sequence<vector<_Tp, _Allocator> >
     47     {
     48       typedef _GLIBCXX_STD_D::vector<_Tp, _Allocator> _Base;
     49       typedef __gnu_debug::_Safe_sequence<vector>              _Safe_base;
     50 
     51       typedef typename _Base::const_iterator _Base_const_iterator;
     52       typedef __gnu_debug::_After_nth_from<_Base_const_iterator> _After_nth;
     53 
     54     public:
     55       typedef typename _Base::reference             reference;
     56       typedef typename _Base::const_reference       const_reference;
     57 
     58       typedef __gnu_debug::_Safe_iterator<typename _Base::iterator,vector>
     59       iterator;
     60       typedef __gnu_debug::_Safe_iterator<typename _Base::const_iterator,vector>
     61       const_iterator;
     62 
     63       typedef typename _Base::size_type             size_type;
     64       typedef typename _Base::difference_type       difference_type;
     65 
     66       typedef _Tp				    value_type;
     67       typedef _Allocator			    allocator_type;
     68       typedef typename _Base::pointer               pointer;
     69       typedef typename _Base::const_pointer         const_pointer;
     70       typedef std::reverse_iterator<iterator>       reverse_iterator;
     71       typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
     72 
     73       // 23.2.4.1 construct/copy/destroy:
     74       explicit vector(const _Allocator& __a = _Allocator())
     75       : _Base(__a), _M_guaranteed_capacity(0) { }
     76 
     77       explicit vector(size_type __n, const _Tp& __value = _Tp(),
     78 		      const _Allocator& __a = _Allocator())
     79       : _Base(__n, __value, __a), _M_guaranteed_capacity(__n) { }
     80 
     81       template<class _InputIterator>
     82         vector(_InputIterator __first, _InputIterator __last,
     83 	       const _Allocator& __a = _Allocator())
     84 	: _Base(__gnu_debug::__check_valid_range(__first, __last),
     85 		__last, __a),
     86 	  _M_guaranteed_capacity(0)
     87         { _M_update_guaranteed_capacity(); }
     88 
     89       vector(const vector& __x)
     90       : _Base(__x), _Safe_base(), _M_guaranteed_capacity(__x.size()) { }
     91 
     92       /// Construction from a release-mode vector
     93       vector(const _Base& __x)
     94       : _Base(__x), _Safe_base(), _M_guaranteed_capacity(__x.size()) { }
     95 
     96 #ifdef __GXX_EXPERIMENTAL_CXX0X__
     97       vector(vector&& __x)
     98       : _Base(std::forward<vector>(__x)), _Safe_base(),
     99 	_M_guaranteed_capacity(this->size())
    100       {
    101 	this->_M_swap(__x);
    102 	__x._M_guaranteed_capacity = 0;
    103       }
    104 
    105       vector(initializer_list<value_type> __l,
    106 	     const allocator_type& __a = allocator_type())
    107       : _Base(__l, __a), _Safe_base(),
    108 	_M_guaranteed_capacity(__l.size()) { }
    109 #endif
    110 
    111       ~vector() { }
    112 
    113       vector&
    114       operator=(const vector& __x)
    115       {
    116 	static_cast<_Base&>(*this) = __x;
    117 	this->_M_invalidate_all();
    118 	_M_update_guaranteed_capacity();
    119 	return *this;
    120       }
    121 
    122 #ifdef __GXX_EXPERIMENTAL_CXX0X__
    123       vector&
    124       operator=(vector&& __x)
    125       {
    126         // NB: DR 675.
    127 	clear();
    128 	swap(__x);
    129 	return *this;
    130       }
    131 
    132       vector&
    133       operator=(initializer_list<value_type> __l)
    134       {
    135 	static_cast<_Base&>(*this) = __l;
    136 	this->_M_invalidate_all();
    137 	_M_update_guaranteed_capacity();
    138 	return *this;
    139       }
    140 #endif
    141 
    142       template<typename _InputIterator>
    143         void
    144         assign(_InputIterator __first, _InputIterator __last)
    145         {
    146 	  __glibcxx_check_valid_range(__first, __last);
    147 	  _Base::assign(__first, __last);
    148 	  this->_M_invalidate_all();
    149 	  _M_update_guaranteed_capacity();
    150 	}
    151 
    152       void
    153       assign(size_type __n, const _Tp& __u)
    154       {
    155 	_Base::assign(__n, __u);
    156 	this->_M_invalidate_all();
    157 	_M_update_guaranteed_capacity();
    158       }
    159 
    160 #ifdef __GXX_EXPERIMENTAL_CXX0X__
    161       void
    162       assign(initializer_list<value_type> __l)
    163       {
    164 	_Base::assign(__l);
    165 	this->_M_invalidate_all();
    166 	_M_update_guaranteed_capacity();
    167       }
    168 #endif
    169 
    170       using _Base::get_allocator;
    171 
    172       // iterators:
    173       iterator
    174       begin()
    175       { return iterator(_Base::begin(), this); }
    176 
    177       const_iterator
    178       begin() const
    179       { return const_iterator(_Base::begin(), this); }
    180 
    181       iterator
    182       end()
    183       { return iterator(_Base::end(), this); }
    184 
    185       const_iterator
    186       end() const
    187       { return const_iterator(_Base::end(), this); }
    188 
    189       reverse_iterator
    190       rbegin()
    191       { return reverse_iterator(end()); }
    192 
    193       const_reverse_iterator
    194       rbegin() const
    195       { return const_reverse_iterator(end()); }
    196 
    197       reverse_iterator
    198       rend()
    199       { return reverse_iterator(begin()); }
    200 
    201       const_reverse_iterator
    202       rend() const
    203       { return const_reverse_iterator(begin()); }
    204 
    205 #ifdef __GXX_EXPERIMENTAL_CXX0X__
    206       const_iterator
    207       cbegin() const
    208       { return const_iterator(_Base::begin(), this); }
    209 
    210       const_iterator
    211       cend() const
    212       { return const_iterator(_Base::end(), this); }
    213 
    214       const_reverse_iterator
    215       crbegin() const
    216       { return const_reverse_iterator(end()); }
    217 
    218       const_reverse_iterator
    219       crend() const
    220       { return const_reverse_iterator(begin()); }
    221 #endif
    222 
    223       // 23.2.4.2 capacity:
    224       using _Base::size;
    225       using _Base::max_size;
    226 
    227       void
    228       resize(size_type __sz, _Tp __c = _Tp())
    229       {
    230 	bool __realloc = _M_requires_reallocation(__sz);
    231 	if (__sz < this->size())
    232 	  this->_M_invalidate_if(_After_nth(__sz, _M_base().begin()));
    233 	_Base::resize(__sz, __c);
    234 	if (__realloc)
    235 	  this->_M_invalidate_all();
    236       }
    237 
    238       size_type
    239       capacity() const
    240       {
    241 #ifdef _GLIBCXX_DEBUG_PEDANTIC
    242 	return _M_guaranteed_capacity;
    243 #else
    244 	return _Base::capacity();
    245 #endif
    246       }
    247 
    248       using _Base::empty;
    249 
    250       void
    251       reserve(size_type __n)
    252       {
    253 	bool __realloc = _M_requires_reallocation(__n);
    254 	_Base::reserve(__n);
    255 	if (__n > _M_guaranteed_capacity)
    256 	  _M_guaranteed_capacity = __n;
    257 	if (__realloc)
    258 	  this->_M_invalidate_all();
    259       }
    260 
    261       // element access:
    262       reference
    263       operator[](size_type __n)
    264       {
    265 	__glibcxx_check_subscript(__n);
    266 	return _M_base()[__n];
    267       }
    268 
    269       const_reference
    270       operator[](size_type __n) const
    271       {
    272 	__glibcxx_check_subscript(__n);
    273 	return _M_base()[__n];
    274       }
    275 
    276       using _Base::at;
    277 
    278       reference
    279       front()
    280       {
    281 	__glibcxx_check_nonempty();
    282 	return _Base::front();
    283       }
    284 
    285       const_reference
    286       front() const
    287       {
    288 	__glibcxx_check_nonempty();
    289 	return _Base::front();
    290       }
    291 
    292       reference
    293       back()
    294       {
    295 	__glibcxx_check_nonempty();
    296 	return _Base::back();
    297       }
    298 
    299       const_reference
    300       back() const
    301       {
    302 	__glibcxx_check_nonempty();
    303 	return _Base::back();
    304       }
    305 
    306       // _GLIBCXX_RESOLVE_LIB_DEFECTS
    307       // DR 464. Suggestion for new member functions in standard containers.
    308       using _Base::data;
    309 
    310       // 23.2.4.3 modifiers:
    311       void
    312       push_back(const _Tp& __x)
    313       {
    314 	bool __realloc = _M_requires_reallocation(this->size() + 1);
    315 	_Base::push_back(__x);
    316 	if (__realloc)
    317 	  this->_M_invalidate_all();
    318 	_M_update_guaranteed_capacity();
    319       }
    320 
    321 #ifdef __GXX_EXPERIMENTAL_CXX0X__
    322       template<typename _Up = _Tp>
    323         typename __gnu_cxx::__enable_if<!std::__are_same<_Up, bool>::__value,
    324 					void>::__type
    325         push_back(_Tp&& __x)
    326 	{ emplace_back(std::move(__x)); }
    327 
    328       template<typename... _Args>
    329         void
    330         emplace_back(_Args&&... __args)
    331 	{
    332 	  bool __realloc = _M_requires_reallocation(this->size() + 1);
    333 	  _Base::emplace_back(std::forward<_Args>(__args)...);
    334 	  if (__realloc)
    335 	    this->_M_invalidate_all();
    336 	  _M_update_guaranteed_capacity();
    337 	}
    338 #endif
    339 
    340       void
    341       pop_back()
    342       {
    343 	__glibcxx_check_nonempty();
    344 	iterator __victim = end() - 1;
    345 	__victim._M_invalidate();
    346 	_Base::pop_back();
    347       }
    348 
    349 #ifdef __GXX_EXPERIMENTAL_CXX0X__
    350       template<typename... _Args>
    351         iterator
    352         emplace(iterator __position, _Args&&... __args)
    353 	{
    354 	  __glibcxx_check_insert(__position);
    355 	  bool __realloc = _M_requires_reallocation(this->size() + 1);
    356 	  difference_type __offset = __position - begin();
    357 	  typename _Base::iterator __res = _Base::emplace(__position.base(),
    358 					    std::forward<_Args>(__args)...);
    359 	  if (__realloc)
    360 	    this->_M_invalidate_all();
    361 	  else
    362 	    this->_M_invalidate_if(_After_nth(__offset, _M_base().begin()));
    363 	  _M_update_guaranteed_capacity();
    364 	  return iterator(__res, this);
    365 	}
    366 #endif
    367 
    368       iterator
    369       insert(iterator __position, const _Tp& __x)
    370       {
    371 	__glibcxx_check_insert(__position);
    372 	bool __realloc = _M_requires_reallocation(this->size() + 1);
    373 	difference_type __offset = __position - begin();
    374 	typename _Base::iterator __res = _Base::insert(__position.base(),__x);
    375 	if (__realloc)
    376 	  this->_M_invalidate_all();
    377 	else
    378 	  this->_M_invalidate_if(_After_nth(__offset, _M_base().begin()));
    379 	_M_update_guaranteed_capacity();
    380 	return iterator(__res, this);
    381       }
    382 
    383 #ifdef __GXX_EXPERIMENTAL_CXX0X__
    384       template<typename _Up = _Tp>
    385         typename __gnu_cxx::__enable_if<!std::__are_same<_Up, bool>::__value,
    386 					iterator>::__type
    387         insert(iterator __position, _Tp&& __x)
    388         { return emplace(__position, std::move(__x)); }
    389 
    390       void
    391       insert(iterator __position, initializer_list<value_type> __l)
    392       { this->insert(__position, __l.begin(), __l.end()); }
    393 #endif
    394 
    395       void
    396       insert(iterator __position, size_type __n, const _Tp& __x)
    397       {
    398 	__glibcxx_check_insert(__position);
    399 	bool __realloc = _M_requires_reallocation(this->size() + __n);
    400 	difference_type __offset = __position - begin();
    401 	_Base::insert(__position.base(), __n, __x);
    402 	if (__realloc)
    403 	  this->_M_invalidate_all();
    404 	else
    405 	  this->_M_invalidate_if(_After_nth(__offset, _M_base().begin()));
    406 	_M_update_guaranteed_capacity();
    407       }
    408 
    409       template<class _InputIterator>
    410         void
    411         insert(iterator __position,
    412 	       _InputIterator __first, _InputIterator __last)
    413         {
    414 	  __glibcxx_check_insert_range(__position, __first, __last);
    415 
    416 	  /* Hard to guess if invalidation will occur, because __last
    417 	     - __first can't be calculated in all cases, so we just
    418 	     punt here by checking if it did occur. */
    419 	  typename _Base::iterator __old_begin = _M_base().begin();
    420 	  difference_type __offset = __position - begin();
    421 	  _Base::insert(__position.base(), __first, __last);
    422 
    423 	  if (_M_base().begin() != __old_begin)
    424 	    this->_M_invalidate_all();
    425 	  else
    426 	    this->_M_invalidate_if(_After_nth(__offset, _M_base().begin()));
    427 	  _M_update_guaranteed_capacity();
    428 	}
    429 
    430       iterator
    431       erase(iterator __position)
    432       {
    433 	__glibcxx_check_erase(__position);
    434 	difference_type __offset = __position - begin();
    435 	typename _Base::iterator __res = _Base::erase(__position.base());
    436 	this->_M_invalidate_if(_After_nth(__offset, _M_base().begin()));
    437 	return iterator(__res, this);
    438       }
    439 
    440       iterator
    441       erase(iterator __first, iterator __last)
    442       {
    443 	// _GLIBCXX_RESOLVE_LIB_DEFECTS
    444 	// 151. can't currently clear() empty container
    445 	__glibcxx_check_erase_range(__first, __last);
    446 
    447 	difference_type __offset = __first - begin();
    448 	typename _Base::iterator __res = _Base::erase(__first.base(),
    449 							 __last.base());
    450 	this->_M_invalidate_if(_After_nth(__offset, _M_base().begin()));
    451 	return iterator(__res, this);
    452       }
    453 
    454       void
    455 #ifdef __GXX_EXPERIMENTAL_CXX0X__
    456       swap(vector&& __x)
    457 #else
    458       swap(vector& __x)
    459 #endif
    460       {
    461 	_Base::swap(__x);
    462 	this->_M_swap(__x);
    463         std::swap(_M_guaranteed_capacity, __x._M_guaranteed_capacity);
    464       }
    465 
    466       void
    467       clear()
    468       {
    469 	_Base::clear();
    470 	this->_M_invalidate_all();
    471         _M_guaranteed_capacity = 0;
    472       }
    473 
    474       _Base&
    475       _M_base() { return *this; }
    476 
    477       const _Base&
    478       _M_base() const { return *this; }
    479 
    480     private:
    481       size_type _M_guaranteed_capacity;
    482 
    483       bool
    484       _M_requires_reallocation(size_type __elements)
    485       { return __elements > this->capacity(); }
    486 
    487       void
    488       _M_update_guaranteed_capacity()
    489       {
    490 	if (this->size() > _M_guaranteed_capacity)
    491 	  _M_guaranteed_capacity = this->size();
    492       }
    493     };
    494 
    495   template<typename _Tp, typename _Alloc>
    496     inline bool
    497     operator==(const vector<_Tp, _Alloc>& __lhs,
    498 	       const vector<_Tp, _Alloc>& __rhs)
    499     { return __lhs._M_base() == __rhs._M_base(); }
    500 
    501   template<typename _Tp, typename _Alloc>
    502     inline bool
    503     operator!=(const vector<_Tp, _Alloc>& __lhs,
    504 	       const vector<_Tp, _Alloc>& __rhs)
    505     { return __lhs._M_base() != __rhs._M_base(); }
    506 
    507   template<typename _Tp, typename _Alloc>
    508     inline bool
    509     operator<(const vector<_Tp, _Alloc>& __lhs,
    510 	      const vector<_Tp, _Alloc>& __rhs)
    511     { return __lhs._M_base() < __rhs._M_base(); }
    512 
    513   template<typename _Tp, typename _Alloc>
    514     inline bool
    515     operator<=(const vector<_Tp, _Alloc>& __lhs,
    516 	       const vector<_Tp, _Alloc>& __rhs)
    517     { return __lhs._M_base() <= __rhs._M_base(); }
    518 
    519   template<typename _Tp, typename _Alloc>
    520     inline bool
    521     operator>=(const vector<_Tp, _Alloc>& __lhs,
    522 	       const vector<_Tp, _Alloc>& __rhs)
    523     { return __lhs._M_base() >= __rhs._M_base(); }
    524 
    525   template<typename _Tp, typename _Alloc>
    526     inline bool
    527     operator>(const vector<_Tp, _Alloc>& __lhs,
    528 	      const vector<_Tp, _Alloc>& __rhs)
    529     { return __lhs._M_base() > __rhs._M_base(); }
    530 
    531   template<typename _Tp, typename _Alloc>
    532     inline void
    533     swap(vector<_Tp, _Alloc>& __lhs, vector<_Tp, _Alloc>& __rhs)
    534     { __lhs.swap(__rhs); }
    535 
    536 #ifdef __GXX_EXPERIMENTAL_CXX0X__
    537   template<typename _Tp, typename _Alloc>
    538     inline void
    539     swap(vector<_Tp, _Alloc>&& __lhs, vector<_Tp, _Alloc>& __rhs)
    540     { __lhs.swap(__rhs); }
    541 
    542   template<typename _Tp, typename _Alloc>
    543     inline void
    544     swap(vector<_Tp, _Alloc>& __lhs, vector<_Tp, _Alloc>&& __rhs)
    545     { __lhs.swap(__rhs); }
    546 #endif
    547 
    548 } // namespace __debug
    549 } // namespace std
    550 
    551 #endif
    552