diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -108,10 +108,12 @@ __functional_base __functional/binary_function.h __functional/binary_negate.h + __functional/bind_back.h __functional/bind_front.h __functional/bind.h __functional/binder1st.h __functional/binder2nd.h + __functional/compose.h __functional/default_searcher.h __functional/function.h __functional/hash.h @@ -198,10 +200,11 @@ __ranges/enable_borrowed_range.h __ranges/enable_view.h __ranges/non_propagating_cache.h + __ranges/range_adaptor.h __ranges/ref_view.h - __ranges/take_view.h __ranges/size.h __ranges/subrange.h + __ranges/take_view.h __ranges/transform_view.h __ranges/view_interface.h __split_buffer diff --git a/libcxx/include/__functional/bind_back.h b/libcxx/include/__functional/bind_back.h new file mode 100644 --- /dev/null +++ b/libcxx/include/__functional/bind_back.h @@ -0,0 +1,79 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___FUNCTIONAL_BIND_BACK_H +#define _LIBCPP___FUNCTIONAL_BIND_BACK_H + +#include <__config> +#include <__functional/invoke.h> +#include <__functional/perfect_forward.h> +#include <__utility/forward.h> +#include <__utility/integer_sequence.h> +#include +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +#pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER > 17 + +// Passes the provided arguments to std::invoke in the order specified by the given index_sequence. +template > +_LIBCPP_HIDE_FROM_ABI +constexpr auto __invoke_shuffle(index_sequence<_Ip...>, _Args&& ...__args) + noexcept(is_nothrow_invocable_v...>) + -> typename invoke_result...>::type +{ + _AsTuple __as_tuple = _VSTD::forward_as_tuple(_VSTD::forward<_Args>(__args)...); + return _VSTD::invoke(_VSTD::forward>(_VSTD::get<_Ip>(__as_tuple))...); +} + +template +struct __bind_back_op { + template , // [0, 1) = the function object to invoke + __shift_index_sequence_by<_NBound+1, make_index_sequence<_NUnbound>>, // [_NBound+1, _NUnbound) = the passed arguments, which go first + __shift_index_sequence_by<1, make_index_sequence<_NBound>> // [1, _NBound) = the bound arguments, which go last + >> + _LIBCPP_HIDE_FROM_ABI + static constexpr auto __call(_Fn&& __f, _Args&& ...__args) + noexcept(noexcept(_VSTD::__invoke_shuffle(_Sequence{}, _VSTD::forward<_Fn>(__f), _VSTD::forward<_Args>(__args)...))) + -> decltype( _VSTD::__invoke_shuffle(_Sequence{}, _VSTD::forward<_Fn>(__f), _VSTD::forward<_Args>(__args)...)) + { return _VSTD::__invoke_shuffle(_Sequence{}, _VSTD::forward<_Fn>(__f), _VSTD::forward<_Args>(__args)...); } +}; + +template +struct __bind_back_t : __perfect_forward<__bind_back_op, _Fn, _BoundArgs...> { + using __perfect_forward<__bind_back_op, _Fn, _BoundArgs...>::__perfect_forward; +}; + +template , _Fn>, + is_move_constructible>, + is_constructible, _Args>..., + is_move_constructible>... + > +>> +_LIBCPP_HIDE_FROM_ABI +constexpr auto __bind_back(_Fn&& __f, _Args&&... __args) +noexcept(noexcept(__bind_back_t, decay_t<_Args>...>(_VSTD::forward<_Fn>(__f), _VSTD::forward<_Args>(__args)...))) +-> decltype( __bind_back_t, decay_t<_Args>...>(_VSTD::forward<_Fn>(__f), _VSTD::forward<_Args>(__args)...)) +{ return __bind_back_t, decay_t<_Args>...>(_VSTD::forward<_Fn>(__f), _VSTD::forward<_Args>(__args)...); } + +#endif // _LIBCPP_STD_VER > 17 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___FUNCTIONAL_BIND_BACK_H diff --git a/libcxx/include/__functional/compose.h b/libcxx/include/__functional/compose.h new file mode 100644 --- /dev/null +++ b/libcxx/include/__functional/compose.h @@ -0,0 +1,51 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___FUNCTIONAL_COMPOSE_H +#define _LIBCPP___FUNCTIONAL_COMPOSE_H + +#include <__config> +#include <__functional/invoke.h> +#include <__functional/perfect_forward.h> +#include <__utility/forward.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +#pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER > 17 + +struct __compose_op { + template + _LIBCPP_HIDE_FROM_ABI + static constexpr auto __call(_Fn1&& __f1, _Fn2&& __f2, _Args&&... __args) + noexcept(noexcept(_VSTD::invoke(_VSTD::forward<_Fn1>(__f1), _VSTD::invoke(_VSTD::forward<_Fn2>(__f2), _VSTD::forward<_Args>(__args)...)))) + -> decltype( _VSTD::invoke(_VSTD::forward<_Fn1>(__f1), _VSTD::invoke(_VSTD::forward<_Fn2>(__f2), _VSTD::forward<_Args>(__args)...))) + { return _VSTD::invoke(_VSTD::forward<_Fn1>(__f1), _VSTD::invoke(_VSTD::forward<_Fn2>(__f2), _VSTD::forward<_Args>(__args)...)); } +}; + +template +struct __compose_t : __perfect_forward<__compose_op, _Fn1, _Fn2> { + using __perfect_forward<__compose_op, _Fn1, _Fn2>::__perfect_forward; +}; + +template +_LIBCPP_HIDE_FROM_ABI +constexpr auto __compose(_Fn1&& __f1, _Fn2&& __f2) +noexcept(noexcept(__compose_t, decay_t<_Fn2>>(_VSTD::forward<_Fn1>(__f1), _VSTD::forward<_Fn2>(__f2)))) +-> decltype( __compose_t, decay_t<_Fn2>>(_VSTD::forward<_Fn1>(__f1), _VSTD::forward<_Fn2>(__f2))) +{ return __compose_t, decay_t<_Fn2>>(_VSTD::forward<_Fn1>(__f1), _VSTD::forward<_Fn2>(__f2)); } + +#endif // _LIBCPP_STD_VER > 17 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___FUNCTIONAL_COMPOSE_H diff --git a/libcxx/include/__ranges/all.h b/libcxx/include/__ranges/all.h --- a/libcxx/include/__ranges/all.h +++ b/libcxx/include/__ranges/all.h @@ -14,6 +14,7 @@ #include <__iterator/iterator_traits.h> #include <__ranges/access.h> #include <__ranges/concepts.h> +#include <__ranges/range_adaptor.h> #include <__ranges/ref_view.h> #include <__ranges/subrange.h> #include <__utility/__decay_copy.h> @@ -35,7 +36,7 @@ namespace views { namespace __all { - struct __fn { + struct __fn : __range_adaptor_closure<__fn> { template requires ranges::view> _LIBCPP_HIDE_FROM_ABI diff --git a/libcxx/include/__ranges/range_adaptor.h b/libcxx/include/__ranges/range_adaptor.h new file mode 100644 --- /dev/null +++ b/libcxx/include/__ranges/range_adaptor.h @@ -0,0 +1,66 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___RANGES_RANGE_ADAPTOR_H +#define _LIBCPP___RANGES_RANGE_ADAPTOR_H + +#include <__config> +#include <__functional/compose.h> +#include <__functional/invoke.h> +#include <__ranges/concepts.h> +#include <__utility/forward.h> +#include <__utility/move.h> +#include +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +#pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if !defined(_LIBCPP_HAS_NO_RANGES) + +// CRTP base that one can derive from in order to be considered a range adaptor closure +// by the library. That allows opting into the `operator|`s provided below. +template +struct __range_adaptor_closure { }; + +template +concept _RangeAdaptorClosure = derived_from<_Tp, __range_adaptor_closure<_Tp>>; + +// Type that wraps an arbitrary function object and makes it into a range adaptor closure, +// i.e. something that can be called via the `x | f` notation. +template +struct __range_adaptor_closure_t : _Fn, __range_adaptor_closure<__range_adaptor_closure_t<_Fn>> { + constexpr explicit __range_adaptor_closure_t(_Fn&& __f) : _Fn(_VSTD::move(__f)) { } +}; + +template + requires _RangeAdaptorClosure> +_LIBCPP_HIDE_FROM_ABI +constexpr auto operator|(_View&& __view, _Closure&& __closure) +noexcept(noexcept(_VSTD::invoke(_VSTD::forward<_Closure>(__closure), _VSTD::forward<_View>(__view)))) +-> decltype( _VSTD::invoke(_VSTD::forward<_Closure>(__closure), _VSTD::forward<_View>(__view))) +{ return _VSTD::invoke(_VSTD::forward<_Closure>(__closure), _VSTD::forward<_View>(__view)); } + +template + requires _RangeAdaptorClosure> && + _RangeAdaptorClosure> +_LIBCPP_HIDE_FROM_ABI +constexpr auto operator|(_Closure1&& __c1, _Closure2&& __c2) +noexcept(noexcept(__range_adaptor_closure_t(_VSTD::__compose(_VSTD::forward<_Closure2>(__c2), _VSTD::forward<_Closure1>(__c1))))) +-> decltype( __range_adaptor_closure_t(_VSTD::__compose(_VSTD::forward<_Closure2>(__c2), _VSTD::forward<_Closure1>(__c1)))) +{ return __range_adaptor_closure_t(_VSTD::__compose(_VSTD::forward<_Closure2>(__c2), _VSTD::forward<_Closure1>(__c1))); } + +#endif // !defined(_LIBCPP_HAS_NO_RANGES) + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___RANGES_RANGE_ADAPTOR_H diff --git a/libcxx/include/__ranges/transform_view.h b/libcxx/include/__ranges/transform_view.h --- a/libcxx/include/__ranges/transform_view.h +++ b/libcxx/include/__ranges/transform_view.h @@ -10,6 +10,8 @@ #define _LIBCPP___RANGES_TRANSFORM_VIEW_H #include <__config> +#include <__functional/bind_back.h> +#include <__functional/invoke.h> #include <__iterator/concepts.h> #include <__iterator/iter_swap.h> #include <__iterator/iterator_traits.h> @@ -18,8 +20,10 @@ #include <__ranges/concepts.h> #include <__ranges/copyable_box.h> #include <__ranges/empty.h> +#include <__ranges/range_adaptor.h> #include <__ranges/size.h> #include <__ranges/view_interface.h> +#include <__utility/forward.h> #include #include @@ -399,6 +403,30 @@ } // namespace ranges +namespace views { +namespace __transform { + struct __fn { + template + _LIBCPP_HIDE_FROM_ABI + constexpr auto operator()(_Range&& __range, _Fn&& __f) const + noexcept(noexcept(ranges::transform_view(_VSTD::forward<_Range>(__range), _VSTD::forward<_Fn>(__f)))) + -> decltype( ranges::transform_view(_VSTD::forward<_Range>(__range), _VSTD::forward<_Fn>(__f))) + { return ranges::transform_view(_VSTD::forward<_Range>(__range), _VSTD::forward<_Fn>(__f)); } + + template + _LIBCPP_HIDE_FROM_ABI + constexpr auto operator()(_Fn&& __f) const + noexcept(noexcept(__range_adaptor_closure_t(_VSTD::__bind_back(*this, _VSTD::forward<_Fn>(__f))))) + -> decltype( __range_adaptor_closure_t(_VSTD::__bind_back(*this, _VSTD::forward<_Fn>(__f)))) + { return __range_adaptor_closure_t(_VSTD::__bind_back(*this, _VSTD::forward<_Fn>(__f))); } + }; +} + +inline namespace __cpo { + inline constexpr auto transform = __transform::__fn{}; +} +} // end namespace views + #endif // !defined(_LIBCPP_HAS_NO_RANGES) _LIBCPP_END_NAMESPACE_STD diff --git a/libcxx/include/__utility/integer_sequence.h b/libcxx/include/__utility/integer_sequence.h --- a/libcxx/include/__utility/integer_sequence.h +++ b/libcxx/include/__utility/integer_sequence.h @@ -74,6 +74,39 @@ template using index_sequence_for = make_index_sequence; + +template +struct __join_integer_sequences_impl; + +template +struct __join_integer_sequences_impl<_S1> { + using type = _S1; +}; + +template +struct __join_integer_sequences_impl, integer_sequence<_Tp, _Ip2...>> { + using type = integer_sequence<_Tp, _Ip1..., _Ip2...>; +}; + +template +struct __join_integer_sequences_impl<_S1, _S2, _Sn...> + : __join_integer_sequences_impl::type, _Sn...> +{ }; + +template +using __join_integer_sequences = typename __join_integer_sequences_impl<_Sequences...>::type; + +template +struct __shift_index_sequence_by_impl; + +template +struct __shift_index_sequence_by_impl<_Np, index_sequence<_Ips...>> { + using type = index_sequence<(_Np + _Ips)...>; +}; + +template +using __shift_index_sequence_by = typename __shift_index_sequence_by_impl<_Np, _Sequence>::type; + #endif // _LIBCPP_STD_VER > 11 _LIBCPP_END_NAMESPACE_STD diff --git a/libcxx/include/functional b/libcxx/include/functional --- a/libcxx/include/functional +++ b/libcxx/include/functional @@ -492,6 +492,7 @@ #include <__debug> #include <__functional/binary_function.h> // TODO: deprecate #include <__functional/binary_negate.h> +#include <__functional/bind_back.h> #include <__functional/bind_front.h> #include <__functional/bind.h> #include <__functional/binder1st.h> diff --git a/libcxx/include/module.modulemap b/libcxx/include/module.modulemap --- a/libcxx/include/module.modulemap +++ b/libcxx/include/module.modulemap @@ -419,15 +419,17 @@ module binary_function { private header "__functional/binary_function.h" } module binary_negate { private header "__functional/binary_negate.h" } module bind { private header "__functional/bind.h" } + module bind_back { private header "__functional/bind_back.h" } module bind_front { private header "__functional/bind_front.h" } module binder1st { private header "__functional/binder1st.h" } module binder2nd { private header "__functional/binder2nd.h" } + module compose { private header "__functional/compose.h" } module default_searcher { private header "__functional/default_searcher.h" } module function { private header "__functional/function.h" } module hash { private header "__functional/hash.h" } module identity { private header "__functional/identity.h" } - module is_transparent { private header "__functional/is_transparent.h" } module invoke { private header "__functional/invoke.h" } + module is_transparent { private header "__functional/is_transparent.h" } module mem_fn { private header "__functional/mem_fn.h" } module mem_fun_ref { private header "__functional/mem_fun_ref.h" } module not_fn { private header "__functional/not_fn.h" } @@ -630,6 +632,7 @@ module enable_borrowed_range { private header "__ranges/enable_borrowed_range.h" } module enable_view { private header "__ranges/enable_view.h" } module non_propagating_cache { private header "__ranges/non_propagating_cache.h" } + module range_adaptor { private header "__ranges/range_adaptor.h" } module ref_view { private header "__ranges/ref_view.h" } module size { private header "__ranges/size.h" } module subrange { private header "__ranges/subrange.h" } diff --git a/libcxx/test/libcxx/diagnostics/detail.headers/functional/bind_back.module.verify.cpp b/libcxx/test/libcxx/diagnostics/detail.headers/functional/bind_back.module.verify.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/libcxx/diagnostics/detail.headers/functional/bind_back.module.verify.cpp @@ -0,0 +1,16 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// REQUIRES: modules-build + +// WARNING: This test was generated by 'generate_private_header_tests.py' +// and should not be edited manually. + +// expected-error@*:* {{use of private header from outside its module: '__functional/bind_back.h'}} +#include <__functional/bind_back.h> diff --git a/libcxx/test/libcxx/diagnostics/detail.headers/functional/compose.module.verify.cpp b/libcxx/test/libcxx/diagnostics/detail.headers/functional/compose.module.verify.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/libcxx/diagnostics/detail.headers/functional/compose.module.verify.cpp @@ -0,0 +1,16 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// REQUIRES: modules-build + +// WARNING: This test was generated by 'generate_private_header_tests.py' +// and should not be edited manually. + +// expected-error@*:* {{use of private header from outside its module: '__functional/compose.h'}} +#include <__functional/compose.h> diff --git a/libcxx/test/libcxx/diagnostics/detail.headers/ranges/range_adaptor.module.verify.cpp b/libcxx/test/libcxx/diagnostics/detail.headers/ranges/range_adaptor.module.verify.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/libcxx/diagnostics/detail.headers/ranges/range_adaptor.module.verify.cpp @@ -0,0 +1,16 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// REQUIRES: modules-build + +// WARNING: This test was generated by 'generate_private_header_tests.py' +// and should not be edited manually. + +// expected-error@*:* {{use of private header from outside its module: '__ranges/range_adaptor.h'}} +#include <__ranges/range_adaptor.h> diff --git a/libcxx/test/libcxx/utilities/function.objects/func.bind_back/bind_back.pass.cpp b/libcxx/test/libcxx/utilities/function.objects/func.bind_back/bind_back.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/libcxx/utilities/function.objects/func.bind_back/bind_back.pass.cpp @@ -0,0 +1,119 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// functional + +// template +// constexpr unspecified __bind_back(F&&, Args&&...); + +// This isn't part of the standard, however we use it internally and there is a +// chance that it will be added to the standard, so we implement those tests +// as-if it were part of the spec. + +#include +#include +#include +#include + +struct MakeTuple { + template + constexpr auto operator()(Args&& ...args) const { + return std::make_tuple(std::forward(args)...); + } +}; + +constexpr bool test() { + // Bind arguments, call without arguments + { + { + auto f = std::__bind_back(MakeTuple{}); + assert(f() == std::make_tuple()); + } + { + auto f = std::__bind_back(MakeTuple{}, 1); + assert(f() == std::make_tuple(1)); + } + { + auto f = std::__bind_back(MakeTuple{}, 1, '2'); + assert(f() == std::make_tuple(1, '2')); + } + { + auto f = std::__bind_back(MakeTuple{}, 1, '2', 3.0f); + assert(f() == std::make_tuple(1, '2', 3.0f)); + } + } + + // Bind no arguments, call with arguments + { + { + auto f = std::__bind_back(MakeTuple{}); + assert(f(1) == std::make_tuple(1)); + } + { + auto f = std::__bind_back(MakeTuple{}); + assert(f(1, '2') == std::make_tuple(1, '2')); + } + { + auto f = std::__bind_back(MakeTuple{}); + assert(f(1, '2', 3.0f) == std::make_tuple(1, '2', 3.0f)); + } + } + + // Bind arguments, call with arguments + { + { + auto f = std::__bind_back(MakeTuple{}, 1); + assert(f(10) == std::make_tuple(10, 1)); + } + { + auto f = std::__bind_back(MakeTuple{}, 1, 2); + assert(f(10) == std::make_tuple(10, 1, 2)); + } + { + auto f = std::__bind_back(MakeTuple{}, 1, 2, 3); + assert(f(10) == std::make_tuple(10, 1, 2, 3)); + } + + { + auto f = std::__bind_back(MakeTuple{}, 1); + assert(f(10, 11) == std::make_tuple(10, 11, 1)); + } + { + auto f = std::__bind_back(MakeTuple{}, 1, 2); + assert(f(10, 11) == std::make_tuple(10, 11, 1, 2)); + } + { + auto f = std::__bind_back(MakeTuple{}, 1, 2, 3); + assert(f(10, 11) == std::make_tuple(10, 11, 1, 2, 3)); + } + + { + auto f = std::__bind_back(MakeTuple{}, 1); + assert(f(10, 11, 12) == std::make_tuple(10, 11, 12, 1)); + } + { + auto f = std::__bind_back(MakeTuple{}, 1, 2); + assert(f(10, 11, 12) == std::make_tuple(10, 11, 12, 1, 2)); + } + { + auto f = std::__bind_back(MakeTuple{}, 1, 2, 3); + assert(f(10, 11, 12) == std::make_tuple(10, 11, 12, 1, 2, 3)); + } + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/ranges/range.adaptors/range.all/adaptor.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.all/adaptor.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.adaptors/range.all/adaptor.pass.cpp @@ -0,0 +1,49 @@ +//===----------------------------------------------------------------------===// +// +// 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-no-concepts +// UNSUPPORTED: gcc-10 +// UNSUPPORTED: libcpp-has-no-incomplete-ranges + +// std::views::all + +#include +#include +#include + +struct Range { + int* ptr_; + int start_; + int end_; + constexpr explicit Range(int* ptr, int start, int end) noexcept : ptr_(ptr), start_(start), end_(end) { } + friend constexpr int* begin(Range const& range) { return range.ptr_ + range.start_; } + friend constexpr int* begin(Range& range) { return range.ptr_ + range.start_; } + friend constexpr int* end(Range const& range) { return range.ptr_ + range.end_; } + friend constexpr int* end(Range& range) { return range.ptr_ + range.end_; } +}; + +constexpr bool test() { + int buff[8] = {0, 1, 2, 3, 4, 5, 6, 7}; + + { + Range range(buff, 0, 8); + auto result = range | std::views::all; + static_assert(std::is_same_v>); + assert(&result.base() == &range); + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/ranges/range.adaptors/range.transform/adaptor.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.transform/adaptor.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.adaptors/range.transform/adaptor.pass.cpp @@ -0,0 +1,71 @@ +//===----------------------------------------------------------------------===// +// +// 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-no-concepts +// UNSUPPORTED: gcc-10 +// UNSUPPORTED: libcpp-has-no-incomplete-ranges + +// std::views::transform + +#include +#include +#include +#include + +#include "test_macros.h" +#include "types.h" + +template +concept CanBePiped = requires (int* buff, T&& t) { + { ContiguousView{buff} | std::forward(t) }; +}; + +static_assert(!CanBePiped); +static_assert( CanBePiped); + +constexpr bool test() { + int buff[8] = {0, 1, 2, 3, 4, 5, 6, 7}; + + { + auto partial = std::views::transform(Increment{}); + auto result = partial(ContiguousView{buff}); + ASSERT_SAME_TYPE(decltype(result), std::ranges::transform_view); + assert(result.begin().base() == buff); + assert(result[0] == 1); + assert(result[1] == 2); + assert(result[2] == 3); + } + { + auto result = ContiguousView{buff} | std::views::transform(Increment{}); + ASSERT_SAME_TYPE(decltype(result), std::ranges::transform_view); + assert(result.begin().base() == buff); + assert(result[0] == 1); + assert(result[1] == 2); + assert(result[2] == 3); + } + + // Test that one can call std::views::transform with arbitrary stuff, as long as we + // don't try to actually complete the call by passing it a range. + // + // That makes no sense and we can't do anything with the result, but it's valid. + { + struct X { }; + auto partial = std::views::transform(X{}); + (void)partial; + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +}