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 
26 #include "name-tree-iterator.hpp"
27 #include "name-tree.hpp"
28 #include "common/logger.hpp"
29 
30 namespace nfd::name_tree {
31 
32 NFD_LOG_INIT(NameTreeIterator);
33 
34 Iterator::Iterator() = default;
35 
36 Iterator::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 
44 Iterator&
46 {
47  BOOST_ASSERT(m_impl != nullptr);
48  m_impl->advance(*this);
49  NFD_LOG_TRACE("advanced " << *this);
50  return *this;
51 }
52 
53 std::ostream&
54 operator<<(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 
86 void
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 
136 void
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 
206 void
207 PrefixMatchImpl::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.
Entry * getParent() const noexcept
const std::vector< Entry * > & getChildren() const noexcept
Returns the children of this entry.
bool hasChildren() const
Check whether this entry has any children.
const Name & getName() const noexcept
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.