table: StrategyInfoHost stores StrategyInfo as unique_ptr

refs #3205

Change-Id: Ia194ca94717347848d257096549cfec5df1ba6c9
diff --git a/daemon/fw/access-strategy.cpp b/daemon/fw/access-strategy.cpp
index a7eed83..9401968 100644
--- a/daemon/fw/access-strategy.cpp
+++ b/daemon/fw/access-strategy.cpp
@@ -69,7 +69,7 @@
 {
   const fib::Entry& fibEntry = this->lookupFib(*pitEntry);
   Name miName;
-  shared_ptr<MtInfo> mi;
+  MtInfo* mi = nullptr;
   std::tie(miName, mi) = this->findPrefixMeasurements(*pitEntry);
 
   // has measurements for Interest Name?
@@ -136,7 +136,7 @@
   this->sendInterest(pitEntry, *face);
 
   // schedule RTO timeout
-  shared_ptr<PitInfo> pi = pitEntry->insertStrategyInfo<PitInfo>();
+  PitInfo* pi = pitEntry->insertStrategyInfo<PitInfo>().first;
   pi->rtoTimer = scheduler::schedule(rto,
       bind(&AccessStrategy::afterRtoTimeout, this, weak_ptr<pit::Entry>(pitEntry),
            inFace.getId(), mi.lastNexthop));
@@ -177,7 +177,7 @@
 AccessStrategy::beforeSatisfyInterest(const shared_ptr<pit::Entry>& pitEntry,
                                       const Face& inFace, const Data& data)
 {
-  shared_ptr<PitInfo> pi = pitEntry->getStrategyInfo<PitInfo>();
+  PitInfo* pi = pitEntry->getStrategyInfo<PitInfo>();
   if (pi != nullptr) {
     pi->rtoTimer.cancel();
   }
@@ -208,7 +208,7 @@
   FaceInfo& fi = m_fit[inFace.getId()];
   fi.rtt.addMeasurement(rtt);
 
-  shared_ptr<MtInfo> mi = this->addPrefixMeasurements(data);
+  MtInfo* mi = this->addPrefixMeasurements(data);
   if (mi->lastNexthop != inFace.getId()) {
     mi->lastNexthop = inFace.getId();
     mi->rtt = fi.rtt;
@@ -224,7 +224,7 @@
 {
 }
 
-std::tuple<Name, shared_ptr<AccessStrategy::MtInfo>>
+std::tuple<Name, AccessStrategy::MtInfo*>
 AccessStrategy::findPrefixMeasurements(const pit::Entry& pitEntry)
 {
   measurements::Entry* me = this->getMeasurements().findLongestPrefixMatch(pitEntry);
@@ -232,14 +232,14 @@
     return std::make_tuple(Name(), nullptr);
   }
 
-  shared_ptr<MtInfo> mi = me->getStrategyInfo<MtInfo>();
+  MtInfo* mi = me->getStrategyInfo<MtInfo>();
   BOOST_ASSERT(mi != nullptr);
   // XXX after runtime strategy change, it's possible that me exists but mi doesn't exist;
   // this case needs another longest prefix match until mi is found
   return std::make_tuple(me->getName(), mi);
 }
 
-shared_ptr<AccessStrategy::MtInfo>
+AccessStrategy::MtInfo*
 AccessStrategy::addPrefixMeasurements(const Data& data)
 {
   measurements::Entry* me = nullptr;
@@ -255,7 +255,7 @@
   static const time::nanoseconds ME_LIFETIME = time::seconds(8);
   this->getMeasurements().extendLifetime(*me, ME_LIFETIME);
 
-  return me->insertStrategyInfo<MtInfo>();
+  return me->insertStrategyInfo<MtInfo>().first;
 }
 
 AccessStrategy::FaceInfo::FaceInfo()
diff --git a/daemon/fw/access-strategy.hpp b/daemon/fw/access-strategy.hpp
index b71f2c6..223d596 100644
--- a/daemon/fw/access-strategy.hpp
+++ b/daemon/fw/access-strategy.hpp
@@ -97,13 +97,13 @@
 
   /** \brief find per-prefix measurements for Interest
    */
-  std::tuple<Name, shared_ptr<MtInfo>>
+  std::tuple<Name, MtInfo*>
   findPrefixMeasurements(const pit::Entry& pitEntry);
 
   /** \brief get or create pre-prefix measurements for incoming Data
    *  \note This function creates MtInfo but doesn't update it.
    */
-  shared_ptr<MtInfo>
+  MtInfo*
   addPrefixMeasurements(const Data& data);
 
   /** \brief global per-face StrategyInfo
diff --git a/daemon/fw/asf-measurements.cpp b/daemon/fw/asf-measurements.cpp
index c7f68c9..c98ca86 100644
--- a/daemon/fw/asf-measurements.cpp
+++ b/daemon/fw/asf-measurements.cpp
@@ -76,7 +76,7 @@
 }
 
 void
-FaceInfo::setTimeoutEvent(const scheduler::EventId& id, const ndn::Name& interestName)
+FaceInfo::setTimeoutEvent(const scheduler::EventId& id, const Name& interestName)
 {
   if (!m_isTimeoutScheduled) {
     m_timeoutEventId = id;
@@ -96,7 +96,7 @@
 }
 
 void
-FaceInfo::cancelTimeoutEvent(const ndn::Name& prefix)
+FaceInfo::cancelTimeoutEvent(const Name& prefix)
 {
   if (isTimeoutScheduled() && doesNameMatchLastInterest(prefix)) {
     cancelTimeoutEvent();
@@ -104,7 +104,7 @@
 }
 
 bool
-FaceInfo::doesNameMatchLastInterest(const ndn::Name& name)
+FaceInfo::doesNameMatchLastInterest(const Name& name)
 {
   return m_lastInterestName.isPrefixOf(name);
 }
@@ -125,7 +125,7 @@
 }
 
 void
-FaceInfo::recordTimeout(const ndn::Name& interestName)
+FaceInfo::recordTimeout(const Name& interestName)
 {
   m_rttStats.recordTimeout();
   cancelTimeoutEvent(interestName);
@@ -203,24 +203,23 @@
 }
 
 FaceInfo*
-AsfMeasurements::getFaceInfo(const fib::Entry& fibEntry, const ndn::Interest& interest, const Face& face)
+AsfMeasurements::getFaceInfo(const fib::Entry& fibEntry, const Interest& interest, const Face& face)
 {
   NamespaceInfo& info = getOrCreateNamespaceInfo(fibEntry, interest);
   return info.getFaceInfo(fibEntry, face);
 }
 
 FaceInfo&
-AsfMeasurements::getOrCreateFaceInfo(const fib::Entry& fibEntry, const ndn::Interest& interest, const Face& face)
+AsfMeasurements::getOrCreateFaceInfo(const fib::Entry& fibEntry, const Interest& interest, const Face& face)
 {
   NamespaceInfo& info = getOrCreateNamespaceInfo(fibEntry, interest);
   return info.getOrCreateFaceInfo(fibEntry, face);
 }
 
-shared_ptr<NamespaceInfo>
-AsfMeasurements::getNamespaceInfo(const ndn::Name& prefix)
+NamespaceInfo*
+AsfMeasurements::getNamespaceInfo(const Name& prefix)
 {
   measurements::Entry* me = m_measurements.findLongestPrefixMatch(prefix);
-
   if (me == nullptr) {
     return nullptr;
   }
@@ -228,14 +227,13 @@
   // Set or update entry lifetime
   extendLifetime(*me);
 
-  shared_ptr<NamespaceInfo> info = me->insertStrategyInfo<NamespaceInfo>();
+  NamespaceInfo* info = me->insertStrategyInfo<NamespaceInfo>().first;
   BOOST_ASSERT(info != nullptr);
-
   return info;
 }
 
 NamespaceInfo&
-AsfMeasurements::getOrCreateNamespaceInfo(const fib::Entry& fibEntry, const ndn::Interest& interest)
+AsfMeasurements::getOrCreateNamespaceInfo(const fib::Entry& fibEntry, const Interest& interest)
 {
   measurements::Entry* me = m_measurements.get(fibEntry);
 
@@ -252,9 +250,8 @@
   // Set or update entry lifetime
   extendLifetime(*me);
 
-  shared_ptr<NamespaceInfo> info = me->insertStrategyInfo<NamespaceInfo>();
+  NamespaceInfo* info = me->insertStrategyInfo<NamespaceInfo>().first;
   BOOST_ASSERT(info != nullptr);
-
   return *info;
 }
 
diff --git a/daemon/fw/asf-measurements.hpp b/daemon/fw/asf-measurements.hpp
index 205219d..0988837 100644
--- a/daemon/fw/asf-measurements.hpp
+++ b/daemon/fw/asf-measurements.hpp
@@ -107,7 +107,7 @@
   ~FaceInfo();
 
   void
-  setTimeoutEvent(const scheduler::EventId& id, const ndn::Name& interestName);
+  setTimeoutEvent(const scheduler::EventId& id, const Name& interestName);
 
   void
   setMeasurementExpirationEventId(const scheduler::EventId& id)
@@ -122,7 +122,7 @@
   }
 
   void
-  cancelTimeoutEvent(const ndn::Name& prefix);
+  cancelTimeoutEvent(const Name& prefix);
 
   bool
   isTimeoutScheduled() const
@@ -134,7 +134,7 @@
   recordRtt(const shared_ptr<pit::Entry>& pitEntry, const Face& inFace);
 
   void
-  recordTimeout(const ndn::Name& interestName);
+  recordTimeout(const Name& interestName);
 
   bool
   isTimeout() const
@@ -171,11 +171,11 @@
   cancelTimeoutEvent();
 
   bool
-  doesNameMatchLastInterest(const ndn::Name& name);
+  doesNameMatchLastInterest(const Name& name);
 
 private:
   RttStats m_rttStats;
-  ndn::Name m_lastInterestName;
+  Name m_lastInterestName;
 
   // Timeout associated with measurement
   scheduler::EventId m_measurementExpirationId;
@@ -283,16 +283,16 @@
   AsfMeasurements(MeasurementsAccessor& measurements);
 
   FaceInfo*
-  getFaceInfo(const fib::Entry& fibEntry, const ndn::Interest& interest, const Face& face);
+  getFaceInfo(const fib::Entry& fibEntry, const Interest& interest, const Face& face);
 
   FaceInfo&
-  getOrCreateFaceInfo(const fib::Entry& fibEntry, const ndn::Interest& interest, const Face& face);
+  getOrCreateFaceInfo(const fib::Entry& fibEntry, const Interest& interest, const Face& face);
 
-  shared_ptr<NamespaceInfo>
-  getNamespaceInfo(const ndn::Name& prefix);
+  NamespaceInfo*
+  getNamespaceInfo(const Name& prefix);
 
   NamespaceInfo&
-  getOrCreateNamespaceInfo(const fib::Entry& fibEntry, const ndn::Interest& interest);
+  getOrCreateNamespaceInfo(const fib::Entry& fibEntry, const Interest& interest);
 
 private:
   void
diff --git a/daemon/fw/asf-probing-module.cpp b/daemon/fw/asf-probing-module.cpp
index d60a215..99449cd 100644
--- a/daemon/fw/asf-probing-module.cpp
+++ b/daemon/fw/asf-probing-module.cpp
@@ -47,11 +47,11 @@
 void
 ProbingModule::scheduleProbe(const fib::Entry& fibEntry, const time::milliseconds& interval)
 {
-  ndn::Name prefix = fibEntry.getPrefix();
+  Name prefix = fibEntry.getPrefix();
 
   // Set the probing flag for the namespace to true after passed interval of time
   scheduler::schedule(interval, [this, prefix] {
-    shared_ptr<NamespaceInfo> info = m_measurements.getNamespaceInfo(prefix);
+    NamespaceInfo* info = m_measurements.getNamespaceInfo(prefix);
 
     if (info == nullptr) {
       // fib::Entry with the passed prefix has been removed or the fib::Entry has
@@ -112,7 +112,7 @@
 }
 
 bool
-ProbingModule::isProbingNeeded(const fib::Entry& fibEntry, const ndn::Interest& interest)
+ProbingModule::isProbingNeeded(const fib::Entry& fibEntry, const Interest& interest)
 {
   // Return the probing status flag for a namespace
   NamespaceInfo& info = m_measurements.getOrCreateNamespaceInfo(fibEntry, interest);
@@ -130,7 +130,7 @@
 }
 
 void
-ProbingModule::afterForwardingProbe(const fib::Entry& fibEntry, const ndn::Interest& interest)
+ProbingModule::afterForwardingProbe(const fib::Entry& fibEntry, const Interest& interest)
 {
   // After probing is done, need to set probing flag to false and
   // schedule another future probe
diff --git a/daemon/fw/asf-probing-module.hpp b/daemon/fw/asf-probing-module.hpp
index 3a4df6e..055adb0 100644
--- a/daemon/fw/asf-probing-module.hpp
+++ b/daemon/fw/asf-probing-module.hpp
@@ -50,10 +50,10 @@
                  const Face& faceUsed);
 
   bool
-  isProbingNeeded(const fib::Entry& fibEntry, const ndn::Interest& interest);
+  isProbingNeeded(const fib::Entry& fibEntry, const Interest& interest);
 
   void
-  afterForwardingProbe(const fib::Entry& fibEntry, const ndn::Interest& interest);
+  afterForwardingProbe(const fib::Entry& fibEntry, const Interest& interest);
 
 private:
   // Used to associate FaceInfo with the face in a NextHop
diff --git a/daemon/fw/asf-strategy.cpp b/daemon/fw/asf-strategy.cpp
index 9ed2c77..657656c 100644
--- a/daemon/fw/asf-strategy.cpp
+++ b/daemon/fw/asf-strategy.cpp
@@ -103,7 +103,7 @@
 AsfStrategy::beforeSatisfyInterest(const shared_ptr<pit::Entry>& pitEntry,
                                    const Face& inFace, const Data& data)
 {
-  shared_ptr<NamespaceInfo> namespaceInfo = m_measurements.getNamespaceInfo(pitEntry->getName());
+  NamespaceInfo* namespaceInfo = m_measurements.getNamespaceInfo(pitEntry->getName());
 
   if (namespaceInfo == nullptr) {
     NFD_LOG_TRACE("Could not find measurements entry for " << pitEntry->getName());
@@ -254,7 +254,7 @@
 {
   NFD_LOG_TRACE("FaceId: " << faceId << " for " << interestName << " has timed-out");
 
-  shared_ptr<NamespaceInfo> namespaceInfo = m_measurements.getNamespaceInfo(interestName);
+  NamespaceInfo* namespaceInfo = m_measurements.getNamespaceInfo(interestName);
 
   if (namespaceInfo == nullptr) {
     NFD_LOG_TRACE("FibEntry for " << interestName << " has been removed since timeout scheduling");
diff --git a/daemon/fw/ncc-strategy.cpp b/daemon/fw/ncc-strategy.cpp
index c56eef4..f1a888a 100644
--- a/daemon/fw/ncc-strategy.cpp
+++ b/daemon/fw/ncc-strategy.cpp
@@ -54,7 +54,7 @@
     return;
   }
 
-  shared_ptr<PitEntryInfo> pitEntryInfo = pitEntry->insertStrategyInfo<PitEntryInfo>();
+  PitEntryInfo* pitEntryInfo = pitEntry->insertStrategyInfo<PitEntryInfo>().first;
   bool isNewPitEntry = !hasPendingOutRecords(*pitEntry);
   if (!isNewPitEntry) {
     return;
@@ -118,7 +118,7 @@
   }
   const fib::Entry& fibEntry = this->lookupFib(*pitEntry);
 
-  shared_ptr<PitEntryInfo> pitEntryInfo = pitEntry->getStrategyInfo<PitEntryInfo>();
+  PitEntryInfo* pitEntryInfo = pitEntry->getStrategyInfo<PitEntryInfo>();
   // pitEntryInfo is guaranteed to exist here, because doPropagate is triggered
   // from a timer set by NccStrategy.
   BOOST_ASSERT(pitEntryInfo != nullptr);
@@ -199,7 +199,7 @@
     measurementsEntry = this->getMeasurements().getParent(*measurementsEntry);
   }
 
-  shared_ptr<PitEntryInfo> pitEntryInfo = pitEntry->getStrategyInfo<PitEntryInfo>();
+  PitEntryInfo* pitEntryInfo = pitEntry->getStrategyInfo<PitEntryInfo>();
   if (pitEntryInfo != nullptr) {
     scheduler::cancel(pitEntryInfo->propagateTimer);
 
@@ -223,14 +223,13 @@
 NccStrategy::getMeasurementsEntryInfo(measurements::Entry* entry)
 {
   BOOST_ASSERT(entry != nullptr);
-  shared_ptr<MeasurementsEntryInfo> info = entry->getStrategyInfo<MeasurementsEntryInfo>();
-  if (info != nullptr) {
+  MeasurementsEntryInfo* info = nullptr;
+  bool isNew = false;
+  std::tie(info, isNew) = entry->insertStrategyInfo<MeasurementsEntryInfo>();
+  if (!isNew) {
     return *info;
   }
 
-  info = make_shared<MeasurementsEntryInfo>();
-  entry->setStrategyInfo(info);
-
   measurements::Entry* parentEntry = this->getMeasurements().getParent(*entry);
   if (parentEntry != nullptr) {
     MeasurementsEntryInfo& parentInfo = this->getMeasurementsEntryInfo(parentEntry);
diff --git a/daemon/fw/retx-suppression-exponential.cpp b/daemon/fw/retx-suppression-exponential.cpp
index 5edff29..aabc719 100644
--- a/daemon/fw/retx-suppression-exponential.cpp
+++ b/daemon/fw/retx-suppression-exponential.cpp
@@ -82,7 +82,7 @@
   time::steady_clock::TimePoint now = time::steady_clock::now();
   time::steady_clock::Duration sinceLastOutgoing = now - lastOutgoing;
 
-  shared_ptr<PitInfo> pi = pitEntry.insertStrategyInfo<PitInfo>(m_initialInterval);
+  PitInfo* pi = pitEntry.insertStrategyInfo<PitInfo>(m_initialInterval).first;
   bool shouldSuppress = sinceLastOutgoing < pi->suppressionInterval;
 
   if (shouldSuppress) {
diff --git a/daemon/table/strategy-info-host.hpp b/daemon/table/strategy-info-host.hpp
index 23b5fcc..db88558 100644
--- a/daemon/table/strategy-info-host.hpp
+++ b/daemon/table/strategy-info-host.hpp
@@ -40,7 +40,7 @@
    *  \return an existing StrategyInfo item of type T, or nullptr if it does not exist
    */
   template<typename T>
-  shared_ptr<T>
+  T*
   getStrategyInfo() const
   {
     static_assert(std::is_base_of<fw::StrategyInfo, T>::value,
@@ -50,44 +50,41 @@
     if (it == m_items.end()) {
       return nullptr;
     }
-    return static_pointer_cast<T, fw::StrategyInfo>(it->second);
-  }
-
-  /** \brief set a StrategyInfo item
-   *  \tparam T type of StrategyInfo, must be a subclass of nfd::fw::StrategyInfo
-   */
-  template<typename T>
-  void
-  setStrategyInfo(shared_ptr<T> item)
-  {
-    static_assert(std::is_base_of<fw::StrategyInfo, T>::value,
-                  "T must inherit from StrategyInfo");
-
-    if (item == nullptr) {
-      m_items.erase(T::getTypeId());
-    }
-    else {
-      m_items[T::getTypeId()] = item;
-    }
+    return static_cast<T*>(it->second.get());
   }
 
   /** \brief insert a StrategyInfo item
    *  \tparam T type of StrategyInfo, must be a subclass of fw::StrategyInfo
-   *  \return a new or existing StrategyInfo item of type T
+   *  \return a new or existing StrategyInfo item of type T,
+   *          and true for new item, false for existing item
    */
   template<typename T, typename ...A>
-  shared_ptr<T>
+  std::pair<T*, bool>
   insertStrategyInfo(A&&... args)
   {
     static_assert(std::is_base_of<fw::StrategyInfo, T>::value,
                   "T must inherit from StrategyInfo");
 
-    shared_ptr<T> item = this->getStrategyInfo<T>();
-    if (!static_cast<bool>(item)) {
-      item = std::make_shared<T>(std::forward<A>(args)...);
-      this->setStrategyInfo(item);
+    unique_ptr<fw::StrategyInfo>& item = m_items[T::getTypeId()];
+    bool isNew = (item == nullptr);
+    if (isNew) {
+      item.reset(new T(std::forward<A>(args)...));
     }
-    return item;
+    return {static_cast<T*>(item.get()), isNew};
+  }
+
+  /** \brief erase a StrategyInfo item
+   *  \tparam T type of StrategyInfo, must be a subclass of fw::StrategyInfo
+   *  \return number of items erased
+   */
+  template<typename T>
+  size_t
+  eraseStrategyInfo()
+  {
+    static_assert(std::is_base_of<fw::StrategyInfo, T>::value,
+                  "T must inherit from StrategyInfo");
+
+    return m_items.erase(T::getTypeId());
   }
 
   /** \brief clear all StrategyInfo items
@@ -96,7 +93,7 @@
   clearStrategyInfo();
 
 private:
-  std::map<int, shared_ptr<fw::StrategyInfo>> m_items;
+  std::unordered_map<int, unique_ptr<fw::StrategyInfo>> m_items;
 };
 
 } // namespace nfd
diff --git a/tests/daemon/fw/ncc-strategy.t.cpp b/tests/daemon/fw/ncc-strategy.t.cpp
index f3b34b6..cc32201 100644
--- a/tests/daemon/fw/ncc-strategy.t.cpp
+++ b/tests/daemon/fw/ncc-strategy.t.cpp
@@ -341,7 +341,7 @@
   topo.addIntervalConsumer(consumer->getClientFace(), "ndn:/P",
                            time::milliseconds(100), 300);
 
-  auto getMeInfo = [&] () -> shared_ptr<NccStrategy::MeasurementsEntryInfo> {
+  auto getMeInfo = [&] () -> NccStrategy::MeasurementsEntryInfo* {
     Measurements& measurements = topo.getForwarder(nodeA).getMeasurements();
     measurements::Entry* me = measurements.findExactMatch("ndn:/P");
     return me == nullptr ? nullptr : me->getStrategyInfo<NccStrategy::MeasurementsEntryInfo>();
diff --git a/tests/daemon/table/strategy-info-host.t.cpp b/tests/daemon/table/strategy-info-host.t.cpp
index 4eaf9b0..0a3dc2a 100644
--- a/tests/daemon/table/strategy-info-host.t.cpp
+++ b/tests/daemon/table/strategy-info-host.t.cpp
@@ -34,7 +34,7 @@
 
 static int g_DummyStrategyInfo_count = 0;
 
-class DummyStrategyInfo : public StrategyInfo
+class DummyStrategyInfo : public StrategyInfo, noncopyable
 {
 public:
   static constexpr int
@@ -55,10 +55,11 @@
     --g_DummyStrategyInfo_count;
   }
 
+public:
   int m_id;
 };
 
-class DummyStrategyInfo2 : public StrategyInfo
+class DummyStrategyInfo2 : public StrategyInfo, noncopyable
 {
 public:
   static constexpr int
@@ -72,55 +73,44 @@
   {
   }
 
+public:
   int m_id;
 };
 
-BOOST_FIXTURE_TEST_SUITE(TableStrategyInfoHost, BaseFixture)
+BOOST_AUTO_TEST_SUITE(Table)
+BOOST_FIXTURE_TEST_SUITE(TestStrategyInfoHost, BaseFixture)
 
-BOOST_AUTO_TEST_CASE(SetGetClear)
+BOOST_AUTO_TEST_CASE(Basic)
 {
   StrategyInfoHost host;
-
-  BOOST_CHECK(host.getStrategyInfo<DummyStrategyInfo>() == nullptr);
-
   g_DummyStrategyInfo_count = 0;
+  bool isNew = false;
 
-  shared_ptr<DummyStrategyInfo> info = make_shared<DummyStrategyInfo>(7591);
-  host.setStrategyInfo(info);
-  BOOST_REQUIRE(host.getStrategyInfo<DummyStrategyInfo>() != nullptr);
-  BOOST_CHECK_EQUAL(host.getStrategyInfo<DummyStrategyInfo>()->m_id, 7591);
+  DummyStrategyInfo* info = nullptr;
+  std::tie(info, isNew) = host.insertStrategyInfo<DummyStrategyInfo>(3503);
+  BOOST_CHECK_EQUAL(isNew, true);
+  BOOST_CHECK_EQUAL(g_DummyStrategyInfo_count, 1);
+  BOOST_REQUIRE(info != nullptr);
+  BOOST_CHECK_EQUAL(info->m_id, 3503);
+  BOOST_CHECK_EQUAL(host.getStrategyInfo<DummyStrategyInfo>(), info);
 
-  info.reset(); // unlink local reference
-  // host should still have a reference to info
-  BOOST_REQUIRE(host.getStrategyInfo<DummyStrategyInfo>() != nullptr);
-  BOOST_CHECK_EQUAL(host.getStrategyInfo<DummyStrategyInfo>()->m_id, 7591);
+  DummyStrategyInfo* info2 = nullptr;
+  std::tie(info2, isNew) = host.insertStrategyInfo<DummyStrategyInfo>(1032);
+  BOOST_CHECK_EQUAL(isNew, false);
+  BOOST_CHECK_EQUAL(g_DummyStrategyInfo_count, 1);
+  BOOST_CHECK_EQUAL(info2, info);
+  BOOST_CHECK_EQUAL(info->m_id, 3503);
+  BOOST_CHECK_EQUAL(host.getStrategyInfo<DummyStrategyInfo>(), info);
 
   host.clearStrategyInfo();
   BOOST_CHECK(host.getStrategyInfo<DummyStrategyInfo>() == nullptr);
   BOOST_CHECK_EQUAL(g_DummyStrategyInfo_count, 0);
 }
 
-BOOST_AUTO_TEST_CASE(Create)
-{
-  StrategyInfoHost host;
-
-  host.insertStrategyInfo<DummyStrategyInfo>(3503);
-  BOOST_REQUIRE(host.getStrategyInfo<DummyStrategyInfo>() != nullptr);
-  BOOST_CHECK_EQUAL(host.getStrategyInfo<DummyStrategyInfo>()->m_id, 3503);
-
-  host.insertStrategyInfo<DummyStrategyInfo>(1032);
-  BOOST_REQUIRE(host.getStrategyInfo<DummyStrategyInfo>() != nullptr);
-  BOOST_CHECK_EQUAL(host.getStrategyInfo<DummyStrategyInfo>()->m_id, 3503);
-
-  host.setStrategyInfo<DummyStrategyInfo>(nullptr);
-  host.insertStrategyInfo<DummyStrategyInfo>(9956);
-  BOOST_REQUIRE(host.getStrategyInfo<DummyStrategyInfo>() != nullptr);
-  BOOST_CHECK_EQUAL(host.getStrategyInfo<DummyStrategyInfo>()->m_id, 9956);
-}
-
 BOOST_AUTO_TEST_CASE(Types)
 {
   StrategyInfoHost host;
+  g_DummyStrategyInfo_count = 0;
 
   host.insertStrategyInfo<DummyStrategyInfo>(8063);
   BOOST_REQUIRE(host.getStrategyInfo<DummyStrategyInfo>() != nullptr);
@@ -132,9 +122,17 @@
 
   BOOST_REQUIRE(host.getStrategyInfo<DummyStrategyInfo>() != nullptr);
   BOOST_CHECK_EQUAL(host.getStrategyInfo<DummyStrategyInfo>()->m_id, 8063);
+
+  BOOST_CHECK_EQUAL(host.eraseStrategyInfo<DummyStrategyInfo>(), 1);
+  BOOST_CHECK(host.getStrategyInfo<DummyStrategyInfo>() == nullptr);
+  BOOST_CHECK_EQUAL(g_DummyStrategyInfo_count, 0);
+  BOOST_CHECK(host.getStrategyInfo<DummyStrategyInfo2>() != nullptr);
+
+  BOOST_CHECK_EQUAL(host.eraseStrategyInfo<DummyStrategyInfo>(), 0);
 }
 
-BOOST_AUTO_TEST_SUITE_END()
+BOOST_AUTO_TEST_SUITE_END() // TestStrategyInfoHost
+BOOST_AUTO_TEST_SUITE_END() // Table
 
 } // namespace tests
 } // namespace nfd