aboutsummaryrefslogtreecommitdiff
path: root/libcxx
diff options
context:
space:
mode:
Diffstat (limited to 'libcxx')
-rw-r--r--libcxx/include/__algorithm/equal_range.h87
-rw-r--r--libcxx/include/__algorithm/includes.h58
-rw-r--r--libcxx/include/__algorithm/inplace_merge.h48
-rw-r--r--libcxx/include/__algorithm/iterator_operations.h28
-rw-r--r--libcxx/include/__algorithm/make_heap.h7
-rw-r--r--libcxx/include/__algorithm/make_projected.h15
-rw-r--r--libcxx/include/__algorithm/min_element.h44
-rw-r--r--libcxx/include/__algorithm/nth_element.h36
-rw-r--r--libcxx/include/__algorithm/partial_sort.h71
-rw-r--r--libcxx/include/__algorithm/partial_sort_copy.h12
-rw-r--r--libcxx/include/__algorithm/partition.h49
-rw-r--r--libcxx/include/__algorithm/pop_heap.h17
-rw-r--r--libcxx/include/__algorithm/push_heap.h17
-rw-r--r--libcxx/include/__algorithm/ranges_equal_range.h41
-rw-r--r--libcxx/include/__algorithm/ranges_fill.h2
-rw-r--r--libcxx/include/__algorithm/ranges_find_end.h18
-rw-r--r--libcxx/include/__algorithm/ranges_for_each_n.h1
-rw-r--r--libcxx/include/__algorithm/ranges_generate_n.h1
-rw-r--r--libcxx/include/__algorithm/ranges_includes.h60
-rw-r--r--libcxx/include/__algorithm/ranges_is_heap.h1
-rw-r--r--libcxx/include/__algorithm/ranges_iterator_concept.h51
-rw-r--r--libcxx/include/__algorithm/ranges_make_heap.h3
-rw-r--r--libcxx/include/__algorithm/ranges_min_element.h1
-rw-r--r--libcxx/include/__algorithm/ranges_nth_element.h3
-rw-r--r--libcxx/include/__algorithm/ranges_partial_sort.h77
-rw-r--r--libcxx/include/__algorithm/ranges_partition.h22
-rw-r--r--libcxx/include/__algorithm/ranges_partition_copy.h36
-rw-r--r--libcxx/include/__algorithm/ranges_partition_point.h37
-rw-r--r--libcxx/include/__algorithm/ranges_pop_heap.h3
-rw-r--r--libcxx/include/__algorithm/ranges_push_heap.h3
-rw-r--r--libcxx/include/__algorithm/ranges_set_union.h84
-rw-r--r--libcxx/include/__algorithm/ranges_shuffle.h49
-rw-r--r--libcxx/include/__algorithm/ranges_sort.h3
-rw-r--r--libcxx/include/__algorithm/ranges_sort_heap.h3
-rw-r--r--libcxx/include/__algorithm/ranges_stable_partition.h25
-rw-r--r--libcxx/include/__algorithm/ranges_stable_sort.h3
-rw-r--r--libcxx/include/__algorithm/rotate.h85
-rw-r--r--libcxx/include/__algorithm/search_n.h2
-rw-r--r--libcxx/include/__algorithm/set_union.h102
-rw-r--r--libcxx/include/__algorithm/shuffle.h25
-rw-r--r--libcxx/include/__algorithm/sift_down.h13
-rw-r--r--libcxx/include/__algorithm/sort.h268
-rw-r--r--libcxx/include/__algorithm/sort_heap.h12
-rw-r--r--libcxx/include/__algorithm/stable_partition.h95
-rw-r--r--libcxx/include/__algorithm/stable_sort.h75
-rw-r--r--libcxx/include/__algorithm/unwrap_iter.h76
-rw-r--r--libcxx/include/__algorithm/upper_bound.h64
-rw-r--r--libcxx/include/__config25
-rw-r--r--libcxx/include/__debug_utils/randomize_range.h7
-rw-r--r--libcxx/include/__format/extended_grapheme_cluster_table.h332
-rw-r--r--libcxx/include/__format/formatter_integral.h2
-rw-r--r--libcxx/include/__format/formatter_output.h111
-rw-r--r--libcxx/include/__format/formatter_string.h4
-rw-r--r--libcxx/include/__format/parser_std_format_spec.h664
-rw-r--r--libcxx/include/__format/unicode.h339
-rw-r--r--libcxx/include/__iterator/reverse_iterator.h39
-rw-r--r--libcxx/include/__locale9
-rw-r--r--libcxx/include/__random/binomial_distribution.h2
-rw-r--r--libcxx/include/__random/discrete_distribution.h2
-rw-r--r--libcxx/include/__random/geometric_distribution.h2
-rw-r--r--libcxx/include/__random/is_valid.h7
-rw-r--r--libcxx/include/__random/negative_binomial_distribution.h8
-rw-r--r--libcxx/include/__random/poisson_distribution.h2
-rw-r--r--libcxx/include/__random/uniform_int_distribution.h2
-rw-r--r--libcxx/include/algorithm122
-rw-r--r--libcxx/include/bit3
-rw-r--r--libcxx/include/format3
-rw-r--r--libcxx/include/limits4
-rw-r--r--libcxx/include/module.modulemap.in46
-rw-r--r--libcxx/include/ostream84
-rw-r--r--libcxx/include/version4
71 files changed, 2400 insertions, 1256 deletions
diff --git a/libcxx/include/__algorithm/equal_range.h b/libcxx/include/__algorithm/equal_range.h
index f30f55be64fc..42d009ebbc0f 100644
--- a/libcxx/include/__algorithm/equal_range.h
+++ b/libcxx/include/__algorithm/equal_range.h
@@ -17,9 +17,13 @@
#include <__algorithm/upper_bound.h>
#include <__config>
#include <__functional/identity.h>
+#include <__functional/invoke.h>
#include <__iterator/advance.h>
#include <__iterator/distance.h>
#include <__iterator/iterator_traits.h>
+#include <__type_traits/is_callable.h>
+#include <__type_traits/is_copy_constructible.h>
+#include <__utility/move.h>
#include <__utility/pair.h>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
@@ -28,59 +32,50 @@
_LIBCPP_BEGIN_NAMESPACE_STD
-template <class _Compare, class _ForwardIterator, class _Tp>
-_LIBCPP_CONSTEXPR_AFTER_CXX17 pair<_ForwardIterator, _ForwardIterator>
-__equal_range(_ForwardIterator __first, _ForwardIterator __last, const _Tp& __value, _Compare __comp)
-{
- typedef typename iterator_traits<_ForwardIterator>::difference_type difference_type;
- difference_type __len = _VSTD::distance(__first, __last);
- while (__len != 0)
- {
- difference_type __l2 = _VSTD::__half_positive(__len);
- _ForwardIterator __m = __first;
- _VSTD::advance(__m, __l2);
- if (__comp(*__m, __value))
- {
- __first = ++__m;
- __len -= __l2 + 1;
- }
- else if (__comp(__value, *__m))
- {
- __last = __m;
- __len = __l2;
- }
- else
- {
- auto __proj = std::__identity();
- _ForwardIterator __mp1 = __m;
- return pair<_ForwardIterator, _ForwardIterator>
- (
- _VSTD::__lower_bound_impl<_ClassicAlgPolicy>(__first, __m, __value, __comp, __proj),
- _VSTD::__upper_bound<_Compare>(++__mp1, __last, __value, __comp)
- );
- }
+template <class _AlgPolicy, class _Compare, class _Iter, class _Sent, class _Tp, class _Proj>
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17 pair<_Iter, _Iter>
+__equal_range(_Iter __first, _Sent __last, const _Tp& __value, _Compare&& __comp, _Proj&& __proj) {
+ auto __len = _IterOps<_AlgPolicy>::distance(__first, __last);
+ _Iter __end = _IterOps<_AlgPolicy>::next(__first, __last);
+ while (__len != 0) {
+ auto __half_len = std::__half_positive(__len);
+ _Iter __mid = _IterOps<_AlgPolicy>::next(__first, __half_len);
+ if (std::__invoke(__comp, std::__invoke(__proj, *__mid), __value)) {
+ __first = ++__mid;
+ __len -= __half_len + 1;
+ } else if (std::__invoke(__comp, __value, std::__invoke(__proj, *__mid))) {
+ __end = __mid;
+ __len = __half_len;
+ } else {
+ _Iter __mp1 = __mid;
+ return pair<_Iter, _Iter>(
+ std::__lower_bound_impl<_AlgPolicy>(__first, __mid, __value, __comp, __proj),
+ std::__upper_bound<_AlgPolicy>(++__mp1, __end, __value, __comp, __proj));
}
- return pair<_ForwardIterator, _ForwardIterator>(__first, __first);
+ }
+ return pair<_Iter, _Iter>(__first, __first);
}
template <class _ForwardIterator, class _Tp, class _Compare>
-_LIBCPP_NODISCARD_EXT inline
-_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
-pair<_ForwardIterator, _ForwardIterator>
-equal_range(_ForwardIterator __first, _ForwardIterator __last, const _Tp& __value, _Compare __comp)
-{
- typedef typename __comp_ref_type<_Compare>::type _Comp_ref;
- return _VSTD::__equal_range<_Comp_ref>(__first, __last, __value, __comp);
+_LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17 pair<_ForwardIterator, _ForwardIterator>
+equal_range(_ForwardIterator __first, _ForwardIterator __last, const _Tp& __value, _Compare __comp) {
+ static_assert(__is_callable<_Compare, decltype(*__first), const _Tp&>::value,
+ "The comparator has to be callable");
+ static_assert(is_copy_constructible<_ForwardIterator>::value,
+ "Iterator has to be copy constructible");
+ typedef typename __comp_ref_type<_Compare>::type _Comp_ref;
+ return std::__equal_range<_ClassicAlgPolicy>(
+ std::move(__first), std::move(__last), __value, static_cast<_Comp_ref>(__comp), std::__identity());
}
template <class _ForwardIterator, class _Tp>
-_LIBCPP_NODISCARD_EXT inline
-_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
-pair<_ForwardIterator, _ForwardIterator>
-equal_range(_ForwardIterator __first, _ForwardIterator __last, const _Tp& __value)
-{
- return _VSTD::equal_range(__first, __last, __value,
- __less<typename iterator_traits<_ForwardIterator>::value_type, _Tp>());
+_LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17 pair<_ForwardIterator, _ForwardIterator>
+equal_range(_ForwardIterator __first, _ForwardIterator __last, const _Tp& __value) {
+ return std::equal_range(
+ std::move(__first),
+ std::move(__last),
+ __value,
+ __less<typename iterator_traits<_ForwardIterator>::value_type, _Tp>());
}
_LIBCPP_END_NAMESPACE_STD
diff --git a/libcxx/include/__algorithm/includes.h b/libcxx/include/__algorithm/includes.h
index 4c87e8d22116..102d3db39a2d 100644
--- a/libcxx/include/__algorithm/includes.h
+++ b/libcxx/include/__algorithm/includes.h
@@ -13,6 +13,7 @@
#include <__algorithm/comp_ref_type.h>
#include <__config>
#include <__iterator/iterator_traits.h>
+#include <__utility/move.h>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
@@ -20,41 +21,40 @@
_LIBCPP_BEGIN_NAMESPACE_STD
-template <class _Compare, class _InputIterator1, class _InputIterator2>
-_LIBCPP_CONSTEXPR_AFTER_CXX17 bool
-__includes(_InputIterator1 __first1, _InputIterator1 __last1, _InputIterator2 __first2, _InputIterator2 __last2,
- _Compare __comp)
-{
- for (; __first2 != __last2; ++__first1)
- {
- if (__first1 == __last1 || __comp(*__first2, *__first1))
- return false;
- if (!__comp(*__first1, *__first2))
- ++__first2;
- }
- return true;
+template <class _Iter1, class _Sent1, class _Iter2, class _Sent2, class _Comp>
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17 bool
+__includes(_Iter1 __first1, _Sent1 __last1, _Iter2 __first2, _Sent2 __last2, _Comp&& __comp) {
+ for (; __first2 != __last2; ++__first1) {
+ if (__first1 == __last1 || __comp(*__first2, *__first1))
+ return false;
+ if (!__comp(*__first1, *__first2))
+ ++__first2;
+ }
+ return true;
}
template <class _InputIterator1, class _InputIterator2, class _Compare>
-_LIBCPP_NODISCARD_EXT inline
-_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
-bool
-includes(_InputIterator1 __first1, _InputIterator1 __last1, _InputIterator2 __first2, _InputIterator2 __last2,
- _Compare __comp)
-{
- typedef typename __comp_ref_type<_Compare>::type _Comp_ref;
- return _VSTD::__includes<_Comp_ref>(__first1, __last1, __first2, __last2, __comp);
+_LIBCPP_NODISCARD_EXT inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17 bool includes(
+ _InputIterator1 __first1,
+ _InputIterator1 __last1,
+ _InputIterator2 __first2,
+ _InputIterator2 __last2,
+ _Compare __comp) {
+ typedef typename __comp_ref_type<_Compare>::type _Comp_ref;
+ return std::__includes(
+ std::move(__first1), std::move(__last1), std::move(__first2), std::move(__last2), static_cast<_Comp_ref>(__comp));
}
template <class _InputIterator1, class _InputIterator2>
-_LIBCPP_NODISCARD_EXT inline
-_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
-bool
-includes(_InputIterator1 __first1, _InputIterator1 __last1, _InputIterator2 __first2, _InputIterator2 __last2)
-{
- return _VSTD::includes(__first1, __last1, __first2, __last2,
- __less<typename iterator_traits<_InputIterator1>::value_type,
- typename iterator_traits<_InputIterator2>::value_type>());
+_LIBCPP_NODISCARD_EXT inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17 bool
+includes(_InputIterator1 __first1, _InputIterator1 __last1, _InputIterator2 __first2, _InputIterator2 __last2) {
+ return std::includes(
+ std::move(__first1),
+ std::move(__last1),
+ std::move(__first2),
+ std::move(__last2),
+ __less<typename iterator_traits<_InputIterator1>::value_type,
+ typename iterator_traits<_InputIterator2>::value_type>());
}
_LIBCPP_END_NAMESPACE_STD
diff --git a/libcxx/include/__algorithm/inplace_merge.h b/libcxx/include/__algorithm/inplace_merge.h
index 58919ddbae76..f4364969b8f9 100644
--- a/libcxx/include/__algorithm/inplace_merge.h
+++ b/libcxx/include/__algorithm/inplace_merge.h
@@ -11,17 +11,18 @@
#include <__algorithm/comp.h>
#include <__algorithm/comp_ref_type.h>
+#include <__algorithm/iterator_operations.h>
#include <__algorithm/lower_bound.h>
#include <__algorithm/min.h>
#include <__algorithm/move.h>
#include <__algorithm/rotate.h>
#include <__algorithm/upper_bound.h>
#include <__config>
+#include <__functional/identity.h>
#include <__iterator/advance.h>
#include <__iterator/distance.h>
#include <__iterator/iterator_traits.h>
#include <__iterator/reverse_iterator.h>
-#include <__utility/swap.h>
#include <memory>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
@@ -53,7 +54,7 @@ public:
bool operator()(const _T1& __x, const _T2& __y) {return __p_(__y, __x);}
};
-template <class _Compare, class _InputIterator1, class _InputIterator2,
+template <class _AlgPolicy, class _Compare, class _InputIterator1, class _InputIterator2,
class _OutputIterator>
void __half_inplace_merge(_InputIterator1 __first1, _InputIterator1 __last1,
_InputIterator2 __first2, _InputIterator2 __last2,
@@ -63,25 +64,26 @@ void __half_inplace_merge(_InputIterator1 __first1, _InputIterator1 __last1,
{
if (__first2 == __last2)
{
+ // TODO(alg-policy): pass `_AlgPolicy` once it's supported by `move`.
_VSTD::move(__first1, __last1, __result);
return;
}
if (__comp(*__first2, *__first1))
{
- *__result = _VSTD::move(*__first2);
+ *__result = _IterOps<_AlgPolicy>::__iter_move(__first2);
++__first2;
}
else
{
- *__result = _VSTD::move(*__first1);
+ *__result = _IterOps<_AlgPolicy>::__iter_move(__first1);
++__first1;
}
}
// __first2 through __last2 are already in the right spot.
}
-template <class _Compare, class _BidirectionalIterator>
+template <class _AlgPolicy, class _Compare, class _BidirectionalIterator>
void
__buffered_inplace_merge(_BidirectionalIterator __first, _BidirectionalIterator __middle, _BidirectionalIterator __last,
_Compare __comp, typename iterator_traits<_BidirectionalIterator>::difference_type __len1,
@@ -95,30 +97,32 @@ __buffered_inplace_merge(_BidirectionalIterator __first, _BidirectionalIterator
{
value_type* __p = __buff;
for (_BidirectionalIterator __i = __first; __i != __middle; __d.template __incr<value_type>(), (void) ++__i, (void) ++__p)
- ::new ((void*)__p) value_type(_VSTD::move(*__i));
- _VSTD::__half_inplace_merge<_Compare>(__buff, __p, __middle, __last, __first, __comp);
+ ::new ((void*)__p) value_type(_IterOps<_AlgPolicy>::__iter_move(__i));
+ std::__half_inplace_merge<_AlgPolicy, _Compare>(__buff, __p, __middle, __last, __first, __comp);
}
else
{
value_type* __p = __buff;
for (_BidirectionalIterator __i = __middle; __i != __last; __d.template __incr<value_type>(), (void) ++__i, (void) ++__p)
- ::new ((void*)__p) value_type(_VSTD::move(*__i));
+ ::new ((void*)__p) value_type(_IterOps<_AlgPolicy>::__iter_move(__i));
typedef reverse_iterator<_BidirectionalIterator> _RBi;
typedef reverse_iterator<value_type*> _Rv;
typedef __invert<_Compare> _Inverted;
- _VSTD::__half_inplace_merge<_Inverted>(_Rv(__p), _Rv(__buff),
+ std::__half_inplace_merge<_AlgPolicy, _Inverted>(_Rv(__p), _Rv(__buff),
_RBi(__middle), _RBi(__first),
_RBi(__last), _Inverted(__comp));
}
}
-template <class _Compare, class _BidirectionalIterator>
+template <class _AlgPolicy, class _Compare, class _BidirectionalIterator>
void
__inplace_merge(_BidirectionalIterator __first, _BidirectionalIterator __middle, _BidirectionalIterator __last,
_Compare __comp, typename iterator_traits<_BidirectionalIterator>::difference_type __len1,
typename iterator_traits<_BidirectionalIterator>::difference_type __len2,
typename iterator_traits<_BidirectionalIterator>::value_type* __buff, ptrdiff_t __buff_size)
{
+ using _Ops = _IterOps<_AlgPolicy>;
+
typedef typename iterator_traits<_BidirectionalIterator>::difference_type difference_type;
while (true)
{
@@ -126,7 +130,7 @@ __inplace_merge(_BidirectionalIterator __first, _BidirectionalIterator __middle,
if (__len2 == 0)
return;
if (__len1 <= __buff_size || __len2 <= __buff_size)
- return _VSTD::__buffered_inplace_merge<_Compare>
+ return std::__buffered_inplace_merge<_AlgPolicy, _Compare>
(__first, __middle, __last, __comp, __len1, __len2, __buff);
// shrink [__first, __middle) as much as possible (with no moves), returning if it shrinks to 0
for (; true; ++__first, (void) --__len1)
@@ -153,35 +157,38 @@ __inplace_merge(_BidirectionalIterator __first, _BidirectionalIterator __middle,
{ // __len >= 1, __len2 >= 2
__len21 = __len2 / 2;
__m2 = __middle;
- _VSTD::advance(__m2, __len21);
- __m1 = _VSTD::__upper_bound<_Compare>(__first, __middle, *__m2, __comp);
- __len11 = _VSTD::distance(__first, __m1);
+ _Ops::advance(__m2, __len21);
+ // TODO: replace _ClassicAlgPolicy and __identity with _AlgPolicy and projection
+ __m1 = std::__upper_bound<_ClassicAlgPolicy>(__first, __middle, *__m2, __comp, std::__identity());
+ __len11 = _Ops::distance(__first, __m1);
}
else
{
if (__len1 == 1)
{ // __len1 >= __len2 && __len2 > 0, therefore __len2 == 1
// It is known *__first > *__middle
- swap(*__first, *__middle);
+ _Ops::iter_swap(__first, __middle);
return;
}
// __len1 >= 2, __len2 >= 1
__len11 = __len1 / 2;
__m1 = __first;
- _VSTD::advance(__m1, __len11);
+ _Ops::advance(__m1, __len11);
__m2 = std::lower_bound(__middle, __last, *__m1, __comp);
- __len21 = _VSTD::distance(__middle, __m2);
+ __len21 = _Ops::distance(__middle, __m2);
}
difference_type __len12 = __len1 - __len11; // distance(__m1, __middle)
difference_type __len22 = __len2 - __len21; // distance(__m2, __last)
// [__first, __m1) [__m1, __middle) [__middle, __m2) [__m2, __last)
// swap middle two partitions
+ // TODO(alg-policy): pass `_AlgPolicy` once it's supported by `rotate`.
__middle = _VSTD::rotate(__m1, __middle, __m2);
// __len12 and __len21 now have swapped meanings
// merge smaller range with recursive call and larger with tail recursion elimination
if (__len11 + __len21 < __len12 + __len22)
{
- _VSTD::__inplace_merge<_Compare>(__first, __m1, __middle, __comp, __len11, __len21, __buff, __buff_size);
+ std::__inplace_merge<_AlgPolicy, _Compare>(
+ __first, __m1, __middle, __comp, __len11, __len21, __buff, __buff_size);
// _VSTD::__inplace_merge<_Compare>(__middle, __m2, __last, __comp, __len12, __len22, __buff, __buff_size);
__first = __middle;
__middle = __m2;
@@ -190,7 +197,8 @@ __inplace_merge(_BidirectionalIterator __first, _BidirectionalIterator __middle,
}
else
{
- _VSTD::__inplace_merge<_Compare>(__middle, __m2, __last, __comp, __len12, __len22, __buff, __buff_size);
+ std::__inplace_merge<_AlgPolicy, _Compare>(
+ __middle, __m2, __last, __comp, __len12, __len22, __buff, __buff_size);
// _VSTD::__inplace_merge<_Compare>(__first, __m1, __middle, __comp, __len11, __len21, __buff, __buff_size);
__last = __middle;
__middle = __m1;
@@ -217,7 +225,7 @@ _LIBCPP_SUPPRESS_DEPRECATED_PUSH
_LIBCPP_SUPPRESS_DEPRECATED_POP
unique_ptr<value_type, __return_temporary_buffer> __h(__buf.first);
typedef typename __comp_ref_type<_Compare>::type _Comp_ref;
- return _VSTD::__inplace_merge<_Comp_ref>(__first, __middle, __last, __comp, __len1, __len2,
+ return _VSTD::__inplace_merge<_ClassicAlgPolicy, _Comp_ref>(__first, __middle, __last, __comp, __len1, __len2,
__buf.first, __buf.second);
}
diff --git a/libcxx/include/__algorithm/iterator_operations.h b/libcxx/include/__algorithm/iterator_operations.h
index eb627e1ace7a..8307d71214e5 100644
--- a/libcxx/include/__algorithm/iterator_operations.h
+++ b/libcxx/include/__algorithm/iterator_operations.h
@@ -41,6 +41,7 @@ struct _IterOps<_RangeAlgPolicy> {
static constexpr auto next = ranges::next;
static constexpr auto __advance_to = ranges::advance;
};
+
#endif
struct _ClassicAlgPolicy {};
@@ -65,11 +66,24 @@ struct _IterOps<_ClassicAlgPolicy> {
// iter_move
template <class _Iter>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX11
- // Declaring the return type is necessary for the C++03 mode (which doesn't support placeholder return types).
- static typename iterator_traits<__uncvref_t<_Iter> >::value_type&& __iter_move(_Iter&& __i) {
+ // Declaring the return type is necessary for C++03, so we basically mirror what `decltype(auto)` would deduce.
+ static __enable_if_t<
+ is_reference<typename iterator_traits<__uncvref_t<_Iter> >::reference>::value,
+ typename remove_reference< typename iterator_traits<__uncvref_t<_Iter> >::reference >::type&&>
+ __iter_move(_Iter&& __i) {
return std::move(*std::forward<_Iter>(__i));
}
+ template <class _Iter>
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX11
+ // Declaring the return type is necessary for C++03, so we basically mirror what `decltype(auto)` would deduce.
+ static __enable_if_t<
+ !is_reference<typename iterator_traits<__uncvref_t<_Iter> >::reference>::value,
+ typename iterator_traits<__uncvref_t<_Iter> >::reference>
+ __iter_move(_Iter&& __i) {
+ return *std::forward<_Iter>(__i);
+ }
+
// iter_swap
template <class _Iter1, class _Iter2>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX11
@@ -85,7 +99,15 @@ struct _IterOps<_ClassicAlgPolicy> {
}
template <class _Iter>
- _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR_AFTER_CXX11 void __advance_to(_Iter& __first, _Iter __last) {
+ _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR_AFTER_CXX11
+ __uncvref_t<_Iter> next(_Iter&& __it,
+ typename iterator_traits<__uncvref_t<_Iter> >::difference_type __n = 1){
+ return std::next(std::forward<_Iter>(__it), __n);
+ }
+
+ template <class _Iter>
+ _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR_AFTER_CXX11
+ void __advance_to(_Iter& __first, _Iter __last) {
__first = __last;
}
};
diff --git a/libcxx/include/__algorithm/make_heap.h b/libcxx/include/__algorithm/make_heap.h
index bc39d82bf916..bf9dd96756af 100644
--- a/libcxx/include/__algorithm/make_heap.h
+++ b/libcxx/include/__algorithm/make_heap.h
@@ -11,6 +11,7 @@
#include <__algorithm/comp.h>
#include <__algorithm/comp_ref_type.h>
+#include <__algorithm/iterator_operations.h>
#include <__algorithm/sift_down.h>
#include <__config>
#include <__iterator/iterator_traits.h>
@@ -22,7 +23,7 @@
_LIBCPP_BEGIN_NAMESPACE_STD
-template <class _Compare, class _RandomAccessIterator>
+template <class _AlgPolicy, class _Compare, class _RandomAccessIterator>
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX11
void __make_heap(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare& __comp) {
using _CompRef = typename __comp_ref_type<_Compare>::type;
@@ -33,7 +34,7 @@ void __make_heap(_RandomAccessIterator __first, _RandomAccessIterator __last, _C
if (__n > 1) {
// start from the first parent, there is no need to consider children
for (difference_type __start = (__n - 2) / 2; __start >= 0; --__start) {
- std::__sift_down<_CompRef>(__first, __comp_ref, __n, __first + __start);
+ std::__sift_down<_AlgPolicy, _CompRef>(__first, __comp_ref, __n, __first + __start);
}
}
}
@@ -41,7 +42,7 @@ void __make_heap(_RandomAccessIterator __first, _RandomAccessIterator __last, _C
template <class _RandomAccessIterator, class _Compare>
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17
void make_heap(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp) {
- std::__make_heap(std::move(__first), std::move(__last), __comp);
+ std::__make_heap<_ClassicAlgPolicy>(std::move(__first), std::move(__last), __comp);
}
template <class _RandomAccessIterator>
diff --git a/libcxx/include/__algorithm/make_projected.h b/libcxx/include/__algorithm/make_projected.h
index 6d8ebfd3d90e..64fc3dfb6a12 100644
--- a/libcxx/include/__algorithm/make_projected.h
+++ b/libcxx/include/__algorithm/make_projected.h
@@ -27,6 +27,21 @@ _LIBCPP_BEGIN_NAMESPACE_STD
namespace ranges {
+template <class _Pred, class _Proj>
+_LIBCPP_HIDE_FROM_ABI constexpr static
+decltype(auto) __make_projected_pred(_Pred& __pred, _Proj& __proj) {
+ if constexpr (same_as<decay_t<_Proj>, identity> && !is_member_pointer_v<decay_t<_Pred>>) {
+ // Avoid creating the lambda and just use the pristine predicate -- for certain algorithms, this would enable
+ // optimizations that rely on the type of the predicate.
+ return __pred;
+
+ } else {
+ return [&](auto&& __x) {
+ return std::invoke(__pred, std::invoke(__proj, std::forward<decltype(__x)>(__x)));
+ };
+ }
+}
+
template <class _Comp, class _Proj>
_LIBCPP_HIDE_FROM_ABI constexpr static
decltype(auto) __make_projected_comp(_Comp& __comp, _Proj& __proj) {
diff --git a/libcxx/include/__algorithm/min_element.h b/libcxx/include/__algorithm/min_element.h
index 129833d42bda..17b242c341e6 100644
--- a/libcxx/include/__algorithm/min_element.h
+++ b/libcxx/include/__algorithm/min_element.h
@@ -12,7 +12,11 @@
#include <__algorithm/comp.h>
#include <__algorithm/comp_ref_type.h>
#include <__config>
+#include <__functional/identity.h>
+#include <__functional/invoke.h>
#include <__iterator/iterator_traits.h>
+#include <__type_traits/is_callable.h>
+#include <__utility/move.h>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
@@ -20,28 +24,38 @@
_LIBCPP_BEGIN_NAMESPACE_STD
-template <class _Compare, class _ForwardIterator>
-inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX11 _ForwardIterator
-__min_element(_ForwardIterator __first, _ForwardIterator __last, _Compare __comp)
-{
- static_assert(__is_cpp17_forward_iterator<_ForwardIterator>::value,
- "std::min_element requires a ForwardIterator");
- if (__first != __last)
- {
- _ForwardIterator __i = __first;
- while (++__i != __last)
- if (__comp(*__i, *__first))
- __first = __i;
- }
+template <class _Comp, class _Iter, class _Sent, class _Proj>
+inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX11
+_Iter __min_element(_Iter __first, _Sent __last, _Comp __comp, _Proj& __proj) {
+ if (__first == __last)
return __first;
+
+ _Iter __i = __first;
+ while (++__i != __last)
+ if (std::__invoke(__comp, std::__invoke(__proj, *__i), std::__invoke(__proj, *__first)))
+ __first = __i;
+
+ return __first;
+}
+
+template <class _Comp, class _Iter, class _Sent>
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX11
+_Iter __min_element(_Iter __first, _Sent __last, _Comp __comp) {
+ auto __proj = __identity();
+ return std::__min_element<_Comp>(std::move(__first), std::move(__last), __comp, __proj);
}
template <class _ForwardIterator, class _Compare>
_LIBCPP_NODISCARD_EXT inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX11 _ForwardIterator
min_element(_ForwardIterator __first, _ForwardIterator __last, _Compare __comp)
{
- typedef typename __comp_ref_type<_Compare>::type _Comp_ref;
- return _VSTD::__min_element<_Comp_ref>(__first, __last, __comp);
+ static_assert(__is_cpp17_forward_iterator<_ForwardIterator>::value,
+ "std::min_element requires a ForwardIterator");
+ static_assert(__is_callable<_Compare, decltype(*__first), decltype(*__first)>::value,
+ "The comparator has to be callable");
+
+ typedef typename __comp_ref_type<_Compare>::type _Comp_ref;
+ return std::__min_element<_Comp_ref>(std::move(__first), std::move(__last), __comp);
}
template <class _ForwardIterator>
diff --git a/libcxx/include/__algorithm/nth_element.h b/libcxx/include/__algorithm/nth_element.h
index c7cdef5be817..688398dee814 100644
--- a/libcxx/include/__algorithm/nth_element.h
+++ b/libcxx/include/__algorithm/nth_element.h
@@ -11,13 +11,13 @@
#include <__algorithm/comp.h>
#include <__algorithm/comp_ref_type.h>
+#include <__algorithm/iterator_operations.h>
#include <__algorithm/sort.h>
#include <__config>
#include <__debug>
#include <__debug_utils/randomize_range.h>
#include <__iterator/iterator_traits.h>
#include <__utility/move.h>
-#include <__utility/swap.h>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
@@ -41,10 +41,12 @@ __nth_element_find_guard(_RandomAccessIterator& __i, _RandomAccessIterator& __j,
}
}
-template <class _Compare, class _RandomAccessIterator>
+template <class _AlgPolicy, class _Compare, class _RandomAccessIterator>
_LIBCPP_CONSTEXPR_AFTER_CXX11 void
__nth_element(_RandomAccessIterator __first, _RandomAccessIterator __nth, _RandomAccessIterator __last, _Compare __comp)
{
+ using _Ops = _IterOps<_AlgPolicy>;
+
// _Compare is known to be a reference type
typedef typename iterator_traits<_RandomAccessIterator>::difference_type difference_type;
const difference_type __limit = 7;
@@ -60,24 +62,24 @@ __nth_element(_RandomAccessIterator __first, _RandomAccessIterator __nth, _Rando
return;
case 2:
if (__comp(*--__last, *__first))
- swap(*__first, *__last);
+ _Ops::iter_swap(__first, __last);
return;
case 3:
{
_RandomAccessIterator __m = __first;
- _VSTD::__sort3<_Compare>(__first, ++__m, --__last, __comp);
+ std::__sort3<_AlgPolicy, _Compare>(__first, ++__m, --__last, __comp);
return;
}
}
if (__len <= __limit)
{
- _VSTD::__selection_sort<_Compare>(__first, __last, __comp);
+ std::__selection_sort<_AlgPolicy, _Compare>(__first, __last, __comp);
return;
}
// __len > __limit >= 3
_RandomAccessIterator __m = __first + __len/2;
_RandomAccessIterator __lm1 = __last;
- unsigned __n_swaps = _VSTD::__sort3<_Compare>(__first, __m, --__lm1, __comp);
+ unsigned __n_swaps = std::__sort3<_AlgPolicy, _Compare>(__first, __m, --__lm1, __comp);
// *__m is median
// partition [__first, __m) < *__m and *__m <= [__m, __last)
// (this inhibits tossing elements equivalent to __m around unnecessarily)
@@ -90,7 +92,7 @@ __nth_element(_RandomAccessIterator __first, _RandomAccessIterator __nth, _Rando
{
// *__first == *__m, *__first doesn't go in first part
if (_VSTD::__nth_element_find_guard<_Compare>(__i, __j, __m, __comp)) {
- swap(*__i, *__j);
+ _Ops::iter_swap(__i, __j);
++__n_swaps;
} else {
// *__first == *__m, *__m <= all other elements
@@ -102,7 +104,7 @@ __nth_element(_RandomAccessIterator __first, _RandomAccessIterator __nth, _Rando
if (__i == __j) {
return; // [__first, __last) all equivalent elements
} else if (__comp(*__first, *__i)) {
- swap(*__i, *__j);
+ _Ops::iter_swap(__i, __j);
++__n_swaps;
++__i;
break;
@@ -121,7 +123,7 @@ __nth_element(_RandomAccessIterator __first, _RandomAccessIterator __nth, _Rando
;
if (__i >= __j)
break;
- swap(*__i, *__j);
+ _Ops::iter_swap(__i, __j);
++__n_swaps;
++__i;
}
@@ -152,7 +154,7 @@ __nth_element(_RandomAccessIterator __first, _RandomAccessIterator __nth, _Rando
;
if (__i >= __j)
break;
- swap(*__i, *__j);
+ _Ops::iter_swap(__i, __j);
++__n_swaps;
// It is known that __m != __j
// If __m just moved, follow it
@@ -164,7 +166,7 @@ __nth_element(_RandomAccessIterator __first, _RandomAccessIterator __nth, _Rando
// [__first, __i) < *__m and *__m <= [__i, __last)
if (__i != __m && __comp(*__m, *__i))
{
- swap(*__i, *__m);
+ _Ops::iter_swap(__i, __m);
++__n_swaps;
}
// [__first, __i) < *__i and *__i <= [__i+1, __last)
@@ -220,21 +222,21 @@ __nth_element(_RandomAccessIterator __first, _RandomAccessIterator __nth, _Rando
}
}
-template <class _RandomAccessIterator, class _Compare>
+template <class _AlgPolicy, class _RandomAccessIterator, class _Compare>
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17
void __nth_element_impl(_RandomAccessIterator __first, _RandomAccessIterator __nth, _RandomAccessIterator __last,
_Compare& __comp) {
if (__nth == __last)
return;
- std::__debug_randomize_range(__first, __last);
+ std::__debug_randomize_range<_AlgPolicy>(__first, __last);
using _Comp_ref = typename __comp_ref_type<_Compare>::type;
- std::__nth_element<_Comp_ref>(__first, __nth, __last, __comp);
+ std::__nth_element<_AlgPolicy, _Comp_ref>(__first, __nth, __last, __comp);
- std::__debug_randomize_range(__first, __nth);
+ std::__debug_randomize_range<_AlgPolicy>(__first, __nth);
if (__nth != __last) {
- std::__debug_randomize_range(++__nth, __last);
+ std::__debug_randomize_range<_AlgPolicy>(++__nth, __last);
}
}
@@ -242,7 +244,7 @@ template <class _RandomAccessIterator, class _Compare>
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17
void nth_element(_RandomAccessIterator __first, _RandomAccessIterator __nth, _RandomAccessIterator __last,
_Compare __comp) {
- std::__nth_element_impl(std::move(__first), std::move(__nth), std::move(__last), __comp);
+ std::__nth_element_impl<_ClassicAlgPolicy>(std::move(__first), std::move(__nth), std::move(__last), __comp);
}
template <class _RandomAccessIterator>
diff --git a/libcxx/include/__algorithm/partial_sort.h b/libcxx/include/__algorithm/partial_sort.h
index e008c0c99679..24016e5cf5a5 100644
--- a/libcxx/include/__algorithm/partial_sort.h
+++ b/libcxx/include/__algorithm/partial_sort.h
@@ -11,6 +11,7 @@
#include <__algorithm/comp.h>
#include <__algorithm/comp_ref_type.h>
+#include <__algorithm/iterator_operations.h>
#include <__algorithm/make_heap.h>
#include <__algorithm/sift_down.h>
#include <__algorithm/sort_heap.h>
@@ -18,7 +19,8 @@
#include <__debug>
#include <__debug_utils/randomize_range.h>
#include <__iterator/iterator_traits.h>
-#include <__utility/swap.h>
+#include <__utility/move.h>
+#include <type_traits>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
@@ -26,24 +28,47 @@
_LIBCPP_BEGIN_NAMESPACE_STD
-template <class _Compare, class _RandomAccessIterator>
-_LIBCPP_CONSTEXPR_AFTER_CXX17 void
-__partial_sort(_RandomAccessIterator __first, _RandomAccessIterator __middle, _RandomAccessIterator __last,
- _Compare __comp)
-{
- if (__first == __middle)
- return;
- _VSTD::__make_heap<_Compare>(__first, __middle, __comp);
- typename iterator_traits<_RandomAccessIterator>::difference_type __len = __middle - __first;
- for (_RandomAccessIterator __i = __middle; __i != __last; ++__i)
- {
- if (__comp(*__i, *__first))
- {
- swap(*__i, *__first);
- _VSTD::__sift_down<_Compare>(__first, __comp, __len, __first);
- }
- }
- _VSTD::__sort_heap<_Compare>(__first, __middle, __comp);
+template <class _AlgPolicy, class _Compare, class _RandomAccessIterator, class _Sentinel>
+_LIBCPP_CONSTEXPR_AFTER_CXX17
+_RandomAccessIterator __partial_sort_impl(
+ _RandomAccessIterator __first, _RandomAccessIterator __middle, _Sentinel __last, _Compare __comp) {
+ if (__first == __middle) {
+ return _IterOps<_AlgPolicy>::next(__middle, __last);
+ }
+
+ std::__make_heap<_AlgPolicy, _Compare>(__first, __middle, __comp);
+
+ typename iterator_traits<_RandomAccessIterator>::difference_type __len = __middle - __first;
+ _RandomAccessIterator __i = __middle;
+ for (; __i != __last; ++__i)
+ {
+ if (__comp(*__i, *__first))
+ {
+ _IterOps<_AlgPolicy>::iter_swap(__i, __first);
+ std::__sift_down<_AlgPolicy, _Compare>(__first, __comp, __len, __first);
+ }
+
+ }
+ std::__sort_heap<_AlgPolicy, _Compare>(std::move(__first), std::move(__middle), __comp);
+
+ return __i;
+}
+
+template <class _AlgPolicy, class _Compare, class _RandomAccessIterator, class _Sentinel>
+_LIBCPP_CONSTEXPR_AFTER_CXX17
+_RandomAccessIterator __partial_sort(_RandomAccessIterator __first, _RandomAccessIterator __middle, _Sentinel __last,
+ _Compare& __comp) {
+ if (__first == __middle)
+ return _IterOps<_AlgPolicy>::next(__middle, __last);
+
+ std::__debug_randomize_range<_AlgPolicy>(__first, __last);
+
+ using _Comp_ref = typename __comp_ref_type<_Compare>::type;
+ auto __last_iter = std::__partial_sort_impl<_AlgPolicy, _Comp_ref>(__first, __middle, __last, __comp);
+
+ std::__debug_randomize_range<_AlgPolicy>(__middle, __last);
+
+ return __last_iter;
}
template <class _RandomAccessIterator, class _Compare>
@@ -52,10 +77,10 @@ void
partial_sort(_RandomAccessIterator __first, _RandomAccessIterator __middle, _RandomAccessIterator __last,
_Compare __comp)
{
- std::__debug_randomize_range(__first, __last);
- typedef typename __comp_ref_type<_Compare>::type _Comp_ref;
- _VSTD::__partial_sort<_Comp_ref>(__first, __middle, __last, __comp);
- std::__debug_randomize_range(__middle, __last);
+ static_assert(std::is_copy_constructible<_RandomAccessIterator>::value, "Iterators must be copy constructible.");
+ static_assert(std::is_copy_assignable<_RandomAccessIterator>::value, "Iterators must be copy assignable.");
+
+ (void)std::__partial_sort<_ClassicAlgPolicy>(std::move(__first), std::move(__middle), std::move(__last), __comp);
}
template <class _RandomAccessIterator>
diff --git a/libcxx/include/__algorithm/partial_sort_copy.h b/libcxx/include/__algorithm/partial_sort_copy.h
index 7ed1e538e9b8..3556764e652d 100644
--- a/libcxx/include/__algorithm/partial_sort_copy.h
+++ b/libcxx/include/__algorithm/partial_sort_copy.h
@@ -11,6 +11,7 @@
#include <__algorithm/comp.h>
#include <__algorithm/comp_ref_type.h>
+#include <__algorithm/iterator_operations.h>
#include <__algorithm/make_heap.h>
#include <__algorithm/sift_down.h>
#include <__algorithm/sort_heap.h>
@@ -23,7 +24,7 @@
_LIBCPP_BEGIN_NAMESPACE_STD
-template <class _Compare, class _InputIterator, class _RandomAccessIterator>
+template <class _AlgPolicy, class _Compare, class _InputIterator, class _RandomAccessIterator>
_LIBCPP_CONSTEXPR_AFTER_CXX17 _RandomAccessIterator
__partial_sort_copy(_InputIterator __first, _InputIterator __last,
_RandomAccessIterator __result_first, _RandomAccessIterator __result_last, _Compare __comp)
@@ -33,15 +34,15 @@ __partial_sort_copy(_InputIterator __first, _InputIterator __last,
{
for (; __first != __last && __r != __result_last; ++__first, (void) ++__r)
*__r = *__first;
- _VSTD::__make_heap<_Compare>(__result_first, __r, __comp);
+ std::__make_heap<_AlgPolicy, _Compare>(__result_first, __r, __comp);
typename iterator_traits<_RandomAccessIterator>::difference_type __len = __r - __result_first;
for (; __first != __last; ++__first)
if (__comp(*__first, *__result_first))
{
*__result_first = *__first;
- _VSTD::__sift_down<_Compare>(__result_first, __comp, __len, __result_first);
+ std::__sift_down<_AlgPolicy, _Compare>(__result_first, __comp, __len, __result_first);
}
- _VSTD::__sort_heap<_Compare>(__result_first, __r, __comp);
+ std::__sort_heap<_AlgPolicy, _Compare>(__result_first, __r, __comp);
}
return __r;
}
@@ -53,7 +54,8 @@ partial_sort_copy(_InputIterator __first, _InputIterator __last,
_RandomAccessIterator __result_first, _RandomAccessIterator __result_last, _Compare __comp)
{
typedef typename __comp_ref_type<_Compare>::type _Comp_ref;
- return _VSTD::__partial_sort_copy<_Comp_ref>(__first, __last, __result_first, __result_last, __comp);
+ return std::__partial_sort_copy<_ClassicAlgPolicy, _Comp_ref>(
+ __first, __last, __result_first, __result_last, __comp);
}
template <class _InputIterator, class _RandomAccessIterator>
diff --git a/libcxx/include/__algorithm/partition.h b/libcxx/include/__algorithm/partition.h
index 73d94831ed87..60b4e290ebeb 100644
--- a/libcxx/include/__algorithm/partition.h
+++ b/libcxx/include/__algorithm/partition.h
@@ -9,9 +9,12 @@
#ifndef _LIBCPP___ALGORITHM_PARTITION_H
#define _LIBCPP___ALGORITHM_PARTITION_H
+#include <__algorithm/iterator_operations.h>
#include <__config>
#include <__iterator/iterator_traits.h>
-#include <__utility/swap.h>
+#include <__utility/move.h>
+#include <__utility/pair.h>
+#include <type_traits>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
@@ -19,40 +22,45 @@
_LIBCPP_BEGIN_NAMESPACE_STD
-template <class _Predicate, class _ForwardIterator>
-_LIBCPP_CONSTEXPR_AFTER_CXX17 _ForwardIterator
-__partition(_ForwardIterator __first, _ForwardIterator __last, _Predicate __pred, forward_iterator_tag)
+template <class _Predicate, class _AlgPolicy, class _ForwardIterator, class _Sentinel>
+_LIBCPP_CONSTEXPR_AFTER_CXX17 pair<_ForwardIterator, _ForwardIterator>
+__partition_impl(_ForwardIterator __first, _Sentinel __last, _Predicate __pred, forward_iterator_tag)
{
while (true)
{
if (__first == __last)
- return __first;
+ return std::make_pair(std::move(__first), std::move(__first));
if (!__pred(*__first))
break;
++__first;
}
- for (_ForwardIterator __p = __first; ++__p != __last;)
+
+ _ForwardIterator __p = __first;
+ while (++__p != __last)
{
if (__pred(*__p))
{
- swap(*__first, *__p);
+ _IterOps<_AlgPolicy>::iter_swap(__first, __p);
++__first;
}
}
- return __first;
+ return std::make_pair(std::move(__first), std::move(__p));
}
-template <class _Predicate, class _BidirectionalIterator>
-_LIBCPP_CONSTEXPR_AFTER_CXX17 _BidirectionalIterator
-__partition(_BidirectionalIterator __first, _BidirectionalIterator __last, _Predicate __pred,
+template <class _Predicate, class _AlgPolicy, class _BidirectionalIterator, class _Sentinel>
+_LIBCPP_CONSTEXPR_AFTER_CXX17 pair<_BidirectionalIterator, _BidirectionalIterator>
+__partition_impl(_BidirectionalIterator __first, _Sentinel __sentinel, _Predicate __pred,
bidirectional_iterator_tag)
{
+ _BidirectionalIterator __original_last = _IterOps<_AlgPolicy>::next(__first, __sentinel);
+ _BidirectionalIterator __last = __original_last;
+
while (true)
{
while (true)
{
if (__first == __last)
- return __first;
+ return std::make_pair(std::move(__first), std::move(__original_last));
if (!__pred(*__first))
break;
++__first;
@@ -60,20 +68,29 @@ __partition(_BidirectionalIterator __first, _BidirectionalIterator __last, _Pred
do
{
if (__first == --__last)
- return __first;
+ return std::make_pair(std::move(__first), std::move(__original_last));
} while (!__pred(*__last));
- swap(*__first, *__last);
+ _IterOps<_AlgPolicy>::iter_swap(__first, __last);
++__first;
}
}
+template <class _AlgPolicy, class _ForwardIterator, class _Sentinel, class _Predicate, class _IterCategory>
+inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17
+pair<_ForwardIterator, _ForwardIterator> __partition(
+ _ForwardIterator __first, _Sentinel __last, _Predicate&& __pred, _IterCategory __iter_category) {
+ return std::__partition_impl<__uncvref_t<_Predicate>&, _AlgPolicy>(
+ std::move(__first), std::move(__last), __pred, __iter_category);
+}
+
template <class _ForwardIterator, class _Predicate>
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
_ForwardIterator
partition(_ForwardIterator __first, _ForwardIterator __last, _Predicate __pred)
{
- return _VSTD::__partition<_Predicate&>(
- __first, __last, __pred, typename iterator_traits<_ForwardIterator>::iterator_category());
+ using _IterCategory = typename iterator_traits<_ForwardIterator>::iterator_category;
+ auto __result = std::__partition<_ClassicAlgPolicy>(std::move(__first), std::move(__last), __pred, _IterCategory());
+ return __result.first;
}
_LIBCPP_END_NAMESPACE_STD
diff --git a/libcxx/include/__algorithm/pop_heap.h b/libcxx/include/__algorithm/pop_heap.h
index cadda81f6c88..870af50c133e 100644
--- a/libcxx/include/__algorithm/pop_heap.h
+++ b/libcxx/include/__algorithm/pop_heap.h
@@ -11,12 +11,14 @@
#include <__algorithm/comp.h>
#include <__algorithm/comp_ref_type.h>
+#include <__algorithm/iterator_operations.h>
#include <__algorithm/push_heap.h>
#include <__algorithm/sift_down.h>
#include <__assert>
#include <__config>
#include <__iterator/iterator_traits.h>
#include <__utility/move.h>
+#include <type_traits>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
@@ -24,7 +26,7 @@
_LIBCPP_BEGIN_NAMESPACE_STD
-template <class _Compare, class _RandomAccessIterator>
+template <class _AlgPolicy, class _Compare, class _RandomAccessIterator>
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX11
void __pop_heap(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare& __comp,
typename iterator_traits<_RandomAccessIterator>::difference_type __len) {
@@ -35,17 +37,17 @@ void __pop_heap(_RandomAccessIterator __first, _RandomAccessIterator __last, _Co
using value_type = typename iterator_traits<_RandomAccessIterator>::value_type;
if (__len > 1) {
- value_type __top = std::move(*__first); // create a hole at __first
- _RandomAccessIterator __hole = std::__floyd_sift_down<_CompRef>(__first, __comp_ref, __len);
+ value_type __top = _IterOps<_AlgPolicy>::__iter_move(__first); // create a hole at __first
+ _RandomAccessIterator __hole = std::__floyd_sift_down<_AlgPolicy, _CompRef>(__first, __comp_ref, __len);
--__last;
if (__hole == __last) {
*__hole = std::move(__top);
} else {
- *__hole = std::move(*__last);
+ *__hole = _IterOps<_AlgPolicy>::__iter_move(__last);
++__hole;
*__last = std::move(__top);
- std::__sift_up<_CompRef>(__first, __hole, __comp_ref, __hole - __first);
+ std::__sift_up<_AlgPolicy, _CompRef>(__first, __hole, __comp_ref, __hole - __first);
}
}
}
@@ -53,8 +55,11 @@ void __pop_heap(_RandomAccessIterator __first, _RandomAccessIterator __last, _Co
template <class _RandomAccessIterator, class _Compare>
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17
void pop_heap(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp) {
+ static_assert(std::is_copy_constructible<_RandomAccessIterator>::value, "Iterators must be copy constructible.");
+ static_assert(std::is_copy_assignable<_RandomAccessIterator>::value, "Iterators must be copy assignable.");
+
typename iterator_traits<_RandomAccessIterator>::difference_type __len = __last - __first;
- std::__pop_heap(std::move(__first), std::move(__last), __comp, __len);
+ std::__pop_heap<_ClassicAlgPolicy>(std::move(__first), std::move(__last), __comp, __len);
}
template <class _RandomAccessIterator>
diff --git a/libcxx/include/__algorithm/push_heap.h b/libcxx/include/__algorithm/push_heap.h
index 1e3eec373d4f..716670b76788 100644
--- a/libcxx/include/__algorithm/push_heap.h
+++ b/libcxx/include/__algorithm/push_heap.h
@@ -11,9 +11,11 @@
#include <__algorithm/comp.h>
#include <__algorithm/comp_ref_type.h>
+#include <__algorithm/iterator_operations.h>
#include <__config>
#include <__iterator/iterator_traits.h>
#include <__utility/move.h>
+#include <type_traits>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
@@ -21,7 +23,7 @@
_LIBCPP_BEGIN_NAMESPACE_STD
-template <class _Compare, class _RandomAccessIterator>
+template <class _AlgPolicy, class _Compare, class _RandomAccessIterator>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX11
void __sift_up(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp,
typename iterator_traits<_RandomAccessIterator>::difference_type __len) {
@@ -32,9 +34,9 @@ void __sift_up(_RandomAccessIterator __first, _RandomAccessIterator __last, _Com
_RandomAccessIterator __ptr = __first + __len;
if (__comp(*__ptr, *--__last)) {
- value_type __t(std::move(*__last));
+ value_type __t(_IterOps<_AlgPolicy>::__iter_move(__last));
do {
- *__last = std::move(*__ptr);
+ *__last = _IterOps<_AlgPolicy>::__iter_move(__ptr);
__last = __ptr;
if (__len == 0)
break;
@@ -47,18 +49,21 @@ void __sift_up(_RandomAccessIterator __first, _RandomAccessIterator __last, _Com
}
}
-template <class _RandomAccessIterator, class _Compare>
+template <class _AlgPolicy, class _RandomAccessIterator, class _Compare>
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX11
void __push_heap(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare& __comp) {
using _CompRef = typename __comp_ref_type<_Compare>::type;
typename iterator_traits<_RandomAccessIterator>::difference_type __len = __last - __first;
- std::__sift_up<_CompRef>(std::move(__first), std::move(__last), __comp, __len);
+ std::__sift_up<_AlgPolicy, _CompRef>(std::move(__first), std::move(__last), __comp, __len);
}
template <class _RandomAccessIterator, class _Compare>
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17
void push_heap(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp) {
- std::__push_heap(std::move(__first), std::move(__last), __comp);
+ static_assert(std::is_copy_constructible<_RandomAccessIterator>::value, "Iterators must be copy constructible.");
+ static_assert(std::is_copy_assignable<_RandomAccessIterator>::value, "Iterators must be copy assignable.");
+
+ std::__push_heap<_ClassicAlgPolicy>(std::move(__first), std::move(__last), __comp);
}
template <class _RandomAccessIterator>
diff --git a/libcxx/include/__algorithm/ranges_equal_range.h b/libcxx/include/__algorithm/ranges_equal_range.h
index 28d721530bda..dd4b377df1a1 100644
--- a/libcxx/include/__algorithm/ranges_equal_range.h
+++ b/libcxx/include/__algorithm/ranges_equal_range.h
@@ -10,7 +10,7 @@
#define _LIBCPP___ALGORITHM_RANGES_EQUAL_RANGE_H
#include <__algorithm/equal_range.h>
-#include <__algorithm/make_projected.h>
+#include <__algorithm/iterator_operations.h>
#include <__config>
#include <__functional/identity.h>
#include <__functional/invoke.h>
@@ -37,27 +37,30 @@ namespace ranges {
namespace __equal_range {
struct __fn {
-
- template <forward_iterator _Iter, sentinel_for<_Iter> _Sent, class _Tp, class _Proj = identity,
- indirect_strict_weak_order<const _Tp*, projected<_Iter, _Proj>> _Comp = ranges::less>
- _LIBCPP_HIDE_FROM_ABI constexpr
- subrange<_Iter> operator()(_Iter __first, _Sent __last, const _Tp& __value, _Comp __comp = {},
- _Proj __proj = {}) const {
- // TODO: implement
- (void)__first; (void)__last; (void)__value; (void)__comp; (void)__proj;
- return {};
+ template <
+ forward_iterator _Iter,
+ sentinel_for<_Iter> _Sent,
+ class _Tp,
+ class _Proj = identity,
+ indirect_strict_weak_order<const _Tp*, projected<_Iter, _Proj>> _Comp = ranges::less>
+ _LIBCPP_HIDE_FROM_ABI constexpr subrange<_Iter>
+ operator()(_Iter __first, _Sent __last, const _Tp& __value, _Comp __comp = {}, _Proj __proj = {}) const {
+ auto __ret = std::__equal_range<_RangeAlgPolicy>(
+ std::move(__first), std::move(__last), __value, __comp, __proj);
+ return {std::move(__ret.first), std::move(__ret.second)};
}
- template <forward_range _Range, class _Tp, class _Proj = identity,
- indirect_strict_weak_order<const _Tp*, projected<iterator_t<_Range>, _Proj>> _Comp = ranges::less>
- _LIBCPP_HIDE_FROM_ABI constexpr
- borrowed_subrange_t<_Range> operator()(_Range&& __range, const _Tp& __value, _Comp __comp = {},
- _Proj __proj = {}) const {
- // TODO: implement
- (void)__range; (void)__value; (void)__comp; (void)__proj;
- return {};
+ template <
+ forward_range _Range,
+ class _Tp,
+ class _Proj = identity,
+ indirect_strict_weak_order<const _Tp*, projected<iterator_t<_Range>, _Proj>> _Comp = ranges::less>
+ _LIBCPP_HIDE_FROM_ABI constexpr borrowed_subrange_t<_Range>
+ operator()(_Range&& __range, const _Tp& __value, _Comp __comp = {}, _Proj __proj = {}) const {
+ auto __ret = std::__equal_range<_RangeAlgPolicy>(
+ ranges::begin(__range), ranges::end(__range), __value, __comp, __proj);
+ return {std::move(__ret.first), std::move(__ret.second)};
}
-
};
} // namespace __equal_range
diff --git a/libcxx/include/__algorithm/ranges_fill.h b/libcxx/include/__algorithm/ranges_fill.h
index 846e31885141..7ce4a76ba9e9 100644
--- a/libcxx/include/__algorithm/ranges_fill.h
+++ b/libcxx/include/__algorithm/ranges_fill.h
@@ -30,7 +30,7 @@ struct __fn {
template <class _Type, output_iterator<const _Type&> _Iter, sentinel_for<_Iter> _Sent>
_LIBCPP_HIDE_FROM_ABI constexpr
_Iter operator()(_Iter __first, _Sent __last, const _Type& __value) const {
- if constexpr(random_access_iterator<_Iter>) {
+ if constexpr(random_access_iterator<_Iter> && sized_sentinel_for<_Sent, _Iter>) {
return ranges::fill_n(__first, __last - __first, __value);
} else {
for (; __first != __last; ++__first)
diff --git a/libcxx/include/__algorithm/ranges_find_end.h b/libcxx/include/__algorithm/ranges_find_end.h
index fec709e79f5a..270b00649848 100644
--- a/libcxx/include/__algorithm/ranges_find_end.h
+++ b/libcxx/include/__algorithm/ranges_find_end.h
@@ -11,6 +11,7 @@
#include <__algorithm/find_end.h>
#include <__algorithm/iterator_operations.h>
+#include <__algorithm/ranges_iterator_concept.h>
#include <__config>
#include <__functional/identity.h>
#include <__functional/ranges_operations.h>
@@ -29,23 +30,6 @@
_LIBCPP_BEGIN_NAMESPACE_STD
-template <class _Iter>
-consteval auto __get_iterator_concept() {
- if constexpr (contiguous_iterator<_Iter>)
- return contiguous_iterator_tag();
- else if constexpr (random_access_iterator<_Iter>)
- return random_access_iterator_tag();
- else if constexpr (bidirectional_iterator<_Iter>)
- return bidirectional_iterator_tag();
- else if constexpr (forward_iterator<_Iter>)
- return forward_iterator_tag();
- else if constexpr (input_iterator<_Iter>)
- return input_iterator_tag();
-}
-
-template <class _Iter>
-using __iterator_concept = decltype(__get_iterator_concept<_Iter>());
-
namespace ranges {
namespace __find_end {
struct __fn {
diff --git a/libcxx/include/__algorithm/ranges_for_each_n.h b/libcxx/include/__algorithm/ranges_for_each_n.h
index ddf8b047cdb2..013afbd19389 100644
--- a/libcxx/include/__algorithm/ranges_for_each_n.h
+++ b/libcxx/include/__algorithm/ranges_for_each_n.h
@@ -18,7 +18,6 @@
#include <__iterator/iterator_traits.h>
#include <__iterator/projected.h>
#include <__ranges/concepts.h>
-#include <__ranges/dangling.h>
#include <__utility/move.h>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
diff --git a/libcxx/include/__algorithm/ranges_generate_n.h b/libcxx/include/__algorithm/ranges_generate_n.h
index bcf50e025ecc..7bde5fb4e579 100644
--- a/libcxx/include/__algorithm/ranges_generate_n.h
+++ b/libcxx/include/__algorithm/ranges_generate_n.h
@@ -23,7 +23,6 @@
#include <__iterator/projected.h>
#include <__ranges/access.h>
#include <__ranges/concepts.h>
-#include <__ranges/dangling.h>
#include <__utility/forward.h>
#include <__utility/move.h>
diff --git a/libcxx/include/__algorithm/ranges_includes.h b/libcxx/include/__algorithm/ranges_includes.h
index 19c17870ed6f..ba054e6fd89d 100644
--- a/libcxx/include/__algorithm/ranges_includes.h
+++ b/libcxx/include/__algorithm/ranges_includes.h
@@ -9,8 +9,8 @@
#ifndef _LIBCPP___ALGORITHM_RANGES_INCLUDES_H
#define _LIBCPP___ALGORITHM_RANGES_INCLUDES_H
-#include <__algorithm/make_projected.h>
#include <__algorithm/includes.h>
+#include <__algorithm/make_projected.h>
#include <__config>
#include <__functional/identity.h>
#include <__functional/invoke.h>
@@ -20,7 +20,6 @@
#include <__iterator/projected.h>
#include <__ranges/access.h>
#include <__ranges/concepts.h>
-#include <__ranges/dangling.h>
#include <__utility/forward.h>
#include <__utility/move.h>
@@ -36,29 +35,46 @@ namespace ranges {
namespace __includes {
struct __fn {
-
- template <input_iterator _Iter1, sentinel_for<_Iter1> _Sent1, input_iterator _Iter2, sentinel_for<_Iter2> _Sent2,
- class _Proj1 = identity, class _Proj2 = identity,
- indirect_strict_weak_order<projected<_Iter1, _Proj1>, projected<_Iter2, _Proj2>> _Comp = ranges::less>
- _LIBCPP_HIDE_FROM_ABI constexpr
- bool operator()(_Iter1 __first1, _Sent1 __last1, _Iter2 __first2, _Sent2 __last2, _Comp __comp = {},
- _Proj1 __proj1 = {}, _Proj2 __proj2 = {}) const {
- // TODO: implement
- (void)__first1; (void)__last1; (void)__first2; (void)__last2; (void)__comp; (void)__proj1; (void)__proj2;
- return {};
+ template <
+ input_iterator _Iter1,
+ sentinel_for<_Iter1> _Sent1,
+ input_iterator _Iter2,
+ sentinel_for<_Iter2> _Sent2,
+ class _Proj1 = identity,
+ class _Proj2 = identity,
+ indirect_strict_weak_order<projected<_Iter1, _Proj1>, projected<_Iter2, _Proj2>> _Comp = ranges::less>
+ _LIBCPP_HIDE_FROM_ABI constexpr bool operator()(
+ _Iter1 __first1,
+ _Sent1 __last1,
+ _Iter2 __first2,
+ _Sent2 __last2,
+ _Comp __comp = {},
+ _Proj1 __proj1 = {},
+ _Proj2 __proj2 = {}) const {
+ return std::__includes(
+ std::move(__first1),
+ std::move(__last1),
+ std::move(__first2),
+ std::move(__last2),
+ ranges::__make_projected_comp(__comp, __proj1, __proj2));
}
- template <input_range _Range1, input_range _Range2, class _Proj1 = identity, class _Proj2 = identity,
- indirect_strict_weak_order<projected<iterator_t<_Range1>, _Proj1>,
- projected<iterator_t<_Range2>, _Proj2>> _Comp = ranges::less>
- _LIBCPP_HIDE_FROM_ABI constexpr
- bool operator()(_Range1&& __range1, _Range2&& __range2, _Comp __comp = {},
- _Proj1 __proj1 = {}, _Proj2 __proj2 = {}) const {
- // TODO: implement
- (void)__range1; (void)__range2; (void)__comp; (void)__proj1; (void)__proj2;
- return {};
+ template <
+ input_range _Range1,
+ input_range _Range2,
+ class _Proj1 = identity,
+ class _Proj2 = identity,
+ indirect_strict_weak_order<projected<iterator_t<_Range1>, _Proj1>, projected<iterator_t<_Range2>, _Proj2>>
+ _Comp = ranges::less>
+ _LIBCPP_HIDE_FROM_ABI constexpr bool operator()(
+ _Range1&& __range1, _Range2&& __range2, _Comp __comp = {}, _Proj1 __proj1 = {}, _Proj2 __proj2 = {}) const {
+ return std::__includes(
+ ranges::begin(__range1),
+ ranges::end(__range1),
+ ranges::begin(__range2),
+ ranges::end(__range2),
+ ranges::__make_projected_comp(__comp, __proj1, __proj2));
}
-
};
} // namespace __includes
diff --git a/libcxx/include/__algorithm/ranges_is_heap.h b/libcxx/include/__algorithm/ranges_is_heap.h
index 0f10fa4dcec9..00105189fed7 100644
--- a/libcxx/include/__algorithm/ranges_is_heap.h
+++ b/libcxx/include/__algorithm/ranges_is_heap.h
@@ -20,7 +20,6 @@
#include <__iterator/projected.h>
#include <__ranges/access.h>
#include <__ranges/concepts.h>
-#include <__ranges/dangling.h>
#include <__utility/forward.h>
#include <__utility/move.h>
diff --git a/libcxx/include/__algorithm/ranges_iterator_concept.h b/libcxx/include/__algorithm/ranges_iterator_concept.h
new file mode 100644
index 000000000000..3323119317ae
--- /dev/null
+++ b/libcxx/include/__algorithm/ranges_iterator_concept.h
@@ -0,0 +1,51 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBCPP___ALGORITHM_RANGES_ITERATOR_CONCEPT_H
+#define _LIBCPP___ALGORITHM_RANGES_ITERATOR_CONCEPT_H
+
+#include <__config>
+#include <__iterator/concepts.h>
+#include <__iterator/iterator_traits.h>
+#include <type_traits>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+# pragma GCC system_header
+#endif
+
+#if _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES)
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+namespace ranges {
+
+template <class _IterMaybeQualified>
+consteval auto __get_iterator_concept() {
+ using _Iter = __uncvref_t<_IterMaybeQualified>;
+
+ if constexpr (contiguous_iterator<_Iter>)
+ return contiguous_iterator_tag();
+ else if constexpr (random_access_iterator<_Iter>)
+ return random_access_iterator_tag();
+ else if constexpr (bidirectional_iterator<_Iter>)
+ return bidirectional_iterator_tag();
+ else if constexpr (forward_iterator<_Iter>)
+ return forward_iterator_tag();
+ else if constexpr (input_iterator<_Iter>)
+ return input_iterator_tag();
+}
+
+template <class _Iter>
+using __iterator_concept = decltype(__get_iterator_concept<_Iter>());
+
+} // namespace ranges
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES)
+
+#endif // _LIBCPP___ALGORITHM_RANGES_ITERATOR_CONCEPT_H
diff --git a/libcxx/include/__algorithm/ranges_make_heap.h b/libcxx/include/__algorithm/ranges_make_heap.h
index fd488dc11a4b..8eabdd12cd2f 100644
--- a/libcxx/include/__algorithm/ranges_make_heap.h
+++ b/libcxx/include/__algorithm/ranges_make_heap.h
@@ -9,6 +9,7 @@
#ifndef _LIBCPP___ALGORITHM_RANGES_MAKE_HEAP_H
#define _LIBCPP___ALGORITHM_RANGES_MAKE_HEAP_H
+#include <__algorithm/iterator_operations.h>
#include <__algorithm/make_heap.h>
#include <__algorithm/make_projected.h>
#include <__concepts/same_as.h>
@@ -45,7 +46,7 @@ struct __fn {
auto __last_iter = ranges::next(__first, __last);
auto&& __projected_comp = ranges::__make_projected_comp(__comp, __proj);
- std::__make_heap(std::move(__first), __last_iter, __projected_comp);
+ std::__make_heap<_RangeAlgPolicy>(std::move(__first), __last_iter, __projected_comp);
return __last_iter;
}
diff --git a/libcxx/include/__algorithm/ranges_min_element.h b/libcxx/include/__algorithm/ranges_min_element.h
index ae82dceb9ad8..26f95fe3a6d2 100644
--- a/libcxx/include/__algorithm/ranges_min_element.h
+++ b/libcxx/include/__algorithm/ranges_min_element.h
@@ -30,6 +30,7 @@ _LIBCPP_BEGIN_NAMESPACE_STD
namespace ranges {
+// TODO(ranges): `ranges::min_element` can now simply delegate to `std::__min_element`.
template <class _Ip, class _Sp, class _Proj, class _Comp>
_LIBCPP_HIDE_FROM_ABI static constexpr
_Ip __min_element_impl(_Ip __first, _Sp __last, _Comp& __comp, _Proj& __proj) {
diff --git a/libcxx/include/__algorithm/ranges_nth_element.h b/libcxx/include/__algorithm/ranges_nth_element.h
index 2a929eacb89d..b15eb816b918 100644
--- a/libcxx/include/__algorithm/ranges_nth_element.h
+++ b/libcxx/include/__algorithm/ranges_nth_element.h
@@ -9,6 +9,7 @@
#ifndef _LIBCPP___ALGORITHM_RANGES_NTH_ELEMENT_H
#define _LIBCPP___ALGORITHM_RANGES_NTH_ELEMENT_H
+#include <__algorithm/iterator_operations.h>
#include <__algorithm/make_projected.h>
#include <__algorithm/nth_element.h>
#include <__config>
@@ -44,7 +45,7 @@ struct __fn {
auto __last_iter = ranges::next(__first, __last);
auto&& __projected_comp = ranges::__make_projected_comp(__comp, __proj);
- std::__nth_element_impl(std::move(__first), std::move(__nth), __last_iter, __projected_comp);
+ std::__nth_element_impl<_RangeAlgPolicy>(std::move(__first), std::move(__nth), __last_iter, __projected_comp);
return __last_iter;
}
diff --git a/libcxx/include/__algorithm/ranges_partial_sort.h b/libcxx/include/__algorithm/ranges_partial_sort.h
new file mode 100644
index 000000000000..5e82bc6fcc32
--- /dev/null
+++ b/libcxx/include/__algorithm/ranges_partial_sort.h
@@ -0,0 +1,77 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBCPP___ALGORITHM_RANGES_PARTIAL_SORT_H
+#define _LIBCPP___ALGORITHM_RANGES_PARTIAL_SORT_H
+
+#include <__algorithm/iterator_operations.h>
+#include <__algorithm/make_projected.h>
+#include <__algorithm/partial_sort.h>
+#include <__concepts/same_as.h>
+#include <__config>
+#include <__functional/identity.h>
+#include <__functional/invoke.h>
+#include <__functional/ranges_operations.h>
+#include <__iterator/concepts.h>
+#include <__iterator/iterator_traits.h>
+#include <__iterator/next.h>
+#include <__iterator/projected.h>
+#include <__iterator/sortable.h>
+#include <__ranges/access.h>
+#include <__ranges/concepts.h>
+#include <__ranges/dangling.h>
+#include <__utility/forward.h>
+#include <__utility/move.h>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+# pragma GCC system_header
+#endif
+
+#if _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES)
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+namespace ranges {
+namespace __partial_sort {
+
+struct __fn {
+ template <class _Iter, class _Sent, class _Comp, class _Proj>
+ _LIBCPP_HIDE_FROM_ABI constexpr static
+ _Iter __partial_sort_fn_impl(_Iter __first, _Iter __middle, _Sent __last, _Comp& __comp, _Proj& __proj) {
+ auto&& __projected_comp = ranges::__make_projected_comp(__comp, __proj);
+ return std::__partial_sort<_RangeAlgPolicy>(std::move(__first), std::move(__middle), __last, __projected_comp);
+ }
+
+ template <random_access_iterator _Iter, sentinel_for<_Iter> _Sent, class _Comp = ranges::less, class _Proj = identity>
+ requires sortable<_Iter, _Comp, _Proj>
+ _LIBCPP_HIDE_FROM_ABI constexpr
+ _Iter operator()(_Iter __first, _Iter __middle, _Sent __last, _Comp __comp = {}, _Proj __proj = {}) const {
+ return __partial_sort_fn_impl(std::move(__first), std::move(__middle), std::move(__last), __comp, __proj);
+ }
+
+ template <random_access_range _Range, class _Comp = ranges::less, class _Proj = identity>
+ requires sortable<iterator_t<_Range>, _Comp, _Proj>
+ _LIBCPP_HIDE_FROM_ABI constexpr
+ borrowed_iterator_t<_Range> operator()(_Range&& __r, iterator_t<_Range> __middle, _Comp __comp = {},
+ _Proj __proj = {}) const {
+ return __partial_sort_fn_impl(ranges::begin(__r), std::move(__middle), ranges::end(__r), __comp, __proj);
+ }
+};
+
+} // namespace __partial_sort
+
+inline namespace __cpo {
+ inline constexpr auto partial_sort = __partial_sort::__fn{};
+} // namespace __cpo
+} // namespace ranges
+
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES)
+
+#endif // _LIBCPP___ALGORITHM_RANGES_PARTIAL_SORT_H
diff --git a/libcxx/include/__algorithm/ranges_partition.h b/libcxx/include/__algorithm/ranges_partition.h
index c145e7bdb4a2..60bee699d90e 100644
--- a/libcxx/include/__algorithm/ranges_partition.h
+++ b/libcxx/include/__algorithm/ranges_partition.h
@@ -9,8 +9,10 @@
#ifndef _LIBCPP___ALGORITHM_RANGES_PARTITION_H
#define _LIBCPP___ALGORITHM_RANGES_PARTITION_H
+#include <__algorithm/iterator_operations.h>
#include <__algorithm/make_projected.h>
#include <__algorithm/partition.h>
+#include <__algorithm/ranges_iterator_concept.h>
#include <__config>
#include <__functional/identity.h>
#include <__functional/invoke.h>
@@ -21,10 +23,10 @@
#include <__iterator/projected.h>
#include <__ranges/access.h>
#include <__ranges/concepts.h>
-#include <__ranges/dangling.h>
#include <__ranges/subrange.h>
#include <__utility/forward.h>
#include <__utility/move.h>
+#include <type_traits>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
@@ -39,13 +41,21 @@ namespace __partition {
struct __fn {
+ template <class _Iter, class _Sent, class _Proj, class _Pred>
+ _LIBCPP_HIDE_FROM_ABI static constexpr
+ subrange<__uncvref_t<_Iter>> __partition_fn_impl(_Iter&& __first, _Sent&& __last, _Pred&& __pred, _Proj&& __proj) {
+ auto&& __projected_pred = ranges::__make_projected_pred(__pred, __proj);
+ auto __result = std::__partition<_RangeAlgPolicy>(
+ std::move(__first), std::move(__last), __projected_pred, __iterator_concept<_Iter>());
+
+ return {std::move(__result.first), std::move(__result.second)};
+ }
+
template <permutable _Iter, sentinel_for<_Iter> _Sent, class _Proj = identity,
indirect_unary_predicate<projected<_Iter, _Proj>> _Pred>
_LIBCPP_HIDE_FROM_ABI constexpr
subrange<_Iter> operator()(_Iter __first, _Sent __last, _Pred __pred, _Proj __proj = {}) const {
- // TODO: implement
- (void)__first; (void)__last; (void)__pred; (void)__proj;
- return {};
+ return __partition_fn_impl(__first, __last, __pred, __proj);
}
template <forward_range _Range, class _Proj = identity,
@@ -53,9 +63,7 @@ struct __fn {
requires permutable<iterator_t<_Range>>
_LIBCPP_HIDE_FROM_ABI constexpr
borrowed_subrange_t<_Range> operator()(_Range&& __range, _Pred __pred, _Proj __proj = {}) const {
- // TODO: implement
- (void)__range; (void)__pred; (void)__proj;
- return {};
+ return __partition_fn_impl(ranges::begin(__range), ranges::end(__range), __pred, __proj);
}
};
diff --git a/libcxx/include/__algorithm/ranges_partition_copy.h b/libcxx/include/__algorithm/ranges_partition_copy.h
index f55089b94ea5..7201a8cbfe45 100644
--- a/libcxx/include/__algorithm/ranges_partition_copy.h
+++ b/libcxx/include/__algorithm/ranges_partition_copy.h
@@ -10,20 +10,17 @@
#define _LIBCPP___ALGORITHM_RANGES_PARTITION_COPY_H
#include <__algorithm/in_out_out_result.h>
-#include <__algorithm/make_projected.h>
-#include <__algorithm/partition_copy.h>
#include <__config>
#include <__functional/identity.h>
#include <__functional/invoke.h>
-#include <__functional/ranges_operations.h>
#include <__iterator/concepts.h>
#include <__iterator/iterator_traits.h>
#include <__iterator/projected.h>
#include <__ranges/access.h>
#include <__ranges/concepts.h>
#include <__ranges/dangling.h>
-#include <__utility/forward.h>
#include <__utility/move.h>
+#include <type_traits>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
@@ -42,6 +39,27 @@ namespace __partition_copy {
struct __fn {
+ // TODO(ranges): delegate to the classic algorithm.
+ template <class _InIter, class _Sent, class _OutIter1, class _OutIter2, class _Proj, class _Pred>
+ _LIBCPP_HIDE_FROM_ABI constexpr
+ static partition_copy_result<
+ __uncvref_t<_InIter>, __uncvref_t<_OutIter1>, __uncvref_t<_OutIter2>
+ > __partition_copy_fn_impl( _InIter&& __first, _Sent&& __last, _OutIter1&& __out_true, _OutIter2&& __out_false,
+ _Pred& __pred, _Proj& __proj) {
+ for (; __first != __last; ++__first) {
+ if (std::invoke(__pred, std::invoke(__proj, *__first))) {
+ *__out_true = *__first;
+ ++__out_true;
+
+ } else {
+ *__out_false = *__first;
+ ++__out_false;
+ }
+ }
+
+ return {std::move(__first), std::move(__out_true), std::move(__out_false)};
+ }
+
template <input_iterator _InIter, sentinel_for<_InIter> _Sent,
weakly_incrementable _OutIter1, weakly_incrementable _OutIter2,
class _Proj = identity, indirect_unary_predicate<projected<_InIter, _Proj>> _Pred>
@@ -50,9 +68,8 @@ struct __fn {
partition_copy_result<_InIter, _OutIter1, _OutIter2>
operator()(_InIter __first, _Sent __last, _OutIter1 __out_true, _OutIter2 __out_false,
_Pred __pred, _Proj __proj = {}) const {
- // TODO: implement
- (void)__first; (void)__last; (void)__out_true; (void)__out_false; (void)__pred; (void)__proj;
- return {};
+ return __partition_copy_fn_impl(
+ std::move(__first), std::move(__last), std::move(__out_true), std::move(__out_false), __pred, __proj);
}
template <input_range _Range, weakly_incrementable _OutIter1, weakly_incrementable _OutIter2,
@@ -61,9 +78,8 @@ struct __fn {
_LIBCPP_HIDE_FROM_ABI constexpr
partition_copy_result<borrowed_iterator_t<_Range>, _OutIter1, _OutIter2>
operator()(_Range&& __range, _OutIter1 __out_true, _OutIter2 __out_false, _Pred __pred, _Proj __proj = {}) const {
- // TODO: implement
- (void)__range; (void)__out_true; (void)__out_false; (void)__pred; (void)__proj;
- return {};
+ return __partition_copy_fn_impl(
+ ranges::begin(__range), ranges::end(__range), std::move(__out_true), std::move(__out_false), __pred, __proj);
}
};
diff --git a/libcxx/include/__algorithm/ranges_partition_point.h b/libcxx/include/__algorithm/ranges_partition_point.h
index 336b29f63284..6614a0bb50fd 100644
--- a/libcxx/include/__algorithm/ranges_partition_point.h
+++ b/libcxx/include/__algorithm/ranges_partition_point.h
@@ -9,19 +9,18 @@
#ifndef _LIBCPP___ALGORITHM_RANGES_PARTITION_POINT_H
#define _LIBCPP___ALGORITHM_RANGES_PARTITION_POINT_H
-#include <__algorithm/make_projected.h>
-#include <__algorithm/partition_point.h>
+#include <__algorithm/half_positive.h>
#include <__config>
#include <__functional/identity.h>
#include <__functional/invoke.h>
-#include <__functional/ranges_operations.h>
#include <__iterator/concepts.h>
+#include <__iterator/distance.h>
#include <__iterator/iterator_traits.h>
+#include <__iterator/next.h>
#include <__iterator/projected.h>
#include <__ranges/access.h>
#include <__ranges/concepts.h>
#include <__ranges/dangling.h>
-#include <__utility/forward.h>
#include <__utility/move.h>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
@@ -37,22 +36,40 @@ namespace __partition_point {
struct __fn {
+ // TODO(ranges): delegate to the classic algorithm.
+ template <class _Iter, class _Sent, class _Proj, class _Pred>
+ _LIBCPP_HIDE_FROM_ABI constexpr
+ static _Iter __partition_point_fn_impl(_Iter&& __first, _Sent&& __last, _Pred& __pred, _Proj& __proj) {
+ auto __len = ranges::distance(__first, __last);
+
+ while (__len != 0) {
+ auto __half_len = std::__half_positive(__len);
+ auto __mid = ranges::next(__first, __half_len);
+
+ if (std::invoke(__pred, std::invoke(__proj, *__mid))) {
+ __first = ++__mid;
+ __len -= __half_len + 1;
+
+ } else {
+ __len = __half_len;
+ }
+ }
+
+ return __first;
+ }
+
template <forward_iterator _Iter, sentinel_for<_Iter> _Sent, class _Proj = identity,
indirect_unary_predicate<projected<_Iter, _Proj>> _Pred>
_LIBCPP_HIDE_FROM_ABI constexpr
_Iter operator()(_Iter __first, _Sent __last, _Pred __pred, _Proj __proj = {}) const {
- // TODO: implement
- (void)__first; (void)__last; (void)__pred; (void)__proj;
- return {};
+ return __partition_point_fn_impl(std::move(__first), std::move(__last), __pred, __proj);
}
template <forward_range _Range, class _Proj = identity,
indirect_unary_predicate<projected<iterator_t<_Range>, _Proj>> _Pred>
_LIBCPP_HIDE_FROM_ABI constexpr
borrowed_iterator_t<_Range> operator()(_Range&& __range, _Pred __pred, _Proj __proj = {}) const {
- // TODO: implement
- (void)__range; (void)__pred; (void)__proj;
- return {};
+ return __partition_point_fn_impl(ranges::begin(__range), ranges::end(__range), __pred, __proj);
}
};
diff --git a/libcxx/include/__algorithm/ranges_pop_heap.h b/libcxx/include/__algorithm/ranges_pop_heap.h
index d0b8314e5b0a..92df6119d34a 100644
--- a/libcxx/include/__algorithm/ranges_pop_heap.h
+++ b/libcxx/include/__algorithm/ranges_pop_heap.h
@@ -9,6 +9,7 @@
#ifndef _LIBCPP___ALGORITHM_RANGES_POP_HEAP_H
#define _LIBCPP___ALGORITHM_RANGES_POP_HEAP_H
+#include <__algorithm/iterator_operations.h>
#include <__algorithm/make_projected.h>
#include <__algorithm/pop_heap.h>
#include <__concepts/same_as.h>
@@ -46,7 +47,7 @@ struct __fn {
auto __len = __last_iter - __first;
auto&& __projected_comp = ranges::__make_projected_comp(__comp, __proj);
- std::__pop_heap(std::move(__first), __last_iter, __projected_comp, __len);
+ std::__pop_heap<_RangeAlgPolicy>(std::move(__first), __last_iter, __projected_comp, __len);
return __last_iter;
}
diff --git a/libcxx/include/__algorithm/ranges_push_heap.h b/libcxx/include/__algorithm/ranges_push_heap.h
index e46ad19cfed7..4c41b00128de 100644
--- a/libcxx/include/__algorithm/ranges_push_heap.h
+++ b/libcxx/include/__algorithm/ranges_push_heap.h
@@ -9,6 +9,7 @@
#ifndef _LIBCPP___ALGORITHM_RANGES_PUSH_HEAP_H
#define _LIBCPP___ALGORITHM_RANGES_PUSH_HEAP_H
+#include <__algorithm/iterator_operations.h>
#include <__algorithm/make_projected.h>
#include <__algorithm/push_heap.h>
#include <__concepts/same_as.h>
@@ -45,7 +46,7 @@ struct __fn {
auto __last_iter = ranges::next(__first, __last);
auto&& __projected_comp = ranges::__make_projected_comp(__comp, __proj);
- std::__push_heap(std::move(__first), __last_iter, __projected_comp);
+ std::__push_heap<_RangeAlgPolicy>(std::move(__first), __last_iter, __projected_comp);
return __last_iter;
}
diff --git a/libcxx/include/__algorithm/ranges_set_union.h b/libcxx/include/__algorithm/ranges_set_union.h
index 39537503b98f..3826e55688f7 100644
--- a/libcxx/include/__algorithm/ranges_set_union.h
+++ b/libcxx/include/__algorithm/ranges_set_union.h
@@ -42,34 +42,68 @@ using set_union_result = in_in_out_result<_InIter1, _InIter2, _OutIter>;
namespace __set_union {
struct __fn {
-
- template <input_iterator _InIter1, sentinel_for<_InIter1> _Sent1,
- input_iterator _InIter2, sentinel_for<_InIter2> _Sent2,
- weakly_incrementable _OutIter, class _Comp = ranges::less,
- class _Proj1 = identity, class _Proj2 = identity>
- requires mergeable<_InIter1, _InIter2, _OutIter, _Comp, _Proj1, _Proj2>
- _LIBCPP_HIDE_FROM_ABI constexpr
- set_union_result<_InIter1, _InIter2, _OutIter>
- operator()(_InIter1 __first1, _Sent1 __last1, _InIter2 __first2, _Sent2 __last2, _OutIter __result, _Comp __comp = {},
- _Proj1 __proj1 = {}, _Proj2 __proj2 = {}) const {
- // TODO: implement
- (void)__first1; (void)__last1; (void)__first2; (void)__last2; (void)__result; (void)__comp; (void)__proj1;
- (void)__proj2;
- return {};
+ template <
+ input_iterator _InIter1,
+ sentinel_for<_InIter1> _Sent1,
+ input_iterator _InIter2,
+ sentinel_for<_InIter2> _Sent2,
+ weakly_incrementable _OutIter,
+ class _Comp = ranges::less,
+ class _Proj1 = identity,
+ class _Proj2 = identity>
+ requires mergeable<_InIter1, _InIter2, _OutIter, _Comp, _Proj1, _Proj2>
+ _LIBCPP_HIDE_FROM_ABI constexpr set_union_result<_InIter1, _InIter2, _OutIter> operator()(
+ _InIter1 __first1,
+ _Sent1 __last1,
+ _InIter2 __first2,
+ _Sent2 __last2,
+ _OutIter __result,
+ _Comp __comp = {},
+ _Proj1 __proj1 = {},
+ _Proj2 __proj2 = {}) const {
+ auto __ret = std::__set_union(
+ std::move(__first1),
+ std::move(__last1),
+ std::move(__first2),
+ std::move(__last2),
+ std::move(__result),
+ ranges::__make_projected_comp(__comp, __proj1, __proj2));
+ return {std::move(__ret.__in1_), std::move(__ret.__in2_), std::move(__ret.__out_)};
}
- template <input_range _Range1, input_range _Range2, weakly_incrementable _OutIter,
- class _Comp = ranges::less, class _Proj1 = identity, class _Proj2 = identity>
- requires mergeable<iterator_t<_Range1>, iterator_t<_Range2>, _OutIter, _Comp, _Proj1, _Proj2>
- _LIBCPP_HIDE_FROM_ABI constexpr
- set_union_result<borrowed_iterator_t<_Range1>, borrowed_iterator_t<_Range2>, _OutIter>
- operator()(_Range1&& __range1, _Range2&& __range2, _OutIter __result, _Comp __comp = {},
- _Proj1 __proj1 = {}, _Proj2 __proj2 = {}) const {
- // TODO: implement
- (void)__range1; (void)__range2; (void)__result; (void)__comp; (void)__proj1; (void)__proj2;
- return {};
+ template <
+ input_range _Range1,
+ input_range _Range2,
+ weakly_incrementable _OutIter,
+ class _Comp = ranges::less,
+ class _Proj1 = identity,
+ class _Proj2 = identity>
+ requires mergeable<
+ iterator_t<_Range1>,
+ iterator_t<_Range2>,
+ _OutIter,
+ _Comp,
+ _Proj1,
+ _Proj2>
+ _LIBCPP_HIDE_FROM_ABI constexpr set_union_result<borrowed_iterator_t<_Range1>,
+ borrowed_iterator_t<_Range2>,
+ _OutIter>
+ operator()(
+ _Range1&& __range1,
+ _Range2&& __range2,
+ _OutIter __result,
+ _Comp __comp = {},
+ _Proj1 __proj1 = {},
+ _Proj2 __proj2 = {}) const {
+ auto __ret = std::__set_union(
+ ranges::begin(__range1),
+ ranges::end(__range1),
+ ranges::begin(__range2),
+ ranges::end(__range2),
+ std::move(__result),
+ ranges::__make_projected_comp(__comp, __proj1, __proj2));
+ return {std::move(__ret.__in1_), std::move(__ret.__in2_), std::move(__ret.__out_)};
}
-
};
} // namespace __set_union
diff --git a/libcxx/include/__algorithm/ranges_shuffle.h b/libcxx/include/__algorithm/ranges_shuffle.h
index bf9c28b4ce26..b101a8582eac 100644
--- a/libcxx/include/__algorithm/ranges_shuffle.h
+++ b/libcxx/include/__algorithm/ranges_shuffle.h
@@ -9,23 +9,22 @@
#ifndef _LIBCPP___ALGORITHM_RANGES_SHUFFLE_H
#define _LIBCPP___ALGORITHM_RANGES_SHUFFLE_H
-#include <__algorithm/make_projected.h>
+#include <__algorithm/iterator_operations.h>
#include <__algorithm/shuffle.h>
#include <__config>
-#include <__functional/identity.h>
#include <__functional/invoke.h>
#include <__functional/ranges_operations.h>
#include <__iterator/concepts.h>
#include <__iterator/iterator_traits.h>
+#include <__iterator/next.h>
#include <__iterator/permutable.h>
-#include <__iterator/projected.h>
#include <__random/uniform_random_bit_generator.h>
#include <__ranges/access.h>
#include <__ranges/concepts.h>
#include <__ranges/dangling.h>
-#include <__type_traits/remove_reference.h>
#include <__utility/forward.h>
#include <__utility/move.h>
+#include <type_traits>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
@@ -33,29 +32,57 @@
#if _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES)
+_LIBCPP_PUSH_MACROS
+#include <__undef_macros>
+
_LIBCPP_BEGIN_NAMESPACE_STD
namespace ranges {
namespace __shuffle {
struct __fn {
+ // `std::shuffle` is more constrained than `std::ranges::shuffle`. `std::ranges::shuffle` only requires the given
+ // generator to satisfy the `std::uniform_random_bit_generator` concept. `std::shuffle` requires the given
+ // generator to meet the uniform random bit generator requirements; these requirements include satisfying
+ // `std::uniform_random_bit_generator` and add a requirement for the generator to provide a nested `result_type`
+ // typedef (see `[rand.req.urng]`).
+ //
+ // To reuse the implementation from `std::shuffle`, make the given generator meet the classic requirements by wrapping
+ // it into an adaptor type that forwards all of its interface and adds the required typedef.
+ template <class _Gen>
+ class _ClassicGenAdaptor {
+ private:
+ // The generator is not required to be copyable or movable, so it has to be stored as a reference.
+ _Gen& __gen;
+
+ public:
+ using result_type = invoke_result_t<_Gen&>;
+
+ _LIBCPP_HIDE_FROM_ABI
+ static constexpr auto min() { return __uncvref_t<_Gen>::min(); }
+ _LIBCPP_HIDE_FROM_ABI
+ static constexpr auto max() { return __uncvref_t<_Gen>::max(); }
+
+ _LIBCPP_HIDE_FROM_ABI
+ constexpr explicit _ClassicGenAdaptor(_Gen& __g) : __gen(__g) {}
+
+ _LIBCPP_HIDE_FROM_ABI
+ constexpr auto operator()() const { return __gen(); }
+ };
template <random_access_iterator _Iter, sentinel_for<_Iter> _Sent, class _Gen>
requires permutable<_Iter> && uniform_random_bit_generator<remove_reference_t<_Gen>>
_LIBCPP_HIDE_FROM_ABI
_Iter operator()(_Iter __first, _Sent __last, _Gen&& __gen) const {
- // TODO: implement
- (void)__first; (void)__last; (void)__gen;
- return {};
+ _ClassicGenAdaptor<_Gen> __adapted_gen(__gen);
+ return std::__shuffle<_RangeAlgPolicy>(std::move(__first), std::move(__last), __adapted_gen);
}
template<random_access_range _Range, class _Gen>
requires permutable<iterator_t<_Range>> && uniform_random_bit_generator<remove_reference_t<_Gen>>
_LIBCPP_HIDE_FROM_ABI
borrowed_iterator_t<_Range> operator()(_Range&& __range, _Gen&& __gen) const {
- // TODO: implement
- (void)__range; (void)__gen;
- return {};
+ return (*this)(ranges::begin(__range), ranges::end(__range), std::forward<_Gen>(__gen));
}
};
@@ -69,6 +96,8 @@ inline namespace __cpo {
_LIBCPP_END_NAMESPACE_STD
+_LIBCPP_POP_MACROS
+
#endif // _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES)
#endif // _LIBCPP___ALGORITHM_RANGES_SHUFFLE_H
diff --git a/libcxx/include/__algorithm/ranges_sort.h b/libcxx/include/__algorithm/ranges_sort.h
index 8297940df237..ef14db64295d 100644
--- a/libcxx/include/__algorithm/ranges_sort.h
+++ b/libcxx/include/__algorithm/ranges_sort.h
@@ -9,6 +9,7 @@
#ifndef _LIBCPP___ALGORITHM_RANGES_SORT_H
#define _LIBCPP___ALGORITHM_RANGES_SORT_H
+#include <__algorithm/iterator_operations.h>
#include <__algorithm/make_projected.h>
#include <__algorithm/sort.h>
#include <__config>
@@ -44,7 +45,7 @@ struct __fn {
auto __last_iter = ranges::next(__first, __last);
auto&& __projected_comp = ranges::__make_projected_comp(__comp, __proj);
- std::__sort_impl(std::move(__first), __last_iter, __projected_comp);
+ std::__sort_impl<_RangeAlgPolicy>(std::move(__first), __last_iter, __projected_comp);
return __last_iter;
}
diff --git a/libcxx/include/__algorithm/ranges_sort_heap.h b/libcxx/include/__algorithm/ranges_sort_heap.h
index c753e20c44a6..eb6a30dcd3d0 100644
--- a/libcxx/include/__algorithm/ranges_sort_heap.h
+++ b/libcxx/include/__algorithm/ranges_sort_heap.h
@@ -9,6 +9,7 @@
#ifndef _LIBCPP___ALGORITHM_RANGES_SORT_HEAP_H
#define _LIBCPP___ALGORITHM_RANGES_SORT_HEAP_H
+#include <__algorithm/iterator_operations.h>
#include <__algorithm/make_projected.h>
#include <__algorithm/sort_heap.h>
#include <__concepts/same_as.h>
@@ -45,7 +46,7 @@ struct __fn {
auto __last_iter = ranges::next(__first, __last);
auto&& __projected_comp = ranges::__make_projected_comp(__comp, __proj);
- std::__sort_heap(std::move(__first), __last_iter, __projected_comp);
+ std::__sort_heap<_RangeAlgPolicy>(std::move(__first), __last_iter, __projected_comp);
return __last_iter;
}
diff --git a/libcxx/include/__algorithm/ranges_stable_partition.h b/libcxx/include/__algorithm/ranges_stable_partition.h
index 178c953ebdae..27957db8829f 100644
--- a/libcxx/include/__algorithm/ranges_stable_partition.h
+++ b/libcxx/include/__algorithm/ranges_stable_partition.h
@@ -9,7 +9,9 @@
#ifndef _LIBCPP___ALGORITHM_RANGES_STABLE_PARTITION_H
#define _LIBCPP___ALGORITHM_RANGES_STABLE_PARTITION_H
+#include <__algorithm/iterator_operations.h>
#include <__algorithm/make_projected.h>
+#include <__algorithm/ranges_iterator_concept.h>
#include <__algorithm/stable_partition.h>
#include <__config>
#include <__functional/identity.h>
@@ -17,6 +19,7 @@
#include <__functional/ranges_operations.h>
#include <__iterator/concepts.h>
#include <__iterator/iterator_traits.h>
+#include <__iterator/next.h>
#include <__iterator/permutable.h>
#include <__iterator/projected.h>
#include <__ranges/access.h>
@@ -25,6 +28,7 @@
#include <__ranges/subrange.h>
#include <__utility/forward.h>
#include <__utility/move.h>
+#include <type_traits>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
@@ -39,14 +43,25 @@ namespace __stable_partition {
struct __fn {
+ template <class _Iter, class _Sent, class _Proj, class _Pred>
+ _LIBCPP_HIDE_FROM_ABI static
+ subrange<__uncvref_t<_Iter>> __stable_partition_fn_impl(
+ _Iter&& __first, _Sent&& __last, _Pred&& __pred, _Proj&& __proj) {
+ auto __last_iter = ranges::next(__first, __last);
+
+ auto&& __projected_pred = ranges::__make_projected_pred(__pred, __proj);
+ auto __result = std::__stable_partition<_RangeAlgPolicy>(
+ std::move(__first), __last_iter, __projected_pred, __iterator_concept<_Iter>());
+
+ return {std::move(__result), std::move(__last_iter)};
+ }
+
template <bidirectional_iterator _Iter, sentinel_for<_Iter> _Sent, class _Proj = identity,
indirect_unary_predicate<projected<_Iter, _Proj>> _Pred>
requires permutable<_Iter>
_LIBCPP_HIDE_FROM_ABI
subrange<_Iter> operator()(_Iter __first, _Sent __last, _Pred __pred, _Proj __proj = {}) const {
- // TODO: implement
- (void)__first; (void)__last; (void)__pred; (void)__proj;
- return {};
+ return __stable_partition_fn_impl(__first, __last, __pred, __proj);
}
template <bidirectional_range _Range, class _Proj = identity,
@@ -54,9 +69,7 @@ struct __fn {
requires permutable<iterator_t<_Range>>
_LIBCPP_HIDE_FROM_ABI
borrowed_subrange_t<_Range> operator()(_Range&& __range, _Pred __pred, _Proj __proj = {}) const {
- // TODO: implement
- (void)__range; (void)__pred; (void)__proj;
- return {};
+ return __stable_partition_fn_impl(ranges::begin(__range), ranges::end(__range), __pred, __proj);
}
};
diff --git a/libcxx/include/__algorithm/ranges_stable_sort.h b/libcxx/include/__algorithm/ranges_stable_sort.h
index 20e840426434..de48416a41be 100644
--- a/libcxx/include/__algorithm/ranges_stable_sort.h
+++ b/libcxx/include/__algorithm/ranges_stable_sort.h
@@ -9,6 +9,7 @@
#ifndef _LIBCPP___ALGORITHM_RANGES_STABLE_SORT_H
#define _LIBCPP___ALGORITHM_RANGES_STABLE_SORT_H
+#include <__algorithm/iterator_operations.h>
#include <__algorithm/make_projected.h>
#include <__algorithm/stable_sort.h>
#include <__config>
@@ -44,7 +45,7 @@ struct __fn {
auto __last_iter = ranges::next(__first, __last);
auto&& __projected_comp = ranges::__make_projected_comp(__comp, __proj);
- std::__stable_sort_impl(std::move(__first), __last_iter, __projected_comp);
+ std::__stable_sort_impl<_RangeAlgPolicy>(std::move(__first), __last_iter, __projected_comp);
return __last_iter;
}
diff --git a/libcxx/include/__algorithm/rotate.h b/libcxx/include/__algorithm/rotate.h
index c9ea5bad4c5a..fcf8444a65a0 100644
--- a/libcxx/include/__algorithm/rotate.h
+++ b/libcxx/include/__algorithm/rotate.h
@@ -9,6 +9,7 @@
#ifndef _LIBCPP___ALGORITHM_ROTATE_H
#define _LIBCPP___ALGORITHM_ROTATE_H
+#include <__algorithm/iterator_operations.h>
#include <__algorithm/move.h>
#include <__algorithm/move_backward.h>
#include <__algorithm/swap_ranges.h>
@@ -26,37 +27,40 @@
_LIBCPP_BEGIN_NAMESPACE_STD
-template <class _ForwardIterator>
+template <class _AlgPolicy, class _ForwardIterator>
_LIBCPP_CONSTEXPR_AFTER_CXX11 _ForwardIterator
__rotate_left(_ForwardIterator __first, _ForwardIterator __last)
{
typedef typename iterator_traits<_ForwardIterator>::value_type value_type;
- value_type __tmp = _VSTD::move(*__first);
+ value_type __tmp = _IterOps<_AlgPolicy>::__iter_move(__first);
+ // TODO(ranges): pass `_AlgPolicy` to `move`.
_ForwardIterator __lm1 = _VSTD::move(_VSTD::next(__first), __last, __first);
*__lm1 = _VSTD::move(__tmp);
return __lm1;
}
-template <class _BidirectionalIterator>
+template <class _AlgPolicy, class _BidirectionalIterator>
_LIBCPP_CONSTEXPR_AFTER_CXX11 _BidirectionalIterator
__rotate_right(_BidirectionalIterator __first, _BidirectionalIterator __last)
{
typedef typename iterator_traits<_BidirectionalIterator>::value_type value_type;
+ // TODO(ranges): pass `_AlgPolicy` to `prev`.
_BidirectionalIterator __lm1 = _VSTD::prev(__last);
- value_type __tmp = _VSTD::move(*__lm1);
+ value_type __tmp = _IterOps<_AlgPolicy>::__iter_move(__lm1);
+ // TODO(ranges): pass `_AlgPolicy` to `move_backward`.
_BidirectionalIterator __fp1 = _VSTD::move_backward(__first, __lm1, __last);
*__first = _VSTD::move(__tmp);
return __fp1;
}
-template <class _ForwardIterator>
+template <class _AlgPolicy, class _ForwardIterator>
_LIBCPP_CONSTEXPR_AFTER_CXX14 _ForwardIterator
__rotate_forward(_ForwardIterator __first, _ForwardIterator __middle, _ForwardIterator __last)
{
_ForwardIterator __i = __middle;
while (true)
{
- swap(*__first, *__i);
+ _IterOps<_AlgPolicy>::iter_swap(__first, __i);
++__first;
if (++__i == __last)
break;
@@ -69,7 +73,7 @@ __rotate_forward(_ForwardIterator __first, _ForwardIterator __middle, _ForwardIt
__i = __middle;
while (true)
{
- swap(*__first, *__i);
+ _IterOps<_AlgPolicy>::iter_swap(__first, __i);
++__first;
if (++__i == __last)
{
@@ -98,7 +102,7 @@ __algo_gcd(_Integral __x, _Integral __y)
return __x;
}
-template<typename _RandomAccessIterator>
+template <class _AlgPolicy, typename _RandomAccessIterator>
_LIBCPP_CONSTEXPR_AFTER_CXX14 _RandomAccessIterator
__rotate_gcd(_RandomAccessIterator __first, _RandomAccessIterator __middle, _RandomAccessIterator __last)
{
@@ -109,18 +113,19 @@ __rotate_gcd(_RandomAccessIterator __first, _RandomAccessIterator __middle, _Ran
const difference_type __m2 = __last - __middle;
if (__m1 == __m2)
{
+ // TODO(ranges): pass `_AlgPolicy` to `swap_ranges`.
_VSTD::swap_ranges(__first, __middle, __middle);
return __middle;
}
const difference_type __g = _VSTD::__algo_gcd(__m1, __m2);
for (_RandomAccessIterator __p = __first + __g; __p != __first;)
{
- value_type __t(_VSTD::move(*--__p));
+ value_type __t(_IterOps<_AlgPolicy>::__iter_move(--__p));
_RandomAccessIterator __p1 = __p;
_RandomAccessIterator __p2 = __p1 + __m1;
do
{
- *__p1 = _VSTD::move(*__p2);
+ *__p1 = _IterOps<_AlgPolicy>::__iter_move(__p2);
__p1 = __p2;
const difference_type __d = __last - __p2;
if (__m1 < __d)
@@ -133,54 +138,66 @@ __rotate_gcd(_RandomAccessIterator __first, _RandomAccessIterator __middle, _Ran
return __first + __m2;
}
-template <class _ForwardIterator>
+template <class _AlgPolicy, class _ForwardIterator>
inline _LIBCPP_INLINE_VISIBILITY
_LIBCPP_CONSTEXPR_AFTER_CXX11 _ForwardIterator
-__rotate(_ForwardIterator __first, _ForwardIterator __middle, _ForwardIterator __last,
+__rotate_impl(_ForwardIterator __first, _ForwardIterator __middle, _ForwardIterator __last,
_VSTD::forward_iterator_tag)
{
typedef typename iterator_traits<_ForwardIterator>::value_type value_type;
if (is_trivially_move_assignable<value_type>::value)
{
- if (_VSTD::next(__first) == __middle)
- return _VSTD::__rotate_left(__first, __last);
+ if (_IterOps<_AlgPolicy>::next(__first) == __middle)
+ return std::__rotate_left<_AlgPolicy>(__first, __last);
}
- return _VSTD::__rotate_forward(__first, __middle, __last);
+ return std::__rotate_forward<_AlgPolicy>(__first, __middle, __last);
}
-template <class _BidirectionalIterator>
+template <class _AlgPolicy, class _BidirectionalIterator>
inline _LIBCPP_INLINE_VISIBILITY
_LIBCPP_CONSTEXPR_AFTER_CXX11 _BidirectionalIterator
-__rotate(_BidirectionalIterator __first, _BidirectionalIterator __middle, _BidirectionalIterator __last,
+__rotate_impl(_BidirectionalIterator __first, _BidirectionalIterator __middle, _BidirectionalIterator __last,
bidirectional_iterator_tag)
{
typedef typename iterator_traits<_BidirectionalIterator>::value_type value_type;
if (is_trivially_move_assignable<value_type>::value)
{
- if (_VSTD::next(__first) == __middle)
- return _VSTD::__rotate_left(__first, __last);
- if (_VSTD::next(__middle) == __last)
- return _VSTD::__rotate_right(__first, __last);
+ if (_IterOps<_AlgPolicy>::next(__first) == __middle)
+ return std::__rotate_left<_AlgPolicy>(__first, __last);
+ if (_IterOps<_AlgPolicy>::next(__middle) == __last)
+ return std::__rotate_right<_AlgPolicy>(__first, __last);
}
- return _VSTD::__rotate_forward(__first, __middle, __last);
+ return std::__rotate_forward<_AlgPolicy>(__first, __middle, __last);
}
-template <class _RandomAccessIterator>
+template <class _AlgPolicy, class _RandomAccessIterator>
inline _LIBCPP_INLINE_VISIBILITY
_LIBCPP_CONSTEXPR_AFTER_CXX11 _RandomAccessIterator
-__rotate(_RandomAccessIterator __first, _RandomAccessIterator __middle, _RandomAccessIterator __last,
+__rotate_impl(_RandomAccessIterator __first, _RandomAccessIterator __middle, _RandomAccessIterator __last,
random_access_iterator_tag)
{
typedef typename iterator_traits<_RandomAccessIterator>::value_type value_type;
if (is_trivially_move_assignable<value_type>::value)
{
- if (_VSTD::next(__first) == __middle)
- return _VSTD::__rotate_left(__first, __last);
- if (_VSTD::next(__middle) == __last)
- return _VSTD::__rotate_right(__first, __last);
- return _VSTD::__rotate_gcd(__first, __middle, __last);
+ if (_IterOps<_AlgPolicy>::next(__first) == __middle)
+ return std::__rotate_left<_AlgPolicy>(__first, __last);
+ if (_IterOps<_AlgPolicy>::next(__middle) == __last)
+ return std::__rotate_right<_AlgPolicy>(__first, __last);
+ return std::__rotate_gcd<_AlgPolicy>(__first, __middle, __last);
}
- return _VSTD::__rotate_forward(__first, __middle, __last);
+ return std::__rotate_forward<_AlgPolicy>(__first, __middle, __last);
+}
+
+template <class _AlgPolicy, class _RandomAccessIterator, class _IterCategory>
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX11
+_RandomAccessIterator __rotate(_RandomAccessIterator __first, _RandomAccessIterator __middle,
+ _RandomAccessIterator __last, _IterCategory __iter_category) {
+ if (__first == __middle)
+ return __last;
+ if (__middle == __last)
+ return __first;
+
+ return std::__rotate_impl<_AlgPolicy>(std::move(__first), std::move(__middle), std::move(__last), __iter_category);
}
template <class _ForwardIterator>
@@ -188,12 +205,8 @@ inline _LIBCPP_INLINE_VISIBILITY
_LIBCPP_CONSTEXPR_AFTER_CXX17 _ForwardIterator
rotate(_ForwardIterator __first, _ForwardIterator __middle, _ForwardIterator __last)
{
- if (__first == __middle)
- return __last;
- if (__middle == __last)
- return __first;
- return _VSTD::__rotate(__first, __middle, __last,
- typename iterator_traits<_ForwardIterator>::iterator_category());
+ return std::__rotate<_ClassicAlgPolicy>(__first, __middle, __last,
+ typename iterator_traits<_ForwardIterator>::iterator_category());
}
_LIBCPP_END_NAMESPACE_STD
diff --git a/libcxx/include/__algorithm/search_n.h b/libcxx/include/__algorithm/search_n.h
index 2a0547565ee9..ccb8e845f5b1 100644
--- a/libcxx/include/__algorithm/search_n.h
+++ b/libcxx/include/__algorithm/search_n.h
@@ -163,7 +163,7 @@ _ForwardIterator search_n(_ForwardIterator __first, _ForwardIterator __last,
_Size __count,
const _Tp& __value,
_BinaryPredicate __pred) {
- static_assert(__is_callable<_BinaryPredicate, decltype(*__first), decltype(*__last)>::value,
+ static_assert(__is_callable<_BinaryPredicate, decltype(*__first), const _Tp&>::value,
"BinaryPredicate has to be callable");
auto __proj = __identity();
return std::__search_n_impl(__first, __last, std::__convert_to_integral(__count), __value, __pred, __proj).first;
diff --git a/libcxx/include/__algorithm/set_union.h b/libcxx/include/__algorithm/set_union.h
index 0ec6b09380ed..3bd437980161 100644
--- a/libcxx/include/__algorithm/set_union.h
+++ b/libcxx/include/__algorithm/set_union.h
@@ -14,6 +14,7 @@
#include <__algorithm/copy.h>
#include <__config>
#include <__iterator/iterator_traits.h>
+#include <__utility/move.h>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
@@ -21,50 +22,77 @@
_LIBCPP_BEGIN_NAMESPACE_STD
-template <class _Compare, class _InputIterator1, class _InputIterator2, class _OutputIterator>
-_LIBCPP_CONSTEXPR_AFTER_CXX17 _OutputIterator
-__set_union(_InputIterator1 __first1, _InputIterator1 __last1,
- _InputIterator2 __first2, _InputIterator2 __last2, _OutputIterator __result, _Compare __comp)
-{
- for (; __first1 != __last1; ++__result)
- {
- if (__first2 == __last2)
- return _VSTD::copy(__first1, __last1, __result);
- if (__comp(*__first2, *__first1))
- {
- *__result = *__first2;
- ++__first2;
- }
- else
- {
- if (!__comp(*__first1, *__first2))
- ++__first2;
- *__result = *__first1;
- ++__first1;
- }
+template <class _InIter1, class _InIter2, class _OutIter>
+struct __set_union_result {
+ _InIter1 __in1_;
+ _InIter2 __in2_;
+ _OutIter __out_;
+
+ // need a constructor as C++03 aggregate init is hard
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17
+ __set_union_result(_InIter1&& __in_iter1, _InIter2&& __in_iter2, _OutIter&& __out_iter)
+ : __in1_(std::move(__in_iter1)), __in2_(std::move(__in_iter2)), __out_(std::move(__out_iter)) {}
+};
+
+template <class _Compare, class _InIter1, class _Sent1, class _InIter2, class _Sent2, class _OutIter>
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17 __set_union_result<_InIter1, _InIter2, _OutIter> __set_union(
+ _InIter1 __first1, _Sent1 __last1, _InIter2 __first2, _Sent2 __last2, _OutIter __result, _Compare&& __comp) {
+ for (; __first1 != __last1; ++__result) {
+ if (__first2 == __last2) {
+ auto __ret1 = std::__copy_impl(std::move(__first1), std::move(__last1), std::move(__result));
+ return __set_union_result<_InIter1, _InIter2, _OutIter>(
+ std::move(__ret1.first), std::move(__first2), std::move((__ret1.second)));
+ }
+ if (__comp(*__first2, *__first1)) {
+ *__result = *__first2;
+ ++__first2;
+ } else {
+ if (!__comp(*__first1, *__first2)) {
+ ++__first2;
+ }
+ *__result = *__first1;
+ ++__first1;
}
- return _VSTD::copy(__first2, __last2, __result);
+ }
+ auto __ret2 = std::__copy_impl(std::move(__first2), std::move(__last2), std::move(__result));
+ return __set_union_result<_InIter1, _InIter2, _OutIter>(
+ std::move(__first1), std::move(__ret2.first), std::move((__ret2.second)));
}
template <class _InputIterator1, class _InputIterator2, class _OutputIterator, class _Compare>
-inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
-_OutputIterator
-set_union(_InputIterator1 __first1, _InputIterator1 __last1,
- _InputIterator2 __first2, _InputIterator2 __last2, _OutputIterator __result, _Compare __comp)
-{
- typedef typename __comp_ref_type<_Compare>::type _Comp_ref;
- return _VSTD::__set_union<_Comp_ref>(__first1, __last1, __first2, __last2, __result, __comp);
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17 _OutputIterator set_union(
+ _InputIterator1 __first1,
+ _InputIterator1 __last1,
+ _InputIterator2 __first2,
+ _InputIterator2 __last2,
+ _OutputIterator __result,
+ _Compare __comp) {
+ typedef typename __comp_ref_type<_Compare>::type _Comp_ref;
+ return std::__set_union<_Comp_ref>(
+ std::move(__first1),
+ std::move(__last1),
+ std::move(__first2),
+ std::move(__last2),
+ std::move(__result),
+ __comp)
+ .__out_;
}
template <class _InputIterator1, class _InputIterator2, class _OutputIterator>
-inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
-_OutputIterator
-set_union(_InputIterator1 __first1, _InputIterator1 __last1,
- _InputIterator2 __first2, _InputIterator2 __last2, _OutputIterator __result)
-{
- return _VSTD::set_union(__first1, __last1, __first2, __last2, __result,
- __less<typename iterator_traits<_InputIterator1>::value_type,
- typename iterator_traits<_InputIterator2>::value_type>());
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17 _OutputIterator set_union(
+ _InputIterator1 __first1,
+ _InputIterator1 __last1,
+ _InputIterator2 __first2,
+ _InputIterator2 __last2,
+ _OutputIterator __result) {
+ return std::set_union(
+ std::move(__first1),
+ std::move(__last1),
+ std::move(__first2),
+ std::move(__last2),
+ std::move(__result),
+ __less<typename iterator_traits<_InputIterator1>::value_type,
+ typename iterator_traits<_InputIterator2>::value_type>());
}
_LIBCPP_END_NAMESPACE_STD
diff --git a/libcxx/include/__algorithm/shuffle.h b/libcxx/include/__algorithm/shuffle.h
index 6c6ff5675dad..e32c6a7608ba 100644
--- a/libcxx/include/__algorithm/shuffle.h
+++ b/libcxx/include/__algorithm/shuffle.h
@@ -9,11 +9,13 @@
#ifndef _LIBCPP___ALGORITHM_SHUFFLE_H
#define _LIBCPP___ALGORITHM_SHUFFLE_H
+#include <__algorithm/iterator_operations.h>
#include <__config>
#include <__debug>
#include <__iterator/iterator_traits.h>
#include <__random/uniform_int_distribution.h>
-#include <__utility/swap.h>
+#include <__utility/forward.h>
+#include <__utility/move.h>
#include <cstddef>
#include <cstdint>
@@ -134,13 +136,15 @@ random_shuffle(_RandomAccessIterator __first, _RandomAccessIterator __last,
}
#endif
-template<class _RandomAccessIterator, class _UniformRandomNumberGenerator>
- void shuffle(_RandomAccessIterator __first, _RandomAccessIterator __last,
- _UniformRandomNumberGenerator&& __g)
-{
+template <class _AlgPolicy, class _RandomAccessIterator, class _Sentinel, class _UniformRandomNumberGenerator>
+_RandomAccessIterator __shuffle(
+ _RandomAccessIterator __first, _Sentinel __last_sentinel, _UniformRandomNumberGenerator&& __g) {
typedef typename iterator_traits<_RandomAccessIterator>::difference_type difference_type;
typedef uniform_int_distribution<ptrdiff_t> _Dp;
typedef typename _Dp::param_type _Pp;
+
+ auto __original_last = _IterOps<_AlgPolicy>::next(__first, __last_sentinel);
+ auto __last = __original_last;
difference_type __d = __last - __first;
if (__d > 1)
{
@@ -149,9 +153,18 @@ template<class _RandomAccessIterator, class _UniformRandomNumberGenerator>
{
difference_type __i = __uid(__g, _Pp(0, __d));
if (__i != difference_type(0))
- swap(*__first, *(__first + __i));
+ _IterOps<_AlgPolicy>::iter_swap(__first, __first + __i);
}
}
+
+ return __original_last;
+}
+
+template <class _RandomAccessIterator, class _UniformRandomNumberGenerator>
+void shuffle(_RandomAccessIterator __first, _RandomAccessIterator __last,
+ _UniformRandomNumberGenerator&& __g) {
+ (void)std::__shuffle<_ClassicAlgPolicy>(
+ std::move(__first), std::move(__last), std::forward<_UniformRandomNumberGenerator>(__g));
}
_LIBCPP_END_NAMESPACE_STD
diff --git a/libcxx/include/__algorithm/sift_down.h b/libcxx/include/__algorithm/sift_down.h
index 0351a1c578b0..be2eb29dd53a 100644
--- a/libcxx/include/__algorithm/sift_down.h
+++ b/libcxx/include/__algorithm/sift_down.h
@@ -9,6 +9,7 @@
#ifndef _LIBCPP___ALGORITHM_SIFT_DOWN_H
#define _LIBCPP___ALGORITHM_SIFT_DOWN_H
+#include <__algorithm/iterator_operations.h>
#include <__assert>
#include <__config>
#include <__iterator/iterator_traits.h>
@@ -20,12 +21,14 @@
_LIBCPP_BEGIN_NAMESPACE_STD
-template <class _Compare, class _RandomAccessIterator>
+template <class _AlgPolicy, class _Compare, class _RandomAccessIterator>
_LIBCPP_CONSTEXPR_AFTER_CXX11 void
__sift_down(_RandomAccessIterator __first, _Compare __comp,
typename iterator_traits<_RandomAccessIterator>::difference_type __len,
_RandomAccessIterator __start)
{
+ using _Ops = _IterOps<_AlgPolicy>;
+
typedef typename iterator_traits<_RandomAccessIterator>::difference_type difference_type;
typedef typename iterator_traits<_RandomAccessIterator>::value_type value_type;
// left-child of __start is at 2 * __start + 1
@@ -49,11 +52,11 @@ __sift_down(_RandomAccessIterator __first, _Compare __comp,
// we are, __start is larger than its largest child
return;
- value_type __top(_VSTD::move(*__start));
+ value_type __top(_Ops::__iter_move(__start));
do
{
// we are not in heap-order, swap the parent with its largest child
- *__start = _VSTD::move(*__child_i);
+ *__start = _Ops::__iter_move(__child_i);
__start = __child_i;
if ((__len - 2) / 2 < __child)
@@ -74,7 +77,7 @@ __sift_down(_RandomAccessIterator __first, _Compare __comp,
*__start = _VSTD::move(__top);
}
-template <class _Compare, class _RandomAccessIterator>
+template <class _AlgPolicy, class _Compare, class _RandomAccessIterator>
_LIBCPP_CONSTEXPR_AFTER_CXX11 _RandomAccessIterator
__floyd_sift_down(_RandomAccessIterator __first, _Compare __comp,
typename iterator_traits<_RandomAccessIterator>::difference_type __len)
@@ -97,7 +100,7 @@ __floyd_sift_down(_RandomAccessIterator __first, _Compare __comp,
}
// swap __hole with its largest child
- *__hole = std::move(*__child_i);
+ *__hole = _IterOps<_AlgPolicy>::__iter_move(__child_i);
__hole = __child_i;
// if __hole is now a leaf, we're done
diff --git a/libcxx/include/__algorithm/sort.h b/libcxx/include/__algorithm/sort.h
index 76a18215731b..1ca2f1b81712 100644
--- a/libcxx/include/__algorithm/sort.h
+++ b/libcxx/include/__algorithm/sort.h
@@ -11,6 +11,7 @@
#include <__algorithm/comp.h>
#include <__algorithm/comp_ref_type.h>
+#include <__algorithm/iterator_operations.h>
#include <__algorithm/min_element.h>
#include <__algorithm/partial_sort.h>
#include <__algorithm/unwrap_iter.h>
@@ -21,7 +22,6 @@
#include <__functional/operations.h>
#include <__functional/ranges_operations.h>
#include <__iterator/iterator_traits.h>
-#include <__utility/swap.h>
#include <climits>
#include <memory>
@@ -31,37 +31,85 @@
_LIBCPP_BEGIN_NAMESPACE_STD
+// Wraps an algorithm policy tag and a comparator in a single struct, used to pass the policy tag around without
+// changing the number of template arguments (to keep the ABI stable). This is only used for the "range" policy tag.
+//
+// To create an object of this type, use `_WrapAlgPolicy<T, C>::type` -- see the specialization below for the rationale.
+template <class _PolicyT, class _CompT, class = void>
+struct _WrapAlgPolicy {
+ using type = _WrapAlgPolicy;
+
+ using _AlgPolicy = _PolicyT;
+ using _Comp = _CompT;
+ _Comp& __comp;
+
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX11
+ _WrapAlgPolicy(_Comp& __c) : __comp(__c) {}
+};
+
+// Specialization for the "classic" policy tag that avoids creating a struct and simply defines an alias for the
+// comparator. When unwrapping, a pristine comparator is always considered to have the "classic" tag attached. Passing
+// the pristine comparator where possible allows using template instantiations from the dylib.
+template <class _PolicyT, class _CompT>
+struct _WrapAlgPolicy<_PolicyT, _CompT, __enable_if_t<std::is_same<_PolicyT, _ClassicAlgPolicy>::value> > {
+ using type = _CompT;
+};
+
+// Unwraps a pristine functor (e.g. `std::less`) as if it were wrapped using `_WrapAlgPolicy`. The policy tag is always
+// set to "classic".
+template <class _CompT>
+struct _UnwrapAlgPolicy {
+ using _AlgPolicy = _ClassicAlgPolicy;
+ using _Comp = _CompT;
+
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX11 static
+ _Comp __get_comp(_Comp __comp) { return __comp; }
+};
+
+// Unwraps a `_WrapAlgPolicy` struct.
+template <class... _Ts>
+struct _UnwrapAlgPolicy<_WrapAlgPolicy<_Ts...> > {
+ using _Wrapped = _WrapAlgPolicy<_Ts...>;
+ using _AlgPolicy = typename _Wrapped::_AlgPolicy;
+ using _Comp = typename _Wrapped::_Comp;
+
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX11 static
+ _Comp __get_comp(_Wrapped& __w) { return __w.__comp; }
+};
+
// stable, 2-3 compares, 0-2 swaps
-template <class _Compare, class _ForwardIterator>
+template <class _AlgPolicy, class _Compare, class _ForwardIterator>
_LIBCPP_CONSTEXPR_AFTER_CXX11 unsigned __sort3(_ForwardIterator __x, _ForwardIterator __y, _ForwardIterator __z,
_Compare __c) {
+ using _Ops = _IterOps<_AlgPolicy>;
+
unsigned __r = 0;
if (!__c(*__y, *__x)) // if x <= y
{
if (!__c(*__z, *__y)) // if y <= z
return __r; // x <= y && y <= z
// x <= y && y > z
- swap(*__y, *__z); // x <= z && y < z
+ _Ops::iter_swap(__y, __z); // x <= z && y < z
__r = 1;
if (__c(*__y, *__x)) // if x > y
{
- swap(*__x, *__y); // x < y && y <= z
+ _Ops::iter_swap(__x, __y); // x < y && y <= z
__r = 2;
}
return __r; // x <= y && y < z
}
if (__c(*__z, *__y)) // x > y, if y > z
{
- swap(*__x, *__z); // x < y && y < z
+ _Ops::iter_swap(__x, __z); // x < y && y < z
__r = 1;
return __r;
}
- swap(*__x, *__y); // x > y && y <= z
+ _Ops::iter_swap(__x, __y); // x > y && y <= z
__r = 1; // x < y && x <= z
if (__c(*__z, *__y)) // if y > z
{
- swap(*__y, *__z); // x <= y && y < z
+ _Ops::iter_swap(__y, __z); // x <= y && y < z
__r = 2;
}
return __r;
@@ -69,18 +117,20 @@ _LIBCPP_CONSTEXPR_AFTER_CXX11 unsigned __sort3(_ForwardIterator __x, _ForwardIte
// stable, 3-6 compares, 0-5 swaps
-template <class _Compare, class _ForwardIterator>
+template <class _AlgPolicy, class _Compare, class _ForwardIterator>
unsigned __sort4(_ForwardIterator __x1, _ForwardIterator __x2, _ForwardIterator __x3, _ForwardIterator __x4,
_Compare __c) {
- unsigned __r = _VSTD::__sort3<_Compare>(__x1, __x2, __x3, __c);
+ using _Ops = _IterOps<_AlgPolicy>;
+
+ unsigned __r = std::__sort3<_AlgPolicy, _Compare>(__x1, __x2, __x3, __c);
if (__c(*__x4, *__x3)) {
- swap(*__x3, *__x4);
+ _Ops::iter_swap(__x3, __x4);
++__r;
if (__c(*__x3, *__x2)) {
- swap(*__x2, *__x3);
+ _Ops::iter_swap(__x2, __x3);
++__r;
if (__c(*__x2, *__x1)) {
- swap(*__x1, *__x2);
+ _Ops::iter_swap(__x1, __x2);
++__r;
}
}
@@ -90,21 +140,28 @@ unsigned __sort4(_ForwardIterator __x1, _ForwardIterator __x2, _ForwardIterator
// stable, 4-10 compares, 0-9 swaps
-template <class _Compare, class _ForwardIterator>
+template <class _WrappedComp, class _ForwardIterator>
_LIBCPP_HIDDEN unsigned __sort5(_ForwardIterator __x1, _ForwardIterator __x2, _ForwardIterator __x3,
- _ForwardIterator __x4, _ForwardIterator __x5, _Compare __c) {
- unsigned __r = _VSTD::__sort4<_Compare>(__x1, __x2, __x3, __x4, __c);
+ _ForwardIterator __x4, _ForwardIterator __x5, _WrappedComp __wrapped_comp) {
+ using _Unwrap = _UnwrapAlgPolicy<_WrappedComp>;
+ using _AlgPolicy = typename _Unwrap::_AlgPolicy;
+ using _Ops = _IterOps<_AlgPolicy>;
+
+ using _Compare = typename _Unwrap::_Comp;
+ _Compare __c = _Unwrap::__get_comp(__wrapped_comp);
+
+ unsigned __r = std::__sort4<_AlgPolicy, _Compare>(__x1, __x2, __x3, __x4, __c);
if (__c(*__x5, *__x4)) {
- swap(*__x4, *__x5);
+ _Ops::iter_swap(__x4, __x5);
++__r;
if (__c(*__x4, *__x3)) {
- swap(*__x3, *__x4);
+ _Ops::iter_swap(__x3, __x4);
++__r;
if (__c(*__x3, *__x2)) {
- swap(*__x2, *__x3);
+ _Ops::iter_swap(__x2, __x3);
++__r;
if (__c(*__x2, *__x1)) {
- swap(*__x1, *__x2);
+ _Ops::iter_swap(__x1, __x2);
++__r;
}
}
@@ -113,6 +170,16 @@ _LIBCPP_HIDDEN unsigned __sort5(_ForwardIterator __x1, _ForwardIterator __x2, _F
return __r;
}
+template <class _AlgPolicy, class _Compare, class _ForwardIterator>
+_LIBCPP_HIDDEN unsigned __sort5_wrap_policy(
+ _ForwardIterator __x1, _ForwardIterator __x2, _ForwardIterator __x3, _ForwardIterator __x4, _ForwardIterator __x5,
+ _Compare __c) {
+ using _WrappedComp = typename _WrapAlgPolicy<_AlgPolicy, _Compare>::type;
+ _WrappedComp __wrapped_comp(__c);
+ return std::__sort5<_WrappedComp>(
+ std::move(__x1), std::move(__x2), std::move(__x3), std::move(__x4), std::move(__x5), __wrapped_comp);
+}
+
// The comparator being simple is a prerequisite for using the branchless optimization.
template <class _Tp>
struct __is_simple_comparator : false_type {};
@@ -137,6 +204,7 @@ using __use_branchless_sort =
// Ensures that __c(*__x, *__y) is true by swapping *__x and *__y if necessary.
template <class _Compare, class _RandomAccessIterator>
inline _LIBCPP_HIDE_FROM_ABI void __cond_swap(_RandomAccessIterator __x, _RandomAccessIterator __y, _Compare __c) {
+ // Note: this function behaves correctly even with proxy iterators (because it relies on `value_type`).
using value_type = typename iterator_traits<_RandomAccessIterator>::value_type;
bool __r = __c(*__x, *__y);
value_type __tmp = __r ? *__x : *__y;
@@ -149,6 +217,7 @@ inline _LIBCPP_HIDE_FROM_ABI void __cond_swap(_RandomAccessIterator __x, _Random
template <class _Compare, class _RandomAccessIterator>
inline _LIBCPP_HIDE_FROM_ABI void __partially_sorted_swap(_RandomAccessIterator __x, _RandomAccessIterator __y,
_RandomAccessIterator __z, _Compare __c) {
+ // Note: this function behaves correctly even with proxy iterators (because it relies on `value_type`).
using value_type = typename iterator_traits<_RandomAccessIterator>::value_type;
bool __r = __c(*__z, *__x);
value_type __tmp = __r ? *__z : *__x;
@@ -158,7 +227,7 @@ inline _LIBCPP_HIDE_FROM_ABI void __partially_sorted_swap(_RandomAccessIterator
*__y = __r ? *__y : __tmp;
}
-template <class _Compare, class _RandomAccessIterator>
+template <class, class _Compare, class _RandomAccessIterator>
inline _LIBCPP_HIDE_FROM_ABI __enable_if_t<__use_branchless_sort<_Compare, _RandomAccessIterator>::value, void>
__sort3_maybe_branchless(_RandomAccessIterator __x1, _RandomAccessIterator __x2, _RandomAccessIterator __x3,
_Compare __c) {
@@ -166,14 +235,14 @@ __sort3_maybe_branchless(_RandomAccessIterator __x1, _RandomAccessIterator __x2,
_VSTD::__partially_sorted_swap<_Compare>(__x1, __x2, __x3, __c);
}
-template <class _Compare, class _RandomAccessIterator>
+template <class _AlgPolicy, class _Compare, class _RandomAccessIterator>
inline _LIBCPP_HIDE_FROM_ABI __enable_if_t<!__use_branchless_sort<_Compare, _RandomAccessIterator>::value, void>
__sort3_maybe_branchless(_RandomAccessIterator __x1, _RandomAccessIterator __x2, _RandomAccessIterator __x3,
_Compare __c) {
- _VSTD::__sort3<_Compare>(__x1, __x2, __x3, __c);
+ std::__sort3<_AlgPolicy, _Compare>(__x1, __x2, __x3, __c);
}
-template <class _Compare, class _RandomAccessIterator>
+template <class, class _Compare, class _RandomAccessIterator>
inline _LIBCPP_HIDE_FROM_ABI __enable_if_t<__use_branchless_sort<_Compare, _RandomAccessIterator>::value, void>
__sort4_maybe_branchless(_RandomAccessIterator __x1, _RandomAccessIterator __x2, _RandomAccessIterator __x3,
_RandomAccessIterator __x4, _Compare __c) {
@@ -184,14 +253,14 @@ __sort4_maybe_branchless(_RandomAccessIterator __x1, _RandomAccessIterator __x2,
_VSTD::__cond_swap<_Compare>(__x2, __x3, __c);
}
-template <class _Compare, class _RandomAccessIterator>
+template <class _AlgPolicy, class _Compare, class _RandomAccessIterator>
inline _LIBCPP_HIDE_FROM_ABI __enable_if_t<!__use_branchless_sort<_Compare, _RandomAccessIterator>::value, void>
__sort4_maybe_branchless(_RandomAccessIterator __x1, _RandomAccessIterator __x2, _RandomAccessIterator __x3,
_RandomAccessIterator __x4, _Compare __c) {
- _VSTD::__sort4<_Compare>(__x1, __x2, __x3, __x4, __c);
+ std::__sort4<_AlgPolicy, _Compare>(__x1, __x2, __x3, __x4, __c);
}
-template <class _Compare, class _RandomAccessIterator>
+template <class, class _Compare, class _RandomAccessIterator>
inline _LIBCPP_HIDE_FROM_ABI __enable_if_t<__use_branchless_sort<_Compare, _RandomAccessIterator>::value, void>
__sort5_maybe_branchless(_RandomAccessIterator __x1, _RandomAccessIterator __x2, _RandomAccessIterator __x3,
_RandomAccessIterator __x4, _RandomAccessIterator __x5, _Compare __c) {
@@ -203,53 +272,57 @@ __sort5_maybe_branchless(_RandomAccessIterator __x1, _RandomAccessIterator __x2,
_VSTD::__partially_sorted_swap<_Compare>(__x2, __x3, __x4, __c);
}
-template <class _Compare, class _RandomAccessIterator>
+template <class _AlgPolicy, class _Compare, class _RandomAccessIterator>
inline _LIBCPP_HIDE_FROM_ABI __enable_if_t<!__use_branchless_sort<_Compare, _RandomAccessIterator>::value, void>
__sort5_maybe_branchless(_RandomAccessIterator __x1, _RandomAccessIterator __x2, _RandomAccessIterator __x3,
_RandomAccessIterator __x4, _RandomAccessIterator __x5, _Compare __c) {
- _VSTD::__sort5<_Compare>(__x1, __x2, __x3, __x4, __x5, __c);
+ std::__sort5_wrap_policy<_AlgPolicy, _Compare>(__x1, __x2, __x3, __x4, __x5, __c);
}
// Assumes size > 0
-template <class _Compare, class _BidirectionalIterator>
+template <class _AlgPolicy, class _Compare, class _BidirectionalIterator>
_LIBCPP_CONSTEXPR_AFTER_CXX11 void __selection_sort(_BidirectionalIterator __first, _BidirectionalIterator __last,
_Compare __comp) {
_BidirectionalIterator __lm1 = __last;
for (--__lm1; __first != __lm1; ++__first) {
- _BidirectionalIterator __i = _VSTD::min_element(__first, __last, __comp);
+ _BidirectionalIterator __i = std::__min_element<_Compare>(__first, __last, __comp);
if (__i != __first)
- swap(*__first, *__i);
+ _IterOps<_AlgPolicy>::iter_swap(__first, __i);
}
}
-template <class _Compare, class _BidirectionalIterator>
+template <class _AlgPolicy, class _Compare, class _BidirectionalIterator>
void __insertion_sort(_BidirectionalIterator __first, _BidirectionalIterator __last, _Compare __comp) {
+ using _Ops = _IterOps<_AlgPolicy>;
+
typedef typename iterator_traits<_BidirectionalIterator>::value_type value_type;
if (__first != __last) {
_BidirectionalIterator __i = __first;
for (++__i; __i != __last; ++__i) {
_BidirectionalIterator __j = __i;
- value_type __t(_VSTD::move(*__j));
+ value_type __t(_Ops::__iter_move(__j));
for (_BidirectionalIterator __k = __i; __k != __first && __comp(__t, *--__k); --__j)
- *__j = _VSTD::move(*__k);
+ *__j = _Ops::__iter_move(__k);
*__j = _VSTD::move(__t);
}
}
}
-template <class _Compare, class _RandomAccessIterator>
+template <class _AlgPolicy, class _Compare, class _RandomAccessIterator>
void __insertion_sort_3(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp) {
+ using _Ops = _IterOps<_AlgPolicy>;
+
typedef typename iterator_traits<_RandomAccessIterator>::difference_type difference_type;
typedef typename iterator_traits<_RandomAccessIterator>::value_type value_type;
_RandomAccessIterator __j = __first + difference_type(2);
- _VSTD::__sort3_maybe_branchless<_Compare>(__first, __first + difference_type(1), __j, __comp);
+ std::__sort3_maybe_branchless<_AlgPolicy, _Compare>(__first, __first + difference_type(1), __j, __comp);
for (_RandomAccessIterator __i = __j + difference_type(1); __i != __last; ++__i) {
if (__comp(*__i, *__j)) {
- value_type __t(_VSTD::move(*__i));
+ value_type __t(_Ops::__iter_move(__i));
_RandomAccessIterator __k = __j;
__j = __i;
do {
- *__j = _VSTD::move(*__k);
+ *__j = _Ops::__iter_move(__k);
__j = __k;
} while (__j != __first && __comp(__t, *--__k));
*__j = _VSTD::move(__t);
@@ -258,8 +331,16 @@ void __insertion_sort_3(_RandomAccessIterator __first, _RandomAccessIterator __l
}
}
-template <class _Compare, class _RandomAccessIterator>
-bool __insertion_sort_incomplete(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp) {
+template <class _WrappedComp, class _RandomAccessIterator>
+bool __insertion_sort_incomplete(
+ _RandomAccessIterator __first, _RandomAccessIterator __last, _WrappedComp __wrapped_comp) {
+ using _Unwrap = _UnwrapAlgPolicy<_WrappedComp>;
+ using _AlgPolicy = typename _Unwrap::_AlgPolicy;
+ using _Ops = _IterOps<_AlgPolicy>;
+
+ using _Compare = typename _Unwrap::_Comp;
+ _Compare __comp = _Unwrap::__get_comp(__wrapped_comp);
+
typedef typename iterator_traits<_RandomAccessIterator>::difference_type difference_type;
switch (__last - __first) {
case 0:
@@ -267,32 +348,33 @@ bool __insertion_sort_incomplete(_RandomAccessIterator __first, _RandomAccessIte
return true;
case 2:
if (__comp(*--__last, *__first))
- swap(*__first, *__last);
+ _IterOps<_AlgPolicy>::iter_swap(__first, __last);
return true;
case 3:
- _VSTD::__sort3_maybe_branchless<_Compare>(__first, __first + difference_type(1), --__last, __comp);
+ std::__sort3_maybe_branchless<_AlgPolicy, _Compare>(__first, __first + difference_type(1), --__last, __comp);
return true;
case 4:
- _VSTD::__sort4_maybe_branchless<_Compare>(__first, __first + difference_type(1), __first + difference_type(2),
- --__last, __comp);
+ std::__sort4_maybe_branchless<_AlgPolicy, _Compare>(
+ __first, __first + difference_type(1), __first + difference_type(2), --__last, __comp);
return true;
case 5:
- _VSTD::__sort5_maybe_branchless<_Compare>(__first, __first + difference_type(1), __first + difference_type(2),
- __first + difference_type(3), --__last, __comp);
+ std::__sort5_maybe_branchless<_AlgPolicy, _Compare>(
+ __first, __first + difference_type(1), __first + difference_type(2), __first + difference_type(3),
+ --__last, __comp);
return true;
}
typedef typename iterator_traits<_RandomAccessIterator>::value_type value_type;
_RandomAccessIterator __j = __first + difference_type(2);
- _VSTD::__sort3_maybe_branchless<_Compare>(__first, __first + difference_type(1), __j, __comp);
+ std::__sort3_maybe_branchless<_AlgPolicy, _Compare>(__first, __first + difference_type(1), __j, __comp);
const unsigned __limit = 8;
unsigned __count = 0;
for (_RandomAccessIterator __i = __j + difference_type(1); __i != __last; ++__i) {
if (__comp(*__i, *__j)) {
- value_type __t(_VSTD::move(*__i));
+ value_type __t(_Ops::__iter_move(__i));
_RandomAccessIterator __k = __j;
__j = __i;
do {
- *__j = _VSTD::move(*__k);
+ *__j = _Ops::__iter_move(__k);
__j = __k;
} while (__j != __first && __comp(__t, *--__k));
*__j = _VSTD::move(__t);
@@ -304,27 +386,29 @@ bool __insertion_sort_incomplete(_RandomAccessIterator __first, _RandomAccessIte
return true;
}
-template <class _Compare, class _BidirectionalIterator>
+template <class _AlgPolicy, class _Compare, class _BidirectionalIterator>
void __insertion_sort_move(_BidirectionalIterator __first1, _BidirectionalIterator __last1,
typename iterator_traits<_BidirectionalIterator>::value_type* __first2, _Compare __comp) {
+ using _Ops = _IterOps<_AlgPolicy>;
+
typedef typename iterator_traits<_BidirectionalIterator>::value_type value_type;
if (__first1 != __last1) {
__destruct_n __d(0);
unique_ptr<value_type, __destruct_n&> __h(__first2, __d);
value_type* __last2 = __first2;
- ::new ((void*)__last2) value_type(_VSTD::move(*__first1));
+ ::new ((void*)__last2) value_type(_Ops::__iter_move(__first1));
__d.template __incr<value_type>();
for (++__last2; ++__first1 != __last1; ++__last2) {
value_type* __j2 = __last2;
value_type* __i2 = __j2;
if (__comp(*__first1, *--__i2)) {
- ::new ((void*)__j2) value_type(_VSTD::move(*__i2));
+ ::new ((void*)__j2) value_type(std::move(*__i2));
__d.template __incr<value_type>();
for (--__j2; __i2 != __first2 && __comp(*__first1, *--__i2); --__j2)
- *__j2 = _VSTD::move(*__i2);
- *__j2 = _VSTD::move(*__first1);
+ *__j2 = std::move(*__i2);
+ *__j2 = _Ops::__iter_move(__first1);
} else {
- ::new ((void*)__j2) value_type(_VSTD::move(*__first1));
+ ::new ((void*)__j2) value_type(_Ops::__iter_move(__first1));
__d.template __incr<value_type>();
}
}
@@ -332,9 +416,11 @@ void __insertion_sort_move(_BidirectionalIterator __first1, _BidirectionalIterat
}
}
-template <class _Compare, class _RandomAccessIterator>
+template <class _AlgPolicy, class _Compare, class _RandomAccessIterator>
void __introsort(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp,
typename iterator_traits<_RandomAccessIterator>::difference_type __depth) {
+ using _Ops = _IterOps<_AlgPolicy>;
+
typedef typename iterator_traits<_RandomAccessIterator>::difference_type difference_type;
typedef typename iterator_traits<_RandomAccessIterator>::value_type value_type;
const difference_type __limit =
@@ -348,28 +434,29 @@ void __introsort(_RandomAccessIterator __first, _RandomAccessIterator __last, _C
return;
case 2:
if (__comp(*--__last, *__first))
- swap(*__first, *__last);
+ _IterOps<_AlgPolicy>::iter_swap(__first, __last);
return;
case 3:
- _VSTD::__sort3_maybe_branchless<_Compare>(__first, __first + difference_type(1), --__last, __comp);
+ std::__sort3_maybe_branchless<_AlgPolicy, _Compare>(__first, __first + difference_type(1), --__last, __comp);
return;
case 4:
- _VSTD::__sort4_maybe_branchless<_Compare>(__first, __first + difference_type(1), __first + difference_type(2),
- --__last, __comp);
+ std::__sort4_maybe_branchless<_AlgPolicy, _Compare>(
+ __first, __first + difference_type(1), __first + difference_type(2), --__last, __comp);
return;
case 5:
- _VSTD::__sort5_maybe_branchless<_Compare>(__first, __first + difference_type(1), __first + difference_type(2),
- __first + difference_type(3), --__last, __comp);
+ std::__sort5_maybe_branchless<_AlgPolicy, _Compare>(
+ __first, __first + difference_type(1), __first + difference_type(2), __first + difference_type(3),
+ --__last, __comp);
return;
}
if (__len <= __limit) {
- _VSTD::__insertion_sort_3<_Compare>(__first, __last, __comp);
+ std::__insertion_sort_3<_AlgPolicy, _Compare>(__first, __last, __comp);
return;
}
// __len > 5
if (__depth == 0) {
// Fallback to heap sort as Introsort suggests.
- _VSTD::__partial_sort<_Compare>(__first, __last, __last, __comp);
+ std::__partial_sort<_AlgPolicy, _Compare>(__first, __last, __last, __comp);
return;
}
--__depth;
@@ -383,11 +470,12 @@ void __introsort(_RandomAccessIterator __first, _RandomAccessIterator __last, _C
__delta = __len / 2;
__m += __delta;
__delta /= 2;
- __n_swaps = _VSTD::__sort5<_Compare>(__first, __first + __delta, __m, __m + __delta, __lm1, __comp);
+ __n_swaps = std::__sort5_wrap_policy<_AlgPolicy, _Compare>(
+ __first, __first + __delta, __m, __m + __delta, __lm1, __comp);
} else {
__delta = __len / 2;
__m += __delta;
- __n_swaps = _VSTD::__sort3<_Compare>(__first, __m, __lm1, __comp);
+ __n_swaps = std::__sort3<_AlgPolicy, _Compare>(__first, __m, __lm1, __comp);
}
}
// *__m is median
@@ -414,7 +502,7 @@ void __introsort(_RandomAccessIterator __first, _RandomAccessIterator __last, _C
if (__i == __j)
return; // [__first, __last) all equivalent elements
if (__comp(*__first, *__i)) {
- swap(*__i, *__j);
+ _Ops::iter_swap(__i, __j);
++__n_swaps;
++__i;
break;
@@ -432,7 +520,7 @@ void __introsort(_RandomAccessIterator __first, _RandomAccessIterator __last, _C
;
if (__i >= __j)
break;
- swap(*__i, *__j);
+ _Ops::iter_swap(__i, __j);
++__n_swaps;
++__i;
}
@@ -443,7 +531,7 @@ void __introsort(_RandomAccessIterator __first, _RandomAccessIterator __last, _C
goto __restart;
}
if (__comp(*__j, *__m)) {
- swap(*__i, *__j);
+ _Ops::iter_swap(__i, __j);
++__n_swaps;
break; // found guard for downward moving __j, now use unguarded partition
}
@@ -465,7 +553,7 @@ void __introsort(_RandomAccessIterator __first, _RandomAccessIterator __last, _C
;
if (__i > __j)
break;
- swap(*__i, *__j);
+ _Ops::iter_swap(__i, __j);
++__n_swaps;
// It is known that __m != __j
// If __m just moved, follow it
@@ -476,14 +564,16 @@ void __introsort(_RandomAccessIterator __first, _RandomAccessIterator __last, _C
}
// [__first, __i) < *__m and *__m <= [__i, __last)
if (__i != __m && __comp(*__m, *__i)) {
- swap(*__i, *__m);
+ _Ops::iter_swap(__i, __m);
++__n_swaps;
}
// [__first, __i) < *__i and *__i <= [__i+1, __last)
// If we were given a perfect partition, see if insertion sort is quick...
if (__n_swaps == 0) {
- bool __fs = _VSTD::__insertion_sort_incomplete<_Compare>(__first, __i, __comp);
- if (_VSTD::__insertion_sort_incomplete<_Compare>(__i + difference_type(1), __last, __comp)) {
+ using _WrappedComp = typename _WrapAlgPolicy<_AlgPolicy, _Compare>::type;
+ _WrappedComp __wrapped_comp(__comp);
+ bool __fs = std::__insertion_sort_incomplete<_WrappedComp>(__first, __i, __wrapped_comp);
+ if (std::__insertion_sort_incomplete<_WrappedComp>(__i + difference_type(1), __last, __wrapped_comp)) {
if (__fs)
return;
__last = __i;
@@ -497,10 +587,10 @@ void __introsort(_RandomAccessIterator __first, _RandomAccessIterator __last, _C
}
// sort smaller range with recursive call and larger with tail recursion elimination
if (__i - __first < __last - __i) {
- _VSTD::__introsort<_Compare>(__first, __i, __comp, __depth);
+ std::__introsort<_AlgPolicy, _Compare>(__first, __i, __comp, __depth);
__first = ++__i;
} else {
- _VSTD::__introsort<_Compare>(__i + difference_type(1), __last, __comp, __depth);
+ std::__introsort<_AlgPolicy, _Compare>(__i + difference_type(1), __last, __comp, __depth);
__last = __i;
}
}
@@ -525,17 +615,22 @@ inline _LIBCPP_HIDE_FROM_ABI _Number __log2i(_Number __n) {
return __log2;
}
-template <class _Compare, class _RandomAccessIterator>
-void __sort(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp) {
+template <class _WrappedComp, class _RandomAccessIterator>
+void __sort(_RandomAccessIterator __first, _RandomAccessIterator __last, _WrappedComp __wrapped_comp) {
typedef typename iterator_traits<_RandomAccessIterator>::difference_type difference_type;
difference_type __depth_limit = 2 * __log2i(__last - __first);
- _VSTD::__introsort<_Compare>(__first, __last, __comp, __depth_limit);
+
+ using _Unwrap = _UnwrapAlgPolicy<_WrappedComp>;
+ using _AlgPolicy = typename _Unwrap::_AlgPolicy;
+ using _Compare = typename _Unwrap::_Comp;
+ _Compare __comp = _Unwrap::__get_comp(__wrapped_comp);
+ std::__introsort<_AlgPolicy, _Compare>(__first, __last, __comp, __depth_limit);
}
template <class _Compare, class _Tp>
inline _LIBCPP_INLINE_VISIBILITY void __sort(_Tp** __first, _Tp** __last, __less<_Tp*>&) {
__less<uintptr_t> __comp;
- _VSTD::__sort<__less<uintptr_t>&, uintptr_t*>((uintptr_t*)__first, (uintptr_t*)__last, __comp);
+ std::__sort<__less<uintptr_t>&, uintptr_t*>((uintptr_t*)__first, (uintptr_t*)__last, __comp);
}
extern template _LIBCPP_FUNC_VIS void __sort<__less<char>&, char*>(char*, char*, __less<char>&);
@@ -576,22 +671,27 @@ extern template _LIBCPP_FUNC_VIS bool __insertion_sort_incomplete<__less<long do
extern template _LIBCPP_FUNC_VIS unsigned __sort5<__less<long double>&, long double*>(long double*, long double*, long double*, long double*, long double*, __less<long double>&);
-template <class _RandomAccessIterator, class _Comp>
+template <class _AlgPolicy, class _RandomAccessIterator, class _Comp>
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17
void __sort_impl(_RandomAccessIterator __first, _RandomAccessIterator __last, _Comp& __comp) {
- std::__debug_randomize_range(__first, __last);
+ std::__debug_randomize_range<_AlgPolicy>(__first, __last);
+
using _Comp_ref = typename __comp_ref_type<_Comp>::type;
if (__libcpp_is_constant_evaluated()) {
- std::__partial_sort<_Comp_ref>(__first, __last, __last, _Comp_ref(__comp));
+ std::__partial_sort<_AlgPolicy>(__first, __last, __last, __comp);
+
} else {
- std::__sort<_Comp_ref>(std::__unwrap_iter(__first), std::__unwrap_iter(__last), _Comp_ref(__comp));
+ using _WrappedComp = typename _WrapAlgPolicy<_AlgPolicy, _Comp_ref>::type;
+ _Comp_ref __comp_ref(__comp);
+ _WrappedComp __wrapped_comp(__comp_ref);
+ std::__sort<_WrappedComp>(std::__unwrap_iter(__first), std::__unwrap_iter(__last), __wrapped_comp);
}
}
template <class _RandomAccessIterator, class _Comp>
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17
void sort(_RandomAccessIterator __first, _RandomAccessIterator __last, _Comp __comp) {
- std::__sort_impl(std::move(__first), std::move(__last), __comp);
+ std::__sort_impl<_ClassicAlgPolicy>(std::move(__first), std::move(__last), __comp);
}
template <class _RandomAccessIterator>
diff --git a/libcxx/include/__algorithm/sort_heap.h b/libcxx/include/__algorithm/sort_heap.h
index 261adedd0eaf..b9f0b2c9690d 100644
--- a/libcxx/include/__algorithm/sort_heap.h
+++ b/libcxx/include/__algorithm/sort_heap.h
@@ -11,11 +11,12 @@
#include <__algorithm/comp.h>
#include <__algorithm/comp_ref_type.h>
+#include <__algorithm/iterator_operations.h>
#include <__algorithm/pop_heap.h>
#include <__config>
#include <__iterator/iterator_traits.h>
#include <__utility/move.h>
-#include <type_traits> // swap
+#include <type_traits>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
@@ -23,7 +24,7 @@
_LIBCPP_BEGIN_NAMESPACE_STD
-template <class _Compare, class _RandomAccessIterator>
+template <class _AlgPolicy, class _Compare, class _RandomAccessIterator>
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX11
void __sort_heap(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare& __comp) {
using _CompRef = typename __comp_ref_type<_Compare>::type;
@@ -31,13 +32,16 @@ void __sort_heap(_RandomAccessIterator __first, _RandomAccessIterator __last, _C
using difference_type = typename iterator_traits<_RandomAccessIterator>::difference_type;
for (difference_type __n = __last - __first; __n > 1; --__last, (void) --__n)
- std::__pop_heap<_CompRef>(__first, __last, __comp_ref, __n);
+ std::__pop_heap<_AlgPolicy, _CompRef>(__first, __last, __comp_ref, __n);
}
template <class _RandomAccessIterator, class _Compare>
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17
void sort_heap(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp) {
- std::__sort_heap(std::move(__first), std::move(__last), __comp);
+ static_assert(std::is_copy_constructible<_RandomAccessIterator>::value, "Iterators must be copy constructible.");
+ static_assert(std::is_copy_assignable<_RandomAccessIterator>::value, "Iterators must be copy assignable.");
+
+ std::__sort_heap<_ClassicAlgPolicy>(std::move(__first), std::move(__last), __comp);
}
template <class _RandomAccessIterator>
diff --git a/libcxx/include/__algorithm/stable_partition.h b/libcxx/include/__algorithm/stable_partition.h
index 969ac7a6173e..e5ad48b2ed51 100644
--- a/libcxx/include/__algorithm/stable_partition.h
+++ b/libcxx/include/__algorithm/stable_partition.h
@@ -9,13 +9,14 @@
#ifndef _LIBCPP___ALGORITHM_STABLE_PARTITION_H
#define _LIBCPP___ALGORITHM_STABLE_PARTITION_H
+#include <__algorithm/iterator_operations.h>
#include <__algorithm/rotate.h>
#include <__config>
#include <__iterator/advance.h>
#include <__iterator/distance.h>
#include <__iterator/iterator_traits.h>
-#include <__utility/swap.h>
#include <memory>
+#include <type_traits>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
@@ -23,11 +24,13 @@
_LIBCPP_BEGIN_NAMESPACE_STD
-template <class _Predicate, class _ForwardIterator, class _Distance, class _Pair>
+template <class _AlgPolicy, class _Predicate, class _ForwardIterator, class _Distance, class _Pair>
_ForwardIterator
-__stable_partition(_ForwardIterator __first, _ForwardIterator __last, _Predicate __pred,
+__stable_partition_impl(_ForwardIterator __first, _ForwardIterator __last, _Predicate __pred,
_Distance __len, _Pair __p, forward_iterator_tag __fit)
{
+ using _Ops = _IterOps<_AlgPolicy>;
+
// *__first is known to be false
// __len >= 1
if (__len == 1)
@@ -37,7 +40,7 @@ __stable_partition(_ForwardIterator __first, _ForwardIterator __last, _Predicate
_ForwardIterator __m = __first;
if (__pred(*++__m))
{
- swap(*__first, *__m);
+ _Ops::iter_swap(__first, __m);
return __m;
}
return __first;
@@ -50,7 +53,7 @@ __stable_partition(_ForwardIterator __first, _ForwardIterator __last, _Predicate
// Move the falses into the temporary buffer, and the trues to the front of the line
// Update __first to always point to the end of the trues
value_type* __t = __p.first;
- ::new ((void*)__t) value_type(_VSTD::move(*__first));
+ ::new ((void*)__t) value_type(_Ops::__iter_move(__first));
__d.template __incr<value_type>();
++__t;
_ForwardIterator __i = __first;
@@ -58,12 +61,12 @@ __stable_partition(_ForwardIterator __first, _ForwardIterator __last, _Predicate
{
if (__pred(*__i))
{
- *__first = _VSTD::move(*__i);
+ *__first = _Ops::__iter_move(__i);
++__first;
}
else
{
- ::new ((void*)__t) value_type(_VSTD::move(*__i));
+ ::new ((void*)__t) value_type(_Ops::__iter_move(__i));
__d.template __incr<value_type>();
++__t;
}
@@ -72,7 +75,7 @@ __stable_partition(_ForwardIterator __first, _ForwardIterator __last, _Predicate
// Move falses back into range, but don't mess up __first which points to first false
__i = __first;
for (value_type* __t2 = __p.first; __t2 < __t; ++__t2, (void) ++__i)
- *__i = _VSTD::move(*__t2);
+ *__i = _Ops::__iter_move(__t2);
// __h destructs moved-from values out of the temp buffer, but doesn't deallocate buffer
return __first;
}
@@ -80,11 +83,12 @@ __stable_partition(_ForwardIterator __first, _ForwardIterator __last, _Predicate
// __len >= 3
_ForwardIterator __m = __first;
_Distance __len2 = __len / 2; // __len2 >= 2
- _VSTD::advance(__m, __len2);
+ _Ops::advance(__m, __len2);
// recurse on [__first, __m), *__first know to be false
// F?????????????????
// f m l
- _ForwardIterator __first_false = _VSTD::__stable_partition<_Predicate&>(__first, __m, __pred, __len2, __p, __fit);
+ _ForwardIterator __first_false = std::__stable_partition_impl<_AlgPolicy, _Predicate&>(
+ __first, __m, __pred, __len2, __p, __fit);
// TTTFFFFF??????????
// f ff m l
// recurse on [__m, __last], except increase __m until *(__m) is false, *__last know to be true
@@ -99,18 +103,19 @@ __stable_partition(_ForwardIterator __first, _ForwardIterator __last, _Predicate
}
// TTTFFFFFTTTF??????
// f ff m m1 l
- __second_false = _VSTD::__stable_partition<_Predicate&>(__m1, __last, __pred, __len_half, __p, __fit);
+ __second_false = std::__stable_partition_impl<_AlgPolicy, _Predicate&>(
+ __m1, __last, __pred, __len_half, __p, __fit);
__second_half_done:
// TTTFFFFFTTTTTFFFFF
// f ff m sf l
- return _VSTD::rotate(__first_false, __m, __second_false);
+ return std::__rotate<_AlgPolicy>(__first_false, __m, __second_false, __fit);
// TTTTTTTTFFFFFFFFFF
// |
}
-template <class _Predicate, class _ForwardIterator>
+template <class _AlgPolicy, class _Predicate, class _ForwardIterator>
_ForwardIterator
-__stable_partition(_ForwardIterator __first, _ForwardIterator __last, _Predicate __pred,
+__stable_partition_impl(_ForwardIterator __first, _ForwardIterator __last, _Predicate __pred,
forward_iterator_tag)
{
const unsigned __alloc_limit = 3; // might want to make this a function of trivial assignment
@@ -127,7 +132,7 @@ __stable_partition(_ForwardIterator __first, _ForwardIterator __last, _Predicate
// *__first is known to be false
typedef typename iterator_traits<_ForwardIterator>::difference_type difference_type;
typedef typename iterator_traits<_ForwardIterator>::value_type value_type;
- difference_type __len = _VSTD::distance(__first, __last);
+ difference_type __len = _IterOps<_AlgPolicy>::distance(__first, __last);
pair<value_type*, ptrdiff_t> __p(0, 0);
unique_ptr<value_type, __return_temporary_buffer> __h;
if (__len >= __alloc_limit)
@@ -138,20 +143,23 @@ _LIBCPP_SUPPRESS_DEPRECATED_PUSH
_LIBCPP_SUPPRESS_DEPRECATED_POP
__h.reset(__p.first);
}
- return _VSTD::__stable_partition<_Predicate&>(__first, __last, __pred, __len, __p, forward_iterator_tag());
+ return std::__stable_partition_impl<_AlgPolicy, _Predicate&>(
+ std::move(__first), std::move(__last), __pred, __len, __p, forward_iterator_tag());
}
-template <class _Predicate, class _BidirectionalIterator, class _Distance, class _Pair>
+template <class _AlgPolicy, class _Predicate, class _BidirectionalIterator, class _Distance, class _Pair>
_BidirectionalIterator
-__stable_partition(_BidirectionalIterator __first, _BidirectionalIterator __last, _Predicate __pred,
+__stable_partition_impl(_BidirectionalIterator __first, _BidirectionalIterator __last, _Predicate __pred,
_Distance __len, _Pair __p, bidirectional_iterator_tag __bit)
{
+ using _Ops = _IterOps<_AlgPolicy>;
+
// *__first is known to be false
// *__last is known to be true
// __len >= 2
if (__len == 2)
{
- swap(*__first, *__last);
+ _Ops::iter_swap(__first, __last);
return __last;
}
if (__len == 3)
@@ -159,12 +167,12 @@ __stable_partition(_BidirectionalIterator __first, _BidirectionalIterator __last
_BidirectionalIterator __m = __first;
if (__pred(*++__m))
{
- swap(*__first, *__m);
- swap(*__m, *__last);
+ _Ops::iter_swap(__first, __m);
+ _Ops::iter_swap(__m, __last);
return __last;
}
- swap(*__m, *__last);
- swap(*__first, *__m);
+ _Ops::iter_swap(__m, __last);
+ _Ops::iter_swap(__first, __m);
return __m;
}
if (__len <= __p.second)
@@ -175,7 +183,7 @@ __stable_partition(_BidirectionalIterator __first, _BidirectionalIterator __last
// Move the falses into the temporary buffer, and the trues to the front of the line
// Update __first to always point to the end of the trues
value_type* __t = __p.first;
- ::new ((void*)__t) value_type(_VSTD::move(*__first));
+ ::new ((void*)__t) value_type(_Ops::__iter_move(__first));
__d.template __incr<value_type>();
++__t;
_BidirectionalIterator __i = __first;
@@ -183,23 +191,23 @@ __stable_partition(_BidirectionalIterator __first, _BidirectionalIterator __last
{
if (__pred(*__i))
{
- *__first = _VSTD::move(*__i);
+ *__first = _Ops::__iter_move(__i);
++__first;
}
else
{
- ::new ((void*)__t) value_type(_VSTD::move(*__i));
+ ::new ((void*)__t) value_type(_Ops::__iter_move(__i));
__d.template __incr<value_type>();
++__t;
}
}
// move *__last, known to be true
- *__first = _VSTD::move(*__i);
+ *__first = _Ops::__iter_move(__i);
__i = ++__first;
// All trues now at start of range, all falses in buffer
// Move falses back into range, but don't mess up __first which points to first false
for (value_type* __t2 = __p.first; __t2 < __t; ++__t2, (void) ++__i)
- *__i = _VSTD::move(*__t2);
+ *__i = _Ops::__iter_move(__t2);
// __h destructs moved-from values out of the temp buffer, but doesn't deallocate buffer
return __first;
}
@@ -207,7 +215,7 @@ __stable_partition(_BidirectionalIterator __first, _BidirectionalIterator __last
// __len >= 4
_BidirectionalIterator __m = __first;
_Distance __len2 = __len / 2; // __len2 >= 2
- _VSTD::advance(__m, __len2);
+ _Ops::advance(__m, __len2);
// recurse on [__first, __m-1], except reduce __m-1 until *(__m-1) is true, *__first know to be false
// F????????????????T
// f m l
@@ -222,7 +230,8 @@ __stable_partition(_BidirectionalIterator __first, _BidirectionalIterator __last
}
// F???TFFF?????????T
// f m1 m l
- __first_false = _VSTD::__stable_partition<_Predicate&>(__first, __m1, __pred, __len_half, __p, __bit);
+ __first_false = std::__stable_partition_impl<_AlgPolicy, _Predicate&>(
+ __first, __m1, __pred, __len_half, __p, __bit);
__first_half_done:
// TTTFFFFF?????????T
// f ff m l
@@ -239,18 +248,19 @@ __first_half_done:
}
// TTTFFFFFTTTF?????T
// f ff m m1 l
- __second_false = _VSTD::__stable_partition<_Predicate&>(__m1, __last, __pred, __len_half, __p, __bit);
+ __second_false = std::__stable_partition_impl<_AlgPolicy, _Predicate&>(
+ __m1, __last, __pred, __len_half, __p, __bit);
__second_half_done:
// TTTFFFFFTTTTTFFFFF
// f ff m sf l
- return _VSTD::rotate(__first_false, __m, __second_false);
+ return std::__rotate<_AlgPolicy>(__first_false, __m, __second_false, __bit);
// TTTTTTTTFFFFFFFFFF
// |
}
-template <class _Predicate, class _BidirectionalIterator>
+template <class _AlgPolicy, class _Predicate, class _BidirectionalIterator>
_BidirectionalIterator
-__stable_partition(_BidirectionalIterator __first, _BidirectionalIterator __last, _Predicate __pred,
+__stable_partition_impl(_BidirectionalIterator __first, _BidirectionalIterator __last, _Predicate __pred,
bidirectional_iterator_tag)
{
typedef typename iterator_traits<_BidirectionalIterator>::difference_type difference_type;
@@ -276,7 +286,7 @@ __stable_partition(_BidirectionalIterator __first, _BidirectionalIterator __last
// *__first is known to be false
// *__last is known to be true
// __len >= 2
- difference_type __len = _VSTD::distance(__first, __last) + 1;
+ difference_type __len = _IterOps<_AlgPolicy>::distance(__first, __last) + 1;
pair<value_type*, ptrdiff_t> __p(0, 0);
unique_ptr<value_type, __return_temporary_buffer> __h;
if (__len >= __alloc_limit)
@@ -287,7 +297,16 @@ _LIBCPP_SUPPRESS_DEPRECATED_PUSH
_LIBCPP_SUPPRESS_DEPRECATED_POP
__h.reset(__p.first);
}
- return _VSTD::__stable_partition<_Predicate&>(__first, __last, __pred, __len, __p, bidirectional_iterator_tag());
+ return std::__stable_partition_impl<_AlgPolicy, _Predicate&>(
+ std::move(__first), std::move(__last), __pred, __len, __p, bidirectional_iterator_tag());
+}
+
+template <class _AlgPolicy, class _Predicate, class _ForwardIterator, class _IterCategory>
+_LIBCPP_HIDE_FROM_ABI
+_ForwardIterator __stable_partition(
+ _ForwardIterator __first, _ForwardIterator __last, _Predicate&& __pred, _IterCategory __iter_category) {
+ return std::__stable_partition_impl<_AlgPolicy, __uncvref_t<_Predicate>&>(
+ std::move(__first), std::move(__last), __pred, __iter_category);
}
template <class _ForwardIterator, class _Predicate>
@@ -295,7 +314,9 @@ inline _LIBCPP_INLINE_VISIBILITY
_ForwardIterator
stable_partition(_ForwardIterator __first, _ForwardIterator __last, _Predicate __pred)
{
- return _VSTD::__stable_partition<_Predicate&>(__first, __last, __pred, typename iterator_traits<_ForwardIterator>::iterator_category());
+ using _IterCategory = typename iterator_traits<_ForwardIterator>::iterator_category;
+ return std::__stable_partition<_ClassicAlgPolicy, _Predicate&>(
+ std::move(__first), std::move(__last), __pred, _IterCategory());
}
_LIBCPP_END_NAMESPACE_STD
diff --git a/libcxx/include/__algorithm/stable_sort.h b/libcxx/include/__algorithm/stable_sort.h
index e3479aad62e6..6122758bdefe 100644
--- a/libcxx/include/__algorithm/stable_sort.h
+++ b/libcxx/include/__algorithm/stable_sort.h
@@ -12,11 +12,11 @@
#include <__algorithm/comp.h>
#include <__algorithm/comp_ref_type.h>
#include <__algorithm/inplace_merge.h>
+#include <__algorithm/iterator_operations.h>
#include <__algorithm/sort.h>
#include <__config>
#include <__iterator/iterator_traits.h>
#include <__utility/move.h>
-#include <__utility/swap.h>
#include <memory>
#include <type_traits>
@@ -26,12 +26,14 @@
_LIBCPP_BEGIN_NAMESPACE_STD
-template <class _Compare, class _InputIterator1, class _InputIterator2>
+template <class _AlgPolicy, class _Compare, class _InputIterator1, class _InputIterator2>
void
__merge_move_construct(_InputIterator1 __first1, _InputIterator1 __last1,
_InputIterator2 __first2, _InputIterator2 __last2,
typename iterator_traits<_InputIterator1>::value_type* __result, _Compare __comp)
{
+ using _Ops = _IterOps<_AlgPolicy>;
+
typedef typename iterator_traits<_InputIterator1>::value_type value_type;
__destruct_n __d(0);
unique_ptr<value_type, __destruct_n&> __h(__result, __d);
@@ -40,111 +42,115 @@ __merge_move_construct(_InputIterator1 __first1, _InputIterator1 __last1,
if (__first1 == __last1)
{
for (; __first2 != __last2; ++__first2, (void) ++__result, __d.template __incr<value_type>())
- ::new ((void*)__result) value_type(_VSTD::move(*__first2));
+ ::new ((void*)__result) value_type(_Ops::__iter_move(__first2));
__h.release();
return;
}
if (__first2 == __last2)
{
for (; __first1 != __last1; ++__first1, (void) ++__result, __d.template __incr<value_type>())
- ::new ((void*)__result) value_type(_VSTD::move(*__first1));
+ ::new ((void*)__result) value_type(_Ops::__iter_move(__first1));
__h.release();
return;
}
if (__comp(*__first2, *__first1))
{
- ::new ((void*)__result) value_type(_VSTD::move(*__first2));
+ ::new ((void*)__result) value_type(_Ops::__iter_move(__first2));
__d.template __incr<value_type>();
++__first2;
}
else
{
- ::new ((void*)__result) value_type(_VSTD::move(*__first1));
+ ::new ((void*)__result) value_type(_Ops::__iter_move(__first1));
__d.template __incr<value_type>();
++__first1;
}
}
}
-template <class _Compare, class _InputIterator1, class _InputIterator2, class _OutputIterator>
+template <class _AlgPolicy, class _Compare, class _InputIterator1, class _InputIterator2, class _OutputIterator>
void
__merge_move_assign(_InputIterator1 __first1, _InputIterator1 __last1,
_InputIterator2 __first2, _InputIterator2 __last2,
_OutputIterator __result, _Compare __comp)
{
+ using _Ops = _IterOps<_AlgPolicy>;
+
for (; __first1 != __last1; ++__result)
{
if (__first2 == __last2)
{
for (; __first1 != __last1; ++__first1, (void) ++__result)
- *__result = _VSTD::move(*__first1);
+ *__result = _Ops::__iter_move(__first1);
return;
}
if (__comp(*__first2, *__first1))
{
- *__result = _VSTD::move(*__first2);
+ *__result = _Ops::__iter_move(__first2);
++__first2;
}
else
{
- *__result = _VSTD::move(*__first1);
+ *__result = _Ops::__iter_move(__first1);
++__first1;
}
}
for (; __first2 != __last2; ++__first2, (void) ++__result)
- *__result = _VSTD::move(*__first2);
+ *__result = _Ops::__iter_move(__first2);
}
-template <class _Compare, class _RandomAccessIterator>
+template <class _AlgPolicy, class _Compare, class _RandomAccessIterator>
void
__stable_sort(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp,
typename iterator_traits<_RandomAccessIterator>::difference_type __len,
typename iterator_traits<_RandomAccessIterator>::value_type* __buff, ptrdiff_t __buff_size);
-template <class _Compare, class _RandomAccessIterator>
+template <class _AlgPolicy, class _Compare, class _RandomAccessIterator>
void
__stable_sort_move(_RandomAccessIterator __first1, _RandomAccessIterator __last1, _Compare __comp,
typename iterator_traits<_RandomAccessIterator>::difference_type __len,
typename iterator_traits<_RandomAccessIterator>::value_type* __first2)
{
+ using _Ops = _IterOps<_AlgPolicy>;
+
typedef typename iterator_traits<_RandomAccessIterator>::value_type value_type;
switch (__len)
{
case 0:
return;
case 1:
- ::new ((void*)__first2) value_type(_VSTD::move(*__first1));
+ ::new ((void*)__first2) value_type(_Ops::__iter_move(__first1));
return;
case 2:
__destruct_n __d(0);
unique_ptr<value_type, __destruct_n&> __h2(__first2, __d);
if (__comp(*--__last1, *__first1))
{
- ::new ((void*)__first2) value_type(_VSTD::move(*__last1));
+ ::new ((void*)__first2) value_type(_Ops::__iter_move(__last1));
__d.template __incr<value_type>();
++__first2;
- ::new ((void*)__first2) value_type(_VSTD::move(*__first1));
+ ::new ((void*)__first2) value_type(_Ops::__iter_move(__first1));
}
else
{
- ::new ((void*)__first2) value_type(_VSTD::move(*__first1));
+ ::new ((void*)__first2) value_type(_Ops::__iter_move(__first1));
__d.template __incr<value_type>();
++__first2;
- ::new ((void*)__first2) value_type(_VSTD::move(*__last1));
+ ::new ((void*)__first2) value_type(_Ops::__iter_move(__last1));
}
__h2.release();
return;
}
if (__len <= 8)
{
- _VSTD::__insertion_sort_move<_Compare>(__first1, __last1, __first2, __comp);
+ std::__insertion_sort_move<_AlgPolicy, _Compare>(__first1, __last1, __first2, __comp);
return;
}
typename iterator_traits<_RandomAccessIterator>::difference_type __l2 = __len / 2;
_RandomAccessIterator __m = __first1 + __l2;
- _VSTD::__stable_sort<_Compare>(__first1, __m, __comp, __l2, __first2, __l2);
- _VSTD::__stable_sort<_Compare>(__m, __last1, __comp, __len - __l2, __first2 + __l2, __len - __l2);
- _VSTD::__merge_move_construct<_Compare>(__first1, __m, __m, __last1, __first2, __comp);
+ std::__stable_sort<_AlgPolicy, _Compare>(__first1, __m, __comp, __l2, __first2, __l2);
+ std::__stable_sort<_AlgPolicy, _Compare>(__m, __last1, __comp, __len - __l2, __first2 + __l2, __len - __l2);
+ std::__merge_move_construct<_AlgPolicy, _Compare>(__first1, __m, __m, __last1, __first2, __comp);
}
template <class _Tp>
@@ -153,7 +159,7 @@ struct __stable_sort_switch
static const unsigned value = 128*is_trivially_copy_assignable<_Tp>::value;
};
-template <class _Compare, class _RandomAccessIterator>
+template <class _AlgPolicy, class _Compare, class _RandomAccessIterator>
void
__stable_sort(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp,
typename iterator_traits<_RandomAccessIterator>::difference_type __len,
@@ -168,12 +174,12 @@ __stable_sort(_RandomAccessIterator __first, _RandomAccessIterator __last, _Comp
return;
case 2:
if (__comp(*--__last, *__first))
- swap(*__first, *__last);
+ _IterOps<_AlgPolicy>::iter_swap(__first, __last);
return;
}
if (__len <= static_cast<difference_type>(__stable_sort_switch<value_type>::value))
{
- _VSTD::__insertion_sort<_Compare>(__first, __last, __comp);
+ std::__insertion_sort<_AlgPolicy, _Compare>(__first, __last, __comp);
return;
}
typename iterator_traits<_RandomAccessIterator>::difference_type __l2 = __len / 2;
@@ -182,11 +188,12 @@ __stable_sort(_RandomAccessIterator __first, _RandomAccessIterator __last, _Comp
{
__destruct_n __d(0);
unique_ptr<value_type, __destruct_n&> __h2(__buff, __d);
- _VSTD::__stable_sort_move<_Compare>(__first, __m, __comp, __l2, __buff);
+ std::__stable_sort_move<_AlgPolicy, _Compare>(__first, __m, __comp, __l2, __buff);
__d.__set(__l2, (value_type*)nullptr);
- _VSTD::__stable_sort_move<_Compare>(__m, __last, __comp, __len - __l2, __buff + __l2);
+ std::__stable_sort_move<_AlgPolicy, _Compare>(__m, __last, __comp, __len - __l2, __buff + __l2);
__d.__set(__len, (value_type*)nullptr);
- _VSTD::__merge_move_assign<_Compare>(__buff, __buff + __l2, __buff + __l2, __buff + __len, __first, __comp);
+ std::__merge_move_assign<_AlgPolicy, _Compare>(
+ __buff, __buff + __l2, __buff + __l2, __buff + __len, __first, __comp);
// _VSTD::__merge<_Compare>(move_iterator<value_type*>(__buff),
// move_iterator<value_type*>(__buff + __l2),
// move_iterator<_RandomAccessIterator>(__buff + __l2),
@@ -194,12 +201,12 @@ __stable_sort(_RandomAccessIterator __first, _RandomAccessIterator __last, _Comp
// __first, __comp);
return;
}
- _VSTD::__stable_sort<_Compare>(__first, __m, __comp, __l2, __buff, __buff_size);
- _VSTD::__stable_sort<_Compare>(__m, __last, __comp, __len - __l2, __buff, __buff_size);
- _VSTD::__inplace_merge<_Compare>(__first, __m, __last, __comp, __l2, __len - __l2, __buff, __buff_size);
+ std::__stable_sort<_AlgPolicy, _Compare>(__first, __m, __comp, __l2, __buff, __buff_size);
+ std::__stable_sort<_AlgPolicy, _Compare>(__m, __last, __comp, __len - __l2, __buff, __buff_size);
+ std::__inplace_merge<_AlgPolicy, _Compare>(__first, __m, __last, __comp, __l2, __len - __l2, __buff, __buff_size);
}
-template <class _RandomAccessIterator, class _Compare>
+template <class _AlgPolicy, class _RandomAccessIterator, class _Compare>
inline _LIBCPP_HIDE_FROM_ABI
void __stable_sort_impl(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare& __comp) {
using value_type = typename iterator_traits<_RandomAccessIterator>::value_type;
@@ -217,13 +224,13 @@ _LIBCPP_SUPPRESS_DEPRECATED_POP
}
using _Comp_ref = typename __comp_ref_type<_Compare>::type;
- std::__stable_sort<_Comp_ref>(__first, __last, __comp, __len, __buf.first, __buf.second);
+ std::__stable_sort<_AlgPolicy, _Comp_ref>(__first, __last, __comp, __len, __buf.first, __buf.second);
}
template <class _RandomAccessIterator, class _Compare>
inline _LIBCPP_HIDE_FROM_ABI
void stable_sort(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare __comp) {
- std::__stable_sort_impl(std::move(__first), std::move(__last), __comp);
+ std::__stable_sort_impl<_ClassicAlgPolicy>(std::move(__first), std::move(__last), __comp);
}
template <class _RandomAccessIterator>
diff --git a/libcxx/include/__algorithm/unwrap_iter.h b/libcxx/include/__algorithm/unwrap_iter.h
index 7d1807b7bbf9..fa9a8fbf2dde 100644
--- a/libcxx/include/__algorithm/unwrap_iter.h
+++ b/libcxx/include/__algorithm/unwrap_iter.h
@@ -12,6 +12,7 @@
#include <__config>
#include <__iterator/iterator_traits.h>
#include <__memory/pointer_traits.h>
+#include <__utility/move.h>
#include <type_traits>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
@@ -20,77 +21,50 @@
_LIBCPP_BEGIN_NAMESPACE_STD
-// The job of __unwrap_iter is to lower contiguous iterators (such as
-// vector<T>::iterator) into pointers, to reduce the number of template
-// instantiations and to enable pointer-based optimizations e.g. in std::copy.
-// For iterators that are not contiguous, it must be a no-op.
+// TODO: Change the name of __unwrap_iter_impl to something more appropriate
+// The job of __unwrap_iter is to remove iterator wrappers (like reverse_iterator or __wrap_iter),
+// to reduce the number of template instantiations and to enable pointer-based optimizations e.g. in std::copy.
// In debug mode, we don't do this.
//
-// __unwrap_iter is non-constexpr for user-defined iterators whose
-// `to_address` and/or `operator->` is non-constexpr. This is okay; but we
-// try to avoid doing __unwrap_iter in constant-evaluated contexts anyway.
-//
// Some algorithms (e.g. std::copy, but not std::sort) need to convert an
-// "unwrapped" result back into a contiguous iterator. Since contiguous iterators
-// are random-access, we can do this portably using iterator arithmetic; this
-// is the job of __rewrap_iter.
+// "unwrapped" result back into the original iterator type. Doing that is the job of __rewrap_iter.
+// Default case - we can't unwrap anything
template <class _Iter, bool = __is_cpp17_contiguous_iterator<_Iter>::value>
struct __unwrap_iter_impl {
- static _LIBCPP_CONSTEXPR _Iter
- __apply(_Iter __i) _NOEXCEPT {
- return __i;
- }
+ static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR _Iter __rewrap(_Iter, _Iter __iter) { return __iter; }
+ static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR _Iter __unwrap(_Iter __i) _NOEXCEPT { return __i; }
};
#ifndef _LIBCPP_ENABLE_DEBUG_MODE
+// It's a contiguous iterator, so we can use a raw pointer instead
template <class _Iter>
struct __unwrap_iter_impl<_Iter, true> {
- static _LIBCPP_CONSTEXPR decltype(_VSTD::__to_address(declval<_Iter>()))
- __apply(_Iter __i) _NOEXCEPT {
- return _VSTD::__to_address(__i);
- }
-};
+ using _ToAddressT = decltype(std::__to_address(std::declval<_Iter>()));
-#endif // !_LIBCPP_ENABLE_DEBUG_MODE
-
-template<class _Iter, class _Impl = __unwrap_iter_impl<_Iter> >
-inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR
-decltype(_Impl::__apply(declval<_Iter>()))
-__unwrap_iter(_Iter __i) _NOEXCEPT
-{
- return _Impl::__apply(__i);
-}
-
-template <class _OrigIter, class _UnwrappedIter>
-struct __rewrap_iter_impl {
- static _LIBCPP_CONSTEXPR _OrigIter __apply(_OrigIter __first, _UnwrappedIter __result) {
- // Precondition: __result is reachable from __first
- // Precondition: _OrigIter is a contiguous iterator
- return __first + (__result - std::__unwrap_iter(__first));
+ static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR _Iter __rewrap(_Iter __orig_iter, _ToAddressT __unwrapped_iter) {
+ return __orig_iter + (__unwrapped_iter - std::__to_address(__orig_iter));
}
-};
-template <class _OrigIter>
-struct __rewrap_iter_impl<_OrigIter, _OrigIter> {
- static _LIBCPP_CONSTEXPR _OrigIter __apply(_OrigIter, _OrigIter __result) {
- return __result;
+ static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR _ToAddressT __unwrap(_Iter __i) _NOEXCEPT {
+ return std::__to_address(__i);
}
};
-template<class _OrigIter>
-_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR
-_OrigIter __rewrap_iter(_OrigIter, _OrigIter __result)
-{
- return __result;
+#endif // !_LIBCPP_ENABLE_DEBUG_MODE
+
+template<class _Iter,
+ class _Impl = __unwrap_iter_impl<_Iter>,
+ __enable_if_t<is_copy_constructible<_Iter>::value, int> = 0>
+inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX11
+decltype(_Impl::__unwrap(std::declval<_Iter>())) __unwrap_iter(_Iter __i) _NOEXCEPT {
+ return _Impl::__unwrap(__i);
}
-template<class _OrigIter, class _UnwrappedIter, class _Impl = __rewrap_iter_impl<_OrigIter, _UnwrappedIter> >
-_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR
-_OrigIter __rewrap_iter(_OrigIter __first, _UnwrappedIter __result)
-{
- return _Impl::__apply(__first, __result);
+template <class _OrigIter, class _Iter, class _Impl = __unwrap_iter_impl<_OrigIter> >
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR _OrigIter __rewrap_iter(_OrigIter __orig_iter, _Iter __iter) _NOEXCEPT {
+ return _Impl::__rewrap(std::move(__orig_iter), std::move(__iter));
}
_LIBCPP_END_NAMESPACE_STD
diff --git a/libcxx/include/__algorithm/upper_bound.h b/libcxx/include/__algorithm/upper_bound.h
index 3fc254873532..1045380bc84e 100644
--- a/libcxx/include/__algorithm/upper_bound.h
+++ b/libcxx/include/__algorithm/upper_bound.h
@@ -11,10 +11,15 @@
#include <__algorithm/comp.h>
#include <__algorithm/half_positive.h>
+#include <__algorithm/iterator_operations.h>
#include <__config>
+#include <__functional/identity.h>
+#include <__functional/invoke.h>
#include <__iterator/advance.h>
#include <__iterator/distance.h>
#include <__iterator/iterator_traits.h>
+#include <__type_traits/is_copy_constructible.h>
+#include <__utility/move.h>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
@@ -22,45 +27,40 @@
_LIBCPP_BEGIN_NAMESPACE_STD
-template <class _Compare, class _ForwardIterator, class _Tp>
-_LIBCPP_CONSTEXPR_AFTER_CXX17 _ForwardIterator
-__upper_bound(_ForwardIterator __first, _ForwardIterator __last, const _Tp& __value, _Compare __comp)
-{
- typedef typename iterator_traits<_ForwardIterator>::difference_type difference_type;
- difference_type __len = _VSTD::distance(__first, __last);
- while (__len != 0)
- {
- difference_type __l2 = _VSTD::__half_positive(__len);
- _ForwardIterator __m = __first;
- _VSTD::advance(__m, __l2);
- if (__comp(__value, *__m))
- __len = __l2;
- else
- {
- __first = ++__m;
- __len -= __l2 + 1;
- }
+template <class _AlgPolicy, class _Compare, class _Iter, class _Sent, class _Tp, class _Proj>
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17 _Iter
+__upper_bound(_Iter __first, _Sent __last, const _Tp& __value, _Compare&& __comp, _Proj&& __proj) {
+ auto __len = _IterOps<_AlgPolicy>::distance(__first, __last);
+ while (__len != 0) {
+ auto __half_len = std::__half_positive(__len);
+ auto __mid = _IterOps<_AlgPolicy>::next(__first, __half_len);
+ if (std::__invoke(__comp, __value, std::__invoke(__proj, *__mid)))
+ __len = __half_len;
+ else {
+ __first = ++__mid;
+ __len -= __half_len + 1;
}
- return __first;
+ }
+ return __first;
}
template <class _ForwardIterator, class _Tp, class _Compare>
-_LIBCPP_NODISCARD_EXT inline
-_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
-_ForwardIterator
-upper_bound(_ForwardIterator __first, _ForwardIterator __last, const _Tp& __value, _Compare __comp)
-{
- return _VSTD::__upper_bound<_Compare&>(__first, __last, __value, __comp);
+_LIBCPP_NODISCARD_EXT inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17 _ForwardIterator
+upper_bound(_ForwardIterator __first, _ForwardIterator __last, const _Tp& __value, _Compare __comp) {
+ static_assert(is_copy_constructible<_ForwardIterator>::value,
+ "Iterator has to be copy constructible");
+ return std::__upper_bound<_ClassicAlgPolicy>(
+ std::move(__first), std::move(__last), __value, std::move(__comp), std::__identity());
}
template <class _ForwardIterator, class _Tp>
-_LIBCPP_NODISCARD_EXT inline
-_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
-_ForwardIterator
-upper_bound(_ForwardIterator __first, _ForwardIterator __last, const _Tp& __value)
-{
- return _VSTD::upper_bound(__first, __last, __value,
- __less<_Tp, typename iterator_traits<_ForwardIterator>::value_type>());
+_LIBCPP_NODISCARD_EXT inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17 _ForwardIterator
+upper_bound(_ForwardIterator __first, _ForwardIterator __last, const _Tp& __value) {
+ return std::upper_bound(
+ std::move(__first),
+ std::move(__last),
+ __value,
+ __less<_Tp, typename iterator_traits<_ForwardIterator>::value_type>());
}
_LIBCPP_END_NAMESPACE_STD
diff --git a/libcxx/include/__config b/libcxx/include/__config
index 22c2ed7fd87b..8c2f7614af53 100644
--- a/libcxx/include/__config
+++ b/libcxx/include/__config
@@ -214,6 +214,12 @@
# error "libc++ only supports C++03 with Clang-based compilers. Please enable C++11"
# endif
+# ifdef _LIBCPP_COMPILER_MSVC
+# error If you successfully use libc++ with MSVC please tell the libc++ developers and consider upstreaming your \
+changes. We are not aware of anybody using this configuration and know that at least some code is currently broken. \
+If there are users of this configuration we are happy to provide support.
+# endif
+
// FIXME: ABI detection should be done via compiler builtin macros. This
// is just a placeholder until Clang implements such macros. For now assume
// that Windows compilers pretending to be MSVC++ target the Microsoft ABI,
@@ -237,6 +243,19 @@
# define _LIBCPP_ABI_VCRUNTIME
# endif
+# if __has_feature(experimental_library)
+# ifndef _LIBCPP_ENABLE_EXPERIMENTAL
+# define _LIBCPP_ENABLE_EXPERIMENTAL
+# endif
+# endif
+
+// Incomplete features get their own specific disabling flags. This makes it
+// easier to grep for target specific flags once the feature is complete.
+# if !defined(_LIBCPP_ENABLE_EXPERIMENTAL) && !defined(_LIBCPP_BUILDING_LIBRARY)
+# define _LIBCPP_HAS_NO_INCOMPLETE_FORMAT
+# define _LIBCPP_HAS_NO_INCOMPLETE_RANGES
+# endif
+
// Need to detect which libc we're using if we're on Linux.
# if defined(__linux__)
# include <features.h>
@@ -545,11 +564,15 @@ typedef __char32_t char32_t;
# define _LIBCPP_TYPE_VIS _LIBCPP_VISIBILITY("default")
# define _LIBCPP_TEMPLATE_DATA_VIS _LIBCPP_VISIBILITY("default")
# define _LIBCPP_EXPORTED_FROM_ABI _LIBCPP_VISIBILITY("default")
-# define _LIBCPP_OVERRIDABLE_FUNC_VIS _LIBCPP_VISIBILITY("default")
# define _LIBCPP_EXCEPTION_ABI _LIBCPP_VISIBILITY("default")
# define _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS _LIBCPP_VISIBILITY("default")
# define _LIBCPP_CLASS_TEMPLATE_INSTANTIATION_VIS
+// TODO: Make this a proper customization point or remove the option to override it.
+# ifndef _LIBCPP_OVERRIDABLE_FUNC_VIS
+# define _LIBCPP_OVERRIDABLE_FUNC_VIS _LIBCPP_VISIBILITY("default")
+# endif
+
# if !defined(_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS)
// The inline should be removed once PR32114 is resolved
# define _LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS inline _LIBCPP_HIDDEN
diff --git a/libcxx/include/__debug_utils/randomize_range.h b/libcxx/include/__debug_utils/randomize_range.h
index fd5b9e588493..9843709019d4 100644
--- a/libcxx/include/__debug_utils/randomize_range.h
+++ b/libcxx/include/__debug_utils/randomize_range.h
@@ -22,15 +22,16 @@
_LIBCPP_BEGIN_NAMESPACE_STD
-template <class _Iterator>
-_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX11 void __debug_randomize_range(_Iterator __first, _Iterator __last) {
+template <class _AlgPolicy, class _Iterator, class _Sentinel>
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX11
+void __debug_randomize_range(_Iterator __first, _Sentinel __last) {
#ifdef _LIBCPP_DEBUG_RANDOMIZE_UNSPECIFIED_STABILITY
# ifdef _LIBCPP_CXX03_LANG
# error Support for unspecified stability is only for C++11 and higher
# endif
if (!__libcpp_is_constant_evaluated())
- std::shuffle(__first, __last, __libcpp_debug_randomizer());
+ std::__shuffle<_AlgPolicy>(__first, __last, __libcpp_debug_randomizer());
#else
(void)__first;
(void)__last;
diff --git a/libcxx/include/__format/extended_grapheme_cluster_table.h b/libcxx/include/__format/extended_grapheme_cluster_table.h
new file mode 100644
index 000000000000..00cd0e91cd15
--- /dev/null
+++ b/libcxx/include/__format/extended_grapheme_cluster_table.h
@@ -0,0 +1,332 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// WARNING, this entire header is generated by
+// utiles/generate_extended_grapheme_cluster_table.py
+// DO NOT MODIFY!
+
+// UNICODE, INC. LICENSE AGREEMENT - DATA FILES AND SOFTWARE
+//
+// See Terms of Use <https://www.unicode.org/copyright.html>
+// for definitions of Unicode Inc.'s Data Files and Software.
+//
+// NOTICE TO USER: Carefully read the following legal agreement.
+// BY DOWNLOADING, INSTALLING, COPYING OR OTHERWISE USING UNICODE INC.'S
+// DATA FILES ("DATA FILES"), AND/OR SOFTWARE ("SOFTWARE"),
+// YOU UNEQUIVOCALLY ACCEPT, AND AGREE TO BE BOUND BY, ALL OF THE
+// TERMS AND CONDITIONS OF THIS AGREEMENT.
+// IF YOU DO NOT AGREE, DO NOT DOWNLOAD, INSTALL, COPY, DISTRIBUTE OR USE
+// THE DATA FILES OR SOFTWARE.
+//
+// COPYRIGHT AND PERMISSION NOTICE
+//
+// Copyright (c) 1991-2022 Unicode, Inc. All rights reserved.
+// Distributed under the Terms of Use in https://www.unicode.org/copyright.html.
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of the Unicode data files and any associated documentation
+// (the "Data Files") or Unicode software and any associated documentation
+// (the "Software") to deal in the Data Files or Software
+// without restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, and/or sell copies of
+// the Data Files or Software, and to permit persons to whom the Data Files
+// or Software are furnished to do so, provided that either
+// (a) this copyright and permission notice appear with all copies
+// of the Data Files or Software, or
+// (b) this copyright and permission notice appear in associated
+// Documentation.
+//
+// THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF
+// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT OF THIRD PARTY RIGHTS.
+// IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS
+// NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL
+// DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+// DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+// TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THE DATA FILES OR SOFTWARE.
+//
+// Except as contained in this notice, the name of a copyright holder
+// shall not be used in advertising or otherwise to promote the sale,
+// use or other dealings in these Data Files or Software without prior
+// written authorization of the copyright holder.
+
+#ifndef _LIBCPP___FORMAT_EXTENDED_GRAPHEME_CLUSTER_TABLE_H
+#define _LIBCPP___FORMAT_EXTENDED_GRAPHEME_CLUSTER_TABLE_H
+
+#include <__algorithm/upper_bound.h>
+#include <__config>
+#include <__iterator/access.h>
+#include <cstddef>
+#include <cstdint>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+# pragma GCC system_header
+#endif
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+#if _LIBCPP_STD_VER > 17
+
+namespace __extended_grapheme_custer_property_boundary {
+
+enum class __property : uint8_t {
+ // Values generated from the data files.
+ __CR,
+ __Control,
+ __Extend,
+ __Extended_Pictographic,
+ __L,
+ __LF,
+ __LV,
+ __LVT,
+ __Prepend,
+ __Regional_Indicator,
+ __SpacingMark,
+ __T,
+ __V,
+ __ZWJ,
+
+ // The properies below aren't stored in the "database".
+
+ // Text position properties.
+ __sot,
+ __eot,
+
+ // The code unit has none of above properties.
+ __none
+};
+
+/// The entries of the extended grapheme cluster bondary property table.
+///
+/// The data is generated from
+/// - https://www.unicode.org/Public/UCD/latest/ucd/auxiliary/GraphemeBreakProperty.txt
+/// - https://www.unicode.org/Public/UCD/latest/ucd/emoji/emoji-data.txt
+///
+/// The data has 3 values
+/// - bits [0, 3] The property. One of the values generated form the datafiles
+/// of \ref __property
+/// - bits [4, 10] The size of the range.
+/// - bits [11, 31] The lower bound code point of the range. The upper bound of
+/// the range is lower bound + size.
+///
+/// The 7 bits for the size allow a maximum range of 128 elements. Some ranges
+/// in the Unicode tables are larger. They are stored in multiple consecutive
+/// ranges in the data table. An alternative would be to store the sizes in a
+/// separate 16-bit value. The original MSVC STL code had such an approach, but
+/// this approach uses less space for the data and is about 4% faster in the
+/// following benchmark.
+/// libcxx/benchmarks/std_format_spec_string_unicode.bench.cpp
+inline constexpr uint32_t __entries[1480] = {
+ 0x00000091, 0x00005005, 0x00005811, 0x00006800, 0x00007111, 0x0003fa01, 0x00054803, 0x00056801, 0x00057003,
+ 0x001806f2, 0x00241862, 0x002c8ac2, 0x002df802, 0x002e0812, 0x002e2012, 0x002e3802, 0x00300058, 0x003080a2,
+ 0x0030e001, 0x00325942, 0x00338002, 0x0036b062, 0x0036e808, 0x0036f852, 0x00373812, 0x00375032, 0x00387808,
+ 0x00388802, 0x003981a2, 0x003d30a2, 0x003f5882, 0x003fe802, 0x0040b032, 0x0040d882, 0x00412822, 0x00414842,
+ 0x0042c822, 0x00448018, 0x0044c072, 0x00465172, 0x00471008, 0x004719f2, 0x0048180a, 0x0049d002, 0x0049d80a,
+ 0x0049e002, 0x0049f02a, 0x004a0872, 0x004a483a, 0x004a6802, 0x004a701a, 0x004a8862, 0x004b1012, 0x004c0802,
+ 0x004c101a, 0x004de002, 0x004df002, 0x004df81a, 0x004e0832, 0x004e381a, 0x004e581a, 0x004e6802, 0x004eb802,
+ 0x004f1012, 0x004ff002, 0x00500812, 0x0050180a, 0x0051e002, 0x0051f02a, 0x00520812, 0x00523812, 0x00525822,
+ 0x00528802, 0x00538012, 0x0053a802, 0x00540812, 0x0054180a, 0x0055e002, 0x0055f02a, 0x00560842, 0x00563812,
+ 0x0056480a, 0x0056581a, 0x00566802, 0x00571012, 0x0057d052, 0x00580802, 0x0058101a, 0x0059e002, 0x0059f012,
+ 0x005a000a, 0x005a0832, 0x005a381a, 0x005a581a, 0x005a6802, 0x005aa822, 0x005b1012, 0x005c1002, 0x005df002,
+ 0x005df80a, 0x005e0002, 0x005e081a, 0x005e302a, 0x005e502a, 0x005e6802, 0x005eb802, 0x00600002, 0x0060082a,
+ 0x00602002, 0x0061e002, 0x0061f022, 0x0062083a, 0x00623022, 0x00625032, 0x0062a812, 0x00631012, 0x00640802,
+ 0x0064101a, 0x0065e002, 0x0065f00a, 0x0065f802, 0x0066001a, 0x00661002, 0x0066181a, 0x00663002, 0x0066381a,
+ 0x0066501a, 0x00666012, 0x0066a812, 0x00671012, 0x00680012, 0x0068101a, 0x0069d812, 0x0069f002, 0x0069f81a,
+ 0x006a0832, 0x006a302a, 0x006a502a, 0x006a6802, 0x006a7008, 0x006ab802, 0x006b1012, 0x006c0802, 0x006c101a,
+ 0x006e5002, 0x006e7802, 0x006e801a, 0x006e9022, 0x006eb002, 0x006ec06a, 0x006ef802, 0x006f901a, 0x00718802,
+ 0x0071980a, 0x0071a062, 0x00723872, 0x00758802, 0x0075980a, 0x0075a082, 0x00764052, 0x0078c012, 0x0079a802,
+ 0x0079b802, 0x0079c802, 0x0079f01a, 0x007b88d2, 0x007bf80a, 0x007c0042, 0x007c3012, 0x007c68a2, 0x007cca32,
+ 0x007e3002, 0x00816832, 0x0081880a, 0x00819052, 0x0081c812, 0x0081d81a, 0x0081e812, 0x0082b01a, 0x0082c012,
+ 0x0082f022, 0x00838832, 0x00841002, 0x0084200a, 0x00842812, 0x00846802, 0x0084e802, 0x008805f4, 0x008b047c,
+ 0x008d457b, 0x009ae822, 0x00b89022, 0x00b8a80a, 0x00b99012, 0x00b9a00a, 0x00ba9012, 0x00bb9012, 0x00bda012,
+ 0x00bdb00a, 0x00bdb862, 0x00bdf07a, 0x00be3002, 0x00be381a, 0x00be48a2, 0x00bee802, 0x00c05822, 0x00c07001,
+ 0x00c07802, 0x00c42812, 0x00c54802, 0x00c90022, 0x00c9183a, 0x00c93812, 0x00c9482a, 0x00c9801a, 0x00c99002,
+ 0x00c9985a, 0x00c9c822, 0x00d0b812, 0x00d0c81a, 0x00d0d802, 0x00d2a80a, 0x00d2b002, 0x00d2b80a, 0x00d2c062,
+ 0x00d30002, 0x00d31002, 0x00d32872, 0x00d3685a, 0x00d39892, 0x00d3f802, 0x00d581e2, 0x00d80032, 0x00d8200a,
+ 0x00d9a062, 0x00d9d80a, 0x00d9e002, 0x00d9e84a, 0x00da1002, 0x00da181a, 0x00db5882, 0x00dc0012, 0x00dc100a,
+ 0x00dd080a, 0x00dd1032, 0x00dd301a, 0x00dd4012, 0x00dd500a, 0x00dd5822, 0x00df3002, 0x00df380a, 0x00df4012,
+ 0x00df502a, 0x00df6802, 0x00df700a, 0x00df7822, 0x00df901a, 0x00e1207a, 0x00e16072, 0x00e1a01a, 0x00e1b012,
+ 0x00e68022, 0x00e6a0c2, 0x00e7080a, 0x00e71062, 0x00e76802, 0x00e7a002, 0x00e7b80a, 0x00e7c012, 0x00ee03f2,
+ 0x01005801, 0x01006002, 0x0100680d, 0x01007011, 0x01014061, 0x0101e003, 0x01024803, 0x010300f1, 0x01068202,
+ 0x01091003, 0x0109c803, 0x010ca053, 0x010d4813, 0x0118d013, 0x01194003, 0x011c4003, 0x011e7803, 0x011f48a3,
+ 0x011fc023, 0x01261003, 0x012d5013, 0x012db003, 0x012e0003, 0x012fd833, 0x01300053, 0x013038b3, 0x0130a713,
+ 0x01348753, 0x013840a3, 0x0138a003, 0x0138b003, 0x0138e803, 0x01390803, 0x01394003, 0x01399813, 0x013a2003,
+ 0x013a3803, 0x013a6003, 0x013a7003, 0x013a9823, 0x013ab803, 0x013b1843, 0x013ca823, 0x013d0803, 0x013d8003,
+ 0x013df803, 0x0149a013, 0x01582823, 0x0158d813, 0x015a8003, 0x015aa803, 0x01677822, 0x016bf802, 0x016f01f2,
+ 0x01815052, 0x01818003, 0x0181e803, 0x0184c812, 0x0194b803, 0x0194c803, 0x05337832, 0x0533a092, 0x0534f012,
+ 0x05378012, 0x05401002, 0x05403002, 0x05405802, 0x0541181a, 0x05412812, 0x0541380a, 0x05416002, 0x0544001a,
+ 0x0545a0fa, 0x05462012, 0x05470112, 0x0547f802, 0x05493072, 0x054a38a2, 0x054a901a, 0x054b01c4, 0x054c0022,
+ 0x054c180a, 0x054d9802, 0x054da01a, 0x054db032, 0x054dd01a, 0x054de012, 0x054df02a, 0x054f2802, 0x05514852,
+ 0x0551781a, 0x05518812, 0x0551981a, 0x0551a812, 0x05521802, 0x05526002, 0x0552680a, 0x0553e002, 0x05558002,
+ 0x05559022, 0x0555b812, 0x0555f012, 0x05560802, 0x0557580a, 0x05576012, 0x0557701a, 0x0557a80a, 0x0557b002,
+ 0x055f181a, 0x055f2802, 0x055f301a, 0x055f4002, 0x055f481a, 0x055f600a, 0x055f6802, 0x05600006, 0x056009a7,
+ 0x0560e006, 0x0560e9a7, 0x0561c006, 0x0561c9a7, 0x0562a006, 0x0562a9a7, 0x05638006, 0x056389a7, 0x05646006,
+ 0x056469a7, 0x05654006, 0x056549a7, 0x05662006, 0x056629a7, 0x05670006, 0x056709a7, 0x0567e006, 0x0567e9a7,
+ 0x0568c006, 0x0568c9a7, 0x0569a006, 0x0569a9a7, 0x056a8006, 0x056a89a7, 0x056b6006, 0x056b69a7, 0x056c4006,
+ 0x056c49a7, 0x056d2006, 0x056d29a7, 0x056e0006, 0x056e09a7, 0x056ee006, 0x056ee9a7, 0x056fc006, 0x056fc9a7,
+ 0x0570a006, 0x0570a9a7, 0x05718006, 0x057189a7, 0x05726006, 0x057269a7, 0x05734006, 0x057349a7, 0x05742006,
+ 0x057429a7, 0x05750006, 0x057509a7, 0x0575e006, 0x0575e9a7, 0x0576c006, 0x0576c9a7, 0x0577a006, 0x0577a9a7,
+ 0x05788006, 0x057889a7, 0x05796006, 0x057969a7, 0x057a4006, 0x057a49a7, 0x057b2006, 0x057b29a7, 0x057c0006,
+ 0x057c09a7, 0x057ce006, 0x057ce9a7, 0x057dc006, 0x057dc9a7, 0x057ea006, 0x057ea9a7, 0x057f8006, 0x057f89a7,
+ 0x05806006, 0x058069a7, 0x05814006, 0x058149a7, 0x05822006, 0x058229a7, 0x05830006, 0x058309a7, 0x0583e006,
+ 0x0583e9a7, 0x0584c006, 0x0584c9a7, 0x0585a006, 0x0585a9a7, 0x05868006, 0x058689a7, 0x05876006, 0x058769a7,
+ 0x05884006, 0x058849a7, 0x05892006, 0x058929a7, 0x058a0006, 0x058a09a7, 0x058ae006, 0x058ae9a7, 0x058bc006,
+ 0x058bc9a7, 0x058ca006, 0x058ca9a7, 0x058d8006, 0x058d89a7, 0x058e6006, 0x058e69a7, 0x058f4006, 0x058f49a7,
+ 0x05902006, 0x059029a7, 0x05910006, 0x059109a7, 0x0591e006, 0x0591e9a7, 0x0592c006, 0x0592c9a7, 0x0593a006,
+ 0x0593a9a7, 0x05948006, 0x059489a7, 0x05956006, 0x059569a7, 0x05964006, 0x059649a7, 0x05972006, 0x059729a7,
+ 0x05980006, 0x059809a7, 0x0598e006, 0x0598e9a7, 0x0599c006, 0x0599c9a7, 0x059aa006, 0x059aa9a7, 0x059b8006,
+ 0x059b89a7, 0x059c6006, 0x059c69a7, 0x059d4006, 0x059d49a7, 0x059e2006, 0x059e29a7, 0x059f0006, 0x059f09a7,
+ 0x059fe006, 0x059fe9a7, 0x05a0c006, 0x05a0c9a7, 0x05a1a006, 0x05a1a9a7, 0x05a28006, 0x05a289a7, 0x05a36006,
+ 0x05a369a7, 0x05a44006, 0x05a449a7, 0x05a52006, 0x05a529a7, 0x05a60006, 0x05a609a7, 0x05a6e006, 0x05a6e9a7,
+ 0x05a7c006, 0x05a7c9a7, 0x05a8a006, 0x05a8a9a7, 0x05a98006, 0x05a989a7, 0x05aa6006, 0x05aa69a7, 0x05ab4006,
+ 0x05ab49a7, 0x05ac2006, 0x05ac29a7, 0x05ad0006, 0x05ad09a7, 0x05ade006, 0x05ade9a7, 0x05aec006, 0x05aec9a7,
+ 0x05afa006, 0x05afa9a7, 0x05b08006, 0x05b089a7, 0x05b16006, 0x05b169a7, 0x05b24006, 0x05b249a7, 0x05b32006,
+ 0x05b329a7, 0x05b40006, 0x05b409a7, 0x05b4e006, 0x05b4e9a7, 0x05b5c006, 0x05b5c9a7, 0x05b6a006, 0x05b6a9a7,
+ 0x05b78006, 0x05b789a7, 0x05b86006, 0x05b869a7, 0x05b94006, 0x05b949a7, 0x05ba2006, 0x05ba29a7, 0x05bb0006,
+ 0x05bb09a7, 0x05bbe006, 0x05bbe9a7, 0x05bcc006, 0x05bcc9a7, 0x05bda006, 0x05bda9a7, 0x05be8006, 0x05be89a7,
+ 0x05bf6006, 0x05bf69a7, 0x05c04006, 0x05c049a7, 0x05c12006, 0x05c129a7, 0x05c20006, 0x05c209a7, 0x05c2e006,
+ 0x05c2e9a7, 0x05c3c006, 0x05c3c9a7, 0x05c4a006, 0x05c4a9a7, 0x05c58006, 0x05c589a7, 0x05c66006, 0x05c669a7,
+ 0x05c74006, 0x05c749a7, 0x05c82006, 0x05c829a7, 0x05c90006, 0x05c909a7, 0x05c9e006, 0x05c9e9a7, 0x05cac006,
+ 0x05cac9a7, 0x05cba006, 0x05cba9a7, 0x05cc8006, 0x05cc89a7, 0x05cd6006, 0x05cd69a7, 0x05ce4006, 0x05ce49a7,
+ 0x05cf2006, 0x05cf29a7, 0x05d00006, 0x05d009a7, 0x05d0e006, 0x05d0e9a7, 0x05d1c006, 0x05d1c9a7, 0x05d2a006,
+ 0x05d2a9a7, 0x05d38006, 0x05d389a7, 0x05d46006, 0x05d469a7, 0x05d54006, 0x05d549a7, 0x05d62006, 0x05d629a7,
+ 0x05d70006, 0x05d709a7, 0x05d7e006, 0x05d7e9a7, 0x05d8c006, 0x05d8c9a7, 0x05d9a006, 0x05d9a9a7, 0x05da8006,
+ 0x05da89a7, 0x05db6006, 0x05db69a7, 0x05dc4006, 0x05dc49a7, 0x05dd2006, 0x05dd29a7, 0x05de0006, 0x05de09a7,
+ 0x05dee006, 0x05dee9a7, 0x05dfc006, 0x05dfc9a7, 0x05e0a006, 0x05e0a9a7, 0x05e18006, 0x05e189a7, 0x05e26006,
+ 0x05e269a7, 0x05e34006, 0x05e349a7, 0x05e42006, 0x05e429a7, 0x05e50006, 0x05e509a7, 0x05e5e006, 0x05e5e9a7,
+ 0x05e6c006, 0x05e6c9a7, 0x05e7a006, 0x05e7a9a7, 0x05e88006, 0x05e889a7, 0x05e96006, 0x05e969a7, 0x05ea4006,
+ 0x05ea49a7, 0x05eb2006, 0x05eb29a7, 0x05ec0006, 0x05ec09a7, 0x05ece006, 0x05ece9a7, 0x05edc006, 0x05edc9a7,
+ 0x05eea006, 0x05eea9a7, 0x05ef8006, 0x05ef89a7, 0x05f06006, 0x05f069a7, 0x05f14006, 0x05f149a7, 0x05f22006,
+ 0x05f229a7, 0x05f30006, 0x05f309a7, 0x05f3e006, 0x05f3e9a7, 0x05f4c006, 0x05f4c9a7, 0x05f5a006, 0x05f5a9a7,
+ 0x05f68006, 0x05f689a7, 0x05f76006, 0x05f769a7, 0x05f84006, 0x05f849a7, 0x05f92006, 0x05f929a7, 0x05fa0006,
+ 0x05fa09a7, 0x05fae006, 0x05fae9a7, 0x05fbc006, 0x05fbc9a7, 0x05fca006, 0x05fca9a7, 0x05fd8006, 0x05fd89a7,
+ 0x05fe6006, 0x05fe69a7, 0x05ff4006, 0x05ff49a7, 0x06002006, 0x060029a7, 0x06010006, 0x060109a7, 0x0601e006,
+ 0x0601e9a7, 0x0602c006, 0x0602c9a7, 0x0603a006, 0x0603a9a7, 0x06048006, 0x060489a7, 0x06056006, 0x060569a7,
+ 0x06064006, 0x060649a7, 0x06072006, 0x060729a7, 0x06080006, 0x060809a7, 0x0608e006, 0x0608e9a7, 0x0609c006,
+ 0x0609c9a7, 0x060aa006, 0x060aa9a7, 0x060b8006, 0x060b89a7, 0x060c6006, 0x060c69a7, 0x060d4006, 0x060d49a7,
+ 0x060e2006, 0x060e29a7, 0x060f0006, 0x060f09a7, 0x060fe006, 0x060fe9a7, 0x0610c006, 0x0610c9a7, 0x0611a006,
+ 0x0611a9a7, 0x06128006, 0x061289a7, 0x06136006, 0x061369a7, 0x06144006, 0x061449a7, 0x06152006, 0x061529a7,
+ 0x06160006, 0x061609a7, 0x0616e006, 0x0616e9a7, 0x0617c006, 0x0617c9a7, 0x0618a006, 0x0618a9a7, 0x06198006,
+ 0x061989a7, 0x061a6006, 0x061a69a7, 0x061b4006, 0x061b49a7, 0x061c2006, 0x061c29a7, 0x061d0006, 0x061d09a7,
+ 0x061de006, 0x061de9a7, 0x061ec006, 0x061ec9a7, 0x061fa006, 0x061fa9a7, 0x06208006, 0x062089a7, 0x06216006,
+ 0x062169a7, 0x06224006, 0x062249a7, 0x06232006, 0x062329a7, 0x06240006, 0x062409a7, 0x0624e006, 0x0624e9a7,
+ 0x0625c006, 0x0625c9a7, 0x0626a006, 0x0626a9a7, 0x06278006, 0x062789a7, 0x06286006, 0x062869a7, 0x06294006,
+ 0x062949a7, 0x062a2006, 0x062a29a7, 0x062b0006, 0x062b09a7, 0x062be006, 0x062be9a7, 0x062cc006, 0x062cc9a7,
+ 0x062da006, 0x062da9a7, 0x062e8006, 0x062e89a7, 0x062f6006, 0x062f69a7, 0x06304006, 0x063049a7, 0x06312006,
+ 0x063129a7, 0x06320006, 0x063209a7, 0x0632e006, 0x0632e9a7, 0x0633c006, 0x0633c9a7, 0x0634a006, 0x0634a9a7,
+ 0x06358006, 0x063589a7, 0x06366006, 0x063669a7, 0x06374006, 0x063749a7, 0x06382006, 0x063829a7, 0x06390006,
+ 0x063909a7, 0x0639e006, 0x0639e9a7, 0x063ac006, 0x063ac9a7, 0x063ba006, 0x063ba9a7, 0x063c8006, 0x063c89a7,
+ 0x063d6006, 0x063d69a7, 0x063e4006, 0x063e49a7, 0x063f2006, 0x063f29a7, 0x06400006, 0x064009a7, 0x0640e006,
+ 0x0640e9a7, 0x0641c006, 0x0641c9a7, 0x0642a006, 0x0642a9a7, 0x06438006, 0x064389a7, 0x06446006, 0x064469a7,
+ 0x06454006, 0x064549a7, 0x06462006, 0x064629a7, 0x06470006, 0x064709a7, 0x0647e006, 0x0647e9a7, 0x0648c006,
+ 0x0648c9a7, 0x0649a006, 0x0649a9a7, 0x064a8006, 0x064a89a7, 0x064b6006, 0x064b69a7, 0x064c4006, 0x064c49a7,
+ 0x064d2006, 0x064d29a7, 0x064e0006, 0x064e09a7, 0x064ee006, 0x064ee9a7, 0x064fc006, 0x064fc9a7, 0x0650a006,
+ 0x0650a9a7, 0x06518006, 0x065189a7, 0x06526006, 0x065269a7, 0x06534006, 0x065349a7, 0x06542006, 0x065429a7,
+ 0x06550006, 0x065509a7, 0x0655e006, 0x0655e9a7, 0x0656c006, 0x0656c9a7, 0x0657a006, 0x0657a9a7, 0x06588006,
+ 0x065889a7, 0x06596006, 0x065969a7, 0x065a4006, 0x065a49a7, 0x065b2006, 0x065b29a7, 0x065c0006, 0x065c09a7,
+ 0x065ce006, 0x065ce9a7, 0x065dc006, 0x065dc9a7, 0x065ea006, 0x065ea9a7, 0x065f8006, 0x065f89a7, 0x06606006,
+ 0x066069a7, 0x06614006, 0x066149a7, 0x06622006, 0x066229a7, 0x06630006, 0x066309a7, 0x0663e006, 0x0663e9a7,
+ 0x0664c006, 0x0664c9a7, 0x0665a006, 0x0665a9a7, 0x06668006, 0x066689a7, 0x06676006, 0x066769a7, 0x06684006,
+ 0x066849a7, 0x06692006, 0x066929a7, 0x066a0006, 0x066a09a7, 0x066ae006, 0x066ae9a7, 0x066bc006, 0x066bc9a7,
+ 0x066ca006, 0x066ca9a7, 0x066d8006, 0x066d89a7, 0x066e6006, 0x066e69a7, 0x066f4006, 0x066f49a7, 0x06702006,
+ 0x067029a7, 0x06710006, 0x067109a7, 0x0671e006, 0x0671e9a7, 0x0672c006, 0x0672c9a7, 0x0673a006, 0x0673a9a7,
+ 0x06748006, 0x067489a7, 0x06756006, 0x067569a7, 0x06764006, 0x067649a7, 0x06772006, 0x067729a7, 0x06780006,
+ 0x067809a7, 0x0678e006, 0x0678e9a7, 0x0679c006, 0x0679c9a7, 0x067aa006, 0x067aa9a7, 0x067b8006, 0x067b89a7,
+ 0x067c6006, 0x067c69a7, 0x067d4006, 0x067d49a7, 0x067e2006, 0x067e29a7, 0x067f0006, 0x067f09a7, 0x067fe006,
+ 0x067fe9a7, 0x0680c006, 0x0680c9a7, 0x0681a006, 0x0681a9a7, 0x06828006, 0x068289a7, 0x06836006, 0x068369a7,
+ 0x06844006, 0x068449a7, 0x06852006, 0x068529a7, 0x06860006, 0x068609a7, 0x0686e006, 0x0686e9a7, 0x0687c006,
+ 0x0687c9a7, 0x0688a006, 0x0688a9a7, 0x06898006, 0x068989a7, 0x068a6006, 0x068a69a7, 0x068b4006, 0x068b49a7,
+ 0x068c2006, 0x068c29a7, 0x068d0006, 0x068d09a7, 0x068de006, 0x068de9a7, 0x068ec006, 0x068ec9a7, 0x068fa006,
+ 0x068fa9a7, 0x06908006, 0x069089a7, 0x06916006, 0x069169a7, 0x06924006, 0x069249a7, 0x06932006, 0x069329a7,
+ 0x06940006, 0x069409a7, 0x0694e006, 0x0694e9a7, 0x0695c006, 0x0695c9a7, 0x0696a006, 0x0696a9a7, 0x06978006,
+ 0x069789a7, 0x06986006, 0x069869a7, 0x06994006, 0x069949a7, 0x069a2006, 0x069a29a7, 0x069b0006, 0x069b09a7,
+ 0x069be006, 0x069be9a7, 0x069cc006, 0x069cc9a7, 0x069da006, 0x069da9a7, 0x069e8006, 0x069e89a7, 0x069f6006,
+ 0x069f69a7, 0x06a04006, 0x06a049a7, 0x06a12006, 0x06a129a7, 0x06a20006, 0x06a209a7, 0x06a2e006, 0x06a2e9a7,
+ 0x06a3c006, 0x06a3c9a7, 0x06a4a006, 0x06a4a9a7, 0x06a58006, 0x06a589a7, 0x06a66006, 0x06a669a7, 0x06a74006,
+ 0x06a749a7, 0x06a82006, 0x06a829a7, 0x06a90006, 0x06a909a7, 0x06a9e006, 0x06a9e9a7, 0x06aac006, 0x06aac9a7,
+ 0x06aba006, 0x06aba9a7, 0x06ac8006, 0x06ac89a7, 0x06ad6006, 0x06ad69a7, 0x06ae4006, 0x06ae49a7, 0x06af2006,
+ 0x06af29a7, 0x06b00006, 0x06b009a7, 0x06b0e006, 0x06b0e9a7, 0x06b1c006, 0x06b1c9a7, 0x06b2a006, 0x06b2a9a7,
+ 0x06b38006, 0x06b389a7, 0x06b46006, 0x06b469a7, 0x06b54006, 0x06b549a7, 0x06b62006, 0x06b629a7, 0x06b70006,
+ 0x06b709a7, 0x06b7e006, 0x06b7e9a7, 0x06b8c006, 0x06b8c9a7, 0x06b9a006, 0x06b9a9a7, 0x06ba8006, 0x06ba89a7,
+ 0x06bb6006, 0x06bb69a7, 0x06bc4006, 0x06bc49a7, 0x06bd816c, 0x06be5b0b, 0x07d8f002, 0x07f000f2, 0x07f100f2,
+ 0x07f7f801, 0x07fcf012, 0x07ff80b1, 0x080fe802, 0x08170002, 0x081bb042, 0x08500822, 0x08502812, 0x08506032,
+ 0x0851c022, 0x0851f802, 0x08572812, 0x08692032, 0x08755812, 0x087a30a2, 0x087c1032, 0x0880000a, 0x08800802,
+ 0x0880100a, 0x0881c0e2, 0x08838002, 0x08839812, 0x0883f822, 0x0884100a, 0x0885802a, 0x08859832, 0x0885b81a,
+ 0x0885c812, 0x0885e808, 0x08861002, 0x08866808, 0x08880022, 0x08893842, 0x0889600a, 0x08896872, 0x088a281a,
+ 0x088b9802, 0x088c0012, 0x088c100a, 0x088d982a, 0x088db082, 0x088df81a, 0x088e1018, 0x088e4832, 0x088e700a,
+ 0x088e7802, 0x0891602a, 0x08917822, 0x0891901a, 0x0891a002, 0x0891a80a, 0x0891b012, 0x0891f002, 0x0896f802,
+ 0x0897002a, 0x08971872, 0x08980012, 0x0898101a, 0x0899d812, 0x0899f002, 0x0899f80a, 0x089a0002, 0x089a083a,
+ 0x089a381a, 0x089a582a, 0x089ab802, 0x089b101a, 0x089b3062, 0x089b8042, 0x08a1a82a, 0x08a1c072, 0x08a2001a,
+ 0x08a21022, 0x08a2280a, 0x08a23002, 0x08a2f002, 0x08a58002, 0x08a5881a, 0x08a59852, 0x08a5c80a, 0x08a5d002,
+ 0x08a5d81a, 0x08a5e802, 0x08a5f00a, 0x08a5f812, 0x08a6080a, 0x08a61012, 0x08ad7802, 0x08ad801a, 0x08ad9032,
+ 0x08adc03a, 0x08ade012, 0x08adf00a, 0x08adf812, 0x08aee012, 0x08b1802a, 0x08b19872, 0x08b1d81a, 0x08b1e802,
+ 0x08b1f00a, 0x08b1f812, 0x08b55802, 0x08b5600a, 0x08b56802, 0x08b5701a, 0x08b58052, 0x08b5b00a, 0x08b5b802,
+ 0x08b8e822, 0x08b91032, 0x08b9300a, 0x08b93842, 0x08c1602a, 0x08c17882, 0x08c1c00a, 0x08c1c812, 0x08c98002,
+ 0x08c9884a, 0x08c9b81a, 0x08c9d812, 0x08c9e80a, 0x08c9f002, 0x08c9f808, 0x08ca000a, 0x08ca0808, 0x08ca100a,
+ 0x08ca1802, 0x08ce882a, 0x08cea032, 0x08ced012, 0x08cee03a, 0x08cf0002, 0x08cf200a, 0x08d00892, 0x08d19852,
+ 0x08d1c80a, 0x08d1d008, 0x08d1d832, 0x08d23802, 0x08d28852, 0x08d2b81a, 0x08d2c822, 0x08d42058, 0x08d450c2,
+ 0x08d4b80a, 0x08d4c012, 0x08e1780a, 0x08e18062, 0x08e1c052, 0x08e1f00a, 0x08e1f802, 0x08e49152, 0x08e5480a,
+ 0x08e55062, 0x08e5880a, 0x08e59012, 0x08e5a00a, 0x08e5a812, 0x08e98852, 0x08e9d002, 0x08e9e012, 0x08e9f862,
+ 0x08ea3008, 0x08ea3802, 0x08ec504a, 0x08ec8012, 0x08ec981a, 0x08eca802, 0x08ecb00a, 0x08ecb802, 0x08f79812,
+ 0x08f7a81a, 0x09a18081, 0x0b578042, 0x0b598062, 0x0b7a7802, 0x0b7a8b6a, 0x0b7c7832, 0x0b7f2002, 0x0b7f801a,
+ 0x0de4e812, 0x0de50031, 0x0e7802d2, 0x0e798162, 0x0e8b2802, 0x0e8b300a, 0x0e8b3822, 0x0e8b680a, 0x0e8b7042,
+ 0x0e8b9871, 0x0e8bd872, 0x0e8c2862, 0x0e8d5032, 0x0e921022, 0x0ed00362, 0x0ed1db12, 0x0ed3a802, 0x0ed42002,
+ 0x0ed4d842, 0x0ed508e2, 0x0f000062, 0x0f004102, 0x0f00d862, 0x0f011812, 0x0f013042, 0x0f098062, 0x0f157002,
+ 0x0f176032, 0x0f468062, 0x0f4a2062, 0x0f8007f3, 0x0f8407f3, 0x0f886823, 0x0f897803, 0x0f8b6053, 0x0f8bf013,
+ 0x0f8c7003, 0x0f8c8893, 0x0f8d6b83, 0x0f8f3199, 0x0f9008e3, 0x0f90d003, 0x0f917803, 0x0f919083, 0x0f91e033,
+ 0x0f924ff3, 0x0f964ff3, 0x0f9a4ff3, 0x0f9e4b13, 0x0f9fd842, 0x0fa007f3, 0x0fa407f3, 0x0fa803d3, 0x0faa37f3,
+ 0x0fae37f3, 0x0fb23093, 0x0fb407f3, 0x0fbba0b3, 0x0fbeaaa3, 0x0fc06033, 0x0fc24073, 0x0fc2d053, 0x0fc44073,
+ 0x0fc57513, 0x0fc862e3, 0x0fc9e093, 0x0fca3ff3, 0x0fce3ff3, 0x0fd23ff3, 0x0fd63b83, 0x0fe007f3, 0x0fe407f3,
+ 0x0fe807f3, 0x0fec07f3, 0x0ff007f3, 0x0ff407f3, 0x0ff807f3, 0x0ffc07d3, 0x700001f1, 0x700105f2, 0x700407f1,
+ 0x700807f2, 0x700c06f2, 0x700f87f1, 0x701387f1, 0x701787f1, 0x701b87f1, 0x701f87f1, 0x702387f1, 0x702787f1,
+ 0x702b87f1, 0x702f87f1, 0x703387f1, 0x703787f1, 0x703b87f1, 0x703f87f1, 0x704387f1, 0x704787f1, 0x704b87f1,
+ 0x704f87f1, 0x705387f1, 0x705787f1, 0x705b87f1, 0x705f87f1, 0x706387f1, 0x706787f1, 0x706b87f1, 0x706f87f1,
+ 0x707387f1, 0x707787f1, 0x707b87f1, 0x707f80f1};
+
+/// Returns the extended grapheme cluster bondary property of a code point.
+[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr __property __get_property(const char32_t __code_point) noexcept {
+ // TODO FMT use std::ranges::upper_bound.
+
+ // The algorithm searches for the upper bound of the range and, when found,
+ // steps back one entry. This algorithm is used since the code point can be
+ // anywhere in the range. After a lower bound is found the next step is to
+ // compare whether the code unit is indeed in the range.
+ //
+ // Since the entry contains a code unit, size, and property the code point
+ // being sought needs to be adjusted. Just shifting the code point to the
+ // proper position doesn't work; suppose an entry has property 0, size 1,
+ // and lower bound 3. This results in the entry 0x1810.
+ // When searching for code point 3 it will search for 0x1800, find 0x1810
+ // and moves to the previous entry. Thus the lower bound value will never
+ // be found.
+ // The simple solution is to set the bits belonging to the property and
+ // size. Then the upper bound for code point 3 will return the entry after
+ // 0x1810. After moving to the previous entry the algorithm arrives at the
+ // correct entry.
+ ptrdiff_t __i = std::upper_bound(__entries, std::end(__entries), (__code_point << 11) | 0x7ffu) - __entries;
+ if (__i == 0)
+ return __property::__none;
+
+ --__i;
+ uint32_t __upper_bound = (__entries[__i] >> 11) + ((__entries[__i] >> 4) & 0x7f);
+ if (__code_point <= __upper_bound)
+ return static_cast<__property>(__entries[__i] & 0xf);
+
+ return __property::__none;
+}
+
+} // namespace __extended_grapheme_custer_property_boundary
+
+#endif //_LIBCPP_STD_VER > 17
+
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP___FORMAT_EXTENDED_GRAPHEME_CLUSTER_TABLE_H
diff --git a/libcxx/include/__format/formatter_integral.h b/libcxx/include/__format/formatter_integral.h
index d6fa5ec18eb8..b9ed5fe80f7f 100644
--- a/libcxx/include/__format/formatter_integral.h
+++ b/libcxx/include/__format/formatter_integral.h
@@ -343,7 +343,7 @@ __format_bool(bool __value, auto& __ctx, __format_spec::__parsed_specifications<
if (__specs.__std_.__locale_specific_form_) {
const auto& __np = use_facet<numpunct<_CharT>>(__ctx.locale());
basic_string<_CharT> __str = __value ? __np.truename() : __np.falsename();
- return __formatter::__write_unicode_no_precision(basic_string_view<_CharT>{__str}, __ctx.out(), __specs);
+ return __formatter::__write_string_no_precision(basic_string_view<_CharT>{__str}, __ctx.out(), __specs);
}
# endif
basic_string_view<_CharT> __str =
diff --git a/libcxx/include/__format/formatter_output.h b/libcxx/include/__format/formatter_output.h
index c59cbbeeb5dd..e09534c41dff 100644
--- a/libcxx/include/__format/formatter_output.h
+++ b/libcxx/include/__format/formatter_output.h
@@ -17,6 +17,7 @@
#include <__config>
#include <__format/formatter.h>
#include <__format/parser_std_format_spec.h>
+#include <__format/unicode.h>
#include <__utility/move.h>
#include <__utility/unreachable.h>
#include <cstddef>
@@ -59,8 +60,8 @@ struct _LIBCPP_TYPE_VIS __padding_size_result {
_LIBCPP_HIDE_FROM_ABI constexpr __padding_size_result
__padding_size(size_t __size, size_t __width, __format_spec::__alignment __align) {
_LIBCPP_ASSERT(__width > __size, "don't call this function when no padding is required");
- _LIBCPP_ASSERT(__align != __format_spec::__alignment::__zero_padding,
- "the caller should have handled the zero-padding");
+ _LIBCPP_ASSERT(
+ __align != __format_spec::__alignment::__zero_padding, "the caller should have handled the zero-padding");
size_t __fill = __width - __size;
switch (__align) {
@@ -75,7 +76,7 @@ __padding_size(size_t __size, size_t __width, __format_spec::__alignment __align
// __before = floor(__fill, 2);
// __after = ceil(__fill, 2);
size_t __before = __fill / 2;
- size_t __after = __fill - __before;
+ size_t __after = __fill - __before;
return {__before, __after};
}
case __format_spec::__alignment::__default:
@@ -173,10 +174,12 @@ _LIBCPP_HIDE_FROM_ABI _OutIt __write_using_decimal_separators(_OutIt __out_it, c
/// conversion, which means the [\a __first, \a __last) always contains elements
/// of the type \c char.
template <class _CharT, class _ParserCharT>
-_LIBCPP_HIDE_FROM_ABI auto __write(const _CharT* __first, const _CharT* __last,
- output_iterator<const _CharT&> auto __out_it,
- __format_spec::__parsed_specifications<_ParserCharT> __specs, ptrdiff_t __size)
- -> decltype(__out_it) {
+_LIBCPP_HIDE_FROM_ABI auto __write(
+ const _CharT* __first,
+ const _CharT* __last,
+ output_iterator<const _CharT&> auto __out_it,
+ __format_spec::__parsed_specifications<_ParserCharT> __specs,
+ ptrdiff_t __size) -> decltype(__out_it) {
_LIBCPP_ASSERT(__first <= __last, "Not a valid range");
if (__size >= __specs.__width_)
@@ -189,6 +192,7 @@ _LIBCPP_HIDE_FROM_ABI auto __write(const _CharT* __first, const _CharT* __last,
}
/// \overload
+///
/// Calls the function above where \a __size = \a __last - \a __first.
template <class _CharT, class _ParserCharT>
_LIBCPP_HIDE_FROM_ABI auto __write(const _CharT* __first, const _CharT* __last,
@@ -243,77 +247,56 @@ _LIBCPP_HIDE_FROM_ABI auto __write_using_trailing_zeros(
return _VSTD::fill_n(_VSTD::move(__out_it), __padding.__after_, __specs.__fill_);
}
-# ifndef _LIBCPP_HAS_NO_UNICODE
+/// Writes a string using format's width estimation algorithm.
+///
+/// \pre !__specs.__has_precision()
+///
+/// \note When \c _LIBCPP_HAS_NO_UNICODE is defined the function assumes the
+/// input is ASCII.
template <class _CharT>
-_LIBCPP_HIDE_FROM_ABI auto __write_unicode_no_precision(basic_string_view<_CharT> __str,
- output_iterator<const _CharT&> auto __out_it,
- __format_spec::__parsed_specifications<_CharT> __specs)
- -> decltype(__out_it) {
+_LIBCPP_HIDE_FROM_ABI auto __write_string_no_precision(
+ basic_string_view<_CharT> __str,
+ output_iterator<const _CharT&> auto __out_it,
+ __format_spec::__parsed_specifications<_CharT> __specs) -> decltype(__out_it) {
+ _LIBCPP_ASSERT(!__specs.__has_precision(), "use __write_string");
- _LIBCPP_ASSERT(!__specs.__has_precision(), "use __write_unicode");
// No padding -> copy the string
if (!__specs.__has_width())
return _VSTD::copy(__str.begin(), __str.end(), _VSTD::move(__out_it));
- // Non Unicode part larger than width -> copy the string
- auto __last = __format_spec::__detail::__estimate_column_width_fast(__str.begin(), __str.end());
- ptrdiff_t __size = __last - __str.begin();
- if (__size >= __specs.__width_)
- return _VSTD::copy(__str.begin(), __str.end(), _VSTD::move(__out_it));
-
- // Is there a non Unicode part?
- if (__last != __str.end()) {
- // Non Unicode and Unicode part larger than width -> copy the string
- __format_spec::__detail::__column_width_result __column_width =
- __format_spec::__detail::__estimate_column_width(__last, __str.end(), __specs.__width_);
- __size += __column_width.__width; // Note this new size is used when __size < __specs.__width_
- if (__size >= __specs.__width_)
- return _VSTD::copy(__str.begin(), __str.end(), _VSTD::move(__out_it));
- }
+ // Note when the estimated width is larger than size there's no padding. So
+ // there's no reason to get the real size when the estimate is larger than or
+ // equal to the minimum field width.
+ size_t __size =
+ __format_spec::__estimate_column_width(__str, __specs.__width_, __format_spec::__column_width_rounding::__up)
+ .__width_;
return __formatter::__write(__str.begin(), __str.end(), _VSTD::move(__out_it), __specs, __size);
}
-# endif
template <class _CharT>
-_LIBCPP_HIDE_FROM_ABI auto __write_unicode(basic_string_view<_CharT> __str,
- output_iterator<const _CharT&> auto __out_it,
- __format_spec::__parsed_specifications<_CharT> __specs)
- -> decltype(__out_it) {
-# ifndef _LIBCPP_HAS_NO_UNICODE
- if (!__specs.__has_precision())
- return __formatter::__write_unicode_no_precision(__str, _VSTD::move(__out_it), __specs);
-
- // Non unicode part larger than precision -> truncate the output and use the normal write operation.
- auto __last = __format_spec::__detail::__estimate_column_width_fast(__str.begin(), __str.end());
- ptrdiff_t __size = __last - __str.begin();
- if (__size >= __specs.__precision_)
- return __formatter::__write(__str.begin(), __str.begin() + __specs.__precision_, _VSTD::move(__out_it), __specs,
- __specs.__precision_);
-
- // No non Unicode part, implies __size < __specs.__precision_ -> use normal write operation
- if (__last == __str.end())
- return __formatter::__write(__str.begin(), __str.end(), _VSTD::move(__out_it), __specs, __str.size());
-
- __format_spec::__detail::__column_width_result __column_width =
- __format_spec::__detail::__estimate_column_width(__last, __str.end(), __specs.__precision_ - __size);
- __size += __column_width.__width;
- // Truncate the output
- if (__column_width.__ptr != __str.end())
- __str.remove_suffix(__str.end() - __column_width.__ptr);
+_LIBCPP_HIDE_FROM_ABI int __truncate(basic_string_view<_CharT>& __str, int __precision) {
+ __format_spec::__column_width_result<_CharT> __result =
+ __format_spec::__estimate_column_width(__str, __precision, __format_spec::__column_width_rounding::__down);
+ __str = basic_string_view<_CharT>{__str.begin(), __result.__last_};
+ return __result.__width_;
+}
- return __formatter::__write(__str.begin(), __str.end(), _VSTD::move(__out_it), __specs, __size);
+/// Writes a string using format's width estimation algorithm.
+///
+/// \note When \c _LIBCPP_HAS_NO_UNICODE is defined the function assumes the
+/// input is ASCII.
+template <class _CharT>
+_LIBCPP_HIDE_FROM_ABI auto __write_string(
+ basic_string_view<_CharT> __str,
+ output_iterator<const _CharT&> auto __out_it,
+ __format_spec::__parsed_specifications<_CharT> __specs) -> decltype(__out_it) {
+ if (!__specs.__has_precision())
+ return __formatter::__write_string_no_precision(__str, _VSTD::move(__out_it), __specs);
-# else
- if (__specs.__has_precision()) {
- ptrdiff_t __size = __str.size();
- if (__size > __specs.__precision_)
- return __formatter::__write(__str.begin(), __str.begin() + __specs.__precision_, _VSTD::move(__out_it), __specs,
- __specs.__precision_);
- }
- return __formatter::__write(__str.begin(), __str.end(), _VSTD::move(__out_it), __specs, __str.size());
+ int __size = __formatter::__truncate(__str, __specs.__precision_);
-# endif
+ return __write(__str.begin(), __str.end(), _VSTD::move(__out_it), __specs, __size);
}
} // namespace __formatter
diff --git a/libcxx/include/__format/formatter_string.h b/libcxx/include/__format/formatter_string.h
index 139c05e58c28..71bda4fcded1 100644
--- a/libcxx/include/__format/formatter_string.h
+++ b/libcxx/include/__format/formatter_string.h
@@ -40,7 +40,7 @@ public:
}
_LIBCPP_HIDE_FROM_ABI auto format(basic_string_view<_CharT> __str, auto& __ctx) const -> decltype(__ctx.out()) {
- return __formatter::__write_unicode(__str, __ctx.out(), __parser_.__get_parsed_std_specifications(__ctx));
+ return __formatter::__write_string(__str, __ctx.out(), __parser_.__get_parsed_std_specifications(__ctx));
}
__format_spec::__parser<_CharT> __parser_;
@@ -69,7 +69,7 @@ struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT formatter<const _CharT*,
// TODO FMT Implement these improvements.
__format_spec::__parsed_specifications<_CharT> __specs = _Base::__parser_.__get_parsed_std_specifications(__ctx);
if (__specs.__has_width() || __specs.__has_precision())
- return __formatter::__write_unicode(basic_string_view<_CharT>{__str}, __ctx.out(), __specs);
+ return __formatter::__write_string(basic_string_view<_CharT>{__str}, __ctx.out(), __specs);
// No formatting required, copy the string to the output.
auto __out_it = __ctx.out();
diff --git a/libcxx/include/__format/parser_std_format_spec.h b/libcxx/include/__format/parser_std_format_spec.h
index 034fc55a44dc..1425a953ebaa 100644
--- a/libcxx/include/__format/parser_std_format_spec.h
+++ b/libcxx/include/__format/parser_std_format_spec.h
@@ -25,10 +25,12 @@
#include <__format/format_error.h>
#include <__format/format_parse_context.h>
#include <__format/format_string.h>
+#include <__format/unicode.h>
#include <__variant/monostate.h>
#include <bit>
#include <concepts>
#include <cstdint>
+#include <string_view>
#include <type_traits>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
@@ -91,462 +93,6 @@ __substitute_arg_id(basic_format_arg<_Context> __format_arg) {
__format_arg);
}
-/** Helper struct returned from @ref __get_string_alignment. */
-template <class _CharT>
-struct _LIBCPP_TEMPLATE_VIS __string_alignment {
- /** Points beyond the last character to write to the output. */
- const _CharT* __last;
- /**
- * The estimated number of columns in the output or 0.
- *
- * Only when the output needs to be aligned it's required to know the exact
- * number of columns in the output. So if the formatted output has only a
- * minimum width the exact size isn't important. It's only important to know
- * the minimum has been reached. The minimum width is the width specified in
- * the format-spec.
- *
- * For example in this code @code std::format("{:10}", MyString); @endcode
- * the width estimation can stop once the algorithm has determined the output
- * width is 10 columns.
- *
- * So if:
- * * @ref __align == @c true the @ref __size is the estimated number of
- * columns required.
- * * @ref __align == @c false the @ref __size is the estimated number of
- * columns required or 0 when the estimation algorithm stopped prematurely.
- */
- ptrdiff_t __size;
- /**
- * Does the output need to be aligned.
- *
- * When alignment is needed the output algorithm needs to add the proper
- * padding. Else the output algorithm just needs to copy the input up to
- * @ref __last.
- */
- bool __align;
-};
-
-#ifndef _LIBCPP_HAS_NO_UNICODE
-namespace __detail {
-
-/**
- * Unicode column width estimates.
- *
- * Unicode can be stored in several formats: UTF-8, UTF-16, and UTF-32.
- * Depending on format the relation between the number of code units stored and
- * the number of output columns differs. The first relation is the number of
- * code units forming a code point. (The text assumes the code units are
- * unsigned.)
- * - UTF-8 The number of code units is between one and four. The first 127
- * Unicode code points match the ASCII character set. When the highest bit is
- * set it means the code point has more than one code unit.
- * - UTF-16: The number of code units is between 1 and 2. When the first
- * code unit is in the range [0xd800,0xdfff) it means the code point uses two
- * code units.
- * - UTF-32: The number of code units is always one.
- *
- * The code point to the number of columns isn't well defined. The code uses the
- * estimations defined in [format.string.std]/11. This list might change in the
- * future.
- *
- * The algorithm of @ref __get_string_alignment uses two different scanners:
- * - The simple scanner @ref __estimate_column_width_fast. This scanner assumes
- * 1 code unit is 1 column. This scanner stops when it can't be sure the
- * assumption is valid:
- * - UTF-8 when the code point is encoded in more than 1 code unit.
- * - UTF-16 and UTF-32 when the first multi-column code point is encountered.
- * (The code unit's value is lower than 0xd800 so the 2 code unit encoding
- * is irrelevant for this scanner.)
- * Due to these assumptions the scanner is faster than the full scanner. It
- * can process all text only containing ASCII. For UTF-16/32 it can process
- * most (all?) European languages. (Note the set it can process might be
- * reduced in the future, due to updates in the scanning rules.)
- * - The full scanner @ref __estimate_column_width. This scanner, if needed,
- * converts multiple code units into one code point then converts the code
- * point to a column width.
- *
- * See also:
- * - [format.string.general]/11
- * - https://en.wikipedia.org/wiki/UTF-8#Encoding
- * - https://en.wikipedia.org/wiki/UTF-16#U+D800_to_U+DFFF
- */
-
-/**
- * The first 2 column code point.
- *
- * This is the point where the fast UTF-16/32 scanner needs to stop processing.
- */
-inline constexpr uint32_t __two_column_code_point = 0x1100;
-
-/** Helper concept for an UTF-8 character type. */
-template <class _CharT>
-concept __utf8_character = same_as<_CharT, char> || same_as<_CharT, char8_t>;
-
-/** Helper concept for an UTF-16 character type. */
-template <class _CharT>
-concept __utf16_character = (same_as<_CharT, wchar_t> && sizeof(wchar_t) == 2) || same_as<_CharT, char16_t>;
-
-/** Helper concept for an UTF-32 character type. */
-template <class _CharT>
-concept __utf32_character = (same_as<_CharT, wchar_t> && sizeof(wchar_t) == 4) || same_as<_CharT, char32_t>;
-
-/** Helper concept for an UTF-16 or UTF-32 character type. */
-template <class _CharT>
-concept __utf16_or_32_character = __utf16_character<_CharT> || __utf32_character<_CharT>;
-
-/**
- * Converts a code point to the column width.
- *
- * The estimations are conforming to [format.string.general]/11
- *
- * This version expects a value less than 0x1'0000, which is a 3-byte UTF-8
- * character.
- */
-_LIBCPP_HIDE_FROM_ABI inline constexpr int __column_width_3(uint32_t __c) noexcept {
- _LIBCPP_ASSERT(__c < 0x10000,
- "Use __column_width_4 or __column_width for larger values");
-
- // clang-format off
- return 1 + (__c >= 0x1100 && (__c <= 0x115f ||
- (__c >= 0x2329 && (__c <= 0x232a ||
- (__c >= 0x2e80 && (__c <= 0x303e ||
- (__c >= 0x3040 && (__c <= 0xa4cf ||
- (__c >= 0xac00 && (__c <= 0xd7a3 ||
- (__c >= 0xf900 && (__c <= 0xfaff ||
- (__c >= 0xfe10 && (__c <= 0xfe19 ||
- (__c >= 0xfe30 && (__c <= 0xfe6f ||
- (__c >= 0xff00 && (__c <= 0xff60 ||
- (__c >= 0xffe0 && (__c <= 0xffe6
- ))))))))))))))))))));
- // clang-format on
-}
-
-/**
- * @overload
- *
- * This version expects a value greater than or equal to 0x1'0000, which is a
- * 4-byte UTF-8 character.
- */
-_LIBCPP_HIDE_FROM_ABI inline constexpr int __column_width_4(uint32_t __c) noexcept {
- _LIBCPP_ASSERT(__c >= 0x10000,
- "Use __column_width_3 or __column_width for smaller values");
-
- // clang-format off
- return 1 + (__c >= 0x1'f300 && (__c <= 0x1'f64f ||
- (__c >= 0x1'f900 && (__c <= 0x1'f9ff ||
- (__c >= 0x2'0000 && (__c <= 0x2'fffd ||
- (__c >= 0x3'0000 && (__c <= 0x3'fffd
- ))))))));
- // clang-format on
-}
-
-/**
- * @overload
- *
- * The general case, accepting all values.
- */
-_LIBCPP_HIDE_FROM_ABI inline constexpr int __column_width(uint32_t __c) noexcept {
- if (__c < 0x10000)
- return __column_width_3(__c);
-
- return __column_width_4(__c);
-}
-
-/**
- * Estimate the column width for the UTF-8 sequence using the fast algorithm.
- */
-template <__utf8_character _CharT>
-_LIBCPP_HIDE_FROM_ABI constexpr const _CharT*
-__estimate_column_width_fast(const _CharT* __first,
- const _CharT* __last) noexcept {
- return _VSTD::find_if(__first, __last,
- [](unsigned char __c) { return __c & 0x80; });
-}
-
-/**
- * @overload
- *
- * The implementation for UTF-16/32.
- */
-template <__utf16_or_32_character _CharT>
-_LIBCPP_HIDE_FROM_ABI constexpr const _CharT*
-__estimate_column_width_fast(const _CharT* __first,
- const _CharT* __last) noexcept {
- return _VSTD::find_if(__first, __last,
- [](uint32_t __c) { return __c >= 0x1100; });
-}
-
-template <class _CharT>
-struct _LIBCPP_TEMPLATE_VIS __column_width_result {
- /** The number of output columns. */
- size_t __width;
- /**
- * The last parsed element.
- *
- * This limits the original output to fit in the wanted number of columns.
- */
- const _CharT* __ptr;
-};
-
-/**
- * Small helper to determine the width of malformed Unicode.
- *
- * @note This function's only needed for UTF-8. During scanning UTF-8 there
- * are multiple place where it can be detected that the Unicode is malformed.
- * UTF-16 only requires 1 test and UTF-32 requires no testing.
- */
-template <__utf8_character _CharT>
-_LIBCPP_HIDE_FROM_ABI constexpr __column_width_result<_CharT>
-__estimate_column_width_malformed(const _CharT* __first, const _CharT* __last,
- size_t __maximum, size_t __result) noexcept {
- size_t __size = __last - __first;
- size_t __n = _VSTD::min(__size, __maximum);
- return {__result + __n, __first + __n};
-}
-
-/**
- * Determines the number of output columns needed to render the input.
- *
- * @note When the scanner encounters malformed Unicode it acts as-if every code
- * unit at the end of the input is one output column. It's expected the output
- * terminal will replace these malformed code units with a one column
- * replacement characters.
- *
- * @param __first Points to the first element of the input range.
- * @param __last Points beyond the last element of the input range.
- * @param __maximum The maximum number of output columns. The returned number
- * of estimated output columns will not exceed this value.
- */
-template <__utf8_character _CharT>
-_LIBCPP_HIDE_FROM_ABI constexpr __column_width_result<_CharT>
-__estimate_column_width(const _CharT* __first, const _CharT* __last,
- size_t __maximum) noexcept {
- size_t __result = 0;
-
- while (__first != __last) {
- // Based on the number of leading 1 bits the number of code units in the
- // code point can be determined. See
- // https://en.wikipedia.org/wiki/UTF-8#Encoding
- switch (_VSTD::countl_one(static_cast<unsigned char>(*__first))) {
- case 0: // 1-code unit encoding: all 1 column
- ++__result;
- ++__first;
- break;
-
- case 2: // 2-code unit encoding: all 1 column
- // Malformed Unicode.
- if (__last - __first < 2) [[unlikely]]
- return __estimate_column_width_malformed(__first, __last, __maximum,
- __result);
- __first += 2;
- ++__result;
- break;
-
- case 3: // 3-code unit encoding: either 1 or 2 columns
- // Malformed Unicode.
- if (__last - __first < 3) [[unlikely]]
- return __estimate_column_width_malformed(__first, __last, __maximum,
- __result);
- {
- uint32_t __c = static_cast<unsigned char>(*__first++) & 0x0f;
- __c <<= 6;
- __c |= static_cast<unsigned char>(*__first++) & 0x3f;
- __c <<= 6;
- __c |= static_cast<unsigned char>(*__first++) & 0x3f;
- __result += __column_width_3(__c);
- if (__result > __maximum)
- return {__result - 2, __first - 3};
- }
- break;
- case 4: // 4-code unit encoding: either 1 or 2 columns
- // Malformed Unicode.
- if (__last - __first < 4) [[unlikely]]
- return __estimate_column_width_malformed(__first, __last, __maximum,
- __result);
- {
- uint32_t __c = static_cast<unsigned char>(*__first++) & 0x07;
- __c <<= 6;
- __c |= static_cast<unsigned char>(*__first++) & 0x3f;
- __c <<= 6;
- __c |= static_cast<unsigned char>(*__first++) & 0x3f;
- __c <<= 6;
- __c |= static_cast<unsigned char>(*__first++) & 0x3f;
- __result += __column_width_4(__c);
- if (__result > __maximum)
- return {__result - 2, __first - 4};
- }
- break;
- default:
- // Malformed Unicode.
- return __estimate_column_width_malformed(__first, __last, __maximum,
- __result);
- }
-
- if (__result >= __maximum)
- return {__result, __first};
- }
- return {__result, __first};
-}
-
-template <__utf16_character _CharT>
-_LIBCPP_HIDE_FROM_ABI constexpr __column_width_result<_CharT>
-__estimate_column_width(const _CharT* __first, const _CharT* __last,
- size_t __maximum) noexcept {
- size_t __result = 0;
-
- while (__first != __last) {
- uint32_t __c = *__first;
- // Is the code unit part of a surrogate pair? See
- // https://en.wikipedia.org/wiki/UTF-16#U+D800_to_U+DFFF
- if (__c >= 0xd800 && __c <= 0xDfff) {
- // Malformed Unicode.
- if (__last - __first < 2) [[unlikely]]
- return {__result + 1, __first + 1};
-
- __c -= 0xd800;
- __c <<= 10;
- __c += (*(__first + 1) - 0xdc00);
- __c += 0x10000;
-
- __result += __column_width_4(__c);
- if (__result > __maximum)
- return {__result - 2, __first};
- __first += 2;
- } else {
- __result += __column_width_3(__c);
- if (__result > __maximum)
- return {__result - 2, __first};
- ++__first;
- }
-
- if (__result >= __maximum)
- return {__result, __first};
- }
-
- return {__result, __first};
-}
-
-template <__utf32_character _CharT>
-_LIBCPP_HIDE_FROM_ABI constexpr __column_width_result<_CharT>
-__estimate_column_width(const _CharT* __first, const _CharT* __last,
- size_t __maximum) noexcept {
- size_t __result = 0;
-
- while (__first != __last) {
- uint32_t __c = *__first;
- __result += __column_width(__c);
-
- if (__result > __maximum)
- return {__result - 2, __first};
-
- ++__first;
- if (__result >= __maximum)
- return {__result, __first};
- }
-
- return {__result, __first};
-}
-
-} // namespace __detail
-
-template <class _CharT>
-_LIBCPP_HIDE_FROM_ABI constexpr __string_alignment<_CharT>
-__get_string_alignment(const _CharT* __first, const _CharT* __last,
- ptrdiff_t __width, ptrdiff_t __precision) noexcept {
- _LIBCPP_ASSERT(__width != 0 || __precision != -1,
- "The function has no effect and shouldn't be used");
-
- // TODO FMT There might be more optimizations possible:
- // If __precision == __format::__number_max and the encoding is:
- // * UTF-8 : 4 * (__last - __first) >= __width
- // * UTF-16 : 2 * (__last - __first) >= __width
- // * UTF-32 : (__last - __first) >= __width
- // In these cases it's certain the output is at least the requested width.
- // It's unknown how often this happens in practice. For now the improvement
- // isn't implemented.
-
- /*
- * First assume there are no special Unicode code units in the input.
- * - Apply the precision (this may reduce the size of the input). When
- * __precison == -1 this step is omitted.
- * - Scan for special code units in the input.
- * If our assumption was correct the __pos will be at the end of the input.
- */
- const ptrdiff_t __length = __last - __first;
- const _CharT* __limit =
- __first +
- (__precision == -1 ? __length : _VSTD::min(__length, __precision));
- ptrdiff_t __size = __limit - __first;
- const _CharT* __pos =
- __detail::__estimate_column_width_fast(__first, __limit);
-
- if (__pos == __limit)
- return {__limit, __size, __size < __width};
-
- /*
- * Our assumption was wrong, there are special Unicode code units.
- * The range [__first, __pos) contains a set of code units with the
- * following property:
- * Every _CharT in the range will be rendered in 1 column.
- *
- * If there's no maximum width and the parsed size already exceeds the
- * minimum required width. The real size isn't important. So bail out.
- */
- if (__precision == -1 && (__pos - __first) >= __width)
- return {__last, 0, false};
-
- /* If there's a __precision, truncate the output to that width. */
- ptrdiff_t __prefix = __pos - __first;
- if (__precision != -1) {
- _LIBCPP_ASSERT(__precision > __prefix, "Logic error.");
- auto __lengh_info = __detail::__estimate_column_width(
- __pos, __last, __precision - __prefix);
- __size = __lengh_info.__width + __prefix;
- return {__lengh_info.__ptr, __size, __size < __width};
- }
-
- /* Else use __width to determine the number of required padding characters. */
- _LIBCPP_ASSERT(__width > __prefix, "Logic error.");
- /*
- * The column width is always one or two columns. For the precision the wanted
- * column width is the maximum, for the width it's the minimum. Using the
- * width estimation with its truncating behavior will result in the wrong
- * result in the following case:
- * - The last code unit processed requires two columns and exceeds the
- * maximum column width.
- * By increasing the __maximum by one avoids this issue. (It means it may
- * pass one code point more than required to determine the proper result;
- * that however isn't a problem for the algorithm.)
- */
- size_t __maximum = 1 + __width - __prefix;
- auto __lengh_info =
- __detail::__estimate_column_width(__pos, __last, __maximum);
- if (__lengh_info.__ptr != __last) {
- // Consumed the width number of code units. The exact size of the string
- // is unknown. We only know we don't need to align the output.
- _LIBCPP_ASSERT(static_cast<ptrdiff_t>(__lengh_info.__width + __prefix) >=
- __width,
- "Logic error");
- return {__last, 0, false};
- }
-
- __size = __lengh_info.__width + __prefix;
- return {__last, __size, __size < __width};
-}
-#else // _LIBCPP_HAS_NO_UNICODE
-template <class _CharT>
-_LIBCPP_HIDE_FROM_ABI constexpr __string_alignment<_CharT>
-__get_string_alignment(const _CharT* __first, const _CharT* __last,
- ptrdiff_t __width, ptrdiff_t __precision) noexcept {
- const ptrdiff_t __length = __last - __first;
- const _CharT* __limit =
- __first +
- (__precision == -1 ? __length : _VSTD::min(__length, __precision));
- ptrdiff_t __size = __limit - __first;
- return {__limit, __size, __size < __width};
-}
-#endif // _LIBCPP_HAS_NO_UNICODE
-
/// These fields are a filter for which elements to parse.
///
/// They default to false so when a new field is added it needs to be opted in
@@ -1143,6 +689,212 @@ _LIBCPP_HIDE_FROM_ABI constexpr void __process_display_type_pointer(__format_spe
}
}
+template <class _CharT>
+struct __column_width_result {
+ /// The number of output columns.
+ size_t __width_;
+ /// One beyond the last code unit used in the estimation.
+ ///
+ /// This limits the original output to fit in the wanted number of columns.
+ const _CharT* __last_;
+};
+
+/// Since a column width can be two it's possible that the requested column
+/// width can't be achieved. Depending on the intended usage the policy can be
+/// selected.
+/// - When used as precision the maximum width may not be exceeded and the
+/// result should be "rounded down" to the previous boundary.
+/// - When used as a width we're done once the minimum is reached, but
+/// exceeding is not an issue. Rounding down is an issue since that will
+/// result in writing fill characters. Therefore the result needs to be
+/// "rounded up".
+enum class __column_width_rounding { __down, __up };
+
+# ifndef _LIBCPP_HAS_NO_UNICODE
+
+namespace __detail {
+
+/// Converts a code point to the column width.
+///
+/// The estimations are conforming to [format.string.general]/11
+///
+/// This version expects a value less than 0x1'0000, which is a 3-byte UTF-8
+/// character.
+_LIBCPP_HIDE_FROM_ABI constexpr int __column_width_3(uint32_t __c) noexcept {
+ _LIBCPP_ASSERT(__c < 0x10000, "Use __column_width_4 or __column_width for larger values");
+
+ // clang-format off
+ return 1 + (__c >= 0x1100 && (__c <= 0x115f ||
+ (__c >= 0x2329 && (__c <= 0x232a ||
+ (__c >= 0x2e80 && (__c <= 0x303e ||
+ (__c >= 0x3040 && (__c <= 0xa4cf ||
+ (__c >= 0xac00 && (__c <= 0xd7a3 ||
+ (__c >= 0xf900 && (__c <= 0xfaff ||
+ (__c >= 0xfe10 && (__c <= 0xfe19 ||
+ (__c >= 0xfe30 && (__c <= 0xfe6f ||
+ (__c >= 0xff00 && (__c <= 0xff60 ||
+ (__c >= 0xffe0 && (__c <= 0xffe6
+ ))))))))))))))))))));
+ // clang-format on
+}
+
+/// @overload
+///
+/// This version expects a value greater than or equal to 0x1'0000, which is a
+/// 4-byte UTF-8 character.
+_LIBCPP_HIDE_FROM_ABI constexpr int __column_width_4(uint32_t __c) noexcept {
+ _LIBCPP_ASSERT(__c >= 0x10000, "Use __column_width_3 or __column_width for smaller values");
+
+ // clang-format off
+ return 1 + (__c >= 0x1'f300 && (__c <= 0x1'f64f ||
+ (__c >= 0x1'f900 && (__c <= 0x1'f9ff ||
+ (__c >= 0x2'0000 && (__c <= 0x2'fffd ||
+ (__c >= 0x3'0000 && (__c <= 0x3'fffd
+ ))))))));
+ // clang-format on
+}
+
+/// @overload
+///
+/// The general case, accepting all values.
+_LIBCPP_HIDE_FROM_ABI constexpr int __column_width(uint32_t __c) noexcept {
+ if (__c < 0x10000)
+ return __detail::__column_width_3(__c);
+
+ return __detail::__column_width_4(__c);
+}
+
+template <class _CharT>
+_LIBCPP_HIDE_FROM_ABI constexpr __column_width_result<_CharT> __estimate_column_width_grapheme_clustering(
+ const _CharT* __first, const _CharT* __last, size_t __maximum, __column_width_rounding __rounding) noexcept {
+ __unicode::__extended_grapheme_cluster_view<_CharT> __view{__first, __last};
+
+ __column_width_result<_CharT> __result{0, __first};
+ while (__result.__last_ != __last && __result.__width_ <= __maximum) {
+ typename __unicode::__extended_grapheme_cluster_view<_CharT>::__cluster __cluster = __view.__consume();
+ int __width = __detail::__column_width(__cluster.__code_point_);
+
+ // When the next entry would exceed the maximum width the previous width
+ // might be returned. For example when a width of 100 is requested the
+ // returned width might be 99, since the next code point has an estimated
+ // column width of 2. This depends on the rounding flag.
+ // When the maximum is exceeded the loop will abort the next iteration.
+ if (__rounding == __column_width_rounding::__down && __result.__width_ + __width > __maximum)
+ return __result;
+
+ __result.__width_ += __width;
+ __result.__last_ = __cluster.__last_;
+ }
+
+ return __result;
+}
+
+} // namespace __detail
+
+// Unicode can be stored in several formats: UTF-8, UTF-16, and UTF-32.
+// Depending on format the relation between the number of code units stored and
+// the number of output columns differs. The first relation is the number of
+// code units forming a code point. (The text assumes the code units are
+// unsigned.)
+// - UTF-8 The number of code units is between one and four. The first 127
+// Unicode code points match the ASCII character set. When the highest bit is
+// set it means the code point has more than one code unit.
+// - UTF-16: The number of code units is between 1 and 2. When the first
+// code unit is in the range [0xd800,0xdfff) it means the code point uses two
+// code units.
+// - UTF-32: The number of code units is always one.
+//
+// The code point to the number of columns is specified in
+// [format.string.std]/11. This list might change in the future.
+//
+// Another thing to be taken into account is Grapheme clustering. This means
+// that in some cases multiple code points are combined one element in the
+// output. For example:
+// - an ASCII character with a combined diacritical mark
+// - an emoji with a skin tone modifier
+// - a group of combined people emoji to create a family
+// - a combination of flag emoji
+//
+// See also:
+// - [format.string.general]/11
+// - https://en.wikipedia.org/wiki/UTF-8#Encoding
+// - https://en.wikipedia.org/wiki/UTF-16#U+D800_to_U+DFFF
+
+_LIBCPP_HIDE_FROM_ABI constexpr bool __is_ascii(char32_t __c) { return __c < 0x80; }
+
+/// Determines the number of output columns needed to render the input.
+///
+/// \note When the scanner encounters malformed Unicode it acts as-if every
+/// code unit is a one column code point. Typically a terminal uses the same
+/// strategy and replaces every malformed code unit with a one column
+/// replacement character.
+///
+/// \param __first Points to the first element of the input range.
+/// \param __last Points beyond the last element of the input range.
+/// \param __maximum The maximum number of output columns. The returned number
+/// of estimated output columns will not exceed this value.
+/// \param __rounding Selects the rounding method.
+/// \c __down result.__width_ <= __maximum
+/// \c __up result.__width_ <= __maximum + 1
+template <class _CharT>
+_LIBCPP_HIDE_FROM_ABI constexpr __column_width_result<_CharT> __estimate_column_width(
+ basic_string_view<_CharT> __str, size_t __maximum, __column_width_rounding __rounding) noexcept {
+ // The width estimation is done in two steps:
+ // - Quickly process for the ASCII part. ASCII has the following properties
+ // - One code unit is one code point
+ // - Every code point has an estimated width of one
+ // - When needed it will a Unicode Grapheme clustering algorithm to find
+ // the proper place for truncation.
+
+ if (__str.empty() || __maximum == 0)
+ return {0, __str.begin()};
+
+ // ASCII has one caveat; when an ASCII character is followed by a non-ASCII
+ // character they might be part of an extended grapheme cluster. For example:
+ // an ASCII letter and a COMBINING ACUTE ACCENT
+ // The truncate should happen after the COMBINING ACUTE ACCENT. Therefore we
+ // need to scan one code unit beyond the requested precision. When this code
+ // unit is non-ASCII we omit the current code unit and let the Grapheme
+ // clustering algorithm do its work.
+ const _CharT* __it = __str.begin();
+ if (__is_ascii(*__it)) {
+ do {
+ --__maximum;
+ ++__it;
+ if (__it == __str.end())
+ return {__str.size(), __str.end()};
+
+ if (__maximum == 0) {
+ if (__is_ascii(*__it))
+ return {static_cast<size_t>(__it - __str.begin()), __it};
+
+ break;
+ }
+ } while (__is_ascii(*__it));
+ --__it;
+ ++__maximum;
+ }
+
+ ptrdiff_t __ascii_size = __it - __str.begin();
+ __column_width_result __result =
+ __detail::__estimate_column_width_grapheme_clustering(__it, __str.end(), __maximum, __rounding);
+
+ __result.__width_ += __ascii_size;
+ return __result;
+}
+# else // !defined(_LIBCPP_HAS_NO_UNICODE)
+template <class _CharT>
+_LIBCPP_HIDE_FROM_ABI constexpr __column_width_result<_CharT>
+__estimate_column_width(basic_string_view<_CharT> __str, size_t __maximum, __column_width_rounding) noexcept {
+ // When Unicode isn't supported assume ASCII and every code unit is one code
+ // point. In ASCII the estimated column width is always one. Thus there's no
+ // need for rounding.
+ size_t __width_ = _VSTD::min(__str.size(), __maximum);
+ return {__width_, __str.begin() + __width_};
+}
+
+# endif // !defined(_LIBCPP_HAS_NO_UNICODE)
+
} // namespace __format_spec
#endif //_LIBCPP_STD_VER > 17
diff --git a/libcxx/include/__format/unicode.h b/libcxx/include/__format/unicode.h
new file mode 100644
index 000000000000..3316217f4a1e
--- /dev/null
+++ b/libcxx/include/__format/unicode.h
@@ -0,0 +1,339 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBCPP___FORMAT_UNICODE_H
+#define _LIBCPP___FORMAT_UNICODE_H
+
+#include <__assert>
+#include <__config>
+#include <__format/extended_grapheme_cluster_table.h>
+#include <__utility/unreachable.h>
+#include <bit>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+# pragma GCC system_header
+#endif
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+#if _LIBCPP_STD_VER > 17
+
+# ifndef _LIBCPP_HAS_NO_UNICODE
+
+/// Implements the grapheme cluster boundary rules
+///
+/// These rules are used to implement format's width estimation as stated in
+/// [format.string.std]/11
+///
+/// The Standard refers to UAX \#29 for Unicode 12.0.0
+/// https://www.unicode.org/reports/tr29/#Grapheme_Cluster_Boundary_Rules
+///
+/// The data tables used are
+/// https://www.unicode.org/Public/UCD/latest/ucd/auxiliary/GraphemeBreakProperty.txt
+/// https://www.unicode.org/Public/UCD/latest/ucd/emoji/emoji-data.txt
+/// https://www.unicode.org/Public/UCD/latest/ucd/auxiliary/GraphemeBreakTest.txt (for testing only)
+
+namespace __unicode {
+
+inline constexpr char32_t __replacement_character = U'\ufffd';
+
+_LIBCPP_HIDE_FROM_ABI constexpr bool __is_continuation(const char* __char, int __count) {
+ do {
+ if ((*__char & 0b1000'0000) != 0b1000'0000)
+ return false;
+ --__count;
+ ++__char;
+ } while (__count);
+ return true;
+}
+
+/// Helper class to extract a code unit from a Unicode character range.
+///
+/// The stored range is a view. There are multiple specialization for different
+/// character types.
+template <class _CharT>
+class __code_point_view;
+
+/// UTF-8 specialization.
+template <>
+class __code_point_view<char> {
+public:
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __code_point_view(const char* __first, const char* __last)
+ : __first_(__first), __last_(__last) {}
+
+ _LIBCPP_HIDE_FROM_ABI constexpr bool __at_end() const noexcept { return __first_ == __last_; }
+ _LIBCPP_HIDE_FROM_ABI constexpr const char* __position() const noexcept { return __first_; }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr char32_t __consume() noexcept {
+ _LIBCPP_ASSERT(__first_ != __last_, "can't move beyond the end of input");
+
+ // Based on the number of leading 1 bits the number of code units in the
+ // code point can be determined. See
+ // https://en.wikipedia.org/wiki/UTF-8#Encoding
+ switch (_VSTD::countl_one(static_cast<unsigned char>(*__first_))) {
+ case 0:
+ return *__first_++;
+
+ case 2:
+ if (__last_ - __first_ < 2 || !__unicode::__is_continuation(__first_ + 1, 1)) [[unlikely]]
+ break;
+ else {
+ char32_t __value = static_cast<unsigned char>(*__first_++) & 0x1f;
+ __value <<= 6;
+ __value |= static_cast<unsigned char>(*__first_++) & 0x3f;
+ return __value;
+ }
+
+ case 3:
+ if (__last_ - __first_ < 3 || !__unicode::__is_continuation(__first_ + 1, 2)) [[unlikely]]
+ break;
+ else {
+ char32_t __value = static_cast<unsigned char>(*__first_++) & 0x0f;
+ __value <<= 6;
+ __value |= static_cast<unsigned char>(*__first_++) & 0x3f;
+ __value <<= 6;
+ __value |= static_cast<unsigned char>(*__first_++) & 0x3f;
+ return __value;
+ }
+
+ case 4:
+ if (__last_ - __first_ < 4 || !__unicode::__is_continuation(__first_ + 1, 3)) [[unlikely]]
+ break;
+ else {
+ char32_t __value = static_cast<unsigned char>(*__first_++) & 0x07;
+ __value <<= 6;
+ __value |= static_cast<unsigned char>(*__first_++) & 0x3f;
+ __value <<= 6;
+ __value |= static_cast<unsigned char>(*__first_++) & 0x3f;
+ __value <<= 6;
+ __value |= static_cast<unsigned char>(*__first_++) & 0x3f;
+ return __value;
+ }
+ }
+ // An invalid number of leading ones can be garbage or a code unit in the
+ // middle of a code point. By consuming one code unit the parser may get
+ // "in sync" after a few code units.
+ ++__first_;
+ return __replacement_character;
+ }
+
+private:
+ const char* __first_;
+ const char* __last_;
+};
+
+# ifndef TEST_HAS_NO_WIDE_CHARACTERS
+/// This specialization depends on the size of wchar_t
+/// - 2 UTF-16 (for example Windows and AIX)
+/// - 4 UTF-32 (for example Linux)
+template <>
+class __code_point_view<wchar_t> {
+public:
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __code_point_view(const wchar_t* __first, const wchar_t* __last)
+ : __first_(__first), __last_(__last) {}
+
+ _LIBCPP_HIDE_FROM_ABI constexpr const wchar_t* __position() const noexcept { return __first_; }
+ _LIBCPP_HIDE_FROM_ABI constexpr bool __at_end() const noexcept { return __first_ == __last_; }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr char32_t __consume() noexcept {
+ _LIBCPP_ASSERT(__first_ != __last_, "can't move beyond the end of input");
+
+ if constexpr (sizeof(wchar_t) == 2) {
+ char32_t __result = *__first_++;
+ // Is the code unit part of a surrogate pair? See
+ // https://en.wikipedia.org/wiki/UTF-16#U+D800_to_U+DFFF
+ if (__result >= 0xd800 && __result <= 0xDfff) {
+ // Malformed Unicode.
+ if (__first_ == __last_) [[unlikely]]
+ return __replacement_character;
+
+ __result -= 0xd800;
+ __result <<= 10;
+ __result += *__first_++ - 0xdc00;
+ __result += 0x10000;
+ }
+ return __result;
+
+ } else if constexpr (sizeof(wchar_t) == 4) {
+ char32_t __result = *__first_++;
+ if (__result > 0x10FFFF) [[unlikely]]
+ return __replacement_character;
+ return __result;
+ } else {
+ // TODO FMT P2593R0 Use static_assert(false, "sizeof(wchar_t) has a not implemented value");
+ _LIBCPP_ASSERT(sizeof(wchar_t) == 0, "sizeof(wchar_t) has a not implemented value");
+ __libcpp_unreachable();
+ }
+ }
+
+private:
+ const wchar_t* __first_;
+ const wchar_t* __last_;
+};
+# endif
+
+_LIBCPP_HIDE_FROM_ABI constexpr bool __at_extended_grapheme_cluster_break(
+ bool& __ri_break_allowed,
+ bool __has_extened_pictographic,
+ __extended_grapheme_custer_property_boundary::__property __prev,
+ __extended_grapheme_custer_property_boundary::__property __next) {
+ using __extended_grapheme_custer_property_boundary::__property;
+
+ __has_extened_pictographic |= __prev == __property::__Extended_Pictographic;
+
+ // https://www.unicode.org/reports/tr29/tr29-39.html#Grapheme_Cluster_Boundary_Rules
+
+ // *** Break at the start and end of text, unless the text is empty. ***
+
+ _LIBCPP_ASSERT(__prev != __property::__sot, "should be handled in the constructor"); // GB1
+ _LIBCPP_ASSERT(__prev != __property::__eot, "should be handled by our caller"); // GB2
+
+ // *** Do not break between a CR and LF. Otherwise, break before and after controls. ***
+ if (__prev == __property::__CR && __next == __property::__LF) // GB3
+ return false;
+
+ if (__prev == __property::__Control || __prev == __property::__CR || __prev == __property::__LF) // GB4
+ return true;
+
+ if (__next == __property::__Control || __next == __property::__CR || __next == __property::__LF) // GB5
+ return true;
+
+ // *** Do not break Hangul syllable sequences. ***
+ if (__prev == __property::__L &&
+ (__next == __property::__L || __next == __property::__V || __next == __property::__LV ||
+ __next == __property::__LVT)) // GB6
+ return false;
+
+ if ((__prev == __property::__LV || __prev == __property::__V) &&
+ (__next == __property::__V || __next == __property::__T)) // GB7
+ return false;
+
+ if ((__prev == __property::__LVT || __prev == __property::__T) && __next == __property::__T) // GB8
+ return false;
+
+ // *** Do not break before extending characters or ZWJ. ***
+ if (__next == __property::__Extend || __next == __property::__ZWJ)
+ return false; // GB9
+
+ // *** Do not break before SpacingMarks, or after Prepend characters. ***
+ if (__next == __property::__SpacingMark) // GB9a
+ return false;
+
+ if (__prev == __property::__Prepend) // GB9b
+ return false;
+
+ // *** Do not break within emoji modifier sequences or emoji zwj sequences. ***
+
+ // GB11 \p{Extended_Pictographic} Extend* ZWJ x \p{Extended_Pictographic}
+ //
+ // Note that several parts of this rule are matched by GB9: Any x (Extend | ZWJ)
+ // - \p{Extended_Pictographic} x Extend
+ // - Extend x Extend
+ // - \p{Extended_Pictographic} x ZWJ
+ // - Extend x ZWJ
+ //
+ // So the only case left to test is
+ // - \p{Extended_Pictographic}' x ZWJ x \p{Extended_Pictographic}
+ // where \p{Extended_Pictographic}' is stored in __has_extened_pictographic
+ if (__has_extened_pictographic && __prev == __property::__ZWJ && __next == __property::__Extended_Pictographic)
+ return false;
+
+ // *** Do not break within emoji flag sequences ***
+
+ // That is, do not break between regional indicator (RI) symbols if there
+ // is an odd number of RI characters before the break point.
+
+ if (__prev == __property::__Regional_Indicator && __next == __property::__Regional_Indicator) { // GB12 + GB13
+ __ri_break_allowed = !__ri_break_allowed;
+ if (__ri_break_allowed)
+ return true;
+
+ return false;
+ }
+
+ // *** Otherwise, break everywhere. ***
+ return true; // GB999
+}
+
+/// Helper class to extract an extended grapheme cluster from a Unicode character range.
+///
+/// This function is used to determine the column width of an extended grapheme
+/// cluster. In order to do that only the first code point is evaluated.
+/// Therefore only this code point is extracted.
+template <class _CharT>
+class __extended_grapheme_cluster_view {
+public:
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __extended_grapheme_cluster_view(const _CharT* __first, const _CharT* __last)
+ : __code_point_view_(__first, __last),
+ __next_code_point_(__code_point_view_.__consume()),
+ __next_prop_(__extended_grapheme_custer_property_boundary::__get_property(__next_code_point_)) {}
+
+ struct __cluster {
+ /// The first code point of the extended grapheme cluster.
+ ///
+ /// The first code point is used to estimate the width of the extended
+ /// grapheme cluster.
+ char32_t __code_point_;
+
+ /// Points one beyond the last code unit in the extended grapheme cluster.
+ ///
+ /// It's expected the caller has the start position and thus can determine
+ /// the code unit range of the extended grapheme cluster.
+ const _CharT* __last_;
+ };
+
+ _LIBCPP_HIDE_FROM_ABI constexpr __cluster __consume() {
+ _LIBCPP_ASSERT(
+ __next_prop_ != __extended_grapheme_custer_property_boundary::__property::__eot,
+ "can't move beyond the end of input");
+ char32_t __code_point = __next_code_point_;
+ if (!__code_point_view_.__at_end())
+ return {__code_point, __get_break()};
+
+ __next_prop_ = __extended_grapheme_custer_property_boundary::__property::__eot;
+ return {__code_point, __code_point_view_.__position()};
+ }
+
+private:
+ __code_point_view<_CharT> __code_point_view_;
+
+ char32_t __next_code_point_;
+ __extended_grapheme_custer_property_boundary::__property __next_prop_;
+
+ _LIBCPP_HIDE_FROM_ABI constexpr const _CharT* __get_break() {
+ bool __ri_break_allowed = true;
+ bool __has_extened_pictographic = false;
+ while (true) {
+ const _CharT* __result = __code_point_view_.__position();
+ __extended_grapheme_custer_property_boundary::__property __prev = __next_prop_;
+ if (__code_point_view_.__at_end()) {
+ __next_prop_ = __extended_grapheme_custer_property_boundary::__property::__eot;
+ return __result;
+ }
+ __next_code_point_ = __code_point_view_.__consume();
+ __next_prop_ = __extended_grapheme_custer_property_boundary::__get_property(__next_code_point_);
+
+ __has_extened_pictographic |=
+ __prev == __extended_grapheme_custer_property_boundary::__property::__Extended_Pictographic;
+
+ if (__at_extended_grapheme_cluster_break(__ri_break_allowed, __has_extened_pictographic, __prev, __next_prop_))
+ return __result;
+ }
+ }
+};
+
+} // namespace __unicode
+
+# endif // _LIBCPP_HAS_NO_UNICODE
+
+#endif //_LIBCPP_STD_VER > 17
+
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP___FORMAT_UNICODE_H
diff --git a/libcxx/include/__iterator/reverse_iterator.h b/libcxx/include/__iterator/reverse_iterator.h
index a915609dbe33..7f4ef3c3d503 100644
--- a/libcxx/include/__iterator/reverse_iterator.h
+++ b/libcxx/include/__iterator/reverse_iterator.h
@@ -332,41 +332,16 @@ using _ReverseWrapper = reverse_iterator<reverse_iterator<_Iter> >;
template <class _Iter, bool __b>
struct __unwrap_iter_impl<_ReverseWrapper<_Iter>, __b> {
- static _LIBCPP_CONSTEXPR decltype(std::__unwrap_iter(std::declval<_Iter>()))
- __apply(_ReverseWrapper<_Iter> __i) _NOEXCEPT {
- return std::__unwrap_iter(__i.base().base());
- }
-};
-
-template <class _OrigIter, class _UnwrappedIter>
-struct __rewrap_iter_impl<_ReverseWrapper<_OrigIter>, _UnwrappedIter> {
- template <class _Iter>
- struct _ReverseWrapperCount {
- static _LIBCPP_CONSTEXPR const size_t value = 1;
- };
-
- template <class _Iter>
- struct _ReverseWrapperCount<_ReverseWrapper<_Iter> > {
- static _LIBCPP_CONSTEXPR const size_t value = 1 + _ReverseWrapperCount<_Iter>::value;
- };
-
- template <size_t _RewrapCount, class _OIter, class _UIter, __enable_if_t<_RewrapCount != 0, int> = 0>
- _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR _ReverseWrapper<_OIter> __rewrap(_ReverseWrapper<_OIter> __iter1,
- _UIter __iter2) {
- return _ReverseWrapper<_OIter>(
- reverse_iterator<_OIter>(__rewrap<_RewrapCount - 1>(__iter1.base().base(), __iter2)));
- }
+ using _UnwrappedIter = decltype(__unwrap_iter_impl<_Iter>::__unwrap(std::declval<_Iter>()));
- template <size_t _RewrapCount, class _OIter, class _UIter, __enable_if_t<_RewrapCount == 0, int> = 0>
- _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR decltype(std::__rewrap_iter(std::declval<_OIter>(),
- std::declval<_UIter>()))
- __rewrap(_OIter __iter1, _UIter __iter2) {
- return std::__rewrap_iter(__iter1, __iter2);
+ static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR _ReverseWrapper<_Iter>
+ __rewrap(_ReverseWrapper<_Iter> __orig_iter, _UnwrappedIter __unwrapped_iter) {
+ return _ReverseWrapper<_Iter>(
+ reverse_iterator<_Iter>(__unwrap_iter_impl<_Iter>::__rewrap(__orig_iter.base().base(), __unwrapped_iter)));
}
- _LIBCPP_HIDE_FROM_ABI static _LIBCPP_CONSTEXPR _ReverseWrapper<_OrigIter> __apply(_ReverseWrapper<_OrigIter> __iter1,
- _UnwrappedIter __iter2) {
- return __rewrap<_ReverseWrapperCount<_OrigIter>::value>(__iter1, __iter2);
+ static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR _UnwrappedIter __unwrap(_ReverseWrapper<_Iter> __i) _NOEXCEPT {
+ return __unwrap_iter_impl<_Iter>::__unwrap(__i.base().base());
}
};
diff --git a/libcxx/include/__locale b/libcxx/include/__locale
index 4450123db194..40f9a3ff57c2 100644
--- a/libcxx/include/__locale
+++ b/libcxx/include/__locale
@@ -33,7 +33,7 @@
# include <__support/newlib/xlocale.h>
#elif defined(__OpenBSD__)
# include <__support/openbsd/xlocale.h>
-#elif (defined(__APPLE__) || defined(__FreeBSD__) || defined(__IBMCPP__))
+#elif (defined(__APPLE__) || defined(__FreeBSD__))
# include <xlocale.h>
#elif defined(__Fuchsia__)
# include <__support/fuchsia/xlocale.h>
@@ -492,7 +492,11 @@ public:
static const mask punct = _ISPUNCT;
static const mask xdigit = _ISXDIGIT;
static const mask blank = _ISBLANK;
+# if defined(_AIX)
+ static const mask __regex_word = 0x8000;
+# else
static const mask __regex_word = 0x80;
+# endif
#elif defined(_NEWLIB_VERSION)
// Same type as Newlib's _ctype_ array in newlib/libc/include/ctype.h.
typedef char mask;
@@ -545,11 +549,8 @@ public:
_LIBCPP_INLINE_VISIBILITY ctype_base() {}
-// TODO: Remove the ifndef when the assert no longer fails on AIX.
-#ifndef _AIX
static_assert((__regex_word & ~(space | print | cntrl | upper | lower | alpha | digit | punct | xdigit | blank)) == __regex_word,
"__regex_word can't overlap other bits");
-#endif
};
template <class _CharT> class _LIBCPP_TEMPLATE_VIS ctype;
diff --git a/libcxx/include/__random/binomial_distribution.h b/libcxx/include/__random/binomial_distribution.h
index d0e8f3034939..af60fa2a38e0 100644
--- a/libcxx/include/__random/binomial_distribution.h
+++ b/libcxx/include/__random/binomial_distribution.h
@@ -27,7 +27,7 @@ _LIBCPP_BEGIN_NAMESPACE_STD
template<class _IntType = int>
class _LIBCPP_TEMPLATE_VIS binomial_distribution
{
- static_assert(__libcpp_random_is_valid_inttype<_IntType>::value, "IntType must be an integer type larger than char");
+ static_assert(__libcpp_random_is_valid_inttype<_IntType>::value, "IntType must be a supported integer type");
public:
// types
typedef _IntType result_type;
diff --git a/libcxx/include/__random/discrete_distribution.h b/libcxx/include/__random/discrete_distribution.h
index d899e72d87f9..8dc63c0e98b4 100644
--- a/libcxx/include/__random/discrete_distribution.h
+++ b/libcxx/include/__random/discrete_distribution.h
@@ -30,7 +30,7 @@ _LIBCPP_BEGIN_NAMESPACE_STD
template<class _IntType = int>
class _LIBCPP_TEMPLATE_VIS discrete_distribution
{
- static_assert(__libcpp_random_is_valid_inttype<_IntType>::value, "IntType must be an integer type larger than char");
+ static_assert(__libcpp_random_is_valid_inttype<_IntType>::value, "IntType must be a supported integer type");
public:
// types
typedef _IntType result_type;
diff --git a/libcxx/include/__random/geometric_distribution.h b/libcxx/include/__random/geometric_distribution.h
index 8e1be522e0e3..751cf7860e66 100644
--- a/libcxx/include/__random/geometric_distribution.h
+++ b/libcxx/include/__random/geometric_distribution.h
@@ -27,7 +27,7 @@ _LIBCPP_BEGIN_NAMESPACE_STD
template<class _IntType = int>
class _LIBCPP_TEMPLATE_VIS geometric_distribution
{
- static_assert(__libcpp_random_is_valid_inttype<_IntType>::value, "IntType must be an integer type larger than char");
+ static_assert(__libcpp_random_is_valid_inttype<_IntType>::value, "IntType must be a supported integer type");
public:
// types
typedef _IntType result_type;
diff --git a/libcxx/include/__random/is_valid.h b/libcxx/include/__random/is_valid.h
index d41bfa45ea70..be3b61b8dc01 100644
--- a/libcxx/include/__random/is_valid.h
+++ b/libcxx/include/__random/is_valid.h
@@ -10,6 +10,7 @@
#define _LIBCPP___RANDOM_IS_VALID_H
#include <__config>
+#include <cstdint>
#include <type_traits>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
@@ -25,18 +26,20 @@ _LIBCPP_BEGIN_NAMESPACE_STD
// unsigned int, unsigned long, or unsigned long long.
template<class> struct __libcpp_random_is_valid_inttype : false_type {};
+template<> struct __libcpp_random_is_valid_inttype<int8_t> : true_type {}; // extension
template<> struct __libcpp_random_is_valid_inttype<short> : true_type {};
template<> struct __libcpp_random_is_valid_inttype<int> : true_type {};
template<> struct __libcpp_random_is_valid_inttype<long> : true_type {};
template<> struct __libcpp_random_is_valid_inttype<long long> : true_type {};
+template<> struct __libcpp_random_is_valid_inttype<uint8_t> : true_type {}; // extension
template<> struct __libcpp_random_is_valid_inttype<unsigned short> : true_type {};
template<> struct __libcpp_random_is_valid_inttype<unsigned int> : true_type {};
template<> struct __libcpp_random_is_valid_inttype<unsigned long> : true_type {};
template<> struct __libcpp_random_is_valid_inttype<unsigned long long> : true_type {};
#ifndef _LIBCPP_HAS_NO_INT128
-template<> struct __libcpp_random_is_valid_inttype<__int128_t> : true_type {};
-template<> struct __libcpp_random_is_valid_inttype<__uint128_t> : true_type {};
+template<> struct __libcpp_random_is_valid_inttype<__int128_t> : true_type {}; // extension
+template<> struct __libcpp_random_is_valid_inttype<__uint128_t> : true_type {}; // extension
#endif // _LIBCPP_HAS_NO_INT128
// [rand.req.urng]/3:
diff --git a/libcxx/include/__random/negative_binomial_distribution.h b/libcxx/include/__random/negative_binomial_distribution.h
index 72ce88ea74ba..90d3f0178914 100644
--- a/libcxx/include/__random/negative_binomial_distribution.h
+++ b/libcxx/include/__random/negative_binomial_distribution.h
@@ -29,7 +29,7 @@ _LIBCPP_BEGIN_NAMESPACE_STD
template<class _IntType = int>
class _LIBCPP_TEMPLATE_VIS negative_binomial_distribution
{
- static_assert(__libcpp_random_is_valid_inttype<_IntType>::value, "IntType must be an integer type larger than char");
+ static_assert(__libcpp_random_is_valid_inttype<_IntType>::value, "IntType must be a supported integer type");
public:
// types
typedef _IntType result_type;
@@ -121,7 +121,9 @@ negative_binomial_distribution<_IntType>::operator()(_URNG& __urng, const param_
static_assert(__libcpp_random_is_valid_urng<_URNG>::value, "");
result_type __k = __pr.k();
double __p = __pr.p();
- if (__k <= 21 * __p)
+ // When the number of bits in _IntType is small, we are too likely to
+ // overflow __f below to use this technique.
+ if (__k <= 21 * __p && sizeof(_IntType) > 1)
{
bernoulli_distribution __gen(__p);
result_type __f = 0;
@@ -133,6 +135,8 @@ negative_binomial_distribution<_IntType>::operator()(_URNG& __urng, const param_
else
++__f;
}
+ _LIBCPP_ASSERT(__f >= 0, "std::negative_binomial_distribution should never produce negative values. "
+ "This is almost certainly a signed integer overflow issue on __f.");
return __f;
}
return poisson_distribution<result_type>(gamma_distribution<double>
diff --git a/libcxx/include/__random/poisson_distribution.h b/libcxx/include/__random/poisson_distribution.h
index 7730923ad6ca..ef55b1be4844 100644
--- a/libcxx/include/__random/poisson_distribution.h
+++ b/libcxx/include/__random/poisson_distribution.h
@@ -31,7 +31,7 @@ _LIBCPP_BEGIN_NAMESPACE_STD
template<class _IntType = int>
class _LIBCPP_TEMPLATE_VIS poisson_distribution
{
- static_assert(__libcpp_random_is_valid_inttype<_IntType>::value, "IntType must be an integer type larger than char");
+ static_assert(__libcpp_random_is_valid_inttype<_IntType>::value, "IntType must be a supported integer type");
public:
// types
typedef _IntType result_type;
diff --git a/libcxx/include/__random/uniform_int_distribution.h b/libcxx/include/__random/uniform_int_distribution.h
index dd0a7e4e4982..46b627f45da9 100644
--- a/libcxx/include/__random/uniform_int_distribution.h
+++ b/libcxx/include/__random/uniform_int_distribution.h
@@ -159,7 +159,7 @@ __independent_bits_engine<_Engine, _UIntType>::__eval(true_type)
template<class _IntType = int>
class uniform_int_distribution
{
- static_assert(__libcpp_random_is_valid_inttype<_IntType>::value, "IntType must be an integer type larger than char");
+ static_assert(__libcpp_random_is_valid_inttype<_IntType>::value, "IntType must be a supported integer type");
public:
// types
typedef _IntType result_type;
diff --git a/libcxx/include/algorithm b/libcxx/include/algorithm
index f616a031960e..5958ad1a95af 100644
--- a/libcxx/include/algorithm
+++ b/libcxx/include/algorithm
@@ -360,6 +360,17 @@ namespace ranges {
borrowed_iterator_t<R>
ranges::stable_sort(R&& r, Comp comp = {}, Proj proj = {}); // since C++20
+ template<random_access_iterator I, sentinel_for<I> S, class Comp = ranges::less,
+ class Proj = identity>
+ requires sortable<I, Comp, Proj>
+ constexpr I
+ ranges::partial_sort(I first, I middle, S last, Comp comp = {}, Proj proj = {}); // since C++20
+
+ template<random_access_range R, class Comp = ranges::less, class Proj = identity>
+ requires sortable<iterator_t<R>, Comp, Proj>
+ constexpr borrowed_iterator_t<R>
+ ranges::partial_sort(R&& r, iterator_t<R> middle, Comp comp = {}, Proj proj = {}); // since C++20
+
template<class T, output_iterator<const T&> O, sentinel_for<O> S>
constexpr O ranges::fill(O first, S last, const T& value); // since C++20
@@ -464,6 +475,28 @@ namespace ranges {
ranges::less>
constexpr bool binary_search(R&& r, const T& value, Comp comp = {},
Proj proj = {}); // since C++20
+
+ template<permutable I, sentinel_for<I> S, class Proj = identity,
+ indirect_unary_predicate<projected<I, Proj>> Pred>
+ constexpr subrange<I>
+ partition(I first, S last, Pred pred, Proj proj = {}); // Since C++20
+
+ template<forward_range R, class Proj = identity,
+ indirect_unary_predicate<projected<iterator_t<R>, Proj>> Pred>
+ requires permutable<iterator_t<R>>
+ constexpr borrowed_subrange_t<R>
+ partition(R&& r, Pred pred, Proj proj = {}); // Since C++20
+
+ template<bidirectional_iterator I, sentinel_for<I> S, class Proj = identity,
+ indirect_unary_predicate<projected<I, Proj>> Pred>
+ requires permutable<I>
+ subrange<I> stable_partition(I first, S last, Pred pred, Proj proj = {}); // Since C++20
+
+ template<bidirectional_range R, class Proj = identity,
+ indirect_unary_predicate<projected<iterator_t<R>, Proj>> Pred>
+ requires permutable<iterator_t<R>>
+ borrowed_subrange_t<R> stable_partition(R&& r, Pred pred, Proj proj = {}); // Since C++20
+
template<input_iterator I1, sentinel_for<I1> S1, forward_iterator I2, sentinel_for<I2> S2,
class Pred = ranges::equal_to, class Proj1 = identity, class Proj2 = identity>
requires indirectly_comparable<I1, I2, Pred, Proj1, Proj2>
@@ -548,6 +581,34 @@ namespace ranges {
constexpr ranges::move_result<borrowed_iterator_t<R>, O>
ranges::move(R&& r, O result); // since C++20
+ template<class I, class O1, class O2>
+ using partition_copy_result = in_out_out_result<I, O1, O2>; // since C++20
+
+ template<input_iterator I, sentinel_for<I> S,
+ weakly_incrementable O1, weakly_incrementable O2,
+ class Proj = identity, indirect_unary_predicate<projected<I, Proj>> Pred>
+ requires indirectly_copyable<I, O1> && indirectly_copyable<I, O2>
+ constexpr partition_copy_result<I, O1, O2>
+ partition_copy(I first, S last, O1 out_true, O2 out_false, Pred pred,
+ Proj proj = {}); // Since C++20
+
+ template<input_range R, weakly_incrementable O1, weakly_incrementable O2,
+ class Proj = identity,
+ indirect_unary_predicate<projected<iterator_t<R>, Proj>> Pred>
+ requires indirectly_copyable<iterator_t<R>, O1> &&
+ indirectly_copyable<iterator_t<R>, O2>
+ constexpr partition_copy_result<borrowed_iterator_t<R>, O1, O2>
+ partition_copy(R&& r, O1 out_true, O2 out_false, Pred pred, Proj proj = {}); // Since C++20
+
+ template<forward_iterator I, sentinel_for<I> S, class Proj = identity,
+ indirect_unary_predicate<projected<I, Proj>> Pred>
+ constexpr I partition_point(I first, S last, Pred pred, Proj proj = {}); // Since C++20
+
+ template<forward_range R, class Proj = identity,
+ indirect_unary_predicate<projected<iterator_t<R>, Proj>> Pred>
+ constexpr borrowed_iterator_t<R>
+ partition_point(R&& r, Pred pred, Proj proj = {}); // Since C++20
+
template<class I1, class I2, class O>
using merge_result = in_in_out_result<I1, I2, O>; // since C++20
@@ -649,6 +710,16 @@ namespace ranges {
constexpr ranges::rotate_copy_result<borrowed_iterator_t<R>, O>
ranges::rotate_copy(R&& r, iterator_t<R> middle, O result); // since C++20
+ template<random_access_iterator I, sentinel_for<I> S, class Gen>
+ requires permutable<I> &&
+ uniform_random_bit_generator<remove_reference_t<Gen>>
+ I shuffle(I first, S last, Gen&& g); // Since C++20
+
+ template<random_access_range R, class Gen>
+ requires permutable<iterator_t<R>> &&
+ uniform_random_bit_generator<remove_reference_t<Gen>>
+ borrowed_iterator_t<R> shuffle(R&& r, Gen&& g); // Since C++20
+
template<forward_iterator I1, sentinel_for<I1> S1, forward_iterator I2,
sentinel_for<I2> S2, class Pred = ranges::equal_to,
class Proj1 = identity, class Proj2 = identity>
@@ -711,7 +782,49 @@ namespace ranges {
borrowed_iterator_t<R2>, O>
set_symmetric_difference(R1&& r1, R2&& r2, O result, Comp comp = {},
Proj1 proj1 = {}, Proj2 proj2 = {}); // since C++20
+
+ template<forward_iterator I, sentinel_for<I> S, class T, class Proj = identity,
+ indirect_strict_weak_order<const T*, projected<I, Proj>> Comp = ranges::less>
+ constexpr subrange<I>
+ equal_range(I first, S last, const T& value, Comp comp = {}, Proj proj = {}); // since C++20
+
+ template<forward_range R, class T, class Proj = identity,
+ indirect_strict_weak_order<const T*, projected<iterator_t<R>, Proj>> Comp =
+ ranges::less>
+ constexpr borrowed_subrange_t<R>
+ equal_range(R&& r, const T& value, Comp comp = {}, Proj proj = {}); // since C++20
+
+ template<class I1, class I2, class O>
+ using set_union_result = in_in_out_result<I1, I2, O>; // since C++20
+
+ template<input_iterator I1, sentinel_for<I1> S1, input_iterator I2, sentinel_for<I2> S2,
+ weakly_incrementable O, class Comp = ranges::less,
+ class Proj1 = identity, class Proj2 = identity>
+ requires mergeable<I1, I2, O, Comp, Proj1, Proj2>
+ constexpr set_union_result<I1, I2, O>
+ set_union(I1 first1, S1 last1, I2 first2, S2 last2, O result, Comp comp = {},
+ Proj1 proj1 = {}, Proj2 proj2 = {}); // since C++20
+
+ template<input_range R1, input_range R2, weakly_incrementable O,
+ class Comp = ranges::less, class Proj1 = identity, class Proj2 = identity>
+ requires mergeable<iterator_t<R1>, iterator_t<R2>, O, Comp, Proj1, Proj2>
+ constexpr set_union_result<borrowed_iterator_t<R1>, borrowed_iterator_t<R2>, O>
+ set_union(R1&& r1, R2&& r2, O result, Comp comp = {},
+ Proj1 proj1 = {}, Proj2 proj2 = {}); // since C++20
+
+ template<input_iterator I1, sentinel_for<I1> S1, input_iterator I2, sentinel_for<I2> S2,
+ class Proj1 = identity, class Proj2 = identity,
+ indirect_strict_weak_order<projected<I1, Proj1>, projected<I2, Proj2>> Comp =
+ ranges::less>
+ constexpr bool includes(I1 first1, S1 last1, I2 first2, S2 last2, Comp comp = {},
+ Proj1 proj1 = {}, Proj2 proj2 = {}); // Since C++20
+ template<input_range R1, input_range R2, class Proj1 = identity,
+ class Proj2 = identity,
+ indirect_strict_weak_order<projected<iterator_t<R1>, Proj1>,
+ projected<iterator_t<R2>, Proj2>> Comp = ranges::less>
+ constexpr bool includes(R1&& r1, R2&& r2, Comp comp = {},
+ Proj1 proj1 = {}, Proj2 proj2 = {}); // Since C++20
}
constexpr bool // constexpr in C++20
@@ -1452,6 +1565,7 @@ template <class BidirectionalIterator, class Compare>
#include <__algorithm/ranges_count.h>
#include <__algorithm/ranges_count_if.h>
#include <__algorithm/ranges_equal.h>
+#include <__algorithm/ranges_equal_range.h>
#include <__algorithm/ranges_fill.h>
#include <__algorithm/ranges_fill_n.h>
#include <__algorithm/ranges_find.h>
@@ -1461,6 +1575,7 @@ template <class BidirectionalIterator, class Compare>
#include <__algorithm/ranges_find_if_not.h>
#include <__algorithm/ranges_for_each.h>
#include <__algorithm/ranges_for_each_n.h>
+#include <__algorithm/ranges_includes.h>
#include <__algorithm/ranges_is_partitioned.h>
#include <__algorithm/ranges_is_sorted.h>
#include <__algorithm/ranges_is_sorted_until.h>
@@ -1479,6 +1594,10 @@ template <class BidirectionalIterator, class Compare>
#include <__algorithm/ranges_move_backward.h>
#include <__algorithm/ranges_none_of.h>
#include <__algorithm/ranges_nth_element.h>
+#include <__algorithm/ranges_partial_sort.h>
+#include <__algorithm/ranges_partition.h>
+#include <__algorithm/ranges_partition_copy.h>
+#include <__algorithm/ranges_partition_point.h>
#include <__algorithm/ranges_pop_heap.h>
#include <__algorithm/ranges_push_heap.h>
#include <__algorithm/ranges_remove.h>
@@ -1493,8 +1612,11 @@ template <class BidirectionalIterator, class Compare>
#include <__algorithm/ranges_set_difference.h>
#include <__algorithm/ranges_set_intersection.h>
#include <__algorithm/ranges_set_symmetric_difference.h>
+#include <__algorithm/ranges_set_union.h>
+#include <__algorithm/ranges_shuffle.h>
#include <__algorithm/ranges_sort.h>
#include <__algorithm/ranges_sort_heap.h>
+#include <__algorithm/ranges_stable_partition.h>
#include <__algorithm/ranges_stable_sort.h>
#include <__algorithm/ranges_swap_ranges.h>
#include <__algorithm/ranges_transform.h>
diff --git a/libcxx/include/bit b/libcxx/include/bit
index fe1bcadc818a..15bc13a504b1 100644
--- a/libcxx/include/bit
+++ b/libcxx/include/bit
@@ -75,9 +75,6 @@ namespace std {
# include <iosfwd>
#endif
-#if defined(__IBMCPP__)
-# include "__support/ibm/support.h"
-#endif
#if defined(_LIBCPP_COMPILER_MSVC)
# include <intrin.h>
#endif
diff --git a/libcxx/include/format b/libcxx/include/format
index 60197d24523f..d2ec8fc23363 100644
--- a/libcxx/include/format
+++ b/libcxx/include/format
@@ -131,7 +131,7 @@ namespace std {
#include <__assert> // all public C++ headers provide the assertion handler
// Make sure all feature-test macros are available.
#include <version>
-// Enable the contents of the header only when libc++ was built with LIBCXX_ENABLE_INCOMPLETE_FEATURES.
+// Enable the contents of the header only when libc++ was built with experimental features enabled.
#if !defined(_LIBCPP_HAS_NO_INCOMPLETE_FORMAT)
#include <__algorithm/clamp.h>
@@ -157,6 +157,7 @@ namespace std {
#include <__format/formatter_pointer.h>
#include <__format/formatter_string.h>
#include <__format/parser_std_format_spec.h>
+#include <__format/unicode.h>
#include <__iterator/back_insert_iterator.h>
#include <__iterator/incrementable_traits.h>
#include <__variant/monostate.h>
diff --git a/libcxx/include/limits b/libcxx/include/limits
index 35e4d85734de..1fa3a8228fd8 100644
--- a/libcxx/include/limits
+++ b/libcxx/include/limits
@@ -110,10 +110,6 @@ template<> class numeric_limits<cv long double>;
#include "__support/win32/limits_msvc_win32.h"
#endif // _LIBCPP_MSVCRT
-#if defined(__IBMCPP__)
-#include "__support/ibm/limits.h"
-#endif // __IBMCPP__
-
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
#endif
diff --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in
index 25e1c6e6d0e2..cbf0b4f7f16d 100644
--- a/libcxx/include/module.modulemap.in
+++ b/libcxx/include/module.modulemap.in
@@ -337,6 +337,7 @@ module std [system] {
module ranges_is_partitioned { private header "__algorithm/ranges_is_partitioned.h" }
module ranges_is_sorted { private header "__algorithm/ranges_is_sorted.h" }
module ranges_is_sorted_until { private header "__algorithm/ranges_is_sorted_until.h" }
+ module ranges_iterator_concept { private header "__algorithm/ranges_iterator_concept.h" }
module ranges_lexicographical_compare { private header "__algorithm/ranges_lexicographical_compare.h" }
module ranges_lower_bound { private header "__algorithm/ranges_lower_bound.h" }
module ranges_make_heap { private header "__algorithm/ranges_make_heap.h" }
@@ -352,6 +353,7 @@ module std [system] {
module ranges_move_backward { private header "__algorithm/ranges_move_backward.h" }
module ranges_none_of { private header "__algorithm/ranges_none_of.h" }
module ranges_nth_element { private header "__algorithm/ranges_nth_element.h" }
+ module ranges_partial_sort { private header "__algorithm/ranges_partial_sort.h" }
module ranges_partial_sort_copy { private header "__algorithm/ranges_partial_sort_copy.h" }
module ranges_partition { private header "__algorithm/ranges_partition.h" }
module ranges_partition_copy { private header "__algorithm/ranges_partition_copy.h" }
@@ -614,32 +616,34 @@ module std [system] {
export *
module __format {
- module buffer { private header "__format/buffer.h" }
- module concepts { private header "__format/concepts.h" }
- module enable_insertable { private header "__format/enable_insertable.h" }
- module format_arg { private header "__format/format_arg.h" }
- module format_arg_store { private header "__format/format_arg_store.h" }
- module format_args { private header "__format/format_args.h" }
+ module buffer { private header "__format/buffer.h" }
+ module concepts { private header "__format/concepts.h" }
+ module enable_insertable { private header "__format/enable_insertable.h" }
+ module extended_grapheme_cluster_table { private header "__format/extended_grapheme_cluster_table.h" }
+ module format_arg { private header "__format/format_arg.h" }
+ module format_arg_store { private header "__format/format_arg_store.h" }
+ module format_args { private header "__format/format_args.h" }
module format_context {
private header "__format/format_context.h"
export optional
export locale
}
- module format_error { private header "__format/format_error.h" }
- module format_fwd { private header "__format/format_fwd.h" }
- module format_parse_context { private header "__format/format_parse_context.h" }
- module format_string { private header "__format/format_string.h" }
- module format_to_n_result { private header "__format/format_to_n_result.h" }
- module formatter { private header "__format/formatter.h" }
- module formatter_bool { private header "__format/formatter_bool.h" }
- module formatter_char { private header "__format/formatter_char.h" }
- module formatter_floating_point { private header "__format/formatter_floating_point.h" }
- module formatter_integer { private header "__format/formatter_integer.h" }
- module formatter_integral { private header "__format/formatter_integral.h" }
- module formatter_output { private header "__format/formatter_output.h" }
- module formatter_pointer { private header "__format/formatter_pointer.h" }
- module formatter_string { private header "__format/formatter_string.h" }
- module parser_std_format_spec { private header "__format/parser_std_format_spec.h" }
+ module format_error { private header "__format/format_error.h" }
+ module format_fwd { private header "__format/format_fwd.h" }
+ module format_parse_context { private header "__format/format_parse_context.h" }
+ module format_string { private header "__format/format_string.h" }
+ module format_to_n_result { private header "__format/format_to_n_result.h" }
+ module formatter { private header "__format/formatter.h" }
+ module formatter_bool { private header "__format/formatter_bool.h" }
+ module formatter_char { private header "__format/formatter_char.h" }
+ module formatter_floating_point { private header "__format/formatter_floating_point.h" }
+ module formatter_integer { private header "__format/formatter_integer.h" }
+ module formatter_integral { private header "__format/formatter_integral.h" }
+ module formatter_output { private header "__format/formatter_output.h" }
+ module formatter_pointer { private header "__format/formatter_pointer.h" }
+ module formatter_string { private header "__format/formatter_string.h" }
+ module parser_std_format_spec { private header "__format/parser_std_format_spec.h" }
+ module unicode { private header "__format/unicode.h" }
}
}
module forward_list {
diff --git a/libcxx/include/ostream b/libcxx/include/ostream
index 283774585b92..14b49d78cb03 100644
--- a/libcxx/include/ostream
+++ b/libcxx/include/ostream
@@ -130,6 +130,35 @@ template <class charT, class traits>
template <class Stream, class T>
Stream&& operator<<(Stream&& os, const T& x);
+template<class traits>
+basic_ostream<char, traits>& operator<<(basic_ostream<char, traits>&, wchar_t) = delete; // since C++20
+template<class traits>
+basic_ostream<char, traits>& operator<<(basic_ostream<char, traits>&, char8_t) = delete; // since C++20
+template<class traits>
+basic_ostream<char, traits>& operator<<(basic_ostream<char, traits>&, char16_t) = delete; // since C++20
+template<class traits>
+basic_ostream<char, traits>& operator<<(basic_ostream<char, traits>&, char32_t) = delete; // since C++20
+template<class traits>
+basic_ostream<wchar_t, traits>& operator<<(basic_ostream<wchar_t, traits>&, char8_t) = delete; // since C++20
+template<class traits>
+basic_ostream<wchar_t, traits>& operator<<(basic_ostream<wchar_t, traits>&, char16_t) = delete; // since C++20
+template<class traits>
+basic_ostream<wchar_t, traits>& operator<<(basic_ostream<wchar_t, traits>&, char32_t) = delete; // since C++20
+template<class traits>
+basic_ostream<char, traits>& operator<<(basic_ostream<char, traits>&, const wchar_t*) = delete; // since C++20
+template<class traits>
+basic_ostream<char, traits>& operator<<(basic_ostream<char, traits>&, const char8_t*) = delete; // since C++20
+template<class traits>
+basic_ostream<char, traits>& operator<<(basic_ostream<char, traits>&, const char16_t*) = delete; // since C++20
+template<class traits>
+basic_ostream<char, traits>& operator<<(basic_ostream<char, traits>&, const char32_t*) = delete; // since C++20
+template<class traits>
+basic_ostream<wchar_t, traits>& operator<<(basic_ostream<wchar_t, traits>&, const char8_t*) = delete; // since C++20
+template<class traits>
+basic_ostream<wchar_t, traits>& operator<<(basic_ostream<wchar_t, traits>&, const char16_t*) = delete; // since C++20
+template<class traits>
+basic_ostream<wchar_t, traits>& operator<<(basic_ostream<wchar_t, traits>&, const char32_t*) = delete; // since C++20
+
} // std
*/
@@ -225,9 +254,13 @@ public:
basic_ostream& operator<<(basic_streambuf<char_type, traits_type>* __sb);
+#if _LIBCPP_STD_VER > 14
+// LWG 2221 - nullptr. This is not backported to older standards modes.
+// See https://reviews.llvm.org/D127033 for more info on the rationale.
_LIBCPP_INLINE_VISIBILITY
basic_ostream& operator<<(nullptr_t)
{ return *this << "nullptr"; }
+#endif
// 27.7.2.7 Unformatted output:
basic_ostream& put(char_type __c);
@@ -1098,6 +1131,57 @@ operator<<(basic_ostream<_CharT, _Traits>& __os, const bitset<_Size>& __x)
use_facet<ctype<_CharT> >(__os.getloc()).widen('1'));
}
+#if _LIBCPP_STD_VER > 17
+
+#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
+template <class _Traits>
+basic_ostream<char, _Traits>& operator<<(basic_ostream<char, _Traits>&, wchar_t) = delete;
+
+template <class _Traits>
+basic_ostream<char, _Traits>& operator<<(basic_ostream<char, _Traits>&, const wchar_t*) = delete;
+
+template <class _Traits>
+basic_ostream<wchar_t, _Traits>& operator<<(basic_ostream<wchar_t, _Traits>&, char16_t) = delete;
+
+template <class _Traits>
+basic_ostream<wchar_t, _Traits>& operator<<(basic_ostream<wchar_t, _Traits>&, char32_t) = delete;
+
+template <class _Traits>
+basic_ostream<wchar_t, _Traits>& operator<<(basic_ostream<wchar_t, _Traits>&, const char16_t*) = delete;
+
+template <class _Traits>
+basic_ostream<wchar_t, _Traits>& operator<<(basic_ostream<wchar_t, _Traits>&, const char32_t*) = delete;
+
+#endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS
+
+#ifndef _LIBCPP_HAS_NO_CHAR8_T
+template <class _Traits>
+basic_ostream<char, _Traits>& operator<<(basic_ostream<char, _Traits>&, char8_t) = delete;
+
+template <class _Traits>
+basic_ostream<wchar_t, _Traits>& operator<<(basic_ostream<wchar_t, _Traits>&, char8_t) = delete;
+
+template <class _Traits>
+basic_ostream<char, _Traits>& operator<<(basic_ostream<char, _Traits>&, const char8_t*) = delete;
+
+template <class _Traits>
+basic_ostream<wchar_t, _Traits>& operator<<(basic_ostream<wchar_t, _Traits>&, const char8_t*) = delete;
+#endif
+
+template <class _Traits>
+basic_ostream<char, _Traits>& operator<<(basic_ostream<char, _Traits>&, char16_t) = delete;
+
+template <class _Traits>
+basic_ostream<char, _Traits>& operator<<(basic_ostream<char, _Traits>&, char32_t) = delete;
+
+template <class _Traits>
+basic_ostream<char, _Traits>& operator<<(basic_ostream<char, _Traits>&, const char16_t*) = delete;
+
+template <class _Traits>
+basic_ostream<char, _Traits>& operator<<(basic_ostream<char, _Traits>&, const char32_t*) = delete;
+
+#endif // _LIBCPP_STD_VER > 17
+
extern template class _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS basic_ostream<char>;
#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
extern template class _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS basic_ostream<wchar_t>;
diff --git a/libcxx/include/version b/libcxx/include/version
index 2034e4b1f3d9..1df51fa1cb86 100644
--- a/libcxx/include/version
+++ b/libcxx/include/version
@@ -47,7 +47,7 @@ __cpp_lib_bounded_array_traits 201902L <type_traits>
__cpp_lib_boyer_moore_searcher 201603L <functional>
__cpp_lib_byte 201603L <cstddef>
__cpp_lib_byteswap 202110L <bit>
-__cpp_lib_char8_t 201811L <atomic> <filesystem> <istream>
+__cpp_lib_char8_t 201907L <atomic> <filesystem> <istream>
<limits> <locale> <ostream>
<string> <string_view>
__cpp_lib_chrono 201611L <chrono>
@@ -308,7 +308,7 @@ __cpp_lib_void_t 201411L <type_traits>
// # define __cpp_lib_bitops 201907L
# define __cpp_lib_bounded_array_traits 201902L
# if !defined(_LIBCPP_HAS_NO_CHAR8_T)
-# define __cpp_lib_char8_t 201811L
+# define __cpp_lib_char8_t 201907L
# endif
# define __cpp_lib_concepts 202002L
# define __cpp_lib_constexpr_algorithms 201806L