table: NameTree enumeration
refs #1318
Change-Id: I26f25cefe8f2939ca884103f1b081c0c02325207
diff --git a/daemon/table/fib.cpp b/daemon/table/fib.cpp
index 32aabbf..eea7641 100644
--- a/daemon/table/fib.cpp
+++ b/daemon/table/fib.cpp
@@ -87,13 +87,12 @@
void
Fib::removeNextHopFromAllEntries(shared_ptr<Face> face)
{
- shared_ptr<std::vector<shared_ptr<name_tree::Entry > > > nameTreeEntries =
- m_nameTree.fullEnumerate(&predicate_NameTreeEntry_hasFibEntry);
- for (size_t i = 0; i < nameTreeEntries->size(); ++i) {
- shared_ptr<fib::Entry> entry = nameTreeEntries->at(i)->getFibEntry();
+ for (NameTree::const_iterator it =
+ m_nameTree.fullEnumerate(&predicate_NameTreeEntry_hasFibEntry); it != m_nameTree.end(); it++)
+ {
+ shared_ptr<fib::Entry> entry = it->getFibEntry();
entry->removeNextHop(face);
}
}
-
} // namespace nfd
diff --git a/daemon/table/name-tree-entry.hpp b/daemon/table/name-tree-entry.hpp
index 1708dbf..cca1908 100644
--- a/daemon/table/name-tree-entry.hpp
+++ b/daemon/table/name-tree-entry.hpp
@@ -21,12 +21,12 @@
namespace name_tree {
-// Forward declaration
+// Forward declarations
class Node;
class Entry;
/**
- * @brief Name Tree Node Class
+ * \brief Name Tree Node Class
*/
class Node
{
@@ -43,9 +43,9 @@
};
/**
- * @brief Name Tree Entry Class
+ * \brief Name Tree Entry Class
*/
-class Entry
+class Entry : noncopyable
{
// Make private members accessible by Name Tree
friend class nfd::NameTree;
@@ -72,7 +72,10 @@
std::vector<shared_ptr<Entry> >&
getChildren();
-
+
+ bool
+ hasChildren() const;
+
bool
isEmpty() const;
@@ -88,12 +91,15 @@
void
insertPitEntry(shared_ptr<pit::Entry> pit);
+ bool
+ hasPitEntries() const;
+
std::vector<shared_ptr<pit::Entry> >&
getPitEntries();
/**
- * @brief Erase a PIT Entry
- * @details The address of this PIT Entry is required
+ * \brief Erase a PIT Entry
+ * \details The address of this PIT Entry is required
*/
bool
erasePitEntry(shared_ptr<pit::Entry> pit);
@@ -152,6 +158,12 @@
}
inline bool
+Entry::hasChildren() const
+{
+ return !m_children.empty();
+}
+
+inline bool
Entry::isEmpty() const
{
return m_children.empty() &&
@@ -166,6 +178,12 @@
return m_fibEntry;
}
+inline bool
+Entry::hasPitEntries() const
+{
+ return !m_pitEntries.empty();
+}
+
inline std::vector<shared_ptr<pit::Entry> >&
Entry::getPitEntries()
{
diff --git a/daemon/table/name-tree.cpp b/daemon/table/name-tree.cpp
index 964730e..5d11c27 100644
--- a/daemon/table/name-tree.cpp
+++ b/daemon/table/name-tree.cpp
@@ -38,6 +38,7 @@
, m_nBuckets(nBuckets)
, m_loadFactor(0.5)
, m_resizeFactor(2)
+ , m_endIterator(FULL_ENUMERATE_TYPE, *this, m_end)
{
m_resizeThreshold = static_cast<size_t>(m_loadFactor *
static_cast<double>(m_nBuckets));
@@ -186,7 +187,7 @@
// Return the longest matching Entry address
// start from the full name, and then remove 1 name comp each time
shared_ptr<name_tree::Entry>
-NameTree::findLongestPrefixMatch(const Name& prefix, const name_tree::EntrySelector& entrySelector)
+NameTree::findLongestPrefixMatch(const Name& prefix, const name_tree::EntrySelector& entrySelector) const
{
NFD_LOG_DEBUG("findLongestPrefixMatch " << prefix);
@@ -274,63 +275,82 @@
return false; // if this entry is not empty
}
-shared_ptr<std::vector<shared_ptr<name_tree::Entry> > >
-NameTree::fullEnumerate(const name_tree::EntrySelector& entrySelector)
+NameTree::const_iterator
+NameTree::fullEnumerate(const name_tree::EntrySelector& entrySelector) const
{
NFD_LOG_DEBUG("fullEnumerate");
- shared_ptr<std::vector<shared_ptr<name_tree::Entry> > > results =
- make_shared<std::vector<shared_ptr<name_tree::Entry> > >();
-
- for (size_t i = 0; i < m_nBuckets; i++) {
- for (name_tree::Node* node = m_buckets[i]; node != 0; node = node->m_next) {
- if (static_cast<bool>(node->m_entry) && entrySelector(*node->m_entry)) {
- results->push_back(node->m_entry);
- }
- }
- }
-
- return results;
-}
-
-// Helper function for partialEnumerate()
-void
-NameTree::partialEnumerateAddChildren(shared_ptr<name_tree::Entry> entry,
- const name_tree::EntrySelector& entrySelector,
- std::vector<shared_ptr<name_tree::Entry> >& results)
-{
- BOOST_ASSERT(static_cast<bool>(entry));
-
- if (!entrySelector(*entry)) {
- return;
- }
-
- results.push_back(entry);
- for (size_t i = 0; i < entry->m_children.size(); i++)
+ // find the first eligible entry
+ for (size_t i = 0; i < m_nBuckets; i++)
{
- shared_ptr<name_tree::Entry> child = entry->m_children[i];
- partialEnumerateAddChildren(child, entrySelector, results);
+ for (name_tree::Node* node = m_buckets[i]; node != 0; node = node->m_next)
+ {
+ if (static_cast<bool>(node->m_entry) && entrySelector(*node->m_entry))
+ {
+ const_iterator it(FULL_ENUMERATE_TYPE, *this, node->m_entry, entrySelector);
+ return it;
+ }
+ }
+ }
+
+ // If none of the entry satisfies the requirements, then return the end() iterator.
+ return end();
+}
+
+NameTree::const_iterator
+NameTree::partialEnumerate(const Name& prefix,
+ const name_tree::EntrySubTreeSelector& entrySubTreeSelector) const
+{
+ // the first step is to process the root node
+ shared_ptr<name_tree::Entry> entry = findExactMatch(prefix);
+ if (!static_cast<bool>(entry))
+ {
+ return end();
+ }
+
+ std::pair<bool, bool>result = entrySubTreeSelector(*entry);
+ const_iterator it(PARTIAL_ENUMERATE_TYPE,
+ *this,
+ entry,
+ name_tree::AnyEntry(),
+ entrySubTreeSelector);
+
+ it.m_shouldVisitChildren = (result.second && entry->hasChildren());
+
+ if (result.first)
+ {
+ // root node is acceptable
+ return it;
+ }
+ else
+ {
+ // let the ++ operator handle it
+ ++it;
+ return it;
}
}
-shared_ptr<std::vector<shared_ptr<name_tree::Entry> > >
-NameTree::partialEnumerate(const Name& prefix,
- const name_tree::EntrySelector& entrySelector)
+NameTree::const_iterator
+NameTree::findAllMatches(const Name& prefix,
+ const name_tree::EntrySelector& entrySelector) const
{
- NFD_LOG_DEBUG("partialEnumerate" << prefix);
+ NFD_LOG_DEBUG("NameTree::findAllMatches" << prefix);
- shared_ptr<std::vector<shared_ptr<name_tree::Entry> > > results =
- make_shared<std::vector<shared_ptr<name_tree::Entry> > >();
+ // As we are using Name Prefix Hash Table, and the current LPM() is
+ // implemented as starting from full name, and reduce the number of
+ // components by 1 each time, we could use it here.
+ // For trie-like design, it could be more efficient by walking down the
+ // trie from the root node.
- // find the hash bucket corresponding to that prefix
- shared_ptr<name_tree::Entry> entry = findExactMatch(prefix);
+ shared_ptr<name_tree::Entry> entry = findLongestPrefixMatch(prefix, entrySelector);
- if (static_cast<bool>(entry)) {
- // go through its children list via depth-first-search
- partialEnumerateAddChildren(entry, entrySelector, *results);
- }
-
- return results;
+ if (static_cast<bool>(entry))
+ {
+ const_iterator it(FIND_ALL_MATCHES_TYPE, *this, entry, entrySelector);
+ return it;
+ }
+ // If none of the entry satisfies the requirements, then return the end() iterator.
+ return end();
}
// Hash Table Resize
@@ -388,7 +408,7 @@
// For debugging
void
-NameTree::dump(std::ostream& output)
+NameTree::dump(std::ostream& output) const
{
NFD_LOG_DEBUG("dump()");
@@ -440,4 +460,183 @@
output << "--------------------------\n";
}
+NameTree::const_iterator::const_iterator(NameTree::IteratorType type,
+ const NameTree& nameTree,
+ shared_ptr<name_tree::Entry> entry,
+ const name_tree::EntrySelector& entrySelector,
+ const name_tree::EntrySubTreeSelector& entrySubTreeSelector)
+ : m_nameTree(nameTree)
+ , m_entry(entry)
+ , m_subTreeRoot(entry)
+ , m_entrySelector(make_shared<name_tree::EntrySelector>(entrySelector))
+ , m_entrySubTreeSelector(make_shared<name_tree::EntrySubTreeSelector>(entrySubTreeSelector))
+ , m_type(type)
+ , m_shouldVisitChildren(true)
+{
+}
+
+// operator++()
+NameTree::const_iterator
+NameTree::const_iterator::operator++()
+{
+ NFD_LOG_DEBUG("const_iterator::operator++()");
+
+ BOOST_ASSERT(m_entry != m_nameTree.m_end);
+
+ if (m_type == FULL_ENUMERATE_TYPE) // fullEnumerate
+ {
+ bool isFound = false;
+ // process the entries in the same bucket first
+ while (m_entry->m_node->m_next != 0)
+ {
+ m_entry = m_entry->m_node->m_next->m_entry;
+ if ((*m_entrySelector)(*m_entry))
+ {
+ isFound = true;
+ return *this;
+ }
+ }
+
+ // process other buckets
+ int newLocation = m_entry->m_hash % m_nameTree.m_nBuckets + 1;
+ for (newLocation = newLocation; newLocation < m_nameTree.m_nBuckets; newLocation++)
+ {
+ // process each bucket
+ name_tree::Node* node = m_nameTree.m_buckets[newLocation];
+ while (node != 0)
+ {
+ m_entry = node->m_entry;
+ if ((*m_entrySelector)(*m_entry))
+ {
+ isFound = true;
+ return *this;
+ }
+ node = node->m_next;
+ }
+ }
+ BOOST_ASSERT(isFound == false);
+ // Reach to the end()
+ m_entry = m_nameTree.m_end;
+ return *this;
+ }
+
+ if (m_type == PARTIAL_ENUMERATE_TYPE) // partialEnumerate
+ {
+ // We use pre-order traversal.
+ // if at the root, it could have already been accepted, or this
+ // iterator was just declared, and root doesn't satisfy the
+ // requirement
+ // The if() section handles this special case
+ // Essentially, we need to check root's fist child, and the rest will
+ // be the same as normal process
+ if (m_entry == m_subTreeRoot)
+ {
+ if (m_shouldVisitChildren)
+ {
+ m_entry = m_entry->getChildren()[0];
+ std::pair<bool, bool> result = ((*m_entrySubTreeSelector)(*m_entry));
+ m_shouldVisitChildren = (result.second && m_entry->hasChildren());
+ if(result.first)
+ {
+ return *this;
+ }
+ else
+ {
+ // the first child did not meet the requirement
+ // the rest of the process can just fall through the while loop
+ // as normal
+ }
+ }
+ else
+ {
+ // no children, should return end();
+ // just fall through
+ }
+ }
+
+ // The first thing to do is to visit its child, or go to find its possible
+ // siblings
+ while (m_entry != m_subTreeRoot)
+ {
+ if (m_shouldVisitChildren)
+ {
+ // If this subtree should be visited
+ m_entry = m_entry->getChildren()[0];
+ std::pair<bool, bool> result = ((*m_entrySubTreeSelector)(*m_entry));
+ m_shouldVisitChildren = (result.second && m_entry->hasChildren());
+ if (result.first) // if this node is acceptable
+ {
+ return *this;
+ }
+ else
+ {
+ // do nothing, as this node is essentially ignored
+ // send this node to the while loop.
+ }
+ }
+ else
+ {
+ // Should try to find its sibling
+ shared_ptr<name_tree::Entry> parent = m_entry->getParent();
+
+ std::vector<shared_ptr<name_tree::Entry> >& parentChildrenList = parent->getChildren();
+ bool isFound = false;
+ size_t i = 0;
+ for (i = 0; i < parentChildrenList.size(); i++)
+ {
+ if (parentChildrenList[i] == m_entry)
+ {
+ isFound = true;
+ break;
+ }
+ }
+
+ BOOST_ASSERT(isFound == true);
+ if (i < parentChildrenList.size() - 1) // m_entry not the last child
+ {
+ m_entry = parentChildrenList[i + 1];
+ std::pair<bool, bool> result = ((*m_entrySubTreeSelector)(*m_entry));
+ m_shouldVisitChildren = (result.second && m_entry->hasChildren());
+ if (result.first) // if this node is acceptable
+ {
+ return *this;
+ }
+ else
+ {
+ // do nothing, as this node is essentially ignored
+ // send this node to the while loop.
+ }
+ }
+ else
+ {
+ // m_entry is the last child, no more sibling, should try to find parent's sibling
+ m_shouldVisitChildren = false;
+ m_entry = parent;
+ }
+ }
+ }
+
+ m_entry = m_nameTree.m_end;
+ return *this;
+ }
+
+ if (m_type == FIND_ALL_MATCHES_TYPE) // findAllMatches
+ {
+ // Assumption: at the beginning, m_entry was initialized with the first
+ // eligible Name Tree entry (i.e., has a PIT entry that can be satisfied
+ // by the Data packet)
+
+ while (static_cast<bool>(m_entry->getParent()))
+ {
+ m_entry = m_entry->getParent();
+ if ((*m_entrySelector)(*m_entry))
+ return *this;
+ }
+
+ // Reach to the end (Root)
+ m_entry = m_nameTree.m_end;
+ return *this;
+ }
+}
+
} // namespace nfd
diff --git a/daemon/table/name-tree.hpp b/daemon/table/name-tree.hpp
index 812c916..1a30b2b 100644
--- a/daemon/table/name-tree.hpp
+++ b/daemon/table/name-tree.hpp
@@ -16,8 +16,8 @@
namespace name_tree {
/**
- * @brief Compute the hash value of the given name prefix.
- * @todo 1) have another parameter that specifies the number of components
+ * \brief Compute the hash value of the given name prefix.
+ * \todo 1) have another parameter that specifies the number of components
* 2) optimize the hash function to return a list of have values for all
* the (or a certain number of, like a batch operation) prefixes. 3) move
* the hash-related code to a separate file in /core or ndn-cpp-dev lib.
@@ -28,6 +28,13 @@
/// a predicate to accept or reject an Entry in find operations
typedef function<bool (const Entry& entry)> EntrySelector;
+/**
+ * \brief a predicate to accept or reject an Entry and its children
+ * \return .first indicates whether entry should be accepted;
+ * .second indicates whether entry's children should be visited
+ */
+typedef function<std::pair<bool,bool> (const Entry& entry)> EntrySubTreeSelector;
+
struct AnyEntry {
bool
operator()(const Entry& entry)
@@ -36,134 +43,201 @@
}
};
+struct AnyEntrySubTree {
+ std::pair<bool, bool>
+ operator()(const Entry& entry)
+ {
+ return std::make_pair(true, true);
+ }
+};
+
} // namespace name_tree
/**
- * @brief Class Name Tree
+ * \brief Class Name Tree
*/
class NameTree : noncopyable
{
public:
+ class const_iterator;
+
explicit
NameTree(size_t nBuckets);
~NameTree();
/**
- * @brief Get the number of occupied entries in the Name Tree
+ * \brief Get the number of occupied entries in the Name Tree
*/
size_t
size() const;
/**
- * @brief Get the number of buckets in the Name Tree (NPHT)
- * @details The number of buckets is the one that used to create the hash
+ * \brief Get the number of buckets in the Name Tree (NPHT)
+ * \details The number of buckets is the one that used to create the hash
* table, i.e., m_nBuckets.
*/
size_t
getNBuckets() const;
/**
- * @brief Look for the Name Tree Entry that contains this name prefix.
- * @details Starts from the shortest name prefix, and then increase the
+ * \brief Look for the Name Tree Entry that contains this name prefix.
+ * \details Starts from the shortest name prefix, and then increase the
* number of name components by one each time. All non-existing Name Tree
* Entries will be created.
- * @param prefix The querying name prefix.
- * @return The pointer to the Name Tree Entry that contains this full name
+ * \param prefix The querying name prefix.
+ * \return The pointer to the Name Tree Entry that contains this full name
* prefix.
*/
shared_ptr<name_tree::Entry>
lookup(const Name& prefix);
/**
- * @brief Exact match lookup for the given name prefix.
- * @return a null shared_ptr if this prefix is not found;
+ * \brief Exact match lookup for the given name prefix.
+ * \return a null shared_ptr if this prefix is not found;
* otherwise return the Name Tree Entry address
*/
shared_ptr<name_tree::Entry>
findExactMatch(const Name& prefix) const;
/**
- * @brief Erase a Name Tree Entry if this entry is empty.
- * @details If a Name Tree Entry contains no Children, no FIB, no PIT, and
+ * \brief Erase a Name Tree Entry if this entry is empty.
+ * \details If a Name Tree Entry contains no Children, no FIB, no PIT, and
* no Measurements entries, then it can be erased. In addition, its parent entry
* will also be examined by following the parent pointer until all empty entries
* are erased.
- * @param entry The pointer to the entry to be erased. The entry pointer should
+ * \param entry The pointer to the entry to be erased. The entry pointer should
* returned by the findExactMatch(), lookup(), or findLongestPrefixMatch() functions.
*/
bool
eraseEntryIfEmpty(shared_ptr<name_tree::Entry> entry);
/**
- * @brief Longest prefix matching for the given name
- * @details Starts from the full name string, reduce the number of name component
+ * \brief Longest prefix matching for the given name
+ * \details Starts from the full name string, reduce the number of name component
* by one each time, until an Entry is found.
*/
shared_ptr<name_tree::Entry>
findLongestPrefixMatch(const Name& prefix,
- const name_tree::EntrySelector& entrySelector = name_tree::AnyEntry());
+ const name_tree::EntrySelector& entrySelector =
+ name_tree::AnyEntry()) const;
/**
- * @brief Resize the hash table size when its load factor reaches a threshold.
- * @details As we are currently using a hand-written hash table implementation
+ * \brief Resize the hash table size when its load factor reaches a threshold.
+ * \details As we are currently using a hand-written hash table implementation
* for the Name Tree, the hash table resize() function should be kept in the
* name-tree.hpp file.
- * @param newNBuckets The number of buckets for the new hash table.
+ * \param newNBuckets The number of buckets for the new hash table.
*/
void
resize(size_t newNBuckets);
/**
- * @brief Enumerate all the name prefixes stored in the Name Tree.
+ * \brief Enumerate all the name prefixes stored in the Name Tree.
*/
- shared_ptr<std::vector<shared_ptr<name_tree::Entry> > >
- fullEnumerate(const name_tree::EntrySelector& entrySelector = name_tree::AnyEntry());
+ const_iterator
+ fullEnumerate(const name_tree::EntrySelector& entrySelector = name_tree::AnyEntry()) const;
/**
- * @brief Enumerate all the name prefixes under a specific name prefix
- * @todo It might be better to have functions like fullEnemerateFib() to reduce the
- * number of entries stored in the vector.
- */
- shared_ptr<std::vector<shared_ptr<name_tree::Entry> > >
+ * \brief Enumerate all the name prefixes that satisfies the EntrySubTreeSelector.
+ */
+ const_iterator
partialEnumerate(const Name& prefix,
- const name_tree::EntrySelector& entrySelector = name_tree::AnyEntry());
+ const name_tree::EntrySubTreeSelector& entrySubTreeSelector = name_tree::AnyEntrySubTree()) const;
/**
- * @brief Dump all the information stored in the Name Tree for debugging.
+ * \brief Enumerate all the name prefixes that satisfy the prefix and entrySelector
+ */
+ const_iterator
+ findAllMatches(const Name& prefix,
+ const name_tree::EntrySelector& entrySelector = name_tree::AnyEntry()) const;
+
+ /**
+ * \brief Dump all the information stored in the Name Tree for debugging.
*/
void
- dump(std::ostream& output);
+ dump(std::ostream& output) const;
+
+ const_iterator
+ begin() const;
+
+ const_iterator
+ end() const;
+
+ enum IteratorType
+ {
+ FULL_ENUMERATE_TYPE,
+ PARTIAL_ENUMERATE_TYPE,
+ FIND_ALL_MATCHES_TYPE
+ };
+
+ class const_iterator : public std::iterator<std::forward_iterator_tag, name_tree::Entry>
+ {
+ public:
+ friend class NameTree;
+
+ const_iterator(NameTree::IteratorType type,
+ const NameTree& nameTree,
+ shared_ptr<name_tree::Entry> entry,
+ const name_tree::EntrySelector& entrySelector = name_tree::AnyEntry(),
+ const name_tree::EntrySubTreeSelector& entrySubTreeSelector = name_tree::AnyEntrySubTree());
+
+ ~const_iterator();
+
+ const name_tree::Entry&
+ operator*() const;
+
+ shared_ptr<name_tree::Entry>
+ operator->() const;
+
+ const_iterator
+ operator++();
+
+ const_iterator
+ operator++(int);
+
+ bool
+ operator==(const const_iterator& other) const;
+
+ bool
+ operator!=(const const_iterator& other) const;
+
+ private:
+ bool m_shouldVisitChildren;
+ const NameTree& m_nameTree;
+ shared_ptr<name_tree::Entry> m_entry;
+ shared_ptr<name_tree::Entry> m_subTreeRoot;
+ shared_ptr<name_tree::EntrySelector> m_entrySelector;
+ shared_ptr<name_tree::EntrySubTreeSelector> m_entrySubTreeSelector;
+ NameTree::IteratorType m_type;
+ };
private:
- size_t m_nItems; // Number of items being stored
- size_t m_nBuckets; // Number of hash buckets
- double m_loadFactor;
- size_t m_resizeThreshold;
- int m_resizeFactor;
- name_tree::Node** m_buckets; // Name Tree Buckets in the NPHT
+ size_t m_nItems; // Number of items being stored
+ size_t m_nBuckets; // Number of hash buckets
+ double m_loadFactor;
+ size_t m_resizeThreshold;
+ int m_resizeFactor;
+ name_tree::Node** m_buckets; // Name Tree Buckets in the NPHT
+ shared_ptr<name_tree::Entry> m_end;
+ const_iterator m_endIterator;
/**
- * @brief Create a Name Tree Entry if it does not exist, or return the existing
+ * \brief Create a Name Tree Entry if it does not exist, or return the existing
* Name Tree Entry address.
- * @details Called by lookup() only.
- * @return The first item is the Name Tree Entry address, the second item is
+ * \details Called by lookup() only.
+ * \return The first item is the Name Tree Entry address, the second item is
* a bool value indicates whether this is an old entry (false) or a new
* entry (true).
*/
std::pair<shared_ptr<name_tree::Entry>, bool>
insert(const Name& prefix);
-
- /**
- * @brief Helper function for partialEnumerate()
- */
- void
- partialEnumerateAddChildren(shared_ptr<name_tree::Entry> entry,
- const name_tree::EntrySelector& entrySelector,
- std::vector<shared_ptr<name_tree::Entry> >& results);
-
};
+inline NameTree::const_iterator::~const_iterator()
+{
+}
+
inline size_t
NameTree::size() const
{
@@ -176,6 +250,50 @@
return m_nBuckets;
}
+inline NameTree::const_iterator
+NameTree::begin() const
+{
+ return fullEnumerate();
+}
+
+inline NameTree::const_iterator
+NameTree::end() const
+{
+ return m_endIterator;
+}
+
+inline const name_tree::Entry&
+NameTree::const_iterator::operator*() const
+{
+ return *m_entry;
+}
+
+inline shared_ptr<name_tree::Entry>
+NameTree::const_iterator::operator->() const
+{
+ return m_entry;
+}
+
+inline NameTree::const_iterator
+NameTree::const_iterator::operator++(int)
+{
+ NameTree::const_iterator temp(*this);
+ ++(*this);
+ return temp;
+}
+
+inline bool
+NameTree::const_iterator::operator==(const NameTree::const_iterator& other) const
+{
+ return m_entry == other.m_entry;
+}
+
+inline bool
+NameTree::const_iterator::operator!=(const NameTree::const_iterator& other) const
+{
+ return m_entry != other.m_entry;
+}
+
} // namespace nfd
#endif // NFD_TABLE_NAME_TREE_HPP
diff --git a/daemon/table/pit.cpp b/daemon/table/pit.cpp
index 6f5acf3..dafec47 100644
--- a/daemon/table/pit.cpp
+++ b/daemon/table/pit.cpp
@@ -4,19 +4,6 @@
* See COPYING for copyright and distribution information.
*/
-/**
- * KNOWN ISSUES
- *
- * - To remove a PIT entry, we need to first perform a lookup on NameTree
- * to locate its NameTree Entry, and then call NameTreeEntry->deletePitEntry()
- * function. Alternatively, we could store a pointer at each PIT-Entry, which
- * would speed up this procedure with the cost of additional memory space. Maybe
- * this could also be part of the PIT/FIB/Measurement shortcut, where all of these
- * entries have pointers to their NameTreeEntry. Which could be part of task
- * #1202, shortcuts between FIB, PIT, Measurements.
- *
- */
-
#include "pit.hpp"
namespace nfd {
@@ -30,6 +17,12 @@
}
static inline bool
+predicate_NameTreeEntry_hasPitEntry(const name_tree::Entry& entry)
+{
+ return entry.hasPitEntries();
+}
+
+static inline bool
operator==(const Exclude& a, const Exclude& b)
{
const Block& aBlock = a.wireEncode();
@@ -57,10 +50,10 @@
{
// - first lookup() the Interest Name in the NameTree, which will creates all
// the intermedia nodes, starting from the shortest prefix.
- // - if it is guaranteed that this Interest already has a NameTree Entry, we
+ // - if it is guaranteed that this Interest already has a NameTree Entry, we
// could use findExactMatch() instead.
- // - Alternatively, we could try to do findExactMatch() first, if not found, then
- // do lookup().
+ // - Alternatively, we could try to do findExactMatch() first, if not found,
+ // then do lookup().
shared_ptr<name_tree::Entry> nameTreeEntry = m_nameTree.lookup(interest.getName());
BOOST_ASSERT(static_cast<bool>(nameTreeEntry));
@@ -91,19 +84,11 @@
{
shared_ptr<pit::DataMatchResult> result = make_shared<pit::DataMatchResult>();
- shared_ptr<name_tree::Entry> nameTreeEntry;
-
- // NOTE: We are using findLongestPrefixMatch() here.
- // The reason is that findLongestPrefixMatch() starts with the full name
- // and then remove one component each time, which is the type of behavior we would like
- // to use here.
- // If it could be guranteed that the quering Data packet always has a Name Tree
- // Entry, we could also use findExactMatch().
- for (nameTreeEntry = m_nameTree.findLongestPrefixMatch(data.getName());
- static_cast<bool>(nameTreeEntry);
- nameTreeEntry = nameTreeEntry->getParent())
+ for (NameTree::const_iterator it =
+ m_nameTree.findAllMatches(data.getName(), &predicate_NameTreeEntry_hasPitEntry);
+ it != m_nameTree.end(); it++)
{
- std::vector<shared_ptr<pit::Entry> >& pitEntries = nameTreeEntry->getPitEntries();
+ std::vector<shared_ptr<pit::Entry> >& pitEntries = it->getPitEntries();
for (size_t i = 0; i < pitEntries.size(); i++)
{
if (pitEntries[i]->getInterest().matchesName(data.getName()))
@@ -125,7 +110,7 @@
BOOST_ASSERT(static_cast<bool>(nameTreeEntry));
// erase this PIT entry
- if (static_cast<bool>(nameTreeEntry))
+ if (static_cast<bool>(nameTreeEntry))
{
nameTreeEntry->erasePitEntry(pitEntry);
m_nameTree.eraseEntryIfEmpty(nameTreeEntry);
diff --git a/daemon/table/pit.hpp b/daemon/table/pit.hpp
index 9ea5aac..e0b5ba2 100644
--- a/daemon/table/pit.hpp
+++ b/daemon/table/pit.hpp
@@ -31,31 +31,31 @@
public:
explicit
Pit(NameTree& nameTree);
-
+
~Pit();
- /**
+ /**
* \brief Get the number of items stored in the PIT.
*/
- size_t
+ size_t
size() const;
-
+
/** \brief inserts a FIB entry for prefix
* If an entry for exact same prefix exists, that entry is returned.
* \return{ the entry, and true for new entry, false for existing entry }
*/
std::pair<shared_ptr<pit::Entry>, bool>
insert(const Interest& interest);
-
+
/** \brief performs a Data match
* \return{ an iterable of all PIT entries matching data }
*/
shared_ptr<pit::DataMatchResult>
findAllDataMatches(const Data& data) const;
-
+
/**
* \brief Erase a PIT Entry
- */
+ */
void
erase(shared_ptr<pit::Entry> pitEntry);
diff --git a/tests/table/name-tree.cpp b/tests/table/name-tree.cpp
index 4411fd2..e44c401 100644
--- a/tests/table/name-tree.cpp
+++ b/tests/table/name-tree.cpp
@@ -5,7 +5,6 @@
*/
#include "table/name-tree.hpp"
-
#include "tests/test-common.hpp"
namespace nfd {
@@ -19,7 +18,7 @@
{
Name prefix("ndn:/named-data/research/abc/def/ghi");
- name_tree::Entry npe = name_tree::Entry(prefix);
+ name_tree::Entry npe(prefix);
BOOST_CHECK_EQUAL(npe.getPrefix(), prefix);
// examine all the get methods
@@ -39,7 +38,7 @@
std::vector< shared_ptr<pit::Entry> >& pitList = npe.getPitEntries();
BOOST_CHECK_EQUAL(pitList.size(), 0);
- // examine all the set method
+ // examine all the set method
npe.setHash(12345);
BOOST_CHECK_EQUAL(npe.getHash(), 12345);
@@ -49,15 +48,15 @@
npe.setParent(parent);
BOOST_CHECK_EQUAL(npe.getParent(), parent);
- // Insert FIB
+ // Insert FIB
shared_ptr<fib::Entry> fibEntry(new fib::Entry(prefix));
shared_ptr<fib::Entry> fibEntryParent(new fib::Entry(parentName));
-
+
npe.setFibEntry(fibEntry);
BOOST_CHECK_EQUAL(npe.getFibEntry(), fibEntry);
- // Erase a FIB that does not exist
+ // Erase a FIB that does not exist
BOOST_CHECK_EQUAL(npe.
eraseFibEntry(fibEntryParent), false);
BOOST_CHECK_EQUAL(npe.getFibEntry(), fibEntry);
@@ -70,7 +69,7 @@
// Insert a PIT
shared_ptr<pit::Entry> PitEntry(make_shared<pit::Entry>(prefix));
- shared_ptr<pit::Entry> PitEntry2(make_shared<pit::Entry>(parentName));
+ shared_ptr<pit::Entry> PitEntry2(make_shared<pit::Entry>(parentName));
Name prefix3("ndn:/named-data/research/abc/def");
shared_ptr<pit::Entry> PitEntry3(make_shared<pit::Entry>(prefix3));
@@ -107,25 +106,25 @@
NameTree nt(nBuckets);
BOOST_CHECK_EQUAL(nt.size(), 0);
- BOOST_CHECK_EQUAL(nt.getNBuckets(), nBuckets);
+ BOOST_CHECK_EQUAL(nt.getNBuckets(), nBuckets);
- Name nameABC = ("ndn:/a/b/c");
+ Name nameABC("ndn:/a/b/c");
shared_ptr<name_tree::Entry> npeABC = nt.lookup(nameABC);
BOOST_CHECK_EQUAL(nt.size(), 4);
-
- Name nameABD = ("/a/b/d");
+
+ Name nameABD("/a/b/d");
shared_ptr<name_tree::Entry> npeABD = nt.lookup(nameABD);
BOOST_CHECK_EQUAL(nt.size(), 5);
- Name nameAE = ("/a/e/");
+ Name nameAE("/a/e/");
shared_ptr<name_tree::Entry> npeAE = nt.lookup(nameAE);
BOOST_CHECK_EQUAL(nt.size(), 6);
- Name nameF = ("/f");
+ Name nameF("/f");
shared_ptr<name_tree::Entry> npeF = nt.lookup(nameF);
BOOST_CHECK_EQUAL(nt.size(), 7);
- // validate lookup() and findExactMatch()
+ // validate lookup() and findExactMatch()
Name nameAB ("/a/b");
BOOST_CHECK_EQUAL(npeABC->getParent(), nt.findExactMatch(nameAB));
@@ -138,7 +137,7 @@
BOOST_CHECK_EQUAL(npeF->getParent(), nt.findExactMatch(nameRoot));
BOOST_CHECK_EQUAL(nt.size(), 7);
- Name name0 = ("/does/not/exist");
+ Name name0("/does/not/exist");
shared_ptr<name_tree::Entry> npe0 = nt.findExactMatch(name0);
BOOST_CHECK(!static_cast<bool>(npe0));
@@ -174,8 +173,6 @@
temp = nt.findLongestPrefixMatch(nameRootLPM);
BOOST_CHECK_EQUAL(temp, nt.findExactMatch(nameRoot));
- // nt.dump(std::cout);
-
bool eraseResult = false;
temp = nt.findExactMatch(nameABC);
if (static_cast<bool>(temp))
@@ -187,7 +184,7 @@
eraseResult = false;
temp = nt.findExactMatch(nameABCLPM);
- if (static_cast<bool>(temp))
+ if (static_cast<bool>(temp))
eraseResult = nt.
eraseEntryIfEmpty(temp);
BOOST_CHECK(!static_cast<bool>(temp));
@@ -201,18 +198,16 @@
eraseResult = false;
temp = nt.findExactMatch(nameABC);
- if (static_cast<bool>(temp))
+ if (static_cast<bool>(temp))
eraseResult = nt.
eraseEntryIfEmpty(temp);
BOOST_CHECK_EQUAL(nt.size(), 6);
BOOST_CHECK_EQUAL(eraseResult, true);
BOOST_CHECK(!static_cast<bool>(nt.findExactMatch(nameABC)));
- // nt.dump(std::cout);
-
BOOST_CHECK_EQUAL(nt.getNBuckets(), 16);
- // should resize now
+ // should resize now
Name nameABCD("a/b/c/d");
nt.lookup(nameABCD);
Name nameABCDE("a/b/c/d/e");
@@ -220,9 +215,7 @@
BOOST_CHECK_EQUAL(nt.size(), 9);
BOOST_CHECK_EQUAL(nt.getNBuckets(), 32);
- // nt.dump(std::cout);
-
- // try to erase /a/b/c, should return false
+ // try to erase /a/b/c, should return false
temp = nt.findExactMatch(nameABC);
BOOST_CHECK_EQUAL(temp->getPrefix(), nameABC);
eraseResult = nt.
@@ -232,38 +225,556 @@
BOOST_CHECK_EQUAL(temp->getPrefix(), nameABC);
temp = nt.findExactMatch(nameABD);
- if (static_cast<bool>(temp))
+ if (static_cast<bool>(temp))
nt.
eraseEntryIfEmpty(temp);
BOOST_CHECK_EQUAL(nt.size(), 8);
-
- // nt.dump(std::cout);
+}
- shared_ptr<std::vector<shared_ptr<name_tree::Entry> > > fullList;
- fullList = nt.fullEnumerate();
- BOOST_CHECK_EQUAL(fullList->size(), 8);
- // for (size_t j = 0; j < (*fullList).size(); j++)
- // {
- // temp = (*fullList)[j];
- // std::cout << temp->getPrefix().toUri() << std::endl;
- // }
+BOOST_AUTO_TEST_CASE(NameTreeIteratorFullEnumerate)
+{
+ using namespace std;
- shared_ptr<std::vector<shared_ptr<name_tree::Entry> > > partialList;
- partialList = nt.partialEnumerate(nameA);
- BOOST_CHECK_EQUAL(partialList->size(), 6);
- // for (size_t j = 0; j < (*partialList).size(); j++)
- // {
- // temp = (*partialList)[j];
- // std::cout << temp->getPrefix().toUri() << std::endl;
- // }
+ size_t nBuckets = 1024;
+ NameTree nt(nBuckets);
- partialList = nt.partialEnumerate(nameRoot);
- BOOST_CHECK_EQUAL(partialList->size(), 8);
- // for (size_t j = 0; j < (*partialList).size(); j++)
- // {
- // temp = (*partialList)[j];
- // std::cout << temp->getPrefix().toUri() << std::endl;
- // }
+ BOOST_CHECK_EQUAL(nt.size(), 0);
+ BOOST_CHECK_EQUAL(nt.getNBuckets(), nBuckets);
+
+ Name nameABC("ndn:/a/b/c");
+ shared_ptr<name_tree::Entry> npeABC = nt.lookup(nameABC);
+ BOOST_CHECK_EQUAL(nt.size(), 4);
+
+ Name nameABD("/a/b/d");
+ shared_ptr<name_tree::Entry> npeABD = nt.lookup(nameABD);
+ BOOST_CHECK_EQUAL(nt.size(), 5);
+
+ Name nameAE("/a/e/");
+ shared_ptr<name_tree::Entry> npeAE = nt.lookup(nameAE);
+ BOOST_CHECK_EQUAL(nt.size(), 6);
+
+ Name nameF("/f");
+ shared_ptr<name_tree::Entry> npeF = nt.lookup(nameF);
+ BOOST_CHECK_EQUAL(nt.size(), 7);
+
+ Name nameRoot("/");
+ shared_ptr<name_tree::Entry> npeRoot = nt.lookup(nameRoot);
+ BOOST_CHECK_EQUAL(nt.size(), 7);
+
+ Name nameA("/a");
+ Name nameAB("/a/b");
+
+ bool hasRoot = false;
+ bool hasA = false;
+ bool hasAB = false;
+ bool hasABC = false;
+ bool hasABD = false;
+ bool hasAE = false;
+ bool hasF = false;
+
+ int counter = 0;
+ NameTree::const_iterator it = nt.fullEnumerate();
+
+ for(; it != nt.end(); it++)
+ {
+ counter++;
+
+ if (it->getPrefix() == nameRoot)
+ hasRoot = true;
+ if (it->getPrefix() == nameA)
+ hasA = true;
+ if (it->getPrefix() == nameAB)
+ hasAB = true;
+ if (it->getPrefix() == nameABC)
+ hasABC = true;
+ if (it->getPrefix() == nameABD)
+ hasABD = true;
+ if (it->getPrefix() == nameAE)
+ hasAE = true;
+ if (it->getPrefix() == nameF)
+ hasF = true;
+ }
+
+ BOOST_CHECK_EQUAL(hasRoot , true);
+ BOOST_CHECK_EQUAL(hasA , true);
+ BOOST_CHECK_EQUAL(hasAB , true);
+ BOOST_CHECK_EQUAL(hasABC , true);
+ BOOST_CHECK_EQUAL(hasABD , true);
+ BOOST_CHECK_EQUAL(hasAE , true);
+ BOOST_CHECK_EQUAL(hasF , true);
+
+ BOOST_CHECK_EQUAL(counter , 7);
+}
+
+// Predicates for testing the partial enumerate function
+
+static inline std::pair<bool, bool>
+predicate_NameTreeEntry_NameA_Only(const name_tree::Entry& entry)
+{
+ Name nameA("/a");
+ bool first = nameA.equals(entry.getPrefix());
+ return std::make_pair(first, true);
+}
+
+static inline std::pair<bool, bool>
+predicate_NameTreeEntry_Except_NameA(const name_tree::Entry& entry)
+{
+ Name nameA("/a");
+ bool first = !(nameA.equals(entry.getPrefix()));
+ return std::make_pair(first, true);
+}
+
+static inline std::pair<bool, bool>
+predicate_NameTreeEntry_NoSubNameA(const name_tree::Entry& entry)
+{
+ Name nameA("/a");
+ bool second = !(nameA.equals(entry.getPrefix()));
+ return std::make_pair(true, second);
+}
+
+static inline std::pair<bool, bool>
+predicate_NameTreeEntry_NoNameA_NoSubNameAB(const name_tree::Entry& entry)
+{
+ Name nameA("/a");
+ Name nameAB("/a/b");
+ bool first = !(nameA.equals(entry.getPrefix()));
+ bool second = !(nameAB.equals(entry.getPrefix()));
+ return std::make_pair(first, second);
+}
+
+static inline std::pair<bool, bool>
+predicate_NameTreeEntry_NoNameA_NoSubNameAC(const name_tree::Entry& entry)
+{
+ Name nameA("/a");
+ Name nameAC("/a/c");
+ bool first = !(nameA.equals(entry.getPrefix()));
+ bool second = !(nameAC.equals(entry.getPrefix()));
+ return std::make_pair(first, second);
+}
+
+static inline std::pair<bool, bool>
+predicate_NameTreeEntry_Example(const name_tree::Entry& entry)
+{
+ Name nameRoot("/");
+ Name nameA("/a");
+ Name nameAB("/a/b");
+ Name nameABC("/a/b/c");
+ Name nameAD("/a/d");
+ Name nameE("/e");
+ Name nameF("/f");
+
+ bool first = false;
+ bool second = false;
+
+ Name name = entry.getPrefix();
+
+ if (name == nameRoot || name == nameAB || name == nameABC || name == nameAD)
+ {
+ first = true;
+ }
+
+ if(name == nameRoot || name == nameA || name == nameF)
+ {
+ second = true;
+ }
+
+ return std::make_pair(first, second);
+}
+
+BOOST_AUTO_TEST_CASE(NameTreeIteratorPartialEnumerate)
+{
+ using namespace std;
+ typedef NameTree::const_iterator const_iterator;
+
+ size_t nBuckets = 16;
+ NameTree nameTree(nBuckets);
+ int counter = 0;
+
+ // empty nameTree, should return end();
+ Name nameA("/a");
+ bool hasA = false;
+ const_iterator itA = nameTree.partialEnumerate(nameA);
+ BOOST_CHECK(itA == nameTree.end());
+
+ // We have "/", "/a", "/a/b", "a/c" now.
+ Name nameAB("/a/b");
+ bool hasAB = false;
+ nameTree.lookup(nameAB);
+
+ Name nameAC("/a/c");
+ bool hasAC = false;
+ nameTree.lookup(nameAC);
+ BOOST_CHECK_EQUAL(nameTree.size(), 4);
+
+ // Enumerate on some name that is not in nameTree
+ Name name0="/0";
+ const_iterator it0 = nameTree.partialEnumerate(name0);
+ BOOST_CHECK(it0 == nameTree.end());
+
+ // Accept "root" nameA only
+ const_iterator itAOnly = nameTree.partialEnumerate(nameA, &predicate_NameTreeEntry_NameA_Only);
+ BOOST_CHECK_EQUAL(itAOnly->getPrefix(), nameA);
+ BOOST_CHECK(++itAOnly == nameTree.end());
+
+ // Accept anything except "root" nameA
+ const_iterator itExceptA = nameTree.partialEnumerate(nameA, &predicate_NameTreeEntry_Except_NameA);
+ hasA = false;
+ hasAB = false;
+ hasAC = false;
+
+ counter = 0;
+ for (; itExceptA != nameTree.end(); itExceptA++)
+ {
+ counter++;
+
+ if (itExceptA->getPrefix() == nameA)
+ hasA = true;
+
+ if (itExceptA->getPrefix() == nameAB)
+ hasAB = true;
+
+ if (itExceptA->getPrefix() == nameAC)
+ hasAC = true;
+ }
+ BOOST_CHECK_EQUAL(hasA, false);
+ BOOST_CHECK_EQUAL(hasAB, true);
+ BOOST_CHECK_EQUAL(hasAC, true);
+
+ BOOST_CHECK_EQUAL(counter, 2);
+
+ Name nameAB1("a/b/1");
+ bool hasAB1 = false;
+ nameTree.lookup(nameAB1);
+
+ Name nameAB2("a/b/2");
+ bool hasAB2 = false;
+ nameTree.lookup(nameAB2);
+
+ Name nameAC1("a/c/1");
+ bool hasAC1 = false;
+ nameTree.lookup(nameAC1);
+
+ Name nameAC2("a/c/2");
+ bool hasAC2 = false;
+ nameTree.lookup(nameAC2);
+
+ BOOST_CHECK_EQUAL(nameTree.size(), 8);
+
+ // No NameA
+ // No SubTree from NameAB
+ const_iterator itNoNameANoSubNameAB = nameTree.partialEnumerate(nameA, &predicate_NameTreeEntry_NoNameA_NoSubNameAB);
+ hasA = false;
+ hasAB = false;
+ hasAB1 = false;
+ hasAB2 = false;
+ hasAC = false;
+ hasAC1 = false;
+ hasAC2 = false;
+
+ counter = 0;
+
+ for (; itNoNameANoSubNameAB != nameTree.end(); itNoNameANoSubNameAB++)
+ {
+ counter++;
+
+ if (itNoNameANoSubNameAB->getPrefix() == nameA)
+ hasA = true;
+
+ if (itNoNameANoSubNameAB->getPrefix() == nameAB)
+ hasAB = true;
+
+ if (itNoNameANoSubNameAB->getPrefix() == nameAB1)
+ hasAB1 = true;
+
+ if (itNoNameANoSubNameAB->getPrefix() == nameAB2)
+ hasAB2 = true;
+
+ if (itNoNameANoSubNameAB->getPrefix() == nameAC)
+ hasAC = true;
+
+ if (itNoNameANoSubNameAB->getPrefix() == nameAC1)
+ hasAC1 = true;
+
+ if (itNoNameANoSubNameAB->getPrefix() == nameAC2)
+ hasAC2 = true;
+ }
+
+ BOOST_CHECK_EQUAL(hasA, false);
+ BOOST_CHECK_EQUAL(hasAB, true);
+ BOOST_CHECK_EQUAL(hasAB1, false);
+ BOOST_CHECK_EQUAL(hasAB2, false);
+ BOOST_CHECK_EQUAL(hasAC, true);
+ BOOST_CHECK_EQUAL(hasAC1, true);
+ BOOST_CHECK_EQUAL(hasAC2, true);
+
+ BOOST_CHECK_EQUAL(counter, 4);
+
+ // No NameA
+ // No SubTree from NameAC
+ const_iterator itNoNameANoSubNameAC = nameTree.partialEnumerate(nameA, &predicate_NameTreeEntry_NoNameA_NoSubNameAC);
+ hasA = false;
+ hasAB = false;
+ hasAB1 = false;
+ hasAB2 = false;
+ hasAC = false;
+ hasAC1 = false;
+ hasAC2 = false;
+
+ counter = 0;
+
+ for (; itNoNameANoSubNameAC != nameTree.end(); itNoNameANoSubNameAC++)
+ {
+ counter++;
+
+ if (itNoNameANoSubNameAC->getPrefix() == nameA)
+ hasA = true;
+
+ if (itNoNameANoSubNameAC->getPrefix() == nameAB)
+ hasAB = true;
+
+ if (itNoNameANoSubNameAC->getPrefix() == nameAB1)
+ hasAB1 = true;
+
+ if (itNoNameANoSubNameAC->getPrefix() == nameAB2)
+ hasAB2 = true;
+
+ if (itNoNameANoSubNameAC->getPrefix() == nameAC)
+ hasAC = true;
+
+ if (itNoNameANoSubNameAC->getPrefix() == nameAC1)
+ hasAC1 = true;
+
+ if (itNoNameANoSubNameAC->getPrefix() == nameAC2)
+ hasAC2 = true;
+ }
+
+ BOOST_CHECK_EQUAL(hasA, false);
+ BOOST_CHECK_EQUAL(hasAB, true);
+ BOOST_CHECK_EQUAL(hasAB1, true);
+ BOOST_CHECK_EQUAL(hasAB2, true);
+ BOOST_CHECK_EQUAL(hasAC, true);
+ BOOST_CHECK_EQUAL(hasAC1, false);
+ BOOST_CHECK_EQUAL(hasAC2, false);
+
+ BOOST_CHECK_EQUAL(counter, 4);
+
+ // No Subtree from NameA
+ const_iterator itNoANoSubNameA = nameTree.partialEnumerate(nameA, &predicate_NameTreeEntry_NoSubNameA);
+
+ hasA = false;
+ hasAB = false;
+ hasAB1 = false;
+ hasAB2 = false;
+ hasAC = false;
+ hasAC1 = false;
+ hasAC2 = false;
+
+ counter = 0;
+
+ for (; itNoANoSubNameA != nameTree.end(); itNoANoSubNameA++)
+ {
+ counter++;
+
+ if (itNoANoSubNameA->getPrefix() == nameA)
+ hasA = true;
+
+ if (itNoANoSubNameA->getPrefix() == nameAB)
+ hasAB = true;
+
+ if (itNoANoSubNameA->getPrefix() == nameAB1)
+ hasAB1 = true;
+
+ if (itNoANoSubNameA->getPrefix() == nameAB2)
+ hasAB2 = true;
+
+ if (itNoANoSubNameA->getPrefix() == nameAC)
+ hasAC = true;
+
+ if (itNoANoSubNameA->getPrefix() == nameAC1)
+ hasAC1 = true;
+
+ if (itNoANoSubNameA->getPrefix() == nameAC2)
+ hasAC2 = true;
+ }
+
+ BOOST_CHECK_EQUAL(hasA, true);
+ BOOST_CHECK_EQUAL(hasAB, false);
+ BOOST_CHECK_EQUAL(hasAB1, false);
+ BOOST_CHECK_EQUAL(hasAB2, false);
+ BOOST_CHECK_EQUAL(hasAC, false);
+ BOOST_CHECK_EQUAL(hasAC1, false);
+ BOOST_CHECK_EQUAL(hasAC2, false);
+
+ BOOST_CHECK_EQUAL(counter, 1);
+
+ // Example
+ // /
+ // /A
+ // /A/B x
+ // /A/B/C
+ // /A/D x
+ // /E
+ // /F
+
+ NameTree nameTreeExample(nBuckets);
+
+ Name nameRoot("/");
+ bool hasRoot = false;
+
+ nameTreeExample.lookup(nameA);
+ hasA = false;
+ nameTreeExample.lookup(nameAB);
+ hasAB = false;
+
+ Name nameABC("a/b/c");
+ bool hasABC = false;
+ nameTreeExample.lookup(nameABC);
+
+ Name nameAD("/a/d");
+ nameTreeExample.lookup(nameAD);
+ bool hasAD = false;
+
+ Name nameE("/e");
+ nameTreeExample.lookup(nameE);
+ bool hasE = false;
+
+ Name nameF("/f");
+ nameTreeExample.lookup(nameF);
+ bool hasF = false;
+
+ counter = 0;
+ const_iterator itExample = nameTreeExample.partialEnumerate(nameA, &predicate_NameTreeEntry_Example);
+
+ for (; itExample != nameTreeExample.end(); itExample++)
+ {
+ counter++;
+
+ if (itExample->getPrefix() == nameRoot)
+ hasRoot = true;
+
+ if (itExample->getPrefix() == nameA)
+ hasA = true;
+
+ if (itExample->getPrefix() == nameAB)
+ hasAB = true;
+
+ if (itExample->getPrefix() == nameABC)
+ hasABC = true;
+
+ if (itExample->getPrefix() == nameAD)
+ hasAD = true;
+
+ if (itExample->getPrefix() == nameE)
+ hasE = true;
+
+ if (itExample->getPrefix() == nameF)
+ hasF = true;
+ }
+
+ BOOST_CHECK_EQUAL(hasRoot, false);
+ BOOST_CHECK_EQUAL(hasA, false);
+ BOOST_CHECK_EQUAL(hasAB, true);
+ BOOST_CHECK_EQUAL(hasABC, false);
+ BOOST_CHECK_EQUAL(hasAD, true);
+ BOOST_CHECK_EQUAL(hasE, false);
+ BOOST_CHECK_EQUAL(hasF, false);
+
+ BOOST_CHECK_EQUAL(counter, 2);
+}
+
+
+BOOST_AUTO_TEST_CASE(NameTreeIteratorFindAllMatches)
+{
+ using namespace std;
+
+ size_t nBuckets = 16;
+ NameTree nt(nBuckets);
+ int counter = 0;
+
+ Name nameABCDEF("a/b/c/d/e/f");
+ shared_ptr<name_tree::Entry> npeABCDEF = nt.lookup(nameABCDEF);
+
+ Name nameAAC("a/a/c");
+ shared_ptr<name_tree::Entry> npeAAC = nt.lookup(nameAAC);
+
+ Name nameAAD1("a/a/d/1");
+ shared_ptr<name_tree::Entry> npeAAD1 = nt.lookup(nameAAD1);
+
+ Name nameAAD2("a/a/d/2");
+ shared_ptr<name_tree::Entry> npeAAD2 = nt.lookup(nameAAD2);
+
+
+ BOOST_CHECK_EQUAL(nt.size(), 12);
+
+ Name nameRoot ("/");
+ Name nameA ("/a");
+ Name nameAB ("/a/b");
+ Name nameABC ("/a/b/c");
+ Name nameABCD ("/a/b/c/d");
+ Name nameABCDE("/a/b/c/d/e");
+ Name nameAA ("/a/a");
+ Name nameAAD ("/a/a/d");
+
+ bool hasRoot = false;
+ bool hasA = false;
+ bool hasAB = false;
+ bool hasABC = false;
+ bool hasABCD = false;
+ bool hasABCDE = false;
+ bool hasABCDEF = false;
+ bool hasAA = false;
+ bool hasAAC = false;
+ bool hasAAD = false;
+ bool hasAAD1 = false;
+ bool hasAAD2 = false;
+
+ counter = 0;
+
+ for (NameTree::const_iterator it = nt.findAllMatches(nameABCDEF);
+ it != nt.end(); it++)
+ {
+ counter++;
+
+ if (it->getPrefix() == nameRoot)
+ hasRoot = true;
+ if (it->getPrefix() == nameA)
+ hasA = true;
+ if (it->getPrefix() == nameAB)
+ hasAB = true;
+ if (it->getPrefix() == nameABC)
+ hasABC = true;
+ if (it->getPrefix() == nameABCD)
+ hasABCD = true;
+ if (it->getPrefix() == nameABCDE)
+ hasABCDE = true;
+ if (it->getPrefix() == nameABCDEF)
+ hasABCDEF = true;
+ if (it->getPrefix() == nameAA)
+ hasAA = true;
+ if (it->getPrefix() == nameAAC)
+ hasAAC = true;
+ if (it->getPrefix() == nameAAD)
+ hasAAD = true;
+ if (it->getPrefix() == nameAAD1)
+ hasAAD1 = true;
+ if (it->getPrefix() == nameAAD2)
+ hasAAD2 = true;
+ }
+
+ BOOST_CHECK_EQUAL(hasRoot , true);
+ BOOST_CHECK_EQUAL(hasA , true);
+ BOOST_CHECK_EQUAL(hasAB , true);
+ BOOST_CHECK_EQUAL(hasABC , true);
+ BOOST_CHECK_EQUAL(hasABCD , true);
+ BOOST_CHECK_EQUAL(hasABCDE , true);
+ BOOST_CHECK_EQUAL(hasABCDEF , true);
+ BOOST_CHECK_EQUAL(hasAA , false);
+ BOOST_CHECK_EQUAL(hasAAC , false);
+ BOOST_CHECK_EQUAL(hasAAD , false);
+ BOOST_CHECK_EQUAL(hasAAD1 , false);
+ BOOST_CHECK_EQUAL(hasAAD2 , false);
+
+ BOOST_CHECK_EQUAL(counter, 7);
}
BOOST_AUTO_TEST_SUITE_END()
diff --git a/tests/table/pit.cpp b/tests/table/pit.cpp
index f366ea2..5cece6a 100644
--- a/tests/table/pit.cpp
+++ b/tests/table/pit.cpp
@@ -241,50 +241,63 @@
BOOST_AUTO_TEST_CASE(FindAllDataMatches)
{
- Name nameA ("ndn:/A");
- Name nameAB ("ndn:/A/B");
- Name nameABC("ndn:/A/B/C");
- Name nameD ("ndn:/D");
- Interest interestA (nameA );
- Interest interestAB(nameAB);
- Interest interestD (nameD );
+ Name nameA ("ndn:/A");
+ Name nameAB ("ndn:/A/B");
+ Name nameABC ("ndn:/A/B/C");
+ Name nameABCD("ndn:/A/B/C/D");
+ Name nameD ("ndn:/D");
+
+ Interest interestA (nameA );
+ Interest interestABC(nameABC);
+ Interest interestD (nameD );
NameTree nameTree(16);
Pit pit(nameTree);
+ int count = 0;
BOOST_CHECK_EQUAL(pit.size(), 0);
- pit.insert(interestA );
- pit.insert(interestAB);
- pit.insert(interestD );
+ pit.insert(interestA );
+ pit.insert(interestABC);
+ pit.insert(interestD );
+
+ nameTree.lookup(nameABCD); // make sure /A/B/C/D is in nameTree
BOOST_CHECK_EQUAL(pit.size(), 3);
- Data data(nameABC);
+ Data data(nameABCD);
shared_ptr<pit::DataMatchResult> matches = pit.findAllDataMatches(data);
- int count = 0;
- bool hasA = false;
- bool hasAB = false;
- bool hasD = false;
+
+ bool hasA = false;
+ bool hasAB = false;
+ bool hasABC = false;
+ bool hasD = false;
+
for (pit::DataMatchResult::iterator it = matches->begin();
it != matches->end(); ++it) {
++count;
shared_ptr<pit::Entry> entry = *it;
- if (entry->getName().equals(nameA )) {
- hasA = true;
- }
- if (entry->getName().equals(nameAB)) {
- hasAB = true;
- }
- if (entry->getName().equals(nameD )) {
- hasD = true;
- }
+
+ if (entry->getName().equals(nameA ))
+ hasA = true;
+
+ if (entry->getName().equals(nameAB))
+ hasAB = true;
+
+ if (entry->getName().equals(nameABC))
+ hasABC = true;
+
+ if (entry->getName().equals(nameD))
+ hasD = true;
}
+ BOOST_CHECK_EQUAL(hasA , true);
+ BOOST_CHECK_EQUAL(hasAB , false);
+ BOOST_CHECK_EQUAL(hasABC, true);
+ BOOST_CHECK_EQUAL(hasD , false);
+
BOOST_CHECK_EQUAL(count, 2);
- BOOST_CHECK_EQUAL(hasA , true);
- BOOST_CHECK_EQUAL(hasAB, true);
- BOOST_CHECK_EQUAL(hasD , false);
+
}
BOOST_AUTO_TEST_SUITE_END()