Caffe2 - C++ API
A deep learning, cross platform ML framework
registry.h
1 
5 #ifndef CAFFE2_CORE_REGISTRY_H_
6 #define CAFFE2_CORE_REGISTRY_H_
7 
8 #include <algorithm>
9 #include <cstdlib>
10 #include <functional>
11 #include <iostream>
12 #include <memory>
13 #include <mutex>
14 
15 #include "caffe2/core/common.h"
16 #include "caffe2/core/typeid.h"
17 
18 namespace caffe2 {
19 
30 template <class SrcType, class ObjectType, class... Args>
31 class Registry {
32  public:
33  typedef std::function<std::unique_ptr<ObjectType> (Args ...)> Creator;
34 
35  Registry() : registry_() {}
36 
37  void Register(const SrcType& key, Creator creator) {
38  // The if statement below is essentially the same as the following line:
39  // CHECK_EQ(registry_.count(key), 0) << "Key " << key
40  // << " registered twice.";
41  // However, CHECK_EQ depends on google logging, and since registration is
42  // carried out at static initialization time, we do not want to have an
43  // explicit dependency on glog's initialization function.
44  std::lock_guard<std::mutex> lock(register_mutex_);
45  if (registry_.count(key) != 0) {
46  std::cerr << "Key " << key << " already registered." << std::endl;
47  std::exit(1);
48  }
49  registry_[key] = creator;
50  }
51 
52  void Register(const SrcType& key, Creator creator, const string& help_msg) {
53  Register(key, creator);
54  help_message_[key] = help_msg;
55  }
56 
57  inline bool Has(const SrcType& key) { return (registry_.count(key) != 0); }
58 
59  unique_ptr<ObjectType> Create(const SrcType& key, Args ... args) {
60  if (registry_.count(key) == 0) {
61  // Returns nullptr if the key is not registered.
62  return nullptr;
63  }
64  return registry_[key](args...);
65  }
66 
70  vector<SrcType> Keys() {
71  vector<SrcType> keys;
72  for (const auto& it : registry_) {
73  keys.push_back(it.first);
74  }
75  return keys;
76  }
77 
78  const CaffeMap<SrcType, string>& HelpMessage() const {
79  return help_message_;
80  }
81 
82  const char* HelpMessage(const SrcType& key) const {
83  auto it = help_message_.find(key);
84  if (it == help_message_.end()) {
85  return nullptr;
86  }
87  return it->second.c_str();
88  }
89 
90  private:
91  CaffeMap<SrcType, Creator> registry_;
92  CaffeMap<SrcType, string> help_message_;
93  std::mutex register_mutex_;
94 
95  DISABLE_COPY_AND_ASSIGN(Registry);
96 };
97 
98 template <class SrcType, class ObjectType, class... Args>
99 class Registerer {
100  public:
101  Registerer(const SrcType& key,
103  typename Registry<SrcType, ObjectType, Args...>::Creator creator,
104  const string& help_msg="") {
105  registry->Register(key, creator, help_msg);
106  }
107 
108  template <class DerivedType>
109  static unique_ptr<ObjectType> DefaultCreator(Args ... args) {
110  // TODO(jiayq): old versions of NVCC does not handle make_unique well
111  // so we are forced to use a unique_ptr constructor here. Check if it is
112  // fine to use make_unique in the future.
113  // return make_unique<DerivedType>(args...);
114  return std::unique_ptr<ObjectType>(new DerivedType(args...));
115  }
116 };
117 
123 #define CAFFE_CONCATENATE_IMPL(s1, s2) s1##s2
124 #define CAFFE_CONCATENATE(s1, s2) CAFFE_CONCATENATE_IMPL(s1, s2)
125 #ifdef __COUNTER__
126 #define CAFFE_ANONYMOUS_VARIABLE(str) CAFFE_CONCATENATE(str, __COUNTER__)
127 #else
128 #define CAFFE_ANONYMOUS_VARIABLE(str) CAFFE_CONCATENATE(str, __LINE__)
129 #endif
130 
136 #define CAFFE_DECLARE_TYPED_REGISTRY(RegistryName, SrcType, ObjectType, ...) \
137  Registry<SrcType, ObjectType, ##__VA_ARGS__>* RegistryName(); \
138  typedef Registerer<SrcType, ObjectType, ##__VA_ARGS__> \
139  Registerer##RegistryName;
140 
141 #define CAFFE_DEFINE_TYPED_REGISTRY(RegistryName, SrcType, ObjectType, ...) \
142  Registry<SrcType, ObjectType, ##__VA_ARGS__>* RegistryName() { \
143  static Registry<SrcType, ObjectType, ##__VA_ARGS__>* registry = \
144  new Registry<SrcType, ObjectType, ##__VA_ARGS__>(); \
145  return registry; \
146  }
147 
148 // Note(Yangqing): The __VA_ARGS__ below allows one to specify a templated
149 // creator with comma in its templated arguments.
150 #define CAFFE_REGISTER_TYPED_CREATOR(RegistryName, key, ...) \
151  namespace { \
152  static Registerer##RegistryName CAFFE_ANONYMOUS_VARIABLE(g_##RegistryName)( \
153  key, RegistryName(), __VA_ARGS__); \
154  }
155 
156 #define CAFFE_REGISTER_TYPED_CLASS(RegistryName, key, ...) \
157  namespace { \
158  static Registerer##RegistryName CAFFE_ANONYMOUS_VARIABLE(g_##RegistryName)( \
159  key, \
160  RegistryName(), \
161  Registerer##RegistryName::DefaultCreator<__VA_ARGS__>, \
162  TypeMeta::Name<__VA_ARGS__>()); \
163  }
164 
165 // CAFFE_DECLARE_REGISTRY and CAFFE_DEFINE_REGISTRY are hard-wired to use string
166 // as the key
167 // type, because that is the most commonly used cases.
168 #define CAFFE_DECLARE_REGISTRY(RegistryName, ObjectType, ...) \
169  CAFFE_DECLARE_TYPED_REGISTRY( \
170  RegistryName, std::string, ObjectType, ##__VA_ARGS__)
171 
172 #define CAFFE_DEFINE_REGISTRY(RegistryName, ObjectType, ...) \
173  CAFFE_DEFINE_TYPED_REGISTRY( \
174  RegistryName, std::string, ObjectType, ##__VA_ARGS__)
175 
176 // CAFFE_REGISTER_CREATOR and CAFFE_REGISTER_CLASS are hard-wired to use string
177 // as the key
178 // type, because that is the most commonly used cases.
179 #define CAFFE_REGISTER_CREATOR(RegistryName, key, ...) \
180  CAFFE_REGISTER_TYPED_CREATOR(RegistryName, #key, __VA_ARGS__)
181 
182 #define CAFFE_REGISTER_CLASS(RegistryName, key, ...) \
183  CAFFE_REGISTER_TYPED_CLASS(RegistryName, #key, __VA_ARGS__)
184 
185 } // namespace caffe2
186 #endif // CAFFE2_CORE_REGISTRY_H_
A template class that allows one to register classes by keys.
Definition: registry.h:31
Simple registry implementation in Caffe2 that uses static variables to register object creators durin...
vector< SrcType > Keys()
Returns the keys currently registered as a vector.
Definition: registry.h:70