blob: 31077bed23307b6ab1be8b2388127ea22395d60f [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()
44 : m_state(0)
45{
46}
47
48Iterator::Iterator(shared_ptr<EnumerationImpl> impl, shared_ptr<Entry> ref)
49 : m_impl(impl)
50 , 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
90 os << "entry=" << i.m_entry->getPrefix();
91 if (i.m_ref == nullptr) {
92 os << " ref=null";
93 }
94 else {
95 os << " ref=" << i.m_ref->getPrefix();
96 }
97 os << " state=" << i.m_state;
98 return os;
99}
100
101EnumerationImpl::EnumerationImpl(const NameTree& nt1)
102 : nt(nt1)
103{
104}
105
106FullEnumerationImpl::FullEnumerationImpl(const NameTree& nt, const EntrySelector& pred)
107 : EnumerationImpl(nt)
108 , m_pred(pred)
109{
110}
111
112void
113FullEnumerationImpl::advance(Iterator& i)
114{
115 // find initial entry
116 if (i.m_entry == nullptr) {
117 for (size_t bucket = 0; bucket < nt.m_nBuckets; ++bucket) {
118 Node* node = nt.m_buckets[bucket];
119 if (node != nullptr) {
120 i.m_entry = node->m_entry;
121 break;
122 }
123 }
124 if (i.m_entry == nullptr) { // empty enumeration
125 i = Iterator();
126 return;
127 }
128 if (m_pred(*i.m_entry)) { // visit initial entry
129 return;
130 }
131 }
132
133 // process entries in same bucket
134 for (Node* node = i.m_entry->m_node->m_next; node != nullptr; node = node->m_next) {
135 if (m_pred(*node->m_entry)) {
136 i.m_entry = node->m_entry;
137 return;
138 }
139 }
140
141 // process other buckets
142 for (size_t bucket = i.m_entry->m_hash % nt.m_nBuckets + 1; bucket < nt.m_nBuckets; ++bucket) {
143 for (Node* node = nt.m_buckets[bucket]; node != nullptr; node = node->m_next) {
144 if (m_pred(*node->m_entry)) {
145 i.m_entry = node->m_entry;
146 return;
147 }
148 }
149 }
150
151 // reach the end
152 i = Iterator();
153}
154
155PartialEnumerationImpl::PartialEnumerationImpl(const NameTree& nt, const EntrySubTreeSelector& pred)
156 : EnumerationImpl(nt)
157 , m_pred(pred)
158{
159}
160
161void
162PartialEnumerationImpl::advance(Iterator& i)
163{
164 bool wantSelf = false;
165 bool wantChildren = false;
166
167 // initialize: start from root
168 if (i.m_entry == nullptr) {
169 if (i.m_ref == nullptr) { // empty enumeration
170 i = Iterator();
171 return;
172 }
173
174 i.m_entry = i.m_ref;
175 std::tie(wantSelf, wantChildren) = m_pred(*i.m_entry);
176 if (wantSelf) { // visit root
177 i.m_state = wantChildren;
178 return;
179 }
180 }
181 else {
182 wantChildren = static_cast<bool>(i.m_state);
183 }
184 BOOST_ASSERT(i.m_ref != nullptr);
185
186 // pre-order traversal
187 while (i.m_entry != i.m_ref || (wantChildren && i.m_entry->hasChildren())) {
188 if (wantChildren && i.m_entry->hasChildren()) { // process children of m_entry
189 i.m_entry = i.m_entry->getChildren().front();
190 std::tie(wantSelf, wantChildren) = m_pred(*i.m_entry);
191 if (wantSelf) { // visit first child
192 i.m_state = wantChildren;
193 return;
194 }
195 // first child rejected, let while loop process other children (siblings of new m_entry)
196 }
197 else { // process siblings of m_entry
198 shared_ptr<Entry> parent = i.m_entry->getParent();
199 const std::vector<shared_ptr<Entry>>& siblings = parent->getChildren();
200 auto sibling = std::find(siblings.begin(), siblings.end(), i.m_entry);
201 BOOST_ASSERT(sibling != siblings.end());
202 while (++sibling != siblings.end()) {
203 i.m_entry = *sibling;
204 std::tie(wantSelf, wantChildren) = m_pred(*i.m_entry);
205 if (wantSelf) { // visit sibling
206 i.m_state = wantChildren;
207 return;
208 }
209 if (wantChildren) {
210 break; // let outer while loop process children of m_entry
211 }
212 // process next sibling
213 }
214 if (sibling == siblings.end()) { // no more sibling
215 i.m_entry = parent;
216 wantChildren = false;
217 }
218 }
219 }
220
221 // reach the end
222 i = Iterator();
223}
224
225PrefixMatchImpl::PrefixMatchImpl(const NameTree& nt, const EntrySelector& pred)
226 : EnumerationImpl(nt)
227 , m_pred(pred)
228{
229}
230
231void
232PrefixMatchImpl::advance(Iterator& i)
233{
234 if (i.m_entry == nullptr) {
235 if (i.m_ref == nullptr) { // empty enumeration
236 i = Iterator();
237 return;
238 }
239
240 i.m_entry = i.m_ref;
241 if (m_pred(*i.m_entry)) { // visit starting node
242 return;
243 }
244 }
245
246 // traverse up the tree
247 while ((i.m_entry = i.m_entry->getParent()) != nullptr) {
248 if (m_pred(*i.m_entry)) {
249 return;
250 }
251 }
252
253 // reach the end
254 i = Iterator();
255}
256
257} // namespace name_tree
258} // namespace nfd