any.hpp
Go to the documentation of this file.
1 //
2 // Implementation of N4562 std::experimental::any (merged into C++17) for C++11 compilers.
3 //
4 // See also:
5 // + http://en.cppreference.com/w/cpp/any
6 // + http://en.cppreference.com/w/cpp/experimental/any
7 // + http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4562.html#any
8 // + https://cplusplus.github.io/LWG/lwg-active.html#2509
9 //
10 //
11 // Copyright (c) 2016 Denilson das Mercês Amorim
12 //
13 // Distributed under the Boost Software License, Version 1.0. (See accompanying
14 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
15 //
16 #ifndef LINB_ANY_HPP
17 #define LINB_ANY_HPP
18 #pragma once
19 #include <typeinfo>
20 #include <type_traits>
21 #include <stdexcept>
22 
23 
24 #if defined(PARTICLE)
25 #if !defined(__cpp_exceptions) && !defined(ANY_IMPL_NO_EXCEPTIONS) && !defined(ANY_IMPL_EXCEPTIONS)
26 # define ANY_IMPL_NO_EXCEPTIONS
27 # endif
28 #else
29 // you can opt-out of exceptions by definining ANY_IMPL_NO_EXCEPTIONS,
30 // but you must ensure not to cast badly when passing an `any' object to any_cast<T>(any)
31 #endif
32 
33 #if defined(PARTICLE)
34 #if !defined(__cpp_rtti) && !defined(ANY_IMPL_NO_RTTI) && !defined(ANY_IMPL_RTTI)
35 # define ANY_IMPL_NO_RTTI
36 # endif
37 #else
38 // you can opt-out of RTTI by defining ANY_IMPL_NO_RTTI,
39 // in order to disable functions working with the typeid of a type
40 #endif
41 
42 
43 namespace linb
44 {
45 
46 class bad_any_cast : public std::bad_cast
47 {
48 public:
49  const char* what() const noexcept override
50  {
51  return "bad any cast";
52  }
53 };
54 
55 class any final
56 {
57 public:
59  any() :
60  vtable(nullptr)
61  {
62  }
63 
65  any(const any& rhs) :
66  vtable(rhs.vtable)
67  {
68  if(!rhs.empty())
69  {
70  rhs.vtable->copy(rhs.storage, this->storage);
71  }
72  }
73 
76  any(any&& rhs) noexcept :
77  vtable(rhs.vtable)
78  {
79  if(!rhs.empty())
80  {
81  rhs.vtable->move(rhs.storage, this->storage);
82  rhs.vtable = nullptr;
83  }
84  }
85 
87  ~any()
88  {
89  this->clear();
90  }
91 
97  any(ValueType&& value)
98  {
99  static_assert(std::is_copy_constructible<typename std::decay<ValueType>::type>::value,
100  "T shall satisfy the CopyConstructible requirements.");
101  this->construct(std::forward<ValueType>(value));
102  }
103 
105  any& operator=(const any& rhs)
106  {
107  any(rhs).swap(*this);
108  return *this;
109  }
110 
115  any& operator=(any&& rhs) noexcept
116  {
117  any(std::move(rhs)).swap(*this);
118  return *this;
119  }
120 
126  any& operator=(ValueType&& value)
127  {
128  static_assert(std::is_copy_constructible<typename std::decay<ValueType>::type>::value,
129  "T shall satisfy the CopyConstructible requirements.");
130  any(std::forward<ValueType>(value)).swap(*this);
131  return *this;
132  }
133 
135  void clear() noexcept
136  {
137  if(!empty())
138  {
139  this->vtable->destroy(storage);
140  this->vtable = nullptr;
141  }
142  }
143 
145  bool empty() const noexcept
146  {
147  return this->vtable == nullptr;
148  }
149 
150 #ifndef ANY_IMPL_NO_RTTI
151  const std::type_info& type() const noexcept
153  {
154  return empty()? typeid(void) : this->vtable->type();
155  }
156 #endif
157 
159  void swap(any& rhs) noexcept
160  {
161  if(this->vtable != rhs.vtable)
162  {
163  any tmp(std::move(rhs));
164 
165  // move from *this to rhs.
166  rhs.vtable = this->vtable;
167  if(this->vtable != nullptr)
168  {
169  this->vtable->move(this->storage, rhs.storage);
170  //this->vtable = nullptr; -- unneeded, see below
171  }
172 
173  // move from tmp (previously rhs) to *this.
174  this->vtable = tmp.vtable;
175  if(tmp.vtable != nullptr)
176  {
177  tmp.vtable->move(tmp.storage, this->storage);
178  tmp.vtable = nullptr;
179  }
180  }
181  else // same types
182  {
183  if(this->vtable != nullptr)
184  this->vtable->swap(this->storage, rhs.storage);
185  }
186  }
187 
188 private: // Storage and Virtual Method Table
189 
191  {
192  using stack_storage_t = typename std::aligned_storage<2 * sizeof(void*), std::alignment_of<void*>::value>::type;
193 
194  void* dynamic;
195  stack_storage_t stack; // 2 words for e.g. shared_ptr
196  };
197 
199  struct vtable_type
200  {
201  // Note: The caller is responssible for doing .vtable = nullptr after destructful operations
202  // such as destroy() and/or move().
203 
204 #ifndef ANY_IMPL_NO_RTTI
205  const std::type_info& (*type)() noexcept;
207 #endif
208 
211  void(*destroy)(storage_union&) noexcept;
212 
215  void(*copy)(const storage_union& src, storage_union& dest);
216 
219  void(*move)(storage_union& src, storage_union& dest) noexcept;
220 
222  void(*swap)(storage_union& lhs, storage_union& rhs) noexcept;
223  };
224 
226  template<typename T>
228  {
229 #ifndef ANY_IMPL_NO_RTTI
230  static const std::type_info& type() noexcept
231  {
232  return typeid(T);
233  }
234 #endif
235 
236  static void destroy(storage_union& storage) noexcept
237  {
238  //assert(reinterpret_cast<T*>(storage.dynamic));
239  delete reinterpret_cast<T*>(storage.dynamic);
240  }
241 
242  static void copy(const storage_union& src, storage_union& dest)
243  {
244  dest.dynamic = new T(*reinterpret_cast<const T*>(src.dynamic));
245  }
246 
247  static void move(storage_union& src, storage_union& dest) noexcept
248  {
249  dest.dynamic = src.dynamic;
250  src.dynamic = nullptr;
251  }
252 
253  static void swap(storage_union& lhs, storage_union& rhs) noexcept
254  {
255  // just exchage the storage pointers.
256  std::swap(lhs.dynamic, rhs.dynamic);
257  }
258  };
259 
261  template<typename T>
263  {
264 #ifndef ANY_IMPL_NO_RTTI
265  static const std::type_info& type() noexcept
266  {
267  return typeid(T);
268  }
269 #endif
270 
271  static void destroy(storage_union& storage) noexcept
272  {
273  reinterpret_cast<T*>(&storage.stack)->~T();
274  }
275 
276  static void copy(const storage_union& src, storage_union& dest)
277  {
278  new (&dest.stack) T(reinterpret_cast<const T&>(src.stack));
279  }
280 
281  static void move(storage_union& src, storage_union& dest) noexcept
282  {
283  // one of the conditions for using vtable_stack is a nothrow move constructor,
284  // so this move constructor will never throw a exception.
285  new (&dest.stack) T(std::move(reinterpret_cast<T&>(src.stack)));
286  destroy(src);
287  }
288 
289  static void swap(storage_union& lhs, storage_union& rhs) noexcept
290  {
291  storage_union tmp_storage;
292  move(rhs, tmp_storage);
293  move(lhs, rhs);
294  move(tmp_storage, lhs);
295  }
296  };
297 
299  template<typename T>
301  std::integral_constant<bool,
302  !(std::is_nothrow_move_constructible<T>::value // N4562 §6.3/3 [any.class]
303  && sizeof(T) <= sizeof(storage_union::stack)
304  && std::alignment_of<T>::value <= std::alignment_of<storage_union::stack_storage_t>::value)>
305  {};
306 
308  template<typename T>
309  static vtable_type* vtable_for_type()
310  {
311  using VTableType = typename std::conditional<requires_allocation<T>::value, vtable_dynamic<T>, vtable_stack<T>>::type;
312  static vtable_type table = {
313 #ifndef ANY_IMPL_NO_RTTI
314  VTableType::type,
315 #endif
316  VTableType::destroy,
317  VTableType::copy, VTableType::move,
318  VTableType::swap,
319  };
320  return &table;
321  }
322 
323 protected:
324  template<typename T>
325  friend const T* any_cast(const any* operand) noexcept;
326  template<typename T>
327  friend T* any_cast(any* operand) noexcept;
328 
329 #ifndef ANY_IMPL_NO_RTTI
331  bool is_typed(const std::type_info& t) const
332  {
333  return is_same(this->type(), t);
334  }
335 #endif
336 
337 #ifndef ANY_IMPL_NO_RTTI
344  static bool is_same(const std::type_info& a, const std::type_info& b)
345  {
346 #ifdef ANY_IMPL_FAST_TYPE_INFO_COMPARE
347  return &a == &b;
348 #else
349  return a == b;
350 #endif
351  }
352 #endif
353 
355  template<typename T>
356  const T* cast() const noexcept
357  {
358  return requires_allocation<typename std::decay<T>::type>::value?
359  reinterpret_cast<const T*>(storage.dynamic) :
360  reinterpret_cast<const T*>(&storage.stack);
361  }
362 
364  template<typename T>
365  T* cast() noexcept
366  {
367  return requires_allocation<typename std::decay<T>::type>::value?
368  reinterpret_cast<T*>(storage.dynamic) :
369  reinterpret_cast<T*>(&storage.stack);
370  }
371 
372 private:
373  storage_union storage; // on offset(0) so no padding for align
374  vtable_type* vtable;
375 
376  template<typename ValueType, typename T>
377  typename std::enable_if<requires_allocation<T>::value>::type
378  do_construct(ValueType&& value)
379  {
380  storage.dynamic = new T(std::forward<ValueType>(value));
381  }
382 
383  template<typename ValueType, typename T>
384  typename std::enable_if<!requires_allocation<T>::value>::type
385  do_construct(ValueType&& value)
386  {
387  new (&storage.stack) T(std::forward<ValueType>(value));
388  }
389 
392  template<typename ValueType>
393  void construct(ValueType&& value)
394  {
395  using T = typename std::decay<ValueType>::type;
396 
397  this->vtable = vtable_for_type<T>();
398 
399  do_construct<ValueType,T>(std::forward<ValueType>(value));
400  }
401 };
402 
403 
404 
405 namespace detail
406 {
407  template<typename ValueType>
408  inline ValueType any_cast_move_if_true(typename std::remove_reference<ValueType>::type* p, std::true_type)
409  {
410  return std::move(*p);
411  }
412 
413  template<typename ValueType>
414  inline ValueType any_cast_move_if_true(typename std::remove_reference<ValueType>::type* p, std::false_type)
415  {
416  return *p;
417  }
418 }
419 
421 template<typename ValueType>
422 inline ValueType any_cast(const any& operand)
423 {
425 #ifndef ANY_IMPL_NO_EXCEPTIONS
426  if(p == nullptr) throw bad_any_cast();
427 #endif
428  return *p;
429 }
430 
432 template<typename ValueType>
433 inline ValueType any_cast(any& operand)
434 {
436 #ifndef ANY_IMPL_NO_EXCEPTIONS
437  if(p == nullptr) throw bad_any_cast();
438 #endif
439  return *p;
440 }
441 
447 template<typename ValueType>
448 inline ValueType any_cast(any&& operand)
449 {
450  using can_move = std::integral_constant<bool,
451  std::is_move_constructible<ValueType>::value
452  && !std::is_lvalue_reference<ValueType>::value>;
453 
455 #ifndef ANY_IMPL_NO_EXCEPTIONS
456  if(p == nullptr) throw bad_any_cast();
457 #endif
458  return detail::any_cast_move_if_true<ValueType>(p, can_move());
459 }
460 
463 template<typename ValueType>
464 inline const ValueType* any_cast(const any* operand) noexcept
465 {
466  using T = typename std::decay<ValueType>::type;
467 
468 #ifndef ANY_IMPL_NO_RTTI
469  if (operand && operand->is_typed(typeid(T)))
470 #else
471  if (operand && operand->vtable == any::vtable_for_type<T>())
472 #endif
473  return operand->cast<ValueType>();
474  else
475  return nullptr;
476 }
477 
480 template<typename ValueType>
481 inline ValueType* any_cast(any* operand) noexcept
482 {
483  using T = typename std::decay<ValueType>::type;
484 
485 #ifndef ANY_IMPL_NO_RTTI
486  if (operand && operand->is_typed(typeid(T)))
487 #else
488  if (operand && operand->vtable == any::vtable_for_type<T>())
489 #endif
490  return operand->cast<ValueType>();
491  else
492  return nullptr;
493 }
494 
495 }
496 
497 namespace std
498 {
499  inline void swap(linb::any& lhs, linb::any& rhs) noexcept
500  {
501  lhs.swap(rhs);
502  }
503 }
504 
505 #endif
linb::any::vtable_stack::destroy
static void destroy(storage_union &storage) noexcept
Definition: any.hpp:271
linb::any::operator=
any & operator=(const any &rhs)
Has the same effect as any(rhs).swap(*this). No effects if an exception is thrown.
Definition: any.hpp:105
linb::any::vtable_stack::type
static const std::type_info & type() noexcept
Definition: any.hpp:265
linb::any::storage
storage_union storage
Definition: any.hpp:373
linb::any::storage_union
Definition: any.hpp:190
std::swap
void swap(linb::any &lhs, linb::any &rhs) noexcept
Definition: any.hpp:499
linb::any::storage_union::stack_storage_t
typename std::aligned_storage< 2 *sizeof(void *), std::alignment_of< void * >::value >::type stack_storage_t
Definition: any.hpp:192
linb::any::any
any(const any &rhs)
Constructs an object of type any with an equivalent state as other.
Definition: any.hpp:65
linb
Definition: any.hpp:43
linb::any::empty
bool empty() const noexcept
Returns true if *this has no contained object, otherwise false.
Definition: any.hpp:145
linb::any::type
const std::type_info & type() const noexcept
If *this has a contained object of type T, typeid(T); otherwise typeid(void).
Definition: any.hpp:152
linb::any::vtable_stack::swap
static void swap(storage_union &lhs, storage_union &rhs) noexcept
Definition: any.hpp:289
linb::any::vtable_type::swap
void(* swap)(storage_union &lhs, storage_union &rhs) noexcept
Exchanges the storage between lhs and rhs.
Definition: any.hpp:222
linb::any::do_construct
std::enable_if< requires_allocation< T >::value >::type do_construct(ValueType &&value)
Definition: any.hpp:378
linb::any::construct
void construct(ValueType &&value)
Definition: any.hpp:393
linb::detail::any_cast_move_if_true
ValueType any_cast_move_if_true(typename std::remove_reference< ValueType >::type *p, std::false_type)
Definition: any.hpp:414
linb::any::vtable_dynamic::destroy
static void destroy(storage_union &storage) noexcept
Definition: any.hpp:236
linb::any::vtable_dynamic
VTable for dynamically allocated storage.
Definition: any.hpp:227
linb::any::vtable_type::destroy
void(* destroy)(storage_union &) noexcept
Definition: any.hpp:211
linb::any::any
any(ValueType &&value)
Definition: any.hpp:97
linb::bad_any_cast::what
const char * what() const noexcept override
Definition: any.hpp:49
linb::any::~any
~any()
Same effect as this->clear().
Definition: any.hpp:87
linb::any::vtable_type::move
void(* move)(storage_union &src, storage_union &dest) noexcept
Definition: any.hpp:219
linb::any::any_cast
const friend T * any_cast(const any *operand) noexcept
Definition: any.hpp:464
linb::any::vtable_stack
VTable for stack allocated storage.
Definition: any.hpp:262
linb::any::operator=
any & operator=(ValueType &&value)
Definition: any.hpp:126
linb::bad_any_cast
Definition: any.hpp:46
nanorpc::core::detail::pack::meta::type
type
Definition: pack_meta.h:26
linb::any::vtable_stack::move
static void move(storage_union &src, storage_union &dest) noexcept
Definition: any.hpp:281
linb::any::storage_union::dynamic
void * dynamic
Definition: any.hpp:194
linb::any
Definition: any.hpp:55
linb::any::operator=
any & operator=(any &&rhs) noexcept
Definition: any.hpp:115
std
Definition: Node.hpp:366
linb::any::vtable_type
Base VTable specification.
Definition: any.hpp:199
linb::any::swap
void swap(any &rhs) noexcept
Exchange the states of *this and rhs.
Definition: any.hpp:159
linb::any::storage_union::stack
stack_storage_t stack
Definition: any.hpp:195
linb::any::vtable_dynamic::copy
static void copy(const storage_union &src, storage_union &dest)
Definition: any.hpp:242
linb::any::vtable_for_type
static vtable_type * vtable_for_type()
Returns the pointer to the vtable of the type T.
Definition: any.hpp:309
linb::any::requires_allocation
Whether the type T must be dynamically allocated or can be stored on the stack.
Definition: any.hpp:300
linb::any::vtable
vtable_type * vtable
Definition: any.hpp:374
linb::any::clear
void clear() noexcept
If not empty, destroys the contained object.
Definition: any.hpp:135
linb::any::vtable_stack::copy
static void copy(const storage_union &src, storage_union &dest)
Definition: any.hpp:276
linb::any::vtable_type::copy
void(* copy)(const storage_union &src, storage_union &dest)
Definition: any.hpp:215
linb::any::vtable_dynamic::swap
static void swap(storage_union &lhs, storage_union &rhs) noexcept
Definition: any.hpp:253
linb::any::vtable_type::type
const std::type_info &(* type)() noexcept
The type of the object this vtable is for.
Definition: any.hpp:206
linb::any::vtable_dynamic::type
static const std::type_info & type() noexcept
Definition: any.hpp:230
linb::any::any
any(any &&rhs) noexcept
Definition: any.hpp:76
linb::any::any
any()
Constructs an object of type any with an empty state.
Definition: any.hpp:59
linb::any::vtable_dynamic::move
static void move(storage_union &src, storage_union &dest) noexcept
Definition: any.hpp:247


depthai
Author(s): Martin Peterlin
autogenerated on Sat Mar 22 2025 02:58:18