table: allow strategy versioning

refs #1893

Change-Id: I44eb8dd319d737d786b6ce6f753ae2f9076cf9c1
diff --git a/daemon/table/strategy-choice.cpp b/daemon/table/strategy-choice.cpp
index aa5db1b..6500191 100644
--- a/daemon/table/strategy-choice.cpp
+++ b/daemon/table/strategy-choice.cpp
@@ -44,9 +44,14 @@
 }
 
 bool
-StrategyChoice::hasStrategy(const Name& strategyName) const
+StrategyChoice::hasStrategy(const Name& strategyName, bool isExact) const
 {
-  return m_strategyInstances.count(strategyName) > 0;
+  if (isExact) {
+    return m_strategyInstances.count(strategyName) > 0;
+  }
+  else {
+    return static_cast<bool>(this->getStrategy(strategyName));
+  }
 }
 
 bool
@@ -64,35 +69,51 @@
   return true;
 }
 
+shared_ptr<fw::Strategy>
+StrategyChoice::getStrategy(const Name& strategyName) const
+{
+  shared_ptr<fw::Strategy> candidate;
+  for (StrategyInstanceTable::const_iterator 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;
+    case 1: // unversioned strategyName matches versioned strategy
+      candidate = it->second;
+      break;
+    }
+  }
+  return candidate;
+}
+
 bool
 StrategyChoice::insert(const Name& prefix, const Name& strategyName)
 {
-  shared_ptr<name_tree::Entry> nameTreeEntry = m_nameTree.lookup(prefix);
-  shared_ptr<Entry> entry = nameTreeEntry->getStrategyChoiceEntry();
-  shared_ptr<Strategy> oldStrategy;
-
-  if (static_cast<bool>(entry)) {
-    if (entry->getStrategy().getName() == strategyName) {
-      NFD_LOG_TRACE("insert(" << prefix << "," << strategyName << ") not changing");
-      return true;
-    }
-    oldStrategy = entry->getStrategy().shared_from_this();
-    NFD_LOG_TRACE("insert(" << prefix << "," << strategyName << ") "
-                  "changing from " << oldStrategy->getName());
-  }
-
   shared_ptr<Strategy> strategy = this->getStrategy(strategyName);
   if (!static_cast<bool>(strategy)) {
     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;
+  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();
+    NFD_LOG_TRACE("insert(" << prefix << ") changing from " << oldStrategy->getName() <<
+                  " to " << strategy->getName());
+  }
+
   if (!static_cast<bool>(entry)) {
     oldStrategy = this->findEffectiveStrategy(prefix).shared_from_this();
     entry = make_shared<Entry>(prefix);
     nameTreeEntry->setStrategyChoiceEntry(entry);
     ++m_nItems;
-    NFD_LOG_TRACE("insert(" << prefix << "," << strategyName << ") new entry");
+    NFD_LOG_TRACE("insert(" << prefix << ") new entry " << strategy->getName());
   }
 
   this->changeStrategy(entry, oldStrategy, strategy);
@@ -187,13 +208,6 @@
   return findEffectiveStrategy(nameTreeEntry);
 }
 
-shared_ptr<fw::Strategy>
-StrategyChoice::getStrategy(const Name& strategyName)
-{
-  StrategyInstanceTable::iterator it = m_strategyInstances.find(strategyName);
-  return it != m_strategyInstances.end() ? it->second : shared_ptr<fw::Strategy>();
-}
-
 void
 StrategyChoice::setDefaultStrategy(shared_ptr<Strategy> strategy)
 {