blob: d7c7362db832102870d126927f82d4905c8917df [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"
28#include "core/logger.hpp"
29
30#include <boost/concept/assert.hpp>
31#include <boost/concept_check.hpp>
Junxiao Shi9f6ca602016-08-15 04:50:29 +000032#include <boost/range/concepts.hpp>
Junxiao Shi029401f2016-08-05 12:55:14 +000033#include <type_traits>
34
35namespace nfd {
36namespace name_tree {
37
Junxiao Shi029401f2016-08-05 12:55:14 +000038BOOST_CONCEPT_ASSERT((boost::ForwardIterator<Iterator>));
39static_assert(std::is_default_constructible<Iterator>::value,
40 "Iterator must be default-constructible");
41
Junxiao Shi9f6ca602016-08-15 04:50:29 +000042BOOST_CONCEPT_ASSERT((boost::ForwardRangeConcept<Range>));
43
44NFD_LOG_INIT("NameTreeIterator");
45
Junxiao Shi029401f2016-08-05 12:55:14 +000046Iterator::Iterator()
Junxiao Shib660b4c2016-08-06 20:47:44 +000047 : m_entry(nullptr)
48 , m_ref(nullptr)
49 , m_state(0)
Junxiao Shi029401f2016-08-05 12:55:14 +000050{
51}
52
Junxiao Shib660b4c2016-08-06 20:47:44 +000053Iterator::Iterator(shared_ptr<EnumerationImpl> impl, const Entry* ref)
Junxiao Shi029401f2016-08-05 12:55:14 +000054 : m_impl(impl)
Junxiao Shib660b4c2016-08-06 20:47:44 +000055 , m_entry(nullptr)
Junxiao Shi029401f2016-08-05 12:55:14 +000056 , m_ref(ref)
57 , m_state(0)
58{
59 m_impl->advance(*this);
60 NFD_LOG_TRACE("initialized " << *this);
61}
62
63Iterator&
64Iterator::operator++()
65{
66 BOOST_ASSERT(m_impl != nullptr);
67 m_impl->advance(*this);
68 NFD_LOG_TRACE("advanced " << *this);
69 return *this;
70}
71
72Iterator
73Iterator::operator++(int)
74{
75 Iterator copy = *this;
76 this->operator++();
77 return copy;
78}
79
80bool
81Iterator::operator==(const Iterator& other) const
82{
83 return m_entry == other.m_entry;
84}
85
86std::ostream&
87operator<<(std::ostream& os, const Iterator& i)
88{
89 if (i.m_impl == nullptr) {
90 return os << "end";
91 }
92 if (i.m_entry == nullptr) {
93 return os << "uninitialized";
94 }
95
Junxiao Shie3cf2852016-08-09 03:50:56 +000096 os << "entry=" << i.m_entry->getName();
Junxiao Shi029401f2016-08-05 12:55:14 +000097 if (i.m_ref == nullptr) {
98 os << " ref=null";
99 }
100 else {
Junxiao Shie3cf2852016-08-09 03:50:56 +0000101 os << " ref=" << i.m_ref->getName();
Junxiao Shi029401f2016-08-05 12:55:14 +0000102 }
103 os << " state=" << i.m_state;
104 return os;
105}
106
Junxiao Shib660b4c2016-08-06 20:47:44 +0000107EnumerationImpl::EnumerationImpl(const NameTree& nt)
108 : nt(nt)
109 , ht(nt.m_ht)
Junxiao Shi029401f2016-08-05 12:55:14 +0000110{
111}
112
113FullEnumerationImpl::FullEnumerationImpl(const NameTree& nt, const EntrySelector& pred)
114 : EnumerationImpl(nt)
115 , m_pred(pred)
116{
117}
118
119void
120FullEnumerationImpl::advance(Iterator& i)
121{
Junxiao Shib660b4c2016-08-06 20:47:44 +0000122 // find first entry
Junxiao Shi029401f2016-08-05 12:55:14 +0000123 if (i.m_entry == nullptr) {
Junxiao Shib660b4c2016-08-06 20:47:44 +0000124 for (size_t bucket = 0; bucket < ht.getNBuckets(); ++bucket) {
125 const Node* node = ht.getBucket(bucket);
Junxiao Shi029401f2016-08-05 12:55:14 +0000126 if (node != nullptr) {
Junxiao Shi340d5532016-08-13 04:00:35 +0000127 i.m_entry = &node->entry;
Junxiao Shi029401f2016-08-05 12:55:14 +0000128 break;
129 }
130 }
Junxiao Shib660b4c2016-08-06 20:47:44 +0000131 if (i.m_entry == nullptr) { // empty enumerable
Junxiao Shi029401f2016-08-05 12:55:14 +0000132 i = Iterator();
133 return;
134 }
Junxiao Shib660b4c2016-08-06 20:47:44 +0000135 if (m_pred(*i.m_entry)) { // visit first entry
Junxiao Shi029401f2016-08-05 12:55:14 +0000136 return;
137 }
138 }
139
140 // process entries in same bucket
Junxiao Shib660b4c2016-08-06 20:47:44 +0000141 for (const Node* node = getNode(*i.m_entry)->next; node != nullptr; node = node->next) {
Junxiao Shi340d5532016-08-13 04:00:35 +0000142 if (m_pred(node->entry)) {
143 i.m_entry = &node->entry;
Junxiao Shi029401f2016-08-05 12:55:14 +0000144 return;
145 }
146 }
147
148 // process other buckets
Junxiao Shib660b4c2016-08-06 20:47:44 +0000149 size_t currentBucket = ht.computeBucketIndex(getNode(*i.m_entry)->hash);
150 for (size_t bucket = currentBucket + 1; bucket < ht.getNBuckets(); ++bucket) {
151 for (const Node* node = ht.getBucket(bucket); node != nullptr; node = node->next) {
Junxiao Shi340d5532016-08-13 04:00:35 +0000152 if (m_pred(node->entry)) {
153 i.m_entry = &node->entry;
Junxiao Shi029401f2016-08-05 12:55:14 +0000154 return;
155 }
156 }
157 }
158
159 // reach the end
160 i = Iterator();
161}
162
163PartialEnumerationImpl::PartialEnumerationImpl(const NameTree& nt, const EntrySubTreeSelector& pred)
164 : EnumerationImpl(nt)
165 , m_pred(pred)
166{
167}
168
169void
170PartialEnumerationImpl::advance(Iterator& i)
171{
172 bool wantSelf = false;
173 bool wantChildren = false;
174
175 // initialize: start from root
176 if (i.m_entry == nullptr) {
Junxiao Shib660b4c2016-08-06 20:47:44 +0000177 if (i.m_ref == nullptr) { // root does not exist
Junxiao Shi029401f2016-08-05 12:55:14 +0000178 i = Iterator();
179 return;
180 }
181
182 i.m_entry = i.m_ref;
183 std::tie(wantSelf, wantChildren) = m_pred(*i.m_entry);
184 if (wantSelf) { // visit root
185 i.m_state = wantChildren;
186 return;
187 }
188 }
189 else {
190 wantChildren = static_cast<bool>(i.m_state);
191 }
192 BOOST_ASSERT(i.m_ref != nullptr);
193
194 // pre-order traversal
195 while (i.m_entry != i.m_ref || (wantChildren && i.m_entry->hasChildren())) {
196 if (wantChildren && i.m_entry->hasChildren()) { // process children of m_entry
197 i.m_entry = i.m_entry->getChildren().front();
198 std::tie(wantSelf, wantChildren) = m_pred(*i.m_entry);
199 if (wantSelf) { // visit first child
200 i.m_state = wantChildren;
201 return;
202 }
203 // first child rejected, let while loop process other children (siblings of new m_entry)
204 }
205 else { // process siblings of m_entry
Junxiao Shib660b4c2016-08-06 20:47:44 +0000206 const Entry* parent = i.m_entry->getParent();
207 const std::vector<Entry*>& siblings = parent->getChildren();
Junxiao Shi029401f2016-08-05 12:55:14 +0000208 auto sibling = std::find(siblings.begin(), siblings.end(), i.m_entry);
209 BOOST_ASSERT(sibling != siblings.end());
210 while (++sibling != siblings.end()) {
211 i.m_entry = *sibling;
212 std::tie(wantSelf, wantChildren) = m_pred(*i.m_entry);
213 if (wantSelf) { // visit sibling
214 i.m_state = wantChildren;
215 return;
216 }
217 if (wantChildren) {
218 break; // let outer while loop process children of m_entry
219 }
220 // process next sibling
221 }
222 if (sibling == siblings.end()) { // no more sibling
223 i.m_entry = parent;
224 wantChildren = false;
225 }
226 }
227 }
228
229 // reach the end
230 i = Iterator();
231}
232
233PrefixMatchImpl::PrefixMatchImpl(const NameTree& nt, const EntrySelector& pred)
234 : EnumerationImpl(nt)
235 , m_pred(pred)
236{
237}
238
239void
240PrefixMatchImpl::advance(Iterator& i)
241{
242 if (i.m_entry == nullptr) {
Junxiao Shib660b4c2016-08-06 20:47:44 +0000243 if (i.m_ref == nullptr) { // empty enumerable
Junxiao Shi029401f2016-08-05 12:55:14 +0000244 i = Iterator();
245 return;
246 }
247
248 i.m_entry = i.m_ref;
249 if (m_pred(*i.m_entry)) { // visit starting node
250 return;
251 }
252 }
253
254 // traverse up the tree
255 while ((i.m_entry = i.m_entry->getParent()) != nullptr) {
256 if (m_pred(*i.m_entry)) {
257 return;
258 }
259 }
260
261 // reach the end
262 i = Iterator();
263}
264
265} // namespace name_tree
266} // namespace nfd