table: NameTree::findLongestPrefixMatch accepts all table entry types

This simplifies longest prefix match procedures in FIB and StrategyChoice.

refs #3687

Change-Id: I9aa93232124b91bae7890d065337ac9389e8398e
diff --git a/daemon/table/fib.cpp b/daemon/table/fib.cpp
index 4834783..022bb93 100644
--- a/daemon/table/fib.cpp
+++ b/daemon/table/fib.cpp
@@ -59,10 +59,11 @@
 {
 }
 
+template<typename K>
 const Entry&
-Fib::findLongestPrefixMatch(const Name& prefix) const
+Fib::findLongestPrefixMatchImpl(const K& key) const
 {
-  name_tree::Entry* nte = m_nameTree.findLongestPrefixMatch(prefix, &nteHasFibEntry);
+  name_tree::Entry* nte = m_nameTree.findLongestPrefixMatch(key, &nteHasFibEntry);
   if (nte != nullptr) {
     return *nte->getFibEntry();
   }
@@ -70,34 +71,21 @@
 }
 
 const Entry&
-Fib::findLongestPrefixMatch(const name_tree::Entry& nte) const
+Fib::findLongestPrefixMatch(const Name& prefix) const
 {
-  Entry* entry = nte.getFibEntry();
-  if (entry != nullptr)
-    return *entry;
-
-  const name_tree::Entry* nte2 = m_nameTree.findLongestPrefixMatch(nte, &nteHasFibEntry);
-  if (nte2 != nullptr) {
-    return *nte2->getFibEntry();
-  }
-
-  return *s_emptyEntry;
+  return this->findLongestPrefixMatchImpl(prefix);
 }
 
 const Entry&
 Fib::findLongestPrefixMatch(const pit::Entry& pitEntry) const
 {
-  name_tree::Entry* nte = m_nameTree.findLongestPrefixMatch(pitEntry);
-  BOOST_ASSERT(nte != nullptr);
-  return findLongestPrefixMatch(*nte);
+  return this->findLongestPrefixMatchImpl(pitEntry);
 }
 
 const Entry&
 Fib::findLongestPrefixMatch(const measurements::Entry& measurementsEntry) const
 {
-  name_tree::Entry* nte = m_nameTree.getEntry(measurementsEntry);
-  BOOST_ASSERT(nte != nullptr);
-  return findLongestPrefixMatch(*nte);
+  return this->findLongestPrefixMatchImpl(measurementsEntry);
 }
 
 Entry*
@@ -149,10 +137,11 @@
 Fib::erase(const Entry& entry)
 {
   name_tree::Entry* nte = m_nameTree.getEntry(entry);
-  if (nte != nullptr) {
-    // don't try to erase s_emptyEntry
-    this->erase(nte);
+  if (nte == nullptr) { // don't try to erase s_emptyEntry
+    BOOST_ASSERT(&entry == s_emptyEntry.get());
+    return;
   }
+  this->erase(nte);
 }
 
 void
diff --git a/daemon/table/fib.hpp b/daemon/table/fib.hpp
index 0a44166..eb10850 100644
--- a/daemon/table/fib.hpp
+++ b/daemon/table/fib.hpp
@@ -147,8 +147,11 @@
   };
 
 private:
+  /** \tparam K a parameter acceptable to NameTree::findLongestPrefixMatch
+   */
+  template<typename K>
   const Entry&
-  findLongestPrefixMatch(const name_tree::Entry& nte) const;
+  findLongestPrefixMatchImpl(const K& key) const;
 
   void
   erase(name_tree::Entry* nte, bool canDeleteNte = true);
diff --git a/daemon/table/measurements.hpp b/daemon/table/measurements.hpp
index dd593f6..80c938a 100644
--- a/daemon/table/measurements.hpp
+++ b/daemon/table/measurements.hpp
@@ -136,7 +136,7 @@
   Entry&
   get(name_tree::Entry& nte);
 
-  /** \tparam K a parameter acceptable by NameTree::findLongestPrefixMatch
+  /** \tparam K a parameter acceptable to NameTree::findLongestPrefixMatch
    */
   template<typename K>
   Entry*
diff --git a/daemon/table/name-tree.cpp b/daemon/table/name-tree.cpp
index 90e953e..b806cd4 100644
--- a/daemon/table/name-tree.cpp
+++ b/daemon/table/name-tree.cpp
@@ -175,6 +175,26 @@
   return nullptr;
 }
 
+template<typename ENTRY>
+Entry*
+NameTree::findLongestPrefixMatch(const ENTRY& tableEntry, const EntrySelector& entrySelector) const
+{
+  const Entry* nte = this->getEntry(tableEntry);
+  BOOST_ASSERT(nte != nullptr);
+  return this->findLongestPrefixMatch(*nte, entrySelector);
+}
+
+template Entry*
+NameTree::findLongestPrefixMatch<fib::Entry>(const fib::Entry&, const EntrySelector&) const;
+
+template Entry*
+NameTree::findLongestPrefixMatch<measurements::Entry>(const measurements::Entry&,
+                                                      const EntrySelector&) const;
+
+template Entry*
+NameTree::findLongestPrefixMatch<strategy_choice::Entry>(const strategy_choice::Entry&,
+                                                         const EntrySelector&) const;
+
 Entry*
 NameTree::findLongestPrefixMatch(const pit::Entry& pitEntry, const EntrySelector& entrySelector) const
 {
diff --git a/daemon/table/name-tree.hpp b/daemon/table/name-tree.hpp
index 9c21f7e..9ddf0ff 100644
--- a/daemon/table/name-tree.hpp
+++ b/daemon/table/name-tree.hpp
@@ -99,7 +99,7 @@
   Entry&
   lookup(const measurements::Entry& measurementsEntry);
 
-  /** \brief equivalent to .lookup(strategyChoiceEntry.getName())
+  /** \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.
    */
@@ -142,9 +142,21 @@
   findLongestPrefixMatch(const Entry& entry,
                          const EntrySelector& entrySelector = AnyEntry()) const;
 
-  /** \brief equivalent to .findLongestPrefixMatch(pitEntry.getName(), AnyEntry())
+  /** \brief equivalent to .findLongestPrefixMatch(getEntry(tableEntry)->getName(), entrySelector)
+   *  \tparam ENTRY fib::Entry or measurements::Entry or strategy_choice::Entry
    *  \note This overload is more efficient than
    *        .findLongestPrefixMatch(const Name&, const EntrySelector&) in common cases.
+   *  \warning Undefined behavior may occur if tableEntry is not attached to this name tree.
+   */
+  template<typename ENTRY>
+  Entry*
+  findLongestPrefixMatch(const ENTRY& tableEntry,
+                         const EntrySelector& entrySelector = AnyEntry()) const;
+
+  /** \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 pitEntry is not attached to this name tree.
    */
   Entry*
   findLongestPrefixMatch(const pit::Entry& pitEntry,
diff --git a/daemon/table/strategy-choice.cpp b/daemon/table/strategy-choice.cpp
index 76c19ab..be10945 100644
--- a/daemon/table/strategy-choice.cpp
+++ b/daemon/table/strategy-choice.cpp
@@ -171,40 +171,31 @@
   return {true, entry->getStrategy().getName()};
 }
 
+template<typename K>
 Strategy&
-StrategyChoice::findEffectiveStrategy(const Name& prefix) const
+StrategyChoice::findEffectiveStrategyImpl(const K& key) const
 {
-  name_tree::Entry* nte = m_nameTree.findLongestPrefixMatch(prefix, &nteHasStrategyChoiceEntry);
+  const name_tree::Entry* nte = m_nameTree.findLongestPrefixMatch(key, &nteHasStrategyChoiceEntry);
   BOOST_ASSERT(nte != nullptr);
   return nte->getStrategyChoiceEntry()->getStrategy();
 }
 
 Strategy&
-StrategyChoice::findEffectiveStrategy(const name_tree::Entry& nte) const
+StrategyChoice::findEffectiveStrategy(const Name& prefix) const
 {
-  Entry* entry = nte.getStrategyChoiceEntry();
-  if (entry != nullptr)
-    return entry->getStrategy();
-
-  const name_tree::Entry* nte2 = m_nameTree.findLongestPrefixMatch(nte, &nteHasStrategyChoiceEntry);
-  BOOST_ASSERT(nte2 != nullptr);
-  return nte2->getStrategyChoiceEntry()->getStrategy();
+  return this->findEffectiveStrategyImpl(prefix);
 }
 
 Strategy&
 StrategyChoice::findEffectiveStrategy(const pit::Entry& pitEntry) const
 {
-  const name_tree::Entry* nte = m_nameTree.findLongestPrefixMatch(pitEntry);
-  BOOST_ASSERT(nte != nullptr);
-  return this->findEffectiveStrategy(*nte);
+  return this->findEffectiveStrategyImpl(pitEntry);
 }
 
 Strategy&
 StrategyChoice::findEffectiveStrategy(const measurements::Entry& measurementsEntry) const
 {
-  const name_tree::Entry* nte = m_nameTree.getEntry(measurementsEntry);
-  BOOST_ASSERT(nte != nullptr);
-  return this->findEffectiveStrategy(*nte);
+  return this->findEffectiveStrategyImpl(measurementsEntry);
 }
 
 void
diff --git a/daemon/table/strategy-choice.hpp b/daemon/table/strategy-choice.hpp
index 1388cbb..75d3a47 100644
--- a/daemon/table/strategy-choice.hpp
+++ b/daemon/table/strategy-choice.hpp
@@ -166,8 +166,11 @@
                  fw::Strategy& oldStrategy,
                  fw::Strategy& newStrategy);
 
+  /** \tparam K a parameter acceptable to NameTree::findLongestPrefixMatch
+   */
+  template<typename K>
   fw::Strategy&
-  findEffectiveStrategy(const name_tree::Entry& nte) const;
+  findEffectiveStrategyImpl(const K& key) const;
 
 private:
   NameTree& m_nameTree;