diff --git a/libstdc++-v3/include/std/ranges b/libstdc++-v3/include/std/ranges index adbc6d7b274ef4e9528e10c5a75235bc9f534f20..978578197dc050efaf85a89d5657007cc43b5880 100644 --- a/libstdc++-v3/include/std/ranges +++ b/libstdc++-v3/include/std/ranges @@ -724,168 +724,172 @@ namespace __detail } // namespace __detail -namespace views +namespace views::__adaptor { - namespace __adaptor + // True if the range adaptor _Adaptor can be applied with _Args. + template<typename _Adaptor, typename... _Args> + concept __adaptor_invocable + = requires { std::declval<_Adaptor>()(declval<_Args>()...); }; + + // True if the range adaptor non-closure _Adaptor can be partially applied + // with _Args. + template<typename _Adaptor, typename... _Args> + concept __adaptor_partial_app_viable = (_Adaptor::_S_arity > 1) + && (sizeof...(_Args) == _Adaptor::_S_arity - 1) + && (constructible_from<decay_t<_Args>, _Args> && ...); + + template<typename _Adaptor, typename... _Args> + struct _Partial; + + template<typename _Lhs, typename _Rhs> + struct _Pipe; + + // The base class of every range adaptor closure. + struct _RangeAdaptorClosure { - template<typename _Tp> - inline constexpr auto - __maybe_refwrap(_Tp& __arg) - { return reference_wrapper<_Tp>{__arg}; } + // range | adaptor is equivalent to adaptor(range). + template<typename _Self, typename _Range> + requires derived_from<remove_cvref_t<_Self>, _RangeAdaptorClosure> + && __adaptor_invocable<_Self, _Range> + friend constexpr auto + operator|(_Range&& __r, _Self&& __self) + { return std::forward<_Self>(__self)(std::forward<_Range>(__r)); } + + // Compose the adaptors __lhs and __rhs into a pipeline, returning + // another range adaptor closure object. + template<typename _Lhs, typename _Rhs> + requires derived_from<_Lhs, _RangeAdaptorClosure> + && derived_from<_Rhs, _RangeAdaptorClosure> + friend constexpr auto + operator|(_Lhs __lhs, _Rhs __rhs) + { return _Pipe<_Lhs, _Rhs>{std::move(__lhs), std::move(__rhs)}; } + }; - template<typename _Tp> - inline constexpr auto - __maybe_refwrap(const _Tp& __arg) - { return reference_wrapper<const _Tp>{__arg}; } + // The base class of every range adaptor non-closure. + // + // The static data member _Derived::_S_arity must contain the total number of + // arguments that the adaptor takes, and the class _Derived must introduce + // _RangeAdaptor::operator() into the class scope via a using-declaration. + template<typename _Derived> + struct _RangeAdaptor + { + // Partially apply the arguments __args to the range adaptor _Derived, + // returning a range adaptor closure object. + template<typename... _Args> + requires __adaptor_partial_app_viable<_Derived, _Args...> + constexpr auto + operator()(_Args&&... __args) const + { + return _Partial<_Derived, decay_t<_Args>...>{std::forward<_Args>(__args)...}; + } + }; - template<typename _Tp> - inline constexpr decltype(auto) - __maybe_refwrap(_Tp&& __arg) - { return std::forward<_Tp>(__arg); } + // A range adaptor closure that represents partial application of + // the range adaptor _Adaptor with arguments _Args. + template<typename _Adaptor, typename... _Args> + struct _Partial : _RangeAdaptorClosure + { + tuple<_Args...> _M_args; - template<typename _Callable> - struct _RangeAdaptorClosure; + constexpr + _Partial(_Args... __args) + : _M_args(std::move(__args)...) + { } - template<typename _Callable> - struct _RangeAdaptor - { - protected: - [[no_unique_address]] - __detail::__maybe_present_t<!is_default_constructible_v<_Callable>, - _Callable> _M_callable; + // Invoke _Adaptor with arguments __r, _M_args... according to the + // value category of the range adaptor closure object. + template<typename _Range> + requires __adaptor_invocable<_Adaptor, _Range, const _Args&...> + constexpr auto + operator()(_Range&& __r) const & + { + auto __forwarder = [&__r] (const auto&... __args) { + return _Adaptor{}(std::forward<_Range>(__r), __args...); + }; + return std::apply(__forwarder, _M_args); + } - public: - constexpr - _RangeAdaptor(const _Callable& = {}) - requires is_default_constructible_v<_Callable> - { } + template<typename _Range> + requires __adaptor_invocable<_Adaptor, _Range, _Args...> + constexpr auto + operator()(_Range&& __r) && + { + auto __forwarder = [&__r] (auto&... __args) { + return _Adaptor{}(std::forward<_Range>(__r), std::move(__args)...); + }; + return std::apply(__forwarder, _M_args); + } - constexpr - _RangeAdaptor(_Callable __callable) - requires (!is_default_constructible_v<_Callable>) - : _M_callable(std::move(__callable)) - { } + template<typename _Range> + constexpr auto + operator()(_Range&& __r) const && = delete; + }; - template<typename... _Args> - requires (sizeof...(_Args) >= 1) - constexpr auto - operator()(_Args&&... __args) const - { - // [range.adaptor.object]: If a range adaptor object accepts more - // than one argument, then the following expressions are equivalent: - // - // (1) adaptor(range, args...) - // (2) adaptor(args...)(range) - // (3) range | adaptor(args...) - // - // In this case, adaptor(args...) is a range adaptor closure object. - // - // We handle (1) and (2) here, and (3) is just a special case of a - // more general case already handled by _RangeAdaptorClosure. - if constexpr (is_invocable_v<_Callable, _Args...>) - { - static_assert(sizeof...(_Args) != 1, - "a _RangeAdaptor that accepts only one argument " - "should be defined as a _RangeAdaptorClosure"); - // Here we handle adaptor(range, args...) -- just forward all - // arguments to the underlying adaptor routine. - return _Callable{}(std::forward<_Args>(__args)...); - } - else - { - // Here we handle adaptor(args...)(range). - // Given args..., we return a _RangeAdaptorClosure that takes a - // range argument, such that (2) is equivalent to (1). - // - // We need to be careful about how we capture args... in this - // closure. By using __maybe_refwrap, we capture lvalue - // references by reference (through a reference_wrapper) and - // otherwise capture by value. - auto __closure - = [...__args(__maybe_refwrap(std::forward<_Args>(__args)))] - <typename _Range> (_Range&& __r) { - // This static_cast has two purposes: it forwards a - // reference_wrapper<T> capture as a T&, and otherwise - // forwards the captured argument as an rvalue. - return _Callable{}(std::forward<_Range>(__r), - (static_cast<unwrap_reference_t - <remove_const_t<decltype(__args)>>> - (__args))...); - }; - using _ClosureType = decltype(__closure); - return _RangeAdaptorClosure<_ClosureType>(std::move(__closure)); - } - } - }; + // A lightweight specialization of the above primary template for + // the common case where _Adaptor accepts a single extra argument. + template<typename _Adaptor, typename _Arg> + struct _Partial<_Adaptor, _Arg> : _RangeAdaptorClosure + { + _Arg _M_arg; - template<typename _Callable> - _RangeAdaptor(_Callable) -> _RangeAdaptor<_Callable>; + constexpr + _Partial(_Arg __arg) + : _M_arg(std::move(__arg)) + { } - template<typename _Callable> - struct _RangeAdaptorClosure : public _RangeAdaptor<_Callable> - { - using _RangeAdaptor<_Callable>::_RangeAdaptor; + template<typename _Range> + requires __adaptor_invocable<_Adaptor, _Range, const _Arg&> + constexpr auto + operator()(_Range&& __r) const & + { return _Adaptor{}(std::forward<_Range>(__r), _M_arg); } + + template<typename _Range> + requires __adaptor_invocable<_Adaptor, _Range, _Arg> + constexpr auto + operator()(_Range&& __r) && + { return _Adaptor{}(std::forward<_Range>(__r), std::move(_M_arg)); } + + template<typename _Range> + constexpr auto + operator()(_Range&& __r) const && = delete; + }; - template<viewable_range _Range> - requires requires { declval<_Callable>()(declval<_Range>()); } - constexpr auto - operator()(_Range&& __r) const - { - if constexpr (is_default_constructible_v<_Callable>) - return _Callable{}(std::forward<_Range>(__r)); - else - return this->_M_callable(std::forward<_Range>(__r)); - } + template<typename _Lhs, typename _Rhs, typename _Range> + concept __pipe_invocable + = requires { std::declval<_Rhs>()(std::declval<_Lhs>()(std::declval<_Range>())); }; - template<viewable_range _Range> - requires requires { declval<_Callable>()(declval<_Range>()); } - friend constexpr auto - operator|(_Range&& __r, const _RangeAdaptorClosure& __o) - { return __o(std::forward<_Range>(__r)); } + // A range adaptor closure that represents composition of the range + // adaptor closures _Lhs and _Rhs. + template<typename _Lhs, typename _Rhs> + struct _Pipe : _RangeAdaptorClosure + { + [[no_unique_address]] _Lhs _M_lhs; + [[no_unique_address]] _Rhs _M_rhs; - template<typename _Tp> - friend constexpr auto - operator|(const _RangeAdaptorClosure<_Tp>& __x, - const _RangeAdaptorClosure& __y) - { - if constexpr (is_default_constructible_v<_Tp> - && is_default_constructible_v<_Callable>) - { - auto __closure = [] <typename _Up> (_Up&& __e) { - return std::forward<_Up>(__e) | decltype(__x){} | decltype(__y){}; - }; - return _RangeAdaptorClosure<decltype(__closure)>(__closure); - } - else if constexpr (is_default_constructible_v<_Tp> - && !is_default_constructible_v<_Callable>) - { - auto __closure = [__y] <typename _Up> (_Up&& __e) { - return std::forward<_Up>(__e) | decltype(__x){} | __y; - }; - return _RangeAdaptorClosure<decltype(__closure)>(__closure); - } - else if constexpr (!is_default_constructible_v<_Tp> - && is_default_constructible_v<_Callable>) - { - auto __closure = [__x] <typename _Up> (_Up&& __e) { - return std::forward<_Up>(__e) | __x | decltype(__y){}; - }; - return _RangeAdaptorClosure<decltype(__closure)>(__closure); - } - else - { - auto __closure = [__x, __y] <typename _Up> (_Up&& __e) { - return std::forward<_Up>(__e) | __x | __y; - }; - return _RangeAdaptorClosure<decltype(__closure)>(__closure); - } - } - }; + constexpr + _Pipe(_Lhs __lhs, _Rhs __rhs) + : _M_lhs(std::move(__lhs)), _M_rhs(std::move(__rhs)) + { } - template<typename _Callable> - _RangeAdaptorClosure(_Callable) -> _RangeAdaptorClosure<_Callable>; - } // namespace __adaptor -} // namespace views + // Invoke _M_rhs(_M_lhs(__r)) according to the value category of this + // range adaptor closure object. + template<typename _Range> + requires __pipe_invocable<const _Lhs&, const _Rhs&, _Range> + constexpr auto + operator()(_Range&& __r) const & + { return _M_rhs(_M_lhs(std::forward<_Range>(__r))); } + + template<typename _Range> + requires __pipe_invocable<_Lhs, _Rhs, _Range> + constexpr auto + operator()(_Range&& __r) && + { return std::move(_M_rhs)(std::move(_M_lhs)(std::forward<_Range>(__r))); } + + template<typename _Range> + constexpr auto + operator()(_Range&& __r) const && = delete; + }; +} // namespace views::__adaptor template<range _Range> requires is_object_v<_Range> class ref_view : public view_interface<ref_view<_Range>> @@ -941,20 +945,37 @@ namespace views namespace views { - inline constexpr __adaptor::_RangeAdaptorClosure all - = [] <viewable_range _Range> (_Range&& __r) - { - if constexpr (view<decay_t<_Range>>) - return std::forward<_Range>(__r); - else if constexpr (requires { ref_view{std::forward<_Range>(__r)}; }) - return ref_view{std::forward<_Range>(__r)}; - else - return subrange{std::forward<_Range>(__r)}; - }; + namespace __detail + { + template<typename _Range> + concept __can_ref_view = requires { ref_view{std::declval<_Range>()}; }; + + template<typename _Range> + concept __can_subrange = requires { subrange{std::declval<_Range>()}; }; + } // namespace __detail + + struct _All : __adaptor::_RangeAdaptorClosure + { + template<viewable_range _Range> + requires view<decay_t<_Range>> + || __detail::__can_ref_view<_Range> + || __detail::__can_subrange<_Range> + constexpr auto + operator()(_Range&& __r) const + { + if constexpr (view<decay_t<_Range>>) + return std::forward<_Range>(__r); + else if constexpr (__detail::__can_ref_view<_Range>) + return ref_view{std::forward<_Range>(__r)}; + else + return subrange{std::forward<_Range>(__r)}; + } + }; + + inline constexpr _All all; template<viewable_range _Range> using all_t = decltype(all(std::declval<_Range>())); - } // namespace views // XXX: the following algos are copied from ranges_algo.h to avoid a circular @@ -1305,11 +1326,28 @@ namespace views namespace views { - inline constexpr __adaptor::_RangeAdaptor filter - = [] <viewable_range _Range, typename _Pred> (_Range&& __r, _Pred&& __p) - { - return filter_view{std::forward<_Range>(__r), std::forward<_Pred>(__p)}; - }; + namespace __detail + { + template<typename _Range, typename _Pred> + concept __can_filter_view + = requires { filter_view{std::declval<_Range>(), std::declval<_Pred>()}; }; + } // namespace __detail + + struct _Filter : __adaptor::_RangeAdaptor<_Filter> + { + template<viewable_range _Range, typename _Pred> + requires __detail::__can_filter_view<_Range, _Pred> + constexpr auto + operator()(_Range&& __r, _Pred&& __p) const + { + return filter_view{std::forward<_Range>(__r), std::forward<_Pred>(__p)}; + } + + using _RangeAdaptor<_Filter>::operator(); + static constexpr int _S_arity = 2; + }; + + inline constexpr _Filter filter; } // namespace views template<input_range _Vp, copy_constructible _Fp> @@ -1653,11 +1691,28 @@ namespace views namespace views { - inline constexpr __adaptor::_RangeAdaptor transform - = [] <viewable_range _Range, typename _Fp> (_Range&& __r, _Fp&& __f) - { - return transform_view{std::forward<_Range>(__r), std::forward<_Fp>(__f)}; - }; + namespace __detail + { + template<typename _Range, typename _Fp> + concept __can_transform_view + = requires { transform_view{std::declval<_Range>(), std::declval<_Fp>()}; }; + } // namespace __detail + + struct _Transform : __adaptor::_RangeAdaptor<_Transform> + { + template<viewable_range _Range, typename _Fp> + requires __detail::__can_transform_view<_Range, _Fp> + constexpr auto + operator()(_Range&& __r, _Fp&& __f) const + { + return transform_view{std::forward<_Range>(__r), std::forward<_Fp>(__f)}; + } + + using _RangeAdaptor<_Transform>::operator(); + static constexpr int _S_arity = 2; + }; + + inline constexpr _Transform transform; } // namespace views template<view _Vp> @@ -1816,11 +1871,28 @@ namespace views namespace views { - inline constexpr __adaptor::_RangeAdaptor take - = [] <viewable_range _Range, typename _Tp> (_Range&& __r, _Tp&& __n) - { - return take_view{std::forward<_Range>(__r), std::forward<_Tp>(__n)}; - }; + namespace __detail + { + template<typename _Range, typename _Tp> + concept __can_take_view + = requires { take_view{std::declval<_Range>(), std::declval<_Tp>()}; }; + } // namespace __detail + + struct _Take : __adaptor::_RangeAdaptor<_Take> + { + template<viewable_range _Range, typename _Tp> + requires __detail::__can_take_view<_Range, _Tp> + constexpr auto + operator()(_Range&& __r, _Tp&& __n) const + { + return take_view{std::forward<_Range>(__r), std::forward<_Tp>(__n)}; + } + + using _RangeAdaptor<_Take>::operator(); + static constexpr int _S_arity = 2; + }; + + inline constexpr _Take take; } // namespace views template<view _Vp, typename _Pred> @@ -1918,11 +1990,28 @@ namespace views namespace views { - inline constexpr __adaptor::_RangeAdaptor take_while - = [] <viewable_range _Range, typename _Pred> (_Range&& __r, _Pred&& __p) - { - return take_while_view{std::forward<_Range>(__r), std::forward<_Pred>(__p)}; - }; + namespace __detail + { + template<typename _Range, typename _Pred> + concept __can_take_while_view + = requires { take_while_view{std::declval<_Range>(), std::declval<_Pred>()}; }; + } // namespace __detail + + struct _TakeWhile : __adaptor::_RangeAdaptor<_TakeWhile> + { + template<viewable_range _Range, typename _Pred> + requires __detail::__can_take_while_view<_Range, _Pred> + constexpr auto + operator()(_Range&& __r, _Pred&& __p) const + { + return take_while_view{std::forward<_Range>(__r), std::forward<_Pred>(__p)}; + } + + using _RangeAdaptor<_TakeWhile>::operator(); + static constexpr int _S_arity = 2; + }; + + inline constexpr _TakeWhile take_while; } // namespace views template<view _Vp> @@ -2020,11 +2109,28 @@ namespace views namespace views { - inline constexpr __adaptor::_RangeAdaptor drop - = [] <viewable_range _Range, typename _Tp> (_Range&& __r, _Tp&& __n) - { - return drop_view{std::forward<_Range>(__r), std::forward<_Tp>(__n)}; - }; + namespace __detail + { + template<typename _Range, typename _Tp> + concept __can_drop_view + = requires { drop_view{std::declval<_Range>(), std::declval<_Tp>()}; }; + } // namespace __detail + + struct _Drop : __adaptor::_RangeAdaptor<_Drop> + { + template<viewable_range _Range, typename _Tp> + requires __detail::__can_drop_view<_Range, _Tp> + constexpr auto + operator()(_Range&& __r, _Tp&& __n) const + { + return drop_view{std::forward<_Range>(__r), std::forward<_Tp>(__n)}; + } + + using _RangeAdaptor<_Drop>::operator(); + static constexpr int _S_arity = 2; + }; + + inline constexpr _Drop drop; } // namespace views template<view _Vp, typename _Pred> @@ -2085,12 +2191,29 @@ namespace views namespace views { - inline constexpr __adaptor::_RangeAdaptor drop_while - = [] <viewable_range _Range, typename _Pred> (_Range&& __r, _Pred&& __p) - { - return drop_while_view{std::forward<_Range>(__r), - std::forward<_Pred>(__p)}; - }; + namespace __detail + { + template<typename _Range, typename _Pred> + concept __can_drop_while_view + = requires { drop_while_view{std::declval<_Range>(), std::declval<_Pred>()}; }; + } // namespace __detail + + struct _DropWhile : __adaptor::_RangeAdaptor<_DropWhile> + { + template<viewable_range _Range, typename _Pred> + requires __detail::__can_drop_while_view<_Range, _Pred> + constexpr auto + operator()(_Range&& __r, _Pred&& __p) const + { + return drop_while_view{std::forward<_Range>(__r), + std::forward<_Pred>(__p)}; + } + + using _RangeAdaptor<_DropWhile>::operator(); + static constexpr int _S_arity = 2; + }; + + inline constexpr _DropWhile drop_while; } // namespace views template<input_range _Vp> @@ -2409,13 +2532,27 @@ namespace views namespace views { - inline constexpr __adaptor::_RangeAdaptorClosure join - = [] <viewable_range _Range> (_Range&& __r) - { - // _GLIBCXX_RESOLVE_LIB_DEFECTS - // 3474. Nesting join_views is broken because of CTAD - return join_view<views::all_t<_Range>>{std::forward<_Range>(__r)}; - }; + namespace __detail + { + template<typename _Range> + concept __can_join_view + = requires { join_view<all_t<_Range>>{std::declval<_Range>()}; }; + } // namespace __detail + + struct _Join : __adaptor::_RangeAdaptorClosure + { + template<viewable_range _Range> + requires __detail::__can_join_view<_Range> + constexpr auto + operator()(_Range&& __r) const + { + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 3474. Nesting join_views is broken because of CTAD + return join_view<all_t<_Range>>{std::forward<_Range>(__r)}; + } + }; + + inline constexpr _Join join; } // namespace views namespace __detail @@ -2784,9 +2921,9 @@ namespace views } }; - template<typename _Range, typename _Pred> - split_view(_Range&&, _Pred&&) - -> split_view<views::all_t<_Range>, views::all_t<_Pred>>; + template<typename _Range, typename _Pattern> + split_view(_Range&&, _Pattern&&) + -> split_view<views::all_t<_Range>, views::all_t<_Pattern>>; template<input_range _Range> split_view(_Range&&, range_value_t<_Range>) @@ -2794,11 +2931,28 @@ namespace views namespace views { - inline constexpr __adaptor::_RangeAdaptor split - = [] <viewable_range _Range, typename _Fp> (_Range&& __r, _Fp&& __f) - { - return split_view{std::forward<_Range>(__r), std::forward<_Fp>(__f)}; - }; + namespace __detail + { + template<typename _Range, typename _Pattern> + concept __can_split_view + = requires { split_view{std::declval<_Range>(), std::declval<_Pattern>()}; }; + } // namespace __detail + + struct _Split : __adaptor::_RangeAdaptor<_Split> + { + template<viewable_range _Range, typename _Pattern> + requires __detail::__can_split_view<_Range, _Pattern> + constexpr auto + operator()(_Range&& __r, _Pattern&& __f) const + { + return split_view{std::forward<_Range>(__r), std::forward<_Pattern>(__f)}; + } + + using _RangeAdaptor<_Split>::operator(); + static constexpr int _S_arity = 2; + }; + + inline constexpr _Split split; } // namespace views namespace views @@ -2911,16 +3065,33 @@ namespace views namespace views { - inline constexpr __adaptor::_RangeAdaptorClosure common - = [] <viewable_range _Range> (_Range&& __r) - { - if constexpr (common_range<_Range> - && requires { views::all(std::forward<_Range>(__r)); }) - return views::all(std::forward<_Range>(__r)); - else - return common_view{std::forward<_Range>(__r)}; - }; + namespace __detail + { + template<typename _Range> + concept __already_common = common_range<_Range> + && requires { views::all(std::declval<_Range>()); }; + + template<typename _Range> + concept __can_common_view + = requires { common_view{std::declval<_Range>()}; }; + } // namespace __detail + + struct _Common : __adaptor::_RangeAdaptorClosure + { + template<viewable_range _Range> + requires __detail::__already_common<_Range> + || __detail::__can_common_view<_Range> + constexpr auto + operator()(_Range&& __r) const + { + if constexpr (__detail::__already_common<_Range>) + return views::all(std::forward<_Range>(__r)); + else + return common_view{std::forward<_Range>(__r)}; + } + }; + inline constexpr _Common common; } // namespace views template<view _Vp> @@ -3016,27 +3187,40 @@ namespace views template<typename _Vp> inline constexpr bool __is_reverse_view<reverse_view<_Vp>> = true; - } - inline constexpr __adaptor::_RangeAdaptorClosure reverse - = [] <viewable_range _Range> (_Range&& __r) - { - using _Tp = remove_cvref_t<_Range>; - if constexpr (__detail::__is_reverse_view<_Tp>) - return std::forward<_Range>(__r).base(); - else if constexpr (__detail::__is_reversible_subrange<_Tp>) - { - using _Iter = decltype(ranges::begin(__r).base()); - if constexpr (sized_range<_Tp>) - return subrange<_Iter, _Iter, subrange_kind::sized> - (__r.end().base(), __r.begin().base(), __r.size()); - else - return subrange<_Iter, _Iter, subrange_kind::unsized> - (__r.end().base(), __r.begin().base()); - } - else - return reverse_view{std::forward<_Range>(__r)}; - }; + template<typename _Range> + concept __can_reverse_view + = requires { reverse_view{std::declval<_Range>()}; }; + } // namespace __detail + + struct _Reverse : __adaptor::_RangeAdaptorClosure + { + template<viewable_range _Range> + requires __detail::__is_reverse_view<remove_cvref_t<_Range>> + || __detail::__is_reversible_subrange<remove_cvref_t<_Range>> + || __detail::__can_reverse_view<_Range> + constexpr auto + operator()(_Range&& __r) const + { + using _Tp = remove_cvref_t<_Range>; + if constexpr (__detail::__is_reverse_view<_Tp>) + return std::forward<_Range>(__r).base(); + else if constexpr (__detail::__is_reversible_subrange<_Tp>) + { + using _Iter = decltype(ranges::begin(__r).base()); + if constexpr (sized_range<_Tp>) + return subrange<_Iter, _Iter, subrange_kind::sized> + {__r.end().base(), __r.begin().base(), __r.size()}; + else + return subrange<_Iter, _Iter, subrange_kind::unsized> + {__r.end().base(), __r.begin().base()}; + } + else + return reverse_view{std::forward<_Range>(__r)}; + } + }; + + inline constexpr _Reverse reverse; } // namespace views namespace __detail @@ -3335,16 +3519,29 @@ namespace views namespace views { + namespace __detail + { + template<size_t _Nm, typename _Range> + concept __can_elements_view + = requires { elements_view<all_t<_Range>, _Nm>{std::declval<_Range>()}; }; + } // namespace __detail + template<size_t _Nm> - inline constexpr __adaptor::_RangeAdaptorClosure elements - = [] <viewable_range _Range> (_Range&& __r) + struct _Elements : __adaptor::_RangeAdaptorClosure { - using _El = elements_view<views::all_t<_Range>, _Nm>; - return _El{std::forward<_Range>(__r)}; + template<viewable_range _Range> + requires __detail::__can_elements_view<_Nm, _Range> + constexpr auto + operator()(_Range&& __r) const + { + return elements_view<all_t<_Range>, _Nm>{std::forward<_Range>(__r)}; + } }; - inline constexpr __adaptor::_RangeAdaptorClosure keys = elements<0>; - inline constexpr __adaptor::_RangeAdaptorClosure values = elements<1>; + template<size_t _Nm> + inline constexpr _Elements<_Nm> elements; + inline constexpr auto keys = elements<0>; + inline constexpr auto values = elements<1>; } // namespace views } // namespace ranges diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/99433.cc b/libstdc++-v3/testsuite/std/ranges/adaptors/99433.cc new file mode 100644 index 0000000000000000000000000000000000000000..b9d17942e176d0821d4774733eae804aa6ddfc2c --- /dev/null +++ b/libstdc++-v3/testsuite/std/ranges/adaptors/99433.cc @@ -0,0 +1,41 @@ +// Copyright (C) 2021 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// <http://www.gnu.org/licenses/>. + +// { dg-options "-std=gnu++2a" } +// { dg-do compile { target c++2a } } + +// PR libstdc++/99433 + +#include <ranges> +#include <vector> + +template <typename underlying_adaptor_t> +struct deep +{ + underlying_adaptor_t adaptor; + + template <typename range_t> + friend auto operator|(range_t &range, deep const &me) + { + return me.adaptor(range[0]); + } +}; + +auto f = [] (auto nucl) { return nucl + ' '; }; +auto complement = deep{std::views::transform(f)}; +std::vector<std::vector<char>> foo{}; +auto v = foo | complement; diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/all.cc b/libstdc++-v3/testsuite/std/ranges/adaptors/all.cc index 33e4b96686e3df4b7896cfa4ed8796c45e150dc1..42913ad38a303ce89cb97beca01d2ff3c673ae5f 100644 --- a/libstdc++-v3/testsuite/std/ranges/adaptors/all.cc +++ b/libstdc++-v3/testsuite/std/ranges/adaptors/all.cc @@ -103,6 +103,12 @@ static_assert(std::is_empty_v<decltype(views::common | views::common | views::keys | views::reverse)>); +#if 0 +// Adding empty range adaptor closure objects to a pipeline used to not +// increase the size of the pipeline, but now that our range adaptor closure +// objects derive from a common empty base class, [[no_unique_address]] can no +// longer make two empty adjacent range adaptor closure objects occupy the same +// data member address. static_assert(sizeof(decltype(views::take(5) | views::drop(5))) == sizeof(decltype(views::take(5) | views::join @@ -111,6 +117,18 @@ static_assert(sizeof(decltype(views::take(5) | views::drop(5))) | views::keys | views::drop(5) | views::reverse))); +#endif + +template<auto all = views::all> +void +test05() +{ + // Verify SFINAE behavior. + static_assert(!requires { all(); }); + static_assert(!requires { all(0, 0); }); + static_assert(!requires { all(0); }); + static_assert(!requires { 0 | all; }); +} int main() @@ -119,4 +137,5 @@ main() test02(); static_assert(test03()); static_assert(test04()); + test05(); } diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/common.cc b/libstdc++-v3/testsuite/std/ranges/adaptors/common.cc index 719b25be006a5e00e7e0da4b6551a08e00387957..085e8ff907dd80d3965e230cf15de97ab704d83f 100644 --- a/libstdc++-v3/testsuite/std/ranges/adaptors/common.cc +++ b/libstdc++-v3/testsuite/std/ranges/adaptors/common.cc @@ -60,9 +60,21 @@ test02() VERIFY( std::count(v2.begin(), v2.end(), 1) == 2); } +template<auto common = views::common> +void +test03() +{ + // Verify SFINAE behavior. + static_assert(!requires { common(); }); + static_assert(!requires { common(0, 0); }); + static_assert(!requires { common(0); }); + static_assert(!requires { 0 | common; }); +} + int main() { test01(); test02(); + test03(); } diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/drop.cc b/libstdc++-v3/testsuite/std/ranges/adaptors/drop.cc index 19afba8a9ae075c8d2e25cb2e36cbbcb3743a9cb..c0525109bd1be31e2c55594f0c850f49ba40216e 100644 --- a/libstdc++-v3/testsuite/std/ranges/adaptors/drop.cc +++ b/libstdc++-v3/testsuite/std/ranges/adaptors/drop.cc @@ -258,6 +258,23 @@ test08() VERIFY( ra_test_wrapper<long>::increment_count == 0 ); } +template<auto drop = views::drop> +void +test09() +{ + // Verify SFINAE behavior. + extern int x[5]; + int* n = 0; + static_assert(!requires { drop(); }); + static_assert(!requires { drop(x, n, n); }); + static_assert(!requires { drop(x, n); }); + static_assert(!requires { drop(n)(x); }); + static_assert(!requires { x | (drop(n) | views::all); }); + static_assert(!requires { (drop(n) | views::all)(x); }); + static_assert(!requires { drop | views::all; }); + static_assert(!requires { views::all | drop; }); +} + int main() { @@ -269,4 +286,5 @@ main() test06(); test07(); test08(); + test09(); } diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/drop_while.cc b/libstdc++-v3/testsuite/std/ranges/adaptors/drop_while.cc index e807388538ba9bbd14fa3f1dce68510191969fbf..58489d54f8965e9fef2052beada7d8369f8b46f4 100644 --- a/libstdc++-v3/testsuite/std/ranges/adaptors/drop_while.cc +++ b/libstdc++-v3/testsuite/std/ranges/adaptors/drop_while.cc @@ -89,6 +89,23 @@ test03() VERIFY( ranges::equal(v, (int[]){3,4,5}) ); } +template<auto drop_while = views::drop_while> +void +test04() +{ + // Verify SFINAE behavior. + extern int x[5]; + auto p = [] (int*) { return true; }; + static_assert(!requires { drop_while(); }); + static_assert(!requires { drop_while(x, p, p); }); + static_assert(!requires { drop_while(x, p); }); + static_assert(!requires { drop_while(p)(x); }); + static_assert(!requires { x | (drop_while(p) | views::all); }); + static_assert(!requires { (drop_while(p) | views::all)(x); }); + static_assert(!requires { drop_while | views::all; }); + static_assert(!requires { views::all | drop_while; }); +} + int main() { @@ -96,4 +113,5 @@ main() test02(); test03<forward_iterator_wrapper>(); test03<random_access_iterator_wrapper>(); + test04(); } diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/elements.cc b/libstdc++-v3/testsuite/std/ranges/adaptors/elements.cc index 768077720068acf457736eeee170ed449585c764..b0d122f8db5f2dc59bd658baa813bf8c1f149c10 100644 --- a/libstdc++-v3/testsuite/std/ranges/adaptors/elements.cc +++ b/libstdc++-v3/testsuite/std/ranges/adaptors/elements.cc @@ -89,10 +89,22 @@ test03() VERIFY( (next(b_const, 2) - b_const) == 2 ); } +template<auto elements = views::elements<0>> +void +test04() +{ + // Verify SFINAE behavior. + static_assert(!requires { elements(); }); + static_assert(!requires { elements(0, 0); }); + static_assert(!requires { elements(0); }); + static_assert(!requires { 0 | elements; }); +} + int main() { test01(); test02(); test03(); + test04(); } diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/filter.cc b/libstdc++-v3/testsuite/std/ranges/adaptors/filter.cc index c60eec51368c4ee9e266683e1f0c0308d7b21dd9..e0f6b8d4c4b439e8f8d2c46ac7d536fc77d82bbe 100644 --- a/libstdc++-v3/testsuite/std/ranges/adaptors/filter.cc +++ b/libstdc++-v3/testsuite/std/ranges/adaptors/filter.cc @@ -123,6 +123,23 @@ test05() VERIFY( ranges::equal(v, (int[]){2,4}) ); } +template<auto filter = views::filter> +void +test06() +{ + // Verify SFINAE behavior. + extern int x[5]; + auto p = [] (int*) { return true; }; + static_assert(!requires { filter(); }); + static_assert(!requires { filter(x, p, p); }); + static_assert(!requires { filter(x, p); }); + static_assert(!requires { filter(p)(x); }); + static_assert(!requires { x | (filter(p) | views::all); }); + static_assert(!requires { (filter(p) | views::all)(x); }); + static_assert(!requires { filter | views::all; }); + static_assert(!requires { views::all | filter; }); +} + int main() { @@ -132,4 +149,5 @@ main() test04(); test05<forward_iterator_wrapper>(); test05<random_access_iterator_wrapper>(); + test06(); } diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/join.cc b/libstdc++-v3/testsuite/std/ranges/adaptors/join.cc index 6d780f4887b43a7e90bdccfe7c0b287d912cef8e..fb06a7698afc1d75fc598858d126934d9ff01556 100644 --- a/libstdc++-v3/testsuite/std/ranges/adaptors/join.cc +++ b/libstdc++-v3/testsuite/std/ranges/adaptors/join.cc @@ -149,6 +149,17 @@ test08() VERIFY( i->a == 5 ); } +template<auto join = views::join> +void +test09() +{ + // Verify SFINAE behavior. + static_assert(!requires { join(); }); + static_assert(!requires { join(0, 0); }); + static_assert(!requires { join(0); }); + static_assert(!requires { 0 | join; }); +} + int main() { @@ -160,4 +171,5 @@ main() test06(); test07(); test08(); + test09(); } diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/p2281.cc b/libstdc++-v3/testsuite/std/ranges/adaptors/p2281.cc new file mode 100644 index 0000000000000000000000000000000000000000..c916a5ea8b7a9eb0f08aadb83339e45f6a45b853 --- /dev/null +++ b/libstdc++-v3/testsuite/std/ranges/adaptors/p2281.cc @@ -0,0 +1,83 @@ +// Copyright (C) 2021 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// <http://www.gnu.org/licenses/>. + +// { dg-options "-std=gnu++2a" } +// { dg-do run { target c++2a } } + +#include <algorithm> +#include <ranges> +#include <string> +#include <string_view> +#include <testsuite_hooks.h> + +namespace ranges = std::ranges; +namespace views = std::ranges::views; + +// Verify P2281 changes to the forwarding semantics of partial application +// and composition of range adaptor objects. + +void +test01() +{ + auto split_into_strings = [] (auto p) { + return views::split(p) | views::transform([](auto r){ + return std::string(r.begin(), ranges::next(r.begin(), r.end())); + }); + }; + constexpr std::string_view s = "hello world"; + constexpr std::string_view p = " "; + constexpr auto v1 = s | split_into_strings(p); + constexpr auto v2 = split_into_strings(p)(s); + VERIFY( ranges::equal(v1, (std::string_view[]){"hello", "world"}) ); + VERIFY( ranges::equal(v2, (std::string_view[]){"hello", "world"}) ); +} + +struct move_only_range +{ + move_only_range() { } + move_only_range(move_only_range&&); + move_only_range& operator=(move_only_range&&); + move_only_range(const move_only_range&) = delete; + move_only_range& operator=(const move_only_range&) = delete; + char* begin(); + char* end(); +}; + +template<> + inline constexpr bool std::ranges::enable_view<move_only_range> = true; + +template<auto split = views::split> +void +test02() +{ + std::string_view s; + move_only_range p; + static_assert(requires { s | split(std::move(p)); }); + static_assert(requires { split(std::move(p))(s); }); + static_assert(requires { split(std::move(p)) | views::all; }); + static_assert(requires { views::all | split(std::move(p)); }); + static_assert(!requires { split(p); }); + static_assert(!requires { split(p) | views::all; }); + static_assert(!requires { views::all | split(p); }); +} + +int +main() +{ + test01(); + test02(); +} diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/reverse.cc b/libstdc++-v3/testsuite/std/ranges/adaptors/reverse.cc index 0d52498e207f250e33cc9f80c5c9344adaf32881..47e34eb6581fe2ea763370aabe5eb6e49473c288 100644 --- a/libstdc++-v3/testsuite/std/ranges/adaptors/reverse.cc +++ b/libstdc++-v3/testsuite/std/ranges/adaptors/reverse.cc @@ -138,7 +138,8 @@ namespace test_ns void make_reverse_iterator(T&&) {} } // namespace test_ns -void test06() +void +test06() { // Check that views::reverse works and does not use ADL which could lead // to accidentally finding test_ns::make_reverse_iterator(A*). @@ -149,6 +150,17 @@ void test06() static_assert( std::ranges::range<const V> ); } +template<auto reverse = views::reverse> +void +test07() +{ + // Verify SFINAE behavior. + static_assert(!requires { reverse(); }); + static_assert(!requires { reverse(0, 0); }); + static_assert(!requires { reverse(0); }); + static_assert(!requires { 0 | reverse; }); +} + int main() { @@ -158,4 +170,5 @@ main() test04(); test05(); test06(); + test07(); } diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/split.cc b/libstdc++-v3/testsuite/std/ranges/adaptors/split.cc index dc7f55a2f92c8468de207a12010619cc312cb8fd..b9fb3728708adb2ff89f41775819d91bdfa7070c 100644 --- a/libstdc++-v3/testsuite/std/ranges/adaptors/split.cc +++ b/libstdc++-v3/testsuite/std/ranges/adaptors/split.cc @@ -39,7 +39,7 @@ test01() { auto x = "the quick brown fox"sv; auto p = std::string{" "}; - auto v = x | views::split(p); + auto v = x | views::split(views::all(p)); // views::all is needed here after P2281. auto i = v.begin(); VERIFY( ranges::equal(*i++, "the"sv) ); VERIFY( ranges::equal(*i++, "quick"sv) ); @@ -83,7 +83,7 @@ test04() static_assert(!ranges::view<decltype(p)>); static_assert(std::same_as<decltype(p | views::all), ranges::ref_view<decltype(p)>>); - auto v = x | views::split(p); + auto v = x | views::split(views::all(p)); // views::all is needed here after P2281. auto i = v.begin(); VERIFY( ranges::equal(*i++, "the"sv) ); VERIFY( ranges::equal(*i++, "quick"sv) ); @@ -152,6 +152,36 @@ test08() VERIFY( i == v.end() ); } +template<auto split = views::split> +void +test09() +{ + // Verify SFINAE behavior. + std::string s, p; + static_assert(!requires { split(); }); + static_assert(!requires { split(s, p, 0); }); + static_assert(!requires { split(p)(); }); + static_assert(!requires { s | split; }); + + static_assert(!requires { s | split(p); }); + static_assert(!requires { split(p)(s); }); + static_assert(!requires { s | (split(p) | views::all); }); + static_assert(!requires { (split(p) | views::all)(s); }); + + static_assert(requires { s | split(views::all(p)); }); + static_assert(requires { split(views::all(p))(s); }); + static_assert(requires { s | (split(views::all(p)) | views::all); }); + static_assert(requires { (split(views::all(p)) | views::all)(s); }); + + auto adapt = split(p); + static_assert(requires { s | adapt; }); + static_assert(requires { adapt(s); }); + + auto adapt2 = split(p) | views::all; + static_assert(requires { s | adapt2; }); + static_assert(requires { adapt2(s); }); +} + int main() { @@ -163,4 +193,5 @@ main() test06(); test07(); test08(); + test09(); } diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/split_neg.cc b/libstdc++-v3/testsuite/std/ranges/adaptors/split_neg.cc index fb84049711f458c6f2587b6a89a855df1a1858d6..4229314a9dc5e47e5499093d4fb13a99f0590993 100644 --- a/libstdc++-v3/testsuite/std/ranges/adaptors/split_neg.cc +++ b/libstdc++-v3/testsuite/std/ranges/adaptors/split_neg.cc @@ -30,8 +30,7 @@ test01() { using namespace std::literals; auto x = "the quick brown fox"sv; - auto v = views::split(x, std::initializer_list<char>{' ', ' '}); - v.begin(); // { dg-error "" } + auto v = views::split(x, std::initializer_list<char>{' ', ' '}); // { dg-error "no match" } } void @@ -39,11 +38,8 @@ test02() { using namespace std::literals; auto x = "the quick brown fox"sv; - auto v = x | views::split(std::initializer_list<char>{' ', ' '}); // { dg-error "no match" } - v.begin(); + auto v1 = views::split(std::initializer_list<char>{' ', ' '})(x); // { dg-error "deleted" } + auto v2 = x | views::split(std::initializer_list<char>{' ', ' '}); // { dg-error "no match" } } // { dg-prune-output "in requirements" } -// { dg-error "deduction failed" "" { target *-*-* } 0 } -// { dg-error "no match" "" { target *-*-* } 0 } -// { dg-error "constraint failure" "" { target *-*-* } 0 } diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/take.cc b/libstdc++-v3/testsuite/std/ranges/adaptors/take.cc index 5947c7bafabeae846d7030b7558c030ac87cde97..55f748247376308d69fab014fb971679281dbe9d 100644 --- a/libstdc++-v3/testsuite/std/ranges/adaptors/take.cc +++ b/libstdc++-v3/testsuite/std/ranges/adaptors/take.cc @@ -100,6 +100,23 @@ test05() b = ranges::end(v); } +template<auto take = views::take> +void +test06() +{ + // Verify SFINAE behavior. + extern int x[5]; + int* n = 0; + static_assert(!requires { take(); }); + static_assert(!requires { take(x, n, n); }); + static_assert(!requires { take(x, n); }); + static_assert(!requires { take(n)(x); }); + static_assert(!requires { x | (take(n) | views::all); }); + static_assert(!requires { (take(n) | views::all)(x); }); + static_assert(!requires { take | views::all; }); + static_assert(!requires { views::all | take; }); +} + int main() { @@ -108,4 +125,5 @@ main() test03(); test04(); test05(); + test06(); } diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/take_while.cc b/libstdc++-v3/testsuite/std/ranges/adaptors/take_while.cc index ff377e578c4aa0636ebd1c663db287dac0af20db..1ab8df3bc62b266c308e9f1e5c4b226aead34609 100644 --- a/libstdc++-v3/testsuite/std/ranges/adaptors/take_while.cc +++ b/libstdc++-v3/testsuite/std/ranges/adaptors/take_while.cc @@ -79,6 +79,23 @@ test04() static_assert(!ranges::range<decltype(v) const>); } +template<auto take_while = views::take_while> +void +test05() +{ + // Verify SFINAE behavior. + extern int x[5]; + auto p = [] (int*) { return true; }; + static_assert(!requires { take_while(); }); + static_assert(!requires { take_while(x, p, p); }); + static_assert(!requires { take_while(x, p); }); + static_assert(!requires { take_while(p)(x); }); + static_assert(!requires { x | (take_while(p) | views::all); }); + static_assert(!requires { (take_while(p) | views::all)(x); }); + static_assert(!requires { take_while | views::all; }); + static_assert(!requires { views::all | take_while; }); +} + int main() { @@ -86,4 +103,5 @@ main() test02(); test03(); test04(); + test05(); } diff --git a/libstdc++-v3/testsuite/std/ranges/adaptors/transform.cc b/libstdc++-v3/testsuite/std/ranges/adaptors/transform.cc index 4e7e7ba0a672e0f978d8bf508c5bac3da5965edc..ab2f28a2111683b2769e49680d214238c310edd3 100644 --- a/libstdc++-v3/testsuite/std/ranges/adaptors/transform.cc +++ b/libstdc++-v3/testsuite/std/ranges/adaptors/transform.cc @@ -145,6 +145,33 @@ test06() VERIFY( (next(b_const, 2) - b_const) == 2 ); } +void +test07() +{ + int x[] = {1,2,3,4,5}; + auto v1 = views::transform([] (auto& x) { return &x; }); + auto v2 = views::transform([] (auto x) { return *x; }); + auto v = x | (v1 | v2); + VERIFY( ranges::equal(v, x) ); +} + +template<auto transform = views::transform> +void +test08() +{ + // Verify SFINAE behavior. + extern int x[5]; + auto f = [] (int* e) { return e; }; + static_assert(!requires { transform(); }); + static_assert(!requires { transform(x, f, f); }); + static_assert(!requires { transform(x, f); }); + static_assert(!requires { transform(f)(x); }); + static_assert(!requires { x | (transform(f) | views::all); }); + static_assert(!requires { (transform(f) | views::all)(x); }); + static_assert(!requires { transform | views::all; }); + static_assert(!requires { views::all | transform; }); +} + int main() { @@ -154,4 +181,6 @@ main() test04(); test05(); test06(); + test07(); + test08(); }