mxnet
any.h
Go to the documentation of this file.
1 
6 #ifndef DMLC_ANY_H_
7 #define DMLC_ANY_H_
8 
9 // This code need c++11 to compile
10 #include <typeinfo>
11 #include <type_traits>
12 #include <utility>
13 #include <algorithm>
14 #include <cstring>
15 
16 #include "./base.h"
17 #include "./logging.h"
18 
19 namespace dmlc {
20 // forward declare any;
21 class any;
22 
33 template<typename T>
34 inline T& get(any& src); // NOLINT(*)
35 
46 template<typename T>
47 inline const T& get(const any& src);
48 
59 template<typename T>
60 inline const T& unsafe_get(const any& src);
61 
72 template<typename T>
73 inline T& unsafe_get(any& src); // NOLINT(*)
74 
90 class any {
91  public:
93  inline any() = default;
98  inline any(any&& other); // NOLINT(*)
103  inline any(const any& other); // NOLINT(*)
109  template<typename T>
110  inline any(T&& other); // NOLINT(*)
112  inline ~any();
118  inline any& operator=(any&& other);
124  inline any& operator=(const any& other);
131  template<typename T>
132  inline any& operator=(T&& other);
136  inline bool empty() const;
140  inline void clear();
145  inline void swap(any& other); // NOLINT(*)
149  inline const std::type_info& type() const;
151  template<typename T, typename... Args>
152  inline void construct(Args&&... args);
153 
154  private:
156  // declare of helper class
157  template<typename T>
158  class TypeOnHeap;
159  template<typename T>
160  class TypeOnStack;
161  template<typename T>
162  class TypeInfo;
163  // size of stack space, it takes 32 bytes for one any type.
164  static const size_t kStack = sizeof(void*) * 3;
165  static const size_t kAlign = sizeof(void*);
166  // container use dynamic storage only when space runs lager
167  union Data {
168  // stack space
169  std::aligned_storage<kStack, kAlign>::type stack;
170  // pointer to heap space
171  void* pheap;
172  };
173  // type specific information
174  struct Type {
175  // destructor function
176  void (*destroy)(Data* data);
177  // copy constructor
178  void (*create_from_data)(Data* dst, const Data& src);
179  // the type info function
180  const std::type_info* ptype_info;
181  };
182  // constant to check if data can be stored on heap.
183  template<typename T>
184  struct data_on_stack {
185  static const bool value = alignof(T) <= kAlign && sizeof(T) <= kStack;
186  };
187  // declare friend with
188  template<typename T>
189  friend T& get(any& src); // NOLINT(*)
190  template<typename T>
191  friend const T& get(const any& src);
192  template<typename T>
193  friend T& unsafe_get(any& src); // NOLINT(*)
194  template<typename T>
195  friend const T& unsafe_get(const any& src);
196  // internal construct function
197  inline void construct(any&& other);
198  // internal construct function
199  inline void construct(const any& other);
200  // internal function to check if type is correct.
201  template<typename T>
202  inline void check_type() const;
203  template<typename T>
204  inline void check_type_by_name() const;
205  // internal type specific information
206  const Type* type_{nullptr};
207  // internal data
208  Data data_;
209 };
210 
211 template<typename T>
212 inline any::any(T&& other) {
213  typedef typename std::decay<T>::type DT;
214  if (std::is_same<DT, any>::value) {
215  this->construct(std::forward<T>(other));
216  } else {
217  static_assert(std::is_copy_constructible<DT>::value,
218  "Any can only hold value that is copy constructable");
219  type_ = TypeInfo<DT>::get_type();
220  if (data_on_stack<DT>::value) {
221 #pragma GCC diagnostic push
222 #if 6 <= __GNUC__
223 #pragma GCC diagnostic ignored "-Wplacement-new"
224 #endif
225  new (&(data_.stack)) DT(std::forward<T>(other));
226 #pragma GCC diagnostic pop
227  } else {
228  data_.pheap = new DT(std::forward<T>(other));
229  }
230  }
231 }
232 
233 inline any::any(any&& other) {
234  this->construct(std::move(other));
235 }
236 
237 inline any::any(const any& other) {
238  this->construct(other);
239 }
240 
241 inline void any::construct(any&& other) {
242  type_ = other.type_;
243  data_ = other.data_;
244  other.type_ = nullptr;
245 }
246 
247 inline void any::construct(const any& other) {
248  type_ = other.type_;
249  if (type_ != nullptr) {
250  type_->create_from_data(&data_, other.data_);
251  }
252 }
253 
254 template<typename T, typename... Args>
255 inline void any::construct(Args&&... args) {
256  clear();
257  typedef typename std::decay<T>::type DT;
258  type_ = TypeInfo<DT>::get_type();
259  if (data_on_stack<DT>::value) {
260 #pragma GCC diagnostic push
261 #if 6 <= __GNUC__
262 #pragma GCC diagnostic ignored "-Wplacement-new"
263 #endif
264  new (&(data_.stack)) DT(std::forward<Args>(args)...);
265 #pragma GCC diagnostic pop
266  } else {
267  data_.pheap = new DT(std::forward<Args>(args)...);
268  }
269 }
270 
271 inline any::~any() {
272  this->clear();
273 }
274 
275 inline any& any::operator=(any&& other) {
276  any(std::move(other)).swap(*this);
277  return *this;
278 }
279 
280 inline any& any::operator=(const any& other) {
281  any(other).swap(*this);
282  return *this;
283 }
284 
285 template<typename T>
286 inline any& any::operator=(T&& other) {
287  any(std::forward<T>(other)).swap(*this);
288  return *this;
289 }
290 
291 inline void any::swap(any& other) { // NOLINT(*)
292  std::swap(type_, other.type_);
293  std::swap(data_, other.data_);
294 }
295 
296 inline void any::clear() {
297  if (type_ != nullptr) {
298  if (type_->destroy != nullptr) {
299  type_->destroy(&data_);
300  }
301  type_ = nullptr;
302  }
303 }
304 
305 inline bool any::empty() const {
306  return type_ == nullptr;
307 }
308 
309 inline const std::type_info& any::type() const {
310  if (type_ != nullptr) {
311  return *(type_->ptype_info);
312  } else {
313  return typeid(void);
314  }
315 }
316 
317 template<typename T>
318 inline void any::check_type() const {
319  CHECK(type_ != nullptr)
320  << "The any container is empty"
321  << " requested=" << typeid(T).name();
322  CHECK(*(type_->ptype_info) == typeid(T))
323  << "The stored type mismatch"
324  << " stored=" << type_->ptype_info->name()
325  << " requested=" << typeid(T).name();
326 }
327 
328 template<typename T>
329 inline void any::check_type_by_name() const {
330  CHECK(type_ != nullptr)
331  << "The any container is empty"
332  << " requested=" << typeid(T).name();
333  CHECK(strcmp(type_->ptype_info->name(), typeid(T).name()) == 0)
334  << "The stored type name mismatch"
335  << " stored=" << type_->ptype_info->name()
336  << " requested=" << typeid(T).name();
337 }
338 
339 template<typename T>
340 inline const T& get(const any& src) {
341  src.check_type<T>();
342  return *any::TypeInfo<T>::get_ptr(&(src.data_));
343 }
344 
345 template<typename T>
346 inline T& get(any& src) { // NOLINT(*)
347  src.check_type<T>();
348  return *any::TypeInfo<T>::get_ptr(&(src.data_));
349 }
350 
351 template<typename T>
352 inline const T& unsafe_get(const any& src) {
353  src.check_type_by_name<T>();
354  return *any::TypeInfo<T>::get_ptr(&(src.data_));
355 }
356 
357 template<typename T>
358 inline T& unsafe_get(any& src) { // NOLINT(*)
359  src.check_type_by_name<T>();
360  return *any::TypeInfo<T>::get_ptr(&(src.data_));
361 }
362 
363 template<typename T>
364 class any::TypeOnHeap {
365  public:
366  inline static T* get_ptr(any::Data* data) {
367  return static_cast<T*>(data->pheap);
368  }
369  inline static const T* get_ptr(const any::Data* data) {
370  return static_cast<const T*>(data->pheap);
371  }
372  inline static void create_from_data(any::Data* dst, const any::Data& data) {
373  dst->pheap = new T(*get_ptr(&data));
374  }
375  inline static void destroy(Data* data) {
376  delete static_cast<T*>(data->pheap);
377  }
378 };
379 
380 template<typename T>
381 class any::TypeOnStack {
382  public:
383  inline static T* get_ptr(any::Data* data) {
384  return reinterpret_cast<T*>(&(data->stack));
385  }
386  inline static const T* get_ptr(const any::Data* data) {
387  return reinterpret_cast<const T*>(&(data->stack));
388  }
389  inline static void create_from_data(any::Data* dst, const any::Data& data) {
390  new (&(dst->stack)) T(*get_ptr(&data));
391  }
392  inline static void destroy(Data* data) {
393  T* dptr = reinterpret_cast<T*>(&(data->stack));
394  dptr->~T();
395  }
396 };
397 
398 template<typename T>
399 class any::TypeInfo
400  : public std::conditional<any::data_on_stack<T>::value,
401  any::TypeOnStack<T>,
402  any::TypeOnHeap<T> >::type {
403  public:
404  inline static const Type* get_type() {
405  static TypeInfo<T> tp;
406  return &(tp.type_);
407  }
408 
409  private:
410  // local type
411  Type type_;
412  // constructor
413  TypeInfo() {
414  if (std::is_pod<T>::value && data_on_stack<T>::value) {
415  type_.destroy = nullptr;
416  } else {
417  type_.destroy = TypeInfo<T>::destroy;
418  }
419  type_.create_from_data = TypeInfo<T>::create_from_data;
420  type_.ptype_info = &typeid(T);
421  }
422 };
424 
425 } // namespace dmlc
426 
427 #endif // DMLC_ANY_H_
namespace for dmlc
Definition: array_view.h:12