/// \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_GROUP_BY_HPP #define RANGES_V3_VIEW_GROUP_BY_HPP #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace ranges { // TODO group_by could support Input ranges by keeping mutable state in // the range itself. The group_by view would then be mutable-only and // Input. /// \addtogroup group-views /// @{ template struct group_by_view : view_facade, is_finite::value ? finite : range_cardinality::value> { private: friend range_access; Rng rng_; semiregular_box_t fun_; template struct cursor { private: friend struct cursor; friend range_access; friend group_by_view; using CRng = meta::const_if_c; iterator_t cur_; sentinel_t last_; semiregular_box_ref_or_val_t fun_; struct pred { iterator_t first_; semiregular_box_ref_or_val_t fun_; bool operator()(range_reference_t r) const { return invoke(fun_, *first_, r); } }; #ifdef RANGES_WORKAROUND_MSVC_787074 template auto read() const -> take_while_view>, sentinel_t>>, pred> #else // ^^^ workaround / no workaround vvv auto read() const -> take_while_view, sentinel_t>, pred> #endif // RANGES_WORKAROUND_MSVC_787074 { return {{cur_, last_}, {cur_, fun_}}; } void next() { cur_ = find_if_not(cur_, last_, pred{cur_, fun_}); } bool equal(default_sentinel_t) const { return cur_ == last_; } bool equal(cursor const & that) const { return cur_ == that.cur_; } cursor(semiregular_box_ref_or_val_t fun, iterator_t first, sentinel_t last) : cur_(first) , last_(last) , fun_(fun) {} public: cursor() = default; CPP_template(bool Other)( // requires IsConst && (!Other)) cursor(cursor that) : cur_(std::move(that.cur_)) , last_(std::move(last_)) , fun_(std::move(that.fun_)) {} }; cursor begin_cursor() { return {fun_, ranges::begin(rng_), ranges::end(rng_)}; } template auto begin_cursor() const -> CPP_ret(cursor)( // requires Const && range> && invocable< Fun const &, range_common_reference_t>, range_common_reference_t>>) { return {fun_, ranges::begin(rng_), ranges::end(rng_)}; } public: group_by_view() = default; constexpr group_by_view(Rng rng, Fun fun) : rng_(std::move(rng)) , fun_(std::move(fun)) {} }; #if RANGES_CXX_DEDUCTION_GUIDES >= RANGES_CXX_DEDUCTION_GUIDES_17 CPP_template(typename Rng, typename Fun)(requires copy_constructible) group_by_view(Rng &&, Fun) ->group_by_view, Fun>; #endif namespace views { struct group_by_fn { private: friend view_access; template static constexpr auto bind(group_by_fn group_by, Fun fun) { return make_pipeable(bind_back(group_by, std::move(fun))); } public: template constexpr auto operator()(Rng && rng, Fun fun) const -> CPP_ret(group_by_view, Fun>)( // requires viewable_range && forward_range && indirect_relation>) { return {all(static_cast(rng)), std::move(fun)}; } }; /// \relates group_by_fn /// \ingroup group-views RANGES_INLINE_VARIABLE(view, group_by) } // namespace views /// @} } // namespace ranges #include RANGES_SATISFY_BOOST_RANGE(::ranges::group_by_view) #endif