blob: 32f282dcfcf54634326c4a7671bf40c875671c54 [file] [log] [blame]
Junxiao Shi029401f2016-08-05 12:55:14 +00001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
3 * Copyright (c) 2014-2016, 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"
Junxiao Shi3aba7542016-12-24 02:42:52 +000028#include "core/asserts.hpp"
Junxiao Shi029401f2016-08-05 12:55:14 +000029#include "core/logger.hpp"
Junxiao Shi9f6ca602016-08-15 04:50:29 +000030#include <boost/range/concepts.hpp>
Junxiao Shi029401f2016-08-05 12:55:14 +000031
32namespace nfd {
33namespace name_tree {
34
Junxiao Shi3aba7542016-12-24 02:42:52 +000035NFD_ASSERT_FORWARD_ITERATOR(Iterator);
Junxiao Shi9f6ca602016-08-15 04:50:29 +000036BOOST_CONCEPT_ASSERT((boost::ForwardRangeConcept<Range>));
37
38NFD_LOG_INIT("NameTreeIterator");
39
Junxiao Shi029401f2016-08-05 12:55:14 +000040Iterator::Iterator()
Junxiao Shib660b4c2016-08-06 20:47:44 +000041 : m_entry(nullptr)
42 , m_ref(nullptr)
43 , m_state(0)
Junxiao Shi029401f2016-08-05 12:55:14 +000044{
45}
46
Junxiao Shib660b4c2016-08-06 20:47:44 +000047Iterator::Iterator(shared_ptr<EnumerationImpl> impl, const Entry* ref)
Junxiao Shi029401f2016-08-05 12:55:14 +000048 : m_impl(impl)
Junxiao Shib660b4c2016-08-06 20:47:44 +000049 , m_entry(nullptr)
Junxiao Shi029401f2016-08-05 12:55:14 +000050 , m_ref(ref)
51 , m_state(0)
52{
53 m_impl->advance(*this);
54 NFD_LOG_TRACE("initialized " << *this);
55}
56
57Iterator&
58Iterator::operator++()
59{
60 BOOST_ASSERT(m_impl != nullptr);
61 m_impl->advance(*this);
62 NFD_LOG_TRACE("advanced " << *this);
63 return *this;
64}
65
66Iterator
67Iterator::operator++(int)
68{
69 Iterator copy = *this;
70 this->operator++();
71 return copy;
72}
73
74bool
75Iterator::operator==(const Iterator& other) const
76{
77 return m_entry == other.m_entry;
78}
79
80std::ostream&
81operator<<(std::ostream& os, const Iterator& i)
82{
83 if (i.m_impl == nullptr) {
84 return os << "end";
85 }
86 if (i.m_entry == nullptr) {
87 return os << "uninitialized";
88 }
89
Junxiao Shie3cf2852016-08-09 03:50:56 +000090 os << "entry=" << i.m_entry->getName();
Junxiao Shi029401f2016-08-05 12:55:14 +000091 if (i.m_ref == nullptr) {
92 os << " ref=null";
93 }
94 else {
Junxiao Shie3cf2852016-08-09 03:50:56 +000095 os << " ref=" << i.m_ref->getName();
Junxiao Shi029401f2016-08-05 12:55:14 +000096 }
97 os << " state=" << i.m_state;
98 return os;
99}
100
Junxiao Shib660b4c2016-08-06 20:47:44 +0000101EnumerationImpl::EnumerationImpl(const NameTree& nt)
102 : nt(nt)
103 , ht(nt.m_ht)
Junxiao Shi029401f2016-08-05 12:55:14 +0000104{
105}
106
107FullEnumerationImpl::FullEnumerationImpl(const NameTree& nt, const EntrySelector& pred)
108 : EnumerationImpl(nt)
109 , m_pred(pred)
110{
111}
112
113void
114FullEnumerationImpl::advance(Iterator& i)
115{
Junxiao Shib660b4c2016-08-06 20:47:44 +0000116 // find first entry
Junxiao Shi029401f2016-08-05 12:55:14 +0000117 if (i.m_entry == nullptr) {
Junxiao Shib660b4c2016-08-06 20:47:44 +0000118 for (size_t bucket = 0; bucket < ht.getNBuckets(); ++bucket) {
119 const Node* node = ht.getBucket(bucket);
Junxiao Shi029401f2016-08-05 12:55:14 +0000120 if (node != nullptr) {
Junxiao Shi340d5532016-08-13 04:00:35 +0000121 i.m_entry = &node->entry;
Junxiao Shi029401f2016-08-05 12:55:14 +0000122 break;
123 }
124 }
Junxiao Shib660b4c2016-08-06 20:47:44 +0000125 if (i.m_entry == nullptr) { // empty enumerable
Junxiao Shi029401f2016-08-05 12:55:14 +0000126 i = Iterator();
127 return;
128 }
Junxiao Shib660b4c2016-08-06 20:47:44 +0000129 if (m_pred(*i.m_entry)) { // visit first entry
Junxiao Shi029401f2016-08-05 12:55:14 +0000130 return;
131 }
132 }
133
134 // process entries in same bucket
Junxiao Shib660b4c2016-08-06 20:47:44 +0000135 for (const Node* node = getNode(*i.m_entry)->next; node != nullptr; node = node->next) {
Junxiao Shi340d5532016-08-13 04:00:35 +0000136 if (m_pred(node->entry)) {
137 i.m_entry = &node->entry;
Junxiao Shi029401f2016-08-05 12:55:14 +0000138 return;
139 }
140 }
141
142 // process other buckets
Junxiao Shib660b4c2016-08-06 20:47:44 +0000143 size_t currentBucket = ht.computeBucketIndex(getNode(*i.m_entry)->hash);
144 for (size_t bucket = currentBucket + 1; bucket < ht.getNBuckets(); ++bucket) {
145 for (const Node* node = ht.getBucket(bucket); node != nullptr; node = node->next) {
Junxiao Shi340d5532016-08-13 04:00:35 +0000146 if (m_pred(node->entry)) {
147 i.m_entry = &node->entry;
Junxiao Shi029401f2016-08-05 12:55:14 +0000148 return;
149 }
150 }
151 }
152
153 // reach the end
154 i = Iterator();
155}
156
157PartialEnumerationImpl::PartialEnumerationImpl(const NameTree& nt, const EntrySubTreeSelector& pred)
158 : EnumerationImpl(nt)
159 , m_pred(pred)
160{
161}
162
163void
164PartialEnumerationImpl::advance(Iterator& i)
165{
166 bool wantSelf = false;
167 bool wantChildren = false;
168
169 // initialize: start from root
170 if (i.m_entry == nullptr) {
Junxiao Shib660b4c2016-08-06 20:47:44 +0000171 if (i.m_ref == nullptr) { // root does not exist
Junxiao Shi029401f2016-08-05 12:55:14 +0000172 i = Iterator();
173 return;
174 }
175
176 i.m_entry = i.m_ref;
177 std::tie(wantSelf, wantChildren) = m_pred(*i.m_entry);
178 if (wantSelf) { // visit root
179 i.m_state = wantChildren;
180 return;
181 }
182 }
183 else {
184 wantChildren = static_cast<bool>(i.m_state);
185 }
186 BOOST_ASSERT(i.m_ref != nullptr);
187
188 // pre-order traversal
189 while (i.m_entry != i.m_ref || (wantChildren && i.m_entry->hasChildren())) {
190 if (wantChildren && i.m_entry->hasChildren()) { // process children of m_entry
191 i.m_entry = i.m_entry->getChildren().front();
192 std::tie(wantSelf, wantChildren) = m_pred(*i.m_entry);
193 if (wantSelf) { // visit first child
194 i.m_state = wantChildren;
195 return;
196 }
197 // first child rejected, let while loop process other children (siblings of new m_entry)
198 }
199 else { // process siblings of m_entry
Junxiao Shib660b4c2016-08-06 20:47:44 +0000200 const Entry* parent = i.m_entry->getParent();
201 const std::vector<Entry*>& siblings = parent->getChildren();
Junxiao Shi029401f2016-08-05 12:55:14 +0000202 auto sibling = std::find(siblings.begin(), siblings.end(), i.m_entry);
203 BOOST_ASSERT(sibling != siblings.end());
204 while (++sibling != siblings.end()) {
205 i.m_entry = *sibling;
206 std::tie(wantSelf, wantChildren) = m_pred(*i.m_entry);
207 if (wantSelf) { // visit sibling
208 i.m_state = wantChildren;
209 return;
210 }
211 if (wantChildren) {
212 break; // let outer while loop process children of m_entry
213 }
214 // process next sibling
215 }
216 if (sibling == siblings.end()) { // no more sibling
217 i.m_entry = parent;
218 wantChildren = false;
219 }
220 }
221 }
222
223 // reach the end
224 i = Iterator();
225}
226
227PrefixMatchImpl::PrefixMatchImpl(const NameTree& nt, const EntrySelector& pred)
228 : EnumerationImpl(nt)
229 , m_pred(pred)
230{
231}
232
233void
234PrefixMatchImpl::advance(Iterator& i)
235{
236 if (i.m_entry == nullptr) {
Junxiao Shib660b4c2016-08-06 20:47:44 +0000237 if (i.m_ref == nullptr) { // empty enumerable
Junxiao Shi029401f2016-08-05 12:55:14 +0000238 i = Iterator();
239 return;
240 }
241
242 i.m_entry = i.m_ref;
243 if (m_pred(*i.m_entry)) { // visit starting node
244 return;
245 }
246 }
247
248 // traverse up the tree
249 while ((i.m_entry = i.m_entry->getParent()) != nullptr) {
250 if (m_pred(*i.m_entry)) {
251 return;
252 }
253 }
254
255 // reach the end
256 i = Iterator();
257}
258
259} // namespace name_tree
260} // namespace nfd