]>
Commit | Line | Data |
---|---|---|
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 |
34 | namespace __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 |
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 | ||
526da49c | 470 | #endif |