xref: /netbsd-src/external/gpl3/gcc/dist/libstdc++-v3/include/debug/safe_iterator.tcc (revision 82d56013d7b633d116a93943de88e08335357a7c)
1 // Debugging iterator implementation (out of line) -*- C++ -*-
2 
3 // Copyright (C) 2003-2020 Free Software Foundation, Inc.
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_iterator.tcc
26  *  This file is a GNU debug extension to the Standard C++ Library.
27  */
28 
29 #ifndef _GLIBCXX_DEBUG_SAFE_ITERATOR_TCC
30 #define _GLIBCXX_DEBUG_SAFE_ITERATOR_TCC 1
31 
32 #include <bits/stl_algobase.h>
33 
34 namespace __gnu_debug
35 {
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>
85     bool
86     _Safe_iterator<_Iterator, _Sequence, _Category>::
87     _M_can_advance(difference_type __n, bool __strict) const
88     {
89       if (this->_M_singular())
90 	return false;
91 
92       if (__n == 0)
93 	return true;
94 
95       if (__n < 0)
96 	{
97 	  std::pair<difference_type, _Distance_precision> __dist =
98 	    _M_get_distance_from_begin();
99 	  return __dist.second == __dp_exact
100 	    ? __dist.first >= -__n
101 	    : !__strict && __dist.first > 0;
102 	}
103       else
104 	{
105 	  std::pair<difference_type, _Distance_precision> __dist =
106 	    _M_get_distance_to_end();
107 	  return __dist.second == __dp_exact
108 	    ? __dist.first >= __n
109 	    : !__strict && __dist.first > 0;
110 	}
111     }
112 
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     {
118       typedef typename _Distance_traits<_Iterator>::__type _Dist;
119       typedef _Sequence_traits<_Sequence> _SeqTraits;
120 
121       _Dist __base_dist = __get_distance(this->base(), __rhs.base());
122       if (__base_dist.second == __dp_exact)
123 	return __base_dist;
124 
125       _Dist __seq_dist = _SeqTraits::_S_size(*this->_M_get_sequence());
126       if (this->_M_is_before_begin())
127 	{
128 	  if (__rhs._M_is_begin())
129 	    return std::make_pair(1, __dp_exact);
130 
131 	  return __seq_dist.second == __dp_exact
132 	    ? std::make_pair(__seq_dist.first + 1, __dp_exact)
133 	    : __seq_dist;
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())
142 	    return __seq_dist;
143 
144 	  return std::make_pair(__seq_dist.first,
145 				__seq_dist.second == __dp_exact
146 				? __dp_sign_max_size : __seq_dist.second);
147 	}
148 
149       if (this->_M_is_end())
150 	{
151 	  if (__rhs._M_is_before_begin())
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);
155 
156 	  if (__rhs._M_is_begin())
157 	    return std::make_pair(-__seq_dist.first, __seq_dist.second);
158 
159 	  return std::make_pair(-__seq_dist.first,
160 				__seq_dist.second == __dp_exact
161 				? __dp_sign_max_size : __seq_dist.second);
162 	}
163 
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);
173 
174       if (__rhs._M_is_end())
175 	return std::make_pair(__seq_dist.first,
176 			      __seq_dist.second == __dp_exact
177 			      ? __dp_sign_max_size : __seq_dist.second);
178 
179       return std::make_pair(1, __dp_equality);
180     }
181 
182   template<typename _Iterator, typename _Sequence, typename _Category>
183     bool
184     _Safe_iterator<_Iterator, _Sequence, _Category>::
185     _M_valid_range(const _Safe_iterator& __rhs,
186 		   std::pair<difference_type, _Distance_precision>& __dist,
187 		   bool __check_dereferenceable) const
188     {
189       if (!_M_can_compare(__rhs))
190 	return false;
191 
192       /* Determine iterators order */
193       __dist = _M_get_distance_to(__rhs);
194       switch (__dist.second)
195 	{
196 	case __dp_equality:
197 	  if (__dist.first == 0)
198 	    return true;
199 	  break;
200 
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 	}
208 
209       // Assume that this is a valid range; we can't check anything else.
210       return true;
211     }
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     }
231 } // namespace __gnu_debug
232 
233 namespace 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 
470 #endif
471