face: ProtocolFactory registry

refs #3904

Change-Id: Ic7c8b3d6138b7c27d4189a2e15cc646055ad1294
diff --git a/daemon/face/protocol-factory.hpp b/daemon/face/protocol-factory.hpp
index 328d46e..48f755a 100644
--- a/daemon/face/protocol-factory.hpp
+++ b/daemon/face/protocol-factory.hpp
@@ -44,6 +44,31 @@
  */
 class ProtocolFactory : noncopyable
 {
+public: // registry
+  /** \brief register a protocol factory type
+   *  \tparam S subclass of ProtocolFactory
+   *  \param id factory identifier
+   */
+  template<typename PF>
+  static void
+  registerType(const std::string& id = PF::getId())
+  {
+    Registry& registry = getRegistry();
+    BOOST_ASSERT(registry.count(id) == 0);
+    registry[id] = &make_unique<PF>;
+  }
+
+  /** \return a protocol factory instance
+   *  \retval nullptr if factory with \p id is not registered
+   */
+  static unique_ptr<ProtocolFactory>
+  create(const std::string& id);
+
+  /** \return registered protocol factory ids
+   */
+  static std::set<std::string>
+  listRegistered();
+
 public:
   /**
    * \brief Base class for all exceptions thrown by protocol factories
@@ -58,6 +83,18 @@
     }
   };
 
+  virtual
+  ~ProtocolFactory() = default;
+
+#ifdef DOXYGEN
+  /** \return protocol factory id
+   *
+   *  face_system.factory-id config section is processed by the protocol factory.
+   */
+  static const std::string&
+  getId();
+#endif
+
   /** \brief process face_system subsection that corresponds to this ProtocolFactory type
    *  \param configSection the configuration section or boost::null to indicate it is omitted
    *  \param context provides access to data structures and contextual information
@@ -114,6 +151,13 @@
     return channels;
   }
 
+private: // registry
+  typedef std::function<unique_ptr<ProtocolFactory>()> CreateFunc;
+  typedef std::map<std::string, CreateFunc> Registry; // indexed by factory id
+
+  static Registry&
+  getRegistry();
+
 protected:
   /** \brief FaceUri schemes provided by this ProtocolFactory
    */
@@ -126,4 +170,18 @@
 
 } // namespace nfd
 
+/** \brief registers a protocol factory
+ *
+ *  This macro should appear once in .cpp of each protocol factory.
+ */
+#define NFD_REGISTER_PROTOCOL_FACTORY(PF)                      \
+static class NfdAuto ## PF ## ProtocolFactoryRegistrationClass \
+{                                                              \
+public:                                                        \
+  NfdAuto ## PF ## ProtocolFactoryRegistrationClass()          \
+  {                                                            \
+    ::nfd::face::ProtocolFactory::registerType<PF>();          \
+  }                                                            \
+} g_nfdAuto ## PF ## ProtocolFactoryRegistrationVariable
+
 #endif // NFD_DAEMON_FACE_PROTOCOL_FACTORY_HPP