[libcxx-commits] [PATCH] D137637: [libc++] Implement P2446R2 (views::as_rvalue)

Konstantin Varlamov via Phabricator via libcxx-commits libcxx-commits at lists.llvm.org
Fri Dec 2 15:03:02 PST 2022


var-const added inline comments.


================
Comment at: libcxx/include/__ranges/as_rvalue_view.h:3
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
----------------
Please update the `<ranges>` synopsis as well.


================
Comment at: libcxx/include/__ranges/as_rvalue_view.h:30
+  requires input_range<_View>
+class as_rvalue_view : public view_interface<as_rvalue_view<_View>> {
+  _LIBCPP_NO_UNIQUE_ADDRESS _View __base_ = _View();
----------------
This needs an include (probably currently relying on the transitive include from `all.h`).


================
Comment at: libcxx/include/__ranges/as_rvalue_view.h:110-114
+    requires same_as<range_rvalue_reference_t<_Range>, range_reference_t<_Range>>
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Range&& __range) const
+      noexcept(noexcept(/**/ views::all(std::forward<_Range>(__range))))
+          -> decltype(/*--*/ views::all(std::forward<_Range>(__range))) {
+    return /*-------------*/ views::all(std::forward<_Range>(__range));
----------------
I think this (an optimization, essentially) deserves a comment.


================
Comment at: libcxx/test/std/ranges/range.adaptors/range.as.rvalue/adaptor.pass.cpp:24
+
+static_assert(std::random_access_iterator<rvalue_iterator<int*>>);
+
----------------
I think this check would be better in `test_iterators.h`, right after the definition of `rvalue_iterator`.


================
Comment at: libcxx/test/std/ranges/range.adaptors/range.as.rvalue/adaptor.pass.cpp:44
+constexpr bool test() {
+  { // view | views::as_rvalue
+    View v{{}, 3};
----------------
Can you also check piping a container (i.e. something that is not a view) through `as_rvalue`? Ideally, both lvalue and rvalue.


================
Comment at: libcxx/test/std/ranges/range.adaptors/range.as.rvalue/adaptor.pass.cpp:48
+    assert(view.base().i == 3);
+  }
+  { // adaptor | views::as_rvalue
----------------
Nit: can you add empty lines between the cases? (Here and in some other tests)


================
Comment at: libcxx/test/std/ranges/range.adaptors/range.as.rvalue/adaptor.pass.cpp:52
+    const auto partial = std::views::transform(std::identity{}) | std::views::as_rvalue;
+    std::same_as<std::ranges::as_rvalue_view<std::ranges::transform_view<View, std::identity>>> auto view = partial(v);
+    assert(view.base().base().i == 3);
----------------
`s/auto/decltype(auto)/` (throughout).


================
Comment at: libcxx/test/std/ranges/range.adaptors/range.as.rvalue/adaptor.pass.cpp:55
+  }
+  { // adaptor | views::as_rvalue
+    View v{{}, 3};
----------------
The argument order is swapped in the comment.


================
Comment at: libcxx/test/std/ranges/range.adaptors/range.as.rvalue/adaptor.pass.cpp:73
+  test();
+  static_assert(test());
+}
----------------
Nit: `return 0;`.


================
Comment at: libcxx/test/std/ranges/range.adaptors/range.as.rvalue/begin.pass.cpp:29
+static_assert(HasBegin<std::ranges::as_rvalue_view<View>>);
+static_assert(HasBegin<const std::ranges::as_rvalue_view<View>>);
+
----------------
These checks don't seem to be exhaustive. For example, there should probably be a check that `!HasBegin` if `!range<const _View>`.


================
Comment at: libcxx/test/std/ranges/range.adaptors/range.as.rvalue/begin.pass.cpp:32
+template <class Iter, class Sent>
+constexpr void test_range() {
+  int a[] = {1, 2};
----------------
This only tests the non-const version of `begin`, right? I think it shouldn't be too hard to also test a const `as_rvalue_view` here.


================
Comment at: libcxx/test/std/ranges/range.adaptors/range.as.rvalue/begin.pass.cpp:42
+constexpr void test_range_sentinels() {
+  test_range<Iter, Iter>();
+  test_range<Iter, sentinel_wrapper<Iter>>();
----------------
Optional: I think you could wrap this call in a check like `if constexpr (std::sentinel_for<Iter, Iter>)` and avoid having to call `test_range` directly from `test`.


================
Comment at: libcxx/test/std/ranges/range.adaptors/range.as.rvalue/end.pass.cpp:58
+template <class T>
+concept HasBegin = requires(T t) { t.end(); };
+
----------------
`s/Begin/End/`.


================
Comment at: libcxx/test/std/ranges/range.adaptors/range.as.rvalue/end.pass.cpp:61
+static_assert(HasBegin<std::ranges::as_rvalue_view<View>>);
+static_assert(HasBegin<const std::ranges::as_rvalue_view<View>>);
+
----------------
Can you also test the case where the concept is false?


================
Comment at: libcxx/test/std/ranges/range.adaptors/range.as.rvalue/end.pass.cpp:70
+constexpr void test_range() {
+  using Expected = std::conditional_t<is_common, std::move_iterator<Sent>, std::move_sentinel<Sent>>;
+  int a[]        = {1, 2};
----------------
Is it possible to just use the `std::ranges::common_range` concept?


================
Comment at: libcxx/test/std/ranges/range.adaptors/range.as.rvalue/end.pass.cpp:73
+  std::ranges::subrange range(Iter(std::begin(a)), Sent(Iter(std::end(a))));
+  std::ranges::as_rvalue_view view(std::move(range));
+  std::same_as<Expected> decltype(auto) iter = view.end();
----------------
Same as the `begin` tests -- I think this should also test when a view is `const`.


================
Comment at: libcxx/test/std/ranges/range.adaptors/range.as.rvalue/end.pass.cpp:80
+constexpr void test_range_sentinels() {
+  test_range<Iter, Iter, true>();
+  test_range<Iter, sentinel_wrapper<Iter>, false>();
----------------
Same as the `begin` test -- I think this can be simplified with `if constexpr`.


================
Comment at: libcxx/test/std/ranges/range.adaptors/range.as.rvalue/end.pass.cpp:98
+    std::ranges::as_rvalue_view view(CVCallView{});
+    (void)view.begin();
+    assert(view.base().const_called);
----------------
Why are we checking `begin` here?


================
Comment at: libcxx/test/std/ranges/range.adaptors/range.as.rvalue/size.pass.cpp:53
+  {
+    bool size_called = false;
+    std::ranges::as_rvalue_view view(ConstSizedView{{}, &size_called});
----------------
Doesn't seem to be checked. Also, why is it only on the const sized view and not the non-const one?


================
Comment at: libcxx/test/std/ranges/range.adaptors/range.as.rvalue/size.pass.cpp:56
+    std::same_as<size_t> auto size = view.size();
+    assert(size == 3);
+  }
----------------
Why is the return value only checked for the const case?


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D137637/new/

https://reviews.llvm.org/D137637



More information about the libcxx-commits mailing list