/// \file // Range v3 library // // Copyright Eric Niebler 2013-present // // Use, modification and distribution is subject to the // Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // // Project home: https://github.com/ericniebler/range-v3 // #ifndef RANGES_V3_RANGE_CONVERSION_HPP #define RANGES_V3_RANGE_CONVERSION_HPP #include #include #include #include #include #include #include #include #include #include namespace ranges { /// \cond namespace detail { struct to_container { template struct fn; template struct closure; template using container_t = meta::invoke; template friend auto operator|(Rng && rng, closure> (*)(to_container)) -> CPP_broken_friend_ret(container_t)( /// \pre requires invocable, Rng>) { return fn{}(static_cast(rng)); } template friend auto operator|(closure> (*)(to_container), Pipeable pipe) -> CPP_broken_friend_ret( closure>>)( /// \pre requires (is_pipeable_v)) { return closure>>{ compose(static_cast(pipe), fn{})}; } }; // A simple, light-weight transform iterator that applies ranges::to // to each element in the range. Used by ranges::to to convert a range // of ranges into a container of containers. template struct to_container_iterator { private: using I = range_cpp17_iterator_t; using ValueType = range_value_t; I it_; public: using difference_type = typename std::iterator_traits::difference_type; using value_type = ValueType; using reference = ValueType; using pointer = typename std::iterator_traits::pointer; using iterator_category = typename std::iterator_traits::iterator_category; to_container_iterator() = default; template to_container_iterator(OtherIt it) : it_(std::move(it)) {} friend bool operator==(to_container_iterator const & a, to_container_iterator const & b) { return a.it_ == b.it_; } friend bool operator!=(to_container_iterator const & a, to_container_iterator const & b) { return !(a == b); } reference operator*() const { return to_container::fn>{}(*it_); } to_container_iterator & operator++() { ++it_; return *this; } to_container_iterator operator++(int) { auto tmp = *this; ++it_; return tmp; } CPP_member auto operator--() // -> CPP_ret(to_container_iterator &)( /// \pre requires derived_from) { --it_; return *this; } CPP_member auto operator--(int) // -> CPP_ret(to_container_iterator &)( /// \pre requires derived_from) { auto tmp = *this; ++it_; return tmp; } CPP_member auto operator+=(difference_type n) // -> CPP_ret(to_container_iterator &)( /// \pre requires derived_from) { it_ += n; return *this; } CPP_member auto operator-=(difference_type n) // -> CPP_ret(to_container_iterator &)( /// \pre requires derived_from) { it_ -= n; return *this; } CPP_broken_friend_member friend auto operator+(to_container_iterator i, difference_type n) // -> CPP_broken_friend_ret(to_container_iterator)( /// \pre requires derived_from) { return i += n; } CPP_broken_friend_member friend auto operator-(to_container_iterator i, difference_type n) // -> CPP_broken_friend_ret(to_container_iterator)( /// \pre requires derived_from) { return i -= n; } CPP_broken_friend_member friend auto operator-(difference_type n, to_container_iterator i) // -> CPP_broken_friend_ret(to_container_iterator)( /// \pre requires derived_from) { return i -= n; } CPP_broken_friend_member friend auto operator-(to_container_iterator const & i, to_container_iterator const & j) // -> CPP_broken_friend_ret(difference_type)( /// \pre requires derived_from) { return i.it_ - j.it_; } CPP_member auto operator[](difference_type n) const // -> CPP_ret(reference)( /// \pre requires derived_from) { return *(*this + n); } }; template using to_container_iterator_t = enable_if_t<(bool)range, to_container_iterator>; // clang-format off template(typename Rng)( concept (range_and_not_view_)(Rng), range AND (!view_)); template CPP_concept range_and_not_view = CPP_concept_ref(range_and_not_view_, Rng); template(typename Rng, typename Cont)( concept (convertible_to_cont_impl_)(Rng, Cont), constructible_from, range_reference_t> AND constructible_from< Cont, range_cpp17_iterator_t, range_cpp17_iterator_t> ); template CPP_concept convertible_to_cont = // range_and_not_view && // move_constructible && // CPP_concept_ref(detail::convertible_to_cont_impl_, Rng, Cont); template(typename Rng, typename Cont)( concept (convertible_to_cont_cont_impl_)(Rng, Cont), range_and_not_view> AND // Test that each element of the input range can be ranges::to<> // to the output container. invocable< to_container::fn>>, range_reference_t> AND constructible_from< Cont, to_container_iterator_t, to_container_iterator_t> ); template CPP_concept convertible_to_cont_cont = // range && // (!view_) && // move_constructible && // CPP_concept_ref(detail::convertible_to_cont_cont_impl_, Rng, Cont); template CPP_concept to_container_reserve = // reservable_with_assign && // sized_range; template using container_t = meta::invoke; // clang-format on struct RANGES_STRUCT_WITH_ADL_BARRIER(to_container_closure_base) { // clang-format off template(typename Rng, typename MetaFn, typename Fn)( /// \pre requires input_range AND convertible_to_cont>) friend constexpr auto operator|(Rng && rng, to_container::closure fn) { return static_cast(fn)(static_cast(rng)); } template(typename Rng, typename MetaFn, typename Fn)( /// \pre requires input_range AND (!convertible_to_cont>) AND convertible_to_cont_cont>) friend constexpr auto operator|(Rng && rng, to_container::closure fn) { return static_cast(fn)(static_cast(rng)); } template friend constexpr auto operator|(to_container::closure sh, Pipeable pipe) -> CPP_broken_friend_ret( to_container::closure>)( /// \pre requires is_pipeable_v) { return to_container::closure>{ compose(static_cast(pipe), static_cast(sh))}; } }; template struct to_container::closure : to_container_closure_base , Fn { closure() = default; constexpr explicit closure(Fn fn) : Fn(static_cast(fn)) {} }; template struct to_container::fn { private: template static Cont impl(Rng && rng, std::false_type) { return Cont(I{ranges::begin(rng)}, I{ranges::end(rng)}); } template static auto impl(Rng && rng, std::true_type) { Cont c; auto const rng_size = ranges::size(rng); using size_type = decltype(c.max_size()); using C = common_type_t, size_type>; RANGES_EXPECT(static_cast(rng_size) <= static_cast(c.max_size())); c.reserve(static_cast(rng_size)); c.assign(I{ranges::begin(rng)}, I{ranges::end(rng)}); return c; } public: template(typename Rng)( /// \pre requires input_range AND convertible_to_cont>) container_t operator()(Rng && rng) const { static_assert(!is_infinite::value, "Attempt to convert an infinite range to a container."); using cont_t = container_t; using iter_t = range_cpp17_iterator_t; using use_reserve_t = meta::bool_<(bool)to_container_reserve>; return impl(static_cast(rng), use_reserve_t{}); } template(typename Rng)( /// \pre requires input_range AND (!convertible_to_cont>) AND convertible_to_cont_cont>) container_t operator()(Rng && rng) const { static_assert(!is_infinite::value, "Attempt to convert an infinite range to a container."); using cont_t = container_t; using iter_t = to_container_iterator; using use_reserve_t = meta::bool_<(bool)to_container_reserve>; return impl(static_cast(rng), use_reserve_t{}); } }; template using to_container_closure = to_container::closure; template using to_container_fn = to_container_closure>; template class ContT> struct from_range { #if RANGES_CXX_DEDUCTION_GUIDES >= RANGES_CXX_DEDUCTION_GUIDES_17 // Attempt to use a deduction guide first... template static auto from_rng_(int) // -> decltype(ContT(range_cpp17_iterator_t{}, range_cpp17_iterator_t{})); // No deduction guide. Fallback to instantiating with the // iterator's value type. template static auto from_rng_(long) // -> meta::invoke, range_value_t>; template using invoke = decltype(from_range::from_rng_(0)); #else template using invoke = meta::invoke, range_value_t>; #endif }; } // namespace detail /// \endcond /// \addtogroup group-range /// @{ /// \ingroup group-range RANGES_INLINE_VARIABLE(detail::to_container_fn>, to_vector) /// \cond namespace _to_ { /// \endcond /// \brief For initializing a container of the specified type with the elements of /// an Range template class ContT> auto to(RANGES_HIDDEN_DETAIL(detail::to_container = {})) -> detail::to_container_fn> { return {}; } /// \overload template(template class ContT, typename Rng)( /// \pre requires range AND detail::convertible_to_cont>>) auto to(Rng && rng) -> ContT> { return detail::to_container_fn>{}( static_cast(rng)); } /// \overload template auto to(RANGES_HIDDEN_DETAIL(detail::to_container = {})) -> detail::to_container_fn> { return {}; } /// \overload template(typename Cont, typename Rng)( /// \pre requires range AND detail::convertible_to_cont) auto to(Rng && rng) -> Cont { return detail::to_container_fn>{}(static_cast(rng)); } /// \cond // Slightly odd initializer_list overloads, undocumented for now. template(template class ContT, typename T)( /// \pre requires detail::convertible_to_cont, ContT>) auto to(std::initializer_list il) -> ContT { return detail::to_container_fn>{}(il); } template(typename Cont, typename T)( /// \pre requires detail::convertible_to_cont, Cont>) auto to(std::initializer_list il) -> Cont { return detail::to_container_fn>{}(il); } /// \endcond /// \cond } // namespace _to_ using namespace _to_; /// \endcond /// @} //////////////////////////////////////////////////////////////////////////// /// \cond namespace _to_ { // The old name "ranges::to_" is now deprecated: template class ContT> RANGES_DEPRECATED("Please use ranges::to (no underscore) instead.") detail::to_container_fn> to_(detail::to_container = {}) { return {}; } template(template class ContT, typename Rng)( /// \pre requires range AND detail::convertible_to_cont>>) RANGES_DEPRECATED("Please use ranges::to (no underscore) instead.") ContT> to_(Rng && rng) { return static_cast(rng) | ranges::to_(); } template(template class ContT, typename T)( /// \pre requires detail::convertible_to_cont, ContT>) RANGES_DEPRECATED("Please use ranges::to (no underscore) instead.") ContT to_(std::initializer_list il) { return il | ranges::to_(); } template RANGES_DEPRECATED("Please use ranges::to (no underscore) instead.") detail::to_container_fn> to_(detail::to_container = {}) { return {}; } template(typename Cont, typename Rng)( /// \pre requires range AND detail::convertible_to_cont) RANGES_DEPRECATED("Please use ranges::to (no underscore) instead.") Cont to_(Rng && rng) { return static_cast(rng) | ranges::to_(); } template(typename Cont, typename T)( /// \pre requires detail::convertible_to_cont, Cont>) RANGES_DEPRECATED("Please use ranges::to (no underscore) instead.") Cont to_(std::initializer_list list) { return list | ranges::to_(); } } // namespace _to_ /// \endcond template RANGES_INLINE_VAR constexpr bool is_pipeable_v> = true; } // namespace ranges #include #endif