table: accept predicate in Measurements::findLongestPrefixMatch

This commit also deletes unused Measurements::s_defaultLifetime constant.

refs #2314

Change-Id: I6ffce7dee828f1f9aa47099777df6ee0615ce4f1
diff --git a/daemon/table/measurements.cpp b/daemon/table/measurements.cpp
index 8a24306..f9b9bd3 100644
--- a/daemon/table/measurements.cpp
+++ b/daemon/table/measurements.cpp
@@ -30,20 +30,22 @@
 
 namespace nfd {
 
+using measurements::Entry;
+
 Measurements::Measurements(NameTree& nameTree)
   : m_nameTree(nameTree)
   , m_nItems(0)
 {
 }
 
-shared_ptr<measurements::Entry>
+shared_ptr<Entry>
 Measurements::get(name_tree::Entry& nte)
 {
-  shared_ptr<measurements::Entry> entry = nte.getMeasurementsEntry();
+  shared_ptr<Entry> entry = nte.getMeasurementsEntry();
   if (entry != nullptr)
     return entry;
 
-  entry = make_shared<measurements::Entry>(nte.getPrefix());
+  entry = make_shared<Entry>(nte.getPrefix());
   nte.setMeasurementsEntry(entry);
   ++m_nItems;
 
@@ -54,29 +56,29 @@
   return entry;
 }
 
-shared_ptr<measurements::Entry>
+shared_ptr<Entry>
 Measurements::get(const Name& name)
 {
   shared_ptr<name_tree::Entry> nte = m_nameTree.lookup(name);
   return this->get(*nte);
 }
 
-shared_ptr<measurements::Entry>
+shared_ptr<Entry>
 Measurements::get(const fib::Entry& fibEntry)
 {
   shared_ptr<name_tree::Entry> nte = m_nameTree.get(fibEntry);
   return this->get(*nte);
 }
 
-shared_ptr<measurements::Entry>
+shared_ptr<Entry>
 Measurements::get(const pit::Entry& pitEntry)
 {
   shared_ptr<name_tree::Entry> nte = m_nameTree.get(pitEntry);
   return this->get(*nte);
 }
 
-shared_ptr<measurements::Entry>
-Measurements::getParent(const measurements::Entry& child)
+shared_ptr<Entry>
+Measurements::getParent(const Entry& child)
 {
   if (child.getName().size() == 0) { // the root entry
     return nullptr;
@@ -88,18 +90,22 @@
   return this->get(*nte);
 }
 
-shared_ptr<measurements::Entry>
-Measurements::findLongestPrefixMatch(const Name& name) const
+shared_ptr<Entry>
+Measurements::findLongestPrefixMatch(const Name& name,
+                                     const measurements::EntryPredicate& pred) const
 {
   shared_ptr<name_tree::Entry> nte = m_nameTree.findLongestPrefixMatch(name,
-      [] (const name_tree::Entry& nte) { return nte.getMeasurementsEntry() != nullptr; });
+      [pred] (const name_tree::Entry& nte) -> bool {
+        shared_ptr<Entry> entry = nte.getMeasurementsEntry();
+        return entry != nullptr && pred(*entry);
+      });
   if (nte != nullptr) {
     return nte->getMeasurementsEntry();
   }
   return nullptr;
 }
 
-shared_ptr<measurements::Entry>
+shared_ptr<Entry>
 Measurements::findExactMatch(const Name& name) const
 {
   shared_ptr<name_tree::Entry> nte = m_nameTree.lookup(name);
@@ -109,7 +115,7 @@
 }
 
 void
-Measurements::extendLifetime(measurements::Entry& entry,
+Measurements::extendLifetime(Entry& entry,
                              const time::nanoseconds& lifetime)
 {
   shared_ptr<name_tree::Entry> nte = m_nameTree.get(entry);
@@ -131,7 +137,7 @@
 }
 
 void
-Measurements::cleanup(measurements::Entry& entry)
+Measurements::cleanup(Entry& entry)
 {
   shared_ptr<name_tree::Entry> nte = m_nameTree.get(entry);
   if (nte != nullptr) {
diff --git a/daemon/table/measurements.hpp b/daemon/table/measurements.hpp
index 71d8db5..4d19f34 100644
--- a/daemon/table/measurements.hpp
+++ b/daemon/table/measurements.hpp
@@ -33,15 +33,44 @@
 
 namespace fib {
 class Entry;
-}
+} // namespace fib
 
 namespace pit {
 class Entry;
-}
+} // namespace pit
 
+namespace measurements {
 
-/** \class Measurement
- *  \brief represents the Measurements table
+/** \brief a predicate that accepts or rejects a \p Entry
+ */
+typedef std::function<bool(const Entry&)> EntryPredicate;
+
+/** \brief an \p EntryPredicate that accepts any \p Entry
+ */
+class AnyEntry
+{
+public:
+  bool
+  operator()(const Entry& entry)
+  {
+    return true;
+  }
+};
+
+template<typename T>
+class EntryWithStrategyInfo
+{
+public:
+  bool
+  operator()(const Entry& entry)
+  {
+    return entry.getStrategyInfo<T>() != nullptr;
+  }
+};
+
+} // namespace measurements
+
+/** \brief represents the Measurements table
  */
 class Measurements : noncopyable
 {
@@ -73,7 +102,9 @@
   /** \brief perform a longest prefix match
    */
   shared_ptr<measurements::Entry>
-  findLongestPrefixMatch(const Name& name) const;
+  findLongestPrefixMatch(const Name& name,
+                         const measurements::EntryPredicate& pred =
+                             measurements::AnyEntry()) const;
 
   /** \brief perform an exact match
    */
@@ -103,7 +134,6 @@
 private:
   NameTree& m_nameTree;
   size_t m_nItems;
-  static const time::nanoseconds s_defaultLifetime;
 };
 
 inline time::nanoseconds
diff --git a/tests/daemon/table/measurements.cpp b/tests/daemon/table/measurements.cpp
index 63254bd..4cf7f81 100644
--- a/tests/daemon/table/measurements.cpp
+++ b/tests/daemon/table/measurements.cpp
@@ -57,6 +57,49 @@
   BOOST_CHECK_EQUAL(entry0, entry0c);
 }
 
+class DummyStrategyInfo1 : public fw::StrategyInfo
+{
+public:
+  static constexpr int
+  getTypeId()
+  {
+    return 21;
+  }
+};
+
+class DummyStrategyInfo2 : public fw::StrategyInfo
+{
+public:
+  static constexpr int
+  getTypeId()
+  {
+    return 22;
+  }
+};
+
+BOOST_AUTO_TEST_CASE(FindLongestPrefixMatch)
+{
+  NameTree nameTree;
+  Measurements measurements(nameTree);
+
+  measurements.get("/A");
+  measurements.get("/A/B/C")->getOrCreateStrategyInfo<DummyStrategyInfo1>();
+  measurements.get("/A/B/C/D");
+
+  shared_ptr<measurements::Entry> found1 = measurements.findLongestPrefixMatch("/A/B/C/D/E");
+  BOOST_REQUIRE(found1 != nullptr);
+  BOOST_CHECK_EQUAL(found1->getName(), "/A/B/C/D");
+
+  shared_ptr<measurements::Entry> found2 = measurements.findLongestPrefixMatch("/A/B/C/D/E",
+      measurements::EntryWithStrategyInfo<DummyStrategyInfo1>());
+  BOOST_REQUIRE(found2 != nullptr);
+  BOOST_CHECK_EQUAL(found2->getName(), "/A/B/C");
+
+  shared_ptr<measurements::Entry> found3 = measurements.findLongestPrefixMatch("/A/B/C/D/E",
+      measurements::EntryWithStrategyInfo<DummyStrategyInfo2>());
+  BOOST_CHECK(found3 == nullptr);
+}
+
 BOOST_FIXTURE_TEST_CASE(Lifetime, UnitTestTimeFixture)
 {
   NameTree nameTree;