fw: UnsolicitedDataPolicy registry

refs #2181

Change-Id: I39f5dd02a224f9d872bde29f29aab05f64bb6e06
diff --git a/daemon/fw/unsolicited-data-policy.cpp b/daemon/fw/unsolicited-data-policy.cpp
index 67d4d37..dd68e38 100644
--- a/daemon/fw/unsolicited-data-policy.cpp
+++ b/daemon/fw/unsolicited-data-policy.cpp
@@ -40,12 +40,31 @@
   return os << static_cast<int>(d);
 }
 
+UnsolicitedDataPolicy::Registry&
+UnsolicitedDataPolicy::getRegistry()
+{
+  static Registry registry;
+  return registry;
+}
+
+unique_ptr<UnsolicitedDataPolicy>
+UnsolicitedDataPolicy::create(const std::string& key)
+{
+  Registry& registry = getRegistry();
+  auto i = registry.find(key);
+  return i == registry.end() ? nullptr : i->second();
+}
+
+NFD_REGISTER_UNSOLICITED_DATA_POLICY(DropAllUnsolicitedDataPolicy, "drop-all");
+
 UnsolicitedDataDecision
 DropAllUnsolicitedDataPolicy::decide(const Face& inFace, const Data& data) const
 {
   return UnsolicitedDataDecision::DROP;
 }
 
+NFD_REGISTER_UNSOLICITED_DATA_POLICY(AdmitLocalUnsolicitedDataPolicy, "admit-local");
+
 UnsolicitedDataDecision
 AdmitLocalUnsolicitedDataPolicy::decide(const Face& inFace, const Data& data) const
 {
@@ -55,6 +74,8 @@
   return UnsolicitedDataDecision::DROP;
 }
 
+NFD_REGISTER_UNSOLICITED_DATA_POLICY(AdmitNetworkUnsolicitedDataPolicy, "admit-network");
+
 UnsolicitedDataDecision
 AdmitNetworkUnsolicitedDataPolicy::decide(const Face& inFace, const Data& data) const
 {
@@ -64,30 +85,13 @@
   return UnsolicitedDataDecision::DROP;
 }
 
+NFD_REGISTER_UNSOLICITED_DATA_POLICY(AdmitAllUnsolicitedDataPolicy, "admit-all");
+
 UnsolicitedDataDecision
 AdmitAllUnsolicitedDataPolicy::decide(const Face& inFace, const Data& data) const
 {
   return UnsolicitedDataDecision::CACHE;
 }
 
-unique_ptr<UnsolicitedDataPolicy>
-makeUnsolicitedDataPolicy(const std::string& key)
-{
-  /// \todo register policy with a macro
-  if (key == "drop-all") {
-    return make_unique<DropAllUnsolicitedDataPolicy>();
-  }
-  if (key == "admit-local") {
-    return make_unique<AdmitLocalUnsolicitedDataPolicy>();
-  }
-  if (key == "admit-network") {
-    return make_unique<AdmitNetworkUnsolicitedDataPolicy>();
-  }
-  if (key == "admit-all") {
-    return make_unique<AdmitAllUnsolicitedDataPolicy>();
-  }
-  return nullptr;
-}
-
 } // namespace fw
 } // namespace nfd
diff --git a/daemon/fw/unsolicited-data-policy.hpp b/daemon/fw/unsolicited-data-policy.hpp
index f6ca771..62b64dc 100644
--- a/daemon/fw/unsolicited-data-policy.hpp
+++ b/daemon/fw/unsolicited-data-policy.hpp
@@ -54,6 +54,28 @@
 
   virtual UnsolicitedDataDecision
   decide(const Face& inFace, const Data& data) const = 0;
+
+public: // registry
+  template<typename P>
+  static void
+  registerPolicy(const std::string& key)
+  {
+    Registry& registry = getRegistry();
+    BOOST_ASSERT(registry.count(key) == 0);
+    registry[key] = [] { return make_unique<P>(); };
+  }
+
+  /** \return an UnsolicitedDataPolicy identified by \p key, or nullptr if \p key is unknown
+   */
+  static unique_ptr<UnsolicitedDataPolicy>
+  create(const std::string& key);
+
+private:
+  typedef std::function<unique_ptr<UnsolicitedDataPolicy>()> CreateFunc;
+  typedef std::map<std::string, CreateFunc> Registry; // indexed by key
+
+  static Registry&
+  getRegistry();
 };
 
 /** \brief drops all unsolicited Data
@@ -92,11 +114,6 @@
   decide(const Face& inFace, const Data& data) const final;
 };
 
-/** \return an UnsolicitedDataPolicy identified by \p key, or nullptr if \p key is unknown
- */
-unique_ptr<UnsolicitedDataPolicy>
-makeUnsolicitedDataPolicy(const std::string& key);
-
 /** \brief the default UnsolicitedDataPolicy
  */
 typedef DropAllUnsolicitedDataPolicy DefaultUnsolicitedDataPolicy;
@@ -104,4 +121,18 @@
 } // namespace fw
 } // namespace nfd
 
+/** \brief registers an unsolicited data policy
+ *  \param P a subclass of nfd::fw::UnsolicitedDataPolicy
+ *  \param key the policy keyword, which is available for selection in NFD config file
+ */
+#define NFD_REGISTER_UNSOLICITED_DATA_POLICY(P, key)                \
+static class NfdAuto ## P ## UnsolicitedDataPolicyRegistrationClass \
+{                                                                   \
+public:                                                             \
+  NfdAuto ## P ## UnsolicitedDataPolicyRegistrationClass()          \
+  {                                                                 \
+    ::nfd::fw::UnsolicitedDataPolicy::registerPolicy<P>(key);       \
+  }                                                                 \
+} g_nfdAuto ## P ## UnsolicitedDataPolicyRegistrationVariable
+
 #endif // NFD_DAEMON_FW_UNSOLICITED_DATA_POLICY_HPP
diff --git a/daemon/mgmt/tables-config-section.cpp b/daemon/mgmt/tables-config-section.cpp
index 2773a24..397f26c 100644
--- a/daemon/mgmt/tables-config-section.cpp
+++ b/daemon/mgmt/tables-config-section.cpp
@@ -70,7 +70,7 @@
   OptionalNode unsolicitedDataPolicyNode = section.get_child_optional("cs_unsolicited_policy");
   if (unsolicitedDataPolicyNode) {
     std::string policyKey = unsolicitedDataPolicyNode->get_value<std::string>();
-    unsolicitedDataPolicy = fw::makeUnsolicitedDataPolicy(policyKey);
+    unsolicitedDataPolicy = fw::UnsolicitedDataPolicy::create(policyKey);
     if (unsolicitedDataPolicy == nullptr) {
       BOOST_THROW_EXCEPTION(ConfigFile::Error(
         "Unknown cs_unsolicited_policy \"" + policyKey + "\" in \"tables\" section"));