From 0102527352ff50a6d66402ab0fd8d857dcac3c5a Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Fri, 6 May 2022 14:17:11 -0700 Subject: [PATCH] [libc++][ranges] Implement `views::single`. 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 | 3 +- libcxx/include/__ranges/single_view.h | 24 +++++++- .../cpo.compile.pass.cpp | 2 +- .../range.lazy.split/ctor.range.pass.cpp | 1 - .../range.factories/range.single.view/cpo.pass.cpp | 66 ++++++++++++++++++++++ 5 files changed, 90 insertions(+), 6 deletions(-) create mode 100644 libcxx/test/std/ranges/range.factories/range.single.view/cpo.pass.cpp diff --git a/libcxx/include/__ranges/lazy_split_view.h b/libcxx/include/__ranges/lazy_split_view.h index 68617c4..e559a76 100644 --- a/libcxx/include/__ranges/lazy_split_view.h +++ b/libcxx/include/__ranges/lazy_split_view.h @@ -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_; } diff --git a/libcxx/include/__ranges/single_view.h b/libcxx/include/__ranges/single_view.h index e6a8730..98ebe5f 100644 --- a/libcxx/include/__ranges/single_view.h +++ b/libcxx/include/__ranges/single_view.h @@ -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 - single_view(_Tp) -> single_view<_Tp>; +template +single_view(_Tp) -> single_view<_Tp>; + +namespace views { +namespace __single_view { + +struct __fn : __range_adaptor_closure<__fn> { + template + [[nodiscard]] _LIBCPP_HIDE_FROM_ABI + constexpr auto operator()(_Range&& __range) const + noexcept(noexcept(single_view>(std::forward<_Range>(__range)))) + -> decltype( single_view>(std::forward<_Range>(__range))) + { return single_view>(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) diff --git a/libcxx/test/std/library/description/conventions/customization.point.object/cpo.compile.pass.cpp b/libcxx/test/std/library/description/conventions/customization.point.object/cpo.compile.pass.cpp index 16c5424..6d76668 100644 --- a/libcxx/test/std/library/description/conventions/customization.point.object/cpo.compile.pass.cpp +++ b/libcxx/test/std/library/description/conventions/customization.point.object/cpo.compile.pass.cpp @@ -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, 1); -//static_assert(test(std::views::single, 4)); +static_assert(test(std::views::single, 4)); // [range.adaptors] static_assert(test(std::views::all, a)); diff --git a/libcxx/test/std/ranges/range.adaptors/range.lazy.split/ctor.range.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.lazy.split/ctor.range.pass.cpp index 45796c6..bde1cb6 100644 --- a/libcxx/test/std/ranges/range.adaptors/range.lazy.split/ctor.range.pass.cpp +++ b/libcxx/test/std/ranges/range.adaptors/range.lazy.split/ctor.range.pass.cpp @@ -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; // 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 index 0000000..984f541 --- /dev/null +++ b/libcxx/test/std/ranges/range.factories/range.single.view/cpo.pass.cpp @@ -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 + +#include +#include +#include +#include "MoveOnly.h" + +// Can't invoke without arguments. +static_assert(!std::is_invocable_v); +// Can't invoke with a move-only type. +static_assert(!std::is_invocable_v); + +constexpr bool test() { + // Lvalue. + { + int x = 42; + std::same_as> decltype(auto) v = std::views::single(x); + assert(v.size() == 1); + assert(v.front() == x); + } + + // Prvalue. + { + std::same_as> decltype(auto) v = std::views::single(42); + assert(v.size() == 1); + assert(v.front() == 42); + } + + // Const lvalue. + { + const int x = 42; + std::same_as> decltype(auto) v = std::views::single(x); + assert(v.size() == 1); + assert(v.front() == x); + } + + // Xvalue. + { + int x = 42; + std::same_as> 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; +} -- 2.7.4