blob: 101014a2e23573bfcb5e59390c05248527e248e7 [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"
29
Davide Pesavento52a18f92014-04-10 00:55:01 +020030#include <boost/functional/hash.hpp>
31
HYuana9b85752014-02-26 02:32:30 -060032namespace nfd {
33
34NFD_LOG_INIT("NameTree");
35
36namespace name_tree {
37
38// Interface of different hash functions
39uint32_t
40hashName(const Name& prefix)
41{
42 // fixed value. Used for debugging only.
43 uint32_t ret = 0;
44
45 // Boost hash
46 // requires the /boost/functional/hash.hpp header file
47 // TODO: improve hash efficiency with Name type
48 boost::hash<std::string> stringHash;
49 ret = stringHash(prefix.toUri());
50
51 return ret;
52}
53
54} // namespace name_tree
55
56NameTree::NameTree(size_t nBuckets)
57 : m_nItems(0)
58 , m_nBuckets(nBuckets)
59 , m_loadFactor(0.5)
60 , m_resizeFactor(2)
Haowei Yuane1079fc2014-03-08 14:41:25 -060061 , m_endIterator(FULL_ENUMERATE_TYPE, *this, m_end)
HYuana9b85752014-02-26 02:32:30 -060062{
63 m_resizeThreshold = static_cast<size_t>(m_loadFactor *
64 static_cast<double>(m_nBuckets));
65
66 // array of node pointers
67 m_buckets = new name_tree::Node*[m_nBuckets];
68 // Initialize the pointer array
69 for (size_t i = 0; i < m_nBuckets; i++)
70 m_buckets[i] = 0;
71}
72
73NameTree::~NameTree()
74{
75 for (size_t i = 0; i < m_nBuckets; i++)
76 {
77 if (m_buckets[i] != 0)
78 delete m_buckets[i];
79 }
80
81 delete [] m_buckets;
82}
83
84// insert() is a private function, and called by only lookup()
85std::pair<shared_ptr<name_tree::Entry>, bool>
86NameTree::insert(const Name& prefix)
87{
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -070088 NFD_LOG_TRACE("insert " << prefix);
HYuana9b85752014-02-26 02:32:30 -060089
90 uint32_t hashValue = name_tree::hashName(prefix);
91 uint32_t loc = hashValue % m_nBuckets;
92
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -070093 NFD_LOG_TRACE("Name " << prefix << " hash value = " << hashValue << " location = " << loc);
HYuana9b85752014-02-26 02:32:30 -060094
95 // Check if this Name has been stored
96 name_tree::Node* node = m_buckets[loc];
97 name_tree::Node* nodePrev = node; // initialize nodePrev to node
98
99 for (node = m_buckets[loc]; node != 0; node = node->m_next)
100 {
101 if (static_cast<bool>(node->m_entry))
102 {
103 if (prefix == node->m_entry->m_prefix)
104 {
105 return std::make_pair(node->m_entry, false); // false: old entry
106 }
107 }
108 nodePrev = node;
109 }
110
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700111 NFD_LOG_TRACE("Did not find " << prefix << ", need to insert it to the table");
HYuana9b85752014-02-26 02:32:30 -0600112
113 // If no bucket is empty occupied, we need to create a new node, and it is
114 // linked from nodePrev
115 node = new name_tree::Node();
116 node->m_prev = nodePrev;
117
118 if (nodePrev == 0)
119 {
120 m_buckets[loc] = node;
121 }
122 else
123 {
124 nodePrev->m_next = node;
125 }
126
127 // Create a new Entry
128 shared_ptr<name_tree::Entry> entry(make_shared<name_tree::Entry>(prefix));
129 entry->setHash(hashValue);
130 node->m_entry = entry; // link the Entry to its Node
131 entry->m_node = node; // link the node to Entry. Used in eraseEntryIfEmpty.
132
133 return std::make_pair(entry, true); // true: new entry
134}
135
136// Name Prefix Lookup. Create Name Tree Entry if not found
137shared_ptr<name_tree::Entry>
138NameTree::lookup(const Name& prefix)
139{
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700140 NFD_LOG_TRACE("lookup " << prefix);
HYuana9b85752014-02-26 02:32:30 -0600141
142 shared_ptr<name_tree::Entry> entry;
143 shared_ptr<name_tree::Entry> parent;
144
145 for (size_t i = 0; i <= prefix.size(); i++)
146 {
147 Name temp = prefix.getPrefix(i);
148
149 // insert() will create the entry if it does not exist.
150 std::pair<shared_ptr<name_tree::Entry>, bool> ret = insert(temp);
151 entry = ret.first;
152
153 if (ret.second == true)
154 {
155 m_nItems++; /* Increase the counter */
156 entry->m_parent = parent;
157
158 if (static_cast<bool>(parent))
159 {
160 parent->m_children.push_back(entry);
161 }
162 }
163
164 if (m_nItems > m_resizeThreshold)
165 {
166 resize(m_resizeFactor * m_nBuckets);
167 }
168
169 parent = entry;
170 }
171 return entry;
172}
173
174// Exact Match
175shared_ptr<name_tree::Entry>
176NameTree::findExactMatch(const Name& prefix) const
177{
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700178 NFD_LOG_TRACE("findExactMatch " << prefix);
HYuana9b85752014-02-26 02:32:30 -0600179
180 uint32_t hashValue = name_tree::hashName(prefix);
181 uint32_t loc = hashValue % m_nBuckets;
182
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700183 NFD_LOG_TRACE("Name " << prefix << " hash value = " << hashValue <<
HYuana9b85752014-02-26 02:32:30 -0600184 " location = " << loc);
185
186 shared_ptr<name_tree::Entry> entry;
187 name_tree::Node* node = 0;
188
189 for (node = m_buckets[loc]; node != 0; node = node->m_next)
190 {
191 entry = node->m_entry;
192 if (static_cast<bool>(entry))
193 {
194 if (hashValue == entry->getHash() && prefix == entry->getPrefix())
195 {
196 return entry;
197 }
198 } // if entry
199 } // for node
200
201 // if not found, the default value of entry (null pointer) will be returned
202 entry.reset();
203 return entry;
204}
205
206// Longest Prefix Match
207// Return the longest matching Entry address
208// start from the full name, and then remove 1 name comp each time
209shared_ptr<name_tree::Entry>
Haowei Yuane1079fc2014-03-08 14:41:25 -0600210NameTree::findLongestPrefixMatch(const Name& prefix, const name_tree::EntrySelector& entrySelector) const
HYuana9b85752014-02-26 02:32:30 -0600211{
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700212 NFD_LOG_TRACE("findLongestPrefixMatch " << prefix);
HYuana9b85752014-02-26 02:32:30 -0600213
214 shared_ptr<name_tree::Entry> entry;
215
216 for (int i = prefix.size(); i >= 0; i--)
217 {
218 entry = findExactMatch(prefix.getPrefix(i));
Junxiao Shi40631842014-03-01 13:52:37 -0700219 if (static_cast<bool>(entry) && entrySelector(*entry))
HYuana9b85752014-02-26 02:32:30 -0600220 return entry;
221 }
222
Junxiao Shi40631842014-03-01 13:52:37 -0700223 return shared_ptr<name_tree::Entry>();
HYuana9b85752014-02-26 02:32:30 -0600224}
225
HangZhangcb4fc832014-03-11 16:57:11 +0800226shared_ptr<name_tree::Entry>
227NameTree::findLongestPrefixMatch(shared_ptr<name_tree::Entry> entry,
228 const name_tree::EntrySelector& entrySelector) const
229{
230 while (static_cast<bool>(entry))
231 {
232 if (entrySelector(*entry))
233 return entry;
234 entry = entry->getParent();
235 }
236 return shared_ptr<name_tree::Entry>();
237}
238
HYuana9b85752014-02-26 02:32:30 -0600239// return {false: this entry is not empty, true: this entry is empty and erased}
240bool
241NameTree::eraseEntryIfEmpty(shared_ptr<name_tree::Entry> entry)
242{
243 BOOST_ASSERT(static_cast<bool>(entry));
244
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700245 NFD_LOG_TRACE("eraseEntryIfEmpty " << entry->getPrefix());
HYuana9b85752014-02-26 02:32:30 -0600246
247 // first check if this Entry can be erased
Junxiao Shi40631842014-03-01 13:52:37 -0700248 if (entry->isEmpty())
HYuana9b85752014-02-26 02:32:30 -0600249 {
250 // update child-related info in the parent
251 shared_ptr<name_tree::Entry> parent = entry->getParent();
252
253 if (static_cast<bool>(parent))
254 {
255 std::vector<shared_ptr<name_tree::Entry> >& parentChildrenList =
256 parent->getChildren();
257
258 bool isFound = false;
259 size_t size = parentChildrenList.size();
260 for (size_t i = 0; i < size; i++)
261 {
262 if (parentChildrenList[i] == entry)
263 {
264 parentChildrenList[i] = parentChildrenList[size - 1];
265 parentChildrenList.pop_back();
266 isFound = true;
267 break;
268 }
269 }
270
271 BOOST_ASSERT(isFound == true);
272 }
273
274 // remove this Entry and its Name Tree Node
275 name_tree::Node* node = entry->m_node;
276 name_tree::Node* nodePrev = node->m_prev;
277
278 // configure the previous node
279 if (nodePrev != 0)
280 {
281 // link the previous node to the next node
282 nodePrev->m_next = node->m_next;
283 }
284 else
285 {
286 m_buckets[entry->getHash() % m_nBuckets] = node->m_next;
287 }
288
289 // link the previous node with the next node (skip the erased one)
290 if (node->m_next != 0)
291 {
292 node->m_next->m_prev = nodePrev;
293 node->m_next = 0;
294 }
295
296 BOOST_ASSERT(node->m_next == 0);
297
298 m_nItems--;
299 delete node;
300
301 if (static_cast<bool>(parent))
302 eraseEntryIfEmpty(parent);
303
304 return true;
305
306 } // if this entry is empty
307
308 return false; // if this entry is not empty
309}
310
Haowei Yuane1079fc2014-03-08 14:41:25 -0600311NameTree::const_iterator
312NameTree::fullEnumerate(const name_tree::EntrySelector& entrySelector) const
HYuana9b85752014-02-26 02:32:30 -0600313{
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700314 NFD_LOG_TRACE("fullEnumerate");
HYuana9b85752014-02-26 02:32:30 -0600315
Haowei Yuane1079fc2014-03-08 14:41:25 -0600316 // find the first eligible entry
317 for (size_t i = 0; i < m_nBuckets; i++)
HYuana9b85752014-02-26 02:32:30 -0600318 {
Haowei Yuane1079fc2014-03-08 14:41:25 -0600319 for (name_tree::Node* node = m_buckets[i]; node != 0; node = node->m_next)
320 {
321 if (static_cast<bool>(node->m_entry) && entrySelector(*node->m_entry))
322 {
323 const_iterator it(FULL_ENUMERATE_TYPE, *this, node->m_entry, entrySelector);
324 return it;
325 }
326 }
327 }
328
329 // If none of the entry satisfies the requirements, then return the end() iterator.
330 return end();
331}
332
333NameTree::const_iterator
334NameTree::partialEnumerate(const Name& prefix,
335 const name_tree::EntrySubTreeSelector& entrySubTreeSelector) const
336{
337 // the first step is to process the root node
338 shared_ptr<name_tree::Entry> entry = findExactMatch(prefix);
339 if (!static_cast<bool>(entry))
340 {
341 return end();
342 }
343
344 std::pair<bool, bool>result = entrySubTreeSelector(*entry);
345 const_iterator it(PARTIAL_ENUMERATE_TYPE,
346 *this,
347 entry,
348 name_tree::AnyEntry(),
349 entrySubTreeSelector);
350
351 it.m_shouldVisitChildren = (result.second && entry->hasChildren());
352
353 if (result.first)
354 {
355 // root node is acceptable
356 return it;
357 }
358 else
359 {
360 // let the ++ operator handle it
361 ++it;
362 return it;
HYuana9b85752014-02-26 02:32:30 -0600363 }
364}
365
Haowei Yuane1079fc2014-03-08 14:41:25 -0600366NameTree::const_iterator
367NameTree::findAllMatches(const Name& prefix,
368 const name_tree::EntrySelector& entrySelector) const
HYuana9b85752014-02-26 02:32:30 -0600369{
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700370 NFD_LOG_TRACE("NameTree::findAllMatches" << prefix);
HYuana9b85752014-02-26 02:32:30 -0600371
Haowei Yuane1079fc2014-03-08 14:41:25 -0600372 // As we are using Name Prefix Hash Table, and the current LPM() is
373 // implemented as starting from full name, and reduce the number of
374 // components by 1 each time, we could use it here.
375 // For trie-like design, it could be more efficient by walking down the
376 // trie from the root node.
HYuana9b85752014-02-26 02:32:30 -0600377
Haowei Yuane1079fc2014-03-08 14:41:25 -0600378 shared_ptr<name_tree::Entry> entry = findLongestPrefixMatch(prefix, entrySelector);
HYuana9b85752014-02-26 02:32:30 -0600379
Haowei Yuane1079fc2014-03-08 14:41:25 -0600380 if (static_cast<bool>(entry))
381 {
382 const_iterator it(FIND_ALL_MATCHES_TYPE, *this, entry, entrySelector);
383 return it;
384 }
385 // If none of the entry satisfies the requirements, then return the end() iterator.
386 return end();
HYuana9b85752014-02-26 02:32:30 -0600387}
388
389// Hash Table Resize
390void
391NameTree::resize(size_t newNBuckets)
392{
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700393 NFD_LOG_TRACE("resize");
HYuana9b85752014-02-26 02:32:30 -0600394
395 name_tree::Node** newBuckets = new name_tree::Node*[newNBuckets];
Junxiao Shi40631842014-03-01 13:52:37 -0700396 size_t count = 0;
HYuana9b85752014-02-26 02:32:30 -0600397
398 // referenced ccnx hashtb.c hashtb_rehash()
399 name_tree::Node** pp = 0;
400 name_tree::Node* p = 0;
401 name_tree::Node* pre = 0;
402 name_tree::Node* q = 0; // record p->m_next
Junxiao Shi40631842014-03-01 13:52:37 -0700403 size_t i;
HYuana9b85752014-02-26 02:32:30 -0600404 uint32_t h;
405 uint32_t b;
406
407 for (i = 0; i < newNBuckets; i++)
408 {
409 newBuckets[i] = 0;
410 }
411
412 for (i = 0; i < m_nBuckets; i++)
413 {
414 for (p = m_buckets[i]; p != 0; p = q)
415 {
416 count++;
417 q = p->m_next;
418 BOOST_ASSERT(static_cast<bool>(p->m_entry));
419 h = p->m_entry->m_hash;
420 b = h % newNBuckets;
Haowei Yuan694bfb62014-04-01 14:44:11 -0500421 pre = 0;
HYuana9b85752014-02-26 02:32:30 -0600422 for (pp = &newBuckets[b]; *pp != 0; pp = &((*pp)->m_next))
423 {
424 pre = *pp;
425 continue;
426 }
427 p->m_prev = pre;
428 p->m_next = *pp; // Actually *pp always == 0 in this case
429 *pp = p;
430 }
431 }
432
433 BOOST_ASSERT(count == m_nItems);
434
435 name_tree::Node** oldBuckets = m_buckets;
436 m_buckets = newBuckets;
437 delete oldBuckets;
438
439 m_nBuckets = newNBuckets;
440 m_resizeThreshold = (int)(m_loadFactor * (double)m_nBuckets);
441}
442
443// For debugging
444void
Haowei Yuane1079fc2014-03-08 14:41:25 -0600445NameTree::dump(std::ostream& output) const
HYuana9b85752014-02-26 02:32:30 -0600446{
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700447 NFD_LOG_TRACE("dump()");
HYuana9b85752014-02-26 02:32:30 -0600448
449 name_tree::Node* node = 0;
450 shared_ptr<name_tree::Entry> entry;
451
452 using std::endl;
453
454 for (size_t i = 0; i < m_nBuckets; i++)
455 {
456 for (node = m_buckets[i]; node != 0; node = node->m_next)
457 {
458 entry = node->m_entry;
459
460 // if the Entry exist, dump its information
461 if (static_cast<bool>(entry))
462 {
463 output << "Bucket" << i << "\t" << entry->m_prefix.toUri() << endl;
464 output << "\t\tHash " << entry->m_hash << endl;
465
466 if (static_cast<bool>(entry->m_parent))
467 {
468 output << "\t\tparent->" << entry->m_parent->m_prefix.toUri();
469 }
470 else
471 {
472 output << "\t\tROOT";
473 }
474 output << endl;
475
476 if (entry->m_children.size() != 0)
477 {
478 output << "\t\tchildren = " << entry->m_children.size() << endl;
479
480 for (size_t j = 0; j < entry->m_children.size(); j++)
481 {
482 output << "\t\t\tChild " << j << " " <<
483 entry->m_children[j]->getPrefix() << endl;
484 }
485 }
486
487 } // if (static_cast<bool>(entry))
488
489 } // for node
490 } // for int i
491
492 output << "Bucket count = " << m_nBuckets << endl;
493 output << "Stored item = " << m_nItems << endl;
494 output << "--------------------------\n";
495}
496
Haowei Yuane1079fc2014-03-08 14:41:25 -0600497NameTree::const_iterator::const_iterator(NameTree::IteratorType type,
498 const NameTree& nameTree,
499 shared_ptr<name_tree::Entry> entry,
500 const name_tree::EntrySelector& entrySelector,
501 const name_tree::EntrySubTreeSelector& entrySubTreeSelector)
502 : m_nameTree(nameTree)
503 , m_entry(entry)
504 , m_subTreeRoot(entry)
505 , m_entrySelector(make_shared<name_tree::EntrySelector>(entrySelector))
506 , m_entrySubTreeSelector(make_shared<name_tree::EntrySubTreeSelector>(entrySubTreeSelector))
507 , m_type(type)
508 , m_shouldVisitChildren(true)
509{
510}
511
512// operator++()
513NameTree::const_iterator
514NameTree::const_iterator::operator++()
515{
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700516 NFD_LOG_TRACE("const_iterator::operator++()");
Haowei Yuane1079fc2014-03-08 14:41:25 -0600517
518 BOOST_ASSERT(m_entry != m_nameTree.m_end);
519
520 if (m_type == FULL_ENUMERATE_TYPE) // fullEnumerate
521 {
522 bool isFound = false;
523 // process the entries in the same bucket first
524 while (m_entry->m_node->m_next != 0)
525 {
526 m_entry = m_entry->m_node->m_next->m_entry;
527 if ((*m_entrySelector)(*m_entry))
528 {
529 isFound = true;
530 return *this;
531 }
532 }
533
534 // process other buckets
Junxiao Shiefceadc2014-03-09 18:52:57 -0700535
536 for (int newLocation = m_entry->m_hash % m_nameTree.m_nBuckets + 1;
537 newLocation < static_cast<int>(m_nameTree.m_nBuckets);
538 ++newLocation)
Haowei Yuane1079fc2014-03-08 14:41:25 -0600539 {
540 // process each bucket
541 name_tree::Node* node = m_nameTree.m_buckets[newLocation];
542 while (node != 0)
543 {
544 m_entry = node->m_entry;
545 if ((*m_entrySelector)(*m_entry))
546 {
547 isFound = true;
548 return *this;
549 }
550 node = node->m_next;
551 }
552 }
553 BOOST_ASSERT(isFound == false);
554 // Reach to the end()
555 m_entry = m_nameTree.m_end;
556 return *this;
557 }
558
559 if (m_type == PARTIAL_ENUMERATE_TYPE) // partialEnumerate
560 {
561 // We use pre-order traversal.
562 // if at the root, it could have already been accepted, or this
563 // iterator was just declared, and root doesn't satisfy the
564 // requirement
565 // The if() section handles this special case
566 // Essentially, we need to check root's fist child, and the rest will
567 // be the same as normal process
568 if (m_entry == m_subTreeRoot)
569 {
570 if (m_shouldVisitChildren)
571 {
572 m_entry = m_entry->getChildren()[0];
573 std::pair<bool, bool> result = ((*m_entrySubTreeSelector)(*m_entry));
574 m_shouldVisitChildren = (result.second && m_entry->hasChildren());
575 if(result.first)
576 {
577 return *this;
578 }
579 else
580 {
581 // the first child did not meet the requirement
582 // the rest of the process can just fall through the while loop
583 // as normal
584 }
585 }
586 else
587 {
588 // no children, should return end();
589 // just fall through
590 }
591 }
592
593 // The first thing to do is to visit its child, or go to find its possible
594 // siblings
595 while (m_entry != m_subTreeRoot)
596 {
597 if (m_shouldVisitChildren)
598 {
599 // If this subtree should be visited
600 m_entry = m_entry->getChildren()[0];
601 std::pair<bool, bool> result = ((*m_entrySubTreeSelector)(*m_entry));
602 m_shouldVisitChildren = (result.second && m_entry->hasChildren());
603 if (result.first) // if this node is acceptable
604 {
605 return *this;
606 }
607 else
608 {
609 // do nothing, as this node is essentially ignored
610 // send this node to the while loop.
611 }
612 }
613 else
614 {
615 // Should try to find its sibling
616 shared_ptr<name_tree::Entry> parent = m_entry->getParent();
617
618 std::vector<shared_ptr<name_tree::Entry> >& parentChildrenList = parent->getChildren();
619 bool isFound = false;
620 size_t i = 0;
621 for (i = 0; i < parentChildrenList.size(); i++)
622 {
623 if (parentChildrenList[i] == m_entry)
624 {
625 isFound = true;
626 break;
627 }
628 }
629
630 BOOST_ASSERT(isFound == true);
631 if (i < parentChildrenList.size() - 1) // m_entry not the last child
632 {
633 m_entry = parentChildrenList[i + 1];
634 std::pair<bool, bool> result = ((*m_entrySubTreeSelector)(*m_entry));
635 m_shouldVisitChildren = (result.second && m_entry->hasChildren());
636 if (result.first) // if this node is acceptable
637 {
638 return *this;
639 }
640 else
641 {
642 // do nothing, as this node is essentially ignored
643 // send this node to the while loop.
644 }
645 }
646 else
647 {
648 // m_entry is the last child, no more sibling, should try to find parent's sibling
649 m_shouldVisitChildren = false;
650 m_entry = parent;
651 }
652 }
653 }
654
655 m_entry = m_nameTree.m_end;
656 return *this;
657 }
658
659 if (m_type == FIND_ALL_MATCHES_TYPE) // findAllMatches
660 {
661 // Assumption: at the beginning, m_entry was initialized with the first
662 // eligible Name Tree entry (i.e., has a PIT entry that can be satisfied
663 // by the Data packet)
664
665 while (static_cast<bool>(m_entry->getParent()))
666 {
667 m_entry = m_entry->getParent();
668 if ((*m_entrySelector)(*m_entry))
669 return *this;
670 }
671
672 // Reach to the end (Root)
673 m_entry = m_nameTree.m_end;
674 return *this;
675 }
Junxiao Shiefceadc2014-03-09 18:52:57 -0700676
677 BOOST_ASSERT(false); // unknown type
678 return *this;
Haowei Yuane1079fc2014-03-08 14:41:25 -0600679}
680
HYuana9b85752014-02-26 02:32:30 -0600681} // namespace nfd