Caffe2 - C++ API
A deep learning, cross platform ML framework
typeid.h
1 #ifndef CAFFE2_CORE_TYPEID_H_
2 #define CAFFE2_CORE_TYPEID_H_
3 
4 #include <cassert>
5 #include <cstdlib>
6 #include <iostream>
7 #include <map>
8 #include <mutex>
9 #include <type_traits>
10 #ifdef __GXX_RTTI
11 #include <set>
12 #include <typeinfo>
13 #endif
14 
15 #include <exception>
16 
17 #include "caffe2/core/common.h"
18 
19 namespace caffe2 {
20 
21 typedef intptr_t CaffeTypeId;
22 std::map<CaffeTypeId, string>& gTypeNames();
23 std::set<string>& gRegisteredTypeNames();
24 
25 // A utility function to demangle a function name.
26 string Demangle(const char* name);
27 
33 template <typename T>
34 static const char* DemangleType() {
35 #ifdef __GXX_RTTI
36  static const string name = Demangle(typeid(T).name());
37  return name.c_str();
38 #else // __GXX_RTTI
39  return "(RTTI disabled, cannot show name)";
40 #endif // __GXX_RTTI
41 }
42 
43 // A utility function to return an exception string by prepending its exception
44 // type before its what() content.
45 string GetExceptionString(const std::exception& e);
46 
47 std::mutex& gCaffe2TypeRegistrationMutex();
48 
49 template <typename T>
51  TypeNameRegisterer(CaffeTypeId id, const string& literal_name) {
52  std::lock_guard<std::mutex> guard(gCaffe2TypeRegistrationMutex());
53 #ifdef __GXX_RTTI
54  (void)literal_name;
55 
56  string name = Demangle(typeid(T).name());
57  // If we are in RTTI mode, we will also use this opportunity to do sanity
58  // check if there are duplicated ids registered for the same type. This
59  // usually happens when one does not do RTLD_GLOBAL, which is often the
60  // case in Python. The way we do the check is to make sure that there are
61  // no duplicated names registered - this could be done by checking the
62  // uniqueness of names.
63  if (gRegisteredTypeNames().count(name)) {
64  std::cerr << "Type name " << name
65  << " registered twice. This should "
66  "not happen. Do you have duplicated CAFFE_KNOWN_TYPE?"
67  << std::endl;
68  throw std::runtime_error("TypeNameRegisterer error with type " + name);
69  }
70  gRegisteredTypeNames().insert(name);
71  gTypeNames()[id] = name;
72 #else // __GXX_RTTI
73  if (literal_name.empty()) {
74  gTypeNames()[id] = "(RTTI disabled, cannot show name)";
75  } else {
76  gTypeNames()[id] = literal_name;
77  }
78 #endif // __GXX_RTTI
79  }
80 };
81 
88 class TypeMeta {
89  public:
90  typedef void (*PlacementNew)(void*, size_t);
91  typedef void (*TypedCopy)(const void*, void*, size_t);
92  typedef void (*TypedDestructor)(void*, size_t);
97  : id_(0), itemsize_(0), ctor_(nullptr), copy_(nullptr), dtor_(nullptr) {}
98 
102  TypeMeta(const TypeMeta& src)
103  : id_(src.id_),
104  itemsize_(src.itemsize_),
105  ctor_(src.ctor_),
106  copy_(src.copy_),
107  dtor_(src.dtor_) {}
111  TypeMeta& operator=(const TypeMeta& src) {
112  if (this == &src)
113  return *this;
114  id_ = src.id_;
115  itemsize_ = src.itemsize_;
116  ctor_ = src.ctor_;
117  copy_ = src.copy_;
118  dtor_ = src.dtor_;
119  return *this;
120  }
121 
122  private:
123  // TypeMeta can only be created by Make, making sure that we do not
124  // create incorrectly mixed up TypeMeta objects.
125  TypeMeta(
126  CaffeTypeId i,
127  size_t s,
128  PlacementNew ctor,
129  TypedCopy copy,
130  TypedDestructor dtor)
131  : id_(i), itemsize_(s), ctor_(ctor), copy_(copy), dtor_(dtor) {}
132 
133  public:
137  inline const CaffeTypeId& id() const {
138  return id_;
139  }
143  inline const size_t& itemsize() const {
144  return itemsize_;
145  }
149  inline PlacementNew ctor() const {
150  return ctor_;
151  }
155  inline TypedCopy copy() const {
156  return copy_;
157  }
161  inline TypedDestructor dtor() const {
162  return dtor_;
163  }
167  inline const char* name() const {
168  auto it = gTypeNames().find(id_);
169  assert(it != gTypeNames().end());
170  return it->second.c_str();
171  }
172  inline bool operator==(const TypeMeta& m) const {
173  return (id_ == m.id_);
174  }
175  inline bool operator!=(const TypeMeta& m) const {
176  return (id_ != m.id_);
177  }
178 
179  template <typename T>
180  inline bool Match() const {
181  return (id_ == Id<T>());
182  }
183 
184  // Below are static functions that can be called by passing a specific type.
185 
193  template <typename T>
194  CAFFE2_API static CaffeTypeId Id();
195 
199  template <typename T>
200  static size_t ItemSize() {
201  return sizeof(T);
202  }
203 
209  template <typename T>
210  static const char* TypeName() {
211  auto it = gTypeNames().find(Id<T>());
212  assert(it != gTypeNames().end());
213  return it->second.c_str();
214  }
215 
219  template <typename T>
220  static void _Ctor(void* ptr, size_t n) {
221  T* typed_ptr = static_cast<T*>(ptr);
222  for (int i = 0; i < n; ++i) {
223  new (typed_ptr + i) T;
224  }
225  }
226 
230  template <typename T>
231  static void _Copy(const void* src, void* dst, size_t n) {
232  const T* typed_src = static_cast<const T*>(src);
233  T* typed_dst = static_cast<T*>(dst);
234  for (int i = 0; i < n; ++i) {
235  typed_dst[i] = typed_src[i];
236  }
237  }
238 
242  template <typename T>
243  static void
244  _CopyNotAllowed(const void* /*src*/, void* /*dst*/, size_t /*n*/) {
245  std::cerr << "Type " << DemangleType<T>() << " does not allow assignment.";
246  // This is an error by design, so we will quit loud.
247  abort();
248  }
249 
253  template <typename T>
254  static void _Dtor(void* ptr, size_t n) {
255  T* typed_ptr = static_cast<T*>(ptr);
256  for (int i = 0; i < n; ++i) {
257  typed_ptr[i].~T();
258  }
259  }
260 
264  template <typename T>
265  static typename std::enable_if<
266  std::is_fundamental<T>::value || std::is_pointer<T>::value,
267  TypeMeta>::type
268  Make() {
269  return TypeMeta(Id<T>(), ItemSize<T>(), nullptr, nullptr, nullptr);
270  }
271 
272  template <
273  typename T,
274  typename std::enable_if<
275  !(std::is_fundamental<T>::value || std::is_pointer<T>::value) &&
276  std::is_copy_assignable<T>::value>::type* = nullptr>
277  static TypeMeta Make() {
278  return TypeMeta(Id<T>(), ItemSize<T>(), _Ctor<T>, _Copy<T>, _Dtor<T>);
279  }
280 
281  template <typename T>
282  static TypeMeta Make(
283  typename std::enable_if<
284  !(std::is_fundamental<T>::value || std::is_pointer<T>::value) &&
285  !std::is_copy_assignable<T>::value>::type* = 0) {
286  return TypeMeta(
287  Id<T>(), ItemSize<T>(), _Ctor<T>, _CopyNotAllowed<T>, _Dtor<T>);
288  }
289 
290  private:
291  CaffeTypeId id_;
292  size_t itemsize_;
293  PlacementNew ctor_;
294  TypedCopy copy_;
295  TypedDestructor dtor_;
296 };
297 
311 // Implementation note: in MSVC, we will need to prepend the CAFFE2_EXPORT
312 // keyword in order to get things compiled properly. in Linux, gcc seems to
313 // create attribute ignored error for explicit template instantiations, see
314 // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0537r0.html
315 // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=51930
316 // and as a result, we define these two macros slightly differently.
317 
318 #ifdef _MSC_VER
319 #define CAFFE_KNOWN_TYPE(T) \
320  template <> \
321  CAFFE2_EXPORT CaffeTypeId TypeMeta::Id<T>() { \
322  static bool type_id_bit[1]; \
323  static TypeNameRegisterer<T> registerer( \
324  reinterpret_cast<CaffeTypeId>(type_id_bit), #T); \
325  return reinterpret_cast<CaffeTypeId>(type_id_bit); \
326  }
327 #else // _MSC_VER
328 #define CAFFE_KNOWN_TYPE(T) \
329  template <> \
330  CaffeTypeId TypeMeta::Id<T>() { \
331  static bool type_id_bit[1]; \
332  static TypeNameRegisterer<T> registerer( \
333  reinterpret_cast<CaffeTypeId>(type_id_bit), #T); \
334  return reinterpret_cast<CaffeTypeId>(type_id_bit); \
335  }
336 #endif
337 
338 } // namespace caffe2
339 
340 #endif // CAFFE2_CORE_TYPEID_H_
static size_t ItemSize()
Returns the item size of the type.
Definition: typeid.h:200
TypeMeta(const TypeMeta &src)
Copy constructor.
Definition: typeid.h:102
static const char * TypeName()
Returns the registered printable name of the type.
Definition: typeid.h:210
PlacementNew ctor() const
Returns the placement new function pointer for individual items.
Definition: typeid.h:149
TypeMeta()
Create a dummy TypeMeta object.
Definition: typeid.h:96
static void _Copy(const void *src, void *dst, size_t n)
Typed copy function for classes.
Definition: typeid.h:231
static void _Dtor(void *ptr, size_t n)
Destructor for non-fundamental types.
Definition: typeid.h:254
A global dictionary that holds information about what Caffe2 modules have been loaded in the current ...
const CaffeTypeId & id() const
Returns the type id.
Definition: typeid.h:137
const char * name() const
Returns a printable name for the type.
Definition: typeid.h:167
TypedCopy copy() const
Returns the typed copy function pointer for individual iterms.
Definition: typeid.h:155
static void _Ctor(void *ptr, size_t n)
Placement new function for the type.
Definition: typeid.h:220
TypeMeta & operator=(const TypeMeta &src)
Assignment operator.
Definition: typeid.h:111
static void _CopyNotAllowed(const void *, void *, size_t)
A placeholder function for types that do not allow assignment.
Definition: typeid.h:244
TypedDestructor dtor() const
Returns the destructor function pointer for individual items.
Definition: typeid.h:161
TypeMeta is a thin class that allows us to store the type of a container such as a blob...
Definition: typeid.h:88
static std::enable_if< std::is_fundamental< T >::value||std::is_pointer< T >::value, TypeMeta >::type Make()
Returns a TypeMeta object that corresponds to the typename T.
Definition: typeid.h:268
const size_t & itemsize() const
Returns the size of the item.
Definition: typeid.h:143