VCCC  2024.05
VisualCamp Common C++ library
filter_view.hpp
Go to the documentation of this file.
1 //
2 // Created by yonggyulee on 1/24/24.
3 //
4 
5 #ifndef VCCC_RANGES_VIEWS_FILTER_VIEW_HPP
6 #define VCCC_RANGES_VIEWS_FILTER_VIEW_HPP
7 
8 #include <cassert>
9 #include <functional>
10 #include <memory>
11 #include <type_traits>
12 #include <utility>
13 
28 #include "vccc/__ranges/end.hpp"
39 #include "vccc/__ranges/view.hpp"
44 
45 namespace vccc {
46 namespace ranges {
47 namespace detail {
48 
50 class filter_view_cache;
51 
52 template<typename V>
53 class filter_view_cache<V, true> {
54  public:
55  template<typename I, typename This, typename Base, typename Pred>
56  constexpr I begin(This& thiz, Base& base, Pred& pred) {
57  if (!begin_.has_value()) {
58  begin_.emplace(ranges::find_if(base, std::ref(*pred)));
59  }
60  return I{thiz, begin_.value()};
61  }
62 
63  private:
64  non_propagating_cache<iterator_t<V>> begin_;
65 };
66 
67 template<typename V>
68 class filter_view_cache<V, false> {
69  public:
70  template<typename I, typename This, typename Base, typename Pred>
71  constexpr I begin(This& thiz, Base& base, Pred& pred) {
72  return I{thiz, ranges::find_if(base, std::ref(*pred))};
73  }
74 };
75 
77 struct filter_view_iterator_category {
78 #if __cplusplus < 202002L
79  using iterator_category = iterator_ignore;
80 #endif
81 };
82 
83 template<typename V>
84 struct filter_view_iterator_category<V, true> {
85  private:
86  using C = typename cxx20_iterator_traits<iterator_t<V>>::iterator_category;
87 
88  public:
89  using iterator_category =
90  std::conditional_t<
92  std::conditional_t<
94  C
95  >>;
96 };
97 
99 struct has_arrow : std::false_type {};
100 template<typename I>
101 struct has_arrow<I, true>
102  : disjunction<
103  std::is_pointer<I>,
104  has_operator_arrow<I&>
105  > {};
106 
107 } // namespace detail
108 
111 
112 template<typename V, typename Pred>
113 class filter_view : public view_interface<filter_view<V, Pred>>, detail::filter_view_cache<V> {
114  V base_;
115  movable_box<Pred> pred_;
116  using cache_base = detail::filter_view_cache<V>;
117 
118  public:
119  static_assert(input_range<V>::value, "Constraints not satisfied");
120  static_assert(indirect_unary_predicate<Pred, iterator_t<V>>::value, "Constraints not satisfied");
121  static_assert(view<V>::value, "Constraints not satisfied");
122  static_assert(std::is_object<V>::value, "Constraints not satisfied");
123 
124  class iterator : public detail::filter_view_iterator_category<V> {
125  public:
127  std::conditional_t<
129  std::conditional_t<
132  >>;
135 #if __cplusplus < 202002L
136  using pointer = void;
138 #endif
139 
140  iterator() = default;
141 
142  constexpr iterator(filter_view& parent, iterator_t<V> current)
143  : current_(std::move(current)), parent_(vccc::addressof(parent)) {}
144 
145  constexpr const iterator_t<V>& base() const& noexcept {
146  return current_;
147  }
148 
149  constexpr iterator_t<V> base() && noexcept {
150  return std::move(current_);
151  }
152 
153  constexpr range_reference_t<V> operator*() const {
154  return *current_;
155  }
156 
157  template<typename V2 = V, std::enable_if_t<conjunction<
158  detail::has_arrow<iterator_t<V2>>,
160  >::value, int> = 0>
161  constexpr iterator_t<V> operator->() const {
162  return current_;
163  }
164 
165  constexpr iterator& operator++() {
166  current_ = ranges::find_if(
167  std::move(++current_), ranges::end(parent_->base_), std::ref(*parent_->pred_));
168  return *this;
169  }
170 
172  constexpr void operator++(int) {
173  return ++*this;
174  }
175 
177  constexpr iterator operator++(int) {
178  auto tmp = *this;
179  ++*this;
180  return tmp;
181  }
182 
184  constexpr iterator& operator--() {
185  do {
186  --current_;
187  } while (!vccc::invoke(*parent_->pred_, *current_));
188  return *this;
189  }
190 
192  constexpr iterator& operator--(int) {
193  auto tmp = *this;
194  --*this;
195  return tmp;
196  }
197 
198  template<typename V2 = V, std::enable_if_t<equality_comparable<iterator_t<V2>>::value, int> = 0>
199  friend constexpr bool operator==(const iterator& x, const iterator& y) {
200  return x.current_ == y.current_;
201  }
202 
203  template<typename V2 = V, std::enable_if_t<equality_comparable<iterator_t<V2>>::value, int> = 0>
204  friend constexpr bool operator!=(const iterator& x, const iterator& y) {
205  return !(x == y);
206  }
207 
208  friend constexpr range_rvalue_reference_t<V>
209  iter_move(const iterator& i) noexcept(noexcept( ranges::iter_move(i.current_) )) {
210  return ranges::iter_move(i.current_);
211  }
212 
213  // TODO: Solve "const_cast from rvalue to reference type" in AppleClang 14.0.3.14030022
214  template<typename V2 = V, std::enable_if_t<indirectly_swappable<iterator_t<V2>>::value, int> = 0>
215  friend constexpr void iter_swap(const iterator& x, const iterator& y)
216  noexcept(noexcept(ranges::iter_swap(x.current_, y.current_)))
217  {
218  ranges::iter_swap(x.current_, y.current_);
219  }
220 
221  private:
222  iterator_t<V> current_;
223  filter_view* parent_;
224  };
225 
226  class sentinel {
227  sentinel() = default;
228 
229  constexpr explicit sentinel(filter_view& parent)
230  : end_(ranges::end(parent)) {}
231 
232  constexpr sentinel_t<V> base() const {
233  return end_;
234  }
235 
236  friend constexpr bool operator==(const iterator& x, const sentinel& y) {
237  return x.base() == y.end_;
238  }
239 
240  friend constexpr bool operator==(const sentinel& y, const iterator& x) {
241  return x == y;
242  }
243 
244  friend constexpr bool operator!=(const iterator& x, const sentinel& y) {
245  return !(x == y);
246  }
247 
248  friend constexpr bool operator!=(const sentinel& y, const iterator& x) {
249  return !(x == y);
250  }
251 
252  private:
253  sentinel_t<V> end_;
254  };
255 
256  friend class iterator;
257 
258  filter_view() = default;
259 
260  constexpr explicit filter_view(V base, Pred pred)
261  : base_(std::move(base)), pred_(std::move(pred)) {}
262 
264  constexpr V base() const & {
265  return base_;
266  }
267 
268  constexpr V base() const && {
269  return std::move(base_);
270  }
271 
272  constexpr const Pred& pred() const {
273  assert(((void)"pred_ must contatin a value", pred_.has_value()));
274  return *pred_;
275  }
276 
277  constexpr iterator begin() {
278  return cache_base::template begin<iterator>(*this, base_, pred_);
279  }
280 
281  constexpr auto end() {
282  return end(common_range<V>{});
283  }
284 
285  private:
286  constexpr iterator end(std::true_type /* common_range */) {
287  return {*this, ranges::end(base_)};
288  }
289  constexpr sentinel end(std::false_type /* common_range */) {
290  return {*this};
291  }
292 };
293 
294 
295 #if __cplusplus >= 201703L
296 
297 template<typename R, typename Pred>
298 filter_view(R&&, Pred) -> filter_view<views::all_t<R>, Pred>;
299 
300 #endif
301 
303 
304 
305 } // namespace ranges
306 } // namespace vccc
307 
308 #endif // VCCC_RANGES_VIEWS_FILTER_VIEW_HPP
Definition: filter_view.hpp:124
constexpr iterator & operator--()
Definition: filter_view.hpp:184
range_reference_t< V > reference
Definition: filter_view.hpp:137
constexpr iterator & operator--(int)
Definition: filter_view.hpp:192
constexpr const iterator_t< V > & base() const &noexcept
Definition: filter_view.hpp:145
void pointer
Definition: filter_view.hpp:136
constexpr void operator++(int)
Definition: filter_view.hpp:172
range_value_t< V > value_type
Definition: filter_view.hpp:133
constexpr friend bool operator==(const iterator &x, const iterator &y)
Definition: filter_view.hpp:199
constexpr range_reference_t< V > operator*() const
Definition: filter_view.hpp:153
constexpr friend bool operator!=(const iterator &x, const iterator &y)
Definition: filter_view.hpp:204
constexpr iterator_t< V > operator->() const
Definition: filter_view.hpp:161
constexpr friend range_rvalue_reference_t< V > iter_move(const iterator &i) noexcept(noexcept(ranges::iter_move(i.current_)))
Definition: filter_view.hpp:209
std::conditional_t< bidirectional_range< V >::value, bidirectional_iterator_tag, std::conditional_t< forward_range< V >::value, forward_iterator_tag, input_iterator_tag > > iterator_concept
Definition: filter_view.hpp:132
constexpr iterator operator++(int)
Definition: filter_view.hpp:177
constexpr iterator_t< V > base() &&noexcept
Definition: filter_view.hpp:149
constexpr friend void iter_swap(const iterator &x, const iterator &y) noexcept(noexcept(ranges::iter_swap(x.current_, y.current_)))
Definition: filter_view.hpp:215
range_difference_t< V > difference_type
Definition: filter_view.hpp:134
constexpr iterator & operator++()
Definition: filter_view.hpp:165
constexpr iterator(filter_view &parent, iterator_t< V > current)
Definition: filter_view.hpp:142
Definition: filter_view.hpp:226
constexpr friend bool operator!=(const iterator &x, const sentinel &y)
Definition: filter_view.hpp:244
constexpr friend bool operator==(const iterator &x, const sentinel &y)
Definition: filter_view.hpp:236
constexpr friend bool operator==(const sentinel &y, const iterator &x)
Definition: filter_view.hpp:240
constexpr friend bool operator!=(const sentinel &y, const iterator &x)
Definition: filter_view.hpp:248
Definition: filter_view.hpp:113
constexpr V base() const &
Definition: filter_view.hpp:264
friend class iterator
Definition: filter_view.hpp:256
constexpr const Pred & pred() const
Definition: filter_view.hpp:272
constexpr iterator begin()
Definition: filter_view.hpp:277
constexpr auto end()
Definition: filter_view.hpp:281
constexpr filter_view(V base, Pred pred)
Definition: filter_view.hpp:260
constexpr V base() const &&
Definition: filter_view.hpp:268
helper class template for defining a view, using the curiously recurring template pattern
Definition: view_interface.hpp:78
constexpr VCCC_INLINE_OR_STATIC detail::find_if_niebloid find_if
Definition: find_if.hpp:53
constexpr invoke_result_t< F, Args... > invoke(F &&f, Args &&... args) noexcept(is_nothrow_invocable< F, Args... >::value)
Definition: invoke.hpp:38
constexpr VCCC_INLINE_OR_STATIC detail_iter_move::iter_move_niebloid iter_move
Definition: iter_move.hpp:92
constexpr VCCC_INLINE_OR_STATIC detail_iter_swap::iter_swap_niebloid iter_swap
Definition: iter_swap.hpp:90
std::forward_iterator_tag forward_iterator_tag
Definition: iterator_tag.hpp:17
std::input_iterator_tag input_iterator_tag
Definition: iterator_tag.hpp:15
std::bidirectional_iterator_tag bidirectional_iterator_tag
Definition: iterator_tag.hpp:18
std::enable_if_t< std::is_object< T >::value, T * > addressof(T &t) noexcept
Definition: addressof.hpp:33
typename sentinel< R >::type sentinel_t
Definition: sentinel_t.hpp:29
typename ranges::iterator< T >::type iterator_t
Definition: iterator_t.hpp:32
constexpr VCCC_INLINE_OR_STATIC detail::begin_niebloid begin
returns an iterator to the beginning of a range
Definition: begin.hpp:116
typename range_rvalue_reference< R >::type range_rvalue_reference_t
Used to obtain the rvalue reference type of the iterator type of range type R.
Definition: range_rvalue_reference_t.hpp:38
constexpr VCCC_INLINE_OR_STATIC detail::end_niebloid end
returns a sentinel indicating the end of a range
Definition: end.hpp:120
typename range_difference< R >::type range_difference_t
Used to obtain the difference type of the iterator type of range type R.
Definition: range_difference_t.hpp:41
typename range_reference< R >::type range_reference_t
Used to obtain the reference type of the iterator type of range type R.
Definition: range_reference_t.hpp:42
typename range_value< R >::type range_value_t
Used to obtain the value type of the iterator type of range type R.
Definition: range_value_t.hpp:42
Definition: matrix.hpp:495
Definition: directory.h:12
constexpr VCCC_INLINE_OR_STATIC detail::element_niebloid< 1 > value
Definition: key_value.hpp:35
Definition: conjunction.hpp:22
specifies that an object of a type can be copied, moved, and swapped
Definition: copyable.hpp:59
specifies that a callable type, when invoked with the result of dereferencing an indirectly_readable ...
Definition: indirect_unary_predicate.hpp:49
specifies a range whose iterator type satisfies bidirectional_iterator
Definition: bidirectional_range.hpp:49
Definition: common_range.hpp:41
specifies a range whose iterator type satisfies forward_iterator
Definition: forward_range.hpp:47
specifies a range whose iterator type satisfies input_iterator
Definition: input_range.hpp:46
specifies that a range is a view, that is, it has constant time copy/move/assignment
Definition: view.hpp:31