blob: ecfe40d09e0b7e9e8ace21cba76fabd1732324c5 [file] [log] [blame]
Junxiao Shi029401f2016-08-05 12:55:14 +00001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Davide Pesavento981db802018-04-10 18:05:04 -04002/*
Davide Pesaventoe422f9e2022-06-03 01:30:23 -04003 * Copyright (c) 2014-2022, Regents of the University of California,
Junxiao Shi029401f2016-08-05 12:55:14 +00004 * 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"
Davide Pesavento2cae8ca2019-04-18 20:48:05 -040028#include "common/logger.hpp"
Davide Pesavento981db802018-04-10 18:05:04 -040029
Junxiao Shi9f6ca602016-08-15 04:50:29 +000030#include <boost/range/concepts.hpp>
Davide Pesavento981db802018-04-10 18:05:04 -040031#include <ndn-cxx/util/concepts.hpp>
Junxiao Shi029401f2016-08-05 12:55:14 +000032
Davide Pesaventoe422f9e2022-06-03 01:30:23 -040033namespace nfd::name_tree {
Junxiao Shi029401f2016-08-05 12:55:14 +000034
Davide Pesavento981db802018-04-10 18:05:04 -040035NDN_CXX_ASSERT_FORWARD_ITERATOR(Iterator);
Junxiao Shi9f6ca602016-08-15 04:50:29 +000036BOOST_CONCEPT_ASSERT((boost::ForwardRangeConcept<Range>));
37
Davide Pesaventoa3148082018-04-12 18:21:54 -040038NFD_LOG_INIT(NameTreeIterator);
Junxiao Shi9f6ca602016-08-15 04:50:29 +000039
Davide Pesaventoaa9e3b22022-10-21 17:00:07 -040040Iterator::Iterator() = default;
Junxiao Shi029401f2016-08-05 12:55:14 +000041
Junxiao Shib660b4c2016-08-06 20:47:44 +000042Iterator::Iterator(shared_ptr<EnumerationImpl> impl, const Entry* ref)
Davide Pesaventoe4b22382018-06-10 14:37:24 -040043 : m_impl(std::move(impl))
Junxiao Shi029401f2016-08-05 12:55:14 +000044 , m_ref(ref)
Junxiao Shi029401f2016-08-05 12:55:14 +000045{
46 m_impl->advance(*this);
47 NFD_LOG_TRACE("initialized " << *this);
48}
49
50Iterator&
51Iterator::operator++()
52{
53 BOOST_ASSERT(m_impl != nullptr);
54 m_impl->advance(*this);
55 NFD_LOG_TRACE("advanced " << *this);
56 return *this;
57}
58
59Iterator
60Iterator::operator++(int)
61{
62 Iterator copy = *this;
63 this->operator++();
64 return copy;
65}
66
67bool
68Iterator::operator==(const Iterator& other) const
69{
70 return m_entry == other.m_entry;
71}
72
73std::ostream&
74operator<<(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
Junxiao Shie3cf2852016-08-09 03:50:56 +000083 os << "entry=" << i.m_entry->getName();
Junxiao Shi029401f2016-08-05 12:55:14 +000084 if (i.m_ref == nullptr) {
85 os << " ref=null";
86 }
87 else {
Junxiao Shie3cf2852016-08-09 03:50:56 +000088 os << " ref=" << i.m_ref->getName();
Junxiao Shi029401f2016-08-05 12:55:14 +000089 }
90 os << " state=" << i.m_state;
91 return os;
92}
93
Junxiao Shib660b4c2016-08-06 20:47:44 +000094EnumerationImpl::EnumerationImpl(const NameTree& nt)
95 : nt(nt)
96 , ht(nt.m_ht)
Junxiao Shi029401f2016-08-05 12:55:14 +000097{
98}
99
100FullEnumerationImpl::FullEnumerationImpl(const NameTree& nt, const EntrySelector& pred)
101 : EnumerationImpl(nt)
102 , m_pred(pred)
103{
104}
105
106void
107FullEnumerationImpl::advance(Iterator& i)
108{
Junxiao Shib660b4c2016-08-06 20:47:44 +0000109 // find first entry
Junxiao Shi029401f2016-08-05 12:55:14 +0000110 if (i.m_entry == nullptr) {
Junxiao Shib660b4c2016-08-06 20:47:44 +0000111 for (size_t bucket = 0; bucket < ht.getNBuckets(); ++bucket) {
112 const Node* node = ht.getBucket(bucket);
Junxiao Shi029401f2016-08-05 12:55:14 +0000113 if (node != nullptr) {
Junxiao Shi340d5532016-08-13 04:00:35 +0000114 i.m_entry = &node->entry;
Junxiao Shi029401f2016-08-05 12:55:14 +0000115 break;
116 }
117 }
Junxiao Shib660b4c2016-08-06 20:47:44 +0000118 if (i.m_entry == nullptr) { // empty enumerable
Junxiao Shi029401f2016-08-05 12:55:14 +0000119 i = Iterator();
120 return;
121 }
Junxiao Shib660b4c2016-08-06 20:47:44 +0000122 if (m_pred(*i.m_entry)) { // visit first entry
Junxiao Shi029401f2016-08-05 12:55:14 +0000123 return;
124 }
125 }
126
127 // process entries in same bucket
Junxiao Shib660b4c2016-08-06 20:47:44 +0000128 for (const Node* node = getNode(*i.m_entry)->next; node != nullptr; node = node->next) {
Junxiao Shi340d5532016-08-13 04:00:35 +0000129 if (m_pred(node->entry)) {
130 i.m_entry = &node->entry;
Junxiao Shi029401f2016-08-05 12:55:14 +0000131 return;
132 }
133 }
134
135 // process other buckets
Junxiao Shib660b4c2016-08-06 20:47:44 +0000136 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) {
Junxiao Shi340d5532016-08-13 04:00:35 +0000139 if (m_pred(node->entry)) {
140 i.m_entry = &node->entry;
Junxiao Shi029401f2016-08-05 12:55:14 +0000141 return;
142 }
143 }
144 }
145
146 // reach the end
147 i = Iterator();
148}
149
150PartialEnumerationImpl::PartialEnumerationImpl(const NameTree& nt, const EntrySubTreeSelector& pred)
151 : EnumerationImpl(nt)
152 , m_pred(pred)
153{
154}
155
156void
157PartialEnumerationImpl::advance(Iterator& i)
158{
159 bool wantSelf = false;
160 bool wantChildren = false;
161
162 // initialize: start from root
163 if (i.m_entry == nullptr) {
Junxiao Shib660b4c2016-08-06 20:47:44 +0000164 if (i.m_ref == nullptr) { // root does not exist
Junxiao Shi029401f2016-08-05 12:55:14 +0000165 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
Junxiao Shib660b4c2016-08-06 20:47:44 +0000193 const Entry* parent = i.m_entry->getParent();
194 const std::vector<Entry*>& siblings = parent->getChildren();
Junxiao Shi029401f2016-08-05 12:55:14 +0000195 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
220PrefixMatchImpl::PrefixMatchImpl(const NameTree& nt, const EntrySelector& pred)
221 : EnumerationImpl(nt)
222 , m_pred(pred)
223{
224}
225
226void
227PrefixMatchImpl::advance(Iterator& i)
228{
229 if (i.m_entry == nullptr) {
Junxiao Shib660b4c2016-08-06 20:47:44 +0000230 if (i.m_ref == nullptr) { // empty enumerable
Junxiao Shi029401f2016-08-05 12:55:14 +0000231 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
Davide Pesaventoe422f9e2022-06-03 01:30:23 -0400252} // namespace nfd::name_tree