blob: 24c14220a366d5cabe37844f82b763be0f90c0db [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 Pesavento191a7a22023-05-17 22:40:43 -04003 * Copyright (c) 2014-2023, 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
Junxiao Shi029401f2016-08-05 12:55:14 +000067std::ostream&
68operator<<(std::ostream& os, const Iterator& i)
69{
70 if (i.m_impl == nullptr) {
71 return os << "end";
72 }
73 if (i.m_entry == nullptr) {
74 return os << "uninitialized";
75 }
76
Junxiao Shie3cf2852016-08-09 03:50:56 +000077 os << "entry=" << i.m_entry->getName();
Junxiao Shi029401f2016-08-05 12:55:14 +000078 if (i.m_ref == nullptr) {
79 os << " ref=null";
80 }
81 else {
Junxiao Shie3cf2852016-08-09 03:50:56 +000082 os << " ref=" << i.m_ref->getName();
Junxiao Shi029401f2016-08-05 12:55:14 +000083 }
84 os << " state=" << i.m_state;
85 return os;
86}
87
Junxiao Shib660b4c2016-08-06 20:47:44 +000088EnumerationImpl::EnumerationImpl(const NameTree& nt)
89 : nt(nt)
90 , ht(nt.m_ht)
Junxiao Shi029401f2016-08-05 12:55:14 +000091{
92}
93
94FullEnumerationImpl::FullEnumerationImpl(const NameTree& nt, const EntrySelector& pred)
95 : EnumerationImpl(nt)
96 , m_pred(pred)
97{
98}
99
100void
101FullEnumerationImpl::advance(Iterator& i)
102{
Junxiao Shib660b4c2016-08-06 20:47:44 +0000103 // find first entry
Junxiao Shi029401f2016-08-05 12:55:14 +0000104 if (i.m_entry == nullptr) {
Junxiao Shib660b4c2016-08-06 20:47:44 +0000105 for (size_t bucket = 0; bucket < ht.getNBuckets(); ++bucket) {
106 const Node* node = ht.getBucket(bucket);
Junxiao Shi029401f2016-08-05 12:55:14 +0000107 if (node != nullptr) {
Junxiao Shi340d5532016-08-13 04:00:35 +0000108 i.m_entry = &node->entry;
Junxiao Shi029401f2016-08-05 12:55:14 +0000109 break;
110 }
111 }
Junxiao Shib660b4c2016-08-06 20:47:44 +0000112 if (i.m_entry == nullptr) { // empty enumerable
Junxiao Shi029401f2016-08-05 12:55:14 +0000113 i = Iterator();
114 return;
115 }
Junxiao Shib660b4c2016-08-06 20:47:44 +0000116 if (m_pred(*i.m_entry)) { // visit first entry
Junxiao Shi029401f2016-08-05 12:55:14 +0000117 return;
118 }
119 }
120
121 // process entries in same bucket
Junxiao Shib660b4c2016-08-06 20:47:44 +0000122 for (const Node* node = getNode(*i.m_entry)->next; node != nullptr; node = node->next) {
Junxiao Shi340d5532016-08-13 04:00:35 +0000123 if (m_pred(node->entry)) {
124 i.m_entry = &node->entry;
Junxiao Shi029401f2016-08-05 12:55:14 +0000125 return;
126 }
127 }
128
129 // process other buckets
Junxiao Shib660b4c2016-08-06 20:47:44 +0000130 size_t currentBucket = ht.computeBucketIndex(getNode(*i.m_entry)->hash);
131 for (size_t bucket = currentBucket + 1; bucket < ht.getNBuckets(); ++bucket) {
132 for (const Node* node = ht.getBucket(bucket); node != nullptr; node = node->next) {
Junxiao Shi340d5532016-08-13 04:00:35 +0000133 if (m_pred(node->entry)) {
134 i.m_entry = &node->entry;
Junxiao Shi029401f2016-08-05 12:55:14 +0000135 return;
136 }
137 }
138 }
139
140 // reach the end
141 i = Iterator();
142}
143
144PartialEnumerationImpl::PartialEnumerationImpl(const NameTree& nt, const EntrySubTreeSelector& pred)
145 : EnumerationImpl(nt)
146 , m_pred(pred)
147{
148}
149
150void
151PartialEnumerationImpl::advance(Iterator& i)
152{
153 bool wantSelf = false;
154 bool wantChildren = false;
155
156 // initialize: start from root
157 if (i.m_entry == nullptr) {
Junxiao Shib660b4c2016-08-06 20:47:44 +0000158 if (i.m_ref == nullptr) { // root does not exist
Junxiao Shi029401f2016-08-05 12:55:14 +0000159 i = Iterator();
160 return;
161 }
162
163 i.m_entry = i.m_ref;
164 std::tie(wantSelf, wantChildren) = m_pred(*i.m_entry);
165 if (wantSelf) { // visit root
166 i.m_state = wantChildren;
167 return;
168 }
169 }
170 else {
171 wantChildren = static_cast<bool>(i.m_state);
172 }
173 BOOST_ASSERT(i.m_ref != nullptr);
174
175 // pre-order traversal
176 while (i.m_entry != i.m_ref || (wantChildren && i.m_entry->hasChildren())) {
177 if (wantChildren && i.m_entry->hasChildren()) { // process children of m_entry
178 i.m_entry = i.m_entry->getChildren().front();
179 std::tie(wantSelf, wantChildren) = m_pred(*i.m_entry);
180 if (wantSelf) { // visit first child
181 i.m_state = wantChildren;
182 return;
183 }
184 // first child rejected, let while loop process other children (siblings of new m_entry)
185 }
186 else { // process siblings of m_entry
Junxiao Shib660b4c2016-08-06 20:47:44 +0000187 const Entry* parent = i.m_entry->getParent();
188 const std::vector<Entry*>& siblings = parent->getChildren();
Junxiao Shi029401f2016-08-05 12:55:14 +0000189 auto sibling = std::find(siblings.begin(), siblings.end(), i.m_entry);
190 BOOST_ASSERT(sibling != siblings.end());
191 while (++sibling != siblings.end()) {
192 i.m_entry = *sibling;
193 std::tie(wantSelf, wantChildren) = m_pred(*i.m_entry);
194 if (wantSelf) { // visit sibling
195 i.m_state = wantChildren;
196 return;
197 }
198 if (wantChildren) {
199 break; // let outer while loop process children of m_entry
200 }
201 // process next sibling
202 }
203 if (sibling == siblings.end()) { // no more sibling
204 i.m_entry = parent;
205 wantChildren = false;
206 }
207 }
208 }
209
210 // reach the end
211 i = Iterator();
212}
213
214PrefixMatchImpl::PrefixMatchImpl(const NameTree& nt, const EntrySelector& pred)
215 : EnumerationImpl(nt)
216 , m_pred(pred)
217{
218}
219
220void
221PrefixMatchImpl::advance(Iterator& i)
222{
223 if (i.m_entry == nullptr) {
Junxiao Shib660b4c2016-08-06 20:47:44 +0000224 if (i.m_ref == nullptr) { // empty enumerable
Junxiao Shi029401f2016-08-05 12:55:14 +0000225 i = Iterator();
226 return;
227 }
228
229 i.m_entry = i.m_ref;
230 if (m_pred(*i.m_entry)) { // visit starting node
231 return;
232 }
233 }
234
235 // traverse up the tree
236 while ((i.m_entry = i.m_entry->getParent()) != nullptr) {
237 if (m_pred(*i.m_entry)) {
238 return;
239 }
240 }
241
242 // reach the end
243 i = Iterator();
244}
245
Davide Pesaventoe422f9e2022-06-03 01:30:23 -0400246} // namespace nfd::name_tree