C/C++ API Reference
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
25
28
48template <typename Container, typename Filter>
50 public:
51 // Iterator that only moves to elements that match the provided filter.
52 class iterator {
53 public:
54 using difference_type = std::ptrdiff_t;
55 using value_type = typename Container::value_type;
56 using pointer = typename Container::pointer;
57 using reference = typename Container::reference;
58 using iterator_category = std::bidirectional_iterator_tag;
59
60 constexpr iterator() : view_(nullptr), it_(0) {}
61
62 iterator& operator++();
63
64 iterator operator++(int) {
65 iterator original = *this;
66 operator++();
67 return original;
68 }
69
70 iterator& operator--();
71
72 iterator operator--(int) {
73 iterator original = *this;
74 operator--();
75 return original;
76 }
77
78 const auto& operator*() const { return value(); }
79
80 const auto* operator->() const { return &value(); }
81
82 constexpr bool operator==(const iterator& other) const {
83 return view_ == other.view_ && it_ == other.it_;
84 }
85
86 constexpr bool operator!=(const iterator& other) const {
87 return !(*this == other);
88 }
89
90 private:
91 friend class FilteredView;
92
93 enum EndIterator { kEnd };
94
95 explicit iterator(const FilteredView& view)
96 : view_(&view), it_(view.container_->begin()) {
97 FindMatch();
98 }
99
100 iterator(const FilteredView& view, EndIterator)
101 : view_(&view), it_(view.container_->end()) {}
102
103 // Accesses the value referred to by this iterator.
104 const auto& value() const { return *it_; }
105
106 // Iterates until a match is found, up to end().
107 void FindMatch();
108
109 bool MatchesItem(const value_type& value) const {
110 return view_->filter_(value);
111 }
112
113 const FilteredView* view_;
114 typename Container::const_iterator it_;
115 };
116
117 using const_iterator = iterator;
118
119 constexpr explicit FilteredView(const Container& container,
120 const Filter& filter)
121 : container_(&container), filter_(filter) {}
122
123 constexpr explicit FilteredView(const Container& container, Filter&& filter)
124 : container_(&container), filter_(std::move(filter)) {}
125
126 constexpr FilteredView(FilteredView&&) = default;
127 constexpr FilteredView& operator=(FilteredView&&) = default;
128
129 constexpr FilteredView(const FilteredView&) = delete;
130 constexpr FilteredView& operator=(const FilteredView&) = delete;
131
132 const auto& operator[](size_t index) const {
133 auto it = begin();
134 std::advance(it, index);
135 return *it;
136 }
137
138 // Accesses the first matching element. Invalid if empty().
139 const auto& front() const { return *begin(); }
140
141 // Accesses the last matching element. Invalid if empty().
142 const auto& back() const { return *std::prev(end()); }
143
144 // The number of elements in the container that match the filter.
145 size_t size() const {
146 return static_cast<size_t>(std::distance(begin(), end()));
147 }
148
149 bool empty() const { return begin() == end(); }
150
151 iterator begin() const { return iterator(*this); }
152 iterator end() const { return iterator(*this, iterator::kEnd); }
153
154 private:
155 const Container* container_;
156 Filter filter_;
157};
158
159template <typename Container, typename Filter>
160void FilteredView<Container, Filter>::iterator::FindMatch() {
161 for (; it_ != view_->container_->end(); ++it_) {
162 if (MatchesItem(*it_)) {
163 break;
164 }
165 }
166}
167
168template <typename Container, typename Filter>
169typename FilteredView<Container, Filter>::iterator&
170FilteredView<Container, Filter>::iterator::operator++() {
171 PW_ASSERT(it_ != view_->container_->end());
172
173 ++it_;
174 FindMatch();
175 return *this;
176}
177
178template <typename Container, typename Filter>
179typename FilteredView<Container, Filter>::iterator&
180FilteredView<Container, Filter>::iterator::operator--() {
181 decltype(it_) new_it = view_->container_->end();
182 while (new_it != view_->container_->begin()) {
183 --new_it;
184 if (MatchesItem(*new_it)) {
185 it_ = new_it;
186 return *this;
187 }
188 }
189
190 PW_ASSERT(false);
192}
193
194} // namespace pw::containers
Definition: filtered_view.h:52
Definition: filtered_view.h:49
#define PW_UNREACHABLE
Definition: compiler.h:138