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 <cstdio>
10 #include <cstdlib>
11 #include <functional>
12 #include <memory>
13 #include <mutex>
14 
15 #include "caffe2/core/common.h"
16 #include "caffe2/core/typeid.h"
17 
18 namespace caffe2 {
19 
20 template <typename KeyType>
21 inline void PrintOffendingKey(const KeyType& key) {
22  printf("[key type printing not supported]\n");
23 }
24 
25 template <>
26 inline void PrintOffendingKey(const string& key) {
27  printf("Offending key: %s.\n", key.c_str());
28 }
29 
40 template <class SrcType, class ObjectPtrType, class... Args>
41 class Registry {
42  public:
43  typedef std::function<ObjectPtrType(Args...)> Creator;
44 
45  Registry() : registry_() {}
46 
47  void Register(const SrcType& key, Creator creator) {
48  // The if statement below is essentially the same as the following line:
49  // CHECK_EQ(registry_.count(key), 0) << "Key " << key
50  // << " registered twice.";
51  // However, CHECK_EQ depends on google logging, and since registration is
52  // carried out at static initialization time, we do not want to have an
53  // explicit dependency on glog's initialization function.
54  std::lock_guard<std::mutex> lock(register_mutex_);
55  if (registry_.count(key) != 0) {
56  printf("Key already registered.\n");
57  PrintOffendingKey(key);
58  std::exit(1);
59  }
60  registry_[key] = creator;
61  }
62 
63  void Register(const SrcType& key, Creator creator, const string& help_msg) {
64  Register(key, creator);
65  help_message_[key] = help_msg;
66  }
67 
68  inline bool Has(const SrcType& key) { return (registry_.count(key) != 0); }
69 
70  ObjectPtrType Create(const SrcType& key, Args... args) {
71  if (registry_.count(key) == 0) {
72  // Returns nullptr if the key is not registered.
73  return nullptr;
74  }
75  return registry_[key](args...);
76  }
77 
81  vector<SrcType> Keys() {
82  vector<SrcType> keys;
83  for (const auto& it : registry_) {
84  keys.push_back(it.first);
85  }
86  return keys;
87  }
88 
89  const CaffeMap<SrcType, string>& HelpMessage() const {
90  return help_message_;
91  }
92 
93  const char* HelpMessage(const SrcType& key) const {
94  auto it = help_message_.find(key);
95  if (it == help_message_.end()) {
96  return nullptr;
97  }
98  return it->second.c_str();
99  }
100 
101  private:
102  CaffeMap<SrcType, Creator> registry_;
103  CaffeMap<SrcType, string> help_message_;
104  std::mutex register_mutex_;
105 
106  DISABLE_COPY_AND_ASSIGN(Registry);
107 };
108 
109 template <class SrcType, class ObjectPtrType, class... Args>
110 class Registerer {
111  public:
112  Registerer(
113  const SrcType& key,
115  typename Registry<SrcType, ObjectPtrType, Args...>::Creator creator,
116  const string& help_msg = "") {
117  registry->Register(key, creator, help_msg);
118  }
119 
120  template <class DerivedType>
121  static ObjectPtrType DefaultCreator(Args... args) {
122  // TODO(jiayq): old versions of NVCC does not handle make_unique well
123  // so we are forced to use a unique_ptr constructor here. Check if it is
124  // fine to use make_unique in the future.
125  // return make_unique<DerivedType>(args...);
126  return ObjectPtrType(new DerivedType(args...));
127  }
128 };
129 
135 #define CAFFE_CONCATENATE_IMPL(s1, s2) s1##s2
136 #define CAFFE_CONCATENATE(s1, s2) CAFFE_CONCATENATE_IMPL(s1, s2)
137 #ifdef __COUNTER__
138 #define CAFFE_ANONYMOUS_VARIABLE(str) CAFFE_CONCATENATE(str, __COUNTER__)
139 #else
140 #define CAFFE_ANONYMOUS_VARIABLE(str) CAFFE_CONCATENATE(str, __LINE__)
141 #endif
142 
148 #define CAFFE_DECLARE_TYPED_REGISTRY( \
149  RegistryName, SrcType, ObjectType, PtrType, ...) \
150  Registry<SrcType, PtrType<ObjectType>, ##__VA_ARGS__>* RegistryName(); \
151  typedef Registerer<SrcType, PtrType<ObjectType>, ##__VA_ARGS__> \
152  Registerer##RegistryName;
153 
154 #define CAFFE_DEFINE_TYPED_REGISTRY( \
155  RegistryName, SrcType, ObjectType, PtrType, ...) \
156  Registry<SrcType, PtrType<ObjectType>, ##__VA_ARGS__>* RegistryName() { \
157  static Registry<SrcType, PtrType<ObjectType>, ##__VA_ARGS__>* registry = \
158  new Registry<SrcType, PtrType<ObjectType>, ##__VA_ARGS__>(); \
159  return registry; \
160  }
161 
162 // Note(Yangqing): The __VA_ARGS__ below allows one to specify a templated
163 // creator with comma in its templated arguments.
164 #define CAFFE_REGISTER_TYPED_CREATOR(RegistryName, key, ...) \
165  namespace { \
166  static Registerer##RegistryName CAFFE_ANONYMOUS_VARIABLE(g_##RegistryName)( \
167  key, RegistryName(), __VA_ARGS__); \
168  }
169 
170 #define CAFFE_REGISTER_TYPED_CLASS(RegistryName, key, ...) \
171  namespace { \
172  static Registerer##RegistryName CAFFE_ANONYMOUS_VARIABLE(g_##RegistryName)( \
173  key, \
174  RegistryName(), \
175  Registerer##RegistryName::DefaultCreator<__VA_ARGS__>, \
176  DemangleType<__VA_ARGS__>()); \
177  }
178 
179 // CAFFE_DECLARE_REGISTRY and CAFFE_DEFINE_REGISTRY are hard-wired to use string
180 // as the key
181 // type, because that is the most commonly used cases.
182 #define CAFFE_DECLARE_REGISTRY(RegistryName, ObjectType, ...) \
183  CAFFE_DECLARE_TYPED_REGISTRY( \
184  RegistryName, std::string, ObjectType, std::unique_ptr, ##__VA_ARGS__)
185 
186 #define CAFFE_DEFINE_REGISTRY(RegistryName, ObjectType, ...) \
187  CAFFE_DEFINE_TYPED_REGISTRY( \
188  RegistryName, std::string, ObjectType, std::unique_ptr, ##__VA_ARGS__)
189 
190 #define CAFFE_DECLARE_SHARED_REGISTRY(RegistryName, ObjectType, ...) \
191  CAFFE_DECLARE_TYPED_REGISTRY( \
192  RegistryName, std::string, ObjectType, std::shared_ptr, ##__VA_ARGS__)
193 
194 #define CAFFE_DEFINE_SHARED_REGISTRY(RegistryName, ObjectType, ...) \
195  CAFFE_DEFINE_TYPED_REGISTRY( \
196  RegistryName, std::string, ObjectType, std::shared_ptr, ##__VA_ARGS__)
197 
198 // CAFFE_REGISTER_CREATOR and CAFFE_REGISTER_CLASS are hard-wired to use string
199 // as the key
200 // type, because that is the most commonly used cases.
201 #define CAFFE_REGISTER_CREATOR(RegistryName, key, ...) \
202  CAFFE_REGISTER_TYPED_CREATOR(RegistryName, #key, __VA_ARGS__)
203 
204 #define CAFFE_REGISTER_CLASS(RegistryName, key, ...) \
205  CAFFE_REGISTER_TYPED_CLASS(RegistryName, #key, __VA_ARGS__)
206 
207 } // namespace caffe2
208 #endif // CAFFE2_CORE_REGISTRY_H_
vector< SrcType > Keys()
Returns the keys currently registered as a vector.
Definition: registry.h:81
A global dictionary that holds information about what Caffe2 modules have been loaded in the current ...
A template class that allows one to register classes by keys.
Definition: registry.h:41