Skip to content

[libc++][ranges] Implement LWG4053 and LWG4054 #88612

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Apr 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions libcxx/docs/Status/Cxx2cIssues.csv
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,8 @@
"`4038 <https://wg21.link/LWG4038>`__","``std::text_encoding::aliases_view`` should have constexpr iterators","Tokyo March 2024","","",""
"`4043 <https://wg21.link/LWG4043>`__","""ASCII"" is not a registered character encoding","Tokyo March 2024","|Nothing To Do|","",""
"`4045 <https://wg21.link/LWG4045>`__","``tuple`` can create dangling references from ``tuple-like``","Tokyo March 2024","","",""
"`4053 <https://wg21.link/LWG4053>`__","Unary call to ``std::views::repeat`` does not decay the argument","Tokyo March 2024","","","|ranges|"
"`4054 <https://wg21.link/LWG4054>`__","Repeating a ``repeat_view`` should repeat the view","Tokyo March 2024","","","|ranges|"
"`4053 <https://wg21.link/LWG4053>`__","Unary call to ``std::views::repeat`` does not decay the argument","Tokyo March 2024","|Complete|","19.0","|ranges|"
"`4054 <https://wg21.link/LWG4054>`__","Repeating a ``repeat_view`` should repeat the view","Tokyo March 2024","|Complete|","19.0","|ranges|"
"","","","","",""
"`3343 <https://wg21.link/LWG3343>`__","Ordering of calls to ``unlock()`` and ``notify_all()`` in Effects element of ``notify_all_at_thread_exit()`` should be reversed","Not Yet Adopted","|Complete|","16.0",""
"XXXX","","The sys_info range should be affected by save","Not Yet Adopted","|Complete|","19.0"
Expand Down
11 changes: 6 additions & 5 deletions libcxx/include/__ranges/repeat_view.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include <__ranges/iota_view.h>
#include <__ranges/movable_box.h>
#include <__ranges/view_interface.h>
#include <__type_traits/decay.h>
#include <__type_traits/is_object.h>
#include <__type_traits/make_unsigned.h>
#include <__type_traits/remove_cv.h>
Expand Down Expand Up @@ -127,8 +128,8 @@ class _LIBCPP_ABI_LLVM18_NO_UNIQUE_ADDRESS repeat_view : public view_interface<r
_LIBCPP_NO_UNIQUE_ADDRESS _Bound __bound_ = _Bound();
};

template <class _Tp, class _Bound>
repeat_view(_Tp, _Bound) -> repeat_view<_Tp, _Bound>;
template <class _Tp, class _Bound = unreachable_sentinel_t>
repeat_view(_Tp, _Bound = _Bound()) -> repeat_view<_Tp, _Bound>;

// [range.repeat.iterator]
template <move_constructible _Tp, semiregular _Bound>
Expand Down Expand Up @@ -230,9 +231,9 @@ namespace __repeat {
struct __fn {
template <class _Tp>
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI static constexpr auto operator()(_Tp&& __value)
noexcept(noexcept(ranges::repeat_view(std::forward<_Tp>(__value))))
-> decltype( ranges::repeat_view(std::forward<_Tp>(__value)))
{ return ranges::repeat_view(std::forward<_Tp>(__value)); }
noexcept(noexcept(ranges::repeat_view<decay_t<_Tp>>(std::forward<_Tp>(__value))))
-> decltype( ranges::repeat_view<decay_t<_Tp>>(std::forward<_Tp>(__value)))
{ return ranges::repeat_view<decay_t<_Tp>>(std::forward<_Tp>(__value)); }

template <class _Tp, class _Bound>
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI static constexpr auto operator()(_Tp&& __value, _Bound&& __bound_sentinel)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,10 @@ static_assert(std::same_as<decltype(std::ranges::repeat_view(std::declval<Empty&
static_assert(std::same_as<decltype(std::ranges::repeat_view(10, 1)), std::ranges::repeat_view<int, int>>);
static_assert(std::same_as<decltype(std::ranges::repeat_view(10, 1U)), std::ranges::repeat_view<int, unsigned>>);
static_assert(std::same_as<decltype(std::ranges::repeat_view(10, 1UL)), std::ranges::repeat_view<int, unsigned long>>);

using RPV = std::ranges::repeat_view<const char*>;
static_assert(std::same_as<decltype(std::ranges::repeat_view("foo", std::unreachable_sentinel)), RPV>); // OK
static_assert(std::same_as<decltype(std::ranges::repeat_view(+"foo", std::unreachable_sentinel)), RPV>); // OK
static_assert(std::same_as<decltype(std::ranges::repeat_view("foo")), RPV>); // OK since LWG4053
static_assert(std::same_as<decltype(std::ranges::repeat_view(+"foo")), RPV>); // OK
// clang-format on
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,18 @@ static_assert(!std::is_invocable_v<decltype(std::views::repeat), NonCopyable>);
// Tp is move_constructible
static_assert(std::is_invocable_v<decltype(std::views::repeat), MoveOnly>);

// Test LWG4054 "Repeating a repeat_view should repeat the view"
static_assert(std::is_same_v<decltype(std::views::repeat(std::views::repeat(42))),
std::ranges::repeat_view<std::ranges::repeat_view<int>>>);

// These cases are from LWG4053, but they are actually covered by the resolution of LWG4054,
// and the resolution of LWG4053 only affects CTAD.
using RPV = std::ranges::repeat_view<const char*>;
static_assert(std::same_as<decltype(std::views::repeat("foo", std::unreachable_sentinel)), RPV>); // OK
static_assert(std::same_as<decltype(std::views::repeat(+"foo", std::unreachable_sentinel)), RPV>); // OK
static_assert(std::same_as<decltype(std::views::repeat("foo")), RPV>); // OK since LWG4054
static_assert(std::same_as<decltype(std::views::repeat(+"foo")), RPV>); // OK

constexpr bool test() {
assert(*std::views::repeat(33).begin() == 33);
assert(*std::views::repeat(33, 10).begin() == 33);
Expand Down