blob: 8750867edecfc4df1995076d2843af64cc113cb2 [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>
32#include <type_traits>
33
34namespace nfd {
35namespace name_tree {
36
37NFD_LOG_INIT("NameTreeIterator");
38
39BOOST_CONCEPT_ASSERT((boost::ForwardIterator<Iterator>));
40static_assert(std::is_default_constructible<Iterator>::value,
41 "Iterator must be default-constructible");
42
43Iterator::Iterator()
Junxiao Shib660b4c2016-08-06 20:47:44 +000044 : m_entry(nullptr)
45 , m_ref(nullptr)
46 , m_state(0)
Junxiao Shi029401f2016-08-05 12:55:14 +000047{
48}
49
Junxiao Shib660b4c2016-08-06 20:47:44 +000050Iterator::Iterator(shared_ptr<EnumerationImpl> impl, const Entry* ref)
Junxiao Shi029401f2016-08-05 12:55:14 +000051 : m_impl(impl)
Junxiao Shib660b4c2016-08-06 20:47:44 +000052 , m_entry(nullptr)
Junxiao Shi029401f2016-08-05 12:55:14 +000053 , m_ref(ref)
54 , m_state(0)
55{
56 m_impl->advance(*this);
57 NFD_LOG_TRACE("initialized " << *this);
58}
59
60Iterator&
61Iterator::operator++()
62{
63 BOOST_ASSERT(m_impl != nullptr);
64 m_impl->advance(*this);
65 NFD_LOG_TRACE("advanced " << *this);
66 return *this;
67}
68
69Iterator
70Iterator::operator++(int)
71{
72 Iterator copy = *this;
73 this->operator++();
74 return copy;
75}
76
77bool
78Iterator::operator==(const Iterator& other) const
79{
80 return m_entry == other.m_entry;
81}
82
83std::ostream&
84operator<<(std::ostream& os, const Iterator& i)
85{
86 if (i.m_impl == nullptr) {
87 return os << "end";
88 }
89 if (i.m_entry == nullptr) {
90 return os << "uninitialized";
91 }
92
Junxiao Shie3cf2852016-08-09 03:50:56 +000093 os << "entry=" << i.m_entry->getName();
Junxiao Shi029401f2016-08-05 12:55:14 +000094 if (i.m_ref == nullptr) {
95 os << " ref=null";
96 }
97 else {
Junxiao Shie3cf2852016-08-09 03:50:56 +000098 os << " ref=" << i.m_ref->getName();
Junxiao Shi029401f2016-08-05 12:55:14 +000099 }
100 os << " state=" << i.m_state;
101 return os;
102}
103
Junxiao Shib660b4c2016-08-06 20:47:44 +0000104EnumerationImpl::EnumerationImpl(const NameTree& nt)
105 : nt(nt)
106 , ht(nt.m_ht)
Junxiao Shi029401f2016-08-05 12:55:14 +0000107{
108}
109
110FullEnumerationImpl::FullEnumerationImpl(const NameTree& nt, const EntrySelector& pred)
111 : EnumerationImpl(nt)
112 , m_pred(pred)
113{
114}
115
116void
117FullEnumerationImpl::advance(Iterator& i)
118{
Junxiao Shib660b4c2016-08-06 20:47:44 +0000119 // find first entry
Junxiao Shi029401f2016-08-05 12:55:14 +0000120 if (i.m_entry == nullptr) {
Junxiao Shib660b4c2016-08-06 20:47:44 +0000121 for (size_t bucket = 0; bucket < ht.getNBuckets(); ++bucket) {
122 const Node* node = ht.getBucket(bucket);
Junxiao Shi029401f2016-08-05 12:55:14 +0000123 if (node != nullptr) {
Junxiao Shi340d5532016-08-13 04:00:35 +0000124 i.m_entry = &node->entry;
Junxiao Shi029401f2016-08-05 12:55:14 +0000125 break;
126 }
127 }
Junxiao Shib660b4c2016-08-06 20:47:44 +0000128 if (i.m_entry == nullptr) { // empty enumerable
Junxiao Shi029401f2016-08-05 12:55:14 +0000129 i = Iterator();
130 return;
131 }
Junxiao Shib660b4c2016-08-06 20:47:44 +0000132 if (m_pred(*i.m_entry)) { // visit first entry
Junxiao Shi029401f2016-08-05 12:55:14 +0000133 return;
134 }
135 }
136
137 // process entries in same bucket
Junxiao Shib660b4c2016-08-06 20:47:44 +0000138 for (const Node* node = getNode(*i.m_entry)->next; 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 // process other buckets
Junxiao Shib660b4c2016-08-06 20:47:44 +0000146 size_t currentBucket = ht.computeBucketIndex(getNode(*i.m_entry)->hash);
147 for (size_t bucket = currentBucket + 1; bucket < ht.getNBuckets(); ++bucket) {
148 for (const Node* node = ht.getBucket(bucket); node != nullptr; node = node->next) {
Junxiao Shi340d5532016-08-13 04:00:35 +0000149 if (m_pred(node->entry)) {
150 i.m_entry = &node->entry;
Junxiao Shi029401f2016-08-05 12:55:14 +0000151 return;
152 }
153 }
154 }
155
156 // reach the end
157 i = Iterator();
158}
159
160PartialEnumerationImpl::PartialEnumerationImpl(const NameTree& nt, const EntrySubTreeSelector& pred)
161 : EnumerationImpl(nt)
162 , m_pred(pred)
163{
164}
165
166void
167PartialEnumerationImpl::advance(Iterator& i)
168{
169 bool wantSelf = false;
170 bool wantChildren = false;
171
172 // initialize: start from root
173 if (i.m_entry == nullptr) {
Junxiao Shib660b4c2016-08-06 20:47:44 +0000174 if (i.m_ref == nullptr) { // root does not exist
Junxiao Shi029401f2016-08-05 12:55:14 +0000175 i = Iterator();
176 return;
177 }
178
179 i.m_entry = i.m_ref;
180 std::tie(wantSelf, wantChildren) = m_pred(*i.m_entry);
181 if (wantSelf) { // visit root
182 i.m_state = wantChildren;
183 return;
184 }
185 }
186 else {
187 wantChildren = static_cast<bool>(i.m_state);
188 }
189 BOOST_ASSERT(i.m_ref != nullptr);
190
191 // pre-order traversal
192 while (i.m_entry != i.m_ref || (wantChildren && i.m_entry->hasChildren())) {
193 if (wantChildren && i.m_entry->hasChildren()) { // process children of m_entry
194 i.m_entry = i.m_entry->getChildren().front();
195 std::tie(wantSelf, wantChildren) = m_pred(*i.m_entry);
196 if (wantSelf) { // visit first child
197 i.m_state = wantChildren;
198 return;
199 }
200 // first child rejected, let while loop process other children (siblings of new m_entry)
201 }
202 else { // process siblings of m_entry
Junxiao Shib660b4c2016-08-06 20:47:44 +0000203 const Entry* parent = i.m_entry->getParent();
204 const std::vector<Entry*>& siblings = parent->getChildren();
Junxiao Shi029401f2016-08-05 12:55:14 +0000205 auto sibling = std::find(siblings.begin(), siblings.end(), i.m_entry);
206 BOOST_ASSERT(sibling != siblings.end());
207 while (++sibling != siblings.end()) {
208 i.m_entry = *sibling;
209 std::tie(wantSelf, wantChildren) = m_pred(*i.m_entry);
210 if (wantSelf) { // visit sibling
211 i.m_state = wantChildren;
212 return;
213 }
214 if (wantChildren) {
215 break; // let outer while loop process children of m_entry
216 }
217 // process next sibling
218 }
219 if (sibling == siblings.end()) { // no more sibling
220 i.m_entry = parent;
221 wantChildren = false;
222 }
223 }
224 }
225
226 // reach the end
227 i = Iterator();
228}
229
230PrefixMatchImpl::PrefixMatchImpl(const NameTree& nt, const EntrySelector& pred)
231 : EnumerationImpl(nt)
232 , m_pred(pred)
233{
234}
235
236void
237PrefixMatchImpl::advance(Iterator& i)
238{
239 if (i.m_entry == nullptr) {
Junxiao Shib660b4c2016-08-06 20:47:44 +0000240 if (i.m_ref == nullptr) { // empty enumerable
Junxiao Shi029401f2016-08-05 12:55:14 +0000241 i = Iterator();
242 return;
243 }
244
245 i.m_entry = i.m_ref;
246 if (m_pred(*i.m_entry)) { // visit starting node
247 return;
248 }
249 }
250
251 // traverse up the tree
252 while ((i.m_entry = i.m_entry->getParent()) != nullptr) {
253 if (m_pred(*i.m_entry)) {
254 return;
255 }
256 }
257
258 // reach the end
259 i = Iterator();
260}
261
262} // namespace name_tree
263} // namespace nfd