Loading...
Searching...
No Matches
name-tree-iterator.cpp
Go to the documentation of this file.
1/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/*
3 * Copyright (c) 2014-2023, Regents of the University of California,
4 * Arizona Board of Regents,
5 * Colorado State University,
6 * University Pierre & Marie Curie, Sorbonne University,
7 * Washington University in St. Louis,
8 * Beijing Institute of Technology,
9 * The University of Memphis.
10 *
11 * This file is part of NFD (Named Data Networking Forwarding Daemon).
12 * See AUTHORS.md for complete list of NFD authors and contributors.
13 *
14 * NFD is free software: you can redistribute it and/or modify it under the terms
15 * of the GNU General Public License as published by the Free Software Foundation,
16 * either version 3 of the License, or (at your option) any later version.
17 *
18 * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
19 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
20 * PURPOSE. See the GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License along with
23 * NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
24 */
25
27#include "name-tree.hpp"
28#include "common/logger.hpp"
29
30namespace nfd::name_tree {
31
32NFD_LOG_INIT(NameTreeIterator);
33
34Iterator::Iterator() = default;
35
36Iterator::Iterator(shared_ptr<EnumerationImpl> impl, const Entry* ref)
37 : m_impl(std::move(impl))
38 , m_ref(ref)
39{
40 m_impl->advance(*this);
41 NFD_LOG_TRACE("initialized " << *this);
42}
43
46{
47 BOOST_ASSERT(m_impl != nullptr);
48 m_impl->advance(*this);
49 NFD_LOG_TRACE("advanced " << *this);
50 return *this;
51}
52
53std::ostream&
54operator<<(std::ostream& os, const Iterator& i)
55{
56 if (i.m_impl == nullptr) {
57 return os << "end";
58 }
59 if (i.m_entry == nullptr) {
60 return os << "uninitialized";
61 }
62
63 os << "entry=" << i.m_entry->getName();
64 if (i.m_ref == nullptr) {
65 os << " ref=null";
66 }
67 else {
68 os << " ref=" << i.m_ref->getName();
69 }
70 os << " state=" << i.m_state;
71 return os;
72}
73
75 : nt(nt)
76 , ht(nt.m_ht)
77{
78}
79
81 : EnumerationImpl(nt)
82 , m_pred(pred)
83{
84}
85
86void
88{
89 // find first entry
90 if (i.m_entry == nullptr) {
91 for (size_t bucket = 0; bucket < ht.getNBuckets(); ++bucket) {
92 const Node* node = ht.getBucket(bucket);
93 if (node != nullptr) {
94 i.m_entry = &node->entry;
95 break;
96 }
97 }
98 if (i.m_entry == nullptr) { // empty enumerable
99 i = Iterator();
100 return;
101 }
102 if (m_pred(*i.m_entry)) { // visit first entry
103 return;
104 }
105 }
106
107 // process entries in same bucket
108 for (const Node* node = getNode(*i.m_entry)->next; node != nullptr; node = node->next) {
109 if (m_pred(node->entry)) {
110 i.m_entry = &node->entry;
111 return;
112 }
113 }
114
115 // process other buckets
116 size_t currentBucket = ht.computeBucketIndex(getNode(*i.m_entry)->hash);
117 for (size_t bucket = currentBucket + 1; bucket < ht.getNBuckets(); ++bucket) {
118 for (const Node* node = ht.getBucket(bucket); node != nullptr; node = node->next) {
119 if (m_pred(node->entry)) {
120 i.m_entry = &node->entry;
121 return;
122 }
123 }
124 }
125
126 // reach the end
127 i = Iterator();
128}
129
131 : EnumerationImpl(nt)
132 , m_pred(pred)
133{
134}
135
136void
138{
139 bool wantSelf = false;
140 bool wantChildren = false;
141
142 // initialize: start from root
143 if (i.m_entry == nullptr) {
144 if (i.m_ref == nullptr) { // root does not exist
145 i = Iterator();
146 return;
147 }
148
149 i.m_entry = i.m_ref;
150 std::tie(wantSelf, wantChildren) = m_pred(*i.m_entry);
151 if (wantSelf) { // visit root
152 i.m_state = wantChildren;
153 return;
154 }
155 }
156 else {
157 wantChildren = static_cast<bool>(i.m_state);
158 }
159 BOOST_ASSERT(i.m_ref != nullptr);
160
161 // pre-order traversal
162 while (i.m_entry != i.m_ref || (wantChildren && i.m_entry->hasChildren())) {
163 if (wantChildren && i.m_entry->hasChildren()) { // process children of m_entry
164 i.m_entry = i.m_entry->getChildren().front();
165 std::tie(wantSelf, wantChildren) = m_pred(*i.m_entry);
166 if (wantSelf) { // visit first child
167 i.m_state = wantChildren;
168 return;
169 }
170 // first child rejected, let while loop process other children (siblings of new m_entry)
171 }
172 else { // process siblings of m_entry
173 const Entry* parent = i.m_entry->getParent();
174 const std::vector<Entry*>& siblings = parent->getChildren();
175 auto sibling = std::find(siblings.begin(), siblings.end(), i.m_entry);
176 BOOST_ASSERT(sibling != siblings.end());
177 while (++sibling != siblings.end()) {
178 i.m_entry = *sibling;
179 std::tie(wantSelf, wantChildren) = m_pred(*i.m_entry);
180 if (wantSelf) { // visit sibling
181 i.m_state = wantChildren;
182 return;
183 }
184 if (wantChildren) {
185 break; // let outer while loop process children of m_entry
186 }
187 // process next sibling
188 }
189 if (sibling == siblings.end()) { // no more sibling
190 i.m_entry = parent;
191 wantChildren = false;
192 }
193 }
194 }
195
196 // reach the end
197 i = Iterator();
198}
199
201 : EnumerationImpl(nt)
202 , m_pred(pred)
203{
204}
205
206void
207PrefixMatchImpl::advance(Iterator& i)
208{
209 if (i.m_entry == nullptr) {
210 if (i.m_ref == nullptr) { // empty enumerable
211 i = Iterator();
212 return;
213 }
214
215 i.m_entry = i.m_ref;
216 if (m_pred(*i.m_entry)) { // visit starting node
217 return;
218 }
219 }
220
221 // traverse up the tree
222 while ((i.m_entry = i.m_entry->getParent()) != nullptr) {
223 if (m_pred(*i.m_entry)) {
224 return;
225 }
226 }
227
228 // reach the end
229 i = Iterator();
230}
231
232} // namespace nfd::name_tree
An entry in the name tree.
const Name & getName() const noexcept
Entry * getParent() const noexcept
bool hasChildren() const
Check whether this entry has any children.
const std::vector< Entry * > & getChildren() const noexcept
Returns the children of this entry.
Enumeration operation implementation.
FullEnumerationImpl(const NameTree &nt, const EntrySelector &pred)
const Node * getBucket(size_t bucket) const
size_t computeBucketIndex(HashValue h) const
A common index structure for FIB, PIT, StrategyChoice, and Measurements.
Definition name-tree.hpp:37
PartialEnumerationImpl(const NameTree &nt, const EntrySubTreeSelector &pred)
PrefixMatchImpl(const NameTree &nt, const EntrySelector &pred)
#define NFD_LOG_INIT(name)
Definition logger.hpp:31
#define NFD_LOG_TRACE
Definition logger.hpp:37
std::ostream & operator<<(std::ostream &os, const Iterator &i)
std::function< bool(const Entry &)> EntrySelector
A predicate to accept or reject an Entry in find operations.
Node * getNode(const Entry &entry)
std::function< std::pair< bool, bool >(const Entry &)> EntrySubTreeSelector
A predicate to accept or reject an Entry and its children.