blob: 3ac469db61ff03017f49a0bf5120f275c00cb1cf [file] [log] [blame]
HYuana9b85752014-02-26 02:32:30 -06001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
Junxiao Shi2b73ca32014-11-17 19:16:08 -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 * 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
Haowei Yuanf52dac72014-03-24 23:35:03 -050071typedef boost::mpl::if_c<sizeof(size_t) >= 8, Hash64, Hash32>::type CityHash;
72
73// Interface of different hash functions
74size_t
75computeHash(const Name& prefix)
76{
77 prefix.wireEncode(); // guarantees prefix's wire buffer is not empty
78
79 size_t hashValue = 0;
80 size_t hashUpdate = 0;
81
82 for (Name::const_iterator it = prefix.begin(); it != prefix.end(); it++)
83 {
84 const char* wireFormat = reinterpret_cast<const char*>( it->wire() );
85 hashUpdate = CityHash::compute(wireFormat, it->size());
86 hashValue ^= hashUpdate;
87 }
88
89 return hashValue;
90}
91
92std::vector<size_t>
93computeHashSet(const Name& prefix)
94{
95 prefix.wireEncode(); // guarantees prefix's wire buffer is not empty
96
97 size_t hashValue = 0;
98 size_t hashUpdate = 0;
99
100 std::vector<size_t> hashValueSet;
101 hashValueSet.push_back(hashValue);
102
103 for (Name::const_iterator it = prefix.begin(); it != prefix.end(); it++)
104 {
105 const char* wireFormat = reinterpret_cast<const char*>( it->wire() );
106 hashUpdate = CityHash::compute(wireFormat, it->size());
107 hashValue ^= hashUpdate;
108 hashValueSet.push_back(hashValue);
109 }
110
111 return hashValueSet;
HYuana9b85752014-02-26 02:32:30 -0600112}
113
114} // namespace name_tree
115
116NameTree::NameTree(size_t nBuckets)
117 : m_nItems(0)
118 , m_nBuckets(nBuckets)
Haowei Yuanf52dac72014-03-24 23:35:03 -0500119 , m_minNBuckets(nBuckets)
120 , m_enlargeLoadFactor(0.5) // more than 50% buckets loaded
121 , m_enlargeFactor(2) // double the hash table size
122 , m_shrinkLoadFactor(0.1) // less than 10% buckets loaded
123 , m_shrinkFactor(0.5) // reduce the number of buckets by half
Haowei Yuane1079fc2014-03-08 14:41:25 -0600124 , m_endIterator(FULL_ENUMERATE_TYPE, *this, m_end)
HYuana9b85752014-02-26 02:32:30 -0600125{
Haowei Yuanf52dac72014-03-24 23:35:03 -0500126 m_enlargeThreshold = static_cast<size_t>(m_enlargeLoadFactor *
127 static_cast<double>(m_nBuckets));
128
129 m_shrinkThreshold = static_cast<size_t>(m_shrinkLoadFactor *
HYuana9b85752014-02-26 02:32:30 -0600130 static_cast<double>(m_nBuckets));
131
132 // array of node pointers
133 m_buckets = new name_tree::Node*[m_nBuckets];
134 // Initialize the pointer array
135 for (size_t i = 0; i < m_nBuckets; i++)
136 m_buckets[i] = 0;
137}
138
139NameTree::~NameTree()
140{
141 for (size_t i = 0; i < m_nBuckets; i++)
142 {
Haowei Yuanf52dac72014-03-24 23:35:03 -0500143 if (m_buckets[i] != 0) {
HYuana9b85752014-02-26 02:32:30 -0600144 delete m_buckets[i];
Haowei Yuanf52dac72014-03-24 23:35:03 -0500145 }
HYuana9b85752014-02-26 02:32:30 -0600146 }
147
148 delete [] m_buckets;
149}
150
151// insert() is a private function, and called by only lookup()
152std::pair<shared_ptr<name_tree::Entry>, bool>
153NameTree::insert(const Name& prefix)
154{
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700155 NFD_LOG_TRACE("insert " << prefix);
HYuana9b85752014-02-26 02:32:30 -0600156
Haowei Yuanf52dac72014-03-24 23:35:03 -0500157 size_t hashValue = name_tree::computeHash(prefix);
158 size_t loc = hashValue % m_nBuckets;
HYuana9b85752014-02-26 02:32:30 -0600159
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700160 NFD_LOG_TRACE("Name " << prefix << " hash value = " << hashValue << " location = " << loc);
HYuana9b85752014-02-26 02:32:30 -0600161
162 // Check if this Name has been stored
163 name_tree::Node* node = m_buckets[loc];
164 name_tree::Node* nodePrev = node; // initialize nodePrev to node
165
166 for (node = m_buckets[loc]; node != 0; node = node->m_next)
167 {
168 if (static_cast<bool>(node->m_entry))
169 {
170 if (prefix == node->m_entry->m_prefix)
171 {
172 return std::make_pair(node->m_entry, false); // false: old entry
173 }
174 }
175 nodePrev = node;
176 }
177
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700178 NFD_LOG_TRACE("Did not find " << prefix << ", need to insert it to the table");
HYuana9b85752014-02-26 02:32:30 -0600179
180 // If no bucket is empty occupied, we need to create a new node, and it is
181 // linked from nodePrev
182 node = new name_tree::Node();
183 node->m_prev = nodePrev;
184
185 if (nodePrev == 0)
186 {
187 m_buckets[loc] = node;
188 }
189 else
190 {
191 nodePrev->m_next = node;
192 }
193
194 // Create a new Entry
195 shared_ptr<name_tree::Entry> entry(make_shared<name_tree::Entry>(prefix));
196 entry->setHash(hashValue);
197 node->m_entry = entry; // link the Entry to its Node
198 entry->m_node = node; // link the node to Entry. Used in eraseEntryIfEmpty.
199
200 return std::make_pair(entry, true); // true: new entry
201}
202
203// Name Prefix Lookup. Create Name Tree Entry if not found
204shared_ptr<name_tree::Entry>
205NameTree::lookup(const Name& prefix)
206{
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700207 NFD_LOG_TRACE("lookup " << prefix);
HYuana9b85752014-02-26 02:32:30 -0600208
209 shared_ptr<name_tree::Entry> entry;
210 shared_ptr<name_tree::Entry> parent;
211
212 for (size_t i = 0; i <= prefix.size(); i++)
213 {
214 Name temp = prefix.getPrefix(i);
215
216 // insert() will create the entry if it does not exist.
217 std::pair<shared_ptr<name_tree::Entry>, bool> ret = insert(temp);
218 entry = ret.first;
219
220 if (ret.second == true)
221 {
Haowei Yuanf52dac72014-03-24 23:35:03 -0500222 m_nItems++; // Increase the counter
HYuana9b85752014-02-26 02:32:30 -0600223 entry->m_parent = parent;
224
225 if (static_cast<bool>(parent))
226 {
227 parent->m_children.push_back(entry);
228 }
229 }
230
Haowei Yuanf52dac72014-03-24 23:35:03 -0500231 if (m_nItems > m_enlargeThreshold)
HYuana9b85752014-02-26 02:32:30 -0600232 {
Haowei Yuanf52dac72014-03-24 23:35:03 -0500233 resize(m_enlargeFactor * m_nBuckets);
HYuana9b85752014-02-26 02:32:30 -0600234 }
235
236 parent = entry;
237 }
238 return entry;
239}
240
241// Exact Match
242shared_ptr<name_tree::Entry>
243NameTree::findExactMatch(const Name& prefix) const
244{
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700245 NFD_LOG_TRACE("findExactMatch " << prefix);
HYuana9b85752014-02-26 02:32:30 -0600246
Haowei Yuanf52dac72014-03-24 23:35:03 -0500247 size_t hashValue = name_tree::computeHash(prefix);
248 size_t loc = hashValue % m_nBuckets;
HYuana9b85752014-02-26 02:32:30 -0600249
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700250 NFD_LOG_TRACE("Name " << prefix << " hash value = " << hashValue <<
HYuana9b85752014-02-26 02:32:30 -0600251 " location = " << loc);
252
253 shared_ptr<name_tree::Entry> entry;
254 name_tree::Node* node = 0;
255
256 for (node = m_buckets[loc]; node != 0; node = node->m_next)
257 {
258 entry = node->m_entry;
259 if (static_cast<bool>(entry))
260 {
261 if (hashValue == entry->getHash() && prefix == entry->getPrefix())
262 {
263 return entry;
264 }
265 } // if entry
266 } // for node
267
268 // if not found, the default value of entry (null pointer) will be returned
269 entry.reset();
270 return entry;
271}
272
273// Longest Prefix Match
HYuana9b85752014-02-26 02:32:30 -0600274shared_ptr<name_tree::Entry>
Haowei Yuane1079fc2014-03-08 14:41:25 -0600275NameTree::findLongestPrefixMatch(const Name& prefix, const name_tree::EntrySelector& entrySelector) const
HYuana9b85752014-02-26 02:32:30 -0600276{
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700277 NFD_LOG_TRACE("findLongestPrefixMatch " << prefix);
HYuana9b85752014-02-26 02:32:30 -0600278
279 shared_ptr<name_tree::Entry> entry;
Haowei Yuanf52dac72014-03-24 23:35:03 -0500280 std::vector<size_t> hashValueSet = name_tree::computeHashSet(prefix);
HYuana9b85752014-02-26 02:32:30 -0600281
Haowei Yuanf52dac72014-03-24 23:35:03 -0500282 size_t hashValue = 0;
283 size_t loc = 0;
284
285 for (int i = static_cast<int>(prefix.size()); i >= 0; i--)
HYuana9b85752014-02-26 02:32:30 -0600286 {
Haowei Yuanf52dac72014-03-24 23:35:03 -0500287 hashValue = hashValueSet[i];
288 loc = hashValue % m_nBuckets;
289
290 name_tree::Node* node = 0;
291 for (node = m_buckets[loc]; node != 0; node = node->m_next)
292 {
293 entry = node->m_entry;
294 if (static_cast<bool>(entry))
295 {
296 // isPrefixOf() is used to avoid making a copy of the name
297 if (hashValue == entry->getHash() &&
298 entry->getPrefix().isPrefixOf(prefix) &&
299 entrySelector(*entry))
300 {
301 return entry;
302 }
303 } // if entry
304 } // for node
HYuana9b85752014-02-26 02:32:30 -0600305 }
306
Haowei Yuanf52dac72014-03-24 23:35:03 -0500307 // if not found, the default value of entry (null pointer) will be returned
308 entry.reset();
309 return entry;
HYuana9b85752014-02-26 02:32:30 -0600310}
311
HangZhangcb4fc832014-03-11 16:57:11 +0800312shared_ptr<name_tree::Entry>
313NameTree::findLongestPrefixMatch(shared_ptr<name_tree::Entry> entry,
314 const name_tree::EntrySelector& entrySelector) const
315{
316 while (static_cast<bool>(entry))
317 {
318 if (entrySelector(*entry))
319 return entry;
320 entry = entry->getParent();
321 }
322 return shared_ptr<name_tree::Entry>();
323}
324
HYuana9b85752014-02-26 02:32:30 -0600325// return {false: this entry is not empty, true: this entry is empty and erased}
326bool
327NameTree::eraseEntryIfEmpty(shared_ptr<name_tree::Entry> entry)
328{
329 BOOST_ASSERT(static_cast<bool>(entry));
330
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700331 NFD_LOG_TRACE("eraseEntryIfEmpty " << entry->getPrefix());
HYuana9b85752014-02-26 02:32:30 -0600332
333 // first check if this Entry can be erased
Junxiao Shi40631842014-03-01 13:52:37 -0700334 if (entry->isEmpty())
HYuana9b85752014-02-26 02:32:30 -0600335 {
336 // update child-related info in the parent
337 shared_ptr<name_tree::Entry> parent = entry->getParent();
338
339 if (static_cast<bool>(parent))
340 {
341 std::vector<shared_ptr<name_tree::Entry> >& parentChildrenList =
342 parent->getChildren();
343
344 bool isFound = false;
345 size_t size = parentChildrenList.size();
346 for (size_t i = 0; i < size; i++)
347 {
348 if (parentChildrenList[i] == entry)
349 {
350 parentChildrenList[i] = parentChildrenList[size - 1];
351 parentChildrenList.pop_back();
352 isFound = true;
353 break;
354 }
355 }
356
Junxiao Shiac7b4372014-12-13 21:47:04 -0700357 BOOST_VERIFY(isFound == true);
HYuana9b85752014-02-26 02:32:30 -0600358 }
359
360 // remove this Entry and its Name Tree Node
361 name_tree::Node* node = entry->m_node;
362 name_tree::Node* nodePrev = node->m_prev;
363
364 // configure the previous node
365 if (nodePrev != 0)
366 {
367 // link the previous node to the next node
368 nodePrev->m_next = node->m_next;
369 }
370 else
371 {
372 m_buckets[entry->getHash() % m_nBuckets] = node->m_next;
373 }
374
375 // link the previous node with the next node (skip the erased one)
376 if (node->m_next != 0)
377 {
378 node->m_next->m_prev = nodePrev;
379 node->m_next = 0;
380 }
381
382 BOOST_ASSERT(node->m_next == 0);
383
384 m_nItems--;
385 delete node;
386
387 if (static_cast<bool>(parent))
388 eraseEntryIfEmpty(parent);
389
Haowei Yuanf52dac72014-03-24 23:35:03 -0500390 size_t newNBuckets = static_cast<size_t>(m_shrinkFactor *
391 static_cast<double>(m_nBuckets));
392
393 if (newNBuckets >= m_minNBuckets && m_nItems < m_shrinkThreshold)
394 {
395 resize(newNBuckets);
396 }
397
HYuana9b85752014-02-26 02:32:30 -0600398 return true;
399
400 } // if this entry is empty
401
402 return false; // if this entry is not empty
403}
404
Junxiao Shi5ccd0c22014-12-02 23:54:42 -0700405boost::iterator_range<NameTree::const_iterator>
Haowei Yuane1079fc2014-03-08 14:41:25 -0600406NameTree::fullEnumerate(const name_tree::EntrySelector& entrySelector) const
HYuana9b85752014-02-26 02:32:30 -0600407{
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700408 NFD_LOG_TRACE("fullEnumerate");
HYuana9b85752014-02-26 02:32:30 -0600409
Haowei Yuane1079fc2014-03-08 14:41:25 -0600410 // find the first eligible entry
Junxiao Shi60607c72014-11-26 22:40:36 -0700411 for (size_t i = 0; i < m_nBuckets; i++) {
412 for (name_tree::Node* node = m_buckets[i]; node != 0; node = node->m_next) {
413 if (static_cast<bool>(node->m_entry) && entrySelector(*node->m_entry)) {
414 const_iterator it(FULL_ENUMERATE_TYPE, *this, node->m_entry, entrySelector);
415 return {it, end()};
416 }
Haowei Yuane1079fc2014-03-08 14:41:25 -0600417 }
Junxiao Shi60607c72014-11-26 22:40:36 -0700418 }
Haowei Yuane1079fc2014-03-08 14:41:25 -0600419
420 // If none of the entry satisfies the requirements, then return the end() iterator.
Junxiao Shi60607c72014-11-26 22:40:36 -0700421 return {end(), end()};
Haowei Yuane1079fc2014-03-08 14:41:25 -0600422}
423
Junxiao Shi5ccd0c22014-12-02 23:54:42 -0700424boost::iterator_range<NameTree::const_iterator>
Haowei Yuane1079fc2014-03-08 14:41:25 -0600425NameTree::partialEnumerate(const Name& prefix,
426 const name_tree::EntrySubTreeSelector& entrySubTreeSelector) const
427{
428 // the first step is to process the root node
429 shared_ptr<name_tree::Entry> entry = findExactMatch(prefix);
Junxiao Shi60607c72014-11-26 22:40:36 -0700430 if (!static_cast<bool>(entry)) {
431 return {end(), end()};
432 }
Haowei Yuane1079fc2014-03-08 14:41:25 -0600433
434 std::pair<bool, bool>result = entrySubTreeSelector(*entry);
435 const_iterator it(PARTIAL_ENUMERATE_TYPE,
436 *this,
437 entry,
438 name_tree::AnyEntry(),
439 entrySubTreeSelector);
440
441 it.m_shouldVisitChildren = (result.second && entry->hasChildren());
442
Junxiao Shi60607c72014-11-26 22:40:36 -0700443 if (result.first) {
444 // root node is acceptable
445 }
446 else {
447 // let the ++ operator handle it
448 ++it;
449 }
450 return {it, end()};
HYuana9b85752014-02-26 02:32:30 -0600451}
452
Junxiao Shi5ccd0c22014-12-02 23:54:42 -0700453boost::iterator_range<NameTree::const_iterator>
Haowei Yuane1079fc2014-03-08 14:41:25 -0600454NameTree::findAllMatches(const Name& prefix,
455 const name_tree::EntrySelector& entrySelector) const
HYuana9b85752014-02-26 02:32:30 -0600456{
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700457 NFD_LOG_TRACE("NameTree::findAllMatches" << prefix);
HYuana9b85752014-02-26 02:32:30 -0600458
Haowei Yuane1079fc2014-03-08 14:41:25 -0600459 // As we are using Name Prefix Hash Table, and the current LPM() is
460 // implemented as starting from full name, and reduce the number of
461 // components by 1 each time, we could use it here.
462 // For trie-like design, it could be more efficient by walking down the
463 // trie from the root node.
HYuana9b85752014-02-26 02:32:30 -0600464
Haowei Yuane1079fc2014-03-08 14:41:25 -0600465 shared_ptr<name_tree::Entry> entry = findLongestPrefixMatch(prefix, entrySelector);
HYuana9b85752014-02-26 02:32:30 -0600466
Junxiao Shi2b73ca32014-11-17 19:16:08 -0700467 if (static_cast<bool>(entry)) {
468 const_iterator begin(FIND_ALL_MATCHES_TYPE, *this, entry, entrySelector);
Junxiao Shi60607c72014-11-26 22:40:36 -0700469 return {begin, end()};
Junxiao Shi2b73ca32014-11-17 19:16:08 -0700470 }
Haowei Yuane1079fc2014-03-08 14:41:25 -0600471 // If none of the entry satisfies the requirements, then return the end() iterator.
Junxiao Shi60607c72014-11-26 22:40:36 -0700472 return {end(), end()};
HYuana9b85752014-02-26 02:32:30 -0600473}
474
475// Hash Table Resize
476void
477NameTree::resize(size_t newNBuckets)
478{
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700479 NFD_LOG_TRACE("resize");
HYuana9b85752014-02-26 02:32:30 -0600480
481 name_tree::Node** newBuckets = new name_tree::Node*[newNBuckets];
Junxiao Shi40631842014-03-01 13:52:37 -0700482 size_t count = 0;
HYuana9b85752014-02-26 02:32:30 -0600483
484 // referenced ccnx hashtb.c hashtb_rehash()
485 name_tree::Node** pp = 0;
486 name_tree::Node* p = 0;
487 name_tree::Node* pre = 0;
488 name_tree::Node* q = 0; // record p->m_next
Junxiao Shi40631842014-03-01 13:52:37 -0700489 size_t i;
HYuana9b85752014-02-26 02:32:30 -0600490 uint32_t h;
491 uint32_t b;
492
493 for (i = 0; i < newNBuckets; i++)
494 {
495 newBuckets[i] = 0;
496 }
497
498 for (i = 0; i < m_nBuckets; i++)
499 {
500 for (p = m_buckets[i]; p != 0; p = q)
501 {
502 count++;
503 q = p->m_next;
504 BOOST_ASSERT(static_cast<bool>(p->m_entry));
505 h = p->m_entry->m_hash;
506 b = h % newNBuckets;
Haowei Yuan694bfb62014-04-01 14:44:11 -0500507 pre = 0;
HYuana9b85752014-02-26 02:32:30 -0600508 for (pp = &newBuckets[b]; *pp != 0; pp = &((*pp)->m_next))
509 {
510 pre = *pp;
511 continue;
512 }
513 p->m_prev = pre;
514 p->m_next = *pp; // Actually *pp always == 0 in this case
515 *pp = p;
516 }
517 }
518
519 BOOST_ASSERT(count == m_nItems);
520
521 name_tree::Node** oldBuckets = m_buckets;
522 m_buckets = newBuckets;
Haowei Yuanf52dac72014-03-24 23:35:03 -0500523 delete [] oldBuckets;
HYuana9b85752014-02-26 02:32:30 -0600524
525 m_nBuckets = newNBuckets;
Haowei Yuanf52dac72014-03-24 23:35:03 -0500526
527 m_enlargeThreshold = static_cast<size_t>(m_enlargeLoadFactor *
528 static_cast<double>(m_nBuckets));
529 m_shrinkThreshold = static_cast<size_t>(m_shrinkLoadFactor *
530 static_cast<double>(m_nBuckets));
HYuana9b85752014-02-26 02:32:30 -0600531}
532
533// For debugging
534void
Haowei Yuane1079fc2014-03-08 14:41:25 -0600535NameTree::dump(std::ostream& output) const
HYuana9b85752014-02-26 02:32:30 -0600536{
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700537 NFD_LOG_TRACE("dump()");
HYuana9b85752014-02-26 02:32:30 -0600538
539 name_tree::Node* node = 0;
540 shared_ptr<name_tree::Entry> entry;
541
542 using std::endl;
543
544 for (size_t i = 0; i < m_nBuckets; i++)
545 {
546 for (node = m_buckets[i]; node != 0; node = node->m_next)
547 {
548 entry = node->m_entry;
549
550 // if the Entry exist, dump its information
551 if (static_cast<bool>(entry))
552 {
553 output << "Bucket" << i << "\t" << entry->m_prefix.toUri() << endl;
554 output << "\t\tHash " << entry->m_hash << endl;
555
556 if (static_cast<bool>(entry->m_parent))
557 {
558 output << "\t\tparent->" << entry->m_parent->m_prefix.toUri();
559 }
560 else
561 {
562 output << "\t\tROOT";
563 }
564 output << endl;
565
566 if (entry->m_children.size() != 0)
567 {
568 output << "\t\tchildren = " << entry->m_children.size() << endl;
569
570 for (size_t j = 0; j < entry->m_children.size(); j++)
571 {
572 output << "\t\t\tChild " << j << " " <<
573 entry->m_children[j]->getPrefix() << endl;
574 }
575 }
576
577 } // if (static_cast<bool>(entry))
578
579 } // for node
580 } // for int i
581
582 output << "Bucket count = " << m_nBuckets << endl;
583 output << "Stored item = " << m_nItems << endl;
584 output << "--------------------------\n";
585}
586
Alexander Afanasyev09fc3d92015-01-03 02:02:37 -0800587NameTree::const_iterator::const_iterator()
588 : m_nameTree(nullptr)
589{
590}
591
Haowei Yuane1079fc2014-03-08 14:41:25 -0600592NameTree::const_iterator::const_iterator(NameTree::IteratorType type,
593 const NameTree& nameTree,
594 shared_ptr<name_tree::Entry> entry,
595 const name_tree::EntrySelector& entrySelector,
596 const name_tree::EntrySubTreeSelector& entrySubTreeSelector)
Alexander Afanasyev09fc3d92015-01-03 02:02:37 -0800597 : m_nameTree(&nameTree)
Haowei Yuane1079fc2014-03-08 14:41:25 -0600598 , m_entry(entry)
599 , m_subTreeRoot(entry)
600 , m_entrySelector(make_shared<name_tree::EntrySelector>(entrySelector))
601 , m_entrySubTreeSelector(make_shared<name_tree::EntrySubTreeSelector>(entrySubTreeSelector))
602 , m_type(type)
603 , m_shouldVisitChildren(true)
604{
605}
606
607// operator++()
608NameTree::const_iterator
609NameTree::const_iterator::operator++()
610{
Alexander Afanasyevbf9edee2014-03-31 23:05:27 -0700611 NFD_LOG_TRACE("const_iterator::operator++()");
Haowei Yuane1079fc2014-03-08 14:41:25 -0600612
Alexander Afanasyev09fc3d92015-01-03 02:02:37 -0800613 BOOST_ASSERT(m_entry != m_nameTree->m_end);
Haowei Yuane1079fc2014-03-08 14:41:25 -0600614
615 if (m_type == FULL_ENUMERATE_TYPE) // fullEnumerate
616 {
617 bool isFound = false;
618 // process the entries in the same bucket first
619 while (m_entry->m_node->m_next != 0)
620 {
621 m_entry = m_entry->m_node->m_next->m_entry;
622 if ((*m_entrySelector)(*m_entry))
623 {
624 isFound = true;
625 return *this;
626 }
627 }
628
629 // process other buckets
Junxiao Shiefceadc2014-03-09 18:52:57 -0700630
Alexander Afanasyev09fc3d92015-01-03 02:02:37 -0800631 for (int newLocation = m_entry->m_hash % m_nameTree->m_nBuckets + 1;
632 newLocation < static_cast<int>(m_nameTree->m_nBuckets);
Junxiao Shiefceadc2014-03-09 18:52:57 -0700633 ++newLocation)
Haowei Yuane1079fc2014-03-08 14:41:25 -0600634 {
635 // process each bucket
Alexander Afanasyev09fc3d92015-01-03 02:02:37 -0800636 name_tree::Node* node = m_nameTree->m_buckets[newLocation];
Haowei Yuane1079fc2014-03-08 14:41:25 -0600637 while (node != 0)
638 {
639 m_entry = node->m_entry;
640 if ((*m_entrySelector)(*m_entry))
641 {
642 isFound = true;
643 return *this;
644 }
645 node = node->m_next;
646 }
647 }
Junxiao Shiac7b4372014-12-13 21:47:04 -0700648 BOOST_VERIFY(isFound == false);
Haowei Yuane1079fc2014-03-08 14:41:25 -0600649 // Reach to the end()
Alexander Afanasyev09fc3d92015-01-03 02:02:37 -0800650 m_entry = m_nameTree->m_end;
Haowei Yuane1079fc2014-03-08 14:41:25 -0600651 return *this;
652 }
653
654 if (m_type == PARTIAL_ENUMERATE_TYPE) // partialEnumerate
655 {
656 // We use pre-order traversal.
657 // if at the root, it could have already been accepted, or this
658 // iterator was just declared, and root doesn't satisfy the
659 // requirement
660 // The if() section handles this special case
661 // Essentially, we need to check root's fist child, and the rest will
662 // be the same as normal process
663 if (m_entry == m_subTreeRoot)
664 {
665 if (m_shouldVisitChildren)
666 {
667 m_entry = m_entry->getChildren()[0];
668 std::pair<bool, bool> result = ((*m_entrySubTreeSelector)(*m_entry));
669 m_shouldVisitChildren = (result.second && m_entry->hasChildren());
670 if(result.first)
671 {
672 return *this;
673 }
674 else
675 {
676 // the first child did not meet the requirement
677 // the rest of the process can just fall through the while loop
678 // as normal
679 }
680 }
681 else
682 {
683 // no children, should return end();
684 // just fall through
685 }
686 }
687
688 // The first thing to do is to visit its child, or go to find its possible
689 // siblings
690 while (m_entry != m_subTreeRoot)
691 {
692 if (m_shouldVisitChildren)
693 {
694 // If this subtree should be visited
695 m_entry = m_entry->getChildren()[0];
696 std::pair<bool, bool> result = ((*m_entrySubTreeSelector)(*m_entry));
697 m_shouldVisitChildren = (result.second && m_entry->hasChildren());
698 if (result.first) // if this node is acceptable
699 {
700 return *this;
701 }
702 else
703 {
704 // do nothing, as this node is essentially ignored
705 // send this node to the while loop.
706 }
707 }
708 else
709 {
710 // Should try to find its sibling
711 shared_ptr<name_tree::Entry> parent = m_entry->getParent();
712
713 std::vector<shared_ptr<name_tree::Entry> >& parentChildrenList = parent->getChildren();
714 bool isFound = false;
715 size_t i = 0;
716 for (i = 0; i < parentChildrenList.size(); i++)
717 {
718 if (parentChildrenList[i] == m_entry)
719 {
720 isFound = true;
721 break;
722 }
723 }
724
Junxiao Shiac7b4372014-12-13 21:47:04 -0700725 BOOST_VERIFY(isFound == true);
Haowei Yuane1079fc2014-03-08 14:41:25 -0600726 if (i < parentChildrenList.size() - 1) // m_entry not the last child
727 {
728 m_entry = parentChildrenList[i + 1];
729 std::pair<bool, bool> result = ((*m_entrySubTreeSelector)(*m_entry));
730 m_shouldVisitChildren = (result.second && m_entry->hasChildren());
731 if (result.first) // if this node is acceptable
732 {
733 return *this;
734 }
735 else
736 {
737 // do nothing, as this node is essentially ignored
738 // send this node to the while loop.
739 }
740 }
741 else
742 {
743 // m_entry is the last child, no more sibling, should try to find parent's sibling
744 m_shouldVisitChildren = false;
745 m_entry = parent;
746 }
747 }
748 }
749
Alexander Afanasyev09fc3d92015-01-03 02:02:37 -0800750 m_entry = m_nameTree->m_end;
Haowei Yuane1079fc2014-03-08 14:41:25 -0600751 return *this;
752 }
753
754 if (m_type == FIND_ALL_MATCHES_TYPE) // findAllMatches
755 {
756 // Assumption: at the beginning, m_entry was initialized with the first
757 // eligible Name Tree entry (i.e., has a PIT entry that can be satisfied
758 // by the Data packet)
759
760 while (static_cast<bool>(m_entry->getParent()))
761 {
762 m_entry = m_entry->getParent();
763 if ((*m_entrySelector)(*m_entry))
764 return *this;
765 }
766
767 // Reach to the end (Root)
Alexander Afanasyev09fc3d92015-01-03 02:02:37 -0800768 m_entry = m_nameTree->m_end;
Haowei Yuane1079fc2014-03-08 14:41:25 -0600769 return *this;
770 }
Junxiao Shiefceadc2014-03-09 18:52:57 -0700771
772 BOOST_ASSERT(false); // unknown type
773 return *this;
Haowei Yuane1079fc2014-03-08 14:41:25 -0600774}
775
HYuana9b85752014-02-26 02:32:30 -0600776} // namespace nfd