| 1 | // -*- C++ -*- |
| 2 | //===----------------------------------------------------------------------===// |
| 3 | // |
| 4 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| 5 | // See https://llvm.org/LICENSE.txt for license information. |
| 6 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| 7 | // |
| 8 | //===----------------------------------------------------------------------===// |
| 9 | |
| 10 | #ifndef _LIBCPP___RANGES_RANGE_ADAPTOR_H |
| 11 | #define _LIBCPP___RANGES_RANGE_ADAPTOR_H |
| 12 | |
| 13 | #include <__concepts/constructible.h> |
| 14 | #include <__concepts/derived_from.h> |
| 15 | #include <__concepts/invocable.h> |
| 16 | #include <__concepts/same_as.h> |
| 17 | #include <__config> |
| 18 | #include <__functional/compose.h> |
| 19 | #include <__functional/invoke.h> |
| 20 | #include <__ranges/concepts.h> |
| 21 | #include <__type_traits/decay.h> |
| 22 | #include <__type_traits/invoke.h> |
| 23 | #include <__type_traits/is_class.h> |
| 24 | #include <__type_traits/is_nothrow_constructible.h> |
| 25 | #include <__type_traits/remove_cv.h> |
| 26 | #include <__type_traits/remove_cvref.h> |
| 27 | #include <__utility/forward.h> |
| 28 | #include <__utility/move.h> |
| 29 | |
| 30 | #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) |
| 31 | # pragma GCC system_header |
| 32 | #endif |
| 33 | |
| 34 | _LIBCPP_PUSH_MACROS |
| 35 | #include <__undef_macros> |
| 36 | |
| 37 | _LIBCPP_BEGIN_NAMESPACE_STD |
| 38 | |
| 39 | #if _LIBCPP_STD_VER >= 20 |
| 40 | |
| 41 | namespace ranges { |
| 42 | |
| 43 | // CRTP base that one can derive from in order to be considered a range adaptor closure |
| 44 | // by the library. When deriving from this class, a pipe operator will be provided to |
| 45 | // make the following hold: |
| 46 | // - `x | f` is equivalent to `f(x)` |
| 47 | // - `f1 | f2` is an adaptor closure `g` such that `g(x)` is equivalent to `f2(f1(x))` |
| 48 | template <class _Tp> |
| 49 | requires is_class_v<_Tp> && same_as<_Tp, remove_cv_t<_Tp>> |
| 50 | struct __range_adaptor_closure {}; |
| 51 | |
| 52 | // Type that wraps an arbitrary function object and makes it into a range adaptor closure, |
| 53 | // i.e. something that can be called via the `x | f` notation. |
| 54 | template <class _Fn> |
| 55 | struct __pipeable : _Fn, __range_adaptor_closure<__pipeable<_Fn>> { |
| 56 | _LIBCPP_HIDE_FROM_ABI constexpr explicit __pipeable(_Fn&& __f) : _Fn(std::move(__f)) {} |
| 57 | }; |
| 58 | _LIBCPP_CTAD_SUPPORTED_FOR_TYPE(__pipeable); |
| 59 | |
| 60 | template <class _Tp> |
| 61 | _Tp __derived_from_range_adaptor_closure(__range_adaptor_closure<_Tp>*); |
| 62 | |
| 63 | template <class _Tp> |
| 64 | concept _RangeAdaptorClosure = !ranges::range<remove_cvref_t<_Tp>> && requires { |
| 65 | // Ensure that `remove_cvref_t<_Tp>` is derived from `__range_adaptor_closure<remove_cvref_t<_Tp>>` and isn't derived |
| 66 | // from `__range_adaptor_closure<U>` for any other type `U`. |
| 67 | { ranges::__derived_from_range_adaptor_closure((remove_cvref_t<_Tp>*)nullptr) } -> same_as<remove_cvref_t<_Tp>>; |
| 68 | }; |
| 69 | |
| 70 | template <ranges::range _Range, _RangeAdaptorClosure _Closure> |
| 71 | requires invocable<_Closure, _Range> |
| 72 | [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) |
| 73 | operator|(_Range&& __range, _Closure&& __closure) noexcept(is_nothrow_invocable_v<_Closure, _Range>) { |
| 74 | return std::invoke(std::forward<_Closure>(__closure), std::forward<_Range>(__range)); |
| 75 | } |
| 76 | |
| 77 | template <_RangeAdaptorClosure _Closure, _RangeAdaptorClosure _OtherClosure> |
| 78 | requires constructible_from<decay_t<_Closure>, _Closure> && constructible_from<decay_t<_OtherClosure>, _OtherClosure> |
| 79 | [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator|(_Closure&& __c1, _OtherClosure&& __c2) noexcept( |
| 80 | is_nothrow_constructible_v<decay_t<_Closure>, _Closure> && |
| 81 | is_nothrow_constructible_v<decay_t<_OtherClosure>, _OtherClosure>) { |
| 82 | return __pipeable(std::__compose(std::forward<_OtherClosure>(__c2), std::forward<_Closure>(__c1))); |
| 83 | } |
| 84 | |
| 85 | # if _LIBCPP_STD_VER >= 23 |
| 86 | template <class _Tp> |
| 87 | requires is_class_v<_Tp> && same_as<_Tp, remove_cv_t<_Tp>> |
| 88 | class _LIBCPP_NO_SPECIALIZATIONS range_adaptor_closure : public __range_adaptor_closure<_Tp> {}; |
| 89 | # endif // _LIBCPP_STD_VER >= 23 |
| 90 | |
| 91 | } // namespace ranges |
| 92 | |
| 93 | #endif // _LIBCPP_STD_VER >= 20 |
| 94 | |
| 95 | _LIBCPP_END_NAMESPACE_STD |
| 96 | |
| 97 | _LIBCPP_POP_MACROS |
| 98 | |
| 99 | #endif // _LIBCPP___RANGES_RANGE_ADAPTOR_H |
| 100 | |