table: CS policy registry

refs #3148

Change-Id: I058357839e514787405952569d1abf402375d1ea
diff --git a/daemon/table/cs-policy-lru.cpp b/daemon/table/cs-policy-lru.cpp
index dad467d..5b2f104 100644
--- a/daemon/table/cs-policy-lru.cpp
+++ b/daemon/table/cs-policy-lru.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /**
- * Copyright (c) 2014-2015,  Regents of the University of California,
+ * Copyright (c) 2014-2016,  Regents of the University of California,
  *                           Arizona Board of Regents,
  *                           Colorado State University,
  *                           University Pierre & Marie Curie, Sorbonne University,
@@ -25,13 +25,13 @@
 
 #include "cs-policy-lru.hpp"
 #include "cs.hpp"
-#include <ndn-cxx/util/signal.hpp>
 
 namespace nfd {
 namespace cs {
 namespace lru {
 
 const std::string LruPolicy::POLICY_NAME = "lru";
+NFD_REGISTER_CS_POLICY(LruPolicy);
 
 LruPolicy::LruPolicy()
   : Policy(POLICY_NAME)
diff --git a/daemon/table/cs-policy-lru.hpp b/daemon/table/cs-policy-lru.hpp
index 2cef234..59e3e57 100644
--- a/daemon/table/cs-policy-lru.hpp
+++ b/daemon/table/cs-policy-lru.hpp
@@ -27,7 +27,6 @@
 #define NFD_DAEMON_TABLE_CS_POLICY_LRU_HPP
 
 #include "cs-policy.hpp"
-#include "core/common.hpp"
 
 #include <boost/multi_index_container.hpp>
 #include <boost/multi_index/sequenced_index.hpp>
diff --git a/daemon/table/cs-policy-priority-fifo.cpp b/daemon/table/cs-policy-priority-fifo.cpp
index fa2027b..a61f334 100644
--- a/daemon/table/cs-policy-priority-fifo.cpp
+++ b/daemon/table/cs-policy-priority-fifo.cpp
@@ -1,6 +1,6 @@
 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
 /**
- * Copyright (c) 2014-2015,  Regents of the University of California,
+ * Copyright (c) 2014-2016,  Regents of the University of California,
  *                           Arizona Board of Regents,
  *                           Colorado State University,
  *                           University Pierre & Marie Curie, Sorbonne University,
@@ -25,13 +25,13 @@
 
 #include "cs-policy-priority-fifo.hpp"
 #include "cs.hpp"
-#include <ndn-cxx/util/signal.hpp>
 
 namespace nfd {
 namespace cs {
 namespace priority_fifo {
 
-const std::string PriorityFifoPolicy::POLICY_NAME = "fifo";
+const std::string PriorityFifoPolicy::POLICY_NAME = "priority_fifo";
+NFD_REGISTER_CS_POLICY(PriorityFifoPolicy);
 
 PriorityFifoPolicy::PriorityFifoPolicy()
   : Policy(POLICY_NAME)
@@ -160,6 +160,6 @@
   m_entryInfoMap[i] = entryInfo;
 }
 
-} // namespace priorityfifo
+} // namespace priority_fifo
 } // namespace cs
 } // namespace nfd
diff --git a/daemon/table/cs-policy.cpp b/daemon/table/cs-policy.cpp
index 4e37aad..77101ac 100644
--- a/daemon/table/cs-policy.cpp
+++ b/daemon/table/cs-policy.cpp
@@ -32,6 +32,21 @@
 namespace nfd {
 namespace cs {
 
+Policy::Registry&
+Policy::getRegistry()
+{
+  static Registry registry;
+  return registry;
+}
+
+unique_ptr<Policy>
+Policy::create(const std::string& key)
+{
+  Registry& registry = getRegistry();
+  auto i = registry.find(key);
+  return i == registry.end() ? nullptr : i->second();
+}
+
 Policy::Policy(const std::string& policyName)
   : m_policyName(policyName)
 {
diff --git a/daemon/table/cs-policy.hpp b/daemon/table/cs-policy.hpp
index b5f0200..2da1979 100644
--- a/daemon/table/cs-policy.hpp
+++ b/daemon/table/cs-policy.hpp
@@ -38,6 +38,22 @@
  */
 class Policy : noncopyable
 {
+public: // registry
+  template<typename P>
+  static void
+  registerPolicy()
+  {
+    const std::string& key = P::POLICY_NAME;
+    Registry& registry = getRegistry();
+    BOOST_ASSERT(registry.count(key) == 0);
+    registry[key] = [] { return make_unique<P>(); };
+  }
+
+  /** \return a Policy identified by \p key, or nullptr if \p key is unknown
+   */
+  static unique_ptr<Policy>
+  create(const std::string& key);
+
 public:
   explicit
   Policy(const std::string& policyName);
@@ -155,6 +171,13 @@
 protected:
   DECLARE_SIGNAL_EMIT(beforeEvict)
 
+private: // registry
+  typedef std::function<unique_ptr<Policy>()> CreateFunc;
+  typedef std::map<std::string, CreateFunc> Registry; // indexed by key
+
+  static Registry&
+  getRegistry();
+
 private:
   std::string m_policyName;
   size_t m_limit;
@@ -188,4 +211,17 @@
 } // namespace cs
 } // namespace nfd
 
+/** \brief registers a CS policy
+ *  \param P a subclass of nfd::cs::Policy
+ */
+#define NFD_REGISTER_CS_POLICY(P)                      \
+static class NfdAuto ## P ## CsPolicyRegistrationClass \
+{                                                      \
+public:                                                \
+  NfdAuto ## P ## CsPolicyRegistrationClass()          \
+  {                                                    \
+    ::nfd::cs::Policy::registerPolicy<P>();            \
+  }                                                    \
+} g_nfdAuto ## P ## CsPolicyRegistrationVariable
+
 #endif // NFD_DAEMON_TABLE_CS_POLICY_HPP
diff --git a/daemon/table/cs.cpp b/daemon/table/cs.cpp
index 8578a0d..0dd5ca2 100644
--- a/daemon/table/cs.cpp
+++ b/daemon/table/cs.cpp
@@ -24,7 +24,6 @@
  */
 
 #include "cs.hpp"
-#include "cs-policy-priority-fifo.hpp"
 #include "core/logger.hpp"
 #include "core/algorithm.hpp"
 #include <ndn-cxx/lp/tags.hpp>
@@ -48,12 +47,13 @@
 unique_ptr<Policy>
 makeDefaultPolicy()
 {
-  return make_unique<PriorityFifoPolicy>();
+  const std::string DEFAULT_POLICY = "priority_fifo";
+  return Policy::create(DEFAULT_POLICY);
 }
 
 Cs::Cs(size_t nMaxPackets, unique_ptr<Policy> policy)
 {
-  this->setPolicyImpl(policy);
+  this->setPolicyImpl(std::move(policy));
   m_policy->setLimit(nMaxPackets);
 }
 
@@ -75,7 +75,7 @@
   BOOST_ASSERT(policy != nullptr);
   BOOST_ASSERT(m_policy != nullptr);
   size_t limit = m_policy->getLimit();
-  this->setPolicyImpl(policy);
+  this->setPolicyImpl(std::move(policy));
   m_policy->setLimit(limit);
 }
 
@@ -200,8 +200,9 @@
 }
 
 void
-Cs::setPolicyImpl(unique_ptr<Policy>& policy)
+Cs::setPolicyImpl(unique_ptr<Policy> policy)
 {
+  NFD_LOG_DEBUG("set-policy " << policy->getName());
   m_policy = std::move(policy);
   m_beforeEvictConnection = m_policy->beforeEvict.connect([this] (iterator it) {
       m_table.erase(it);
diff --git a/daemon/table/cs.hpp b/daemon/table/cs.hpp
index 3a9b1ca..8c3e46b 100644
--- a/daemon/table/cs.hpp
+++ b/daemon/table/cs.hpp
@@ -178,7 +178,7 @@
   findRightmostAmongExact(const Interest& interest, iterator first, iterator last) const;
 
   void
-  setPolicyImpl(unique_ptr<Policy>& policy);
+  setPolicyImpl(unique_ptr<Policy> policy);
 
 private:
   Table m_table;