blob: bcf888ea22c8b6c317aafc4fe374425e372a2936 [file] [log] [blame]
HYuana9b85752014-02-26 02:32:30 -06001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
Junxiao Shi4370fde2016-02-24 12:20:46 -07003 * Copyright (c) 2014-2016, Regents of the University of California,
Alexander Afanasyev319f2c82015-01-07 14:56:53 -08004 * 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.
Alexander Afanasyev9bcbc7c2014-04-06 19:37:37 -070010 *
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/>.
Junxiao Shi2b73ca32014-11-17 19:16:08 -070024 */
HYuana9b85752014-02-26 02:32:30 -060025
26#include "name-tree.hpp"
27#include "core/logger.hpp"
Haowei Yuanf52dac72014-03-24 23:35:03 -050028#include "core/city-hash.hpp"
Davide Pesavento52a18f92014-04-10 00:55:01 +020029
Alexander Afanasyev09fc3d92015-01-03 02:02:37 -080030#include <boost/concept/assert.hpp>
31#include <boost/concept_check.hpp>
32#include <type_traits>
33
HYuana9b85752014-02-26 02:32:30 -060034namespace nfd {
35
36NFD_LOG_INIT("NameTree");
37
Alexander Afanasyev09fc3d92015-01-03 02:02:37 -080038// http://en.cppreference.com/w/cpp/concept/ForwardIterator
39BOOST_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
43static_assert(std::is_default_constructible<NameTree::const_iterator>::value,
44 "NameTree::const_iterator must be default-constructible");
45#else
46BOOST_CONCEPT_ASSERT((boost::DefaultConstructible<NameTree::const_iterator>));
47#endif // HAVE_IS_DEFAULT_CONSTRUCTIBLE
48
HYuana9b85752014-02-26 02:32:30 -060049namespace name_tree {
50
Haowei Yuanf52dac72014-03-24 23:35:03 -050051class Hash32
HYuana9b85752014-02-26 02:32:30 -060052{
Haowei Yuanf52dac72014-03-24 23:35:03 -050053public:
54 static size_t
55 compute(const char* buffer, size_t length)
56 {
57 return static_cast<size_t>(CityHash32(buffer, length));
58 }
59};
HYuana9b85752014-02-26 02:32:30 -060060
Haowei Yuanf52dac72014-03-24 23:35:03 -050061class Hash64
62{
63public:
64 static size_t
65 compute(const char* buffer, size_t length)
66 {
67 return static_cast<size_t>(CityHash64(buffer, length));
68 }
69};
HYuana9b85752014-02-26 02:32:30 -060070
Alexander Afanasyevb755e9d2015-10-20 17:35:51 -050071/// @cond NoDocumentation
Haowei Yuanf52dac72014-03-24 23:35:03 -050072typedef boost::mpl::if_c<sizeof(size_t) >= 8, Hash64, Hash32>::type CityHash;
Alexander Afanasyevb755e9d2015-10-20 17:35:51 -050073/// @endcond
Haowei Yuanf52dac72014-03-24 23:35:03 -050074
75// Interface of different hash functions
76size_t
77computeHash(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
94std::vector<size_t>
95computeHashSet(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;
HYuana9b85752014-02-26 02:32:30 -0600114}
115
116} // namespace name_tree
117
118NameTree::NameTree(size_t nBuckets)
119 : m_nItems(0)
120 , m_nBuckets(nBuckets)
Haowei Yuanf52dac72014-03-24 23:35:03 -0500121 , 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
Haowei Yuane1079fc2014-03-08 14:41:25 -0600126 , m_endIterator(FULL_ENUMERATE_TYPE, *this, m_end)
HYuana9b85752014-02-26 02:32:30 -0600127{
Haowei Yuanf52dac72014-03-24 23:35:03 -0500128 m_enlargeThreshold = static_cast<size_t>(m_enlargeLoadFactor *
129 static_cast<double>(m_nBuckets));
130
131 m_shrinkThreshold = static_cast<size_t>(m_shrinkLoadFactor *
HYuana9b85752014-02-26 02:32:30 -0600132 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
141NameTree::~NameTree()
142{
143 for (size_t i = 0; i < m_nBuckets; i++)
144 {
Haowei Yuanf52dac72014-03-24 23:35:03 -0500145 if (m_buckets[i] != 0) {
HYuana9b85752014-02-26 02:32:30 -0600146 delete m_buckets[i];
Haowei Yuanf52dac72014-03-24 23:35:03 -0500147 }
HYuana9b85752014-02-26 02:32:30 -0600148 }
149
150 delete [] m_buckets;
151}
152
153// insert() is a private function, and called by only lookup()
154std::pair<shared_ptr<name_tree::Entry>, bool>
155NameTree::insert(const Name& prefix)
156{
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700157 NFD_LOG_TRACE("insert " << prefix);
HYuana9b85752014-02-26 02:32:30 -0600158
Haowei Yuanf52dac72014-03-24 23:35:03 -0500159 size_t hashValue = name_tree::computeHash(prefix);
160 size_t loc = hashValue % m_nBuckets;
HYuana9b85752014-02-26 02:32:30 -0600161
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700162 NFD_LOG_TRACE("Name " << prefix << " hash value = " << hashValue << " location = " << loc);
HYuana9b85752014-02-26 02:32:30 -0600163
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
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700180 NFD_LOG_TRACE("Did not find " << prefix << ", need to insert it to the table");
HYuana9b85752014-02-26 02:32:30 -0600181
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
206shared_ptr<name_tree::Entry>
207NameTree::lookup(const Name& prefix)
208{
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700209 NFD_LOG_TRACE("lookup " << prefix);
HYuana9b85752014-02-26 02:32:30 -0600210
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 {
Haowei Yuanf52dac72014-03-24 23:35:03 -0500224 m_nItems++; // Increase the counter
HYuana9b85752014-02-26 02:32:30 -0600225 entry->m_parent = parent;
226
227 if (static_cast<bool>(parent))
228 {
229 parent->m_children.push_back(entry);
230 }
231 }
232
Haowei Yuanf52dac72014-03-24 23:35:03 -0500233 if (m_nItems > m_enlargeThreshold)
HYuana9b85752014-02-26 02:32:30 -0600234 {
Haowei Yuanf52dac72014-03-24 23:35:03 -0500235 resize(m_enlargeFactor * m_nBuckets);
HYuana9b85752014-02-26 02:32:30 -0600236 }
237
238 parent = entry;
239 }
240 return entry;
241}
242
Junxiao Shib184e532016-05-26 18:09:57 +0000243shared_ptr<name_tree::Entry>
244NameTree::lookup(const fib::Entry& fibEntry) const
245{
246 shared_ptr<name_tree::Entry> nte = this->getEntry(fibEntry);
Junxiao Shia6de4292016-07-12 02:08:10 +0000247 BOOST_ASSERT(nte == nullptr || nte->getFibEntry() == &fibEntry);
Junxiao Shib184e532016-05-26 18:09:57 +0000248 return nte;
249}
250
251shared_ptr<name_tree::Entry>
252NameTree::lookup(const pit::Entry& pitEntry)
253{
254 shared_ptr<name_tree::Entry> nte = this->getEntry(pitEntry);
255 if (nte == nullptr) {
256 return nullptr;
257 }
258
259 if (nte->getPrefix().size() == pitEntry.getName().size()) {
260 return nte;
261 }
262
263 BOOST_ASSERT(pitEntry.getName().at(-1).isImplicitSha256Digest());
264 BOOST_ASSERT(nte->getPrefix() == pitEntry.getName().getPrefix(-1));
265 return this->lookup(pitEntry.getName());
266}
267
268shared_ptr<name_tree::Entry>
269NameTree::lookup(const measurements::Entry& measurementsEntry) const
270{
271 shared_ptr<name_tree::Entry> nte = this->getEntry(measurementsEntry);
Junxiao Shi80f9fcd2016-07-23 02:48:36 +0000272 BOOST_ASSERT(nte == nullptr || nte->getMeasurementsEntry() == &measurementsEntry);
Junxiao Shib184e532016-05-26 18:09:57 +0000273 return nte;
274}
275
276shared_ptr<name_tree::Entry>
277NameTree::lookup(const strategy_choice::Entry& strategyChoiceEntry) const
278{
279 shared_ptr<name_tree::Entry> nte = this->getEntry(strategyChoiceEntry);
Junxiao Shiff10da62016-07-13 17:57:43 +0000280 BOOST_ASSERT(nte == nullptr || nte->getStrategyChoiceEntry() == &strategyChoiceEntry);
Junxiao Shib184e532016-05-26 18:09:57 +0000281 return nte;
282}
283
Junxiao Shi4370fde2016-02-24 12:20:46 -0700284// return {false: this entry is not empty, true: this entry is empty and erased}
285bool
286NameTree::eraseEntryIfEmpty(shared_ptr<name_tree::Entry> entry)
287{
288 BOOST_ASSERT(static_cast<bool>(entry));
289
290 NFD_LOG_TRACE("eraseEntryIfEmpty " << entry->getPrefix());
291
292 // first check if this Entry can be erased
293 if (entry->isEmpty())
294 {
295 // update child-related info in the parent
296 shared_ptr<name_tree::Entry> parent = entry->getParent();
297
298 if (static_cast<bool>(parent))
299 {
300 std::vector<shared_ptr<name_tree::Entry> >& parentChildrenList =
301 parent->getChildren();
302
303 bool isFound = false;
304 size_t size = parentChildrenList.size();
305 for (size_t i = 0; i < size; i++)
306 {
307 if (parentChildrenList[i] == entry)
308 {
309 parentChildrenList[i] = parentChildrenList[size - 1];
310 parentChildrenList.pop_back();
311 isFound = true;
312 break;
313 }
314 }
315
316 BOOST_VERIFY(isFound == true);
317 }
318
319 // remove this Entry and its Name Tree Node
320 name_tree::Node* node = entry->m_node;
321 name_tree::Node* nodePrev = node->m_prev;
322
323 // configure the previous node
324 if (nodePrev != 0)
325 {
326 // link the previous node to the next node
327 nodePrev->m_next = node->m_next;
328 }
329 else
330 {
331 m_buckets[entry->getHash() % m_nBuckets] = node->m_next;
332 }
333
334 // link the previous node with the next node (skip the erased one)
335 if (node->m_next != 0)
336 {
337 node->m_next->m_prev = nodePrev;
338 node->m_next = 0;
339 }
340
341 BOOST_ASSERT(node->m_next == 0);
342
343 m_nItems--;
344 delete node;
345
346 if (static_cast<bool>(parent))
347 eraseEntryIfEmpty(parent);
348
349 size_t newNBuckets = static_cast<size_t>(m_shrinkFactor *
350 static_cast<double>(m_nBuckets));
351
352 if (newNBuckets >= m_minNBuckets && m_nItems < m_shrinkThreshold)
353 {
354 resize(newNBuckets);
355 }
356
357 return true;
358
359 } // if this entry is empty
360
361 return false; // if this entry is not empty
362}
363
HYuana9b85752014-02-26 02:32:30 -0600364// Exact Match
365shared_ptr<name_tree::Entry>
366NameTree::findExactMatch(const Name& prefix) const
367{
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700368 NFD_LOG_TRACE("findExactMatch " << prefix);
HYuana9b85752014-02-26 02:32:30 -0600369
Haowei Yuanf52dac72014-03-24 23:35:03 -0500370 size_t hashValue = name_tree::computeHash(prefix);
371 size_t loc = hashValue % m_nBuckets;
HYuana9b85752014-02-26 02:32:30 -0600372
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700373 NFD_LOG_TRACE("Name " << prefix << " hash value = " << hashValue <<
HYuana9b85752014-02-26 02:32:30 -0600374 " location = " << loc);
375
376 shared_ptr<name_tree::Entry> entry;
377 name_tree::Node* node = 0;
378
379 for (node = m_buckets[loc]; node != 0; node = node->m_next)
380 {
381 entry = node->m_entry;
382 if (static_cast<bool>(entry))
383 {
384 if (hashValue == entry->getHash() && prefix == entry->getPrefix())
385 {
386 return entry;
387 }
388 } // if entry
389 } // for node
390
391 // if not found, the default value of entry (null pointer) will be returned
392 entry.reset();
393 return entry;
394}
395
396// Longest Prefix Match
HYuana9b85752014-02-26 02:32:30 -0600397shared_ptr<name_tree::Entry>
Haowei Yuane1079fc2014-03-08 14:41:25 -0600398NameTree::findLongestPrefixMatch(const Name& prefix, const name_tree::EntrySelector& entrySelector) const
HYuana9b85752014-02-26 02:32:30 -0600399{
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700400 NFD_LOG_TRACE("findLongestPrefixMatch " << prefix);
HYuana9b85752014-02-26 02:32:30 -0600401
402 shared_ptr<name_tree::Entry> entry;
Haowei Yuanf52dac72014-03-24 23:35:03 -0500403 std::vector<size_t> hashValueSet = name_tree::computeHashSet(prefix);
HYuana9b85752014-02-26 02:32:30 -0600404
Haowei Yuanf52dac72014-03-24 23:35:03 -0500405 size_t hashValue = 0;
406 size_t loc = 0;
407
408 for (int i = static_cast<int>(prefix.size()); i >= 0; i--)
HYuana9b85752014-02-26 02:32:30 -0600409 {
Haowei Yuanf52dac72014-03-24 23:35:03 -0500410 hashValue = hashValueSet[i];
411 loc = hashValue % m_nBuckets;
412
413 name_tree::Node* node = 0;
414 for (node = m_buckets[loc]; node != 0; node = node->m_next)
415 {
416 entry = node->m_entry;
417 if (static_cast<bool>(entry))
418 {
419 // isPrefixOf() is used to avoid making a copy of the name
420 if (hashValue == entry->getHash() &&
421 entry->getPrefix().isPrefixOf(prefix) &&
422 entrySelector(*entry))
423 {
424 return entry;
425 }
426 } // if entry
427 } // for node
HYuana9b85752014-02-26 02:32:30 -0600428 }
429
Haowei Yuanf52dac72014-03-24 23:35:03 -0500430 // if not found, the default value of entry (null pointer) will be returned
431 entry.reset();
432 return entry;
HYuana9b85752014-02-26 02:32:30 -0600433}
434
HangZhangcb4fc832014-03-11 16:57:11 +0800435shared_ptr<name_tree::Entry>
436NameTree::findLongestPrefixMatch(shared_ptr<name_tree::Entry> entry,
437 const name_tree::EntrySelector& entrySelector) const
438{
439 while (static_cast<bool>(entry))
440 {
441 if (entrySelector(*entry))
442 return entry;
443 entry = entry->getParent();
444 }
445 return shared_ptr<name_tree::Entry>();
446}
447
Junxiao Shi4370fde2016-02-24 12:20:46 -0700448shared_ptr<name_tree::Entry>
449NameTree::findLongestPrefixMatch(const pit::Entry& pitEntry) const
HYuana9b85752014-02-26 02:32:30 -0600450{
Junxiao Shib184e532016-05-26 18:09:57 +0000451 shared_ptr<name_tree::Entry> nte = this->getEntry(pitEntry);
452 BOOST_ASSERT(nte != nullptr);
Junxiao Shi4370fde2016-02-24 12:20:46 -0700453 if (nte->getPrefix().size() == pitEntry.getName().size()) {
454 return nte;
455 }
HYuana9b85752014-02-26 02:32:30 -0600456
Junxiao Shi4370fde2016-02-24 12:20:46 -0700457 BOOST_ASSERT(pitEntry.getName().at(-1).isImplicitSha256Digest());
458 BOOST_ASSERT(nte->getPrefix() == pitEntry.getName().getPrefix(-1));
459 shared_ptr<name_tree::Entry> exact = this->findExactMatch(pitEntry.getName());
460 return exact == nullptr ? nte : exact;
461}
HYuana9b85752014-02-26 02:32:30 -0600462
Junxiao Shi4370fde2016-02-24 12:20:46 -0700463boost::iterator_range<NameTree::const_iterator>
464NameTree::findAllMatches(const Name& prefix,
465 const name_tree::EntrySelector& entrySelector) const
466{
467 NFD_LOG_TRACE("NameTree::findAllMatches" << prefix);
HYuana9b85752014-02-26 02:32:30 -0600468
Junxiao Shi4370fde2016-02-24 12:20:46 -0700469 // As we are using Name Prefix Hash Table, and the current LPM() is
470 // implemented as starting from full name, and reduce the number of
471 // components by 1 each time, we could use it here.
472 // For trie-like design, it could be more efficient by walking down the
473 // trie from the root node.
HYuana9b85752014-02-26 02:32:30 -0600474
Junxiao Shi4370fde2016-02-24 12:20:46 -0700475 shared_ptr<name_tree::Entry> entry = findLongestPrefixMatch(prefix, entrySelector);
HYuana9b85752014-02-26 02:32:30 -0600476
Junxiao Shi4370fde2016-02-24 12:20:46 -0700477 if (static_cast<bool>(entry)) {
478 const_iterator begin(FIND_ALL_MATCHES_TYPE, *this, entry, entrySelector);
479 return {begin, end()};
480 }
481 // If none of the entry satisfies the requirements, then return the end() iterator.
482 return {end(), end()};
HYuana9b85752014-02-26 02:32:30 -0600483}
484
Junxiao Shi5ccd0c22014-12-02 23:54:42 -0700485boost::iterator_range<NameTree::const_iterator>
Haowei Yuane1079fc2014-03-08 14:41:25 -0600486NameTree::fullEnumerate(const name_tree::EntrySelector& entrySelector) const
HYuana9b85752014-02-26 02:32:30 -0600487{
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700488 NFD_LOG_TRACE("fullEnumerate");
HYuana9b85752014-02-26 02:32:30 -0600489
Haowei Yuane1079fc2014-03-08 14:41:25 -0600490 // find the first eligible entry
Junxiao Shi60607c72014-11-26 22:40:36 -0700491 for (size_t i = 0; i < m_nBuckets; i++) {
492 for (name_tree::Node* node = m_buckets[i]; node != 0; node = node->m_next) {
493 if (static_cast<bool>(node->m_entry) && entrySelector(*node->m_entry)) {
494 const_iterator it(FULL_ENUMERATE_TYPE, *this, node->m_entry, entrySelector);
495 return {it, end()};
496 }
Haowei Yuane1079fc2014-03-08 14:41:25 -0600497 }
Junxiao Shi60607c72014-11-26 22:40:36 -0700498 }
Haowei Yuane1079fc2014-03-08 14:41:25 -0600499
500 // If none of the entry satisfies the requirements, then return the end() iterator.
Junxiao Shi60607c72014-11-26 22:40:36 -0700501 return {end(), end()};
Haowei Yuane1079fc2014-03-08 14:41:25 -0600502}
503
Junxiao Shi5ccd0c22014-12-02 23:54:42 -0700504boost::iterator_range<NameTree::const_iterator>
Haowei Yuane1079fc2014-03-08 14:41:25 -0600505NameTree::partialEnumerate(const Name& prefix,
506 const name_tree::EntrySubTreeSelector& entrySubTreeSelector) const
507{
508 // the first step is to process the root node
509 shared_ptr<name_tree::Entry> entry = findExactMatch(prefix);
Junxiao Shi60607c72014-11-26 22:40:36 -0700510 if (!static_cast<bool>(entry)) {
511 return {end(), end()};
512 }
Haowei Yuane1079fc2014-03-08 14:41:25 -0600513
514 std::pair<bool, bool>result = entrySubTreeSelector(*entry);
515 const_iterator it(PARTIAL_ENUMERATE_TYPE,
516 *this,
517 entry,
518 name_tree::AnyEntry(),
519 entrySubTreeSelector);
520
521 it.m_shouldVisitChildren = (result.second && entry->hasChildren());
522
Junxiao Shi60607c72014-11-26 22:40:36 -0700523 if (result.first) {
524 // root node is acceptable
525 }
526 else {
527 // let the ++ operator handle it
528 ++it;
529 }
530 return {it, end()};
HYuana9b85752014-02-26 02:32:30 -0600531}
532
HYuana9b85752014-02-26 02:32:30 -0600533// Hash Table Resize
534void
535NameTree::resize(size_t newNBuckets)
536{
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700537 NFD_LOG_TRACE("resize");
HYuana9b85752014-02-26 02:32:30 -0600538
539 name_tree::Node** newBuckets = new name_tree::Node*[newNBuckets];
Junxiao Shi40631842014-03-01 13:52:37 -0700540 size_t count = 0;
HYuana9b85752014-02-26 02:32:30 -0600541
542 // referenced ccnx hashtb.c hashtb_rehash()
543 name_tree::Node** pp = 0;
544 name_tree::Node* p = 0;
545 name_tree::Node* pre = 0;
546 name_tree::Node* q = 0; // record p->m_next
Junxiao Shi40631842014-03-01 13:52:37 -0700547 size_t i;
HYuana9b85752014-02-26 02:32:30 -0600548 uint32_t h;
549 uint32_t b;
550
551 for (i = 0; i < newNBuckets; i++)
552 {
553 newBuckets[i] = 0;
554 }
555
556 for (i = 0; i < m_nBuckets; i++)
557 {
558 for (p = m_buckets[i]; p != 0; p = q)
559 {
560 count++;
561 q = p->m_next;
562 BOOST_ASSERT(static_cast<bool>(p->m_entry));
563 h = p->m_entry->m_hash;
564 b = h % newNBuckets;
Haowei Yuan694bfb62014-04-01 14:44:11 -0500565 pre = 0;
HYuana9b85752014-02-26 02:32:30 -0600566 for (pp = &newBuckets[b]; *pp != 0; pp = &((*pp)->m_next))
567 {
568 pre = *pp;
569 continue;
570 }
571 p->m_prev = pre;
572 p->m_next = *pp; // Actually *pp always == 0 in this case
573 *pp = p;
574 }
575 }
576
577 BOOST_ASSERT(count == m_nItems);
578
579 name_tree::Node** oldBuckets = m_buckets;
580 m_buckets = newBuckets;
Haowei Yuanf52dac72014-03-24 23:35:03 -0500581 delete [] oldBuckets;
HYuana9b85752014-02-26 02:32:30 -0600582
583 m_nBuckets = newNBuckets;
Haowei Yuanf52dac72014-03-24 23:35:03 -0500584
585 m_enlargeThreshold = static_cast<size_t>(m_enlargeLoadFactor *
586 static_cast<double>(m_nBuckets));
587 m_shrinkThreshold = static_cast<size_t>(m_shrinkLoadFactor *
588 static_cast<double>(m_nBuckets));
HYuana9b85752014-02-26 02:32:30 -0600589}
590
591// For debugging
592void
Haowei Yuane1079fc2014-03-08 14:41:25 -0600593NameTree::dump(std::ostream& output) const
HYuana9b85752014-02-26 02:32:30 -0600594{
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700595 NFD_LOG_TRACE("dump()");
HYuana9b85752014-02-26 02:32:30 -0600596
597 name_tree::Node* node = 0;
598 shared_ptr<name_tree::Entry> entry;
599
600 using std::endl;
601
602 for (size_t i = 0; i < m_nBuckets; i++)
603 {
604 for (node = m_buckets[i]; node != 0; node = node->m_next)
605 {
606 entry = node->m_entry;
607
608 // if the Entry exist, dump its information
609 if (static_cast<bool>(entry))
610 {
611 output << "Bucket" << i << "\t" << entry->m_prefix.toUri() << endl;
612 output << "\t\tHash " << entry->m_hash << endl;
613
614 if (static_cast<bool>(entry->m_parent))
615 {
616 output << "\t\tparent->" << entry->m_parent->m_prefix.toUri();
617 }
618 else
619 {
620 output << "\t\tROOT";
621 }
622 output << endl;
623
624 if (entry->m_children.size() != 0)
625 {
626 output << "\t\tchildren = " << entry->m_children.size() << endl;
627
628 for (size_t j = 0; j < entry->m_children.size(); j++)
629 {
630 output << "\t\t\tChild " << j << " " <<
631 entry->m_children[j]->getPrefix() << endl;
632 }
633 }
634
635 } // if (static_cast<bool>(entry))
636
637 } // for node
638 } // for int i
639
640 output << "Bucket count = " << m_nBuckets << endl;
641 output << "Stored item = " << m_nItems << endl;
642 output << "--------------------------\n";
643}
644
Alexander Afanasyev09fc3d92015-01-03 02:02:37 -0800645NameTree::const_iterator::const_iterator()
646 : m_nameTree(nullptr)
647{
648}
649
Haowei Yuane1079fc2014-03-08 14:41:25 -0600650NameTree::const_iterator::const_iterator(NameTree::IteratorType type,
651 const NameTree& nameTree,
652 shared_ptr<name_tree::Entry> entry,
653 const name_tree::EntrySelector& entrySelector,
654 const name_tree::EntrySubTreeSelector& entrySubTreeSelector)
Alexander Afanasyev09fc3d92015-01-03 02:02:37 -0800655 : m_nameTree(&nameTree)
Haowei Yuane1079fc2014-03-08 14:41:25 -0600656 , m_entry(entry)
657 , m_subTreeRoot(entry)
658 , m_entrySelector(make_shared<name_tree::EntrySelector>(entrySelector))
659 , m_entrySubTreeSelector(make_shared<name_tree::EntrySubTreeSelector>(entrySubTreeSelector))
660 , m_type(type)
661 , m_shouldVisitChildren(true)
662{
663}
664
665// operator++()
666NameTree::const_iterator
667NameTree::const_iterator::operator++()
668{
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700669 NFD_LOG_TRACE("const_iterator::operator++()");
Haowei Yuane1079fc2014-03-08 14:41:25 -0600670
Alexander Afanasyev09fc3d92015-01-03 02:02:37 -0800671 BOOST_ASSERT(m_entry != m_nameTree->m_end);
Haowei Yuane1079fc2014-03-08 14:41:25 -0600672
673 if (m_type == FULL_ENUMERATE_TYPE) // fullEnumerate
674 {
Haowei Yuane1079fc2014-03-08 14:41:25 -0600675 // process the entries in the same bucket first
676 while (m_entry->m_node->m_next != 0)
677 {
678 m_entry = m_entry->m_node->m_next->m_entry;
679 if ((*m_entrySelector)(*m_entry))
680 {
Haowei Yuane1079fc2014-03-08 14:41:25 -0600681 return *this;
682 }
683 }
684
685 // process other buckets
Junxiao Shiefceadc2014-03-09 18:52:57 -0700686
Alexander Afanasyev09fc3d92015-01-03 02:02:37 -0800687 for (int newLocation = m_entry->m_hash % m_nameTree->m_nBuckets + 1;
688 newLocation < static_cast<int>(m_nameTree->m_nBuckets);
Junxiao Shiefceadc2014-03-09 18:52:57 -0700689 ++newLocation)
Haowei Yuane1079fc2014-03-08 14:41:25 -0600690 {
691 // process each bucket
Alexander Afanasyev09fc3d92015-01-03 02:02:37 -0800692 name_tree::Node* node = m_nameTree->m_buckets[newLocation];
Haowei Yuane1079fc2014-03-08 14:41:25 -0600693 while (node != 0)
694 {
695 m_entry = node->m_entry;
696 if ((*m_entrySelector)(*m_entry))
697 {
Haowei Yuane1079fc2014-03-08 14:41:25 -0600698 return *this;
699 }
700 node = node->m_next;
701 }
702 }
hwyuan80829932015-07-11 22:59:13 -0500703
704 // Reach the end()
Alexander Afanasyev09fc3d92015-01-03 02:02:37 -0800705 m_entry = m_nameTree->m_end;
Haowei Yuane1079fc2014-03-08 14:41:25 -0600706 return *this;
707 }
708
709 if (m_type == PARTIAL_ENUMERATE_TYPE) // partialEnumerate
710 {
711 // We use pre-order traversal.
712 // if at the root, it could have already been accepted, or this
713 // iterator was just declared, and root doesn't satisfy the
714 // requirement
715 // The if() section handles this special case
716 // Essentially, we need to check root's fist child, and the rest will
717 // be the same as normal process
718 if (m_entry == m_subTreeRoot)
719 {
720 if (m_shouldVisitChildren)
721 {
722 m_entry = m_entry->getChildren()[0];
723 std::pair<bool, bool> result = ((*m_entrySubTreeSelector)(*m_entry));
724 m_shouldVisitChildren = (result.second && m_entry->hasChildren());
725 if(result.first)
726 {
727 return *this;
728 }
729 else
730 {
731 // the first child did not meet the requirement
732 // the rest of the process can just fall through the while loop
733 // as normal
734 }
735 }
736 else
737 {
738 // no children, should return end();
739 // just fall through
740 }
741 }
742
743 // The first thing to do is to visit its child, or go to find its possible
744 // siblings
745 while (m_entry != m_subTreeRoot)
746 {
747 if (m_shouldVisitChildren)
748 {
749 // If this subtree should be visited
750 m_entry = m_entry->getChildren()[0];
751 std::pair<bool, bool> result = ((*m_entrySubTreeSelector)(*m_entry));
752 m_shouldVisitChildren = (result.second && m_entry->hasChildren());
753 if (result.first) // if this node is acceptable
754 {
755 return *this;
756 }
757 else
758 {
759 // do nothing, as this node is essentially ignored
760 // send this node to the while loop.
761 }
762 }
763 else
764 {
765 // Should try to find its sibling
766 shared_ptr<name_tree::Entry> parent = m_entry->getParent();
767
768 std::vector<shared_ptr<name_tree::Entry> >& parentChildrenList = parent->getChildren();
769 bool isFound = false;
770 size_t i = 0;
771 for (i = 0; i < parentChildrenList.size(); i++)
772 {
773 if (parentChildrenList[i] == m_entry)
774 {
775 isFound = true;
776 break;
777 }
778 }
779
Junxiao Shiac7b4372014-12-13 21:47:04 -0700780 BOOST_VERIFY(isFound == true);
Haowei Yuane1079fc2014-03-08 14:41:25 -0600781 if (i < parentChildrenList.size() - 1) // m_entry not the last child
782 {
783 m_entry = parentChildrenList[i + 1];
784 std::pair<bool, bool> result = ((*m_entrySubTreeSelector)(*m_entry));
785 m_shouldVisitChildren = (result.second && m_entry->hasChildren());
786 if (result.first) // if this node is acceptable
787 {
788 return *this;
789 }
790 else
791 {
792 // do nothing, as this node is essentially ignored
793 // send this node to the while loop.
794 }
795 }
796 else
797 {
798 // m_entry is the last child, no more sibling, should try to find parent's sibling
799 m_shouldVisitChildren = false;
800 m_entry = parent;
801 }
802 }
803 }
804
Alexander Afanasyev09fc3d92015-01-03 02:02:37 -0800805 m_entry = m_nameTree->m_end;
Haowei Yuane1079fc2014-03-08 14:41:25 -0600806 return *this;
807 }
808
809 if (m_type == FIND_ALL_MATCHES_TYPE) // findAllMatches
810 {
811 // Assumption: at the beginning, m_entry was initialized with the first
812 // eligible Name Tree entry (i.e., has a PIT entry that can be satisfied
813 // by the Data packet)
814
815 while (static_cast<bool>(m_entry->getParent()))
816 {
817 m_entry = m_entry->getParent();
818 if ((*m_entrySelector)(*m_entry))
819 return *this;
820 }
821
822 // Reach to the end (Root)
Alexander Afanasyev09fc3d92015-01-03 02:02:37 -0800823 m_entry = m_nameTree->m_end;
Haowei Yuane1079fc2014-03-08 14:41:25 -0600824 return *this;
825 }
Junxiao Shiefceadc2014-03-09 18:52:57 -0700826
827 BOOST_ASSERT(false); // unknown type
828 return *this;
Haowei Yuane1079fc2014-03-08 14:41:25 -0600829}
830
HYuana9b85752014-02-26 02:32:30 -0600831} // namespace nfd