blob: b42b2402398670f048603e1f917386a27dd3bf7f [file] [log] [blame]
HYuana9b85752014-02-26 02:32:30 -06001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
Alexander Afanasyev9bcbc7c2014-04-06 19:37:37 -07003 * Copyright (c) 2014 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 *
10 * This file is part of NFD (Named Data Networking Forwarding Daemon).
11 * See AUTHORS.md for complete list of NFD authors and contributors.
12 *
13 * NFD is free software: you can redistribute it and/or modify it under the terms
14 * of the GNU General Public License as published by the Free Software Foundation,
15 * either version 3 of the License, or (at your option) any later version.
16 *
17 * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
18 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
19 * PURPOSE. See the GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License along with
22 * NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
23 **/
HYuana9b85752014-02-26 02:32:30 -060024
25// Name Tree (Name Prefix Hash Table)
26
27#include "name-tree.hpp"
28#include "core/logger.hpp"
Haowei Yuanf52dac72014-03-24 23:35:03 -050029#include "core/city-hash.hpp"
Davide Pesavento52a18f92014-04-10 00:55:01 +020030
HYuana9b85752014-02-26 02:32:30 -060031namespace nfd {
32
33NFD_LOG_INIT("NameTree");
34
35namespace name_tree {
36
Haowei Yuanf52dac72014-03-24 23:35:03 -050037class Hash32
HYuana9b85752014-02-26 02:32:30 -060038{
Haowei Yuanf52dac72014-03-24 23:35:03 -050039public:
40 static size_t
41 compute(const char* buffer, size_t length)
42 {
43 return static_cast<size_t>(CityHash32(buffer, length));
44 }
45};
HYuana9b85752014-02-26 02:32:30 -060046
Haowei Yuanf52dac72014-03-24 23:35:03 -050047class Hash64
48{
49public:
50 static size_t
51 compute(const char* buffer, size_t length)
52 {
53 return static_cast<size_t>(CityHash64(buffer, length));
54 }
55};
HYuana9b85752014-02-26 02:32:30 -060056
Haowei Yuanf52dac72014-03-24 23:35:03 -050057typedef boost::mpl::if_c<sizeof(size_t) >= 8, Hash64, Hash32>::type CityHash;
58
59// Interface of different hash functions
60size_t
61computeHash(const Name& prefix)
62{
63 prefix.wireEncode(); // guarantees prefix's wire buffer is not empty
64
65 size_t hashValue = 0;
66 size_t hashUpdate = 0;
67
68 for (Name::const_iterator it = prefix.begin(); it != prefix.end(); it++)
69 {
70 const char* wireFormat = reinterpret_cast<const char*>( it->wire() );
71 hashUpdate = CityHash::compute(wireFormat, it->size());
72 hashValue ^= hashUpdate;
73 }
74
75 return hashValue;
76}
77
78std::vector<size_t>
79computeHashSet(const Name& prefix)
80{
81 prefix.wireEncode(); // guarantees prefix's wire buffer is not empty
82
83 size_t hashValue = 0;
84 size_t hashUpdate = 0;
85
86 std::vector<size_t> hashValueSet;
87 hashValueSet.push_back(hashValue);
88
89 for (Name::const_iterator it = prefix.begin(); it != prefix.end(); it++)
90 {
91 const char* wireFormat = reinterpret_cast<const char*>( it->wire() );
92 hashUpdate = CityHash::compute(wireFormat, it->size());
93 hashValue ^= hashUpdate;
94 hashValueSet.push_back(hashValue);
95 }
96
97 return hashValueSet;
HYuana9b85752014-02-26 02:32:30 -060098}
99
100} // namespace name_tree
101
102NameTree::NameTree(size_t nBuckets)
103 : m_nItems(0)
104 , m_nBuckets(nBuckets)
Haowei Yuanf52dac72014-03-24 23:35:03 -0500105 , m_minNBuckets(nBuckets)
106 , m_enlargeLoadFactor(0.5) // more than 50% buckets loaded
107 , m_enlargeFactor(2) // double the hash table size
108 , m_shrinkLoadFactor(0.1) // less than 10% buckets loaded
109 , m_shrinkFactor(0.5) // reduce the number of buckets by half
Haowei Yuane1079fc2014-03-08 14:41:25 -0600110 , m_endIterator(FULL_ENUMERATE_TYPE, *this, m_end)
HYuana9b85752014-02-26 02:32:30 -0600111{
Haowei Yuanf52dac72014-03-24 23:35:03 -0500112 m_enlargeThreshold = static_cast<size_t>(m_enlargeLoadFactor *
113 static_cast<double>(m_nBuckets));
114
115 m_shrinkThreshold = static_cast<size_t>(m_shrinkLoadFactor *
HYuana9b85752014-02-26 02:32:30 -0600116 static_cast<double>(m_nBuckets));
117
118 // array of node pointers
119 m_buckets = new name_tree::Node*[m_nBuckets];
120 // Initialize the pointer array
121 for (size_t i = 0; i < m_nBuckets; i++)
122 m_buckets[i] = 0;
123}
124
125NameTree::~NameTree()
126{
127 for (size_t i = 0; i < m_nBuckets; i++)
128 {
Haowei Yuanf52dac72014-03-24 23:35:03 -0500129 if (m_buckets[i] != 0) {
HYuana9b85752014-02-26 02:32:30 -0600130 delete m_buckets[i];
Haowei Yuanf52dac72014-03-24 23:35:03 -0500131 }
HYuana9b85752014-02-26 02:32:30 -0600132 }
133
134 delete [] m_buckets;
135}
136
137// insert() is a private function, and called by only lookup()
138std::pair<shared_ptr<name_tree::Entry>, bool>
139NameTree::insert(const Name& prefix)
140{
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700141 NFD_LOG_TRACE("insert " << prefix);
HYuana9b85752014-02-26 02:32:30 -0600142
Haowei Yuanf52dac72014-03-24 23:35:03 -0500143 size_t hashValue = name_tree::computeHash(prefix);
144 size_t loc = hashValue % m_nBuckets;
HYuana9b85752014-02-26 02:32:30 -0600145
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700146 NFD_LOG_TRACE("Name " << prefix << " hash value = " << hashValue << " location = " << loc);
HYuana9b85752014-02-26 02:32:30 -0600147
148 // Check if this Name has been stored
149 name_tree::Node* node = m_buckets[loc];
150 name_tree::Node* nodePrev = node; // initialize nodePrev to node
151
152 for (node = m_buckets[loc]; node != 0; node = node->m_next)
153 {
154 if (static_cast<bool>(node->m_entry))
155 {
156 if (prefix == node->m_entry->m_prefix)
157 {
158 return std::make_pair(node->m_entry, false); // false: old entry
159 }
160 }
161 nodePrev = node;
162 }
163
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700164 NFD_LOG_TRACE("Did not find " << prefix << ", need to insert it to the table");
HYuana9b85752014-02-26 02:32:30 -0600165
166 // If no bucket is empty occupied, we need to create a new node, and it is
167 // linked from nodePrev
168 node = new name_tree::Node();
169 node->m_prev = nodePrev;
170
171 if (nodePrev == 0)
172 {
173 m_buckets[loc] = node;
174 }
175 else
176 {
177 nodePrev->m_next = node;
178 }
179
180 // Create a new Entry
181 shared_ptr<name_tree::Entry> entry(make_shared<name_tree::Entry>(prefix));
182 entry->setHash(hashValue);
183 node->m_entry = entry; // link the Entry to its Node
184 entry->m_node = node; // link the node to Entry. Used in eraseEntryIfEmpty.
185
186 return std::make_pair(entry, true); // true: new entry
187}
188
189// Name Prefix Lookup. Create Name Tree Entry if not found
190shared_ptr<name_tree::Entry>
191NameTree::lookup(const Name& prefix)
192{
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700193 NFD_LOG_TRACE("lookup " << prefix);
HYuana9b85752014-02-26 02:32:30 -0600194
195 shared_ptr<name_tree::Entry> entry;
196 shared_ptr<name_tree::Entry> parent;
197
198 for (size_t i = 0; i <= prefix.size(); i++)
199 {
200 Name temp = prefix.getPrefix(i);
201
202 // insert() will create the entry if it does not exist.
203 std::pair<shared_ptr<name_tree::Entry>, bool> ret = insert(temp);
204 entry = ret.first;
205
206 if (ret.second == true)
207 {
Haowei Yuanf52dac72014-03-24 23:35:03 -0500208 m_nItems++; // Increase the counter
HYuana9b85752014-02-26 02:32:30 -0600209 entry->m_parent = parent;
210
211 if (static_cast<bool>(parent))
212 {
213 parent->m_children.push_back(entry);
214 }
215 }
216
Haowei Yuanf52dac72014-03-24 23:35:03 -0500217 if (m_nItems > m_enlargeThreshold)
HYuana9b85752014-02-26 02:32:30 -0600218 {
Haowei Yuanf52dac72014-03-24 23:35:03 -0500219 resize(m_enlargeFactor * m_nBuckets);
HYuana9b85752014-02-26 02:32:30 -0600220 }
221
222 parent = entry;
223 }
224 return entry;
225}
226
227// Exact Match
228shared_ptr<name_tree::Entry>
229NameTree::findExactMatch(const Name& prefix) const
230{
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700231 NFD_LOG_TRACE("findExactMatch " << prefix);
HYuana9b85752014-02-26 02:32:30 -0600232
Haowei Yuanf52dac72014-03-24 23:35:03 -0500233 size_t hashValue = name_tree::computeHash(prefix);
234 size_t loc = hashValue % m_nBuckets;
HYuana9b85752014-02-26 02:32:30 -0600235
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700236 NFD_LOG_TRACE("Name " << prefix << " hash value = " << hashValue <<
HYuana9b85752014-02-26 02:32:30 -0600237 " location = " << loc);
238
239 shared_ptr<name_tree::Entry> entry;
240 name_tree::Node* node = 0;
241
242 for (node = m_buckets[loc]; node != 0; node = node->m_next)
243 {
244 entry = node->m_entry;
245 if (static_cast<bool>(entry))
246 {
247 if (hashValue == entry->getHash() && prefix == entry->getPrefix())
248 {
249 return entry;
250 }
251 } // if entry
252 } // for node
253
254 // if not found, the default value of entry (null pointer) will be returned
255 entry.reset();
256 return entry;
257}
258
259// Longest Prefix Match
HYuana9b85752014-02-26 02:32:30 -0600260shared_ptr<name_tree::Entry>
Haowei Yuane1079fc2014-03-08 14:41:25 -0600261NameTree::findLongestPrefixMatch(const Name& prefix, const name_tree::EntrySelector& entrySelector) const
HYuana9b85752014-02-26 02:32:30 -0600262{
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700263 NFD_LOG_TRACE("findLongestPrefixMatch " << prefix);
HYuana9b85752014-02-26 02:32:30 -0600264
265 shared_ptr<name_tree::Entry> entry;
Haowei Yuanf52dac72014-03-24 23:35:03 -0500266 std::vector<size_t> hashValueSet = name_tree::computeHashSet(prefix);
HYuana9b85752014-02-26 02:32:30 -0600267
Haowei Yuanf52dac72014-03-24 23:35:03 -0500268 size_t hashValue = 0;
269 size_t loc = 0;
270
271 for (int i = static_cast<int>(prefix.size()); i >= 0; i--)
HYuana9b85752014-02-26 02:32:30 -0600272 {
Haowei Yuanf52dac72014-03-24 23:35:03 -0500273 hashValue = hashValueSet[i];
274 loc = hashValue % m_nBuckets;
275
276 name_tree::Node* node = 0;
277 for (node = m_buckets[loc]; node != 0; node = node->m_next)
278 {
279 entry = node->m_entry;
280 if (static_cast<bool>(entry))
281 {
282 // isPrefixOf() is used to avoid making a copy of the name
283 if (hashValue == entry->getHash() &&
284 entry->getPrefix().isPrefixOf(prefix) &&
285 entrySelector(*entry))
286 {
287 return entry;
288 }
289 } // if entry
290 } // for node
HYuana9b85752014-02-26 02:32:30 -0600291 }
292
Haowei Yuanf52dac72014-03-24 23:35:03 -0500293 // if not found, the default value of entry (null pointer) will be returned
294 entry.reset();
295 return entry;
HYuana9b85752014-02-26 02:32:30 -0600296}
297
HangZhangcb4fc832014-03-11 16:57:11 +0800298shared_ptr<name_tree::Entry>
299NameTree::findLongestPrefixMatch(shared_ptr<name_tree::Entry> entry,
300 const name_tree::EntrySelector& entrySelector) const
301{
302 while (static_cast<bool>(entry))
303 {
304 if (entrySelector(*entry))
305 return entry;
306 entry = entry->getParent();
307 }
308 return shared_ptr<name_tree::Entry>();
309}
310
HYuana9b85752014-02-26 02:32:30 -0600311// return {false: this entry is not empty, true: this entry is empty and erased}
312bool
313NameTree::eraseEntryIfEmpty(shared_ptr<name_tree::Entry> entry)
314{
315 BOOST_ASSERT(static_cast<bool>(entry));
316
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700317 NFD_LOG_TRACE("eraseEntryIfEmpty " << entry->getPrefix());
HYuana9b85752014-02-26 02:32:30 -0600318
319 // first check if this Entry can be erased
Junxiao Shi40631842014-03-01 13:52:37 -0700320 if (entry->isEmpty())
HYuana9b85752014-02-26 02:32:30 -0600321 {
322 // update child-related info in the parent
323 shared_ptr<name_tree::Entry> parent = entry->getParent();
324
325 if (static_cast<bool>(parent))
326 {
327 std::vector<shared_ptr<name_tree::Entry> >& parentChildrenList =
328 parent->getChildren();
329
330 bool isFound = false;
331 size_t size = parentChildrenList.size();
332 for (size_t i = 0; i < size; i++)
333 {
334 if (parentChildrenList[i] == entry)
335 {
336 parentChildrenList[i] = parentChildrenList[size - 1];
337 parentChildrenList.pop_back();
338 isFound = true;
339 break;
340 }
341 }
342
343 BOOST_ASSERT(isFound == true);
344 }
345
346 // remove this Entry and its Name Tree Node
347 name_tree::Node* node = entry->m_node;
348 name_tree::Node* nodePrev = node->m_prev;
349
350 // configure the previous node
351 if (nodePrev != 0)
352 {
353 // link the previous node to the next node
354 nodePrev->m_next = node->m_next;
355 }
356 else
357 {
358 m_buckets[entry->getHash() % m_nBuckets] = node->m_next;
359 }
360
361 // link the previous node with the next node (skip the erased one)
362 if (node->m_next != 0)
363 {
364 node->m_next->m_prev = nodePrev;
365 node->m_next = 0;
366 }
367
368 BOOST_ASSERT(node->m_next == 0);
369
370 m_nItems--;
371 delete node;
372
373 if (static_cast<bool>(parent))
374 eraseEntryIfEmpty(parent);
375
Haowei Yuanf52dac72014-03-24 23:35:03 -0500376 size_t newNBuckets = static_cast<size_t>(m_shrinkFactor *
377 static_cast<double>(m_nBuckets));
378
379 if (newNBuckets >= m_minNBuckets && m_nItems < m_shrinkThreshold)
380 {
381 resize(newNBuckets);
382 }
383
HYuana9b85752014-02-26 02:32:30 -0600384 return true;
385
386 } // if this entry is empty
387
388 return false; // if this entry is not empty
389}
390
Haowei Yuane1079fc2014-03-08 14:41:25 -0600391NameTree::const_iterator
392NameTree::fullEnumerate(const name_tree::EntrySelector& entrySelector) const
HYuana9b85752014-02-26 02:32:30 -0600393{
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700394 NFD_LOG_TRACE("fullEnumerate");
HYuana9b85752014-02-26 02:32:30 -0600395
Haowei Yuane1079fc2014-03-08 14:41:25 -0600396 // find the first eligible entry
397 for (size_t i = 0; i < m_nBuckets; i++)
HYuana9b85752014-02-26 02:32:30 -0600398 {
Haowei Yuane1079fc2014-03-08 14:41:25 -0600399 for (name_tree::Node* node = m_buckets[i]; node != 0; node = node->m_next)
400 {
401 if (static_cast<bool>(node->m_entry) && entrySelector(*node->m_entry))
402 {
403 const_iterator it(FULL_ENUMERATE_TYPE, *this, node->m_entry, entrySelector);
404 return it;
405 }
406 }
407 }
408
409 // If none of the entry satisfies the requirements, then return the end() iterator.
410 return end();
411}
412
413NameTree::const_iterator
414NameTree::partialEnumerate(const Name& prefix,
415 const name_tree::EntrySubTreeSelector& entrySubTreeSelector) const
416{
417 // the first step is to process the root node
418 shared_ptr<name_tree::Entry> entry = findExactMatch(prefix);
419 if (!static_cast<bool>(entry))
420 {
421 return end();
422 }
423
424 std::pair<bool, bool>result = entrySubTreeSelector(*entry);
425 const_iterator it(PARTIAL_ENUMERATE_TYPE,
426 *this,
427 entry,
428 name_tree::AnyEntry(),
429 entrySubTreeSelector);
430
431 it.m_shouldVisitChildren = (result.second && entry->hasChildren());
432
433 if (result.first)
434 {
435 // root node is acceptable
436 return it;
437 }
438 else
439 {
440 // let the ++ operator handle it
441 ++it;
442 return it;
HYuana9b85752014-02-26 02:32:30 -0600443 }
444}
445
Haowei Yuane1079fc2014-03-08 14:41:25 -0600446NameTree::const_iterator
447NameTree::findAllMatches(const Name& prefix,
448 const name_tree::EntrySelector& entrySelector) const
HYuana9b85752014-02-26 02:32:30 -0600449{
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700450 NFD_LOG_TRACE("NameTree::findAllMatches" << prefix);
HYuana9b85752014-02-26 02:32:30 -0600451
Haowei Yuane1079fc2014-03-08 14:41:25 -0600452 // As we are using Name Prefix Hash Table, and the current LPM() is
453 // implemented as starting from full name, and reduce the number of
454 // components by 1 each time, we could use it here.
455 // For trie-like design, it could be more efficient by walking down the
456 // trie from the root node.
HYuana9b85752014-02-26 02:32:30 -0600457
Haowei Yuane1079fc2014-03-08 14:41:25 -0600458 shared_ptr<name_tree::Entry> entry = findLongestPrefixMatch(prefix, entrySelector);
HYuana9b85752014-02-26 02:32:30 -0600459
Haowei Yuane1079fc2014-03-08 14:41:25 -0600460 if (static_cast<bool>(entry))
461 {
462 const_iterator it(FIND_ALL_MATCHES_TYPE, *this, entry, entrySelector);
463 return it;
464 }
465 // If none of the entry satisfies the requirements, then return the end() iterator.
466 return end();
HYuana9b85752014-02-26 02:32:30 -0600467}
468
469// Hash Table Resize
470void
471NameTree::resize(size_t newNBuckets)
472{
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700473 NFD_LOG_TRACE("resize");
HYuana9b85752014-02-26 02:32:30 -0600474
475 name_tree::Node** newBuckets = new name_tree::Node*[newNBuckets];
Junxiao Shi40631842014-03-01 13:52:37 -0700476 size_t count = 0;
HYuana9b85752014-02-26 02:32:30 -0600477
478 // referenced ccnx hashtb.c hashtb_rehash()
479 name_tree::Node** pp = 0;
480 name_tree::Node* p = 0;
481 name_tree::Node* pre = 0;
482 name_tree::Node* q = 0; // record p->m_next
Junxiao Shi40631842014-03-01 13:52:37 -0700483 size_t i;
HYuana9b85752014-02-26 02:32:30 -0600484 uint32_t h;
485 uint32_t b;
486
487 for (i = 0; i < newNBuckets; i++)
488 {
489 newBuckets[i] = 0;
490 }
491
492 for (i = 0; i < m_nBuckets; i++)
493 {
494 for (p = m_buckets[i]; p != 0; p = q)
495 {
496 count++;
497 q = p->m_next;
498 BOOST_ASSERT(static_cast<bool>(p->m_entry));
499 h = p->m_entry->m_hash;
500 b = h % newNBuckets;
Haowei Yuan694bfb62014-04-01 14:44:11 -0500501 pre = 0;
HYuana9b85752014-02-26 02:32:30 -0600502 for (pp = &newBuckets[b]; *pp != 0; pp = &((*pp)->m_next))
503 {
504 pre = *pp;
505 continue;
506 }
507 p->m_prev = pre;
508 p->m_next = *pp; // Actually *pp always == 0 in this case
509 *pp = p;
510 }
511 }
512
513 BOOST_ASSERT(count == m_nItems);
514
515 name_tree::Node** oldBuckets = m_buckets;
516 m_buckets = newBuckets;
Haowei Yuanf52dac72014-03-24 23:35:03 -0500517 delete [] oldBuckets;
HYuana9b85752014-02-26 02:32:30 -0600518
519 m_nBuckets = newNBuckets;
Haowei Yuanf52dac72014-03-24 23:35:03 -0500520
521 m_enlargeThreshold = static_cast<size_t>(m_enlargeLoadFactor *
522 static_cast<double>(m_nBuckets));
523 m_shrinkThreshold = static_cast<size_t>(m_shrinkLoadFactor *
524 static_cast<double>(m_nBuckets));
HYuana9b85752014-02-26 02:32:30 -0600525}
526
527// For debugging
528void
Haowei Yuane1079fc2014-03-08 14:41:25 -0600529NameTree::dump(std::ostream& output) const
HYuana9b85752014-02-26 02:32:30 -0600530{
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700531 NFD_LOG_TRACE("dump()");
HYuana9b85752014-02-26 02:32:30 -0600532
533 name_tree::Node* node = 0;
534 shared_ptr<name_tree::Entry> entry;
535
536 using std::endl;
537
538 for (size_t i = 0; i < m_nBuckets; i++)
539 {
540 for (node = m_buckets[i]; node != 0; node = node->m_next)
541 {
542 entry = node->m_entry;
543
544 // if the Entry exist, dump its information
545 if (static_cast<bool>(entry))
546 {
547 output << "Bucket" << i << "\t" << entry->m_prefix.toUri() << endl;
548 output << "\t\tHash " << entry->m_hash << endl;
549
550 if (static_cast<bool>(entry->m_parent))
551 {
552 output << "\t\tparent->" << entry->m_parent->m_prefix.toUri();
553 }
554 else
555 {
556 output << "\t\tROOT";
557 }
558 output << endl;
559
560 if (entry->m_children.size() != 0)
561 {
562 output << "\t\tchildren = " << entry->m_children.size() << endl;
563
564 for (size_t j = 0; j < entry->m_children.size(); j++)
565 {
566 output << "\t\t\tChild " << j << " " <<
567 entry->m_children[j]->getPrefix() << endl;
568 }
569 }
570
571 } // if (static_cast<bool>(entry))
572
573 } // for node
574 } // for int i
575
576 output << "Bucket count = " << m_nBuckets << endl;
577 output << "Stored item = " << m_nItems << endl;
578 output << "--------------------------\n";
579}
580
Haowei Yuane1079fc2014-03-08 14:41:25 -0600581NameTree::const_iterator::const_iterator(NameTree::IteratorType type,
582 const NameTree& nameTree,
583 shared_ptr<name_tree::Entry> entry,
584 const name_tree::EntrySelector& entrySelector,
585 const name_tree::EntrySubTreeSelector& entrySubTreeSelector)
586 : m_nameTree(nameTree)
587 , m_entry(entry)
588 , m_subTreeRoot(entry)
589 , m_entrySelector(make_shared<name_tree::EntrySelector>(entrySelector))
590 , m_entrySubTreeSelector(make_shared<name_tree::EntrySubTreeSelector>(entrySubTreeSelector))
591 , m_type(type)
592 , m_shouldVisitChildren(true)
593{
594}
595
596// operator++()
597NameTree::const_iterator
598NameTree::const_iterator::operator++()
599{
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700600 NFD_LOG_TRACE("const_iterator::operator++()");
Haowei Yuane1079fc2014-03-08 14:41:25 -0600601
602 BOOST_ASSERT(m_entry != m_nameTree.m_end);
603
604 if (m_type == FULL_ENUMERATE_TYPE) // fullEnumerate
605 {
606 bool isFound = false;
607 // process the entries in the same bucket first
608 while (m_entry->m_node->m_next != 0)
609 {
610 m_entry = m_entry->m_node->m_next->m_entry;
611 if ((*m_entrySelector)(*m_entry))
612 {
613 isFound = true;
614 return *this;
615 }
616 }
617
618 // process other buckets
Junxiao Shiefceadc2014-03-09 18:52:57 -0700619
620 for (int newLocation = m_entry->m_hash % m_nameTree.m_nBuckets + 1;
621 newLocation < static_cast<int>(m_nameTree.m_nBuckets);
622 ++newLocation)
Haowei Yuane1079fc2014-03-08 14:41:25 -0600623 {
624 // process each bucket
625 name_tree::Node* node = m_nameTree.m_buckets[newLocation];
626 while (node != 0)
627 {
628 m_entry = node->m_entry;
629 if ((*m_entrySelector)(*m_entry))
630 {
631 isFound = true;
632 return *this;
633 }
634 node = node->m_next;
635 }
636 }
637 BOOST_ASSERT(isFound == false);
638 // Reach to the end()
639 m_entry = m_nameTree.m_end;
640 return *this;
641 }
642
643 if (m_type == PARTIAL_ENUMERATE_TYPE) // partialEnumerate
644 {
645 // We use pre-order traversal.
646 // if at the root, it could have already been accepted, or this
647 // iterator was just declared, and root doesn't satisfy the
648 // requirement
649 // The if() section handles this special case
650 // Essentially, we need to check root's fist child, and the rest will
651 // be the same as normal process
652 if (m_entry == m_subTreeRoot)
653 {
654 if (m_shouldVisitChildren)
655 {
656 m_entry = m_entry->getChildren()[0];
657 std::pair<bool, bool> result = ((*m_entrySubTreeSelector)(*m_entry));
658 m_shouldVisitChildren = (result.second && m_entry->hasChildren());
659 if(result.first)
660 {
661 return *this;
662 }
663 else
664 {
665 // the first child did not meet the requirement
666 // the rest of the process can just fall through the while loop
667 // as normal
668 }
669 }
670 else
671 {
672 // no children, should return end();
673 // just fall through
674 }
675 }
676
677 // The first thing to do is to visit its child, or go to find its possible
678 // siblings
679 while (m_entry != m_subTreeRoot)
680 {
681 if (m_shouldVisitChildren)
682 {
683 // If this subtree should be visited
684 m_entry = m_entry->getChildren()[0];
685 std::pair<bool, bool> result = ((*m_entrySubTreeSelector)(*m_entry));
686 m_shouldVisitChildren = (result.second && m_entry->hasChildren());
687 if (result.first) // if this node is acceptable
688 {
689 return *this;
690 }
691 else
692 {
693 // do nothing, as this node is essentially ignored
694 // send this node to the while loop.
695 }
696 }
697 else
698 {
699 // Should try to find its sibling
700 shared_ptr<name_tree::Entry> parent = m_entry->getParent();
701
702 std::vector<shared_ptr<name_tree::Entry> >& parentChildrenList = parent->getChildren();
703 bool isFound = false;
704 size_t i = 0;
705 for (i = 0; i < parentChildrenList.size(); i++)
706 {
707 if (parentChildrenList[i] == m_entry)
708 {
709 isFound = true;
710 break;
711 }
712 }
713
714 BOOST_ASSERT(isFound == true);
715 if (i < parentChildrenList.size() - 1) // m_entry not the last child
716 {
717 m_entry = parentChildrenList[i + 1];
718 std::pair<bool, bool> result = ((*m_entrySubTreeSelector)(*m_entry));
719 m_shouldVisitChildren = (result.second && m_entry->hasChildren());
720 if (result.first) // if this node is acceptable
721 {
722 return *this;
723 }
724 else
725 {
726 // do nothing, as this node is essentially ignored
727 // send this node to the while loop.
728 }
729 }
730 else
731 {
732 // m_entry is the last child, no more sibling, should try to find parent's sibling
733 m_shouldVisitChildren = false;
734 m_entry = parent;
735 }
736 }
737 }
738
739 m_entry = m_nameTree.m_end;
740 return *this;
741 }
742
743 if (m_type == FIND_ALL_MATCHES_TYPE) // findAllMatches
744 {
745 // Assumption: at the beginning, m_entry was initialized with the first
746 // eligible Name Tree entry (i.e., has a PIT entry that can be satisfied
747 // by the Data packet)
748
749 while (static_cast<bool>(m_entry->getParent()))
750 {
751 m_entry = m_entry->getParent();
752 if ((*m_entrySelector)(*m_entry))
753 return *this;
754 }
755
756 // Reach to the end (Root)
757 m_entry = m_nameTree.m_end;
758 return *this;
759 }
Junxiao Shiefceadc2014-03-09 18:52:57 -0700760
761 BOOST_ASSERT(false); // unknown type
762 return *this;
Haowei Yuane1079fc2014-03-08 14:41:25 -0600763}
764
HYuana9b85752014-02-26 02:32:30 -0600765} // namespace nfd