NS-3 based Named Data Networking (NDN) simulator
ndnSIM 2.0: NDN, CCN, CCNx, content centric networks
API Documentation
name-tree.cpp
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
26 #include "name-tree.hpp"
27 #include "core/logger.hpp"
28 #include "core/city-hash.hpp"
29 
30 #include <boost/concept/assert.hpp>
31 #include <boost/concept_check.hpp>
32 #include <type_traits>
33 
34 namespace nfd {
35 
36 NFD_LOG_INIT("NameTree");
37 
38 // http://en.cppreference.com/w/cpp/concept/ForwardIterator
39 BOOST_CONCEPT_ASSERT((boost::ForwardIterator<NameTree::const_iterator>));
40 // boost::ForwardIterator follows SGI standard http://www.sgi.com/tech/stl/ForwardIterator.html,
41 // which doesn't require DefaultConstructible
42 #ifdef HAVE_IS_DEFAULT_CONSTRUCTIBLE
43 static_assert(std::is_default_constructible<NameTree::const_iterator>::value,
44  "NameTree::const_iterator must be default-constructible");
45 #else
46 BOOST_CONCEPT_ASSERT((boost::DefaultConstructible<NameTree::const_iterator>));
47 #endif // HAVE_IS_DEFAULT_CONSTRUCTIBLE
48 
49 namespace name_tree {
50 
51 class Hash32
52 {
53 public:
54  static size_t
55  compute(const char* buffer, size_t length)
56  {
57  return static_cast<size_t>(CityHash32(buffer, length));
58  }
59 };
60 
61 class Hash64
62 {
63 public:
64  static size_t
65  compute(const char* buffer, size_t length)
66  {
67  return static_cast<size_t>(CityHash64(buffer, length));
68  }
69 };
70 
72 typedef boost::mpl::if_c<sizeof(size_t) >= 8, Hash64, Hash32>::type CityHash;
74 
75 // Interface of different hash functions
76 size_t
77 computeHash(const Name& prefix)
78 {
79  prefix.wireEncode(); // guarantees prefix's wire buffer is not empty
80 
81  size_t hashValue = 0;
82  size_t hashUpdate = 0;
83 
84  for (Name::const_iterator it = prefix.begin(); it != prefix.end(); it++)
85  {
86  const char* wireFormat = reinterpret_cast<const char*>( it->wire() );
87  hashUpdate = CityHash::compute(wireFormat, it->size());
88  hashValue ^= hashUpdate;
89  }
90 
91  return hashValue;
92 }
93 
94 std::vector<size_t>
95 computeHashSet(const Name& prefix)
96 {
97  prefix.wireEncode(); // guarantees prefix's wire buffer is not empty
98 
99  size_t hashValue = 0;
100  size_t hashUpdate = 0;
101 
102  std::vector<size_t> hashValueSet;
103  hashValueSet.push_back(hashValue);
104 
105  for (Name::const_iterator it = prefix.begin(); it != prefix.end(); it++)
106  {
107  const char* wireFormat = reinterpret_cast<const char*>( it->wire() );
108  hashUpdate = CityHash::compute(wireFormat, it->size());
109  hashValue ^= hashUpdate;
110  hashValueSet.push_back(hashValue);
111  }
112 
113  return hashValueSet;
114 }
115 
116 } // namespace name_tree
117 
118 NameTree::NameTree(size_t nBuckets)
119  : m_nItems(0)
120  , m_nBuckets(nBuckets)
121  , m_minNBuckets(nBuckets)
122  , m_enlargeLoadFactor(0.5) // more than 50% buckets loaded
123  , m_enlargeFactor(2) // double the hash table size
124  , m_shrinkLoadFactor(0.1) // less than 10% buckets loaded
125  , m_shrinkFactor(0.5) // reduce the number of buckets by half
126  , m_endIterator(FULL_ENUMERATE_TYPE, *this, m_end)
127 {
128  m_enlargeThreshold = static_cast<size_t>(m_enlargeLoadFactor *
129  static_cast<double>(m_nBuckets));
130 
131  m_shrinkThreshold = static_cast<size_t>(m_shrinkLoadFactor *
132  static_cast<double>(m_nBuckets));
133 
134  // array of node pointers
135  m_buckets = new name_tree::Node*[m_nBuckets];
136  // Initialize the pointer array
137  for (size_t i = 0; i < m_nBuckets; i++)
138  m_buckets[i] = 0;
139 }
140 
142 {
143  for (size_t i = 0; i < m_nBuckets; i++)
144  {
145  if (m_buckets[i] != 0) {
146  delete m_buckets[i];
147  }
148  }
149 
150  delete [] m_buckets;
151 }
152 
153 // insert() is a private function, and called by only lookup()
154 std::pair<shared_ptr<name_tree::Entry>, bool>
155 NameTree::insert(const Name& prefix)
156 {
157  NFD_LOG_TRACE("insert " << prefix);
158 
159  size_t hashValue = name_tree::computeHash(prefix);
160  size_t loc = hashValue % m_nBuckets;
161 
162  NFD_LOG_TRACE("Name " << prefix << " hash value = " << hashValue << " location = " << loc);
163 
164  // Check if this Name has been stored
165  name_tree::Node* node = m_buckets[loc];
166  name_tree::Node* nodePrev = node; // initialize nodePrev to node
167 
168  for (node = m_buckets[loc]; node != 0; node = node->m_next)
169  {
170  if (static_cast<bool>(node->m_entry))
171  {
172  if (prefix == node->m_entry->m_prefix)
173  {
174  return std::make_pair(node->m_entry, false); // false: old entry
175  }
176  }
177  nodePrev = node;
178  }
179 
180  NFD_LOG_TRACE("Did not find " << prefix << ", need to insert it to the table");
181 
182  // If no bucket is empty occupied, we need to create a new node, and it is
183  // linked from nodePrev
184  node = new name_tree::Node();
185  node->m_prev = nodePrev;
186 
187  if (nodePrev == 0)
188  {
189  m_buckets[loc] = node;
190  }
191  else
192  {
193  nodePrev->m_next = node;
194  }
195 
196  // Create a new Entry
197  shared_ptr<name_tree::Entry> entry(make_shared<name_tree::Entry>(prefix));
198  entry->setHash(hashValue);
199  node->m_entry = entry; // link the Entry to its Node
200  entry->m_node = node; // link the node to Entry. Used in eraseEntryIfEmpty.
201 
202  return std::make_pair(entry, true); // true: new entry
203 }
204 
205 // Name Prefix Lookup. Create Name Tree Entry if not found
206 shared_ptr<name_tree::Entry>
207 NameTree::lookup(const Name& prefix)
208 {
209  NFD_LOG_TRACE("lookup " << prefix);
210 
211  shared_ptr<name_tree::Entry> entry;
212  shared_ptr<name_tree::Entry> parent;
213 
214  for (size_t i = 0; i <= prefix.size(); i++)
215  {
216  Name temp = prefix.getPrefix(i);
217 
218  // insert() will create the entry if it does not exist.
219  std::pair<shared_ptr<name_tree::Entry>, bool> ret = insert(temp);
220  entry = ret.first;
221 
222  if (ret.second == true)
223  {
224  m_nItems++; // Increase the counter
225  entry->m_parent = parent;
226 
227  if (static_cast<bool>(parent))
228  {
229  parent->m_children.push_back(entry);
230  }
231  }
232 
233  if (m_nItems > m_enlargeThreshold)
234  {
235  resize(m_enlargeFactor * m_nBuckets);
236  }
237 
238  parent = entry;
239  }
240  return entry;
241 }
242 
243 // return {false: this entry is not empty, true: this entry is empty and erased}
244 bool
245 NameTree::eraseEntryIfEmpty(shared_ptr<name_tree::Entry> entry)
246 {
247  BOOST_ASSERT(static_cast<bool>(entry));
248 
249  NFD_LOG_TRACE("eraseEntryIfEmpty " << entry->getPrefix());
250 
251  // first check if this Entry can be erased
252  if (entry->isEmpty())
253  {
254  // update child-related info in the parent
255  shared_ptr<name_tree::Entry> parent = entry->getParent();
256 
257  if (static_cast<bool>(parent))
258  {
259  std::vector<shared_ptr<name_tree::Entry> >& parentChildrenList =
260  parent->getChildren();
261 
262  bool isFound = false;
263  size_t size = parentChildrenList.size();
264  for (size_t i = 0; i < size; i++)
265  {
266  if (parentChildrenList[i] == entry)
267  {
268  parentChildrenList[i] = parentChildrenList[size - 1];
269  parentChildrenList.pop_back();
270  isFound = true;
271  break;
272  }
273  }
274 
275  BOOST_VERIFY(isFound == true);
276  }
277 
278  // remove this Entry and its Name Tree Node
279  name_tree::Node* node = entry->m_node;
280  name_tree::Node* nodePrev = node->m_prev;
281 
282  // configure the previous node
283  if (nodePrev != 0)
284  {
285  // link the previous node to the next node
286  nodePrev->m_next = node->m_next;
287  }
288  else
289  {
290  m_buckets[entry->getHash() % m_nBuckets] = node->m_next;
291  }
292 
293  // link the previous node with the next node (skip the erased one)
294  if (node->m_next != 0)
295  {
296  node->m_next->m_prev = nodePrev;
297  node->m_next = 0;
298  }
299 
300  BOOST_ASSERT(node->m_next == 0);
301 
302  m_nItems--;
303  delete node;
304 
305  if (static_cast<bool>(parent))
306  eraseEntryIfEmpty(parent);
307 
308  size_t newNBuckets = static_cast<size_t>(m_shrinkFactor *
309  static_cast<double>(m_nBuckets));
310 
311  if (newNBuckets >= m_minNBuckets && m_nItems < m_shrinkThreshold)
312  {
313  resize(newNBuckets);
314  }
315 
316  return true;
317 
318  } // if this entry is empty
319 
320  return false; // if this entry is not empty
321 }
322 
323 shared_ptr<name_tree::Entry>
324 NameTree::get(const pit::Entry& pitEntry)
325 {
326  shared_ptr<name_tree::Entry> nte = pitEntry.m_nameTreeEntry;
327  if (nte == nullptr) {
328  return nullptr;
329  }
330 
331  if (nte->getPrefix().size() == pitEntry.getName().size()) {
332  return nte;
333  }
334 
335  BOOST_ASSERT(pitEntry.getName().at(-1).isImplicitSha256Digest());
336  BOOST_ASSERT(nte->getPrefix() == pitEntry.getName().getPrefix(-1));
337  return this->lookup(pitEntry.getName());
338 }
339 
340 // Exact Match
341 shared_ptr<name_tree::Entry>
342 NameTree::findExactMatch(const Name& prefix) const
343 {
344  NFD_LOG_TRACE("findExactMatch " << prefix);
345 
346  size_t hashValue = name_tree::computeHash(prefix);
347  size_t loc = hashValue % m_nBuckets;
348 
349  NFD_LOG_TRACE("Name " << prefix << " hash value = " << hashValue <<
350  " location = " << loc);
351 
352  shared_ptr<name_tree::Entry> entry;
353  name_tree::Node* node = 0;
354 
355  for (node = m_buckets[loc]; node != 0; node = node->m_next)
356  {
357  entry = node->m_entry;
358  if (static_cast<bool>(entry))
359  {
360  if (hashValue == entry->getHash() && prefix == entry->getPrefix())
361  {
362  return entry;
363  }
364  } // if entry
365  } // for node
366 
367  // if not found, the default value of entry (null pointer) will be returned
368  entry.reset();
369  return entry;
370 }
371 
372 // Longest Prefix Match
373 shared_ptr<name_tree::Entry>
374 NameTree::findLongestPrefixMatch(const Name& prefix, const name_tree::EntrySelector& entrySelector) const
375 {
376  NFD_LOG_TRACE("findLongestPrefixMatch " << prefix);
377 
378  shared_ptr<name_tree::Entry> entry;
379  std::vector<size_t> hashValueSet = name_tree::computeHashSet(prefix);
380 
381  size_t hashValue = 0;
382  size_t loc = 0;
383 
384  for (int i = static_cast<int>(prefix.size()); i >= 0; i--)
385  {
386  hashValue = hashValueSet[i];
387  loc = hashValue % m_nBuckets;
388 
389  name_tree::Node* node = 0;
390  for (node = m_buckets[loc]; node != 0; node = node->m_next)
391  {
392  entry = node->m_entry;
393  if (static_cast<bool>(entry))
394  {
395  // isPrefixOf() is used to avoid making a copy of the name
396  if (hashValue == entry->getHash() &&
397  entry->getPrefix().isPrefixOf(prefix) &&
398  entrySelector(*entry))
399  {
400  return entry;
401  }
402  } // if entry
403  } // for node
404  }
405 
406  // if not found, the default value of entry (null pointer) will be returned
407  entry.reset();
408  return entry;
409 }
410 
411 shared_ptr<name_tree::Entry>
412 NameTree::findLongestPrefixMatch(shared_ptr<name_tree::Entry> entry,
413  const name_tree::EntrySelector& entrySelector) const
414 {
415  while (static_cast<bool>(entry))
416  {
417  if (entrySelector(*entry))
418  return entry;
419  entry = entry->getParent();
420  }
421  return shared_ptr<name_tree::Entry>();
422 }
423 
424 shared_ptr<name_tree::Entry>
426 {
427  shared_ptr<name_tree::Entry> nte = pitEntry.m_nameTreeEntry;
428  if (nte->getPrefix().size() == pitEntry.getName().size()) {
429  return nte;
430  }
431 
432  BOOST_ASSERT(pitEntry.getName().at(-1).isImplicitSha256Digest());
433  BOOST_ASSERT(nte->getPrefix() == pitEntry.getName().getPrefix(-1));
434  shared_ptr<name_tree::Entry> exact = this->findExactMatch(pitEntry.getName());
435  return exact == nullptr ? nte : exact;
436 }
437 
438 boost::iterator_range<NameTree::const_iterator>
440  const name_tree::EntrySelector& entrySelector) const
441 {
442  NFD_LOG_TRACE("NameTree::findAllMatches" << prefix);
443 
444  // As we are using Name Prefix Hash Table, and the current LPM() is
445  // implemented as starting from full name, and reduce the number of
446  // components by 1 each time, we could use it here.
447  // For trie-like design, it could be more efficient by walking down the
448  // trie from the root node.
449 
450  shared_ptr<name_tree::Entry> entry = findLongestPrefixMatch(prefix, entrySelector);
451 
452  if (static_cast<bool>(entry)) {
453  const_iterator begin(FIND_ALL_MATCHES_TYPE, *this, entry, entrySelector);
454  return {begin, end()};
455  }
456  // If none of the entry satisfies the requirements, then return the end() iterator.
457  return {end(), end()};
458 }
459 
460 boost::iterator_range<NameTree::const_iterator>
462 {
463  NFD_LOG_TRACE("fullEnumerate");
464 
465  // find the first eligible entry
466  for (size_t i = 0; i < m_nBuckets; i++) {
467  for (name_tree::Node* node = m_buckets[i]; node != 0; node = node->m_next) {
468  if (static_cast<bool>(node->m_entry) && entrySelector(*node->m_entry)) {
469  const_iterator it(FULL_ENUMERATE_TYPE, *this, node->m_entry, entrySelector);
470  return {it, end()};
471  }
472  }
473  }
474 
475  // If none of the entry satisfies the requirements, then return the end() iterator.
476  return {end(), end()};
477 }
478 
479 boost::iterator_range<NameTree::const_iterator>
481  const name_tree::EntrySubTreeSelector& entrySubTreeSelector) const
482 {
483  // the first step is to process the root node
484  shared_ptr<name_tree::Entry> entry = findExactMatch(prefix);
485  if (!static_cast<bool>(entry)) {
486  return {end(), end()};
487  }
488 
489  std::pair<bool, bool>result = entrySubTreeSelector(*entry);
491  *this,
492  entry,
494  entrySubTreeSelector);
495 
496  it.m_shouldVisitChildren = (result.second && entry->hasChildren());
497 
498  if (result.first) {
499  // root node is acceptable
500  }
501  else {
502  // let the ++ operator handle it
503  ++it;
504  }
505  return {it, end()};
506 }
507 
508 // Hash Table Resize
509 void
510 NameTree::resize(size_t newNBuckets)
511 {
512  NFD_LOG_TRACE("resize");
513 
514  name_tree::Node** newBuckets = new name_tree::Node*[newNBuckets];
515  size_t count = 0;
516 
517  // referenced ccnx hashtb.c hashtb_rehash()
518  name_tree::Node** pp = 0;
519  name_tree::Node* p = 0;
520  name_tree::Node* pre = 0;
521  name_tree::Node* q = 0; // record p->m_next
522  size_t i;
523  uint32_t h;
524  uint32_t b;
525 
526  for (i = 0; i < newNBuckets; i++)
527  {
528  newBuckets[i] = 0;
529  }
530 
531  for (i = 0; i < m_nBuckets; i++)
532  {
533  for (p = m_buckets[i]; p != 0; p = q)
534  {
535  count++;
536  q = p->m_next;
537  BOOST_ASSERT(static_cast<bool>(p->m_entry));
538  h = p->m_entry->m_hash;
539  b = h % newNBuckets;
540  pre = 0;
541  for (pp = &newBuckets[b]; *pp != 0; pp = &((*pp)->m_next))
542  {
543  pre = *pp;
544  continue;
545  }
546  p->m_prev = pre;
547  p->m_next = *pp; // Actually *pp always == 0 in this case
548  *pp = p;
549  }
550  }
551 
552  BOOST_ASSERT(count == m_nItems);
553 
554  name_tree::Node** oldBuckets = m_buckets;
555  m_buckets = newBuckets;
556  delete [] oldBuckets;
557 
558  m_nBuckets = newNBuckets;
559 
560  m_enlargeThreshold = static_cast<size_t>(m_enlargeLoadFactor *
561  static_cast<double>(m_nBuckets));
562  m_shrinkThreshold = static_cast<size_t>(m_shrinkLoadFactor *
563  static_cast<double>(m_nBuckets));
564 }
565 
566 // For debugging
567 void
568 NameTree::dump(std::ostream& output) const
569 {
570  NFD_LOG_TRACE("dump()");
571 
572  name_tree::Node* node = 0;
573  shared_ptr<name_tree::Entry> entry;
574 
575  using std::endl;
576 
577  for (size_t i = 0; i < m_nBuckets; i++)
578  {
579  for (node = m_buckets[i]; node != 0; node = node->m_next)
580  {
581  entry = node->m_entry;
582 
583  // if the Entry exist, dump its information
584  if (static_cast<bool>(entry))
585  {
586  output << "Bucket" << i << "\t" << entry->m_prefix.toUri() << endl;
587  output << "\t\tHash " << entry->m_hash << endl;
588 
589  if (static_cast<bool>(entry->m_parent))
590  {
591  output << "\t\tparent->" << entry->m_parent->m_prefix.toUri();
592  }
593  else
594  {
595  output << "\t\tROOT";
596  }
597  output << endl;
598 
599  if (entry->m_children.size() != 0)
600  {
601  output << "\t\tchildren = " << entry->m_children.size() << endl;
602 
603  for (size_t j = 0; j < entry->m_children.size(); j++)
604  {
605  output << "\t\t\tChild " << j << " " <<
606  entry->m_children[j]->getPrefix() << endl;
607  }
608  }
609 
610  } // if (static_cast<bool>(entry))
611 
612  } // for node
613  } // for int i
614 
615  output << "Bucket count = " << m_nBuckets << endl;
616  output << "Stored item = " << m_nItems << endl;
617  output << "--------------------------\n";
618 }
619 
621  : m_nameTree(nullptr)
622 {
623 }
624 
626  const NameTree& nameTree,
627  shared_ptr<name_tree::Entry> entry,
628  const name_tree::EntrySelector& entrySelector,
629  const name_tree::EntrySubTreeSelector& entrySubTreeSelector)
630  : m_nameTree(&nameTree)
631  , m_entry(entry)
632  , m_subTreeRoot(entry)
633  , m_entrySelector(make_shared<name_tree::EntrySelector>(entrySelector))
634  , m_entrySubTreeSelector(make_shared<name_tree::EntrySubTreeSelector>(entrySubTreeSelector))
635  , m_type(type)
636  , m_shouldVisitChildren(true)
637 {
638 }
639 
640 // operator++()
643 {
644  NFD_LOG_TRACE("const_iterator::operator++()");
645 
646  BOOST_ASSERT(m_entry != m_nameTree->m_end);
647 
648  if (m_type == FULL_ENUMERATE_TYPE) // fullEnumerate
649  {
650  // process the entries in the same bucket first
651  while (m_entry->m_node->m_next != 0)
652  {
653  m_entry = m_entry->m_node->m_next->m_entry;
654  if ((*m_entrySelector)(*m_entry))
655  {
656  return *this;
657  }
658  }
659 
660  // process other buckets
661 
662  for (int newLocation = m_entry->m_hash % m_nameTree->m_nBuckets + 1;
663  newLocation < static_cast<int>(m_nameTree->m_nBuckets);
664  ++newLocation)
665  {
666  // process each bucket
667  name_tree::Node* node = m_nameTree->m_buckets[newLocation];
668  while (node != 0)
669  {
670  m_entry = node->m_entry;
671  if ((*m_entrySelector)(*m_entry))
672  {
673  return *this;
674  }
675  node = node->m_next;
676  }
677  }
678 
679  // Reach the end()
680  m_entry = m_nameTree->m_end;
681  return *this;
682  }
683 
684  if (m_type == PARTIAL_ENUMERATE_TYPE) // partialEnumerate
685  {
686  // We use pre-order traversal.
687  // if at the root, it could have already been accepted, or this
688  // iterator was just declared, and root doesn't satisfy the
689  // requirement
690  // The if() section handles this special case
691  // Essentially, we need to check root's fist child, and the rest will
692  // be the same as normal process
693  if (m_entry == m_subTreeRoot)
694  {
695  if (m_shouldVisitChildren)
696  {
697  m_entry = m_entry->getChildren()[0];
698  std::pair<bool, bool> result = ((*m_entrySubTreeSelector)(*m_entry));
699  m_shouldVisitChildren = (result.second && m_entry->hasChildren());
700  if(result.first)
701  {
702  return *this;
703  }
704  else
705  {
706  // the first child did not meet the requirement
707  // the rest of the process can just fall through the while loop
708  // as normal
709  }
710  }
711  else
712  {
713  // no children, should return end();
714  // just fall through
715  }
716  }
717 
718  // The first thing to do is to visit its child, or go to find its possible
719  // siblings
720  while (m_entry != m_subTreeRoot)
721  {
722  if (m_shouldVisitChildren)
723  {
724  // If this subtree should be visited
725  m_entry = m_entry->getChildren()[0];
726  std::pair<bool, bool> result = ((*m_entrySubTreeSelector)(*m_entry));
727  m_shouldVisitChildren = (result.second && m_entry->hasChildren());
728  if (result.first) // if this node is acceptable
729  {
730  return *this;
731  }
732  else
733  {
734  // do nothing, as this node is essentially ignored
735  // send this node to the while loop.
736  }
737  }
738  else
739  {
740  // Should try to find its sibling
741  shared_ptr<name_tree::Entry> parent = m_entry->getParent();
742 
743  std::vector<shared_ptr<name_tree::Entry> >& parentChildrenList = parent->getChildren();
744  bool isFound = false;
745  size_t i = 0;
746  for (i = 0; i < parentChildrenList.size(); i++)
747  {
748  if (parentChildrenList[i] == m_entry)
749  {
750  isFound = true;
751  break;
752  }
753  }
754 
755  BOOST_VERIFY(isFound == true);
756  if (i < parentChildrenList.size() - 1) // m_entry not the last child
757  {
758  m_entry = parentChildrenList[i + 1];
759  std::pair<bool, bool> result = ((*m_entrySubTreeSelector)(*m_entry));
760  m_shouldVisitChildren = (result.second && m_entry->hasChildren());
761  if (result.first) // if this node is acceptable
762  {
763  return *this;
764  }
765  else
766  {
767  // do nothing, as this node is essentially ignored
768  // send this node to the while loop.
769  }
770  }
771  else
772  {
773  // m_entry is the last child, no more sibling, should try to find parent's sibling
774  m_shouldVisitChildren = false;
775  m_entry = parent;
776  }
777  }
778  }
779 
780  m_entry = m_nameTree->m_end;
781  return *this;
782  }
783 
784  if (m_type == FIND_ALL_MATCHES_TYPE) // findAllMatches
785  {
786  // Assumption: at the beginning, m_entry was initialized with the first
787  // eligible Name Tree entry (i.e., has a PIT entry that can be satisfied
788  // by the Data packet)
789 
790  while (static_cast<bool>(m_entry->getParent()))
791  {
792  m_entry = m_entry->getParent();
793  if ((*m_entrySelector)(*m_entry))
794  return *this;
795  }
796 
797  // Reach to the end (Root)
798  m_entry = m_nameTree->m_end;
799  return *this;
800  }
801 
802  BOOST_ASSERT(false); // unknown type
803  return *this;
804 }
805 
806 } // namespace nfd
size_t computeHash(const Name &prefix)
Compute the hash value of the given name prefix&#39;s WIRE FORMAT.
Definition: name-tree.cpp:77
PartialName getPrefix(ssize_t nComponents) const
Extract a prefix (PartialName) of the name, containing first nComponents components.
Definition: name.hpp:249
NameTree(size_t nBuckets=1024)
Definition: name-tree.cpp:118
static size_t compute(const char *buffer, size_t length)
Definition: name-tree.cpp:65
Name Tree Node Class.
shared_ptr< Entry > m_entry
const Component & at(ssize_t i) const
Get component at the specified index.
Definition: name.hpp:442
const_iterator end() const
End iterator (const).
Definition: name.hpp:587
bool eraseEntryIfEmpty(shared_ptr< name_tree::Entry > entry)
Delete a Name Tree Entry if this entry is empty.
Definition: name-tree.cpp:245
uint32 CityHash32(const char *s, size_t len)
Definition: city-hash.cpp:182
function< std::pair< bool, bool >const Entry &entry)> EntrySubTreeSelector
a predicate to accept or reject an Entry and its children
Definition: name-tree.hpp:56
shared_ptr< name_tree::Entry > get(const fib::Entry &fibEntry) const
get NameTree entry from FIB entry
Definition: name-tree.hpp:367
const Name & getName() const
Definition: pit-entry.cpp:41
std::vector< size_t > computeHashSet(const Name &prefix)
Incrementally compute hash values.
Definition: name-tree.cpp:95
void dump(std::ostream &output) const
Dump all the information stored in the Name Tree for debugging.
Definition: name-tree.cpp:568
size_t size() const
Get the number of occupied entries in the Name Tree.
Definition: name-tree.hpp:355
shared_ptr< name_tree::Entry > findLongestPrefixMatch(const Name &prefix, const name_tree::EntrySelector &entrySelector=name_tree::AnyEntry()) const
Longest prefix matching for the given name.
Definition: name-tree.cpp:374
uint64 CityHash64(const char *s, size_t len)
Definition: city-hash.cpp:359
const_iterator begin() const
Get an iterator pointing to the first NameTree entry.
Definition: name-tree.hpp:385
Copyright (c) 2011-2015 Regents of the University of California.
Definition: ndn-common.hpp:40
represents a PIT entry
Definition: pit-entry.hpp:69
Class Name Tree.
Definition: name-tree.hpp:79
shared_ptr< name_tree::Entry > findExactMatch(const Name &prefix) const
Exact match lookup for the given name prefix.
Definition: name-tree.cpp:342
bool isImplicitSha256Digest() const
Check if the component is ImplicitSha256DigestComponent.
Name abstraction to represent an absolute name.
Definition: name.hpp:46
const_iterator begin() const
Begin iterator (const).
Definition: name.hpp:576
shared_ptr< name_tree::Entry > lookup(const Name &prefix)
Look for the Name Tree Entry that contains this name prefix.
Definition: name-tree.cpp:207
boost::iterator_range< const_iterator > findAllMatches(const Name &prefix, const name_tree::EntrySelector &entrySelector=name_tree::AnyEntry()) const
Enumerate all the name prefixes that satisfy the prefix and entrySelector.
Definition: name-tree.cpp:439
const_iterator operator++()
Definition: name-tree.cpp:642
size_t size() const
Get the number of components.
Definition: name.hpp:408
Component holds a read-only name component value.
static size_t compute(const char *buffer, size_t length)
Definition: name-tree.cpp:55
#define NFD_LOG_INIT(name)
Definition: logger.hpp:34
const_iterator end() const
Get an iterator referring to the past-the-end FIB entry.
Definition: name-tree.hpp:391
#define NFD_LOG_TRACE(expression)
Definition: logger.hpp:54
function< bool(const Entry &entry)> EntrySelector
a predicate to accept or reject an Entry in find operations
Definition: name-tree.hpp:49
size_t wireEncode(EncodingImpl< TAG > &encoder) const
Fast encoding or block size estimation.
Definition: name.cpp:69
boost::iterator_range< const_iterator > partialEnumerate(const Name &prefix, const name_tree::EntrySubTreeSelector &entrySubTreeSelector=name_tree::AnyEntrySubTree()) const
Enumerate all entries under a prefix, optionally filtered by an EntrySubTreeSelector.
Definition: name-tree.cpp:480
boost::iterator_range< const_iterator > fullEnumerate(const name_tree::EntrySelector &entrySelector=name_tree::AnyEntry()) const
Enumerate all entries, optionally filtered by an EntrySelector.
Definition: name-tree.cpp:461