[libc++][ranges] Implement `views::single`.
authorKonstantin Varlamov <varconst@apple.com>
Fri, 6 May 2022 21:17:11 +0000 (14:17 -0700)
committerKonstantin Varlamov <varconst@apple.com>
Fri, 6 May 2022 21:27:08 +0000 (14:27 -0700)
This only adds the customization point object (which isn't pipeable),
the view itself has already been implemented previously.

Differential Revision: https://reviews.llvm.org/D124978

libcxx/include/__ranges/lazy_split_view.h
libcxx/include/__ranges/single_view.h
libcxx/test/std/library/description/conventions/customization.point.object/cpo.compile.pass.cpp
libcxx/test/std/ranges/range.adaptors/range.lazy.split/ctor.range.pass.cpp
libcxx/test/std/ranges/range.factories/range.single.view/cpo.pass.cpp [new file with mode: 0644]

index 68617c4..e559a76 100644 (file)
@@ -87,8 +87,7 @@ public:
   _LIBCPP_HIDE_FROM_ABI
   constexpr lazy_split_view(_Range&& __r, range_value_t<_Range> __e)
     : __base_(views::all(std::forward<_Range>(__r)))
-    // TODO(varconst): use `views::single` once it's implemented.
-    , __pattern_(ranges::single_view(std::move(__e))) {}
+    , __pattern_(views::single(std::move(__e))) {}
 
   _LIBCPP_HIDE_FROM_ABI
   constexpr _View base() const& requires copy_constructible<_View> { return __base_; }
index e6a8730..98ebe5f 100644 (file)
@@ -11,6 +11,7 @@
 
 #include <__config>
 #include <__ranges/copyable_box.h>
+#include <__ranges/range_adaptor.h>
 #include <__ranges/view_interface.h>
 #include <__utility/forward.h>
 #include <__utility/in_place.h>
@@ -70,8 +71,27 @@ namespace ranges {
     constexpr const _Tp* data() const noexcept { return __value_.operator->(); }
   };
 
-  template<class _Tp>
-  single_view(_Tp) -> single_view<_Tp>;
+template<class _Tp>
+single_view(_Tp) -> single_view<_Tp>;
+
+namespace views {
+namespace __single_view {
+
+struct __fn : __range_adaptor_closure<__fn> {
+  template<class _Range>
+  [[nodiscard]] _LIBCPP_HIDE_FROM_ABI
+  constexpr auto operator()(_Range&& __range) const
+    noexcept(noexcept(single_view<decay_t<_Range&&>>(std::forward<_Range>(__range))))
+    -> decltype(      single_view<decay_t<_Range&&>>(std::forward<_Range>(__range)))
+    { return          single_view<decay_t<_Range&&>>(std::forward<_Range>(__range)); }
+};
+} // namespace __single_view
+
+inline namespace __cpo {
+  inline constexpr auto single = __single_view::__fn{};
+} // namespace __cpo
+
+} // namespace views
 } // namespace ranges
 
 #endif // _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES)
index 16c5424..6d76668 100644 (file)
@@ -80,7 +80,7 @@ static_assert(test(std::ranges::ssize, a));
 static_assert(test(std::views::iota, 1));
 static_assert(test(std::views::iota, 1, 10));
 //static_assert(test(std::views::istream<int>, 1);
-//static_assert(test(std::views::single, 4));
+static_assert(test(std::views::single, 4));
 
 // [range.adaptors]
 static_assert(test(std::views::all, a));
index 45796c6..bde1cb6 100644 (file)
@@ -125,7 +125,6 @@ constexpr bool test() {
   {
     using Range = RangeWithCounting;
     using Element = ElementWithCounting;
-    // TODO(varconst): use `views::single` once it's implemented.
     using Pattern = std::ranges::single_view<Element>;
 
     // Arguments are lvalues.
diff --git a/libcxx/test/std/ranges/range.factories/range.single.view/cpo.pass.cpp b/libcxx/test/std/ranges/range.factories/range.single.view/cpo.pass.cpp
new file mode 100644 (file)
index 0000000..984f541
--- /dev/null
@@ -0,0 +1,66 @@
+//===----------------------------------------------------------------------===//
+//
+// 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::views::single
+
+#include <ranges>
+
+#include <cassert>
+#include <concepts>
+#include <utility>
+#include "MoveOnly.h"
+
+// Can't invoke without arguments.
+static_assert(!std::is_invocable_v<decltype((std::views::single))>);
+// Can't invoke with a move-only type.
+static_assert(!std::is_invocable_v<decltype((std::views::single)), MoveOnly>);
+
+constexpr bool test() {
+  // Lvalue.
+  {
+    int x = 42;
+    std::same_as<std::ranges::single_view<int>> decltype(auto) v = std::views::single(x);
+    assert(v.size() == 1);
+    assert(v.front() == x);
+  }
+
+  // Prvalue.
+  {
+    std::same_as<std::ranges::single_view<int>> decltype(auto) v = std::views::single(42);
+    assert(v.size() == 1);
+    assert(v.front() == 42);
+  }
+
+  // Const lvalue.
+  {
+    const int x = 42;
+    std::same_as<std::ranges::single_view<int>> decltype(auto) v = std::views::single(x);
+    assert(v.size() == 1);
+    assert(v.front() == x);
+  }
+
+  // Xvalue.
+  {
+    int x = 42;
+    std::same_as<std::ranges::single_view<int>> decltype(auto) v = std::views::single(std::move(x));
+    assert(v.size() == 1);
+    assert(v.front() == x);
+  }
+
+  return true;
+}
+
+int main(int, char**) {
+  test();
+  static_assert(test());
+
+  return 0;
+}