2cae8cacf0
Refs: #4922 Change-Id: I2243dbb87c63f9cbaf7d7051d7a0d4bca2f9fdb5
288 lines
9.9 KiB
C++
288 lines
9.9 KiB
C++
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
|
/*
|
|
* Copyright (c) 2014-2019, Regents of the University of California,
|
|
* Arizona Board of Regents,
|
|
* Colorado State University,
|
|
* University Pierre & Marie Curie, Sorbonne University,
|
|
* Washington University in St. Louis,
|
|
* Beijing Institute of Technology,
|
|
* The University of Memphis.
|
|
*
|
|
* This file is part of NFD (Named Data Networking Forwarding Daemon).
|
|
* See AUTHORS.md for complete list of NFD authors and contributors.
|
|
*
|
|
* NFD is free software: you can redistribute it and/or modify it under the terms
|
|
* of the GNU General Public License as published by the Free Software Foundation,
|
|
* either version 3 of the License, or (at your option) any later version.
|
|
*
|
|
* NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
|
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
|
* PURPOSE. See the GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along with
|
|
* NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#ifndef NFD_DAEMON_TABLE_NAME_TREE_HPP
|
|
#define NFD_DAEMON_TABLE_NAME_TREE_HPP
|
|
|
|
#include "name-tree-iterator.hpp"
|
|
|
|
namespace nfd {
|
|
namespace name_tree {
|
|
|
|
/** \brief A common index structure for FIB, PIT, StrategyChoice, and Measurements
|
|
*/
|
|
class NameTree : noncopyable
|
|
{
|
|
public:
|
|
explicit
|
|
NameTree(size_t nBuckets = 1024);
|
|
|
|
public: // information
|
|
/** \brief Maximum depth of the name tree
|
|
*
|
|
* Calling \c NameTree::lookup with a name with many components would cause the creation of many
|
|
* NameTree entries, which could take very long time. This constant limits the maximum number of
|
|
* name components in the name of a NameTree entry. Thus, it limits the number of NameTree
|
|
* entries created from a long name, bounding the processing complexity.
|
|
*/
|
|
static constexpr size_t
|
|
getMaxDepth()
|
|
{
|
|
return 32;
|
|
}
|
|
|
|
/** \return number of name tree entries
|
|
*/
|
|
size_t
|
|
size() const
|
|
{
|
|
return m_ht.size();
|
|
}
|
|
|
|
/** \return number of hashtable buckets
|
|
*/
|
|
size_t
|
|
getNBuckets() const
|
|
{
|
|
return m_ht.getNBuckets();
|
|
}
|
|
|
|
/** \return name tree entry on which a table entry is attached,
|
|
* or nullptr if the table entry is detached
|
|
*/
|
|
template<typename EntryT>
|
|
Entry*
|
|
getEntry(const EntryT& tableEntry) const
|
|
{
|
|
return Entry::get(tableEntry);
|
|
}
|
|
|
|
public: // mutation
|
|
/** \brief Find or insert an entry by name
|
|
*
|
|
* This method seeks a name tree entry of name \c name.getPrefix(prefixLen).
|
|
* If the entry does not exist, it is created along with all ancestors.
|
|
* Existing iterators are unaffected during this operation.
|
|
*
|
|
* \warning \p prefixLen must not exceed \c name.size().
|
|
* \warning \p prefixLen must not exceed \c getMaxDepth().
|
|
*/
|
|
Entry&
|
|
lookup(const Name& name, size_t prefixLen);
|
|
|
|
/** \brief Equivalent to `lookup(name, name.size())`
|
|
*/
|
|
Entry&
|
|
lookup(const Name& name)
|
|
{
|
|
return this->lookup(name, name.size());
|
|
}
|
|
|
|
/** \brief Equivalent to `lookup(fibEntry.getPrefix())`
|
|
* \param fibEntry a FIB entry attached to this name tree, or \c Fib::s_emptyEntry
|
|
* \note This overload is more efficient than `lookup(const Name&)` in common cases.
|
|
*/
|
|
Entry&
|
|
lookup(const fib::Entry& fibEntry);
|
|
|
|
/** \brief Equivalent to `lookup(pitEntry.getName(), std::min(pitEntry.getName().size(), getMaxDepth()))`
|
|
* \param pitEntry a PIT entry attached to this name tree
|
|
* \note This overload is more efficient than `lookup(const Name&)` in common cases.
|
|
*/
|
|
Entry&
|
|
lookup(const pit::Entry& pitEntry);
|
|
|
|
/** \brief Equivalent to `lookup(measurementsEntry.getName())`
|
|
* \param measurementsEntry a Measurements entry attached to this name tree
|
|
* \note This overload is more efficient than `lookup(const Name&)` in common cases.
|
|
*/
|
|
Entry&
|
|
lookup(const measurements::Entry& measurementsEntry);
|
|
|
|
/** \brief Equivalent to `lookup(strategyChoiceEntry.getPrefix())`
|
|
* \param strategyChoiceEntry a StrategyChoice entry attached to this name tree
|
|
* \note This overload is more efficient than `lookup(const Name&)` in common cases.
|
|
*/
|
|
Entry&
|
|
lookup(const strategy_choice::Entry& strategyChoiceEntry);
|
|
|
|
/** \brief Delete the entry if it is empty
|
|
* \param entry a valid entry
|
|
* \param canEraseAncestors whether ancestors should be deleted if they become empty
|
|
* \return number of deleted entries
|
|
* \sa Entry::isEmpty()
|
|
* \post If the entry is empty, it's deleted. If \p canEraseAncestors is true,
|
|
* ancestors of the entry are also deleted if they become empty.
|
|
* \note This function must be called after detaching a table entry from a name tree entry,
|
|
* \note Existing iterators, except those pointing to deleted entries, are unaffected.
|
|
*/
|
|
size_t
|
|
eraseIfEmpty(Entry* entry, bool canEraseAncestors = true);
|
|
|
|
public: // matching
|
|
/** \brief Exact match lookup
|
|
* \return entry with \c name.getPrefix(prefixLen), or nullptr if it does not exist
|
|
*/
|
|
Entry*
|
|
findExactMatch(const Name& name, size_t prefixLen = std::numeric_limits<size_t>::max()) const;
|
|
|
|
/** \brief Longest prefix matching
|
|
* \return entry whose name is a prefix of \p name and passes \p entrySelector,
|
|
* where no other entry with a longer name satisfies those requirements;
|
|
* or nullptr if no entry satisfying those requirements exists
|
|
*/
|
|
Entry*
|
|
findLongestPrefixMatch(const Name& name,
|
|
const EntrySelector& entrySelector = AnyEntry()) const;
|
|
|
|
/** \brief Equivalent to `findLongestPrefixMatch(entry.getName(), entrySelector)`
|
|
* \note This overload is more efficient than
|
|
* `findLongestPrefixMatch(const Name&, const EntrySelector&)` in common cases.
|
|
*/
|
|
Entry*
|
|
findLongestPrefixMatch(const Entry& entry,
|
|
const EntrySelector& entrySelector = AnyEntry()) const;
|
|
|
|
/** \brief Equivalent to `findLongestPrefixMatch(getEntry(tableEntry)->getName(), entrySelector)`
|
|
* \tparam EntryT \c fib::Entry or \c measurements::Entry or \c strategy_choice::Entry
|
|
* \note This overload is more efficient than
|
|
* `findLongestPrefixMatch(const Name&, const EntrySelector&)` in common cases.
|
|
* \warning Undefined behavior may occur if \p tableEntry is not attached to this name tree.
|
|
*/
|
|
template<typename EntryT>
|
|
Entry*
|
|
findLongestPrefixMatch(const EntryT& tableEntry,
|
|
const EntrySelector& entrySelector = AnyEntry()) const
|
|
{
|
|
const Entry* nte = this->getEntry(tableEntry);
|
|
BOOST_ASSERT(nte != nullptr);
|
|
return this->findLongestPrefixMatch(*nte, entrySelector);
|
|
}
|
|
|
|
/** \brief Equivalent to `findLongestPrefixMatch(pitEntry.getName(), entrySelector)`
|
|
* \note This overload is more efficient than
|
|
* `findLongestPrefixMatch(const Name&, const EntrySelector&)` in common cases.
|
|
* \warning Undefined behavior may occur if \p pitEntry is not attached to this name tree.
|
|
*/
|
|
Entry*
|
|
findLongestPrefixMatch(const pit::Entry& pitEntry,
|
|
const EntrySelector& entrySelector = AnyEntry()) const;
|
|
|
|
/** \brief All-prefixes match lookup
|
|
* \return a range where every entry has a name that is a prefix of \p name ,
|
|
* and matches \p entrySelector.
|
|
*
|
|
* Example:
|
|
* \code
|
|
* Name name("/A/B/C");
|
|
* auto&& allMatches = nt.findAllMatches(name);
|
|
* for (const Entry& nte : allMatches) {
|
|
* BOOST_ASSERT(nte.getName().isPrefixOf(name));
|
|
* ...
|
|
* }
|
|
* \endcode
|
|
* \note Iteration order is implementation-defined.
|
|
* \warning If a name tree entry whose name is a prefix of \p name is inserted
|
|
* during the enumeration, it may or may not be visited.
|
|
* If a name tree entry whose name is a prefix of \p name is deleted
|
|
* during the enumeration, undefined behavior may occur.
|
|
*/
|
|
Range
|
|
findAllMatches(const Name& name,
|
|
const EntrySelector& entrySelector = AnyEntry()) const;
|
|
|
|
public: // enumeration
|
|
using const_iterator = Iterator;
|
|
|
|
/** \brief Enumerate all entries
|
|
* \return a range where every entry matches \p entrySelector
|
|
*
|
|
* Example:
|
|
* \code
|
|
* auto&& enumerable = nt.fullEnumerate();
|
|
* for (const Entry& nte : enumerable) {
|
|
* ...
|
|
* }
|
|
* \endcode
|
|
* \note Iteration order is implementation-defined.
|
|
* \warning If a name tree entry is inserted or deleted during the enumeration,
|
|
* it may cause the enumeration to skip entries or visit some entries twice.
|
|
*/
|
|
Range
|
|
fullEnumerate(const EntrySelector& entrySelector = AnyEntry()) const;
|
|
|
|
/** \brief Enumerate all entries under a prefix
|
|
* \return a range where every entry has a name that starts with \p prefix,
|
|
* and matches \p entrySubTreeSelector.
|
|
*
|
|
* Example:
|
|
* \code
|
|
* Name name("/A/B/C");
|
|
* auto&& enumerable = nt.partialEnumerate(name);
|
|
* for (const Entry& nte : enumerable) {
|
|
* BOOST_ASSERT(name.isPrefixOf(nte.getName()));
|
|
* ...
|
|
* }
|
|
* \endcode
|
|
* \note Iteration order is implementation-defined.
|
|
* \warning If a name tree entry under \p prefix is inserted or deleted during the enumeration,
|
|
* it may cause the enumeration to skip entries or visit some entries twice.
|
|
*/
|
|
Range
|
|
partialEnumerate(const Name& prefix,
|
|
const EntrySubTreeSelector& entrySubTreeSelector = AnyEntrySubTree()) const;
|
|
|
|
/** \return an iterator to the beginning
|
|
* \sa fullEnumerate
|
|
*/
|
|
const_iterator
|
|
begin() const
|
|
{
|
|
return fullEnumerate().begin();
|
|
}
|
|
|
|
/** \return an iterator to the end
|
|
* \sa begin()
|
|
*/
|
|
const_iterator
|
|
end() const
|
|
{
|
|
return Iterator();
|
|
}
|
|
|
|
private:
|
|
Hashtable m_ht;
|
|
|
|
friend class EnumerationImpl;
|
|
};
|
|
|
|
} // namespace name_tree
|
|
|
|
using name_tree::NameTree;
|
|
|
|
} // namespace nfd
|
|
|
|
#endif // NFD_DAEMON_TABLE_NAME_TREE_HPP
|