]>
Commit | Line | Data |
---|---|---|
8e6603f8 | 1 | // Safe iterator implementation -*- C++ -*- |
2 | ||
fbd26352 | 3 | // Copyright (C) 2011-2019 Free Software Foundation, Inc. |
8e6603f8 | 4 | // |
5 | // This file is part of the GNU ISO C++ Library. This library is free | |
6 | // software; you can redistribute it and/or modify it under the | |
7 | // terms of the GNU General Public License as published by the | |
8 | // Free Software Foundation; either version 3, or (at your option) | |
9 | // any later version. | |
10 | ||
11 | // This library is distributed in the hope that it will be useful, | |
12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | // GNU General Public License for more details. | |
15 | ||
16 | // Under Section 7 of GPL version 3, you are granted additional | |
17 | // permissions described in the GCC Runtime Library Exception, version | |
18 | // 3.1, as published by the Free Software Foundation. | |
19 | ||
20 | // You should have received a copy of the GNU General Public License and | |
21 | // a copy of the GCC Runtime Library Exception along with this program; | |
22 | // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see | |
23 | // <http://www.gnu.org/licenses/>. | |
24 | ||
25 | /** @file debug/safe_local_iterator.h | |
26 | * This file is a GNU debug extension to the Standard C++ Library. | |
27 | */ | |
28 | ||
29 | #ifndef _GLIBCXX_DEBUG_SAFE_LOCAL_ITERATOR_H | |
30 | #define _GLIBCXX_DEBUG_SAFE_LOCAL_ITERATOR_H 1 | |
31 | ||
8e6603f8 | 32 | #include <debug/safe_unordered_base.h> |
8e6603f8 | 33 | |
9fe2a042 | 34 | #define _GLIBCXX_DEBUG_VERIFY_OPERANDS(_Lhs, _Rhs) \ |
35 | _GLIBCXX_DEBUG_VERIFY(!_Lhs._M_singular() && !_Rhs._M_singular(), \ | |
36 | _M_message(__msg_iter_compare_bad) \ | |
37 | ._M_iterator(_Lhs, "lhs") \ | |
38 | ._M_iterator(_Rhs, "rhs")); \ | |
39 | _GLIBCXX_DEBUG_VERIFY(_Lhs._M_can_compare(_Rhs), \ | |
40 | _M_message(__msg_compare_different) \ | |
41 | ._M_iterator(_Lhs, "lhs") \ | |
42 | ._M_iterator(_Rhs, "rhs")); \ | |
43 | _GLIBCXX_DEBUG_VERIFY(_Lhs._M_in_same_bucket(_Rhs), \ | |
44 | _M_message(__msg_local_iter_compare_bad) \ | |
45 | ._M_iterator(_Lhs, "lhs") \ | |
46 | ._M_iterator(_Rhs, "rhs")) | |
47 | ||
8e6603f8 | 48 | namespace __gnu_debug |
49 | { | |
50 | /** \brief Safe iterator wrapper. | |
51 | * | |
52 | * The class template %_Safe_local_iterator is a wrapper around an | |
53 | * iterator that tracks the iterator's movement among sequences and | |
54 | * checks that operations performed on the "safe" iterator are | |
55 | * legal. In additional to the basic iterator operations (which are | |
56 | * validated, and then passed to the underlying iterator), | |
57 | * %_Safe_local_iterator has member functions for iterator invalidation, | |
58 | * attaching/detaching the iterator from sequences, and querying | |
59 | * the iterator's state. | |
60 | */ | |
61 | template<typename _Iterator, typename _Sequence> | |
616eb317 | 62 | class _Safe_local_iterator |
63 | : private _Iterator | |
64 | , public _Safe_local_iterator_base | |
8e6603f8 | 65 | { |
616eb317 | 66 | typedef _Iterator _Iter_base; |
67 | typedef _Safe_local_iterator_base _Safe_base; | |
319d9891 | 68 | |
8e6603f8 | 69 | typedef typename _Sequence::size_type size_type; |
70 | ||
8e6603f8 | 71 | typedef std::iterator_traits<_Iterator> _Traits; |
72 | ||
319d9891 | 73 | typedef std::__are_same< |
74 | typename _Sequence::_Base::const_local_iterator, | |
75 | _Iterator> _IsConstant; | |
76 | ||
77 | typedef typename __gnu_cxx::__conditional_type<_IsConstant::__value, | |
78 | typename _Sequence::_Base::local_iterator, | |
79 | typename _Sequence::_Base::const_local_iterator>::__type | |
80 | _OtherIterator; | |
81 | ||
9fe2a042 | 82 | typedef _Safe_local_iterator _Self; |
83 | typedef _Safe_local_iterator<_OtherIterator, _Sequence> _OtherSelf; | |
84 | ||
616eb317 | 85 | struct _Attach_single |
86 | { }; | |
87 | ||
319d9891 | 88 | _Safe_local_iterator(_Iterator __i, _Safe_sequence_base* __cont, |
616eb317 | 89 | _Attach_single) noexcept |
90 | : _Iter_base(__i) | |
91 | { _M_attach_single(__cont); } | |
92 | ||
8e6603f8 | 93 | public: |
b25436b0 | 94 | typedef _Iterator iterator_type; |
95 | typedef typename _Traits::iterator_category iterator_category; | |
96 | typedef typename _Traits::value_type value_type; | |
97 | typedef typename _Traits::difference_type difference_type; | |
98 | typedef typename _Traits::reference reference; | |
99 | typedef typename _Traits::pointer pointer; | |
8e6603f8 | 100 | |
101 | /// @post the iterator is singular and unattached | |
616eb317 | 102 | _Safe_local_iterator() noexcept : _Iter_base() { } |
8e6603f8 | 103 | |
104 | /** | |
105 | * @brief Safe iterator construction from an unsafe iterator and | |
106 | * its sequence. | |
107 | * | |
108 | * @pre @p seq is not NULL | |
109 | * @post this is not singular | |
110 | */ | |
319d9891 | 111 | _Safe_local_iterator(_Iterator __i, const _Safe_sequence_base* __cont) |
4a4fa71e | 112 | : _Iter_base(__i), _Safe_base(__cont, _S_constant()) |
8e6603f8 | 113 | { |
114 | _GLIBCXX_DEBUG_VERIFY(!this->_M_singular(), | |
115 | _M_message(__msg_init_singular) | |
116 | ._M_iterator(*this, "this")); | |
117 | } | |
118 | ||
119 | /** | |
120 | * @brief Copy construction. | |
121 | */ | |
616eb317 | 122 | _Safe_local_iterator(const _Safe_local_iterator& __x) noexcept |
123 | : _Iter_base(__x.base()) | |
8e6603f8 | 124 | { |
125 | // _GLIBCXX_RESOLVE_LIB_DEFECTS | |
126 | // DR 408. Is vector<reverse_iterator<char*> > forbidden? | |
127 | _GLIBCXX_DEBUG_VERIFY(!__x._M_singular() | |
7c9e9664 | 128 | || __x.base() == _Iterator(), |
8e6603f8 | 129 | _M_message(__msg_init_copy_singular) |
130 | ._M_iterator(*this, "this") | |
131 | ._M_iterator(__x, "other")); | |
616eb317 | 132 | _M_attach(__x._M_sequence); |
133 | } | |
134 | ||
135 | /** | |
136 | * @brief Move construction. | |
137 | * @post __x is singular and unattached | |
138 | */ | |
139 | _Safe_local_iterator(_Safe_local_iterator&& __x) noexcept | |
140 | : _Iter_base() | |
141 | { | |
142 | _GLIBCXX_DEBUG_VERIFY(!__x._M_singular() | |
143 | || __x.base() == _Iterator(), | |
144 | _M_message(__msg_init_copy_singular) | |
145 | ._M_iterator(*this, "this") | |
146 | ._M_iterator(__x, "other")); | |
147 | auto __cont = __x._M_sequence; | |
148 | __x._M_detach(); | |
149 | std::swap(base(), __x.base()); | |
150 | _M_attach(__cont); | |
8e6603f8 | 151 | } |
152 | ||
153 | /** | |
154 | * @brief Converting constructor from a mutable iterator to a | |
155 | * constant iterator. | |
156 | */ | |
157 | template<typename _MutableIterator> | |
158 | _Safe_local_iterator( | |
159 | const _Safe_local_iterator<_MutableIterator, | |
319d9891 | 160 | typename __gnu_cxx::__enable_if<_IsConstant::__value && |
161 | std::__are_same<_MutableIterator, _OtherIterator>::__value, | |
162 | _Sequence>::__type>& __x) noexcept | |
616eb317 | 163 | : _Iter_base(__x.base()) |
8e6603f8 | 164 | { |
165 | // _GLIBCXX_RESOLVE_LIB_DEFECTS | |
166 | // DR 408. Is vector<reverse_iterator<char*> > forbidden? | |
167 | _GLIBCXX_DEBUG_VERIFY(!__x._M_singular() | |
319d9891 | 168 | || __x.base() == _MutableIterator(), |
8e6603f8 | 169 | _M_message(__msg_init_const_singular) |
170 | ._M_iterator(*this, "this") | |
171 | ._M_iterator(__x, "other")); | |
616eb317 | 172 | _M_attach(__x._M_sequence); |
8e6603f8 | 173 | } |
174 | ||
175 | /** | |
176 | * @brief Copy assignment. | |
177 | */ | |
178 | _Safe_local_iterator& | |
179 | operator=(const _Safe_local_iterator& __x) | |
180 | { | |
181 | // _GLIBCXX_RESOLVE_LIB_DEFECTS | |
182 | // DR 408. Is vector<reverse_iterator<char*> > forbidden? | |
183 | _GLIBCXX_DEBUG_VERIFY(!__x._M_singular() | |
7c9e9664 | 184 | || __x.base() == _Iterator(), |
8e6603f8 | 185 | _M_message(__msg_copy_singular) |
186 | ._M_iterator(*this, "this") | |
187 | ._M_iterator(__x, "other")); | |
616eb317 | 188 | |
189 | if (this->_M_sequence && this->_M_sequence == __x._M_sequence) | |
190 | { | |
191 | __gnu_cxx::__scoped_lock __l(this->_M_get_mutex()); | |
192 | base() = __x.base(); | |
193 | _M_version = __x._M_sequence->_M_version; | |
194 | } | |
195 | else | |
196 | { | |
197 | _M_detach(); | |
198 | base() = __x.base(); | |
199 | _M_attach(__x._M_sequence); | |
200 | } | |
201 | ||
202 | return *this; | |
203 | } | |
204 | ||
205 | /** | |
206 | * @brief Move assignment. | |
207 | * @post __x is singular and unattached | |
208 | */ | |
209 | _Safe_local_iterator& | |
210 | operator=(_Safe_local_iterator&& __x) noexcept | |
211 | { | |
212 | _GLIBCXX_DEBUG_VERIFY(this != &__x, | |
213 | _M_message(__msg_self_move_assign) | |
214 | ._M_iterator(*this, "this")); | |
215 | _GLIBCXX_DEBUG_VERIFY(!__x._M_singular() | |
216 | || __x.base() == _Iterator(), | |
217 | _M_message(__msg_copy_singular) | |
218 | ._M_iterator(*this, "this") | |
219 | ._M_iterator(__x, "other")); | |
220 | ||
221 | if (this->_M_sequence && this->_M_sequence == __x._M_sequence) | |
222 | { | |
223 | __gnu_cxx::__scoped_lock __l(this->_M_get_mutex()); | |
224 | base() = __x.base(); | |
225 | _M_version = __x._M_sequence->_M_version; | |
226 | } | |
227 | else | |
228 | { | |
229 | _M_detach(); | |
230 | base() = __x.base(); | |
231 | _M_attach(__x._M_sequence); | |
232 | } | |
233 | ||
234 | __x._M_detach(); | |
235 | __x.base() = _Iterator(); | |
8e6603f8 | 236 | return *this; |
237 | } | |
238 | ||
239 | /** | |
240 | * @brief Iterator dereference. | |
241 | * @pre iterator is dereferenceable | |
242 | */ | |
243 | reference | |
244 | operator*() const | |
245 | { | |
246 | _GLIBCXX_DEBUG_VERIFY(this->_M_dereferenceable(), | |
247 | _M_message(__msg_bad_deref) | |
248 | ._M_iterator(*this, "this")); | |
616eb317 | 249 | return *base(); |
8e6603f8 | 250 | } |
251 | ||
252 | /** | |
253 | * @brief Iterator dereference. | |
254 | * @pre iterator is dereferenceable | |
8e6603f8 | 255 | */ |
256 | pointer | |
257 | operator->() const | |
258 | { | |
259 | _GLIBCXX_DEBUG_VERIFY(this->_M_dereferenceable(), | |
260 | _M_message(__msg_bad_deref) | |
261 | ._M_iterator(*this, "this")); | |
005248bc | 262 | return base().operator->(); |
8e6603f8 | 263 | } |
264 | ||
265 | // ------ Input iterator requirements ------ | |
266 | /** | |
267 | * @brief Iterator preincrement | |
268 | * @pre iterator is incrementable | |
269 | */ | |
270 | _Safe_local_iterator& | |
271 | operator++() | |
272 | { | |
273 | _GLIBCXX_DEBUG_VERIFY(this->_M_incrementable(), | |
274 | _M_message(__msg_bad_inc) | |
275 | ._M_iterator(*this, "this")); | |
616eb317 | 276 | __gnu_cxx::__scoped_lock __l(this->_M_get_mutex()); |
277 | ++base(); | |
8e6603f8 | 278 | return *this; |
279 | } | |
280 | ||
281 | /** | |
282 | * @brief Iterator postincrement | |
283 | * @pre iterator is incrementable | |
284 | */ | |
285 | _Safe_local_iterator | |
286 | operator++(int) | |
287 | { | |
288 | _GLIBCXX_DEBUG_VERIFY(this->_M_incrementable(), | |
289 | _M_message(__msg_bad_inc) | |
290 | ._M_iterator(*this, "this")); | |
616eb317 | 291 | __gnu_cxx::__scoped_lock __l(this->_M_get_mutex()); |
292 | return _Safe_local_iterator(base()++, this->_M_sequence, | |
293 | _Attach_single()); | |
8e6603f8 | 294 | } |
295 | ||
296 | // ------ Utilities ------ | |
4a4fa71e | 297 | |
298 | /// Determine if this is a constant iterator. | |
319d9891 | 299 | static constexpr bool |
4a4fa71e | 300 | _S_constant() |
319d9891 | 301 | { return _IsConstant::__value; } |
4a4fa71e | 302 | |
8e6603f8 | 303 | /** |
304 | * @brief Return the underlying iterator | |
305 | */ | |
616eb317 | 306 | _Iterator& |
307 | base() noexcept { return *this; } | |
308 | ||
309 | const _Iterator& | |
310 | base() const noexcept { return *this; } | |
8e6603f8 | 311 | |
312 | /** | |
313 | * @brief Return the bucket | |
314 | */ | |
315 | size_type | |
616eb317 | 316 | bucket() const { return base()._M_get_bucket(); } |
8e6603f8 | 317 | |
318 | /** | |
319 | * @brief Conversion to underlying non-debug iterator to allow | |
320 | * better interaction with non-debug containers. | |
321 | */ | |
616eb317 | 322 | operator _Iterator() const { return *this; } |
8e6603f8 | 323 | |
324 | /** Attach iterator to the given sequence. */ | |
325 | void | |
326 | _M_attach(_Safe_sequence_base* __seq) | |
4a4fa71e | 327 | { _Safe_base::_M_attach(__seq, _S_constant()); } |
8e6603f8 | 328 | |
329 | /** Likewise, but not thread-safe. */ | |
330 | void | |
331 | _M_attach_single(_Safe_sequence_base* __seq) | |
4a4fa71e | 332 | { _Safe_base::_M_attach_single(__seq, _S_constant()); } |
8e6603f8 | 333 | |
334 | /// Is the iterator dereferenceable? | |
335 | bool | |
336 | _M_dereferenceable() const | |
337 | { return !this->_M_singular() && !_M_is_end(); } | |
338 | ||
339 | /// Is the iterator incrementable? | |
340 | bool | |
341 | _M_incrementable() const | |
342 | { return !this->_M_singular() && !_M_is_end(); } | |
343 | ||
344 | // Is the iterator range [*this, __rhs) valid? | |
3188147e | 345 | bool |
d9ba0dd6 | 346 | _M_valid_range(const _Safe_local_iterator& __rhs, |
347 | std::pair<difference_type, | |
348 | _Distance_precision>& __dist_info) const; | |
8e6603f8 | 349 | |
319d9891 | 350 | // Get distance to __rhs. |
351 | typename _Distance_traits<_Iterator>::__type | |
352 | _M_get_distance_to(const _Safe_local_iterator& __rhs) const; | |
353 | ||
8e6603f8 | 354 | // The sequence this iterator references. |
319d9891 | 355 | typename __gnu_cxx::__conditional_type< |
356 | _IsConstant::__value, const _Sequence*, _Sequence*>::__type | |
8e6603f8 | 357 | _M_get_sequence() const |
3188147e | 358 | { return static_cast<_Sequence*>(_M_sequence); } |
8e6603f8 | 359 | |
7c9e9664 | 360 | /// Is this iterator equal to the sequence's begin(bucket) iterator? |
8e6603f8 | 361 | bool _M_is_begin() const |
7c9e9664 | 362 | { return base() == _M_get_sequence()->_M_base().begin(bucket()); } |
8e6603f8 | 363 | |
7c9e9664 | 364 | /// Is this iterator equal to the sequence's end(bucket) iterator? |
8e6603f8 | 365 | bool _M_is_end() const |
7c9e9664 | 366 | { return base() == _M_get_sequence()->_M_base().end(bucket()); } |
8e6603f8 | 367 | |
368 | /// Is this iterator part of the same bucket as the other one? | |
7c9e9664 | 369 | template<typename _Other> |
370 | bool | |
371 | _M_in_same_bucket(const _Safe_local_iterator<_Other, | |
372 | _Sequence>& __other) const | |
373 | { return bucket() == __other.bucket(); } | |
8e6603f8 | 374 | |
9fe2a042 | 375 | friend inline bool |
376 | operator==(const _Self& __lhs, const _OtherSelf& __rhs) noexcept | |
377 | { | |
378 | _GLIBCXX_DEBUG_VERIFY_OPERANDS(__lhs, __rhs); | |
379 | return __lhs.base() == __rhs.base(); | |
380 | } | |
8e6603f8 | 381 | |
9fe2a042 | 382 | friend inline bool |
383 | operator==(const _Self& __lhs, const _Self& __rhs) noexcept | |
384 | { | |
385 | _GLIBCXX_DEBUG_VERIFY_OPERANDS(__lhs, __rhs); | |
386 | return __lhs.base() == __rhs.base(); | |
387 | } | |
8e6603f8 | 388 | |
9fe2a042 | 389 | friend inline bool |
390 | operator!=(const _Self& __lhs, const _OtherSelf& __rhs) noexcept | |
391 | { | |
392 | _GLIBCXX_DEBUG_VERIFY_OPERANDS(__lhs, __rhs); | |
393 | return __lhs.base() != __rhs.base(); | |
394 | } | |
8e6603f8 | 395 | |
9fe2a042 | 396 | friend inline bool |
397 | operator!=(const _Self& __lhs, const _Self& __rhs) noexcept | |
398 | { | |
399 | _GLIBCXX_DEBUG_VERIFY_OPERANDS(__lhs, __rhs); | |
400 | return __lhs.base() != __rhs.base(); | |
401 | } | |
402 | }; | |
e009b1d8 | 403 | |
e009b1d8 | 404 | /** Safe local iterators know how to check if they form a valid range. */ |
405 | template<typename _Iterator, typename _Sequence> | |
406 | inline bool | |
407 | __valid_range(const _Safe_local_iterator<_Iterator, _Sequence>& __first, | |
d9ba0dd6 | 408 | const _Safe_local_iterator<_Iterator, _Sequence>& __last, |
409 | typename _Distance_traits<_Iterator>::__type& __dist_info) | |
410 | { return __first._M_valid_range(__last, __dist_info); } | |
411 | ||
d9ba0dd6 | 412 | template<typename _Iterator, typename _Sequence> |
319d9891 | 413 | inline bool |
414 | __valid_range(const _Safe_local_iterator<_Iterator, _Sequence>& __first, | |
415 | const _Safe_local_iterator<_Iterator, _Sequence>& __last) | |
d9ba0dd6 | 416 | { |
319d9891 | 417 | typename _Distance_traits<_Iterator>::__type __dist_info; |
418 | return __first._M_valid_range(__last, __dist_info); | |
d9ba0dd6 | 419 | } |
420 | ||
421 | #if __cplusplus < 201103L | |
422 | template<typename _Iterator, typename _Sequence> | |
423 | struct _Unsafe_type<_Safe_local_iterator<_Iterator, _Sequence> > | |
424 | { typedef _Iterator _Type; }; | |
425 | #endif | |
426 | ||
427 | template<typename _Iterator, typename _Sequence> | |
428 | inline _Iterator | |
429 | __unsafe(const _Safe_local_iterator<_Iterator, _Sequence>& __it) | |
430 | { return __it.base(); } | |
431 | ||
8e6603f8 | 432 | } // namespace __gnu_debug |
433 | ||
9fe2a042 | 434 | #undef _GLIBCXX_DEBUG_VERIFY_OPERANDS |
435 | ||
8e6603f8 | 436 | #include <debug/safe_local_iterator.tcc> |
437 | ||
438 | #endif |