table: simplify StrategyChoice with C++11 features

refs #2100

Change-Id: If0082c8561d706df86e92c14cb87762962ff200b
diff --git a/daemon/mgmt/strategy-choice-manager.cpp b/daemon/mgmt/strategy-choice-manager.cpp
index 962349d..e93353b 100644
--- a/daemon/mgmt/strategy-choice-manager.cpp
+++ b/daemon/mgmt/strategy-choice-manager.cpp
@@ -162,7 +162,9 @@
   if (m_strategyChoice.insert(prefix, selectedStrategy))
     {
       NFD_LOG_DEBUG("strategy-choice result: SUCCESS");
-      parameters.setStrategy(*m_strategyChoice.get(prefix));
+      auto currentStrategyChoice = m_strategyChoice.get(prefix);
+      BOOST_ASSERT(currentStrategyChoice.first);
+      parameters.setStrategy(currentStrategyChoice.second);
       setResponse(response, 200, "Success", parameters.wireEncode());
     }
   else
diff --git a/daemon/table/strategy-choice-entry.cpp b/daemon/table/strategy-choice-entry.cpp
index 3271186..2b7a257 100644
--- a/daemon/table/strategy-choice-entry.cpp
+++ b/daemon/table/strategy-choice-entry.cpp
@@ -27,13 +27,12 @@
 #include "core/logger.hpp"
 #include "fw/strategy.hpp"
 
-NFD_LOG_INIT("StrategyChoiceEntry");
-
 namespace nfd {
 namespace strategy_choice {
 
 Entry::Entry(const Name& prefix)
   : m_prefix(prefix)
+  , m_strategy(nullptr)
 {
 }
 
@@ -43,14 +42,5 @@
   return m_strategy->getName();
 }
 
-void
-Entry::setStrategy(shared_ptr<fw::Strategy> strategy)
-{
-  BOOST_ASSERT(static_cast<bool>(strategy));
-  m_strategy = strategy;
-
-  NFD_LOG_INFO("Set strategy " << strategy->getName() << " for " << m_prefix << " prefix");
-}
-
 } // namespace strategy_choice
 } // namespace nfd
diff --git a/daemon/table/strategy-choice-entry.hpp b/daemon/table/strategy-choice-entry.hpp
index d937b1c..857a313 100644
--- a/daemon/table/strategy-choice-entry.hpp
+++ b/daemon/table/strategy-choice-entry.hpp
@@ -57,11 +57,11 @@
   getStrategy() const;
 
   void
-  setStrategy(shared_ptr<fw::Strategy> strategy);
+  setStrategy(fw::Strategy& strategy);
 
 private:
   Name m_prefix;
-  shared_ptr<fw::Strategy> m_strategy;
+  fw::Strategy* m_strategy;
 
   shared_ptr<name_tree::Entry> m_nameTreeEntry;
   friend class nfd::NameTree;
@@ -78,10 +78,16 @@
 inline fw::Strategy&
 Entry::getStrategy() const
 {
-  BOOST_ASSERT(static_cast<bool>(m_strategy));
+  BOOST_ASSERT(m_strategy != nullptr);
   return *m_strategy;
 }
 
+inline void
+Entry::setStrategy(fw::Strategy& strategy)
+{
+  m_strategy = &strategy;
+}
+
 } // namespace strategy_choice
 } // namespace nfd
 
diff --git a/daemon/table/strategy-choice.cpp b/daemon/table/strategy-choice.cpp
index c6d45ad..f39df1c 100644
--- a/daemon/table/strategy-choice.cpp
+++ b/daemon/table/strategy-choice.cpp
@@ -60,7 +60,7 @@
   BOOST_ASSERT(static_cast<bool>(strategy));
   const Name& strategyName = strategy->getName();
 
-  if (this->hasStrategy(strategyName)) {
+  if (this->hasStrategy(strategyName, true)) {
     NFD_LOG_ERROR("install(" << strategyName << ") duplicate strategyName");
     return false;
   }
@@ -69,17 +69,17 @@
   return true;
 }
 
-shared_ptr<fw::Strategy>
+fw::Strategy*
 StrategyChoice::getStrategy(const Name& strategyName) const
 {
-  shared_ptr<fw::Strategy> candidate;
-  for (StrategyInstanceTable::const_iterator it = m_strategyInstances.lower_bound(strategyName);
+  fw::Strategy* candidate = nullptr;
+  for (auto it = m_strategyInstances.lower_bound(strategyName);
        it != m_strategyInstances.end() && strategyName.isPrefixOf(it->first); ++it) {
     switch (it->first.size() - strategyName.size()) {
     case 0: // exact match
-      return it->second;
+      return it->second.get();
     case 1: // unversioned strategyName matches versioned strategy
-      candidate = it->second;
+      candidate = it->second.get();
       break;
     }
   }
@@ -89,34 +89,35 @@
 bool
 StrategyChoice::insert(const Name& prefix, const Name& strategyName)
 {
-  shared_ptr<Strategy> strategy = this->getStrategy(strategyName);
-  if (!static_cast<bool>(strategy)) {
+  Strategy* strategy = this->getStrategy(strategyName);
+  if (strategy == nullptr) {
     NFD_LOG_ERROR("insert(" << prefix << "," << strategyName << ") strategy not installed");
     return false;
   }
 
-  shared_ptr<name_tree::Entry> nameTreeEntry = m_nameTree.lookup(prefix);
-  shared_ptr<Entry> entry = nameTreeEntry->getStrategyChoiceEntry();
-  shared_ptr<Strategy> oldStrategy;
+  shared_ptr<name_tree::Entry> nte = m_nameTree.lookup(prefix);
+  shared_ptr<Entry> entry = nte->getStrategyChoiceEntry();
+  Strategy* oldStrategy = nullptr;
   if (static_cast<bool>(entry)) {
     if (entry->getStrategy().getName() == strategy->getName()) {
       NFD_LOG_TRACE("insert(" << prefix << ") not changing " << strategy->getName());
       return true;
     }
-    oldStrategy = entry->getStrategy().shared_from_this();
+    oldStrategy = &entry->getStrategy();
     NFD_LOG_TRACE("insert(" << prefix << ") changing from " << oldStrategy->getName() <<
                   " to " << strategy->getName());
   }
 
   if (!static_cast<bool>(entry)) {
-    oldStrategy = this->findEffectiveStrategy(prefix).shared_from_this();
+    oldStrategy = &this->findEffectiveStrategy(prefix);
     entry = make_shared<Entry>(prefix);
-    nameTreeEntry->setStrategyChoiceEntry(entry);
+    nte->setStrategyChoiceEntry(entry);
     ++m_nItems;
     NFD_LOG_TRACE("insert(" << prefix << ") new entry " << strategy->getName());
   }
 
-  this->changeStrategy(entry, oldStrategy, strategy);
+  this->changeStrategy(*entry, *oldStrategy, *strategy);
+  entry->setStrategy(*strategy);
   return true;
 }
 
@@ -125,12 +126,12 @@
 {
   BOOST_ASSERT(prefix.size() > 0);
 
-  shared_ptr<name_tree::Entry> nameTreeEntry = m_nameTree.findExactMatch(prefix);
-  if (!static_cast<bool>(nameTreeEntry)) {
+  shared_ptr<name_tree::Entry> nte = m_nameTree.findExactMatch(prefix);
+  if (!static_cast<bool>(nte)) {
     return;
   }
 
-  shared_ptr<Entry> entry = nameTreeEntry->getStrategyChoiceEntry();
+  shared_ptr<Entry> entry = nte->getStrategyChoiceEntry();
   if (!static_cast<bool>(entry)) {
     return;
   }
@@ -138,74 +139,73 @@
   Strategy& oldStrategy = entry->getStrategy();
 
   Strategy& parentStrategy = this->findEffectiveStrategy(prefix.getPrefix(-1));
-  this->changeStrategy(entry, oldStrategy.shared_from_this(), parentStrategy.shared_from_this());
+  this->changeStrategy(*entry, oldStrategy, parentStrategy);
 
-  nameTreeEntry->setStrategyChoiceEntry(shared_ptr<Entry>());
-  m_nameTree.eraseEntryIfEmpty(nameTreeEntry);
+  nte->setStrategyChoiceEntry(shared_ptr<Entry>());
+  m_nameTree.eraseEntryIfEmpty(nte);
   --m_nItems;
 }
 
-shared_ptr<const Name>
+std::pair<bool, Name>
 StrategyChoice::get(const Name& prefix) const
 {
-  shared_ptr<name_tree::Entry> nameTreeEntry = m_nameTree.findExactMatch(prefix);
-  if (!static_cast<bool>(nameTreeEntry)) {
-    return shared_ptr<const Name>();
+  shared_ptr<name_tree::Entry> nte = m_nameTree.findExactMatch(prefix);
+  if (!static_cast<bool>(nte)) {
+    return { false, Name() };
   }
 
-  shared_ptr<Entry> entry = nameTreeEntry->getStrategyChoiceEntry();
+  shared_ptr<Entry> entry = nte->getStrategyChoiceEntry();
   if (!static_cast<bool>(entry)) {
-    return shared_ptr<const Name>();
+    return { false, Name() };
   }
 
-  return make_shared<Name>(entry->getStrategy().getName());
-}
-
-static inline bool
-predicate_NameTreeEntry_hasStrategyChoiceEntry(const name_tree::Entry& entry)
-{
-  return static_cast<bool>(entry.getStrategyChoiceEntry());
+  return { true, entry->getStrategy().getName() };
 }
 
 Strategy&
 StrategyChoice::findEffectiveStrategy(const Name& prefix) const
 {
-  shared_ptr<name_tree::Entry> nameTreeEntry =
-    m_nameTree.findLongestPrefixMatch(prefix, &predicate_NameTreeEntry_hasStrategyChoiceEntry);
-  BOOST_ASSERT(static_cast<bool>(nameTreeEntry));
-  return nameTreeEntry->getStrategyChoiceEntry()->getStrategy();
+  shared_ptr<name_tree::Entry> nte = m_nameTree.findLongestPrefixMatch(prefix,
+    [] (const name_tree::Entry& entry) {
+      return static_cast<bool>(entry.getStrategyChoiceEntry());
+    });
+
+  BOOST_ASSERT(static_cast<bool>(nte));
+  return nte->getStrategyChoiceEntry()->getStrategy();
 }
 
 Strategy&
-StrategyChoice::findEffectiveStrategy(shared_ptr<name_tree::Entry> nameTreeEntry) const
+StrategyChoice::findEffectiveStrategy(shared_ptr<name_tree::Entry> nte) const
 {
-  shared_ptr<strategy_choice::Entry> entry = nameTreeEntry->getStrategyChoiceEntry();
+  shared_ptr<strategy_choice::Entry> entry = nte->getStrategyChoiceEntry();
   if (static_cast<bool>(entry))
     return entry->getStrategy();
-  nameTreeEntry = m_nameTree.findLongestPrefixMatch(nameTreeEntry,
-                               &predicate_NameTreeEntry_hasStrategyChoiceEntry);
-  BOOST_ASSERT(static_cast<bool>(nameTreeEntry));
-  return nameTreeEntry->getStrategyChoiceEntry()->getStrategy();
+
+  nte = m_nameTree.findLongestPrefixMatch(nte,
+    [] (const name_tree::Entry& entry) {
+      return static_cast<bool>(entry.getStrategyChoiceEntry());
+    });
+
+  BOOST_ASSERT(static_cast<bool>(nte));
+  return nte->getStrategyChoiceEntry()->getStrategy();
 }
 
 Strategy&
 StrategyChoice::findEffectiveStrategy(const pit::Entry& pitEntry) const
 {
-  shared_ptr<name_tree::Entry> nameTreeEntry = m_nameTree.get(pitEntry);
+  shared_ptr<name_tree::Entry> nte = m_nameTree.get(pitEntry);
 
-  BOOST_ASSERT(static_cast<bool>(nameTreeEntry));
-
-  return findEffectiveStrategy(nameTreeEntry);
+  BOOST_ASSERT(static_cast<bool>(nte));
+  return this->findEffectiveStrategy(nte);
 }
 
 Strategy&
 StrategyChoice::findEffectiveStrategy(const measurements::Entry& measurementsEntry) const
 {
-  shared_ptr<name_tree::Entry> nameTreeEntry = m_nameTree.get(measurementsEntry);
+  shared_ptr<name_tree::Entry> nte = m_nameTree.get(measurementsEntry);
 
-  BOOST_ASSERT(static_cast<bool>(nameTreeEntry));
-
-  return findEffectiveStrategy(nameTreeEntry);
+  BOOST_ASSERT(static_cast<bool>(nte));
+  return this->findEffectiveStrategy(nte);
 }
 
 void
@@ -215,82 +215,70 @@
 
   // don't use .insert here, because it will invoke findEffectiveStrategy
   // which expects an existing root entry
-  shared_ptr<name_tree::Entry> nameTreeEntry = m_nameTree.lookup(Name());
+  shared_ptr<name_tree::Entry> nte = m_nameTree.lookup(Name());
   shared_ptr<Entry> entry = make_shared<Entry>(Name());
-  nameTreeEntry->setStrategyChoiceEntry(entry);
+  nte->setStrategyChoiceEntry(entry);
   ++m_nItems;
-  NFD_LOG_INFO("Set default strategy " << strategy->getName());
+  NFD_LOG_INFO("setDefaultStrategy " << strategy->getName());
 
-  entry->setStrategy(strategy);
+  entry->setStrategy(*strategy);
 }
 
-/** \brief a predicate that decides whether StrategyInfo should be reset
- *
- *  StrategyInfo on a NameTree entry needs to be reset,
- *  if its effective strategy is covered by the changing StrategyChoice entry.
- */
-static inline std::pair<bool,bool>
-predicate_nameTreeEntry_needResetStrategyChoice(const name_tree::Entry& nameTreeEntry,
-                                            const name_tree::Entry& rootEntry)
+static inline void
+clearStrategyInfo(const name_tree::Entry& nte)
 {
-  if (&nameTreeEntry == &rootEntry) {
-    return std::make_pair(true, true);
+  NFD_LOG_TRACE("clearStrategyInfo " << nte.getPrefix());
+
+  for (const shared_ptr<pit::Entry>& pitEntry : nte.getPitEntries()) {
+    pitEntry->clearStrategyInfo();
+    for (const pit::InRecord& inRecord : pitEntry->getInRecords()) {
+      const_cast<pit::InRecord&>(inRecord).clearStrategyInfo();
+    }
+    for (const pit::OutRecord& outRecord : pitEntry->getOutRecords()) {
+      const_cast<pit::OutRecord&>(outRecord).clearStrategyInfo();
+    }
   }
-  if (static_cast<bool>(nameTreeEntry.getStrategyChoiceEntry())) {
-    return std::make_pair(false, false);
-  }
-  return std::make_pair(true, true);
-}
-
-static inline void
-clearStrategyInfo_pitFaceRecord(const pit::FaceRecord& pitFaceRecord)
-{
-  const_cast<pit::FaceRecord&>(pitFaceRecord).clearStrategyInfo();
-}
-
-static inline void
-clearStrategyInfo_pitEntry(shared_ptr<pit::Entry> pitEntry)
-{
-  pitEntry->clearStrategyInfo();
-  std::for_each(pitEntry->getInRecords().begin(), pitEntry->getInRecords().end(),
-                &clearStrategyInfo_pitFaceRecord);
-  std::for_each(pitEntry->getOutRecords().begin(), pitEntry->getOutRecords().end(),
-                &clearStrategyInfo_pitFaceRecord);
-}
-
-static inline void
-clearStrategyInfo(const name_tree::Entry& nameTreeEntry)
-{
-  NFD_LOG_TRACE("clearStrategyInfo " << nameTreeEntry.getPrefix());
-
-  std::for_each(nameTreeEntry.getPitEntries().begin(), nameTreeEntry.getPitEntries().end(),
-                &clearStrategyInfo_pitEntry);
-  if (static_cast<bool>(nameTreeEntry.getMeasurementsEntry())) {
-    nameTreeEntry.getMeasurementsEntry()->clearStrategyInfo();
+  if (static_cast<bool>(nte.getMeasurementsEntry())) {
+    nte.getMeasurementsEntry()->clearStrategyInfo();
   }
 }
 
 void
-StrategyChoice::changeStrategy(shared_ptr<strategy_choice::Entry> entry,
-                               shared_ptr<fw::Strategy> oldStrategy,
-                               shared_ptr<fw::Strategy> newStrategy)
+StrategyChoice::changeStrategy(strategy_choice::Entry& entry,
+                               fw::Strategy& oldStrategy,
+                               fw::Strategy& newStrategy)
 {
-  entry->setStrategy(newStrategy);
-  if (oldStrategy == newStrategy) {
+  if (&oldStrategy == &newStrategy) {
     return;
   }
 
-  std::for_each(m_nameTree.partialEnumerate(entry->getPrefix(),
-                           bind(&predicate_nameTreeEntry_needResetStrategyChoice,
-                                _1, cref(*m_nameTree.get(*entry)))),
-                m_nameTree.end(),
-                &clearStrategyInfo);
+  NFD_LOG_INFO("changeStrategy(" << entry.getPrefix() << ")"
+               << " from " << oldStrategy.getName()
+               << " to " << newStrategy.getName());
+
+  // reset StrategyInfo on a portion of NameTree,
+  // where entry's effective strategy is covered by the changing StrategyChoice entry
+  const name_tree::Entry* rootNte = m_nameTree.get(entry).get();
+  auto ntChanged = m_nameTree.partialEnumerate(entry.getPrefix(),
+    [&rootNte] (const name_tree::Entry& nte) -> std::pair<bool, bool> {
+      if (&nte == rootNte) {
+        return { true, true };
+      }
+      if (static_cast<bool>(nte.getStrategyChoiceEntry())) {
+        return { false, false };
+      }
+      return { true, true };
+    });
+  std::for_each(ntChanged, m_nameTree.end(), &clearStrategyInfo);
 }
 
 StrategyChoice::const_iterator
 StrategyChoice::begin() const
 {
-  return const_iterator(m_nameTree.fullEnumerate(&predicate_NameTreeEntry_hasStrategyChoiceEntry));
+  return const_iterator(m_nameTree.fullEnumerate(
+    [] (const name_tree::Entry& entry) {
+      return static_cast<bool>(entry.getStrategyChoiceEntry());
+    }));
 }
 
 } // namespace nfd
diff --git a/daemon/table/strategy-choice.hpp b/daemon/table/strategy-choice.hpp
index d454a29..fdff3ab 100644
--- a/daemon/table/strategy-choice.hpp
+++ b/daemon/table/strategy-choice.hpp
@@ -57,6 +57,7 @@
 
   /** \brief install a strategy
    *  \return true if installed; false if not installed due to duplicate strategyName
+   *  \note shared_ptr is passed by value because StrategyChoice takes ownership of strategy
    */
   bool
   install(shared_ptr<fw::Strategy> strategy);
@@ -82,9 +83,9 @@
   erase(const Name& prefix);
 
   /** \brief get strategy Name of prefix
-   *  \return strategyName at exact match, or nullptr
+   *  \return true and strategyName at exact match, or false
    */
-  shared_ptr<const Name>
+  std::pair<bool, Name>
   get(const Name& prefix) const;
 
 public: // effective strategy
@@ -146,19 +147,19 @@
   /** \brief get Strategy instance by strategyName
    *  \param strategyName a versioned or unversioned strategyName
    */
-  shared_ptr<fw::Strategy>
+  fw::Strategy*
   getStrategy(const Name& strategyName) const;
 
   void
   setDefaultStrategy(shared_ptr<fw::Strategy> strategy);
 
   void
-  changeStrategy(shared_ptr<strategy_choice::Entry> entry,
-                 shared_ptr<fw::Strategy> oldStrategy,
-                 shared_ptr<fw::Strategy> newStrategy);
+  changeStrategy(strategy_choice::Entry& entry,
+                 fw::Strategy& oldStrategy,
+                 fw::Strategy& newStrategy);
 
   fw::Strategy&
-  findEffectiveStrategy(shared_ptr<name_tree::Entry> nameTreeEntry) const;
+  findEffectiveStrategy(shared_ptr<name_tree::Entry> nte) const;
 
 private:
   NameTree& m_nameTree;