Caffe2 - C++ API
A deep learning, cross platform ML framework
typeid.h
1 
17 #ifndef CAFFE2_CORE_TYPEID_H_
18 #define CAFFE2_CORE_TYPEID_H_
19 
20 #include <cassert>
21 #include <cstdlib>
22 #include <iostream>
23 #include <map>
24 #include <mutex>
25 #include <type_traits>
26 #ifdef __GXX_RTTI
27 #include <set>
28 #include <typeinfo>
29 #endif
30 
31 #include <exception>
32 
33 #include "caffe2/core/common.h"
34 
35 namespace caffe2 {
36 
37 typedef intptr_t CaffeTypeId;
38 std::map<CaffeTypeId, string>& gTypeNames();
39 std::set<string>& gRegisteredTypeNames();
40 
41 // A utility function to demangle a function name.
42 string Demangle(const char* name);
43 
49 template <typename T>
50 static const char* DemangleType() {
51 #ifdef __GXX_RTTI
52  static const string name = Demangle(typeid(T).name());
53  return name.c_str();
54 #else // __GXX_RTTI
55  return "(RTTI disabled, cannot show name)";
56 #endif // __GXX_RTTI
57 }
58 
59 // A utility function to return an exception string by prepending its exception
60 // type before its what() content.
61 string GetExceptionString(const std::exception& e);
62 
63 std::mutex& gCaffe2TypeRegistrationMutex();
64 
65 template <typename T>
67  TypeNameRegisterer(CaffeTypeId id, const string& literal_name) {
68  std::lock_guard<std::mutex> guard(gCaffe2TypeRegistrationMutex());
69 #ifdef __GXX_RTTI
70  (void)literal_name;
71 
72  string name = Demangle(typeid(T).name());
73  // If we are in RTTI mode, we will also use this opportunity to do sanity
74  // check if there are duplicated ids registered for the same type. This
75  // usually happens when one does not do RTLD_GLOBAL, which is often the
76  // case in Python. The way we do the check is to make sure that there are
77  // no duplicated names registered - this could be done by checking the
78  // uniqueness of names.
79  if (gRegisteredTypeNames().count(name)) {
80  std::cerr << "Type name " << name
81  << " registered twice. This should "
82  "not happen. Do you have duplicated CAFFE_KNOWN_TYPE?"
83  << std::endl;
84  throw std::runtime_error("TypeNameRegisterer error with type " + name);
85  }
86  gRegisteredTypeNames().insert(name);
87  gTypeNames()[id] = name;
88 #else // __GXX_RTTI
89  if (literal_name.empty()) {
90  gTypeNames()[id] = "(RTTI disabled, cannot show name)";
91  } else {
92  gTypeNames()[id] = literal_name;
93  }
94 #endif // __GXX_RTTI
95  }
96 };
97 
104 class TypeMeta {
105  public:
106  typedef void (*PlacementNew)(void*, size_t);
107  typedef void (*TypedCopy)(const void*, void*, size_t);
108  typedef void (*TypedDestructor)(void*, size_t);
113  : id_(0), itemsize_(0), ctor_(nullptr), copy_(nullptr), dtor_(nullptr) {}
114 
118  TypeMeta(const TypeMeta& src)
119  : id_(src.id_),
120  itemsize_(src.itemsize_),
121  ctor_(src.ctor_),
122  copy_(src.copy_),
123  dtor_(src.dtor_) {}
127  TypeMeta& operator=(const TypeMeta& src) {
128  if (this == &src)
129  return *this;
130  id_ = src.id_;
131  itemsize_ = src.itemsize_;
132  ctor_ = src.ctor_;
133  copy_ = src.copy_;
134  dtor_ = src.dtor_;
135  return *this;
136  }
137 
138  private:
139  // TypeMeta can only be created by Make, making sure that we do not
140  // create incorrectly mixed up TypeMeta objects.
141  TypeMeta(
142  CaffeTypeId i,
143  size_t s,
144  PlacementNew ctor,
145  TypedCopy copy,
146  TypedDestructor dtor)
147  : id_(i), itemsize_(s), ctor_(ctor), copy_(copy), dtor_(dtor) {}
148 
149  public:
153  inline const CaffeTypeId& id() const {
154  return id_;
155  }
159  inline const size_t& itemsize() const {
160  return itemsize_;
161  }
165  inline PlacementNew ctor() const {
166  return ctor_;
167  }
171  inline TypedCopy copy() const {
172  return copy_;
173  }
177  inline TypedDestructor dtor() const {
178  return dtor_;
179  }
183  inline const char* name() const {
184  auto it = gTypeNames().find(id_);
185  assert(it != gTypeNames().end());
186  return it->second.c_str();
187  }
188  inline bool operator==(const TypeMeta& m) const {
189  return (id_ == m.id_);
190  }
191  inline bool operator!=(const TypeMeta& m) const {
192  return (id_ != m.id_);
193  }
194 
195  template <typename T>
196  inline bool Match() const {
197  return (id_ == Id<T>());
198  }
199 
200  // Below are static functions that can be called by passing a specific type.
201 
209  template <typename T>
210  CAFFE2_API static CaffeTypeId Id();
211 
215  template <typename T>
216  static size_t ItemSize() {
217  return sizeof(T);
218  }
219 
225  template <typename T>
226  static const char* TypeName() {
227  auto it = gTypeNames().find(Id<T>());
228  assert(it != gTypeNames().end());
229  return it->second.c_str();
230  }
231 
235  template <typename T>
236  static void _Ctor(void* ptr, size_t n) {
237  T* typed_ptr = static_cast<T*>(ptr);
238  for (int i = 0; i < n; ++i) {
239  new (typed_ptr + i) T;
240  }
241  }
242 
246  template <typename T>
247  static void _Copy(const void* src, void* dst, size_t n) {
248  const T* typed_src = static_cast<const T*>(src);
249  T* typed_dst = static_cast<T*>(dst);
250  for (int i = 0; i < n; ++i) {
251  typed_dst[i] = typed_src[i];
252  }
253  }
254 
258  template <typename T>
259  static void
260  _CopyNotAllowed(const void* /*src*/, void* /*dst*/, size_t /*n*/) {
261  std::cerr << "Type " << DemangleType<T>() << " does not allow assignment.";
262  // This is an error by design, so we will quit loud.
263  abort();
264  }
265 
269  template <typename T>
270  static void _Dtor(void* ptr, size_t n) {
271  T* typed_ptr = static_cast<T*>(ptr);
272  for (int i = 0; i < n; ++i) {
273  typed_ptr[i].~T();
274  }
275  }
276 
280  template <typename T>
281  static typename std::enable_if<
282  std::is_fundamental<T>::value || std::is_pointer<T>::value,
283  TypeMeta>::type
284  Make() {
285  return TypeMeta(Id<T>(), ItemSize<T>(), nullptr, nullptr, nullptr);
286  }
287 
288  template <
289  typename T,
290  typename std::enable_if<
291  !(std::is_fundamental<T>::value || std::is_pointer<T>::value) &&
292  std::is_copy_assignable<T>::value>::type* = nullptr>
293  static TypeMeta Make() {
294  return TypeMeta(Id<T>(), ItemSize<T>(), _Ctor<T>, _Copy<T>, _Dtor<T>);
295  }
296 
297  template <typename T>
298  static TypeMeta Make(
299  typename std::enable_if<
300  !(std::is_fundamental<T>::value || std::is_pointer<T>::value) &&
301  !std::is_copy_assignable<T>::value>::type* = 0) {
302  return TypeMeta(
303  Id<T>(), ItemSize<T>(), _Ctor<T>, _CopyNotAllowed<T>, _Dtor<T>);
304  }
305 
306  private:
307  CaffeTypeId id_;
308  size_t itemsize_;
309  PlacementNew ctor_;
310  TypedCopy copy_;
311  TypedDestructor dtor_;
312 };
313 
327 // Implementation note: in MSVC, we will need to prepend the CAFFE2_EXPORT
328 // keyword in order to get things compiled properly. in Linux, gcc seems to
329 // create attribute ignored error for explicit template instantiations, see
330 // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0537r0.html
331 // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=51930
332 // and as a result, we define these two macros slightly differently.
333 
334 #ifdef _MSC_VER
335 #define CAFFE_KNOWN_TYPE(T) \
336  template <> \
337  CAFFE2_EXPORT CaffeTypeId TypeMeta::Id<T>() { \
338  static bool type_id_bit[1]; \
339  static TypeNameRegisterer<T> registerer( \
340  reinterpret_cast<CaffeTypeId>(type_id_bit), #T); \
341  return reinterpret_cast<CaffeTypeId>(type_id_bit); \
342  }
343 #else // _MSC_VER
344 #define CAFFE_KNOWN_TYPE(T) \
345  template <> \
346  CaffeTypeId TypeMeta::Id<T>() { \
347  static bool type_id_bit[1]; \
348  static TypeNameRegisterer<T> registerer( \
349  reinterpret_cast<CaffeTypeId>(type_id_bit), #T); \
350  return reinterpret_cast<CaffeTypeId>(type_id_bit); \
351  }
352 #endif
353 
354 } // namespace caffe2
355 
356 #endif // CAFFE2_CORE_TYPEID_H_
static size_t ItemSize()
Returns the item size of the type.
Definition: typeid.h:216
TypeMeta(const TypeMeta &src)
Copy constructor.
Definition: typeid.h:118
static const char * TypeName()
Returns the registered printable name of the type.
Definition: typeid.h:226
PlacementNew ctor() const
Returns the placement new function pointer for individual items.
Definition: typeid.h:165
TypeMeta()
Create a dummy TypeMeta object.
Definition: typeid.h:112
static void _Copy(const void *src, void *dst, size_t n)
Typed copy function for classes.
Definition: typeid.h:247
static void _Dtor(void *ptr, size_t n)
Destructor for non-fundamental types.
Definition: typeid.h:270
Copyright (c) 2016-present, Facebook, Inc.
const CaffeTypeId & id() const
Returns the type id.
Definition: typeid.h:153
const char * name() const
Returns a printable name for the type.
Definition: typeid.h:183
TypedCopy copy() const
Returns the typed copy function pointer for individual iterms.
Definition: typeid.h:171
static void _Ctor(void *ptr, size_t n)
Placement new function for the type.
Definition: typeid.h:236
TypeMeta & operator=(const TypeMeta &src)
Assignment operator.
Definition: typeid.h:127
static void _CopyNotAllowed(const void *, void *, size_t)
A placeholder function for types that do not allow assignment.
Definition: typeid.h:260
TypedDestructor dtor() const
Returns the destructor function pointer for individual items.
Definition: typeid.h:177
TypeMeta is a thin class that allows us to store the type of a container such as a blob...
Definition: typeid.h:104
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:284
const size_t & itemsize() const
Returns the size of the item.
Definition: typeid.h:159