Pigweed
 
Loading...
Searching...
No Matches
filtered_view.h
1// Copyright 2021 The Pigweed Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License"); you may not
4// use this file except in compliance with the License. You may obtain a copy of
5// the License at
6//
7// https://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12// License for the specific language governing permissions and limitations under
13// the License.
14#pragma once
15
16#include <cstddef>
17#include <iterator>
18
19#include "pw_assert/assert.h"
20#include "pw_preprocessor/compiler.h"
21
22namespace pw::containers {
23
43template <typename Container, typename Filter>
45 public:
46 // Iterator that only moves to elements that match the provided filter.
47 class iterator {
48 public:
49 using difference_type = std::ptrdiff_t;
50 using value_type = typename Container::value_type;
51 using pointer = typename Container::pointer;
52 using reference = typename Container::reference;
53 using iterator_category = std::bidirectional_iterator_tag;
54
55 constexpr iterator() : view_(nullptr), it_(0) {}
56
57 iterator& operator++();
58
59 iterator operator++(int) {
60 iterator original = *this;
61 operator++();
62 return original;
63 }
64
65 iterator& operator--();
66
67 iterator operator--(int) {
68 iterator original = *this;
69 operator--();
70 return original;
71 }
72
73 const auto& operator*() const { return value(); }
74
75 const auto* operator->() const { return &value(); }
76
77 constexpr bool operator==(const iterator& other) const {
78 return view_ == other.view_ && it_ == other.it_;
79 }
80
81 constexpr bool operator!=(const iterator& other) const {
82 return !(*this == other);
83 }
84
85 private:
86 friend class FilteredView;
87
88 enum EndIterator { kEnd };
89
90 explicit iterator(const FilteredView& view)
91 : view_(&view), it_(view.container_->begin()) {
92 FindMatch();
93 }
94
95 iterator(const FilteredView& view, EndIterator)
96 : view_(&view), it_(view.container_->end()) {}
97
98 // Accesses the value referred to by this iterator.
99 const auto& value() const { return *it_; }
100
101 // Iterates until a match is found, up to end().
102 void FindMatch();
103
104 bool MatchesItem(const value_type& value) const {
105 return view_->filter_(value);
106 }
107
108 const FilteredView* view_;
109 typename Container::const_iterator it_;
110 };
111
112 using const_iterator = iterator;
113
114 constexpr explicit FilteredView(const Container& container,
115 const Filter& filter)
116 : container_(&container), filter_(filter) {}
117
118 constexpr explicit FilteredView(const Container& container, Filter&& filter)
119 : container_(&container), filter_(std::move(filter)) {}
120
121 constexpr FilteredView(FilteredView&&) = default;
122 constexpr FilteredView& operator=(FilteredView&&) = default;
123
124 constexpr FilteredView(const FilteredView&) = delete;
125 constexpr FilteredView& operator=(const FilteredView&) = delete;
126
127 const auto& operator[](size_t index) const {
128 auto it = begin();
129 std::advance(it, index);
130 return *it;
131 }
132
133 // Accesses the first matching element. Invalid if empty().
134 const auto& front() const { return *begin(); }
135
136 // Accesses the last matching element. Invalid if empty().
137 const auto& back() const { return *std::prev(end()); }
138
139 // The number of elements in the container that match the filter.
140 size_t size() const {
141 return static_cast<size_t>(std::distance(begin(), end()));
142 }
143
144 bool empty() const { return begin() == end(); }
145
146 iterator begin() const { return iterator(*this); }
147 iterator end() const { return iterator(*this, iterator::kEnd); }
148
149 private:
150 const Container* container_;
151 Filter filter_;
152};
153
154template <typename Container, typename Filter>
155void FilteredView<Container, Filter>::iterator::FindMatch() {
156 for (; it_ != view_->container_->end(); ++it_) {
157 if (MatchesItem(*it_)) {
158 break;
159 }
160 }
161}
162
163template <typename Container, typename Filter>
164typename FilteredView<Container, Filter>::iterator&
165FilteredView<Container, Filter>::iterator::operator++() {
166 PW_ASSERT(it_ != view_->container_->end());
167
168 ++it_;
169 FindMatch();
170 return *this;
171}
172
173template <typename Container, typename Filter>
174typename FilteredView<Container, Filter>::iterator&
175FilteredView<Container, Filter>::iterator::operator--() {
176 decltype(it_) new_it = view_->container_->end();
177 while (new_it != view_->container_->begin()) {
178 --new_it;
179 if (MatchesItem(*new_it)) {
180 it_ = new_it;
181 return *this;
182 }
183 }
184
185 PW_ASSERT(false);
187}
188
189} // namespace pw::containers
Definition: filtered_view.h:47
Definition: filtered_view.h:44
#define PW_UNREACHABLE
Definition: compiler.h:135
Definition: algorithm.h:46