halcheck 1.0
Loading...
Searching...
No Matches
filter.hpp
1#ifndef HALCHECK_LIB_ITERATOR_FILTER_HPP
2#define HALCHECK_LIB_ITERATOR_FILTER_HPP
3
4// IWYU pragma: private, include <halcheck/lib/iterator.hpp>
5
6#include <halcheck/lib/functional.hpp>
7#include <halcheck/lib/iterator/base.hpp>
8#include <halcheck/lib/iterator/interface.hpp>
9#include <halcheck/lib/iterator/range.hpp>
10#include <halcheck/lib/iterator/type_traits.hpp>
11#include <halcheck/lib/optional.hpp>
12#include <halcheck/lib/pp.hpp>
13#include <halcheck/lib/type_traits.hpp>
14
15#include <iterator>
16#include <memory>
17
18namespace halcheck { namespace lib {
19
26template<typename I, typename F>
27class filter_iterator : public lib::iterator_interface<filter_iterator<I, F>> {
28public:
29 static_assert(lib::is_input_iterator<I>(), "I must be an input iterator");
30 static_assert(std::is_copy_constructible<F>(), "F must be copy constructible");
31 static_assert(std::is_object<F>(), "F must be an object");
32 static_assert(
34 "F must be invocable and return a boolean-testable value");
35
36 template<typename, typename>
37 friend class filter_iterator;
38
41
46
51
55 using pointer = void;
56
61
67
71 constexpr filter_iterator() = default;
72
79 filter_iterator(I base, I end, F fun) : _base(std::move(base)), _end(std::move(end)), _func(std::move(fun)) {
80 while (_base != _end && !lib::invoke(*_func, *_base))
81 ++_base;
82 }
83
92 template<
93 typename I2,
94 typename F2,
97 constexpr filter_iterator(filter_iterator<I2, F2> other) // NOLINT
98 : _base(std::move(other._base)), _end(std::move(other._end)), _func(std::move(*other._func)) {}
99
109 template<
110 typename I2,
111 typename F2,
115 explicit constexpr filter_iterator(filter_iterator<I2, F2> other) // NOLINT
116 : _base(std::move(other._base)), _end(std::move(other._end)), _func(*std::move(other._func)) {}
117
122 constexpr const I &base() const & noexcept { return _base; }
123
128 I base() && { return std::move(_base); }
129
134 constexpr reference operator*() const noexcept(noexcept(*std::declval<const I &>())) { return *_base; }
135
141 do {
142 ++_base;
143 } while (_base != _end && !lib::invoke(*_func, *_base));
144 return *this;
145 }
146
151 template<bool _ = true, HALCHECK_REQUIRE(lib::is_bidirectional_iterator<I>() && _)>
152 filter_iterator &operator--() {
153 do {
154 --_base;
155 } while (!lib::invoke(*_func, *_base));
156 return *this;
157 }
158
159private:
165 friend constexpr bool operator==(const filter_iterator &lhs, const filter_iterator &rhs) {
166 return lhs._base == rhs._base;
167 }
168
169 I _base, _end;
170 lib::optional<F> _func;
171};
172
189 template<typename I, typename F>
190 lib::filter_iterator<I, F> operator()(I base, I end, F func) const {
191 return lib::filter_iterator<I, F>(std::move(base), std::move(end), std::move(func));
192 }
194
195template<
196 typename V,
197 typename F,
202class filter_view : public lib::view_interface<filter_view<V, F>> {
203private:
204 struct ref {
205 explicit ref(const F *base = nullptr) : base(base) {}
206 template<typename... Args>
207 lib::invoke_result_t<const F &, Args...> operator()(Args &&...args) const {
208 return lib::invoke(*base, std::forward<Args>(args)...);
209 }
210 const F *base;
211 };
212
213public:
214 filter_view() = default;
215
216 filter_view(V base, F func) : _base(std::move(base)), _func(std::move(func)) {}
217
218 template<bool _ = true, HALCHECK_REQUIRE(std::is_copy_constructible<V>() && _)>
219 constexpr V base() const & {
220 return _base;
221 }
222
223 V base() && { return std::move(_base); }
224
225 lib::filter_iterator<lib::iterator_t<V>, ref> begin() {
226 return lib::make_filter_iterator(lib::begin(_base), lib::end(_base), ref{std::addressof(*_func)});
227 }
228
229 template<
230 typename U = V,
231 HALCHECK_REQUIRE(lib::is_input_range<const U>()),
232 HALCHECK_REQUIRE(lib::is_boolean_testable<lib::invoke_result_t<const F &, lib::range_reference_t<const U>>>())>
233 lib::filter_iterator<lib::iterator_t<const U>, ref> begin() const {
234 return lib::make_filter_iterator(lib::begin(_base), lib::end(_base), ref{std::addressof(*_func)});
235 }
236
237 lib::filter_iterator<lib::iterator_t<V>, ref> end() {
238 return lib::make_filter_iterator(lib::end(_base), lib::end(_base), ref{std::addressof(*_func)});
239 }
240
241 template<
242 typename U = V,
243 HALCHECK_REQUIRE(lib::is_range<const U>()),
244 HALCHECK_REQUIRE(lib::is_boolean_testable<lib::invoke_result_t<const F &, lib::range_reference_t<const U>>>())>
245 lib::filter_iterator<lib::iterator_t<const U>, ref> end() const {
246 return lib::make_filter_iterator(lib::end(_base), lib::end(_base), ref{std::addressof(*_func)});
247 }
248
249private:
250 V _base;
251 lib::optional<F> _func;
252};
253
254template<typename V, typename F>
255lib::filter_view<V, F> filter(V base, F func) {
256 return lib::filter_view<V, F>(std::move(base), std::move(func));
257}
258
259}} // namespace halcheck::lib
260
261#endif
T addressof(T... args)
friend constexpr bool operator==(const filter_iterator &lhs, const filter_iterator &rhs)
Compares two filter_iterators for equality.
Definition filter.hpp:165
filter_iterator & operator++()
Advances the base iterator to the next element that satisfies the predicate.
Definition filter.hpp:140
I base() &&
Get the base iterator of this filter_iterator.
Definition filter.hpp:128
constexpr filter_iterator(filter_iterator< I2, F2 > other)
Performs a conversion on a filter_iterator with compatible type parameters.
Definition filter.hpp:97
lib::conditional_t< lib::is_random_access_iterator< I >{}, std::bidirectional_iterator_tag, lib::iter_category_t< I > > iterator_category
Indicates the level of supported iterator operations this type provides.
Definition filter.hpp:65
filter_iterator(I base, I end, F fun)
Constructs a filter_iterator from a (begin, end] pair of iterators and a predicate.
Definition filter.hpp:79
constexpr reference operator*() const noexcept(noexcept(*std::declval< const I & >()))
Dereferences the base iterator.
Definition filter.hpp:134
constexpr const I & base() const &noexcept
Get a reference to the base iterator of this filter_iterator.
Definition filter.hpp:122
An iterator adaptor that skips elements that do not satisfy user-defined predicate.
Definition filter.hpp:27
lib::iter_difference_t< I > difference_type
The return type of operator-.
Definition filter.hpp:60
void pointer
This iterator type does not support operator->.
Definition filter.hpp:55
lib::iter_value_t< I > value_type
The type of value pointed to by this type of iterator.
Definition filter.hpp:45
constexpr filter_iterator()=default
Constructs a default filter_iterator.
lib::iter_reference_t< I > reference
The return type of operator*.
Definition filter.hpp:50
A utility class for easily defining new iterators.
Definition interface.hpp:40
An implementation of std::optional.
Definition optional.hpp:338
An implementation of std::ranges::view_interface.
Definition interface.hpp:238
T forward(T... args)
HALCHECK_INLINE_CONSTEXPR struct halcheck::lib::@20 invoke
An implementation of std::invoke.
decltype(lib::invoke(std::declval< F >(), std::declval< Args >()...)) invoke_result_t
An implementation of std::invoke_result_t.
Definition invoke.hpp:42
typename std::iterator_traits< I >::value_type iter_value_t
The type of value pointed to by an iterator.
Definition base.hpp:16
typename std::iterator_traits< I >::difference_type iter_difference_t
The return type of operator- for an iterator.
Definition base.hpp:32
typename std::iterator_traits< I >::reference iter_reference_t
The return type of operator* for an iterator.
Definition base.hpp:24
typename std::iterator_traits< I >::iterator_category iter_category_t
A tag type indicating the level of supported iterator options a type provides.
Definition base.hpp:40
lib::iter_reference_t< lib::iterator_t< R > > range_reference_t
The type returned by operator* for a range type's iterators.
Definition range.hpp:340
HALCHECK_INLINE_CONSTEXPR struct halcheck::lib::end_cpo::@28 end
Gets an iterator to past the end of a range.
HALCHECK_INLINE_CONSTEXPR struct halcheck::lib::@21 make_filter_iterator
Constructs a filter_iterator.
#define HALCHECK_INLINE_CONSTEXPR
A backwards-compatible substitute for inline constexpr.
Definition pp.hpp:70
typename std::conditional< Cond, T, F >::type conditional_t
An implementation of std::conditional_t.
Definition type_traits.hpp:51
#define HALCHECK_REQUIRE(...)
Expands to a template argument that is only valid if the given argument evaluates to true.
Definition type_traits.hpp:24
STL namespace.
Determines if a type is satisfies the boolean-testable concept.
Definition type_traits.hpp:370
Determines whether a type satisfies the LegacyInputIterator concept.
Definition type_traits.hpp:54
Determines whether a type is a range whose iterators satisfy lib::is_input_iterator.
Definition range.hpp:183