blob: 9752ac7e30729ef7388453db54161af65c25842b [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/*
3 * Copyright (c) 2014-2018, 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"
28#include "core/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
33namespace nfd {
34namespace name_tree {
35
Davide Pesavento981db802018-04-10 18:05:04 -040036NDN_CXX_ASSERT_FORWARD_ITERATOR(Iterator);
Junxiao Shi9f6ca602016-08-15 04:50:29 +000037BOOST_CONCEPT_ASSERT((boost::ForwardRangeConcept<Range>));
38
39NFD_LOG_INIT("NameTreeIterator");
40
Junxiao Shi029401f2016-08-05 12:55:14 +000041Iterator::Iterator()
Junxiao Shib660b4c2016-08-06 20:47:44 +000042 : m_entry(nullptr)
43 , m_ref(nullptr)
44 , m_state(0)
Junxiao Shi029401f2016-08-05 12:55:14 +000045{
46}
47
Junxiao Shib660b4c2016-08-06 20:47:44 +000048Iterator::Iterator(shared_ptr<EnumerationImpl> impl, const Entry* ref)
Junxiao Shi029401f2016-08-05 12:55:14 +000049 : m_impl(impl)
Junxiao Shib660b4c2016-08-06 20:47:44 +000050 , m_entry(nullptr)
Junxiao Shi029401f2016-08-05 12:55:14 +000051 , m_ref(ref)
52 , m_state(0)
53{
54 m_impl->advance(*this);
55 NFD_LOG_TRACE("initialized " << *this);
56}
57
58Iterator&
59Iterator::operator++()
60{
61 BOOST_ASSERT(m_impl != nullptr);
62 m_impl->advance(*this);
63 NFD_LOG_TRACE("advanced " << *this);
64 return *this;
65}
66
67Iterator
68Iterator::operator++(int)
69{
70 Iterator copy = *this;
71 this->operator++();
72 return copy;
73}
74
75bool
76Iterator::operator==(const Iterator& other) const
77{
78 return m_entry == other.m_entry;
79}
80
81std::ostream&
82operator<<(std::ostream& os, const Iterator& i)
83{
84 if (i.m_impl == nullptr) {
85 return os << "end";
86 }
87 if (i.m_entry == nullptr) {
88 return os << "uninitialized";
89 }
90
Junxiao Shie3cf2852016-08-09 03:50:56 +000091 os << "entry=" << i.m_entry->getName();
Junxiao Shi029401f2016-08-05 12:55:14 +000092 if (i.m_ref == nullptr) {
93 os << " ref=null";
94 }
95 else {
Junxiao Shie3cf2852016-08-09 03:50:56 +000096 os << " ref=" << i.m_ref->getName();
Junxiao Shi029401f2016-08-05 12:55:14 +000097 }
98 os << " state=" << i.m_state;
99 return os;
100}
101
Junxiao Shib660b4c2016-08-06 20:47:44 +0000102EnumerationImpl::EnumerationImpl(const NameTree& nt)
103 : nt(nt)
104 , ht(nt.m_ht)
Junxiao Shi029401f2016-08-05 12:55:14 +0000105{
106}
107
108FullEnumerationImpl::FullEnumerationImpl(const NameTree& nt, const EntrySelector& pred)
109 : EnumerationImpl(nt)
110 , m_pred(pred)
111{
112}
113
114void
115FullEnumerationImpl::advance(Iterator& i)
116{
Junxiao Shib660b4c2016-08-06 20:47:44 +0000117 // find first entry
Junxiao Shi029401f2016-08-05 12:55:14 +0000118 if (i.m_entry == nullptr) {
Junxiao Shib660b4c2016-08-06 20:47:44 +0000119 for (size_t bucket = 0; bucket < ht.getNBuckets(); ++bucket) {
120 const Node* node = ht.getBucket(bucket);
Junxiao Shi029401f2016-08-05 12:55:14 +0000121 if (node != nullptr) {
Junxiao Shi340d5532016-08-13 04:00:35 +0000122 i.m_entry = &node->entry;
Junxiao Shi029401f2016-08-05 12:55:14 +0000123 break;
124 }
125 }
Junxiao Shib660b4c2016-08-06 20:47:44 +0000126 if (i.m_entry == nullptr) { // empty enumerable
Junxiao Shi029401f2016-08-05 12:55:14 +0000127 i = Iterator();
128 return;
129 }
Junxiao Shib660b4c2016-08-06 20:47:44 +0000130 if (m_pred(*i.m_entry)) { // visit first entry
Junxiao Shi029401f2016-08-05 12:55:14 +0000131 return;
132 }
133 }
134
135 // process entries in same bucket
Junxiao Shib660b4c2016-08-06 20:47:44 +0000136 for (const Node* node = getNode(*i.m_entry)->next; node != nullptr; node = node->next) {
Junxiao Shi340d5532016-08-13 04:00:35 +0000137 if (m_pred(node->entry)) {
138 i.m_entry = &node->entry;
Junxiao Shi029401f2016-08-05 12:55:14 +0000139 return;
140 }
141 }
142
143 // process other buckets
Junxiao Shib660b4c2016-08-06 20:47:44 +0000144 size_t currentBucket = ht.computeBucketIndex(getNode(*i.m_entry)->hash);
145 for (size_t bucket = currentBucket + 1; bucket < ht.getNBuckets(); ++bucket) {
146 for (const Node* node = ht.getBucket(bucket); node != nullptr; node = node->next) {
Junxiao Shi340d5532016-08-13 04:00:35 +0000147 if (m_pred(node->entry)) {
148 i.m_entry = &node->entry;
Junxiao Shi029401f2016-08-05 12:55:14 +0000149 return;
150 }
151 }
152 }
153
154 // reach the end
155 i = Iterator();
156}
157
158PartialEnumerationImpl::PartialEnumerationImpl(const NameTree& nt, const EntrySubTreeSelector& pred)
159 : EnumerationImpl(nt)
160 , m_pred(pred)
161{
162}
163
164void
165PartialEnumerationImpl::advance(Iterator& i)
166{
167 bool wantSelf = false;
168 bool wantChildren = false;
169
170 // initialize: start from root
171 if (i.m_entry == nullptr) {
Junxiao Shib660b4c2016-08-06 20:47:44 +0000172 if (i.m_ref == nullptr) { // root does not exist
Junxiao Shi029401f2016-08-05 12:55:14 +0000173 i = Iterator();
174 return;
175 }
176
177 i.m_entry = i.m_ref;
178 std::tie(wantSelf, wantChildren) = m_pred(*i.m_entry);
179 if (wantSelf) { // visit root
180 i.m_state = wantChildren;
181 return;
182 }
183 }
184 else {
185 wantChildren = static_cast<bool>(i.m_state);
186 }
187 BOOST_ASSERT(i.m_ref != nullptr);
188
189 // pre-order traversal
190 while (i.m_entry != i.m_ref || (wantChildren && i.m_entry->hasChildren())) {
191 if (wantChildren && i.m_entry->hasChildren()) { // process children of m_entry
192 i.m_entry = i.m_entry->getChildren().front();
193 std::tie(wantSelf, wantChildren) = m_pred(*i.m_entry);
194 if (wantSelf) { // visit first child
195 i.m_state = wantChildren;
196 return;
197 }
198 // first child rejected, let while loop process other children (siblings of new m_entry)
199 }
200 else { // process siblings of m_entry
Junxiao Shib660b4c2016-08-06 20:47:44 +0000201 const Entry* parent = i.m_entry->getParent();
202 const std::vector<Entry*>& siblings = parent->getChildren();
Junxiao Shi029401f2016-08-05 12:55:14 +0000203 auto sibling = std::find(siblings.begin(), siblings.end(), i.m_entry);
204 BOOST_ASSERT(sibling != siblings.end());
205 while (++sibling != siblings.end()) {
206 i.m_entry = *sibling;
207 std::tie(wantSelf, wantChildren) = m_pred(*i.m_entry);
208 if (wantSelf) { // visit sibling
209 i.m_state = wantChildren;
210 return;
211 }
212 if (wantChildren) {
213 break; // let outer while loop process children of m_entry
214 }
215 // process next sibling
216 }
217 if (sibling == siblings.end()) { // no more sibling
218 i.m_entry = parent;
219 wantChildren = false;
220 }
221 }
222 }
223
224 // reach the end
225 i = Iterator();
226}
227
228PrefixMatchImpl::PrefixMatchImpl(const NameTree& nt, const EntrySelector& pred)
229 : EnumerationImpl(nt)
230 , m_pred(pred)
231{
232}
233
234void
235PrefixMatchImpl::advance(Iterator& i)
236{
237 if (i.m_entry == nullptr) {
Junxiao Shib660b4c2016-08-06 20:47:44 +0000238 if (i.m_ref == nullptr) { // empty enumerable
Junxiao Shi029401f2016-08-05 12:55:14 +0000239 i = Iterator();
240 return;
241 }
242
243 i.m_entry = i.m_ref;
244 if (m_pred(*i.m_entry)) { // visit starting node
245 return;
246 }
247 }
248
249 // traverse up the tree
250 while ((i.m_entry = i.m_entry->getParent()) != nullptr) {
251 if (m_pred(*i.m_entry)) {
252 return;
253 }
254 }
255
256 // reach the end
257 i = Iterator();
258}
259
260} // namespace name_tree
261} // namespace nfd