Horizon
group_by.hpp
Go to the documentation of this file.
1 // Range v3 library
3 //
4 // Copyright Eric Niebler 2013-present
5 //
6 // Use, modification and distribution is subject to the
7 // Boost Software License, Version 1.0. (See accompanying
8 // file LICENSE_1_0.txt or copy at
9 // http://www.boost.org/LICENSE_1_0.txt)
10 //
11 // Project home: https://github.com/ericniebler/range-v3
12 //
13 
14 #ifndef RANGES_V3_VIEW_GROUP_BY_HPP
15 #define RANGES_V3_VIEW_GROUP_BY_HPP
16 
17 #include <type_traits>
18 #include <utility>
19 
20 #include <meta/meta.hpp>
21 
22 #include <range/v3/range_fwd.hpp>
23 
33 #include <range/v3/utility/static_const.hpp>
34 #include <range/v3/view/facade.hpp>
37 #include <range/v3/view/view.hpp>
38 
39 #include <range/v3/detail/config.hpp>
40 #include <range/v3/detail/prologue.hpp>
41 
42 namespace ranges
43 {
44  // TODO group_by could support Input ranges by keeping mutable state in
45  // the range itself. The group_by view would then be mutable-only and
46  // Input.
47 
50  template<typename Rng, typename Fun>
52  : view_facade<group_by_view<Rng, Fun>,
53  is_finite<Rng>::value ? finite : range_cardinality<Rng>::value>
54  {
55  private:
56  friend range_access;
57  Rng rng_;
58  // cached version of the end of the first subrange / start of the second subrange
59  detail::non_propagating_cache<iterator_t<Rng>> second_;
60  semiregular_box_t<Fun> fun_;
61 
62  struct pred
63  {
64  iterator_t<Rng> first_;
65  semiregular_box_ref_or_val_t<Fun, false> fun_;
66  bool operator()(range_reference_t<Rng> r) const
67  {
68  return invoke(fun_, *first_, r);
69  }
70  };
71 
72  struct cursor
73  {
74  private:
75  friend range_access;
76  friend group_by_view;
77  iterator_t<Rng> cur_;
78  iterator_t<Rng> next_cur_;
79  sentinel_t<Rng> last_;
80  semiregular_box_ref_or_val_t<Fun, false> fun_;
81 
82  struct mixin : basic_mixin<cursor>
83  {
84  mixin() = default;
85  #ifndef _MSC_VER
87  #else
88  constexpr explicit mixin(cursor && cur)
89  : basic_mixin<cursor>(static_cast<cursor &&>(cur))
90  {}
91  constexpr explicit mixin(cursor const & cur)
92  : basic_mixin<cursor>(cur)
93  {}
94  #endif
95  iterator_t<Rng> base() const
96  {
97  return this->get().cur_;
98  }
99  };
100 
101  #ifdef _MSC_VER
102  template<typename I = iterator_t<Rng>>
103  subrange<I> read() const
104  {
105  return {cur_, next_cur_};
106  }
107  #else
108  subrange<iterator_t<Rng>> read() const
109  {
110  return {cur_, next_cur_};
111  }
112  #endif
113  void next()
114  {
115  cur_ = next_cur_;
116  next_cur_ = cur_ != last_
117  ? find_if_not(ranges::next(cur_), last_, pred{cur_, fun_})
118  : cur_;
119  }
120 
121  bool equal(default_sentinel_t) const
122  {
123  return cur_ == last_;
124  }
125  bool equal(cursor const & that) const
126  {
127  return cur_ == that.cur_;
128  }
129  cursor(semiregular_box_ref_or_val_t<Fun, false> fun, iterator_t<Rng> first,
130  iterator_t<Rng> next_cur, sentinel_t<Rng> last)
131  : cur_(first)
132  , next_cur_(next_cur)
133  , last_(last)
134  , fun_(fun)
135  {}
136 
137  public:
138  cursor() = default;
139  };
140  cursor begin_cursor()
141  {
142  auto b = ranges::begin(rng_);
143  auto e = ranges::end(rng_);
144  if(!second_)
145  {
146  second_ = b != e ? find_if_not(ranges::next(b), e, pred{b, fun_}) : b;
147  }
148  return {fun_, b, *second_, e};
149  }
150 
151  public:
152  group_by_view() = default;
153  constexpr group_by_view(Rng rng, Fun fun)
154  : rng_(std::move(rng))
155  , fun_(std::move(fun))
156  {}
157  Rng base() const
158  {
159  return rng_;
160  }
161  };
162 
163 #if RANGES_CXX_DEDUCTION_GUIDES >= RANGES_CXX_DEDUCTION_GUIDES_17
164  template(typename Rng, typename Fun)(
165  requires copy_constructible<Fun>)
166  group_by_view(Rng &&, Fun)
167  ->group_by_view<views::all_t<Rng>, Fun>;
168 #endif
169 
170  namespace views
171  {
173  {
174  template(typename Rng, typename Fun)(
175  requires viewable_range<Rng> AND forward_range<Rng> AND
177  RANGES_DEPRECATED(
178  "views::group_by is deprecated. Please use views::chunk_by instead. "
179  "Note that views::chunk_by evaluates the predicate between adjacent "
180  "elements.")
181  constexpr group_by_view<all_t<Rng>, Fun> operator()(Rng && rng, Fun fun) const
182  {
183  return {all(static_cast<Rng &&>(rng)), std::move(fun)};
184  }
185  };
186 
188  {
189  using group_by_base_fn::operator();
190 
191  template<typename Fun>
192  RANGES_DEPRECATED(
193  "views::group_by is deprecated. Please use views::chunk_by instead. "
194  "Note that views::chunk_by evaluates the predicate between adjacent "
195  "elements.")
196  constexpr auto operator()(Fun fun) const
197  {
198  return make_view_closure(bind_back(group_by_base_fn{}, std::move(fun)));
199  }
200  };
201 
205  } // namespace views
207 } // namespace ranges
208 
209 #include <range/v3/detail/epilogue.hpp>
210 #include <range/v3/detail/satisfy_boost_range.hpp>
211 RANGES_SATISFY_BOOST_RANGE(::ranges::group_by_view)
212 
213 #endif
CPP_concept indirect_relation
\concept indirect_relation
Definition: concepts.hpp:670
decltype(begin(declval(Rng &))) iterator_t
Definition: access.hpp:698
RANGES_INLINE_VARIABLE(detail::to_container_fn< detail::from_range< std::vector >>, to_vector) template< template< typename... > class ContT > auto to(RANGES_HIDDEN_DETAIL(detail
For initializing a container of the specified type with the elements of an Range.
Definition: conversion.hpp:399
typename Fn::template invoke< Args... > invoke
Evaluate the invocable Fn with the arguments Args.
Definition: meta.hpp:541
defer< bind_back, Fn, Ts... > bind_back
Definition: meta.hpp:994
front< Pair > first
Retrieve the first element of the pair Pair.
Definition: meta.hpp:2251
Tiny meta-programming library.
Definition: basic_iterator.hpp:47
Definition: default_sentinel.hpp:26
Definition: group_by.hpp:54
Definition: subrange.hpp:196
A utility for constructing a view from a (derived) type that implements begin and end cursors.
Definition: facade.hpp:66
Definition: group_by.hpp:173
Definition: group_by.hpp:188