@@ -1666,68 +1666,72 @@ namespace ranges
auto __k = __middle - __first;
if (__k == __n - __k)
{
ranges::swap_ranges(__first, __middle, __middle, __middle + __k);
return {std::move(__middle), std::move(__lasti)};
}
auto __p = __first;
auto __ret = __first + (__lasti - __middle);
for (;;)
{
if (__k < __n - __k)
{
// TODO: is_pod is deprecated, but this condition is
// consistent with the STL implementation.
if constexpr (__is_pod(iter_value_t<_Iter>))
if (__k == 1)
{
+ auto __mid = ranges::next(__p, __n - 1);
+ auto __end = ranges::next(__mid);
auto __t = std::move(*__p);
- ranges::move(__p + 1, __p + __n, __p);
- *(__p + __n - 1) = std::move(__t);
+ ranges::move(ranges::next(__p), __end, __p);
+ *__mid = std::move(__t);
return {std::move(__ret), std::move(__lasti)};
}
auto __q = __p + __k;
for (decltype(__n) __i = 0; __i < __n - __k; ++ __i)
{
ranges::iter_swap(__p, __q);
++__p;
++__q;
}
__n %= __k;
if (__n == 0)
return {std::move(__ret), std::move(__lasti)};
ranges::swap(__n, __k);
__k = __n - __k;
}
else
{
__k = __n - __k;
// TODO: is_pod is deprecated, but this condition is
// consistent with the STL implementation.
if constexpr (__is_pod(iter_value_t<_Iter>))
if (__k == 1)
{
- auto __t = std::move(*(__p + __n - 1));
- ranges::move_backward(__p, __p + __n - 1, __p + __n);
+ auto __mid = ranges::next(__p, __n - 1);
+ auto __end = ranges::next(__mid);
+ auto __t = std::move(*__mid);
+ ranges::move_backward(__p, __mid, __end);
*__p = std::move(__t);
return {std::move(__ret), std::move(__lasti)};
}
auto __q = __p + __n;
__p = __q - __k;
for (decltype(__n) __i = 0; __i < __n - __k; ++ __i)
{
--__p;
--__q;
ranges::iter_swap(__p, __q);
}
__n %= __k;
if (__n == 0)
return {std::move(__ret), std::move(__lasti)};
std::swap(__n, __k);
}
}
}
else if constexpr (bidirectional_iterator<_Iter>)
{
@@ -1953,75 +1957,77 @@ namespace ranges
operator()(_Iter __first, _Sent __last, _Gen&& __g) const
{
// FIXME: Correctly handle integer-class difference types.
if (__first == __last)
return __first;
using _DistanceType = iter_difference_t<_Iter>;
using __ud_type = __detail::__make_unsigned_like_t<_DistanceType>;
using __distr_type = std::uniform_int_distribution<__ud_type>;
using __p_type = typename __distr_type::param_type;
using __uc_type
= common_type_t<typename remove_reference_t<_Gen>::result_type, __ud_type>;
const __uc_type __urngrange = __g.max() - __g.min();
const __uc_type __urange = __uc_type(__last - __first);
if (__urngrange / __urange >= __urange)
// I.e. (__urngrange >= __urange * __urange) but without wrap issues.
{
- _Iter __i = __first + 1;
+ _Iter __i = ranges::next(__first);
// Since we know the range isn't empty, an even number of elements
// means an uneven number of elements /to swap/, in which case we
// do the first one up front:
if ((__urange % 2) == 0)
{
__distr_type __d{0, 1};
- ranges::iter_swap(__i++, __first + __d(__g));
+ ranges::iter_swap(__i++, ranges::next(__first, __d(__g)));
}
// Now we know that __last - __i is even, so we do the rest in pairs,
// using a single distribution invocation to produce swap positions
// for two successive elements at a time:
while (__i != __last)
{
const __uc_type __swap_range = __uc_type(__i - __first) + 1;
- const pair<__uc_type, __uc_type> __pospos =
+ const pair<_DistanceType, _DistanceType> __pospos =
__gen_two_uniform_ints(__swap_range, __swap_range + 1, __g);
- ranges::iter_swap(__i++, __first + __pospos.first);
- ranges::iter_swap(__i++, __first + __pospos.second);
+ ranges::iter_swap(__i++, ranges::next(__first, __pospos.first));
+ ranges::iter_swap(__i++, ranges::next(__first, __pospos.second));
}
return __i;
}
__distr_type __d;
- _Iter __i = __first + 1;
+ _Iter __i = ranges::next(__first);
for (; __i != __last; ++__i)
- ranges::iter_swap(__i, __first + __d(__g, __p_type(0, __i - __first)));
+ ranges::iter_swap(__i,
+ ranges::next(__first,
+ __d(__g, __p_type(0, __i - __first))));
return __i;
}
template<random_access_range _Range, typename _Gen>
requires permutable<iterator_t<_Range>>
&& uniform_random_bit_generator<remove_reference_t<_Gen>>
borrowed_iterator_t<_Range>
operator()(_Range&& __r, _Gen&& __g) const
{
return (*this)(ranges::begin(__r), ranges::end(__r),
std::forward<_Gen>(__g));
}
};
inline constexpr __shuffle_fn shuffle{};
namespace __detail
{
template<typename _Iter, typename _Comp>
@@ -2043,41 +2049,41 @@ namespace ranges
*(__first + __holeIndex) = std::move(__value);
}
} // namespace __detail
struct __push_heap_fn
{
template<random_access_iterator _Iter, sentinel_for<_Iter> _Sent,
typename _Comp = ranges::less, typename _Proj = identity>
requires sortable<_Iter, _Comp, _Proj>
constexpr _Iter
operator()(_Iter __first, _Sent __last,
_Comp __comp = {}, _Proj __proj = {}) const
{
if constexpr (!same_as<_Iter, _Sent>)
return (*this)(__first, ranges::next(__first, __last),
std::move(__comp), std::move(__proj));
else
{
auto __comp_proj = __detail::__make_comp_proj(__comp, __proj);
__detail::__push_heap(__first, (__last - __first) - 1,
- 0, ranges::iter_move(__last - 1),
+ 0, ranges::iter_move(ranges::prev(__last)),
__comp_proj);
return __last;
}
}
template<random_access_range _Range,
typename _Comp = ranges::less, typename _Proj = identity>
requires sortable<iterator_t<_Range>, _Comp, _Proj>
constexpr borrowed_iterator_t<_Range>
operator()(_Range&& __r, _Comp __comp = {}, _Proj __proj = {}) const
{
return (*this)(ranges::begin(__r), ranges::end(__r),
std::move(__comp), std::move(__proj));
}
};
inline constexpr __push_heap_fn push_heap{};
namespace __detail
{
@@ -2120,42 +2126,43 @@ namespace ranges
std::move(__value), __comp);
}
} // namespace __detail
struct __pop_heap_fn
{
template<random_access_iterator _Iter, sentinel_for<_Iter> _Sent,
typename _Comp = ranges::less, typename _Proj = identity>
requires sortable<_Iter, _Comp, _Proj>
constexpr _Iter
operator()(_Iter __first, _Sent __last,
_Comp __comp = {}, _Proj __proj = {}) const
{
if constexpr (!same_as<_Iter, _Sent>)
return (*this)(__first, ranges::next(__first, __last),
std::move(__comp), std::move(__proj));
else
{
if (__last - __first > 1)
{
+ auto __back = ranges::prev(__last);
auto __comp_proj = __detail::__make_comp_proj(__comp, __proj);
- __detail::__pop_heap(__first, __last - 1, __last - 1, __comp_proj);
+ __detail::__pop_heap(__first, __back, __back, __comp_proj);
}
return __last;
}
}
template<random_access_range _Range,
typename _Comp = ranges::less, typename _Proj = identity>
requires sortable<iterator_t<_Range>, _Comp, _Proj>
constexpr borrowed_iterator_t<_Range>
operator()(_Range&& __r, _Comp __comp = {}, _Proj __proj = {}) const
{
return (*this)(ranges::begin(__r), ranges::end(__r),
std::move(__comp), std::move(__proj));
}
};
inline constexpr __pop_heap_fn pop_heap{};
struct __make_heap_fn
{
@@ -2339,102 +2346,105 @@ namespace ranges
{
iter_value_t<_Iter> __val = ranges::iter_move(__last);
_Iter __next = __last;
--__next;
while (__comp(__val, *__next))
{
*__last = ranges::iter_move(__next);
__last = __next;
--__next;
}
*__last = std::move(__val);
}
template<typename _Iter, typename _Comp>
constexpr void
__insertion_sort(_Iter __first, _Iter __last, _Comp __comp)
{
if (__first == __last)
return;
- for (_Iter __i = __first + 1; __i != __last; ++__i)
+ for (_Iter __i = ranges::next(__first); __i != __last; ++__i)
{
if (__comp(*__i, *__first))
{
iter_value_t<_Iter> __val = ranges::iter_move(__i);
- ranges::move_backward(__first, __i, __i + 1);
+ ranges::move_backward(__first, __i, ranges::next(__i));
*__first = std::move(__val);
}
else
__detail::__unguarded_linear_insert(__i, __comp);
}
}
template<typename _Iter, typename _Comp>
constexpr void
__unguarded_insertion_sort(_Iter __first, _Iter __last, _Comp __comp)
{
for (_Iter __i = __first; __i != __last; ++__i)
__detail::__unguarded_linear_insert(__i, __comp);
}
inline constexpr int __sort_threshold = 16;
template<typename _Iter, typename _Comp>
constexpr void
__final_insertion_sort(_Iter __first, _Iter __last, _Comp __comp)
{
- if (__last - __first > __sort_threshold)
+ constexpr iter_difference_t<_Iter> __threshold = __sort_threshold;
+ if (__last - __first > __threshold)
{
- __detail::__insertion_sort(__first, __first + __sort_threshold, __comp);
- __detail::__unguarded_insertion_sort(__first + __sort_threshold, __last,
+ __detail::__insertion_sort(__first, __first + __threshold, __comp);
+ __detail::__unguarded_insertion_sort(__first + __threshold, __last,
__comp);
}
else
__detail::__insertion_sort(__first, __last, __comp);
}
template<typename _Iter, typename _Comp>
constexpr _Iter
__unguarded_partition(_Iter __first, _Iter __last, _Iter __pivot, _Comp __comp)
{
while (true)
{
while (__comp(*__first, *__pivot))
++__first;
--__last;
while (__comp(*__pivot, *__last))
--__last;
if (!(__first < __last))
return __first;
ranges::iter_swap(__first, __last);
++__first;
}
}
template<typename _Iter, typename _Comp>
constexpr _Iter
__unguarded_partition_pivot(_Iter __first, _Iter __last, _Comp __comp)
{
_Iter __mid = __first + (__last - __first) / 2;
- __detail::__move_median_to_first(__first, __first + 1, __mid, __last - 1, __comp);
- return __detail::__unguarded_partition(__first + 1, __last, __first, __comp);
+ __detail::__move_median_to_first(__first, ranges::next(__first), __mid,
+ ranges::prev(__last), __comp);
+ return __detail::__unguarded_partition(ranges::next(__first), __last,
+ __first, __comp);
}
template<typename _Iter, typename _Comp>
constexpr void
__heap_select(_Iter __first, _Iter __middle, _Iter __last, _Comp __comp)
{
ranges::make_heap(__first, __middle, __comp);
for (_Iter __i = __middle; __i < __last; ++__i)
if (__comp(*__i, *__first))
__detail::__pop_heap(__first, __middle, __i, __comp);
}
template<typename _Iter, typename _Comp>
constexpr void
__partial_sort(_Iter __first, _Iter __middle, _Iter __last, _Comp __comp)
{
__detail::__heap_select(__first, __middle, __last, __comp);
ranges::sort_heap(__first, __middle, __comp);
}
@@ -2728,41 +2738,41 @@ namespace ranges
struct __partial_sort_fn
{
template<random_access_iterator _Iter, sentinel_for<_Iter> _Sent,
typename _Comp = ranges::less, typename _Proj = identity>
requires sortable<_Iter, _Comp, _Proj>
constexpr _Iter
operator()(_Iter __first, _Iter __middle, _Sent __last,
_Comp __comp = {}, _Proj __proj = {}) const
{
if (__first == __middle)
return ranges::next(__first, __last);
ranges::make_heap(__first, __middle, __comp, __proj);
auto __i = __middle;
for (; __i != __last; ++__i)
if (std::__invoke(__comp,
std::__invoke(__proj, *__i),
std::__invoke(__proj, *__first)))
{
ranges::pop_heap(__first, __middle, __comp, __proj);
- ranges::iter_swap(__middle-1, __i);
+ ranges::iter_swap(std::prev(__middle), __i);
ranges::push_heap(__first, __middle, __comp, __proj);
}
ranges::sort_heap(__first, __middle, __comp, __proj);
return __i;
}
template<random_access_range _Range,
typename _Comp = ranges::less, typename _Proj = identity>
requires sortable<iterator_t<_Range>, _Comp, _Proj>
constexpr borrowed_iterator_t<_Range>
operator()(_Range&& __r, iterator_t<_Range> __middle,
_Comp __comp = {}, _Proj __proj = {}) const
{
return (*this)(ranges::begin(__r), std::move(__middle),
ranges::end(__r),
std::move(__comp), std::move(__proj));
}
};
@@ -2795,41 +2805,41 @@ namespace ranges
std::move(__last));
return {std::move(__lasti), std::move(__result_first)};
}
auto __result_real_last = __result_first;
while (__first != __last && __result_real_last != __result_last)
{
*__result_real_last = *__first;
++__result_real_last;
++__first;
}
ranges::make_heap(__result_first, __result_real_last, __comp, __proj2);
for (; __first != __last; ++__first)
if (std::__invoke(__comp,
std::__invoke(__proj1, *__first),
std::__invoke(__proj2, *__result_first)))
{
ranges::pop_heap(__result_first, __result_real_last,
__comp, __proj2);
- *(__result_real_last-1) = *__first;
+ *ranges::prev(__result_real_last) = *__first;
ranges::push_heap(__result_first, __result_real_last,
__comp, __proj2);
}
ranges::sort_heap(__result_first, __result_real_last, __comp, __proj2);
return {std::move(__first), std::move(__result_real_last)};
}
template<input_range _Range1, random_access_range _Range2,
typename _Comp = ranges::less,
typename _Proj1 = identity, typename _Proj2 = identity>
requires indirectly_copyable<iterator_t<_Range1>, iterator_t<_Range2>>
&& sortable<iterator_t<_Range2>, _Comp, _Proj2>
&& indirect_strict_weak_order<_Comp,
projected<iterator_t<_Range1>, _Proj1>,
projected<iterator_t<_Range2>, _Proj2>>
constexpr partial_sort_copy_result<borrowed_iterator_t<_Range1>,
borrowed_iterator_t<_Range2>>
operator()(_Range1&& __r, _Range2&& __out, _Comp __comp = {},
_Proj1 __proj1 = {}, _Proj2 __proj2 = {}) const
@@ -2907,41 +2917,42 @@ namespace ranges
operator()(_Range&& __r, _Comp __comp = {}, _Proj __proj = {}) const
{
return (*this)(ranges::begin(__r), ranges::end(__r),
std::move(__comp), std::move(__proj));
}
};
inline constexpr __is_sorted_fn is_sorted{};
namespace __detail
{
template<typename _Iter, typename _Comp>
constexpr void
__introselect(_Iter __first, _Iter __nth, _Iter __last,
iter_difference_t<_Iter> __depth_limit, _Comp __comp)
{
while (__last - __first > 3)
{
if (__depth_limit == 0)
{
- __detail::__heap_select(__first, __nth + 1, __last, __comp);
+ __detail::__heap_select(__first, ranges::next(__nth), __last,
+ __comp);
// Place the nth largest element in its final position.
ranges::iter_swap(__first, __nth);
return;
}
--__depth_limit;
_Iter __cut = __detail::__unguarded_partition_pivot(__first, __last, __comp);
if (__cut <= __nth)
__first = __cut;
else
__last = __cut;
}
__detail::__insertion_sort(__first, __last, __comp);
}
} // namespace __detail
struct __nth_element_fn
{
template<random_access_iterator _Iter, sentinel_for<_Iter> _Sent,
typename _Comp = ranges::less, typename _Proj = identity>
requires sortable<_Iter, _Comp, _Proj>
@@ -883,61 +883,61 @@ namespace ranges
{
while (__it != __bound)
++__it;
}
}
template<input_or_output_iterator _It, sentinel_for<_It> _Sent>
constexpr iter_difference_t<_It>
operator()(_It& __it, iter_difference_t<_It> __n, _Sent __bound) const
{
if constexpr (sized_sentinel_for<_Sent, _It>)
{
const iter_difference_t<_It> __diff = __bound - __it;
if (__diff == 0)
{
// inline any possible side effects of advance(it, bound)
if constexpr (assignable_from<_It&, _Sent>)
__it = std::move(__bound);
else if constexpr (random_access_iterator<_It>)
- __it += 0;
+ __it += iter_difference_t<_It>(0);
return __n;
}
else if (__diff > 0 ? __n >= __diff : __n <= __diff)
{
(*this)(__it, __bound);
return __n - __diff;
}
else if (__n != 0) [[likely]]
{
// n and bound must not lead in opposite directions:
__glibcxx_assert((__n < 0) == (__diff < 0));
(*this)(__it, __n);
return 0;
}
else
{
// inline any possible side effects of advance(it, n)
if constexpr (random_access_iterator<_It>)
- __it += 0;
+ __it += iter_difference_t<_It>(0);
return 0;
}
}
else if (__n == 0 || __it == __bound)
return __n;
else if (__n > 0)
{
iter_difference_t<_It> __m = 0;
do
{
++__it;
++__m;
}
while (__m != __n && __it != __bound);
return __n - __m;
}
else if constexpr (bidirectional_iterator<_It> && same_as<_It, _Sent>)
{
iter_difference_t<_It> __m = 0;
do
@@ -187,41 +187,41 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
__search_n_aux(_RandomAccessIter __first, _RandomAccessIter __last,
_Integer __count, _UnaryPredicate __unary_pred,
std::random_access_iterator_tag)
{
typedef typename std::iterator_traits<_RandomAccessIter>::difference_type
_DistanceType;
_DistanceType __tailSize = __last - __first;
_DistanceType __remainder = __count;
while (__remainder <= __tailSize) // the main loop...
{
__first += __remainder;
__tailSize -= __remainder;
// __first here is always pointing to one past the last element of
// next possible match.
_RandomAccessIter __backTrack = __first;
while (__unary_pred(--__backTrack))
{
if (--__remainder == 0)
- return (__first - __count); // Success
+ return __first - _DistanceType(__count); // Success
}
__remainder = __count + 1 - (__first - __backTrack);
}
return __last; // Failure
}
template<typename _ForwardIterator, typename _Integer,
typename _UnaryPredicate>
_GLIBCXX20_CONSTEXPR
_ForwardIterator
__search_n(_ForwardIterator __first, _ForwardIterator __last,
_Integer __count,
_UnaryPredicate __unary_pred)
{
if (__count <= 0)
return __first;
if (__count == 1)
return std::__find_if(__first, __last, __unary_pred);
@@ -1241,65 +1241,71 @@ _GLIBCXX_BEGIN_INLINE_ABI_NAMESPACE(_V2)
#endif
_Distance __n = __last - __first;
_Distance __k = __middle - __first;
if (__k == __n - __k)
{
std::swap_ranges(__first, __middle, __middle);
return __middle;
}
_RandomAccessIterator __p = __first;
_RandomAccessIterator __ret = __first + (__last - __middle);
for (;;)
{
if (__k < __n - __k)
{
if (__is_pod(_ValueType) && __k == 1)
{
+ _RandomAccessIterator __mid = __p + _Distance(__n - 1);
+ _RandomAccessIterator __end = __mid;
+ ++__end;
_ValueType __t = _GLIBCXX_MOVE(*__p);
- _GLIBCXX_MOVE3(__p + 1, __p + __n, __p);
- *(__p + __n - 1) = _GLIBCXX_MOVE(__t);
+ _GLIBCXX_MOVE3(__p + _Distance(1), __end, __p);
+ *__mid = _GLIBCXX_MOVE(__t);
return __ret;
}
_RandomAccessIterator __q = __p + __k;
for (_Distance __i = 0; __i < __n - __k; ++ __i)
{
std::iter_swap(__p, __q);
++__p;
++__q;
}
__n = static_cast<_UDistance>(__n) % static_cast<_UDistance>(__k);
if (__n == 0)
return __ret;
std::swap(__n, __k);
__k = __n - __k;
}
else
{
__k = __n - __k;
if (__is_pod(_ValueType) && __k == 1)
{
- _ValueType __t = _GLIBCXX_MOVE(*(__p + __n - 1));
- _GLIBCXX_MOVE_BACKWARD3(__p, __p + __n - 1, __p + __n);
+ _RandomAccessIterator __mid = __p + _Distance(__n - 1);
+ _RandomAccessIterator __end = __mid;
+ ++__end;
+ _ValueType __t = _GLIBCXX_MOVE(*__mid);
+ _GLIBCXX_MOVE_BACKWARD3(__p, __mid, __end);
*__p = _GLIBCXX_MOVE(__t);
return __ret;
}
_RandomAccessIterator __q = __p + __n;
__p = __q - __k;
for (_Distance __i = 0; __i < __n - __k; ++ __i)
{
--__p;
--__q;
std::iter_swap(__p, __q);
}
__n = static_cast<_UDistance>(__n) % static_cast<_UDistance>(__k);
if (__n == 0)
return __ret;
std::swap(__n, __k);
}
}
}
// _GLIBCXX_RESOLVE_LIB_DEFECTS
@@ -1753,125 +1759,135 @@ _GLIBCXX_END_INLINE_ABI_NAMESPACE(_V2)
typename iterator_traits<_RandomAccessIterator>::value_type
__val = _GLIBCXX_MOVE(*__last);
_RandomAccessIterator __next = __last;
--__next;
while (__comp(__val, __next))
{
*__last = _GLIBCXX_MOVE(*__next);
__last = __next;
--__next;
}
*__last = _GLIBCXX_MOVE(__val);
}
/// This is a helper function for the sort routine.
template<typename _RandomAccessIterator, typename _Compare>
_GLIBCXX20_CONSTEXPR
void
__insertion_sort(_RandomAccessIterator __first,
_RandomAccessIterator __last, _Compare __comp)
{
- if (__first == __last) return;
+ if (__first == __last)
+ return;
- for (_RandomAccessIterator __i = __first + 1; __i != __last; ++__i)
+ typedef iterator_traits<_RandomAccessIterator> _IterTraits;
+ typedef typename _IterTraits::difference_type _Dist;
+
+ for (_RandomAccessIterator __i = __first + _Dist(1); __i != __last; ++__i)
{
if (__comp(__i, __first))
{
- typename iterator_traits<_RandomAccessIterator>::value_type
- __val = _GLIBCXX_MOVE(*__i);
- _GLIBCXX_MOVE_BACKWARD3(__first, __i, __i + 1);
+ typename _IterTraits::value_type __val = _GLIBCXX_MOVE(*__i);
+ _GLIBCXX_MOVE_BACKWARD3(__first, __i, __i + _Dist(1));
*__first = _GLIBCXX_MOVE(__val);
}
else
std::__unguarded_linear_insert(__i,
__gnu_cxx::__ops::__val_comp_iter(__comp));
}
}
/// This is a helper function for the sort routine.
template<typename _RandomAccessIterator, typename _Compare>
_GLIBCXX20_CONSTEXPR
inline void
__unguarded_insertion_sort(_RandomAccessIterator __first,
_RandomAccessIterator __last, _Compare __comp)
{
for (_RandomAccessIterator __i = __first; __i != __last; ++__i)
std::__unguarded_linear_insert(__i,
__gnu_cxx::__ops::__val_comp_iter(__comp));
}
/**
* @doctodo
* This controls some aspect of the sort routines.
*/
enum { _S_threshold = 16 };
/// This is a helper function for the sort routine.
template<typename _RandomAccessIterator, typename _Compare>
_GLIBCXX20_CONSTEXPR
void
__final_insertion_sort(_RandomAccessIterator __first,
_RandomAccessIterator __last, _Compare __comp)
{
- if (__last - __first > int(_S_threshold))
+ typename iterator_traits<_RandomAccessIterator>::difference_type
+ __threshold = _S_threshold;
+
+ if (__last - __first > __threshold)
{
- std::__insertion_sort(__first, __first + int(_S_threshold), __comp);
- std::__unguarded_insertion_sort(__first + int(_S_threshold), __last,
+ std::__insertion_sort(__first, __first + __threshold, __comp);
+ std::__unguarded_insertion_sort(__first + __threshold, __last,
__comp);
}
else
std::__insertion_sort(__first, __last, __comp);
}
/// This is a helper function...
template<typename _RandomAccessIterator, typename _Compare>
_GLIBCXX20_CONSTEXPR
_RandomAccessIterator
__unguarded_partition(_RandomAccessIterator __first,
_RandomAccessIterator __last,
_RandomAccessIterator __pivot, _Compare __comp)
{
while (true)
{
while (__comp(__first, __pivot))
++__first;
--__last;
while (__comp(__pivot, __last))
--__last;
if (!(__first < __last))
return __first;
std::iter_swap(__first, __last);
++__first;
}
}
/// This is a helper function...
template<typename _RandomAccessIterator, typename _Compare>
_GLIBCXX20_CONSTEXPR
inline _RandomAccessIterator
__unguarded_partition_pivot(_RandomAccessIterator __first,
_RandomAccessIterator __last, _Compare __comp)
{
- _RandomAccessIterator __mid = __first + (__last - __first) / 2;
- std::__move_median_to_first(__first, __first + 1, __mid, __last - 1,
+ typedef iterator_traits<_RandomAccessIterator> _IterTraits;
+ typedef typename _IterTraits::difference_type _Dist;
+
+ _RandomAccessIterator __mid = __first + _Dist((__last - __first) / 2);
+ _RandomAccessIterator __second = __first + _Dist(1);
+ std::__move_median_to_first(__first, __second, __mid, __last - _Dist(1),
__comp);
- return std::__unguarded_partition(__first + 1, __last, __first, __comp);
+ return std::__unguarded_partition(__second, __last, __first, __comp);
}
template<typename _RandomAccessIterator, typename _Compare>
_GLIBCXX20_CONSTEXPR
inline void
__partial_sort(_RandomAccessIterator __first,
_RandomAccessIterator __middle,
_RandomAccessIterator __last,
_Compare __comp)
{
std::__heap_select(__first, __middle, __last, __comp);
std::__sort_heap(__first, __middle, __comp);
}
/// This is a helper function for the sort routine.
template<typename _RandomAccessIterator, typename _Size, typename _Compare>
_GLIBCXX20_CONSTEXPR
void
__introsort_loop(_RandomAccessIterator __first,
_RandomAccessIterator __last,
@@ -1899,45 +1915,48 @@ _GLIBCXX_END_INLINE_ABI_NAMESPACE(_V2)
inline void
__sort(_RandomAccessIterator __first, _RandomAccessIterator __last,
_Compare __comp)
{
if (__first != __last)
{
std::__introsort_loop(__first, __last,
std::__lg(__last - __first) * 2,
__comp);
std::__final_insertion_sort(__first, __last, __comp);
}
}
template<typename _RandomAccessIterator, typename _Size, typename _Compare>
_GLIBCXX20_CONSTEXPR
void
__introselect(_RandomAccessIterator __first, _RandomAccessIterator __nth,
_RandomAccessIterator __last, _Size __depth_limit,
_Compare __comp)
{
+ _RandomAccessIterator __after_nth = __nth;
+ ++__after_nth;
+
while (__last - __first > 3)
{
if (__depth_limit == 0)
{
- std::__heap_select(__first, __nth + 1, __last, __comp);
+ std::__heap_select(__first, __after_nth, __last, __comp);
// Place the nth largest element in its final position.
std::iter_swap(__first, __nth);
return;
}
--__depth_limit;
_RandomAccessIterator __cut =
std::__unguarded_partition_pivot(__first, __last, __comp);
if (__cut <= __nth)
__first = __cut;
else
__last = __cut;
}
std::__insertion_sort(__first, __last, __comp);
}
/// @endcond
// nth_element
// lower_bound moved to stl_algobase.h
@@ -3805,41 +3824,42 @@ _GLIBCXX_BEGIN_NAMESPACE_ALGO
* @param __first An input iterator.
* @param __n A value convertible to an integer.
* @param __f A unary function object.
* @return `__first+__n`
*
* Applies the function object `__f` to each element in the range
* `[first, first+n)`. `__f` must not modify the order of the sequence.
* If `__f` has a return value it is ignored.
*/
template<typename _InputIterator, typename _Size, typename _Function>
_GLIBCXX20_CONSTEXPR
_InputIterator
for_each_n(_InputIterator __first, _Size __n, _Function __f)
{
auto __n2 = std::__size_to_integer(__n);
using _Cat = typename iterator_traits<_InputIterator>::iterator_category;
if constexpr (is_base_of_v<random_access_iterator_tag, _Cat>)
{
if (__n2 <= 0)
return __first;
- auto __last = __first + __n2;
+ typename iterator_traits<_InputIterator>::difference_type __d = __n2;
+ auto __last = __first + __d;
std::for_each(__first, __last, std::move(__f));
return __last;
}
else
{
while (__n2-->0)
{
__f(*__first);
++__first;
}
return __first;
}
}
#endif // C++17
/**
* @brief Find the first occurrence of a value in a sequence.
* @ingroup non_mutating_algorithms
* @param __first An input iterator.
* @param __last An input iterator.
@@ -4527,110 +4547,119 @@ _GLIBCXX_BEGIN_NAMESPACE_ALGO
* distribution, so that every possible ordering of the sequence is
* equally likely.
*
* @deprecated
* Since C++17, `std::random_shuffle` is not part of the C++ standard.
* Use `std::shuffle` instead, which was introduced in C++11.
*/
template<typename _RandomAccessIterator>
_GLIBCXX14_DEPRECATED_SUGGEST("std::shuffle")
inline void
random_shuffle(_RandomAccessIterator __first, _RandomAccessIterator __last)
{
// concept requirements
__glibcxx_function_requires(_Mutable_RandomAccessIteratorConcept<
_RandomAccessIterator>)
__glibcxx_requires_valid_range(__first, __last);
if (__first == __last)
return;
+ typedef typename iterator_traits<_RandomAccessIterator>::difference_type
+ _Dist;
+
#if RAND_MAX < __INT_MAX__
if (__builtin_expect((__last - __first) >= RAND_MAX / 4, 0))
{
// Use a xorshift implementation seeded by two calls to rand()
// instead of using rand() for all the random numbers needed.
unsigned __xss
= (unsigned)std::rand() ^ ((unsigned)std::rand() << 15);
- for (_RandomAccessIterator __i = __first + 1; __i != __last; ++__i)
+ for (_RandomAccessIterator __i = __first + _Dist(1); __i != __last;
+ ++__i)
{
__xss += !__xss;
__xss ^= __xss << 13;
__xss ^= __xss >> 17;
__xss ^= __xss << 5;
- _RandomAccessIterator __j = __first
- + (__xss % ((__i - __first) + 1));
+ _RandomAccessIterator __j
+ = __first + _Dist(__xss % ((__i - __first) + 1));
if (__i != __j)
std::iter_swap(__i, __j);
}
return;
}
#endif
- for (_RandomAccessIterator __i = __first + 1; __i != __last; ++__i)
+ for (_RandomAccessIterator __i = __first + _Dist(1); __i != __last; ++__i)
{
// XXX rand() % N is not uniformly distributed
- _RandomAccessIterator __j = __first
- + (std::rand() % ((__i - __first) + 1));
+ _RandomAccessIterator __j
+ = __first + _Dist(std::rand() % ((__i - __first) + 1));
if (__i != __j)
std::iter_swap(__i, __j);
}
}
/**
* @brief Shuffle the elements of a sequence using a random number
* generator.
* @ingroup mutating_algorithms
* @param __first A forward iterator.
* @param __last A forward iterator.
* @param __rand The RNG functor or function.
* @return Nothing.
*
* Reorders the elements in the range `[__first, __last)` using `__rand`
* to provide a random distribution. Calling `__rand(N)` for a positive
* integer `N` should return a randomly chosen integer from the
* range `[0, N)`.
*
* @deprecated
* Since C++17, `std::random_shuffle` is not part of the C++ standard.
* Use `std::shuffle` instead, which was introduced in C++11.
*/
template<typename _RandomAccessIterator, typename _RandomNumberGenerator>
_GLIBCXX14_DEPRECATED_SUGGEST("std::shuffle")
void
random_shuffle(_RandomAccessIterator __first, _RandomAccessIterator __last,
#if __cplusplus >= 201103L
_RandomNumberGenerator&& __rand)
#else
_RandomNumberGenerator& __rand)
#endif
{
// concept requirements
__glibcxx_function_requires(_Mutable_RandomAccessIteratorConcept<
_RandomAccessIterator>)
__glibcxx_requires_valid_range(__first, __last);
if (__first == __last)
return;
- for (_RandomAccessIterator __i = __first + 1; __i != __last; ++__i)
+
+ typedef typename iterator_traits<_RandomAccessIterator>::difference_type
+ _Dist;
+
+ for (_RandomAccessIterator __i = __first + _Dist(1); __i != __last; ++__i)
{
- _RandomAccessIterator __j = __first + __rand((__i - __first) + 1);
+ _RandomAccessIterator __j
+ = __first + _Dist(__rand((__i - __first) + 1));
if (__i != __j)
std::iter_swap(__i, __j);
}
}
#endif // HOSTED
#endif // <= C++11 || USE_DEPRECATED
/**
* @brief Move elements for which a predicate is true to the beginning
* of a sequence.
* @ingroup mutating_algorithms
* @param __first A forward iterator.
* @param __last A forward iterator.
* @param __pred A predicate functor.
* @return An iterator `middle` such that `__pred(i)` is true for each
* iterator `i` in the range `[__first, middle)` and false for each `i`
* in the range `[middle, __last)`.
*
* `__pred` must not modify its operand. `partition()` does not preserve
* the relative ordering of elements in each group, use
@@ -1133,44 +1133,46 @@ _GLIBCXX_END_NAMESPACE_CONTAINER
{
#if __cplusplus >= 201103L
static_assert(is_integral<_Size>{}, "fill_n must pass integral size");
#endif
return __fill_n_a1(__first, __n, __value);
}
template<typename _OutputIterator, typename _Size, typename _Tp>
__attribute__((__always_inline__))
_GLIBCXX20_CONSTEXPR
inline _OutputIterator
__fill_n_a(_OutputIterator __first, _Size __n, const _Tp& __value,
std::random_access_iterator_tag)
{
#if __cplusplus >= 201103L
static_assert(is_integral<_Size>{}, "fill_n must pass integral size");
#endif
if (__n <= 0)
return __first;
- __glibcxx_requires_can_increment(__first, __n);
+ typename iterator_traits<_OutputIterator>::difference_type __d = __n;
+ __glibcxx_requires_can_increment(__first, __d);
- std::__fill_a(__first, __first + __n, __value);
- return __first + __n;
+ _OutputIterator __last = __first + __d;
+ std::__fill_a(__first, __last, __value);
+ return __last;
}
/**
* @brief Fills the range [first,first+n) with copies of value.
* @ingroup mutating_algorithms
* @param __first An output iterator.
* @param __n The count of copies to perform.
* @param __value A reference-to-const of arbitrary type.
* @return The iterator at first+n.
*
* This function fills a range with copies of the same value. For char
* types filling contiguous areas of memory, this becomes an inline call
* to @c memset or @c wmemset.
*
* If @p __n is negative, the function does nothing.
*/
// _GLIBCXX_RESOLVE_LIB_DEFECTS
// DR 865. More algorithms that throw away information
// DR 426. search_n(), fill_n(), and generate_n() with negative n
template<typename _OI, typename _Size, typename _Tp>
@@ -1293,45 +1295,45 @@ _GLIBCXX_END_NAMESPACE_CONTAINER
static _II1
__newlast1(_II1, _II1 __last1, _II2, _II2)
{ return __last1; }
template<typename _II>
_GLIBCXX20_CONSTEXPR
static bool
__cnd2(_II __first, _II __last)
{ return __first != __last; }
};
template<>
struct __lc_rai<random_access_iterator_tag, random_access_iterator_tag>
{
template<typename _RAI1, typename _RAI2>
_GLIBCXX20_CONSTEXPR
static _RAI1
__newlast1(_RAI1 __first1, _RAI1 __last1,
_RAI2 __first2, _RAI2 __last2)
{
- const typename iterator_traits<_RAI1>::difference_type
- __diff1 = __last1 - __first1;
- const typename iterator_traits<_RAI2>::difference_type
- __diff2 = __last2 - __first2;
- return __diff2 < __diff1 ? __first1 + __diff2 : __last1;
+ typedef typename iterator_traits<_RAI1>::difference_type _Diff1;
+ typedef typename iterator_traits<_RAI2>::difference_type _Diff2;
+ const _Diff1 __diff1 = __last1 - __first1;
+ const _Diff2 __diff2 = __last2 - __first2;
+ return __diff2 < __diff1 ? __first1 + _Diff1(__diff2) : __last1;
}
template<typename _RAI>
static _GLIBCXX20_CONSTEXPR bool
__cnd2(_RAI, _RAI)
{ return true; }
};
template<typename _II1, typename _II2, typename _Compare>
_GLIBCXX20_CONSTEXPR
bool
__lexicographical_compare_impl(_II1 __first1, _II1 __last1,
_II2 __first2, _II2 __last2,
_Compare __comp)
{
typedef typename iterator_traits<_II1>::iterator_category _Category1;
typedef typename iterator_traits<_II2>::iterator_category _Category2;
typedef std::__lc_rai<_Category1, _Category2> __rai_type;
__last1 = __rai_type::__newlast1(__first1, __last1, __first2, __last2);
@@ -59,71 +59,79 @@
#include <bits/move.h>
#include <bits/predefined_ops.h>
#include <bits/stl_iterator_base_funcs.h>
namespace std _GLIBCXX_VISIBILITY(default)
{
_GLIBCXX_BEGIN_NAMESPACE_VERSION
/**
* @defgroup heap_algorithms Heap
* @ingroup sorting_algorithms
*/
template<typename _RandomAccessIterator, typename _Distance,
typename _Compare>
_GLIBCXX20_CONSTEXPR
_Distance
__is_heap_until(_RandomAccessIterator __first, _Distance __n,
_Compare& __comp)
{
+#if __cplusplus >= 201103L
+ using _IterTraits = iterator_traits<_RandomAccessIterator>;
+ static_assert(is_same<typename _IterTraits::difference_type,
+ _Distance>::value,
+ "Argument 'n' must be the iterator's difference type");
+#endif
_Distance __parent = 0;
for (_Distance __child = 1; __child < __n; ++__child)
{
if (__comp(__first + __parent, __first + __child))
return __child;
if ((__child & 1) == 0)
++__parent;
}
return __n;
}
// __is_heap, a predicate testing whether or not a range is a heap.
// This function is an extension, not part of the C++ standard.
template<typename _RandomAccessIterator, typename _Distance>
_GLIBCXX20_CONSTEXPR
inline bool
__is_heap(_RandomAccessIterator __first, _Distance __n)
{
+ typename iterator_traits<_RandomAccessIterator>::difference_type __d(__n);
__gnu_cxx::__ops::_Iter_less_iter __comp;
- return std::__is_heap_until(__first, __n, __comp) == __n;
+ return std::__is_heap_until(__first, __d, __comp) == __n;
}
template<typename _RandomAccessIterator, typename _Compare,
typename _Distance>
_GLIBCXX20_CONSTEXPR
inline bool
__is_heap(_RandomAccessIterator __first, _Compare __comp, _Distance __n)
{
+ typename iterator_traits<_RandomAccessIterator>::difference_type __d(__n);
typedef __decltype(__comp) _Cmp;
__gnu_cxx::__ops::_Iter_comp_iter<_Cmp> __cmp(_GLIBCXX_MOVE(__comp));
- return std::__is_heap_until(__first, __n, __cmp) == __n;
+ return std::__is_heap_until(__first, __d, __cmp) == __n;
}
template<typename _RandomAccessIterator>
_GLIBCXX20_CONSTEXPR
inline bool
__is_heap(_RandomAccessIterator __first, _RandomAccessIterator __last)
{ return std::__is_heap(__first, std::distance(__first, __last)); }
template<typename _RandomAccessIterator, typename _Compare>
_GLIBCXX20_CONSTEXPR
inline bool
__is_heap(_RandomAccessIterator __first, _RandomAccessIterator __last,
_Compare __comp)
{
return std::__is_heap(__first, _GLIBCXX_MOVE(__comp),
std::distance(__first, __last));
}
// Heap-manipulation functions: push_heap, pop_heap, make_heap, sort_heap,
// + is_heap and is_heap_until in C++0x.
@@ -158,78 +166,78 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
*/
template<typename _RandomAccessIterator>
_GLIBCXX20_CONSTEXPR
inline void
push_heap(_RandomAccessIterator __first, _RandomAccessIterator __last)
{
typedef typename iterator_traits<_RandomAccessIterator>::value_type
_ValueType;
typedef typename iterator_traits<_RandomAccessIterator>::difference_type
_DistanceType;
// concept requirements
__glibcxx_function_requires(_Mutable_RandomAccessIteratorConcept<
_RandomAccessIterator>)
__glibcxx_function_requires(_LessThanComparableConcept<_ValueType>)
__glibcxx_requires_valid_range(__first, __last);
__glibcxx_requires_irreflexive(__first, __last);
__glibcxx_requires_heap(__first, __last - 1);
__gnu_cxx::__ops::_Iter_less_val __comp;
- _ValueType __value = _GLIBCXX_MOVE(*(__last - 1));
+ _ValueType __value = _GLIBCXX_MOVE(*(__last - _DistanceType(1)));
std::__push_heap(__first, _DistanceType((__last - __first) - 1),
_DistanceType(0), _GLIBCXX_MOVE(__value), __comp);
}
/**
* @brief Push an element onto a heap using comparison functor.
* @param __first Start of heap.
* @param __last End of heap + element.
* @param __comp Comparison functor.
* @ingroup heap_algorithms
*
* This operation pushes the element at __last-1 onto the valid
* heap over the range [__first,__last-1). After completion,
* [__first,__last) is a valid heap. Compare operations are
* performed using comp.
*/
template<typename _RandomAccessIterator, typename _Compare>
_GLIBCXX20_CONSTEXPR
inline void
push_heap(_RandomAccessIterator __first, _RandomAccessIterator __last,
_Compare __comp)
{
typedef typename iterator_traits<_RandomAccessIterator>::value_type
_ValueType;
typedef typename iterator_traits<_RandomAccessIterator>::difference_type
_DistanceType;
// concept requirements
__glibcxx_function_requires(_Mutable_RandomAccessIteratorConcept<
_RandomAccessIterator>)
__glibcxx_requires_valid_range(__first, __last);
__glibcxx_requires_irreflexive_pred(__first, __last, __comp);
- __glibcxx_requires_heap_pred(__first, __last - 1, __comp);
+ __glibcxx_requires_heap_pred(__first, __last - _DistanceType(1), __comp);
__decltype(__gnu_cxx::__ops::__iter_comp_val(_GLIBCXX_MOVE(__comp)))
__cmp(_GLIBCXX_MOVE(__comp));
- _ValueType __value = _GLIBCXX_MOVE(*(__last - 1));
+ _ValueType __value = _GLIBCXX_MOVE(*(__last - _DistanceType(1)));
std::__push_heap(__first, _DistanceType((__last - __first) - 1),
_DistanceType(0), _GLIBCXX_MOVE(__value), __cmp);
}
template<typename _RandomAccessIterator, typename _Distance,
typename _Tp, typename _Compare>
_GLIBCXX20_CONSTEXPR
void
__adjust_heap(_RandomAccessIterator __first, _Distance __holeIndex,
_Distance __len, _Tp __value, _Compare __comp)
{
const _Distance __topIndex = __holeIndex;
_Distance __secondChild = __holeIndex;
while (__secondChild < (__len - 1) / 2)
{
__secondChild = 2 * (__secondChild + 1);
if (__comp(__first + __secondChild,
__first + (__secondChild - 1)))
__secondChild--;
*(__first + __holeIndex) = _GLIBCXX_MOVE(*(__first + __secondChild));
@@ -1328,38 +1328,38 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
// to give consistent results for lookup in the map.
static_assert(is_same_v<iter_value_t<_RAIter>,
iter_value_t<_RandomAccessIterator2>>);
#endif
auto __patlen = _M_pat_end - _M_pat;
if (__patlen == 0)
return std::make_pair(__first, __first);
const auto& __pred = this->_M_pred();
__diff_type __i = __patlen - 1;
auto __stringlen = __last - __first;
while (__i < __stringlen)
{
__diff_type __j = __patlen - 1;
while (__j >= 0 && __pred(__first[__i], _M_pat[__j]))
{
--__i;
--__j;
}
if (__j < 0)
{
- const auto __match = __first + __i + 1;
+ const auto __match = __first + __diff_type(__i + 1);
return std::make_pair(__match, __match + __patlen);
}
__i += std::max(_M_bad_char_shift(__first[__i]),
_M_good_suffix[__j]);
}
return std::make_pair(__last, __last);
}
#endif // __cpp_lib_boyer_moore_searcher
#endif // C++17
#endif // C++14
#endif // C++11
_GLIBCXX_END_NAMESPACE_VERSION
} // namespace std
#endif // _GLIBCXX_FUNCTIONAL
@@ -25,41 +25,41 @@ using __gnu_test::test_range;
using __gnu_test::random_access_iterator_wrapper;
using __gnu_test::bidirectional_iterator_wrapper;
using __gnu_test::forward_iterator_wrapper;
using __gnu_test::input_iterator_wrapper;
using __gnu_test::output_iterator_wrapper;
void
test01()
{
int a[2] = { };
test_range<int, random_access_iterator_wrapper> r(a);
auto iter = r.begin();
std::ranges::advance(iter, 1);
VERIFY( iter != r.begin() );
VERIFY( iter != r.end() );
std::ranges::advance(iter, 1);
VERIFY( iter == r.end() );
std::ranges::advance(iter, -2);
VERIFY( iter == r.begin() );
- std::ranges::advance(iter, r.begin() + 1);
+ std::ranges::advance(iter, std::ranges::next(r.begin()));
VERIFY( iter != r.begin() );
VERIFY( iter != r.end() );
std::ranges::advance(iter, r.begin());
VERIFY( iter == r.begin() );
auto diff = std::ranges::advance(iter, 99, r.end());
VERIFY( iter == r.end() );
VERIFY( diff == 97 );
diff = std::ranges::advance(iter, -222, r.begin());
VERIFY( iter == r.begin() );
VERIFY( diff == -220 );
}
void
test02()
{
int a[2] = { };
test_range<int, bidirectional_iterator_wrapper> r(a);
auto iter = r.begin();
std::ranges::advance(iter, 1);
new file mode 100644
@@ -0,0 +1,13 @@
+// { dg-do compile { target c++11 } }
+
+#include <algorithm>
+#include <testsuite_iterators.h>
+
+void
+test_pr121890()
+{
+ // algorithms do not use iterator's difference_type for arithmetic
+ int a[1];
+ __gnu_test::random_access_container<int> c(a);
+ std::fill_n(c.begin(), 1U, 0);
+}
new file mode 100644
@@ -0,0 +1,13 @@
+// { dg-do compile { target c++17 } }
+
+#include <algorithm>
+#include <testsuite_iterators.h>
+
+void
+test_pr121890()
+{
+ // algorithms do not use iterator's difference_type for arithmetic
+ int a[1];
+ __gnu_test::random_access_container<int> c(a);
+ std::for_each_n(c.begin(), 1U, [](int){});
+}
@@ -36,61 +36,61 @@ test01()
{
int x[50];
auto pred = std::greater{};
auto proj = [] (int a) { return -a; };
for (int i = 0; i < 50; i++)
{
std::iota(x, x+50, 1);
container<int, random_access_iterator_wrapper> rx(x);
std::ranlux48_base g(i);
ranges::shuffle(rx, g);
auto iter = ranges::make_heap(rx, pred, proj);
VERIFY( iter == rx.end() );
VERIFY( ranges::is_heap(rx, pred, proj) );
VERIFY( ranges::is_heap_until(rx, pred, proj) == rx.end() );
iter = ranges::pop_heap(rx, pred, proj);
VERIFY( iter == rx.end() );
- VERIFY( *(iter-1) == 50 );
- VERIFY( ranges::is_heap_until(rx, pred, proj) == iter-1 );
+ VERIFY( *ranges::prev(iter) == 50 );
+ VERIFY( ranges::is_heap_until(rx, pred, proj) == ranges::prev(iter) );
- iter = ranges::pop_heap(rx.begin(), iter-1, pred, proj);
- VERIFY( iter+1 == rx.end() );
- VERIFY( *(iter-1) == 49 );
- VERIFY( ranges::is_heap_until(rx, pred, proj) == iter-1 );
+ iter = ranges::pop_heap(rx.begin(), ranges::prev(iter), pred, proj);
+ VERIFY( ranges::next(iter) == rx.end() );
+ VERIFY( *ranges::prev(iter) == 49 );
+ VERIFY( ranges::is_heap_until(rx, pred, proj) == ranges::prev(iter) );
- *(iter-1) = i;
+ *ranges::prev(iter) = i;
iter = ranges::push_heap(rx.begin(), iter, pred, proj);
- VERIFY( iter+1 == rx.end() );
+ VERIFY( ranges::next(iter) == rx.end() );
VERIFY( ranges::is_heap_until(rx, pred, proj) == iter );
*iter = 2*i;
iter = ranges::push_heap(rx.begin(), rx.end(), pred, proj);
VERIFY( iter == rx.end() );
VERIFY( ranges::is_heap_until(rx, pred, proj) == iter );
- *(rx.begin()+1) *= -1;
+ *ranges::next(rx.begin()) *= -1;
VERIFY( !ranges::is_heap(rx, pred, proj) );
- *(rx.begin()+1) *= -1;
+ *ranges::next(rx.begin()) *= -1;
VERIFY( ranges::is_heap(rx, pred, proj) );
iter = ranges::sort_heap(rx, pred, proj);
VERIFY( iter == rx.end() );
VERIFY( ranges::is_sorted(rx, pred, proj) );
}
}
constexpr bool
test02()
{
bool ok = true;
int x[] = {1,2,3,4,5};
ranges::make_heap(x);
ranges::pop_heap(x);
x[4] = 7;
ranges::push_heap(x);
ok &= ranges::is_heap(x);
ok &= ranges::is_heap_until(x) == x+5;
ranges::sort_heap(x);
new file mode 100644
@@ -0,0 +1,57 @@
+// { dg-do compile { target c++11 } }
+
+#include <algorithm>
+#include <testsuite_iterators.h>
+
+struct Iter
+{
+ using value_type = int;
+ using difference_type = short;
+ using iterator_category = std::random_access_iterator_tag;
+ using pointer = const value_type*;
+ using reference = const value_type&;
+
+ Iter() : p(nullptr) { }
+ explicit Iter(pointer p) : p(p) { }
+ reference operator*() const { return *p; }
+ pointer operator->() const { return p; }
+ reference operator[](difference_type n) const { return p[n]; }
+ Iter& operator++() { ++p; return *this; }
+ Iter& operator--() { --p; return *this; }
+ Iter operator++(int) { return Iter(p++); }
+ Iter operator--(int) { return Iter(p--); }
+ Iter& operator+=(difference_type n) { p += n; return *this; }
+ Iter& operator-=(difference_type n) { p -= n; return *this; }
+
+ friend Iter operator+(Iter i, difference_type n) { return i += n; }
+ friend Iter operator+(difference_type n, Iter i) { return i += n; }
+ friend Iter operator-(Iter i, difference_type n) { return i -= n; }
+ friend difference_type operator-(Iter i, Iter j) { return i.p - j.p; }
+
+ template<typename D> void operator[](D) const = delete;
+ template<typename D> void operator+=(D) = delete;
+ template<typename D> void operator-=(D) = delete;
+ template<typename D> friend void operator+(Iter, difference_type) = delete;
+ template<typename D> friend void operator+(difference_type, Iter) = delete;
+ template<typename D> friend void operator-(Iter, difference_type) = delete;
+
+ friend bool operator==(Iter i, Iter j) { return i.p == j.p; }
+ friend bool operator!=(Iter i, Iter j) { return i.p != j.p; }
+ friend bool operator<(Iter i, Iter j) { return i.p < j.p; }
+ friend bool operator<=(Iter i, Iter j) { return i.p <= j.p; }
+ friend bool operator>(Iter i, Iter j) { return i.p > j.p; }
+ friend bool operator>=(Iter i, Iter j) { return i.p >= j.p; }
+
+private:
+ pointer p;
+};
+
+void
+test_pr121890()
+{
+ // algorithms do not use iterator's difference_type for arithmetic
+ int a[1] = { };
+ __gnu_test::random_access_container<int> c(a);
+ (void) std::lexicographical_compare(c.begin(), c.end(), Iter(a), Iter(a+1));
+ (void) std::lexicographical_compare(Iter(a), Iter(a+1), c.begin(), c.end());
+}
@@ -26,28 +26,28 @@
using __gnu_test::test_container;
using __gnu_test::random_access_iterator_wrapper;
typedef test_container<int, random_access_iterator_wrapper> Container;
void test01()
{
std::vector<int> v = {
207089,
202585,
180067,
157549,
211592,
216096,
207089
};
Container con(v.data(), v.data() + 7);
- std::nth_element(con.begin(), con.begin() + 3, con.end());
+ std::nth_element(con.begin(), std::next(con.begin(), 3), con.end());
}
int main()
{
test01();
return 0;
}
@@ -21,41 +21,41 @@
#include <algorithm>
#include <random>
#include <ranges>
#include <testsuite_hooks.h>
#include <testsuite_iterators.h>
using __gnu_test::test_container;
using __gnu_test::test_range;
using __gnu_test::random_access_iterator_wrapper;
namespace ranges = std::ranges;
void
test01()
{
int x[50];
std::iota(x, x+50, 0);
auto pred = std::greater{};
auto proj = [] (int a) { return -a; };
- for (int i = 0; i < 50; i++)
+ for (std::ptrdiff_t i = 0; i < 50; i++)
{
test_range<int, random_access_iterator_wrapper> rx(x);
std::ranlux48_base g(i);
ranges::shuffle(rx, g);
auto result = ranges::nth_element(rx, rx.begin()+i, pred, proj);
VERIFY( result == rx.end() );
VERIFY( x[i] == i );
for (int j = 0; j < i; j++)
for (int k = i; k < 50; k++)
VERIFY( !pred(proj(x[k]), proj(x[j])) );
result = ranges::nth_element(rx, rx.begin()+i, pred);
VERIFY( result == rx.end() );
VERIFY( x[i] == 49-i );
for (int j = 0; j < i; j++)
for (int k = i; k < 50; k++)
VERIFY( !pred(x[k], x[j]) );
}
}
new file mode 100644
@@ -0,0 +1,13 @@
+// { dg-do compile { target c++11 } }
+
+#include <algorithm>
+#include <testsuite_iterators.h>
+
+void
+test_pr121890()
+{
+ // algorithms do not use iterator's difference_type for arithmetic
+ int a[1] = { };
+ __gnu_test::random_access_container<int> c(a);
+ std::nth_element(c.begin(), c.begin(), c.end());
+}
@@ -20,42 +20,42 @@
// { dg-require-cstdint "" }
// 25.4.2 [lib.alg.nth.element]
#include <algorithm>
#include <random>
#include <testsuite_hooks.h>
#include <testsuite_iterators.h>
#include <testsuite_containergen.h>
using __gnu_test::test_container;
using __gnu_test::random_access_iterator_wrapper;
typedef test_container<int, random_access_iterator_wrapper> Container;
struct testNthElement
{
template<typename Container, typename RandomGen>
void operator()(Container con, RandomGen& rg)
{
- const int size = con.end() - con.begin();
+ const auto size = con.end() - con.begin();
auto dist = std::uniform_int_distribution<>(0, size);
- const int element = dist(rg);
+ const decltype(size) element = dist(rg);
std::nth_element(con.begin(), con.begin() + element, con.end());
if (element < size)
{
for (int i = 0; i < element; ++i)
VERIFY( con.val(i) <= con.val(element) );
for (int i = element + 1; i < size; ++i)
VERIFY( con.val(i) >= con.val(element) );
}
}
};
int
main()
{
__gnu_test::test_containers<Container>(testNthElement());
}
@@ -26,57 +26,57 @@
#undef _GLIBCXX_PARALLEL
#include <algorithm>
#include <testsuite_hooks.h>
#include <testsuite_iterators.h>
#include <testsuite_rvalref.h>
using __gnu_test::test_container;
using __gnu_test::random_access_iterator_wrapper;
typedef __gnu_test::rvalstruct_compare_by_value V;
typedef test_container<V, random_access_iterator_wrapper> Container;
void
test01()
{
V s1[] = { 10, 20, 1, 11, 2, 12, 3, 13, 4, 14, 5, 15, 6, 16, 7,
17, 8, 18, 9, 19 };
const int N = sizeof(s1) / sizeof(V);
Container con(s1, s1 + N);
- std::partial_sort(con.begin(), con.begin() + 10, con.end());
+ std::partial_sort(con.begin(), std::next(con.begin(), 10), con.end());
VERIFY( s1[0].ok );
for(int i = 1; i < 10; ++i)
VERIFY( s1[i].val > s1[i - 1].val && s1[i].ok );
for(int i = 10; i < N; ++i)
VERIFY( s1[i].val > s1[9].val && s1[i].ok );
}
void
test02()
{
V s1[] = { 10, 20, 1, 11, 2, 12, 3, 13, 4, 14, 5, 15, 6, 16, 7,
17, 8, 18, 9, 19 };
const int N = sizeof(s1) / sizeof(V);
Container con(s1, s1 + N);
- std::partial_sort(con.begin(), con.begin() + 10, con.end(),
+ std::partial_sort(con.begin(), std::next(con.begin(), 10), con.end(),
__gnu_test::order);
VERIFY( s1[0].ok );
for(int i = 1; i < 10; ++i)
VERIFY( s1[i].val > s1[i - 1].val && s1[i].ok );
for(int i = 10; i < N; ++i)
VERIFY( s1[i].val > s1[9].val && s1[i].ok );
}
void
test03()
{
V vvs[] = { 2, 0 };
std::partial_sort(vvs, vvs + 2, vvs + 2);
VERIFY( vvs[0].ok && vvs[0].val == 0 );
VERIFY( vvs[1].ok && vvs[1].val == 2 );
}
int
main()
{
@@ -30,41 +30,42 @@ using __gnu_test::random_access_iterator_wrapper;
namespace ranges = std::ranges;
void
test01()
{
for (unsigned size = 0; size < 50; ++size)
{
std::vector<int> vref(size);
std::iota(vref.begin(), vref.end(), 0);
std::vector<int> v1(vref), v2(vref);
test_container<int, random_access_iterator_wrapper> c
= {v1.data(), v1.data() + size};
test_range<int, random_access_iterator_wrapper> r
= {v2.data(), v2.data() + size};
std::ranlux48_base g1(size), g2(size + 1);
ranges::shuffle(c, g1);
ranges::shuffle(ranges::begin(r), ranges::end(r), g2);
- for (unsigned middle = 0; middle < std::min(size, 10U); ++middle)
+ for (std::ptrdiff_t middle = 0, end = std::min(size, 10U);
+ middle < end; ++middle)
{
auto res1 = ranges::partial_sort(c.begin(), c.begin()+middle, c.end(),
{}, std::negate<>{});
VERIFY( res1 == c.end() );
auto res2 = ranges::partial_sort(r,
ranges::begin(r)+middle,
ranges::greater{});
VERIFY( res2 == ranges::end(r) );
VERIFY( ranges::equal(c.begin(), c.begin()+middle,
r.begin(), r.begin()+middle) );
VERIFY( ranges::equal(c.begin(), c.begin()+middle,
vref.rbegin(), vref.rbegin()+middle) );
}
}
}
constexpr bool
test02()
@@ -20,41 +20,41 @@
// { dg-require-cstdint "" }
// 25.4.1.3 [lib.alg.partial.sort]
#include <algorithm>
#include <random>
#include <testsuite_hooks.h>
#include <testsuite_iterators.h>
#include <testsuite_containergen.h>
using __gnu_test::test_container;
using __gnu_test::random_access_iterator_wrapper;
typedef test_container<int, random_access_iterator_wrapper> Container;
struct testPartialSort
{
template<typename Container, typename RandomGen>
void operator()(Container con, RandomGen& rg)
{
- const int size = con.end() - con.begin();
+ const auto size = con.end() - con.begin();
auto dist = std::uniform_int_distribution<>(0, size);
- const int element = dist(rg);
+ const decltype(size) element = dist(rg);
std::partial_sort(con.begin(), con.begin() + element, con.end());
VERIFY( std::is_sorted(con.begin(), con.begin() + element) );
if (element > 0)
{
for (int i = element; i < size; ++i)
VERIFY( con.val(element - 1) <= con.val(i) );
}
}
};
int
main()
{
__gnu_test::test_containers<Container>(testPartialSort());
}
@@ -18,51 +18,51 @@
// { dg-do run { target c++20 } }
// { dg-require-cstdint "" }
#include <algorithm>
#include <random>
#include <vector>
#include <testsuite_hooks.h>
#include <testsuite_iterators.h>
using __gnu_test::test_container;
using __gnu_test::test_range;
using __gnu_test::input_iterator_wrapper;
using __gnu_test::forward_iterator_wrapper;
using __gnu_test::random_access_iterator_wrapper;
namespace ranges = std::ranges;
void
test01()
{
- for (unsigned size = 0; size < 50; ++size)
+ for (std::ptrdiff_t size = 0; size < 50; ++size)
{
std::vector<int> vref(size);
std::iota(vref.begin(), vref.end(), 0);
std::vector<int> v1(vref), v2(vref);
std::ranlux48_base g1(size), g2(size + 1);
ranges::shuffle(v1, g1);
ranges::shuffle(v2, g2);
- for (unsigned middle = 0; middle < 10; ++middle)
+ for (std::ptrdiff_t middle = 0; middle < 10; ++middle)
{
test_container<int, forward_iterator_wrapper> c
= {v1.data(), v1.data() + size};
test_range<int, input_iterator_wrapper> r
= {v2.data(), v2.data() + size};
std::vector<int> o1(middle), o2(middle);
test_range<int, random_access_iterator_wrapper> w1
= {o1.data(), o1.data()+middle};
test_range<int, random_access_iterator_wrapper> w2
= {o2.data(), o2.data()+middle};
auto [in1, out1] = ranges::partial_sort_copy(c.begin(), c.end(),
w1.begin(), w1.end(),
{},
std::negate<>{},
std::negate<>{});
VERIFY( in1 == c.end() );
VERIFY( out1 == w1.begin() + std::min(size, middle) );
@@ -21,43 +21,43 @@
// 25.4.1.4 [lib.alg.partial.sort.copy]
#include <algorithm>
#include <random>
#include <vector>
#include <testsuite_hooks.h>
#include <testsuite_iterators.h>
#include <testsuite_containergen.h>
using __gnu_test::test_container;
using __gnu_test::random_access_iterator_wrapper;
typedef test_container<int, random_access_iterator_wrapper> Container;
struct testPartialSortCopy
{
template<typename Container, typename RandomGen>
void operator()(Container con, RandomGen& rg)
{
- const int size = con.end() - con.begin();
+ const auto size = con.end() - con.begin();
auto dist = std::uniform_int_distribution<>(0, size);
- const int element = dist(rg);
+ const decltype(size) element = dist(rg);
std::vector<int> outvec(element + 1); // add +1 to avoid empty issues
Container out(outvec.data(), outvec.data() + element);
std::partial_sort_copy(con.begin(), con.end(),
out.begin(), out.begin() + element);
VERIFY( std::is_sorted(out.begin(), out.begin() + element) );
std::sort(con.begin(), con.end());
for (int i = 0; i < element; ++i)
VERIFY( con.val(i) == out.val(i) );
}
};
int
main()
{
new file mode 100644
@@ -0,0 +1,13 @@
+// { dg-do compile { target c++11 } }
+
+#include <algorithm>
+#include <testsuite_iterators.h>
+
+void
+test_pr121890()
+{
+ // algorithms do not use iterator's difference_type for arithmetic
+ int a[1] = { };
+ __gnu_test::random_access_container<int> c(a);
+ std::push_heap(c.begin(), c.end());
+}
new file mode 100644
@@ -0,0 +1,13 @@
+// { dg-do compile { target c++11 } }
+
+#include <algorithm>
+#include <testsuite_iterators.h>
+
+void
+test_pr121890()
+{
+ // algorithms do not use iterator's difference_type for arithmetic
+ int a[1] = { };
+ __gnu_test::random_access_container<int> c(a);
+ std::rotate(c.begin(), c.begin(), c.end());
+}
new file mode 100644
@@ -0,0 +1,13 @@
+// { dg-do compile { target c++11 } }
+
+#include <algorithm>
+#include <testsuite_iterators.h>
+
+void
+test_pr121890()
+{
+ // algorithms do not use iterator's difference_type for arithmetic
+ int a[1] = { };
+ __gnu_test::random_access_container<int> c(a);
+ (void) std::search_n(c.begin(), c.begin(), 1U, 0);
+}
new file mode 100644
@@ -0,0 +1,13 @@
+// { dg-do compile { target c++11 } }
+
+#include <algorithm>
+#include <testsuite_iterators.h>
+
+void
+test_pr121890()
+{
+ // algorithms do not use iterator's difference_type for arithmetic
+ int a[1] = { };
+ __gnu_test::random_access_container<int> c(a);
+ std::sort(c.begin(), c.begin());
+}
@@ -226,41 +226,41 @@ test08()
short a[10]{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
test_range<short, ra_test_wrapper> ra(a);
static_assert( ranges::random_access_range<decltype(ra)> );
ranges::subrange nonsized = {ra.begin(), std::unreachable_sentinel};
using Nonsized = decltype(nonsized);
static_assert( ranges::random_access_range<Nonsized> );
static_assert( ! ranges::sized_range<Nonsized> );
auto v1 = nonsized | views::drop(5);
VERIFY( ra_test_wrapper<short>::increment_count == 0 );
auto b1 = v1.begin();
VERIFY( ra_test_wrapper<short>::increment_count == 5 );
VERIFY( v1.begin() == b1 );
VERIFY( ra_test_wrapper<short>::increment_count == 5 );
VERIFY( *b1 == 5 );
VERIFY( *v1.begin() == 5 );
VERIFY( ra_test_wrapper<short>::increment_count == 5 );
long b[10]{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
test_range<long, ra_test_wrapper> rb(b);
- ranges::subrange sized = {rb.begin(), rb.begin()+6};
+ ranges::subrange sized = {rb.begin(), ranges::next(rb.begin(), 6)};
using Sized = decltype(sized);
static_assert( ranges::random_access_range<Sized> );
static_assert( ranges::sized_range<Sized> );
auto v2 = sized | views::drop(6);
auto b2 = v2.begin();
VERIFY( ra_test_wrapper<long>::increment_count == 0 );
VERIFY( v2.begin() == b2 );
VERIFY( ra_test_wrapper<long>::increment_count == 0 );
VERIFY( *b2 == 6 );
VERIFY( *v2.begin() == 6 );
VERIFY( ra_test_wrapper<long>::increment_count == 0 );
}
template<auto drop = views::drop>
void
test09()
{
// Verify SFINAE behavior.
extern int x[5];
int* n = 0;
@@ -590,78 +590,96 @@ namespace __gnu_test
_GLIBCXX14_CONSTEXPR
random_access_iterator_wrapper
operator-(std::ptrdiff_t n) const
{
random_access_iterator_wrapper<T> tmp = *this;
return tmp -= n;
}
_GLIBCXX14_CONSTEXPR
std::ptrdiff_t
operator-(const random_access_iterator_wrapper<T>& in) const
{
ITERATOR_VERIFY(this->SharedInfo == in.SharedInfo);
return this->ptr - in.ptr;
}
_GLIBCXX14_CONSTEXPR
T& operator[](std::ptrdiff_t n) const
{ return *(*this + n); }
+#if __cplusplus >= 201103L
+ // Ensure that the iterator's difference_type is always used.
+ template<typename D> void operator+=(D) = delete;
+ template<typename D> void operator-=(D) = delete;
+ template<typename D> void operator[](D) const = delete;
+ template<typename D>
+ typename std::enable_if<std::is_integral<D>::value>::type
+ operator-(D) const = delete;
+#endif
+
_GLIBCXX14_CONSTEXPR
bool operator<(const random_access_iterator_wrapper<T>& in) const
{
ITERATOR_VERIFY(this->SharedInfo == in.SharedInfo);
return this->ptr < in.ptr;
}
_GLIBCXX14_CONSTEXPR
bool operator>(const random_access_iterator_wrapper<T>& in) const
{
return in < *this;
}
_GLIBCXX14_CONSTEXPR
bool operator>=(const random_access_iterator_wrapper<T>& in) const
{
return !(*this < in);
}
_GLIBCXX14_CONSTEXPR
bool operator<=(const random_access_iterator_wrapper<T>& in) const
{
return !(*this > in);
}
};
template<typename T>
_GLIBCXX14_CONSTEXPR
random_access_iterator_wrapper<T>
operator+(random_access_iterator_wrapper<T> it, std::ptrdiff_t n)
{ return it += n; }
template<typename T>
_GLIBCXX14_CONSTEXPR
random_access_iterator_wrapper<T>
operator+(std::ptrdiff_t n, random_access_iterator_wrapper<T> it)
{ return it += n; }
+#if __cplusplus >= 201103L
+ // Ensure that the iterator's difference_type is always used.
+ template<typename T, typename D>
+ void operator+(random_access_iterator_wrapper<T>, D) = delete;
+ template<typename T, typename D>
+ void operator+(D, random_access_iterator_wrapper<T>) = delete;
+#endif
+
/**
* @brief A container-type class for holding iterator wrappers
* test_container takes two parameters, a class T and an iterator
* wrapper templated by T (for example forward_iterator_wrapper<T>.
* It takes two pointers representing a range and presents them as
* a container of iterators.
*/
template <class T, template<class TT> class ItType>
struct test_container
{
typename ItType<T>::ContainerType bounds;
_GLIBCXX_CONSTEXPR
test_container(T* _first, T* _last) : bounds(_first, _last)
{ }
template<std::size_t N>
explicit
_GLIBCXX_CONSTEXPR