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-2022, 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 #include <boost/range/concepts.hpp>
31 #include <ndn-cxx/util/concepts.hpp>
32 
33 namespace nfd::name_tree {
34 
36 BOOST_CONCEPT_ASSERT((boost::ForwardRangeConcept<Range>));
37 
38 NFD_LOG_INIT(NameTreeIterator);
39 
40 Iterator::Iterator() = default;
41 
42 Iterator::Iterator(shared_ptr<EnumerationImpl> impl, const Entry* ref)
43  : m_impl(std::move(impl))
44  , m_ref(ref)
45 {
46  m_impl->advance(*this);
47  NFD_LOG_TRACE("initialized " << *this);
48 }
49 
50 Iterator&
52 {
53  BOOST_ASSERT(m_impl != nullptr);
54  m_impl->advance(*this);
55  NFD_LOG_TRACE("advanced " << *this);
56  return *this;
57 }
58 
61 {
62  Iterator copy = *this;
63  this->operator++();
64  return copy;
65 }
66 
67 bool
68 Iterator::operator==(const Iterator& other) const
69 {
70  return m_entry == other.m_entry;
71 }
72 
73 std::ostream&
74 operator<<(std::ostream& os, const Iterator& i)
75 {
76  if (i.m_impl == nullptr) {
77  return os << "end";
78  }
79  if (i.m_entry == nullptr) {
80  return os << "uninitialized";
81  }
82 
83  os << "entry=" << i.m_entry->getName();
84  if (i.m_ref == nullptr) {
85  os << " ref=null";
86  }
87  else {
88  os << " ref=" << i.m_ref->getName();
89  }
90  os << " state=" << i.m_state;
91  return os;
92 }
93 
95  : nt(nt)
96  , ht(nt.m_ht)
97 {
98 }
99 
101  : EnumerationImpl(nt)
102  , m_pred(pred)
103 {
104 }
105 
106 void
108 {
109  // find first entry
110  if (i.m_entry == nullptr) {
111  for (size_t bucket = 0; bucket < ht.getNBuckets(); ++bucket) {
112  const Node* node = ht.getBucket(bucket);
113  if (node != nullptr) {
114  i.m_entry = &node->entry;
115  break;
116  }
117  }
118  if (i.m_entry == nullptr) { // empty enumerable
119  i = Iterator();
120  return;
121  }
122  if (m_pred(*i.m_entry)) { // visit first entry
123  return;
124  }
125  }
126 
127  // process entries in same bucket
128  for (const Node* node = getNode(*i.m_entry)->next; node != nullptr; node = node->next) {
129  if (m_pred(node->entry)) {
130  i.m_entry = &node->entry;
131  return;
132  }
133  }
134 
135  // process other buckets
136  size_t currentBucket = ht.computeBucketIndex(getNode(*i.m_entry)->hash);
137  for (size_t bucket = currentBucket + 1; bucket < ht.getNBuckets(); ++bucket) {
138  for (const Node* node = ht.getBucket(bucket); node != nullptr; node = node->next) {
139  if (m_pred(node->entry)) {
140  i.m_entry = &node->entry;
141  return;
142  }
143  }
144  }
145 
146  // reach the end
147  i = Iterator();
148 }
149 
151  : EnumerationImpl(nt)
152  , m_pred(pred)
153 {
154 }
155 
156 void
158 {
159  bool wantSelf = false;
160  bool wantChildren = false;
161 
162  // initialize: start from root
163  if (i.m_entry == nullptr) {
164  if (i.m_ref == nullptr) { // root does not exist
165  i = Iterator();
166  return;
167  }
168 
169  i.m_entry = i.m_ref;
170  std::tie(wantSelf, wantChildren) = m_pred(*i.m_entry);
171  if (wantSelf) { // visit root
172  i.m_state = wantChildren;
173  return;
174  }
175  }
176  else {
177  wantChildren = static_cast<bool>(i.m_state);
178  }
179  BOOST_ASSERT(i.m_ref != nullptr);
180 
181  // pre-order traversal
182  while (i.m_entry != i.m_ref || (wantChildren && i.m_entry->hasChildren())) {
183  if (wantChildren && i.m_entry->hasChildren()) { // process children of m_entry
184  i.m_entry = i.m_entry->getChildren().front();
185  std::tie(wantSelf, wantChildren) = m_pred(*i.m_entry);
186  if (wantSelf) { // visit first child
187  i.m_state = wantChildren;
188  return;
189  }
190  // first child rejected, let while loop process other children (siblings of new m_entry)
191  }
192  else { // process siblings of m_entry
193  const Entry* parent = i.m_entry->getParent();
194  const std::vector<Entry*>& siblings = parent->getChildren();
195  auto sibling = std::find(siblings.begin(), siblings.end(), i.m_entry);
196  BOOST_ASSERT(sibling != siblings.end());
197  while (++sibling != siblings.end()) {
198  i.m_entry = *sibling;
199  std::tie(wantSelf, wantChildren) = m_pred(*i.m_entry);
200  if (wantSelf) { // visit sibling
201  i.m_state = wantChildren;
202  return;
203  }
204  if (wantChildren) {
205  break; // let outer while loop process children of m_entry
206  }
207  // process next sibling
208  }
209  if (sibling == siblings.end()) { // no more sibling
210  i.m_entry = parent;
211  wantChildren = false;
212  }
213  }
214  }
215 
216  // reach the end
217  i = Iterator();
218 }
219 
221  : EnumerationImpl(nt)
222  , m_pred(pred)
223 {
224 }
225 
226 void
227 PrefixMatchImpl::advance(Iterator& i)
228 {
229  if (i.m_entry == nullptr) {
230  if (i.m_ref == nullptr) { // empty enumerable
231  i = Iterator();
232  return;
233  }
234 
235  i.m_entry = i.m_ref;
236  if (m_pred(*i.m_entry)) { // visit starting node
237  return;
238  }
239  }
240 
241  // traverse up the tree
242  while ((i.m_entry = i.m_entry->getParent()) != nullptr) {
243  if (m_pred(*i.m_entry)) {
244  return;
245  }
246  }
247 
248  // reach the end
249  i = Iterator();
250 }
251 
252 } // 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
bool operator==(const Iterator &other) 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)
NDN_CXX_ASSERT_FORWARD_ITERATOR(Iterator)
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.