// -*- 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_TO_H #define _LIBCPP___RANGES_TO_H #include <__algorithm/ranges_copy.h> #include <__concepts/constructible.h> #include <__concepts/convertible_to.h> #include <__concepts/derived_from.h> #include <__concepts/same_as.h> #include <__config> #include <__functional/bind_back.h> #include <__iterator/back_insert_iterator.h> #include <__iterator/insert_iterator.h> #include <__iterator/iterator_traits.h> #include <__ranges/access.h> #include <__ranges/concepts.h> #include <__ranges/from_range.h> #include <__ranges/range_adaptor.h> #include <__ranges/ref_view.h> #include <__ranges/size.h> #include <__ranges/transform_view.h> #include <__type_traits/add_pointer.h> #include <__type_traits/is_const.h> #include <__type_traits/is_volatile.h> #include <__type_traits/type_identity.h> #include <__utility/declval.h> #include <__utility/forward.h> #include #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header #endif _LIBCPP_BEGIN_NAMESPACE_STD #if _LIBCPP_STD_VER >= 23 namespace ranges { template constexpr bool __reservable_container = sized_range<_Container> && requires(_Container& __c, range_size_t<_Container> __n) { __c.reserve(__n); { __c.capacity() } -> same_as; { __c.max_size() } -> same_as; }; template constexpr bool __container_insertable = requires(_Container& __c, _Ref&& __ref) { requires( requires { __c.push_back(std::forward<_Ref>(__ref)); } || requires { __c.insert(__c.end(), std::forward<_Ref>(__ref)); }); }; template _LIBCPP_HIDE_FROM_ABI constexpr auto __container_inserter(_Container& __c) { if constexpr (requires { __c.push_back(std::declval<_Ref>()); }) { return std::back_inserter(__c); } else { return std::inserter(__c, __c.end()); } } // Note: making this a concept allows short-circuiting the second condition. template concept __try_non_recursive_conversion = !input_range<_Container> || convertible_to, range_value_t<_Container>>; template concept __constructible_from_iter_pair = common_range<_Range> && requires { typename iterator_traits>::iterator_category; } && derived_from>::iterator_category, input_iterator_tag> && constructible_from<_Container, iterator_t<_Range>, sentinel_t<_Range>, _Args...>; template concept __always_false = false; // `ranges::to` base template -- the `_Container` type is a simple type template parameter. template requires(!view<_Container>) [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Container to(_Range&& __range, _Args&&... __args) { // Mandates: C is a cv-unqualified class type. static_assert(!is_const_v<_Container>, "The target container cannot be const-qualified, please remove the const"); static_assert( !is_volatile_v<_Container>, "The target container cannot be volatile-qualified, please remove the volatile"); // First see if the non-recursive case applies -- the conversion target is either: // - a range with a convertible value type; // - a non-range type which might support being created from the input argument(s) (e.g. an `optional`). if constexpr (__try_non_recursive_conversion<_Container, _Range>) { // Case 1 -- construct directly from the given range. if constexpr (constructible_from<_Container, _Range, _Args...>) { return _Container(std::forward<_Range>(__range), std::forward<_Args>(__args)...); } // Case 2 -- construct using the `from_range_t` tagged constructor. else if constexpr (constructible_from<_Container, from_range_t, _Range, _Args...>) { return _Container(from_range, std::forward<_Range>(__range), std::forward<_Args>(__args)...); } // Case 3 -- construct from a begin-end iterator pair. else if constexpr (__constructible_from_iter_pair<_Container, _Range, _Args...>) { return _Container(ranges::begin(__range), ranges::end(__range), std::forward<_Args>(__args)...); } // Case 4 -- default-construct (or construct from the extra arguments) and insert, reserving the size if possible. else if constexpr (constructible_from<_Container, _Args...> && __container_insertable<_Container, range_reference_t<_Range>>) { _Container __result(std::forward<_Args>(__args)...); if constexpr (sized_range<_Range> && __reservable_container<_Container>) { __result.reserve(static_cast>(ranges::size(__range))); } ranges::copy(__range, ranges::__container_inserter>(__result)); return __result; } else { static_assert(__always_false<_Container>, "ranges::to: unable to convert to the given container type."); } // Try the recursive case. } else if constexpr (input_range>) { return ranges::to<_Container>( ref_view(__range) | views::transform([](auto&& __elem) { return ranges::to>(std::forward(__elem)); }), std::forward<_Args>(__args)...); } else { static_assert(__always_false<_Container>, "ranges::to: unable to convert to the given container type."); } } template struct __minimal_input_iterator { using iterator_category = input_iterator_tag; using value_type = range_value_t<_Range>; using difference_type = ptrdiff_t; using pointer = add_pointer_t>; using reference = range_reference_t<_Range>; reference operator*() const; pointer operator->() const; __minimal_input_iterator& operator++(); __minimal_input_iterator operator++(int); bool operator==(const __minimal_input_iterator&) const; }; // Deduces the full type of the container from the given template template parameter. template