/// \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 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 CPP_def ( template(typename Fun, typename Rng) concept iter_transform_1_readable, regular_invocable> && regular_invocable> && regular_invocable> && common_reference_with< invoke_result_t> &&, invoke_result_t> &> && common_reference_with< invoke_result_t> &&, invoke_result_t> &&> && common_reference_with< invoke_result_t> &&, invoke_result_t> const &> ); CPP_def ( template(typename Fun, typename Rng1, typename Rng2) concept iter_transform_2_readable, regular_invocable, iterator_t> && regular_invocable, iterator_t> && regular_invocable, iterator_t> && common_reference_with< invoke_result_t, iterator_t> &&, invoke_result_t, iterator_t> &> && common_reference_with< invoke_result_t, iterator_t> &&, invoke_result_t, iterator_t> &&> && common_reference_with< invoke_result_t, iterator_t> &&, invoke_result_t, iterator_t> const &> ); // 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; fun_ref_ fun_; public: using value_type = detail::decay_t>>; adaptor() = default; adaptor(fun_ref_ fun) : fun_(std::move(fun)) {} CPP_template(bool Other)( // requires IsConst && (!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 auto begin_adaptor() const -> CPP_ret(adaptor)( // requires Const && range> && detail::iter_transform_1_readable>) { return {fun_}; } meta::if_, adaptor_base, adaptor> end_adaptor() { return {fun_}; } template auto end_adaptor() const -> CPP_ret(meta::if_, adaptor_base, adaptor>)( // requires Const && range> && detail::iter_transform_1_readable>) { 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_member constexpr auto CPP_fun(size)()(requires sized_range) { return ranges::size(this->base()); } CPP_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 CPP_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_)) {} CPP_template(bool Other)( // requires Const && (!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_)) {} CPP_template(bool Other)( // requires Const && (!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 auto begin_cursor() const -> CPP_ret(cursor)( // requires Const && range> && range> && detail::iter_transform_2_readable< Fun const, meta::const_if_c, meta::const_if_c>) { return {this, ranges::begin}; } template auto end_cursor() const -> CPP_ret(end_cursor_t)( // requires Const && range> && range> && detail::iter_transform_2_readable< Fun const, meta::const_if_c, meta::const_if_c>) { 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); } CPP_template(bool True = true)( // requires(my_cardinality < 0) && sized_range && sized_range && common_with>, range_size_t>>) // constexpr auto size() const { return size_(*this); } CPP_template(bool True = true)( // requires(my_cardinality < 0) && sized_range && sized_range && 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_fn { private: friend view_access; template static constexpr auto bind(iter_transform_fn iter_transform, Fun fun) { return make_pipeable(bind_back(iter_transform, std::move(fun))); } public: template constexpr auto operator()(Rng && rng, Fun fun) const -> CPP_ret(iter_transform_view, Fun>)( // requires viewable_range && input_range && copy_constructible && detail::iter_transform_1_readable) { return {all(static_cast(rng)), std::move(fun)}; } template constexpr auto operator()(Rng1 && rng1, Rng2 && rng2, Fun fun) const -> CPP_ret(iter_transform2_view, all_t, Fun>)( // requires viewable_range && input_range && viewable_range< Rng2> && input_range && copy_constructible && common_with, range_difference_t> && detail::iter_transform_2_readable) { return {all(static_cast(rng1)), all(static_cast(rng2)), std::move(fun)}; } }; /// \relates iter_transform_fn /// \ingroup group-views RANGES_INLINE_VARIABLE(view, iter_transform) // Don't forget to update views::for_each whenever this set // of concepts changes // clang-format off CPP_def ( template(typename Rng, typename Fun) concept transformable_range, viewable_range && input_range && copy_constructible && regular_invocable> && (!std::is_void>>::value) ); CPP_def ( template(typename Rng1, typename Rng2, typename Fun) concept transformable_ranges, viewable_range && input_range && viewable_range && input_range && copy_constructible && (!std::is_void< indirect_result_t, iterator_t>>::value) ); // clang-format on struct transform_fn { private: friend view_access; template static constexpr auto bind(transform_fn transform, Fun fun) { return make_pipeable(bind_back(transform, std::move(fun))); } public: template constexpr auto operator()(Rng && rng, Fun fun) const -> CPP_ret(transform_view, Fun>)( // requires transformable_range) { return {all(static_cast(rng)), std::move(fun)}; } template constexpr auto operator()(Rng1 && rng1, Rng2 && rng2, Fun fun) const -> CPP_ret(transform2_view, all_t, Fun>)( // requires transformable_ranges) { return {all(static_cast(rng1)), all(static_cast(rng2)), std::move(fun)}; } }; /// \relates transform_fn /// \ingroup group-views RANGES_INLINE_VARIABLE(view, transform) } // namespace views namespace cpp20 { namespace views { using ranges::views::transform; } CPP_template(typename Rng, typename F)( // requires input_range && copy_constructible && view_ && std::is_object::value && regular_invocable>>) // using transform_view = ranges::transform_view; } // namespace cpp20 /// @} } // namespace ranges #include RANGES_SATISFY_BOOST_RANGE(::ranges::iter_transform_view) RANGES_SATISFY_BOOST_RANGE(::ranges::transform_view) #endif