debug/vector

Go to the documentation of this file.
00001 // Debugging vector implementation -*- C++ -*-
00002 
00003 // Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
00004 // Free Software Foundation, Inc.
00005 //
00006 // This file is part of the GNU ISO C++ Library.  This library is free
00007 // software; you can redistribute it and/or modify it under the
00008 // terms of the GNU General Public License as published by the
00009 // Free Software Foundation; either version 3, or (at your option)
00010 // any later version.
00011 
00012 // This library is distributed in the hope that it will be useful,
00013 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015 // GNU General Public License for more details.
00016 
00017 // Under Section 7 of GPL version 3, you are granted additional
00018 // permissions described in the GCC Runtime Library Exception, version
00019 // 3.1, as published by the Free Software Foundation.
00020 
00021 // You should have received a copy of the GNU General Public License and
00022 // a copy of the GCC Runtime Library Exception along with this program;
00023 // see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
00024 // <http://www.gnu.org/licenses/>.
00025 
00026 /** @file debug/vector
00027  *  This file is a GNU debug extension to the Standard C++ Library.
00028  */
00029 
00030 #ifndef _GLIBCXX_DEBUG_VECTOR
00031 #define _GLIBCXX_DEBUG_VECTOR 1
00032 
00033 #include <vector>
00034 #include <utility>
00035 #include <debug/safe_sequence.h>
00036 #include <debug/safe_iterator.h>
00037 
00038 namespace std
00039 {
00040 namespace __debug
00041 {
00042   /// Class std::vector with safety/checking/debug instrumentation.
00043   template<typename _Tp,
00044        typename _Allocator = std::allocator<_Tp> >
00045     class vector
00046     : public _GLIBCXX_STD_D::vector<_Tp, _Allocator>,
00047       public __gnu_debug::_Safe_sequence<vector<_Tp, _Allocator> >
00048     {
00049       typedef _GLIBCXX_STD_D::vector<_Tp, _Allocator> _Base;
00050       typedef __gnu_debug::_Safe_sequence<vector>              _Safe_base;
00051 
00052       typedef typename _Base::const_iterator _Base_const_iterator;
00053       typedef __gnu_debug::_After_nth_from<_Base_const_iterator> _After_nth;
00054 
00055     public:
00056       typedef typename _Base::reference             reference;
00057       typedef typename _Base::const_reference       const_reference;
00058 
00059       typedef __gnu_debug::_Safe_iterator<typename _Base::iterator,vector>
00060       iterator;
00061       typedef __gnu_debug::_Safe_iterator<typename _Base::const_iterator,vector>
00062       const_iterator;
00063 
00064       typedef typename _Base::size_type             size_type;
00065       typedef typename _Base::difference_type       difference_type;
00066 
00067       typedef _Tp                   value_type;
00068       typedef _Allocator                allocator_type;
00069       typedef typename _Base::pointer               pointer;
00070       typedef typename _Base::const_pointer         const_pointer;
00071       typedef std::reverse_iterator<iterator>       reverse_iterator;
00072       typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
00073 
00074       // 23.2.4.1 construct/copy/destroy:
00075       explicit
00076       vector(const _Allocator& __a = _Allocator())
00077       : _Base(__a), _M_guaranteed_capacity(0) { }
00078 
00079 #ifdef __GXX_EXPERIMENTAL_CXX0X__
00080       explicit
00081       vector(size_type __n)
00082       : _Base(__n), _M_guaranteed_capacity(__n) { }
00083 
00084       vector(size_type __n, const _Tp& __value,
00085          const _Allocator& __a = _Allocator())
00086       : _Base(__n, __value, __a), _M_guaranteed_capacity(__n) { }
00087 #else
00088       explicit
00089       vector(size_type __n, const _Tp& __value = _Tp(),
00090          const _Allocator& __a = _Allocator())
00091       : _Base(__n, __value, __a), _M_guaranteed_capacity(__n) { }
00092 #endif
00093 
00094       template<class _InputIterator>
00095         vector(_InputIterator __first, _InputIterator __last,
00096            const _Allocator& __a = _Allocator())
00097     : _Base(__gnu_debug::__check_valid_range(__first, __last),
00098         __last, __a),
00099       _M_guaranteed_capacity(0)
00100         { _M_update_guaranteed_capacity(); }
00101 
00102       vector(const vector& __x)
00103       : _Base(__x), _Safe_base(), _M_guaranteed_capacity(__x.size()) { }
00104 
00105       /// Construction from a release-mode vector
00106       vector(const _Base& __x)
00107       : _Base(__x), _Safe_base(), _M_guaranteed_capacity(__x.size()) { }
00108 
00109 #ifdef __GXX_EXPERIMENTAL_CXX0X__
00110       vector(vector&& __x)
00111       : _Base(std::forward<vector>(__x)), _Safe_base(),
00112     _M_guaranteed_capacity(this->size())
00113       {
00114     this->_M_swap(__x);
00115     __x._M_guaranteed_capacity = 0;
00116       }
00117 
00118       vector(initializer_list<value_type> __l,
00119          const allocator_type& __a = allocator_type())
00120       : _Base(__l, __a), _Safe_base(),
00121     _M_guaranteed_capacity(__l.size()) { }
00122 #endif
00123 
00124       ~vector() { }
00125 
00126       vector&
00127       operator=(const vector& __x)
00128       {
00129     static_cast<_Base&>(*this) = __x;
00130     this->_M_invalidate_all();
00131     _M_update_guaranteed_capacity();
00132     return *this;
00133       }
00134 
00135 #ifdef __GXX_EXPERIMENTAL_CXX0X__
00136       vector&
00137       operator=(vector&& __x)
00138       {
00139     // NB: DR 1204.
00140     // NB: DR 675.
00141     clear();
00142     swap(__x);
00143     return *this;
00144       }
00145 
00146       vector&
00147       operator=(initializer_list<value_type> __l)
00148       {
00149     static_cast<_Base&>(*this) = __l;
00150     this->_M_invalidate_all();
00151     _M_update_guaranteed_capacity();
00152     return *this;
00153       }
00154 #endif
00155 
00156       template<typename _InputIterator>
00157         void
00158         assign(_InputIterator __first, _InputIterator __last)
00159         {
00160       __glibcxx_check_valid_range(__first, __last);
00161       _Base::assign(__first, __last);
00162       this->_M_invalidate_all();
00163       _M_update_guaranteed_capacity();
00164     }
00165 
00166       void
00167       assign(size_type __n, const _Tp& __u)
00168       {
00169     _Base::assign(__n, __u);
00170     this->_M_invalidate_all();
00171     _M_update_guaranteed_capacity();
00172       }
00173 
00174 #ifdef __GXX_EXPERIMENTAL_CXX0X__
00175       void
00176       assign(initializer_list<value_type> __l)
00177       {
00178     _Base::assign(__l);
00179     this->_M_invalidate_all();
00180     _M_update_guaranteed_capacity();
00181       }
00182 #endif
00183 
00184       using _Base::get_allocator;
00185 
00186       // iterators:
00187       iterator
00188       begin()
00189       { return iterator(_Base::begin(), this); }
00190 
00191       const_iterator
00192       begin() const
00193       { return const_iterator(_Base::begin(), this); }
00194 
00195       iterator
00196       end()
00197       { return iterator(_Base::end(), this); }
00198 
00199       const_iterator
00200       end() const
00201       { return const_iterator(_Base::end(), this); }
00202 
00203       reverse_iterator
00204       rbegin()
00205       { return reverse_iterator(end()); }
00206 
00207       const_reverse_iterator
00208       rbegin() const
00209       { return const_reverse_iterator(end()); }
00210 
00211       reverse_iterator
00212       rend()
00213       { return reverse_iterator(begin()); }
00214 
00215       const_reverse_iterator
00216       rend() const
00217       { return const_reverse_iterator(begin()); }
00218 
00219 #ifdef __GXX_EXPERIMENTAL_CXX0X__
00220       const_iterator
00221       cbegin() const
00222       { return const_iterator(_Base::begin(), this); }
00223 
00224       const_iterator
00225       cend() const
00226       { return const_iterator(_Base::end(), this); }
00227 
00228       const_reverse_iterator
00229       crbegin() const
00230       { return const_reverse_iterator(end()); }
00231 
00232       const_reverse_iterator
00233       crend() const
00234       { return const_reverse_iterator(begin()); }
00235 #endif
00236 
00237       // 23.2.4.2 capacity:
00238       using _Base::size;
00239       using _Base::max_size;
00240 
00241 #ifdef __GXX_EXPERIMENTAL_CXX0X__
00242       void
00243       resize(size_type __sz)
00244       {
00245     bool __realloc = _M_requires_reallocation(__sz);
00246     if (__sz < this->size())
00247       this->_M_invalidate_if(_After_nth(__sz, _M_base().begin()));
00248     _Base::resize(__sz);
00249     if (__realloc)
00250       this->_M_invalidate_all();
00251     _M_update_guaranteed_capacity();
00252       }
00253 
00254       void
00255       resize(size_type __sz, const _Tp& __c)
00256       {
00257     bool __realloc = _M_requires_reallocation(__sz);
00258     if (__sz < this->size())
00259       this->_M_invalidate_if(_After_nth(__sz, _M_base().begin()));
00260     _Base::resize(__sz, __c);
00261     if (__realloc)
00262       this->_M_invalidate_all();
00263     _M_update_guaranteed_capacity();
00264       }
00265 #else
00266       void
00267       resize(size_type __sz, _Tp __c = _Tp())
00268       {
00269     bool __realloc = _M_requires_reallocation(__sz);
00270     if (__sz < this->size())
00271       this->_M_invalidate_if(_After_nth(__sz, _M_base().begin()));
00272     _Base::resize(__sz, __c);
00273     if (__realloc)
00274       this->_M_invalidate_all();
00275     _M_update_guaranteed_capacity();
00276       }
00277 #endif
00278 
00279 #ifdef __GXX_EXPERIMENTAL_CXX0X__
00280       using _Base::shrink_to_fit;
00281 #endif
00282 
00283       size_type
00284       capacity() const
00285       {
00286 #ifdef _GLIBCXX_DEBUG_PEDANTIC
00287     return _M_guaranteed_capacity;
00288 #else
00289     return _Base::capacity();
00290 #endif
00291       }
00292 
00293       using _Base::empty;
00294 
00295       void
00296       reserve(size_type __n)
00297       {
00298     bool __realloc = _M_requires_reallocation(__n);
00299     _Base::reserve(__n);
00300     if (__n > _M_guaranteed_capacity)
00301       _M_guaranteed_capacity = __n;
00302     if (__realloc)
00303       this->_M_invalidate_all();
00304       }
00305 
00306       // element access:
00307       reference
00308       operator[](size_type __n)
00309       {
00310     __glibcxx_check_subscript(__n);
00311     return _M_base()[__n];
00312       }
00313 
00314       const_reference
00315       operator[](size_type __n) const
00316       {
00317     __glibcxx_check_subscript(__n);
00318     return _M_base()[__n];
00319       }
00320 
00321       using _Base::at;
00322 
00323       reference
00324       front()
00325       {
00326     __glibcxx_check_nonempty();
00327     return _Base::front();
00328       }
00329 
00330       const_reference
00331       front() const
00332       {
00333     __glibcxx_check_nonempty();
00334     return _Base::front();
00335       }
00336 
00337       reference
00338       back()
00339       {
00340     __glibcxx_check_nonempty();
00341     return _Base::back();
00342       }
00343 
00344       const_reference
00345       back() const
00346       {
00347     __glibcxx_check_nonempty();
00348     return _Base::back();
00349       }
00350 
00351       // _GLIBCXX_RESOLVE_LIB_DEFECTS
00352       // DR 464. Suggestion for new member functions in standard containers.
00353       using _Base::data;
00354 
00355       // 23.2.4.3 modifiers:
00356       void
00357       push_back(const _Tp& __x)
00358       {
00359     bool __realloc = _M_requires_reallocation(this->size() + 1);
00360     _Base::push_back(__x);
00361     if (__realloc)
00362       this->_M_invalidate_all();
00363     _M_update_guaranteed_capacity();
00364       }
00365 
00366 #ifdef __GXX_EXPERIMENTAL_CXX0X__
00367       template<typename _Up = _Tp>
00368         typename __gnu_cxx::__enable_if<!std::__are_same<_Up, bool>::__value,
00369                     void>::__type
00370         push_back(_Tp&& __x)
00371     { emplace_back(std::move(__x)); }
00372 
00373       template<typename... _Args>
00374         void
00375         emplace_back(_Args&&... __args)
00376     {
00377       bool __realloc = _M_requires_reallocation(this->size() + 1);
00378       _Base::emplace_back(std::forward<_Args>(__args)...);
00379       if (__realloc)
00380         this->_M_invalidate_all();
00381       _M_update_guaranteed_capacity();
00382     }
00383 #endif
00384 
00385       void
00386       pop_back()
00387       {
00388     __glibcxx_check_nonempty();
00389     iterator __victim = end() - 1;
00390     __victim._M_invalidate();
00391     _Base::pop_back();
00392       }
00393 
00394 #ifdef __GXX_EXPERIMENTAL_CXX0X__
00395       template<typename... _Args>
00396         iterator
00397         emplace(iterator __position, _Args&&... __args)
00398     {
00399       __glibcxx_check_insert(__position);
00400       bool __realloc = _M_requires_reallocation(this->size() + 1);
00401       difference_type __offset = __position - begin();
00402       typename _Base::iterator __res = _Base::emplace(__position.base(),
00403                         std::forward<_Args>(__args)...);
00404       if (__realloc)
00405         this->_M_invalidate_all();
00406       else
00407         this->_M_invalidate_if(_After_nth(__offset, _M_base().begin()));
00408       _M_update_guaranteed_capacity();
00409       return iterator(__res, this);
00410     }
00411 #endif
00412 
00413       iterator
00414       insert(iterator __position, const _Tp& __x)
00415       {
00416     __glibcxx_check_insert(__position);
00417     bool __realloc = _M_requires_reallocation(this->size() + 1);
00418     difference_type __offset = __position - begin();
00419     typename _Base::iterator __res = _Base::insert(__position.base(),__x);
00420     if (__realloc)
00421       this->_M_invalidate_all();
00422     else
00423       this->_M_invalidate_if(_After_nth(__offset, _M_base().begin()));
00424     _M_update_guaranteed_capacity();
00425     return iterator(__res, this);
00426       }
00427 
00428 #ifdef __GXX_EXPERIMENTAL_CXX0X__
00429       template<typename _Up = _Tp>
00430         typename __gnu_cxx::__enable_if<!std::__are_same<_Up, bool>::__value,
00431                     iterator>::__type
00432         insert(iterator __position, _Tp&& __x)
00433         { return emplace(__position, std::move(__x)); }
00434 
00435       void
00436       insert(iterator __position, initializer_list<value_type> __l)
00437       { this->insert(__position, __l.begin(), __l.end()); }
00438 #endif
00439 
00440       void
00441       insert(iterator __position, size_type __n, const _Tp& __x)
00442       {
00443     __glibcxx_check_insert(__position);
00444     bool __realloc = _M_requires_reallocation(this->size() + __n);
00445     difference_type __offset = __position - begin();
00446     _Base::insert(__position.base(), __n, __x);
00447     if (__realloc)
00448       this->_M_invalidate_all();
00449     else
00450       this->_M_invalidate_if(_After_nth(__offset, _M_base().begin()));
00451     _M_update_guaranteed_capacity();
00452       }
00453 
00454       template<class _InputIterator>
00455         void
00456         insert(iterator __position,
00457            _InputIterator __first, _InputIterator __last)
00458         {
00459       __glibcxx_check_insert_range(__position, __first, __last);
00460 
00461       /* Hard to guess if invalidation will occur, because __last
00462          - __first can't be calculated in all cases, so we just
00463          punt here by checking if it did occur. */
00464       typename _Base::iterator __old_begin = _M_base().begin();
00465       difference_type __offset = __position - begin();
00466       _Base::insert(__position.base(), __first, __last);
00467 
00468       if (_M_base().begin() != __old_begin)
00469         this->_M_invalidate_all();
00470       else
00471         this->_M_invalidate_if(_After_nth(__offset, _M_base().begin()));
00472       _M_update_guaranteed_capacity();
00473     }
00474 
00475       iterator
00476       erase(iterator __position)
00477       {
00478     __glibcxx_check_erase(__position);
00479     difference_type __offset = __position - begin();
00480     typename _Base::iterator __res = _Base::erase(__position.base());
00481     this->_M_invalidate_if(_After_nth(__offset, _M_base().begin()));
00482     return iterator(__res, this);
00483       }
00484 
00485       iterator
00486       erase(iterator __first, iterator __last)
00487       {
00488     // _GLIBCXX_RESOLVE_LIB_DEFECTS
00489     // 151. can't currently clear() empty container
00490     __glibcxx_check_erase_range(__first, __last);
00491 
00492     difference_type __offset = __first - begin();
00493     typename _Base::iterator __res = _Base::erase(__first.base(),
00494                              __last.base());
00495     this->_M_invalidate_if(_After_nth(__offset, _M_base().begin()));
00496     return iterator(__res, this);
00497       }
00498 
00499       void
00500       swap(vector& __x)
00501       {
00502     _Base::swap(__x);
00503     this->_M_swap(__x);
00504         std::swap(_M_guaranteed_capacity, __x._M_guaranteed_capacity);
00505       }
00506 
00507       void
00508       clear()
00509       {
00510     _Base::clear();
00511     this->_M_invalidate_all();
00512         _M_guaranteed_capacity = 0;
00513       }
00514 
00515       _Base&
00516       _M_base() { return *this; }
00517 
00518       const _Base&
00519       _M_base() const { return *this; }
00520 
00521     private:
00522       size_type _M_guaranteed_capacity;
00523 
00524       bool
00525       _M_requires_reallocation(size_type __elements)
00526       { return __elements > this->capacity(); }
00527 
00528       void
00529       _M_update_guaranteed_capacity()
00530       {
00531     if (this->size() > _M_guaranteed_capacity)
00532       _M_guaranteed_capacity = this->size();
00533       }
00534     };
00535 
00536   template<typename _Tp, typename _Alloc>
00537     inline bool
00538     operator==(const vector<_Tp, _Alloc>& __lhs,
00539            const vector<_Tp, _Alloc>& __rhs)
00540     { return __lhs._M_base() == __rhs._M_base(); }
00541 
00542   template<typename _Tp, typename _Alloc>
00543     inline bool
00544     operator!=(const vector<_Tp, _Alloc>& __lhs,
00545            const vector<_Tp, _Alloc>& __rhs)
00546     { return __lhs._M_base() != __rhs._M_base(); }
00547 
00548   template<typename _Tp, typename _Alloc>
00549     inline bool
00550     operator<(const vector<_Tp, _Alloc>& __lhs,
00551           const vector<_Tp, _Alloc>& __rhs)
00552     { return __lhs._M_base() < __rhs._M_base(); }
00553 
00554   template<typename _Tp, typename _Alloc>
00555     inline bool
00556     operator<=(const vector<_Tp, _Alloc>& __lhs,
00557            const vector<_Tp, _Alloc>& __rhs)
00558     { return __lhs._M_base() <= __rhs._M_base(); }
00559 
00560   template<typename _Tp, typename _Alloc>
00561     inline bool
00562     operator>=(const vector<_Tp, _Alloc>& __lhs,
00563            const vector<_Tp, _Alloc>& __rhs)
00564     { return __lhs._M_base() >= __rhs._M_base(); }
00565 
00566   template<typename _Tp, typename _Alloc>
00567     inline bool
00568     operator>(const vector<_Tp, _Alloc>& __lhs,
00569           const vector<_Tp, _Alloc>& __rhs)
00570     { return __lhs._M_base() > __rhs._M_base(); }
00571 
00572   template<typename _Tp, typename _Alloc>
00573     inline void
00574     swap(vector<_Tp, _Alloc>& __lhs, vector<_Tp, _Alloc>& __rhs)
00575     { __lhs.swap(__rhs); }
00576 
00577 } // namespace __debug
00578 
00579 #ifdef __GXX_EXPERIMENTAL_CXX0X__
00580   // DR 1182.
00581   /// std::hash specialization for vector<bool>.
00582   template<typename _Alloc>
00583     struct hash<__debug::vector<bool, _Alloc>>
00584     : public std::unary_function<__debug::vector<bool, _Alloc>, size_t>
00585     {
00586       size_t
00587       operator()(const __debug::vector<bool, _Alloc>& __b) const
00588       { return std::hash<_GLIBCXX_STD_D::vector<bool, _Alloc>>()
00589       (__b._M_base()); }
00590     };
00591 #endif
00592 
00593 } // namespace std
00594 
00595 #endif