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