diff --git a/stl/inc/ranges b/stl/inc/ranges index 0abfedeb742..e1e10c40be0 100644 --- a/stl/inc/ranges +++ b/stl/inc/ranges @@ -2049,6 +2049,133 @@ namespace ranges { inline constexpr _Reverse_fn reverse; } // namespace views + + // CLASS TEMPLATE ranges::common_view + // clang-format off + template + requires (!common_range<_Vw> && copyable>) + class common_view : public view_interface> { + // clang-format on + private: + /* [[no_unique_address]] */ _Vw _Base{}; + + public: + common_view() = default; + constexpr explicit common_view(_Vw _Base_) noexcept(is_nothrow_move_constructible_v<_Vw>) // strengthened + : _Base(_STD move(_Base_)) {} + + // clang-format off + template + requires (!common_range<_Rng> && constructible_from<_Vw, views::all_t<_Rng>>) + constexpr explicit common_view(_Rng&& _Range) noexcept( + is_nothrow_constructible_v<_Vw, views::all_t<_Rng>&&>) // strengthened + : _Base(views::all(_STD forward<_Rng&&>(_Range))) {} + // clang-format on + + _NODISCARD constexpr _Vw base() const& noexcept( + is_nothrow_copy_constructible_v<_Vw>) /* strengthened */ requires copy_constructible<_Vw> { + return _Base; + } + _NODISCARD constexpr _Vw base() && noexcept(is_nothrow_move_constructible_v<_Vw>) /* strengthened */ { + return _STD move(_Base); + } + + _NODISCARD constexpr auto begin() noexcept( + _RANGES begin(_Base) && is_nothrow_move_constructible_v>) { + if constexpr (random_access_range<_Vw> && sized_range<_Vw>) { + return _RANGES begin(_Base); + } else { + return common_iterator, sentinel_t<_Vw>>{_RANGES begin(_Base)}; + } + } + + _NODISCARD constexpr auto begin() const + noexcept(_RANGES begin(_Base) && is_nothrow_move_constructible_v>) { + if constexpr (random_access_range && sized_range) { + return _RANGES begin(_Base); + } else { + return common_iterator, sentinel_t>{_RANGES begin(_Base)}; + } + } + + _NODISCARD constexpr auto end() noexcept( + _RANGES end(_Base) && is_nothrow_move_constructible_v>) { + if constexpr (random_access_range<_Vw> && sized_range<_Vw>) { + return _RANGES begin(_Base) + _RANGES size(_Base); + } else { + return common_iterator, sentinel_t<_Vw>>{_RANGES end(_Base)}; + } + } + + _NODISCARD constexpr auto end() const + noexcept(_RANGES end(_Base) && is_nothrow_move_constructible_v>) { + if constexpr (random_access_range && sized_range) { + return _RANGES begin(_Base) + _RANGES size(_Base); + } else { + return common_iterator, sentinel_t>{_RANGES end(_Base)}; + } + } + + _NODISCARD constexpr auto size() noexcept( + noexcept(_RANGES size(_Base))) /* strengthened */ requires sized_range<_Vw> { + return _RANGES size(_Base); + } + _NODISCARD constexpr auto size() const + noexcept(noexcept(_RANGES size(_Base))) /* strengthened */ requires sized_range { + return _RANGES size(_Base); + } + }; + + template + common_view(_Rng &&) -> common_view>; + + namespace views { + // VARIABLE views::common + template + concept _Can_view_all = requires(_Rng&& __r) { + views::all(static_cast<_Rng&&>(__r)); + }; + + class _Common_fn : public _Pipe::_Base<_Common_fn> { + private: + enum class _St { _None, _All, _Common }; + + template + _NODISCARD static _CONSTEVAL _Choice_t<_St> _Choose() noexcept { + if constexpr (common_range<_Rng> && _Can_view_all<_Rng>) { + return {_St::_All, noexcept(views::all{_STD declval<_Rng>()})}; + } else if constexpr (!common_range<_Rng> && copyable>) { + return {_St::_Common, noexcept(common_view{_STD declval<_Rng>()})}; + } + + return {_St::_None}; + } + + template + static constexpr _Choice_t<_St> _Choice = _Choose<_Rng>(); + + public: + // clang-format off + template + requires (_Choice<_Rng>._Strategy != _St::_None) + _NODISCARD constexpr auto operator()(_Rng&& _Range) const noexcept(_Choice<_Rng>._No_throw) { + // clang-format on + if constexpr (_Choice<_Rng>._Strategy == _St::_All) { + return views::all{_STD forward<_Rng>(_Range)}; + } else if constexpr (_Choice<_Rng>._Strategy == _St::_Common) { + return common_view{_STD forward<_Rng>(_Range)}; + } else { + static_assert(_Always_false<_Rng>, "Should be unreachable"); + } + } + }; + + inline constexpr _Common_fn common; + + // ALIAS TEMPLATE views::common_t + template + using common_t = decltype(common(_STD declval<_Rng>())); + } // namespace views } // namespace ranges namespace views = ranges::views;