]> git.ipfire.org Git - thirdparty/gcc.git/blame - libstdc++-v3/include/debug/safe_iterator.tcc
libstdc++: Rework std::copy/copy_backward/move/move_backward/fill/fill_n algos
[thirdparty/gcc.git] / libstdc++-v3 / include / debug / safe_iterator.tcc
CommitLineData
285b36d6
BK
1// Debugging iterator implementation (out of line) -*- C++ -*-
2
a5544970 3// Copyright (C) 2003-2019 Free Software Foundation, Inc.
285b36d6
BK
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
748086b7 8// Free Software Foundation; either version 3, or (at your option)
285b36d6
BK
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
748086b7
JJ
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.
285b36d6 19
748086b7
JJ
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/>.
285b36d6 24
78a53887
BK
25/** @file debug/safe_iterator.tcc
26 * This file is a GNU debug extension to the Standard C++ Library.
285b36d6
BK
27 */
28
29#ifndef _GLIBCXX_DEBUG_SAFE_ITERATOR_TCC
30#define _GLIBCXX_DEBUG_SAFE_ITERATOR_TCC 1
31
6004c17b
FD
32#include <bits/stl_algobase.h>
33
285b36d6
BK
34namespace __gnu_debug
35{
e9afbed0
FD
36 template<typename _Iterator, typename _Sequence, typename _Category>
37 typename _Distance_traits<_Iterator>::__type
38 _Safe_iterator<_Iterator, _Sequence, _Category>::
39 _M_get_distance_from_begin() const
40 {
41 typedef _Sequence_traits<_Sequence> _SeqTraits;
42
43 // No need to consider before_begin as this function is only used in
44 // _M_can_advance which won't be used for forward_list iterators.
45 if (_M_is_begin())
46 return std::make_pair(0, __dp_exact);
47
48 if (_M_is_end())
49 return _SeqTraits::_S_size(*_M_get_sequence());
50
51 typename _Distance_traits<_Iterator>::__type __res
52 = __get_distance(_M_get_sequence()->_M_base().begin(), base());
53
54 if (__res.second == __dp_equality)
55 return std::make_pair(1, __dp_sign);
56
57 return __res;
58 }
59
60 template<typename _Iterator, typename _Sequence, typename _Category>
61 typename _Distance_traits<_Iterator>::__type
62 _Safe_iterator<_Iterator, _Sequence, _Category>::
63 _M_get_distance_to_end() const
64 {
65 typedef _Sequence_traits<_Sequence> _SeqTraits;
66
67 // No need to consider before_begin as this function is only used in
68 // _M_can_advance which won't be used for forward_list iterators.
69 if (_M_is_begin())
70 return _SeqTraits::_S_size(*_M_get_sequence());
71
72 if (_M_is_end())
73 return std::make_pair(0, __dp_exact);
74
75 typename _Distance_traits<_Iterator>::__type __res
76 = __get_distance(base(), _M_get_sequence()->_M_base().end());
77
78 if (__res.second == __dp_equality)
79 return std::make_pair(1, __dp_sign);
80
81 return __res;
82 }
83
84 template<typename _Iterator, typename _Sequence, typename _Category>
526da49c 85 bool
e9afbed0 86 _Safe_iterator<_Iterator, _Sequence, _Category>::
6004c17b 87 _M_can_advance(difference_type __n, bool __strict) const
285b36d6 88 {
285b36d6
BK
89 if (this->_M_singular())
90 return false;
24167c42 91
285b36d6
BK
92 if (__n == 0)
93 return true;
24167c42 94
526da49c 95 if (__n < 0)
285b36d6 96 {
45f388bb 97 std::pair<difference_type, _Distance_precision> __dist =
e9afbed0 98 _M_get_distance_from_begin();
6004c17b
FD
99 return __dist.second == __dp_exact
100 ? __dist.first >= -__n
101 : !__strict && __dist.first > 0;
285b36d6
BK
102 }
103 else
104 {
45f388bb 105 std::pair<difference_type, _Distance_precision> __dist =
e9afbed0 106 _M_get_distance_to_end();
6004c17b
FD
107 return __dist.second == __dp_exact
108 ? __dist.first >= __n
109 : !__strict && __dist.first > 0;
285b36d6
BK
110 }
111 }
526da49c 112
e9afbed0
FD
113 template<typename _Iterator, typename _Sequence, typename _Category>
114 typename _Distance_traits<_Iterator>::__type
115 _Safe_iterator<_Iterator, _Sequence, _Category>::
116 _M_get_distance_to(const _Safe_iterator& __rhs) const
117 {
36edf9ca 118 typedef typename _Distance_traits<_Iterator>::__type _Dist;
e9afbed0
FD
119 typedef _Sequence_traits<_Sequence> _SeqTraits;
120
36edf9ca
FD
121 _Dist __base_dist = __get_distance(this->base(), __rhs.base());
122 if (__base_dist.second == __dp_exact)
123 return __base_dist;
e9afbed0 124
36edf9ca 125 _Dist __seq_dist = _SeqTraits::_S_size(*this->_M_get_sequence());
e9afbed0
FD
126 if (this->_M_is_before_begin())
127 {
128 if (__rhs._M_is_begin())
129 return std::make_pair(1, __dp_exact);
130
36edf9ca
FD
131 return __seq_dist.second == __dp_exact
132 ? std::make_pair(__seq_dist.first + 1, __dp_exact)
133 : __seq_dist;
e9afbed0
FD
134 }
135
136 if (this->_M_is_begin())
137 {
138 if (__rhs._M_is_before_begin())
139 return std::make_pair(-1, __dp_exact);
140
141 if (__rhs._M_is_end())
36edf9ca 142 return __seq_dist;
e9afbed0 143
36edf9ca
FD
144 return std::make_pair(__seq_dist.first,
145 __seq_dist.second == __dp_exact
146 ? __dp_sign_max_size : __seq_dist.second);
e9afbed0
FD
147 }
148
149 if (this->_M_is_end())
150 {
151 if (__rhs._M_is_before_begin())
36edf9ca
FD
152 return __seq_dist.second == __dp_exact
153 ? std::make_pair(-__seq_dist.first - 1, __dp_exact)
154 : std::make_pair(-__seq_dist.first, __dp_sign);
e9afbed0
FD
155
156 if (__rhs._M_is_begin())
36edf9ca 157 return std::make_pair(-__seq_dist.first, __seq_dist.second);
e9afbed0 158
36edf9ca
FD
159 return std::make_pair(-__seq_dist.first,
160 __seq_dist.second == __dp_exact
161 ? __dp_sign_max_size : __seq_dist.second);
e9afbed0
FD
162 }
163
36edf9ca
FD
164 if (__rhs._M_is_before_begin())
165 return __seq_dist.second == __dp_exact
166 ? std::make_pair(__seq_dist.first - 1, __dp_exact)
167 : std::make_pair(-__seq_dist.first, __dp_sign);
168
169 if (__rhs._M_is_begin())
170 return std::make_pair(-__seq_dist.first,
171 __seq_dist.second == __dp_exact
172 ? __dp_sign_max_size : __seq_dist.second);
e9afbed0
FD
173
174 if (__rhs._M_is_end())
36edf9ca
FD
175 return std::make_pair(__seq_dist.first,
176 __seq_dist.second == __dp_exact
177 ? __dp_sign_max_size : __seq_dist.second);
e9afbed0
FD
178
179 return std::make_pair(1, __dp_equality);
180 }
181
182 template<typename _Iterator, typename _Sequence, typename _Category>
9fc0e24b 183 bool
e9afbed0 184 _Safe_iterator<_Iterator, _Sequence, _Category>::
24167c42
FD
185 _M_valid_range(const _Safe_iterator& __rhs,
186 std::pair<difference_type, _Distance_precision>& __dist,
187 bool __check_dereferenceable) const
9fc0e24b
FD
188 {
189 if (!_M_can_compare(__rhs))
190 return false;
526da49c 191
24167c42 192 /* Determine iterators order */
e9afbed0 193 __dist = _M_get_distance_to(__rhs);
24167c42
FD
194 switch (__dist.second)
195 {
196 case __dp_equality:
197 if (__dist.first == 0)
198 return true;
199 break;
9fc0e24b 200
24167c42
FD
201 case __dp_sign:
202 case __dp_exact:
203 // If range is not empty first iterator must be dereferenceable.
204 if (__dist.first > 0)
205 return !__check_dereferenceable || _M_dereferenceable();
206 return __dist.first == 0;
207 }
9fc0e24b 208
24167c42 209 // Assume that this is a valid range; we can't check anything else.
9fc0e24b
FD
210 return true;
211 }
e9afbed0
FD
212
213 template<typename _Iterator, typename _Sequence>
214 bool
215 _Safe_iterator<_Iterator, _Sequence, std::random_access_iterator_tag>::
216 _M_valid_range(const _Safe_iterator& __rhs,
217 std::pair<difference_type,
218 _Distance_precision>& __dist) const
219 {
220 if (!this->_M_can_compare(__rhs))
221 return false;
222
223 /* Determine iterators order */
224 __dist = std::make_pair(__rhs.base() - this->base(), __dp_exact);
225
226 // If range is not empty first iterator must be dereferenceable.
227 if (__dist.first > 0)
228 return this->_M_dereferenceable();
229 return __dist.first == 0;
230 }
285b36d6
BK
231} // namespace __gnu_debug
232
6004c17b
FD
233namespace std _GLIBCXX_VISIBILITY(default)
234{
235_GLIBCXX_BEGIN_NAMESPACE_VERSION
236
237 template<bool _IsMove,
238 typename _Ite, typename _Seq, typename _Cat, typename _OI>
239 _OI
240 __copy_move_a(
241 const ::__gnu_debug::_Safe_iterator<_Ite, _Seq, _Cat>& __first,
242 const ::__gnu_debug::_Safe_iterator<_Ite, _Seq, _Cat>& __last,
243 _OI __result)
244 {
245 typename ::__gnu_debug::_Distance_traits<_Ite>::__type __dist;
246 __glibcxx_check_valid_range2(__first, __last, __dist);
247 __glibcxx_check_can_increment(__result, __dist.first);
248
249 if (__dist.second > ::__gnu_debug::__dp_equality)
250 return std::__copy_move_a<_IsMove>(__first.base(), __last.base(),
251 __result);
252
253 return std::__copy_move_a1<_IsMove>(__first, __last, __result);
254 }
255
256 template<bool _IsMove,
257 typename _II, typename _Ite, typename _Seq, typename _Cat>
258 __gnu_debug::_Safe_iterator<_Ite, _Seq, _Cat>
259 __copy_move_a(_II __first, _II __last,
260 const ::__gnu_debug::_Safe_iterator<_Ite, _Seq, _Cat>& __result)
261 {
262 typename ::__gnu_debug::_Distance_traits<_II>::__type __dist;
263 __glibcxx_check_valid_range2(__first, __last, __dist);
264 __glibcxx_check_can_increment(__result, __dist.first);
265
266 if (__dist.second > ::__gnu_debug::__dp_sign
267 && __result._M_can_advance(__dist.first, true))
268 return ::__gnu_debug::_Safe_iterator<_Ite, _Seq, _Cat>(
269 std::__copy_move_a<_IsMove>(__first, __last, __result.base()),
270 __result._M_sequence);
271
272 return std::__copy_move_a1<_IsMove>(__first, __last, __result);
273 }
274
275 template<bool _IsMove,
276 typename _IIte, typename _ISeq, typename _ICat,
277 typename _OIte, typename _OSeq, typename _OCat>
278 ::__gnu_debug::_Safe_iterator<_OIte, _OSeq, _OCat>
279 __copy_move_a(
280 const ::__gnu_debug::_Safe_iterator<_IIte, _ISeq, _ICat>& __first,
281 const ::__gnu_debug::_Safe_iterator<_IIte, _ISeq, _ICat>& __last,
282 const ::__gnu_debug::_Safe_iterator<_OIte, _OSeq, _OCat>& __result)
283 {
284 typename ::__gnu_debug::_Distance_traits<_IIte>::__type __dist;
285 __glibcxx_check_valid_range2(__first, __last, __dist);
286 __glibcxx_check_can_increment(__result, __dist.first);
287
288 if (__dist.second > ::__gnu_debug::__dp_equality)
289 {
290 if (__dist.second > ::__gnu_debug::__dp_sign
291 && __result._M_can_advance(__dist.first, true))
292 return ::__gnu_debug::_Safe_iterator<_OIte, _OSeq, _OCat>(
293 std::__copy_move_a<_IsMove>(__first.base(), __last.base(),
294 __result.base()),
295 __result._M_sequence);
296
297 return std::__copy_move_a<_IsMove>(__first.base(), __last.base(),
298 __result);
299 }
300
301 return std::__copy_move_a1<_IsMove>(__first, __last, __result);
302 }
303
304 template<bool _IsMove,
305 typename _Ite, typename _Seq, typename _Cat, typename _OI>
306 _OI
307 __copy_move_backward_a(
308 const ::__gnu_debug::_Safe_iterator<_Ite, _Seq, _Cat>& __first,
309 const ::__gnu_debug::_Safe_iterator<_Ite, _Seq, _Cat>& __last,
310 _OI __result)
311 {
312 typename ::__gnu_debug::_Distance_traits<_Ite>::__type __dist;
313 __glibcxx_check_valid_range2(__first, __last, __dist);
314 __glibcxx_check_can_increment(__result, -__dist.first);
315
316 if (__dist.second > ::__gnu_debug::__dp_equality)
317 return std::__copy_move_backward_a<_IsMove>(
318 __first.base(), __last.base(), __result);
319
320 return std::__copy_move_backward_a1<_IsMove>(__first, __last, __result);
321 }
322
323 template<bool _IsMove,
324 typename _II, typename _Ite, typename _Seq, typename _Cat>
325 __gnu_debug::_Safe_iterator<_Ite, _Seq, _Cat>
326 __copy_move_backward_a(_II __first, _II __last,
327 const ::__gnu_debug::_Safe_iterator<_Ite, _Seq, _Cat>& __result)
328 {
329 typename ::__gnu_debug::_Distance_traits<_II>::__type __dist;
330 __glibcxx_check_valid_range2(__first, __last, __dist);
331 __glibcxx_check_can_increment(__result, -__dist.first);
332
333 if (__dist.second > ::__gnu_debug::__dp_sign
334 && __result._M_can_advance(-__dist.first, true))
335 return ::__gnu_debug::_Safe_iterator<_Ite, _Seq, _Cat>(
336 std::__copy_move_backward_a<_IsMove>(__first, __last,
337 __result.base()),
338 __result._M_sequence);
339
340 return std::__copy_move_backward_a1<_IsMove>(__first, __last, __result);
341 }
342
343 template<bool _IsMove,
344 typename _IIte, typename _ISeq, typename _ICat,
345 typename _OIte, typename _OSeq, typename _OCat>
346 ::__gnu_debug::_Safe_iterator<_OIte, _OSeq, _OCat>
347 __copy_move_backward_a(
348 const ::__gnu_debug::_Safe_iterator<_IIte, _ISeq, _ICat>& __first,
349 const ::__gnu_debug::_Safe_iterator<_IIte, _ISeq, _ICat>& __last,
350 const ::__gnu_debug::_Safe_iterator<_OIte, _OSeq, _OCat>& __result)
351 {
352 typename ::__gnu_debug::_Distance_traits<_IIte>::__type __dist;
353 __glibcxx_check_valid_range2(__first, __last, __dist);
354 __glibcxx_check_can_increment(__result, -__dist.first);
355
356 if (__dist.second > ::__gnu_debug::__dp_equality)
357 {
358 if (__dist.second > ::__gnu_debug::__dp_sign
359 && __result._M_can_advance(-__dist.first, true))
360 return ::__gnu_debug::_Safe_iterator<_OIte, _OSeq, _OCat>(
361 std::__copy_move_backward_a<_IsMove>(__first.base(), __last.base(),
362 __result.base()),
363 __result._M_sequence);
364
365 return std::__copy_move_backward_a<_IsMove>(
366 __first.base(), __last.base(), __result);
367 }
368
369 return std::__copy_move_backward_a1<_IsMove>(__first, __last, __result);
370 }
371
372 template<typename _Ite, typename _Seq, typename _Cat, typename _Tp>
373 void
374 __fill_a(const ::__gnu_debug::_Safe_iterator<_Ite, _Seq, _Cat>& __first,
375 const ::__gnu_debug::_Safe_iterator<_Ite, _Seq, _Cat>& __last,
376 const _Tp& __value)
377 {
378 typename ::__gnu_debug::_Distance_traits<_Ite>::__type __dist;
379 __glibcxx_check_valid_range2(__first, __last, __dist);
380
381 if (__dist.second > ::__gnu_debug::__dp_equality)
382 std::__fill_a(__first.base(), __last.base(), __value);
383
384 std::__fill_a1(__first, __last, __value);
385 }
386
387 template<typename _Ite, typename _Seq, typename _Cat, typename _Size,
388 typename _Tp>
389 ::__gnu_debug::_Safe_iterator<_Ite, _Seq, _Cat>
390 __fill_n_a(const ::__gnu_debug::_Safe_iterator<_Ite, _Seq, _Cat>& __first,
391 _Size __n, const _Tp& __value,
392 std::input_iterator_tag)
393 {
394#if __cplusplus >= 201103L
395 static_assert(is_integral<_Size>{}, "fill_n must pass integral size");
396#endif
397
398 if (__n <= 0)
399 return __first;
400
401 __glibcxx_check_can_increment(__first, __n);
402 if (__first._M_can_advance(__n, true))
403 return ::__gnu_debug::_Safe_iterator<_Ite, _Seq, _Cat>(
404 std::__fill_n_a(__first.base(), __n, __value, _Cat()),
405 __first._M_sequence);
406
407 return std::__fill_n_a1(__first, __n, __value);
408 }
409
410 template<typename _II1, typename _Seq1, typename _Cat1, typename _II2>
411 bool
412 __equal_aux(
413 const ::__gnu_debug::_Safe_iterator<_II1, _Seq1, _Cat1>& __first1,
414 const ::__gnu_debug::_Safe_iterator<_II1, _Seq1, _Cat1>& __last1,
415 _II2 __first2)
416 {
417 typename ::__gnu_debug::_Distance_traits<_II1>::__type __dist;
418 __glibcxx_check_valid_range2(__first1, __last1, __dist);
419 __glibcxx_check_can_increment(__first2, __dist.first);
420
421 if (__dist.second > ::__gnu_debug::__dp_equality)
422 return std::__equal_aux(__first1.base(), __last1.base(), __first2);
423
424 return std::__equal_aux1(__first1, __last1, __first2);
425 }
426
427 template<typename _II1, typename _II2, typename _Seq2, typename _Cat2>
428 bool
429 __equal_aux(_II1 __first1, _II1 __last1,
430 const ::__gnu_debug::_Safe_iterator<_II2, _Seq2, _Cat2>& __first2)
431 {
432 typename ::__gnu_debug::_Distance_traits<_II1>::__type __dist;
433 __glibcxx_check_valid_range2(__first1, __last1, __dist);
434 __glibcxx_check_can_increment(__first2, __dist.first);
435
436 if (__dist.second > ::__gnu_debug::__dp_sign
437 && __first2._M_can_advance(__dist.first, true))
438 return std::__equal_aux(__first1, __last1, __first2.base());
439
440 return std::__equal_aux1(__first1, __last1, __first2);
441 }
442
443 template<typename _II1, typename _Seq1, typename _Cat1,
444 typename _II2, typename _Seq2, typename _Cat2>
445 bool
446 __equal_aux(
447 const ::__gnu_debug::_Safe_iterator<_II1, _Seq1, _Cat1>& __first1,
448 const ::__gnu_debug::_Safe_iterator<_II1, _Seq1, _Cat1>& __last1,
449 const ::__gnu_debug::_Safe_iterator<_II2, _Seq2, _Cat2>& __first2)
450 {
451 typename ::__gnu_debug::_Distance_traits<_II1>::__type __dist;
452 __glibcxx_check_valid_range2(__first1, __last1, __dist);
453 __glibcxx_check_can_increment(__first2, __dist.first);
454
455 if (__dist.second > ::__gnu_debug::__dp_equality)
456 {
457 if (__dist.second > ::__gnu_debug::__dp_sign &&
458 __first2._M_can_advance(__dist.first, true))
459 return std::__equal_aux(__first1.base(), __last1.base(),
460 __first2.base());
461 return std::__equal_aux(__first1.base(), __last1.base(), __first2);
462 }
463
464 return __equal_aux1(__first1, __last1, __first2);
465 }
466
467_GLIBCXX_END_NAMESPACE_VERSION
468} // namespace std
469
526da49c 470#endif