[libc++][ranges] Finish LWG issues directly related to the One Ranges Proposal.
- P1252 ("Ranges Design Cleanup") -- deprecate `move_iterator::operator->` starting from C++20; add range comparisons to the `<functional>` synopsis. This restores `move_iterator::operator->` that was incorrectly deleted in D117656; it's still defined in the latest draft, see http://eel.is/c++draft/depr.move.iter.elem. Note that changes to `*_result` types from 6.1 in the paper are no longer relevant now that these types are aliases; - P2106 ("Alternative wording for GB315 and GB316") -- add a few `*_result` types to the synopsis in `<algorithm>` (some algorithms are not implemented yet and thus some of the proposal still cannot be marked as done); Also mark already done issues as done (or as nothing to do): - P2091 ("Fixing Issues With Range Access CPOs") was already implemented (this patch adds tests for some ill-formed cases); - LWG 3247 ("`ranges::iter_move` should perform ADL-only lookup of `iter_move`") was already implemented; - LWG 3300 ("Non-array ssize overload is underconstrained") doesn't affect the implementation; - LWG 3335 ("Resolve C++20 NB comments US 273 and GB 274") was already implemented; - LWG 3355 ("The memory algorithms should support move-only input iterators introduced by P1207") was already implemented (except for testing). Differential Revision: https://reviews.llvm.org/D126053
This commit is contained in:
parent
f7bf9d13d5
commit
79a2b4ba98
|
@ -205,7 +205,7 @@
|
|||
"`3238 <https://wg21.link/LWG3238>`__","Insufficiently-defined behavior of ``std::function``\ deduction guides","Prague","",""
|
||||
"`3242 <https://wg21.link/LWG3242>`__","``std::format``\ : missing rules for ``arg-id``\ in ``width``\ and ``precision``\ ","Prague","|Complete|","Clang 14","|format|"
|
||||
"`3243 <https://wg21.link/LWG3243>`__","``std::format``\ and negative zeroes","Prague","|Complete|","14.0","|format|"
|
||||
"`3247 <https://wg21.link/LWG3247>`__","``ranges::iter_move``\ should perform ADL-only lookup of ``iter_move``\ ","Prague","","","|ranges|"
|
||||
"`3247 <https://wg21.link/LWG3247>`__","``ranges::iter_move``\ should perform ADL-only lookup of ``iter_move``\ ","Prague","|Complete|","15.0","|ranges|"
|
||||
"`3248 <https://wg21.link/LWG3248>`__","``std::format``\ ``#b``\ , ``#B``\ , ``#o``\ , ``#x``\ , and ``#X``\ presentation types misformat negative numbers","Prague","|Complete|","14.0","|format|"
|
||||
"`3250 <https://wg21.link/LWG3250>`__","``std::format``\ : ``#``\ (alternate form) for NaN and inf","Prague","|Complete|","14.0","|format|"
|
||||
"`3251 <https://wg21.link/LWG3251>`__","Are ``std::format``\ alignment specifiers applied to string arguments?","Prague","|Complete|","14.0","|format|"
|
||||
|
@ -228,7 +228,7 @@
|
|||
"`3294 <https://wg21.link/LWG3294>`__","``zoned_time``\ deduction guides misinterprets ``string``\ /``char*``\ ","Prague","","","|chrono|"
|
||||
"`3296 <https://wg21.link/LWG3296>`__","Inconsistent default argument for ``basic_regex<>::assign``\ ","Prague","|Complete|",""
|
||||
"`3299 <https://wg21.link/LWG3299>`__","Pointers don't need customized iterator behavior","Prague","|Complete|","15.0","|ranges|"
|
||||
"`3300 <https://wg21.link/LWG3300>`__","Non-array ``ssize``\ overload is underconstrained","Prague","",""
|
||||
"`3300 <https://wg21.link/LWG3300>`__","Non-array ``ssize``\ overload is underconstrained","Prague","|Nothing To Do|",""
|
||||
"`3301 <https://wg21.link/LWG3301>`__","``transform_view::iterator``\ has incorrect ``iterator_category``\ ","Prague","|Complete|","15.0","|ranges|"
|
||||
"`3302 <https://wg21.link/LWG3302>`__","Range adaptor objects ``keys``\ and ``values``\ are unspecified","Prague","","","|ranges|"
|
||||
"`3303 <https://wg21.link/LWG3303>`__","Bad ""``constexpr``\ "" marker for ``destroy/destroy_n``\ ","Prague","",""
|
||||
|
@ -255,7 +255,7 @@
|
|||
"`3331 <https://wg21.link/LWG3331>`__","Define ``totally_ordered/_with``\ in terms of ``partially-ordered-with``\ ","Prague","|Complete|","13.0"
|
||||
"`3332 <https://wg21.link/LWG3332>`__","Issue in |sect|\ [time.format]","Prague","","","|chrono| |format|"
|
||||
"`3334 <https://wg21.link/LWG3334>`__","``basic_osyncstream``\ move assignment and destruction calls ``basic_syncbuf::emit()``\ twice","Prague","",""
|
||||
"`3335 <https://wg21.link/LWG3335>`__","Resolve C++20 NB comments US 273 and GB 274","Prague","","","|ranges|"
|
||||
"`3335 <https://wg21.link/LWG3335>`__","Resolve C++20 NB comments US 273 and GB 274","Prague","|Complete|","15.0","|ranges|"
|
||||
"`3338 <https://wg21.link/LWG3338>`__","Rename ``default_constructible``\ to ``default_initializable``\ ","Prague","|Complete|","13.0"
|
||||
"`3340 <https://wg21.link/LWG3340>`__","Formatting functions should throw on argument/format string mismatch in |sect|\ [format.functions]","Prague","|Complete|","14.0","|format|"
|
||||
"`3346 <https://wg21.link/LWG3346>`__","``pair``\ and ``tuple``\ copy and move constructor have backwards specification","Prague","",""
|
||||
|
@ -266,7 +266,7 @@
|
|||
"`3351 <https://wg21.link/LWG3351>`__","``ranges::enable_safe_range``\ should not be constrained","Prague","|Complete|","15.0","|ranges|"
|
||||
"`3352 <https://wg21.link/LWG3352>`__","``strong_equality``\ isn't a thing","Prague","|Nothing To Do|","","|spaceship|"
|
||||
"`3354 <https://wg21.link/LWG3354>`__","``has_strong_structural_equality``\ has a meaningless definition","Prague","|Nothing To Do|","","|spaceship|"
|
||||
"`3355 <https://wg21.link/LWG3355>`__","The memory algorithms should support move-only input iterators introduced by P1207","Prague","","","|ranges|"
|
||||
"`3355 <https://wg21.link/LWG3355>`__","The memory algorithms should support move-only input iterators introduced by P1207","Prague","|Complete|","15.0","|ranges|"
|
||||
"`3356 <https://wg21.link/LWG3356>`__","``__cpp_lib_nothrow_convertible``\ should be ``__cpp_lib_is_nothrow_convertible``\ ","Prague","|Complete|","12.0"
|
||||
"`3358 <https://wg21.link/LWG3358>`__","|sect|\ [span.cons] is mistaken that ``to_address``\ can throw","Prague","",""
|
||||
"`3359 <https://wg21.link/LWG3359>`__","``<chrono>``\ leap second support should allow for negative leap seconds","Prague","","","|chrono|"
|
||||
|
|
Can't render this file because it has a wrong number of fields in line 2.
|
|
@ -187,7 +187,7 @@
|
|||
"`P2002R1 <https://wg21.link/P2002R1>`__","CWG","Defaulted comparison specification cleanups","Prague","* *",""
|
||||
"`P2045R1 <https://wg21.link/P2045R1>`__","LWG","Missing Mandates for the standard library","Prague","* *",""
|
||||
"`P2085R0 <https://wg21.link/P2085R0>`__","CWG","Consistent defaulted comparisons","Prague","* *",""
|
||||
"`P2091R0 <https://wg21.link/P2091R0>`__","LWG","Issues with range access CPOs","Prague","* *",""
|
||||
"`P2091R0 <https://wg21.link/P2091R0>`__","LWG","Issues with range access CPOs","Prague","|Complete|","15.0"
|
||||
"`P2101R0 <https://wg21.link/P2101R0>`__","LWG","'Models' subsumes 'satisfies' (Wording for US298 and US300)","Prague","* *",""
|
||||
"`P2102R0 <https://wg21.link/P2102R0>`__","LWG","Make 'implicit expression variations' more explicit (Wording for US185)","Prague","* *",""
|
||||
"`P2106R0 <https://wg21.link/P2106R0>`__","LWG","Alternative wording for GB315 and GB316","Prague","* *",""
|
||||
|
|
|
|
@ -20,7 +20,7 @@
|
|||
`P1970R2 <https://wg21.link/P1970R2>`__,Consistency for size() functions: Add ranges::ssize,|Complete|,15.0
|
||||
`P1983R0 <https://wg21.link/P1983R0>`__,"Wording for GB301, US296, US292, US291, and US283",|Complete|,15.0
|
||||
`P1994R1 <https://wg21.link/P1994R1>`__,elements_view Needs Its Own sentinel,,
|
||||
`P2091R0 <https://wg21.link/P2091R0>`__,Fixing Issues With Range Access CPOs,,
|
||||
`P2091R0 <https://wg21.link/P2091R0>`__,Fixing Issues With Range Access CPOs,|Complete|,15.0
|
||||
`P2106R0 <https://wg21.link/P2106R0>`__,Range Algorithm Result Types,,
|
||||
|
||||
`P2325R3 <https://wg21.link/P2325R3>`__,Views should not be required to be default constructible ,,
|
||||
|
|
|
|
@ -93,6 +93,9 @@ public:
|
|||
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX14
|
||||
move_iterator& operator++() { ++__current_; return *this; }
|
||||
|
||||
_LIBCPP_DEPRECATED_IN_CXX20 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX14
|
||||
pointer operator->() const { return __current_; }
|
||||
|
||||
#if _LIBCPP_STD_VER > 17
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr
|
||||
move_iterator() requires is_constructible_v<_Iter> : __current_() {}
|
||||
|
@ -156,8 +159,6 @@ public:
|
|||
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX14
|
||||
reference operator*() const { return static_cast<reference>(*__current_); }
|
||||
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX14
|
||||
pointer operator->() const { return __current_; }
|
||||
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX14
|
||||
reference operator[](difference_type __n) const { return static_cast<reference>(__current_[__n]); }
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX14
|
||||
|
|
|
@ -35,68 +35,76 @@ namespace ranges {
|
|||
|
||||
namespace ranges {
|
||||
namespace __size {
|
||||
void size(auto&) = delete;
|
||||
void size(const auto&) = delete;
|
||||
void size(auto&) = delete;
|
||||
void size(const auto&) = delete;
|
||||
|
||||
template <class _Tp>
|
||||
concept __size_enabled = !disable_sized_range<remove_cvref_t<_Tp>>;
|
||||
template <class _Tp>
|
||||
concept __size_enabled = !disable_sized_range<remove_cvref_t<_Tp>>;
|
||||
|
||||
template <class _Tp>
|
||||
concept __member_size =
|
||||
__size_enabled<_Tp> &&
|
||||
__workaround_52970<_Tp> &&
|
||||
requires(_Tp&& __t) {
|
||||
{ _LIBCPP_AUTO_CAST(__t.size()) } -> __integer_like;
|
||||
};
|
||||
|
||||
template <class _Tp>
|
||||
concept __unqualified_size =
|
||||
__size_enabled<_Tp> &&
|
||||
!__member_size<_Tp> &&
|
||||
__class_or_enum<remove_cvref_t<_Tp>> &&
|
||||
requires(_Tp&& __t) {
|
||||
{ _LIBCPP_AUTO_CAST(size(__t)) } -> __integer_like;
|
||||
};
|
||||
|
||||
template <class _Tp>
|
||||
concept __difference =
|
||||
!__member_size<_Tp> &&
|
||||
!__unqualified_size<_Tp> &&
|
||||
__class_or_enum<remove_cvref_t<_Tp>> &&
|
||||
requires(_Tp&& __t) {
|
||||
{ ranges::begin(__t) } -> forward_iterator;
|
||||
{ ranges::end(__t) } -> sized_sentinel_for<decltype(ranges::begin(declval<_Tp>()))>;
|
||||
};
|
||||
|
||||
struct __fn {
|
||||
template <class _Tp, size_t _Sz>
|
||||
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr size_t operator()(_Tp (&&)[_Sz]) const noexcept {
|
||||
return _Sz;
|
||||
}
|
||||
|
||||
template <class _Tp, size_t _Sz>
|
||||
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr size_t operator()(_Tp (&)[_Sz]) const noexcept {
|
||||
return _Sz;
|
||||
}
|
||||
|
||||
template <__member_size _Tp>
|
||||
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr __integer_like auto operator()(_Tp&& __t) const
|
||||
noexcept(noexcept(_LIBCPP_AUTO_CAST(__t.size()))) {
|
||||
return _LIBCPP_AUTO_CAST(__t.size());
|
||||
}
|
||||
|
||||
template <__unqualified_size _Tp>
|
||||
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr __integer_like auto operator()(_Tp&& __t) const
|
||||
noexcept(noexcept(_LIBCPP_AUTO_CAST(size(__t)))) {
|
||||
return _LIBCPP_AUTO_CAST(size(__t));
|
||||
}
|
||||
|
||||
template<__difference _Tp>
|
||||
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr __integer_like auto operator()(_Tp&& __t) const
|
||||
noexcept(noexcept(ranges::end(__t) - ranges::begin(__t))) {
|
||||
return std::__to_unsigned_like(ranges::end(__t) - ranges::begin(__t));
|
||||
}
|
||||
template <class _Tp>
|
||||
concept __member_size =
|
||||
__size_enabled<_Tp> &&
|
||||
__workaround_52970<_Tp> &&
|
||||
requires(_Tp&& __t) {
|
||||
{ _LIBCPP_AUTO_CAST(__t.size()) } -> __integer_like;
|
||||
};
|
||||
|
||||
template <class _Tp>
|
||||
concept __unqualified_size =
|
||||
__size_enabled<_Tp> &&
|
||||
!__member_size<_Tp> &&
|
||||
__class_or_enum<remove_cvref_t<_Tp>> &&
|
||||
requires(_Tp&& __t) {
|
||||
{ _LIBCPP_AUTO_CAST(size(__t)) } -> __integer_like;
|
||||
};
|
||||
|
||||
template <class _Tp>
|
||||
concept __difference =
|
||||
!__member_size<_Tp> &&
|
||||
!__unqualified_size<_Tp> &&
|
||||
__class_or_enum<remove_cvref_t<_Tp>> &&
|
||||
requires(_Tp&& __t) {
|
||||
{ ranges::begin(__t) } -> forward_iterator;
|
||||
{ ranges::end(__t) } -> sized_sentinel_for<decltype(ranges::begin(declval<_Tp>()))>;
|
||||
};
|
||||
|
||||
struct __fn {
|
||||
|
||||
// `[range.prim.size]`: the array case (for rvalues).
|
||||
template <class _Tp, size_t _Sz>
|
||||
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr size_t operator()(_Tp (&&)[_Sz]) const noexcept {
|
||||
return _Sz;
|
||||
}
|
||||
|
||||
// `[range.prim.size]`: the array case (for lvalues).
|
||||
template <class _Tp, size_t _Sz>
|
||||
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr size_t operator()(_Tp (&)[_Sz]) const noexcept {
|
||||
return _Sz;
|
||||
}
|
||||
|
||||
// `[range.prim.size]`: `auto(t.size())` is a valid expression.
|
||||
template <__member_size _Tp>
|
||||
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr __integer_like auto operator()(_Tp&& __t) const
|
||||
noexcept(noexcept(_LIBCPP_AUTO_CAST(__t.size()))) {
|
||||
return _LIBCPP_AUTO_CAST(__t.size());
|
||||
}
|
||||
|
||||
// `[range.prim.size]`: `auto(size(t))` is a valid expression.
|
||||
template <__unqualified_size _Tp>
|
||||
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr __integer_like auto operator()(_Tp&& __t) const
|
||||
noexcept(noexcept(_LIBCPP_AUTO_CAST(size(__t)))) {
|
||||
return _LIBCPP_AUTO_CAST(size(__t));
|
||||
}
|
||||
|
||||
// [range.prim.size]: the `to-unsigned-like` case.
|
||||
template <__difference _Tp>
|
||||
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Tp&& __t) const
|
||||
noexcept(noexcept(std::__to_unsigned_like(ranges::end(__t) - ranges::begin(__t))))
|
||||
-> decltype( std::__to_unsigned_like(ranges::end(__t) - ranges::begin(__t)))
|
||||
{ return std::__to_unsigned_like(ranges::end(__t) - ranges::begin(__t));
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace __size
|
||||
|
||||
inline namespace __cpo {
|
||||
|
@ -108,19 +116,18 @@ inline namespace __cpo {
|
|||
|
||||
namespace ranges {
|
||||
namespace __ssize {
|
||||
struct __fn {
|
||||
template<class _Tp>
|
||||
requires requires (_Tp&& __t) { ranges::size(__t); }
|
||||
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr integral auto operator()(_Tp&& __t) const
|
||||
noexcept(noexcept(ranges::size(__t)))
|
||||
{
|
||||
using _Signed = make_signed_t<decltype(ranges::size(__t))>;
|
||||
if constexpr (sizeof(ptrdiff_t) > sizeof(_Signed))
|
||||
return static_cast<ptrdiff_t>(ranges::size(__t));
|
||||
else
|
||||
return static_cast<_Signed>(ranges::size(__t));
|
||||
}
|
||||
};
|
||||
struct __fn {
|
||||
template<class _Tp>
|
||||
requires requires (_Tp&& __t) { ranges::size(__t); }
|
||||
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr integral auto operator()(_Tp&& __t) const
|
||||
noexcept(noexcept(ranges::size(__t))) {
|
||||
using _Signed = make_signed_t<decltype(ranges::size(__t))>;
|
||||
if constexpr (sizeof(ptrdiff_t) > sizeof(_Signed))
|
||||
return static_cast<ptrdiff_t>(ranges::size(__t));
|
||||
else
|
||||
return static_cast<_Signed>(ranges::size(__t));
|
||||
}
|
||||
};
|
||||
} // namespace __ssize
|
||||
|
||||
inline namespace __cpo {
|
||||
|
|
|
@ -19,12 +19,17 @@ namespace std
|
|||
{
|
||||
|
||||
namespace ranges {
|
||||
|
||||
// [algorithms.results], algorithm result types
|
||||
template <class I, class F>
|
||||
struct in_fun_result; // since C++20
|
||||
|
||||
template <class I1, class I2>
|
||||
struct in_in_result; // since C++20
|
||||
|
||||
template <class I, class O>
|
||||
struct in_out_result; // since C++20
|
||||
|
||||
template <class I1, class I2, class O>
|
||||
struct in_in_out_result; // since C++20
|
||||
|
||||
|
@ -53,6 +58,9 @@ namespace ranges {
|
|||
indirect_strict_weak_order<projected<iterator_t<R>, Proj>> Comp = ranges::less>
|
||||
constexpr borrowed_iterator_t<R> ranges::max_element(R&& r, Comp comp = {}, Proj proj = {}); // since C++20
|
||||
|
||||
template<class I1, class I2>
|
||||
using mismatch_result = in_in_result<I1, I2>;
|
||||
|
||||
template <input_iterator I1, sentinel_for<_I1> S1, input_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>
|
||||
|
@ -174,6 +182,9 @@ namespace ranges {
|
|||
constexpr range_difference_t<R>
|
||||
count_if(R&& r, Pred pred, Proj proj = {}); // since C++20
|
||||
|
||||
template<class T>
|
||||
using minmax_result = min_max_result<T>;
|
||||
|
||||
template<class T, class Proj = identity,
|
||||
indirect_strict_weak_order<projected<const T*, Proj>> Comp = ranges::less>
|
||||
constexpr ranges::minmax_result<const T&>
|
||||
|
@ -190,6 +201,9 @@ namespace ranges {
|
|||
constexpr ranges::minmax_result<range_value_t<R>>
|
||||
minmax(R&& r, Comp comp = {}, Proj proj = {}); // since C++20
|
||||
|
||||
template<class I>
|
||||
using minmax_element_result = min_max_result<I>;
|
||||
|
||||
template<forward_iterator I, sentinel_for<I> S, class Proj = identity,
|
||||
indirect_strict_weak_order<projected<I, Proj>> Comp = ranges::less>
|
||||
constexpr ranges::minmax_element_result<I>
|
||||
|
@ -201,10 +215,10 @@ namespace ranges {
|
|||
minmax_element(R&& r, Comp comp = {}, Proj proj = {}); // since C++20
|
||||
|
||||
template<class I, class O>
|
||||
using copy_result = in_out_result<I, O>; // since C++20
|
||||
using copy_result = in_out_result<I, O>; // since C++20
|
||||
|
||||
template<class I, class O>
|
||||
using copy_n_result = in_out_result<I, O>; // since C++20
|
||||
template<class I, class O>
|
||||
using copy_n_result = in_out_result<I, O>; // since C++20
|
||||
|
||||
template<class I, class O>
|
||||
using copy_if_result = in_out_result<I, O>; // since C++20
|
||||
|
@ -638,19 +652,34 @@ template <class BidirectionalIterator1, class BidirectionalIterator2>
|
|||
copy_backward(BidirectionalIterator1 first, BidirectionalIterator1 last,
|
||||
BidirectionalIterator2 result);
|
||||
|
||||
// [alg.move], move
|
||||
template<class InputIterator, class OutputIterator>
|
||||
constexpr OutputIterator move(InputIterator first, InputIterator last,
|
||||
OutputIterator result);
|
||||
|
||||
template<class BidirectionalIterator1, class BidirectionalIterator2>
|
||||
constexpr BidirectionalIterator2
|
||||
move_backward(BidirectionalIterator1 first, BidirectionalIterator1 last,
|
||||
BidirectionalIterator2 result);
|
||||
|
||||
template <class ForwardIterator1, class ForwardIterator2>
|
||||
constexpr ForwardIterator2 // constexpr in C++20
|
||||
swap_ranges(ForwardIterator1 first1, ForwardIterator1 last1, ForwardIterator2 first2);
|
||||
|
||||
namespace ranges {
|
||||
template<class I1, class I2>
|
||||
using swap_ranges_result = in_in_result<I1, I2>;
|
||||
|
||||
template<input_iterator I1, sentinel_for<I1> S1, input_iterator I2, sentinel_for<I2> S2>
|
||||
requires indirectly_swappable<I1, I2>
|
||||
constexpr ranges::swap_ranges_result<I1, I2>
|
||||
ranges::swap_ranges(I1 first1, S1 last1, I2 first2, S2 last2);
|
||||
swap_ranges(I1 first1, S1 last1, I2 first2, S2 last2);
|
||||
|
||||
template<input_range R1, input_range R2>
|
||||
requires indirectly_swappable<iterator_t<R1>, iterator_t<R2>>
|
||||
constexpr ranges::swap_ranges_result<borrowed_iterator_t<R1>, borrowed_iterator_t<R2>>
|
||||
ranges::swap_ranges(R1&& r1, R2&& r2);
|
||||
swap_ranges(R1&& r1, R2&& r2);
|
||||
}
|
||||
|
||||
template <class ForwardIterator1, class ForwardIterator2>
|
||||
constexpr void // constexpr in C++20
|
||||
|
|
|
@ -482,6 +482,16 @@ template <> struct hash<long double>;
|
|||
template<class T> struct hash<T*>;
|
||||
template <> struct hash<nullptr_t>; // C++17
|
||||
|
||||
namespace ranges {
|
||||
// [range.cmp], concept-constrained comparisons
|
||||
struct equal_to;
|
||||
struct not_equal_to;
|
||||
struct greater;
|
||||
struct less;
|
||||
struct greater_equal;
|
||||
struct less_equal;
|
||||
}
|
||||
|
||||
} // std
|
||||
|
||||
POLICY: For non-variadic implementations, the number of arguments is limited
|
||||
|
|
|
@ -406,7 +406,7 @@ public:
|
|||
constexpr Iterator base() &&; // From C++20
|
||||
|
||||
constexpr reference operator*() const;
|
||||
constexpr pointer operator->() const; // Removed in C++20
|
||||
constexpr pointer operator->() const; // Deprecated in C++20
|
||||
constexpr move_iterator& operator++();
|
||||
constexpr auto operator++(int); // Return type was move_iterator until C++20
|
||||
constexpr move_iterator& operator--();
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17
|
||||
|
||||
// move_iterator
|
||||
|
||||
#include <iterator>
|
||||
|
||||
int main(int, char**) {
|
||||
(void)std::move_iterator<int*>().operator->();
|
||||
// expected-warning@-1{{'operator->' is deprecated}}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -6,6 +6,8 @@
|
|||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_DISABLE_DEPRECATION_WARNINGS
|
||||
|
||||
// <iterator>
|
||||
|
||||
// move_iterator
|
||||
|
@ -13,32 +15,21 @@
|
|||
// pointer operator->() const;
|
||||
//
|
||||
// constexpr in C++17
|
||||
// removed in C++20
|
||||
// deprecated in C++20
|
||||
|
||||
#include <iterator>
|
||||
#include <cassert>
|
||||
|
||||
#include "test_macros.h"
|
||||
|
||||
#if TEST_STD_VER > 17
|
||||
template <class T>
|
||||
concept HasArrow = requires (T t) {
|
||||
t.operator->();
|
||||
};
|
||||
static_assert(!HasArrow<std::move_iterator<int*>>);
|
||||
static_assert(!HasArrow<std::move_iterator<int*>&>);
|
||||
static_assert(!HasArrow<std::move_iterator<int*>&&>);
|
||||
#endif // TEST_STD_VER > 17
|
||||
|
||||
TEST_CONSTEXPR_CXX17 bool test()
|
||||
{
|
||||
#if TEST_STD_VER <= 17
|
||||
char a[] = "123456789";
|
||||
std::move_iterator<char *> it1 = std::make_move_iterator(a);
|
||||
std::move_iterator<char *> it2 = std::make_move_iterator(a + 1);
|
||||
assert(it1.operator->() == a);
|
||||
assert(it2.operator->() == a + 1);
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17
|
||||
// UNSUPPORTED: libcpp-has-no-incomplete-ranges
|
||||
|
||||
// std::ranges::begin
|
||||
|
||||
#include <ranges>
|
||||
|
||||
struct NonBorrowedRange {
|
||||
int* begin() const;
|
||||
int* end() const;
|
||||
};
|
||||
static_assert(!std::ranges::enable_borrowed_range<NonBorrowedRange>);
|
||||
|
||||
// Verify that if the expression is an rvalue and `enable_borrowed_range` is false, `ranges::begin` is ill-formed.
|
||||
void test() {
|
||||
std::ranges::begin(NonBorrowedRange());
|
||||
// expected-error-re@-1 {{{{call to deleted function call operator in type 'const (std::ranges::)?__begin::__fn'}}}}
|
||||
// expected-error@-2 {{attempt to use a deleted function}}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17
|
||||
// UNSUPPORTED: libcpp-has-no-incomplete-ranges
|
||||
|
||||
// std::ranges::data
|
||||
|
||||
#include <ranges>
|
||||
|
||||
struct NonBorrowedRange {
|
||||
int* begin() const;
|
||||
int* end() const;
|
||||
};
|
||||
static_assert(!std::ranges::enable_borrowed_range<NonBorrowedRange>);
|
||||
|
||||
// Verify that if the expression is an rvalue and `enable_borrowed_range` is false, `ranges::data` is ill-formed.
|
||||
void test() {
|
||||
std::ranges::data(NonBorrowedRange());
|
||||
// expected-error-re@-1 {{{{no matching function for call to object of type 'const (std::ranges::)?__data::__fn'}}}}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17
|
||||
// UNSUPPORTED: libcpp-has-no-incomplete-ranges
|
||||
|
||||
// std::ranges::empty
|
||||
|
||||
#include <ranges>
|
||||
|
||||
extern int arr[];
|
||||
|
||||
// Verify that for an array of unknown bound `ranges::empty` is ill-formed.
|
||||
void test() {
|
||||
std::ranges::empty(arr);
|
||||
// expected-error-re@-1 {{{{no matching function for call to object of type 'const (std::ranges::)?__empty::__fn'}}}}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17
|
||||
// UNSUPPORTED: libcpp-has-no-incomplete-ranges
|
||||
|
||||
// std::ranges::end
|
||||
|
||||
#include <ranges>
|
||||
|
||||
struct NonBorrowedRange {
|
||||
int* begin() const;
|
||||
int* end() const;
|
||||
};
|
||||
static_assert(!std::ranges::enable_borrowed_range<NonBorrowedRange>);
|
||||
|
||||
// Verify that if the expression is an rvalue and `enable_borrowed_range` is false, `ranges::end` is ill-formed.
|
||||
void test() {
|
||||
std::ranges::end(NonBorrowedRange());
|
||||
// expected-error-re@-1 {{{{call to deleted function call operator in type 'const (std::ranges::)?__end::__fn'}}}}
|
||||
// expected-error@-2 {{attempt to use a deleted function}}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17
|
||||
// UNSUPPORTED: libcpp-has-no-incomplete-ranges
|
||||
|
||||
// std::ranges::rbegin
|
||||
|
||||
#include <ranges>
|
||||
|
||||
struct NonBorrowedRange {
|
||||
int* begin() const;
|
||||
int* end() const;
|
||||
};
|
||||
static_assert(!std::ranges::enable_borrowed_range<NonBorrowedRange>);
|
||||
|
||||
// Verify that if the expression is an rvalue and `enable_borrowed_range` is false, `ranges::rbegin` is ill-formed.
|
||||
void test() {
|
||||
std::ranges::rbegin(NonBorrowedRange());
|
||||
// expected-error-re@-1 {{{{call to deleted function call operator in type 'const (std::ranges::)?__rbegin::__fn'}}}}
|
||||
// expected-error@-2 {{attempt to use a deleted function}}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17
|
||||
// UNSUPPORTED: libcpp-has-no-incomplete-ranges
|
||||
|
||||
// std::ranges::rend
|
||||
|
||||
#include <ranges>
|
||||
|
||||
struct NonBorrowedRange {
|
||||
int* begin() const;
|
||||
int* end() const;
|
||||
};
|
||||
static_assert(!std::ranges::enable_borrowed_range<NonBorrowedRange>);
|
||||
|
||||
// Verify that if the expression is an rvalue and `enable_borrowed_range` is false, `ranges::rend` is ill-formed.
|
||||
void test() {
|
||||
std::ranges::rend(NonBorrowedRange());
|
||||
// expected-error-re@-1 {{{{call to deleted function call operator in type 'const (std::ranges::)?__rend::__fn'}}}}
|
||||
// expected-error@-2 {{attempt to use a deleted function}}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17
|
||||
// UNSUPPORTED: libcpp-has-no-incomplete-ranges
|
||||
|
||||
// std::ranges::size
|
||||
|
||||
#include <ranges>
|
||||
|
||||
extern int arr[];
|
||||
|
||||
// Verify that for an array of unknown bound `ranges::size` is ill-formed.
|
||||
void test() {
|
||||
std::ranges::size(arr);
|
||||
// expected-error-re@-1 {{{{no matching function for call to object of type 'const (std::ranges::)?__size::__fn'}}}}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17
|
||||
// UNSUPPORTED: libcpp-has-no-incomplete-ranges
|
||||
|
||||
// std::ranges::size
|
||||
|
||||
#include <ranges>
|
||||
|
||||
extern int arr[];
|
||||
|
||||
// Verify that for an array of unknown bound `ranges::ssize` is ill-formed.
|
||||
void test() {
|
||||
std::ranges::ssize(arr);
|
||||
// expected-error-re@-1 {{{{no matching function for call to object of type 'const (std::ranges::)?__ssize::__fn'}}}}
|
||||
}
|
|
@ -370,5 +370,32 @@ int main(int, char**) {
|
|||
assert(result.out == out.end());
|
||||
}
|
||||
|
||||
// Move-only iterators are supported.
|
||||
{
|
||||
using MoveOnlyIter = cpp20_input_iterator<const int*>;
|
||||
static_assert(!std::is_copy_constructible_v<MoveOnlyIter>);
|
||||
|
||||
constexpr int N = 3;
|
||||
struct MoveOnlyRange {
|
||||
int buffer[N] = {1, 2, 3};
|
||||
auto begin() const { return MoveOnlyIter(buffer); }
|
||||
auto end() const { return sentinel_wrapper<MoveOnlyIter>(MoveOnlyIter(buffer)); }
|
||||
};
|
||||
static_assert(std::ranges::input_range<MoveOnlyRange>);
|
||||
MoveOnlyRange in;
|
||||
|
||||
// (iter, sentinel) overload.
|
||||
{
|
||||
Buffer<int, N> out;
|
||||
std::ranges::uninitialized_copy(in.begin(), in.end(), out.begin(), out.end());
|
||||
}
|
||||
|
||||
// (range) overload.
|
||||
{
|
||||
Buffer<int, N> out;
|
||||
std::ranges::uninitialized_copy(in, out);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include <memory>
|
||||
#include <ranges>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include "../buffer.h"
|
||||
#include "../counted.h"
|
||||
|
@ -148,5 +149,18 @@ int main(int, char**) {
|
|||
assert(result.out == out.end());
|
||||
}
|
||||
|
||||
// Move-only iterators are supported.
|
||||
{
|
||||
using MoveOnlyIter = cpp20_input_iterator<const int*>;
|
||||
static_assert(!std::is_copy_constructible_v<MoveOnlyIter>);
|
||||
|
||||
constexpr int N = 3;
|
||||
int buffer[N] = {1, 2, 3};
|
||||
|
||||
MoveOnlyIter in(buffer);
|
||||
Buffer<int, N> out;
|
||||
std::ranges::uninitialized_copy_n(std::move(in), N, out.begin(), out.end());
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -391,5 +391,32 @@ int main(int, char**) {
|
|||
iter_moves = 0;
|
||||
}
|
||||
|
||||
// Move-only iterators are supported.
|
||||
{
|
||||
using MoveOnlyIter = cpp20_input_iterator<const int*>;
|
||||
static_assert(!std::is_copy_constructible_v<MoveOnlyIter>);
|
||||
|
||||
constexpr int N = 3;
|
||||
struct MoveOnlyRange {
|
||||
int buffer[N] = {1, 2, 3};
|
||||
auto begin() const { return MoveOnlyIter(buffer); }
|
||||
auto end() const { return sentinel_wrapper<MoveOnlyIter>(MoveOnlyIter(buffer)); }
|
||||
};
|
||||
static_assert(std::ranges::input_range<MoveOnlyRange>);
|
||||
MoveOnlyRange in;
|
||||
|
||||
// (iter, sentinel) overload.
|
||||
{
|
||||
Buffer<int, N> out;
|
||||
std::ranges::uninitialized_move(in.begin(), in.end(), out.begin(), out.end());
|
||||
}
|
||||
|
||||
// (range) overload.
|
||||
{
|
||||
Buffer<int, N> out;
|
||||
std::ranges::uninitialized_move(in, out);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -167,5 +167,18 @@ int main(int, char**) {
|
|||
iter_moves = 0;
|
||||
}
|
||||
|
||||
// Move-only iterators are supported.
|
||||
{
|
||||
using MoveOnlyIter = cpp20_input_iterator<const int*>;
|
||||
static_assert(!std::is_copy_constructible_v<MoveOnlyIter>);
|
||||
|
||||
constexpr int N = 3;
|
||||
int buffer[N] = {1, 2, 3};
|
||||
|
||||
MoveOnlyIter in(buffer);
|
||||
Buffer<int, N> out;
|
||||
std::ranges::uninitialized_move_n(std::move(in), N, out.begin(), out.end());
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue