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