/// \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_VIEW_TRANSFORM_HPP #define RANGES_V3_VIEW_TRANSFORM_HPP #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace ranges { /// \cond namespace detail { constexpr cardinality transform2_cardinality(cardinality c1, cardinality c2) { return c1 >= 0 || c2 >= 0 ? (c1 >= 0 && c2 >= 0 ? (c1 < c2 ? c1 : c2) : finite) : c1 == finite || c2 == finite ? finite : c1 == unknown || c2 == unknown ? unknown : infinite; } // clang-format off /// \concept iter_transform_1_readable_ /// \brief The \c iter_transform_1_readable_ concept template(typename Fun, typename Rng)( concept (iter_transform_1_readable_)(Fun, Rng), regular_invocable> AND regular_invocable> AND regular_invocable> AND common_reference_with< invoke_result_t> &&, invoke_result_t> &> AND common_reference_with< invoke_result_t> &&, invoke_result_t> &&> AND common_reference_with< invoke_result_t> &&, invoke_result_t> const &> ); /// \concept iter_transform_1_readable /// \brief The \c iter_transform_1_readable concept template CPP_concept iter_transform_1_readable = CPP_concept_ref(detail::iter_transform_1_readable_, Fun, Rng); /// \concept iter_transform_2_readable_ /// \brief The \c iter_transform_2_readable_ concept template(typename Fun, typename Rng1, typename Rng2)( concept (iter_transform_2_readable_)(Fun, Rng1, Rng2), regular_invocable, iterator_t> AND regular_invocable, iterator_t> AND regular_invocable, iterator_t> AND common_reference_with< invoke_result_t, iterator_t> &&, invoke_result_t, iterator_t> &> AND common_reference_with< invoke_result_t, iterator_t> &&, invoke_result_t, iterator_t> &&> AND common_reference_with< invoke_result_t, iterator_t> &&, invoke_result_t, iterator_t> const &> ); /// \concept iter_transform_2_readable /// \brief The \c iter_transform_2_readable concept template CPP_concept iter_transform_2_readable = CPP_concept_ref(detail::iter_transform_2_readable_, Fun, Rng1, Rng2); // clang-format on } // namespace detail /// \endcond /// \addtogroup group-views /// @{ template struct iter_transform_view : view_adaptor, Rng> { private: friend range_access; RANGES_NO_UNIQUE_ADDRESS semiregular_box_t fun_; template using use_sentinel_t = meta::bool_> || single_pass_iterator_>>>; template struct adaptor : adaptor_base { private: friend struct adaptor; using CRng = meta::const_if_c; using fun_ref_ = semiregular_box_ref_or_val_t; RANGES_NO_UNIQUE_ADDRESS fun_ref_ fun_; public: using value_type = detail::decay_t>>; adaptor() = default; adaptor(fun_ref_ fun) : fun_(std::move(fun)) {} template(bool Other)( requires IsConst AND CPP_NOT(Other)) // adaptor(adaptor that) : fun_(std::move(that.fun_)) {} // clang-format off auto CPP_auto_fun(read)(iterator_t it)(const) ( return invoke(fun_, it) ) auto CPP_auto_fun(iter_move)(iterator_t it)(const) ( return invoke(fun_, move_tag{}, it) ) // clang-format on }; adaptor begin_adaptor() { return {fun_}; } template(bool Const = true)( requires Const AND range> AND detail::iter_transform_1_readable>) adaptor begin_adaptor() const { return {fun_}; } meta::if_, adaptor_base, adaptor> end_adaptor() { return {fun_}; } template(bool Const = true)( requires Const AND range> AND detail::iter_transform_1_readable>) meta::if_, adaptor_base, adaptor> end_adaptor() const { return {fun_}; } public: iter_transform_view() = default; iter_transform_view(Rng rng, Fun fun) : iter_transform_view::view_adaptor{std::move(rng)} , fun_(std::move(fun)) {} CPP_auto_member constexpr auto CPP_fun(size)()( requires sized_range) { return ranges::size(this->base()); } CPP_auto_member constexpr auto CPP_fun(size)()(const // requires sized_range) { return ranges::size(this->base()); } }; template struct transform_view : iter_transform_view> { transform_view() = default; transform_view(Rng rng, Fun fun) : iter_transform_view>{std::move(rng), indirect(std::move(fun))} {} }; #if RANGES_CXX_DEDUCTION_GUIDES >= RANGES_CXX_DEDUCTION_GUIDES_17 template(typename Rng, typename Fun)( requires copy_constructible) transform_view(Rng &&, Fun) -> transform_view, Fun>; #endif template struct iter_transform2_view : view_facade, detail::transform2_cardinality(range_cardinality::value, range_cardinality::value)> { private: friend range_access; RANGES_NO_UNIQUE_ADDRESS semiregular_box_t fun_; Rng1 rng1_; Rng2 rng2_; using difference_type_ = common_type_t, range_difference_t>; static constexpr cardinality my_cardinality = detail::transform2_cardinality( range_cardinality::value, range_cardinality::value); template struct cursor; template struct sentinel { private: friend struct cursor; sentinel_t> end1_; sentinel_t> end2_; public: sentinel() = default; sentinel(meta::const_if_c * parent, decltype(ranges::end)) : end1_(end(parent->rng1_)) , end2_(end(parent->rng2_)) {} template(bool Other)( requires Const AND CPP_NOT(Other)) // sentinel(sentinel that) : end1_(std::move(that.end1_)) , end2_(std::move(that.end2_)) {} }; template struct cursor { private: using fun_ref_ = semiregular_box_ref_or_val_t; using R1 = meta::const_if_c; using R2 = meta::const_if_c; fun_ref_ fun_; iterator_t it1_; iterator_t it2_; public: using difference_type = difference_type_; using single_pass = meta::or_c<(bool)single_pass_iterator_>, (bool)single_pass_iterator_>>; using value_type = detail::decay_t &, copy_tag, iterator_t, iterator_t>>; cursor() = default; template cursor(meta::const_if_c * parent, BeginEndFn begin_end) : fun_(parent->fun_) , it1_(begin_end(parent->rng1_)) , it2_(begin_end(parent->rng2_)) {} template(bool Other)( requires Const AND CPP_NOT(Other)) // cursor(cursor that) : fun_(std::move(that.fun_)) , it1_(std::move(that.end1_)) , it2_(std::move(that.end2_)) {} // clang-format off auto CPP_auto_fun(read)()(const) ( return invoke(fun_, it1_, it2_) ) // clang-format on void next() { ++it1_; ++it2_; } CPP_member auto equal(cursor const & that) const // -> CPP_ret(bool)( requires forward_range && forward_range) { // By returning true if *any* of the iterators are equal, we allow // transformed ranges to be of different lengths, stopping when the first // one reaches the last. return it1_ == that.it1_ || it2_ == that.it2_; } bool equal(sentinel const & s) const { // By returning true if *any* of the iterators are equal, we allow // transformed ranges to be of different lengths, stopping when the first // one reaches the last. return it1_ == s.end1_ || it2_ == s.end2_; } CPP_member auto prev() // -> CPP_ret(void)( requires bidirectional_range && bidirectional_range) { --it1_; --it2_; } CPP_member auto advance(difference_type n) -> CPP_ret(void)( requires random_access_range && random_access_range) { ranges::advance(it1_, n); ranges::advance(it2_, n); } CPP_member auto distance_to(cursor const & that) const // -> CPP_ret(difference_type)( requires sized_sentinel_for, iterator_t> && sized_sentinel_for, iterator_t>) { // Return the smallest distance (in magnitude) of any of the iterator // pairs. This is to accommodate zippers of sequences of different length. difference_type d1 = that.it1_ - it1_, d2 = that.it2_ - it2_; return 0 < d1 ? ranges::min(d1, d2) : ranges::max(d1, d2); } // clang-format off auto CPP_auto_fun(move)()(const) ( return invoke(fun_, move_tag{}, it1_, it2_) ) // clang-format on }; template using end_cursor_t = meta::if_c< common_range> && common_range> && !single_pass_iterator_>> && !single_pass_iterator_>>, cursor, sentinel>; cursor() && simple_view()> begin_cursor() { return {this, ranges::begin}; } end_cursor_t() && simple_view()> end_cursor() { return {this, ranges::end}; } template(bool Const = true)( requires Const AND range> AND range> AND detail::iter_transform_2_readable< // Fun const, // meta::const_if_c, // meta::const_if_c>) cursor begin_cursor() const { return {this, ranges::begin}; } template(bool Const = true)( requires Const AND range> AND range> AND detail::iter_transform_2_readable< // Fun const, // meta::const_if_c, // meta::const_if_c>) end_cursor_t end_cursor() const { return {this, ranges::end}; } template static constexpr auto size_(Self & self) { using size_type = common_type_t, range_size_t>; return ranges::min(static_cast(ranges::size(self.rng1_)), static_cast(ranges::size(self.rng2_))); } template using R1 = meta::invoke, Rng1>; template using R2 = meta::invoke, Rng2>; public: iter_transform2_view() = default; constexpr iter_transform2_view(Rng1 rng1, Rng2 rng2, Fun fun) : fun_(std::move(fun)) , rng1_(std::move(rng1)) , rng2_(std::move(rng2)) {} CPP_member static constexpr auto size() // -> CPP_ret(std::size_t)( requires (my_cardinality >= 0)) { return static_cast(my_cardinality); } template(bool True = true)( requires (my_cardinality < 0) AND sized_range AND sized_range AND common_with>, range_size_t>>) constexpr auto size() const { return size_(*this); } template(bool True = true)( requires (my_cardinality < 0) AND sized_range AND sized_range AND common_with>, range_size_t>>) constexpr auto size() { return size_(*this); } }; template struct transform2_view : iter_transform2_view> { transform2_view() = default; constexpr transform2_view(Rng1 rng1, Rng2 rng2, Fun fun) : iter_transform2_view>{std::move(rng1), std::move(rng2), indirect(std::move(fun))} {} }; namespace views { struct iter_transform_base_fn { template(typename Rng, typename Fun)( requires viewable_range AND input_range AND copy_constructible AND detail::iter_transform_1_readable) constexpr iter_transform_view, Fun> // operator()(Rng && rng, Fun fun) const { return {all(static_cast(rng)), std::move(fun)}; } template(typename Rng1, typename Rng2, typename Fun)( requires viewable_range AND input_range AND viewable_range AND input_range AND copy_constructible AND common_with, range_difference_t> AND detail::iter_transform_2_readable) constexpr iter_transform2_view, all_t, Fun> // operator()(Rng1 && rng1, Rng2 && rng2, Fun fun) const { return {all(static_cast(rng1)), all(static_cast(rng2)), std::move(fun)}; } }; struct iter_transform_fn : iter_transform_base_fn { using iter_transform_base_fn::operator(); template constexpr auto operator()(Fun fun) const { return make_view_closure( bind_back(iter_transform_base_fn{}, std::move(fun))); } }; /// \relates iter_transform_fn /// \ingroup group-views RANGES_INLINE_VARIABLE(iter_transform_fn, iter_transform) // Don't forget to update views::for_each whenever this set // of concepts changes // clang-format off /// \concept transformable_range_ /// \brief The \c transformable_range_ concept template(typename Rng, typename Fun)( concept (transformable_range_)(Rng, Fun), regular_invocable> AND (!std::is_void>>::value) ); /// \concept transformable_range /// \brief The \c transformable_range concept template CPP_concept transformable_range = viewable_range && input_range && copy_constructible && CPP_concept_ref(views::transformable_range_, Rng, Fun); /// \concept transformable_ranges_ /// \brief The \c transformable_ranges_ concept template(typename Rng1, typename Rng2, typename Fun)( concept (transformable_ranges_)(Rng1, Rng2, Fun), regular_invocable, range_reference_t> AND (!std::is_void< indirect_result_t, iterator_t>>::value) ); /// \concept transformable_ranges /// \brief The \c transformable_ranges concept template CPP_concept transformable_ranges = viewable_range && input_range && viewable_range && input_range && copy_constructible && CPP_concept_ref(views::transformable_ranges_, Rng1, Rng2, Fun); // clang-format on struct transform_base_fn { template(typename Rng, typename Fun)( requires transformable_range) constexpr transform_view, Fun> operator()(Rng && rng, Fun fun) const { return {all(static_cast(rng)), std::move(fun)}; } template(typename Rng1, typename Rng2, typename Fun)( requires transformable_ranges) constexpr transform2_view, all_t, Fun> // operator()(Rng1 && rng1, Rng2 && rng2, Fun fun) const { return {all(static_cast(rng1)), all(static_cast(rng2)), std::move(fun)}; } }; /// # ranges::views::transform /// The transform view takes in a function `T -> U` and converts an input /// range of `T` into an output range of `U` by calling the function on every /// element of the input range. /// /// ## Example /// \snippet example/view/transform.cpp transform example /// /// ### Output /// \include example/view/transform_golden.txt /// /// ## Syntax /// ```cpp /// auto output_range = input_range | ranges::views::transform(transform_func); /// ``` /// /// ## Parameters ///
transform_func
/// - Maps an input value to an output value (`transform_func(T) -> U`) /// ///
input_range
/// - The range of elements to transform /// - Reference type: `T` /// ///
output_range
/// - The range of output values /// - Reference type: `U` /// - Value type: `decay_t` /// - This range will have the same category as the input range (excluding /// contiguous ranges). Contiguous ranges are reduced to random access ranges. /// struct transform_fn : transform_base_fn { using transform_base_fn::operator(); template constexpr auto operator()(Fun fun) const { return make_view_closure(bind_back(transform_base_fn{}, std::move(fun))); } }; /// \relates transform_fn /// \ingroup group-views RANGES_INLINE_VARIABLE(transform_fn, transform) } // namespace views namespace cpp20 { namespace views { using ranges::views::transform; } template(typename Rng, typename F)( requires input_range AND copy_constructible AND view_ AND std::is_object::value AND regular_invocable>>) using transform_view = ranges::transform_view; } // namespace cpp20 /// @} } // namespace ranges #include #include RANGES_SATISFY_BOOST_RANGE(::ranges::iter_transform_view) RANGES_SATISFY_BOOST_RANGE(::ranges::transform_view) #endif