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 namespace linb
24 {
25 class bad_any_cast : public std::bad_cast
26 {
27  public:
28  const char* what() const noexcept override
29  {
30  return "bad any cast";
31  }
32 };
33 
34 class any final
35 {
36  public:
38  any() : vtable(nullptr)
39  {
40  }
41 
43  any(const any& rhs) : vtable(rhs.vtable)
44  {
45  if (!rhs.empty())
46  {
47  rhs.vtable->copy(rhs.storage, this->storage);
48  }
49  }
50 
53  any(any&& rhs) noexcept : vtable(rhs.vtable)
54  {
55  if (!rhs.empty())
56  {
57  rhs.vtable->move(rhs.storage, this->storage);
58  rhs.vtable = nullptr;
59  }
60  }
61 
63  ~any()
64  {
65  this->clear();
66  }
67 
72  template <typename ValueType, typename = typename std::enable_if<!std::is_same<
73  typename std::decay<ValueType>::type, any>::value>::type>
74  any(ValueType&& value)
75  {
76  static_assert(std::is_copy_constructible<typename std::decay<ValueType>::type>::value,
77  "T shall satisfy the CopyConstructible requirements.");
78  this->construct(std::forward<ValueType>(value));
79  }
80 
82  any& operator=(const any& rhs)
83  {
84  any(rhs).swap(*this);
85  return *this;
86  }
87 
92  any& operator=(any&& rhs) noexcept
93  {
94  any(std::move(rhs)).swap(*this);
95  return *this;
96  }
97 
102  template <typename ValueType, typename = typename std::enable_if<!std::is_same<
103  typename std::decay<ValueType>::type, any>::value>::type>
104  any& operator=(ValueType&& value)
105  {
106  static_assert(std::is_copy_constructible<typename std::decay<ValueType>::type>::value,
107  "T shall satisfy the CopyConstructible requirements.");
108  any(std::forward<ValueType>(value)).swap(*this);
109  return *this;
110  }
111 
113  void clear() noexcept
114  {
115  if (!empty())
116  {
117  this->vtable->destroy(storage);
118  this->vtable = nullptr;
119  }
120  }
121 
123  bool empty() const noexcept
124  {
125  return this->vtable == nullptr;
126  }
127 
129  const std::type_info& type() const noexcept
130  {
131  return empty() ? typeid(void) : this->vtable->type();
132  }
133 
135  void swap(any& rhs) noexcept
136  {
137  if (this->vtable != rhs.vtable)
138  {
139  any tmp(std::move(rhs));
140 
141  // move from *this to rhs.
142  rhs.vtable = this->vtable;
143  if (this->vtable != nullptr)
144  {
145  this->vtable->move(this->storage, rhs.storage);
146  //this->vtable = nullptr; -- uneeded, see below
147  }
148 
149  // move from tmp (previously rhs) to *this.
150  this->vtable = tmp.vtable;
151  if (tmp.vtable != nullptr)
152  {
153  tmp.vtable->move(tmp.storage, this->storage);
154  tmp.vtable = nullptr;
155  }
156  }
157  else // same types
158  {
159  if (this->vtable != nullptr)
160  this->vtable->swap(this->storage, rhs.storage);
161  }
162  }
163 
164  private: // Storage and Virtual Method Table
166  {
167  using stack_storage_t =
168  typename std::aligned_storage<2 * sizeof(void*), std::alignment_of<void*>::value>::type;
169 
170  void* dynamic;
171  stack_storage_t stack; // 2 words for e.g. shared_ptr
172  };
173 
175  struct vtable_type
176  {
177  // Note: The caller is responssible for doing .vtable = nullptr after destructful operations
178  // such as destroy() and/or move().
179 
181  const std::type_info& (*type)() noexcept;
182 
185  void (*destroy)(storage_union&) noexcept;
186 
189  void (*copy)(const storage_union& src, storage_union& dest);
190 
193  void (*move)(storage_union& src, storage_union& dest) noexcept;
194 
196  void (*swap)(storage_union& lhs, storage_union& rhs) noexcept;
197  };
198 
200  template <typename T>
202  {
203  static const std::type_info& type() noexcept
204  {
205  return typeid(T);
206  }
207 
208  static void destroy(storage_union& storage) noexcept
209  {
210  //assert(reinterpret_cast<T*>(storage.dynamic));
211  delete reinterpret_cast<T*>(storage.dynamic);
212  }
213 
214  static void copy(const storage_union& src, storage_union& dest)
215  {
216  dest.dynamic = new T(*reinterpret_cast<const T*>(src.dynamic));
217  }
218 
219  static void move(storage_union& src, storage_union& dest) noexcept
220  {
221  dest.dynamic = src.dynamic;
222  src.dynamic = nullptr;
223  }
224 
225  static void swap(storage_union& lhs, storage_union& rhs) noexcept
226  {
227  // just exchage the storage pointers.
228  std::swap(lhs.dynamic, rhs.dynamic);
229  }
230  };
231 
233  template <typename T>
235  {
236  static const std::type_info& type() noexcept
237  {
238  return typeid(T);
239  }
240 
241  static void destroy(storage_union& storage) noexcept
242  {
243  reinterpret_cast<T*>(&storage.stack)->~T();
244  }
245 
246  static void copy(const storage_union& src, storage_union& dest)
247  {
248  new (&dest.stack) T(reinterpret_cast<const T&>(src.stack));
249  }
250 
251  static void move(storage_union& src, storage_union& dest) noexcept
252  {
253  // one of the conditions for using vtable_stack is a nothrow move constructor,
254  // so this move constructor will never throw a exception.
255  new (&dest.stack) T(std::move(reinterpret_cast<T&>(src.stack)));
256  destroy(src);
257  }
258 
259  static void swap(storage_union& lhs, storage_union& rhs) noexcept
260  {
261  storage_union tmp_storage;
262  move(rhs, tmp_storage);
263  move(lhs, rhs);
264  move(tmp_storage, lhs);
265  }
266  };
267 
269  template <typename T>
271  : std::integral_constant<
272  bool,
273  !(std::is_nothrow_move_constructible<T>::value // N4562 �6.3/3 [any.class]
274  && sizeof(T) <= sizeof(storage_union::stack) &&
275  std::alignment_of<T>::value <=
276  std::alignment_of<storage_union::stack_storage_t>::value)>
277  {
278  };
279 
281  template <typename T>
282  static vtable_type* vtable_for_type()
283  {
284  using VTableType = typename std::conditional<requires_allocation<T>::value,
285  vtable_dynamic<T>, vtable_stack<T>>::type;
286  static vtable_type table = {
287  VTableType::type, VTableType::destroy, VTableType::copy,
288  VTableType::move, VTableType::swap,
289  };
290  return &table;
291  }
292 
293  protected:
294  template <typename T>
295  friend const T* any_cast(const any* operand) noexcept;
296  template <typename T>
297  friend T* any_cast(any* operand) noexcept;
298 
300  bool is_typed(const std::type_info& t) const
301  {
302  return is_same(this->type(), t);
303  }
304 
311  static bool is_same(const std::type_info& a, const std::type_info& b)
312  {
313 #ifdef ANY_IMPL_FAST_TYPE_INFO_COMPARE
314  return &a == &b;
315 #else
316  return a == b;
317 #endif
318  }
319 
321  template <typename T>
322  const T* cast() const noexcept
323  {
324  return requires_allocation<typename std::decay<T>::type>::value ?
325  reinterpret_cast<const T*>(storage.dynamic) :
326  reinterpret_cast<const T*>(&storage.stack);
327  }
328 
330  template <typename T>
331  T* cast() noexcept
332  {
333  return requires_allocation<typename std::decay<T>::type>::value ?
334  reinterpret_cast<T*>(storage.dynamic) :
335  reinterpret_cast<T*>(&storage.stack);
336  }
337 
338  private:
339  storage_union storage; // on offset(0) so no padding for align
340  vtable_type* vtable;
341 
342  template <typename ValueType, typename T>
343  typename std::enable_if<requires_allocation<T>::value>::type do_construct(ValueType&& value)
344  {
345  storage.dynamic = new T(std::forward<ValueType>(value));
346  }
347 
348  template <typename ValueType, typename T>
349  typename std::enable_if<!requires_allocation<T>::value>::type do_construct(ValueType&& value)
350  {
351  new (&storage.stack) T(std::forward<ValueType>(value));
352  }
353 
356  template <typename ValueType>
357  void construct(ValueType&& value)
358  {
359  using T = typename std::decay<ValueType>::type;
360 
361  this->vtable = vtable_for_type<T>();
362 
363  do_construct<ValueType, T>(std::forward<ValueType>(value));
364  }
365 };
366 
367 namespace detail
368 {
369 template <typename ValueType>
370 inline ValueType any_cast_move_if_true(typename std::remove_reference<ValueType>::type* p,
371  std::true_type)
372 {
373  return std::move(*p);
374 }
375 
376 template <typename ValueType>
377 inline ValueType any_cast_move_if_true(typename std::remove_reference<ValueType>::type* p,
378  std::false_type)
379 {
380  return *p;
381 }
382 }
383 
385 template <typename ValueType>
386 inline ValueType any_cast(const any& operand)
387 {
388  auto p =
389  any_cast<typename std::add_const<typename std::remove_reference<ValueType>::type>::type>(
390  &operand);
391  if (p == nullptr)
392  throw bad_any_cast();
393  return *p;
394 }
395 
397 template <typename ValueType>
398 inline ValueType any_cast(any& operand)
399 {
400  auto p = any_cast<typename std::remove_reference<ValueType>::type>(&operand);
401  if (p == nullptr)
402  throw bad_any_cast();
403  return *p;
404 }
405 
415 template <typename ValueType>
416 inline ValueType any_cast(any&& operand)
417 {
418 #ifdef ANY_IMPL_ANY_CAST_MOVEABLE
419  // https://cplusplus.github.io/LWG/lwg-active.html#2509
420  using can_move = std::integral_constant<bool, std::is_move_constructible<ValueType>::value &&
421  !std::is_lvalue_reference<ValueType>::value>;
422 #else
423  using can_move = std::false_type;
424 #endif
425 
426  auto p = any_cast<typename std::remove_reference<ValueType>::type>(&operand);
427  if (p == nullptr)
428  throw bad_any_cast();
429  return detail::any_cast_move_if_true<ValueType>(p, can_move());
430 }
431 
434 template <typename T>
435 inline const T* any_cast(const any* operand) noexcept
436 {
437  if (operand == nullptr || !operand->is_typed(typeid(T)))
438  return nullptr;
439  else
440  return operand->cast<T>();
441 }
442 
445 template <typename T>
446 inline T* any_cast(any* operand) noexcept
447 {
448  if (operand == nullptr || !operand->is_typed(typeid(T)))
449  return nullptr;
450  else
451  return operand->cast<T>();
452 }
453 }
454 
455 namespace std
456 {
457 inline void swap(linb::any& lhs, linb::any& rhs) noexcept
458 {
459  lhs.swap(rhs);
460 }
461 }
462 
463 #endif
void(* swap)(storage_union &lhs, storage_union &rhs) noexcept
Exchanges the storage between lhs and rhs.
Definition: any.hpp:196
any(ValueType &&value)
Definition: any.hpp:74
static void copy(const storage_union &src, storage_union &dest)
Definition: any.hpp:246
static void destroy(storage_union &storage) noexcept
Definition: any.hpp:241
static void swap(storage_union &lhs, storage_union &rhs) noexcept
Definition: any.hpp:259
VTable for stack allocated storage.
Definition: any.hpp:234
any(const any &rhs)
Constructs an object of type any with an equivalent state as other.
Definition: any.hpp:43
bool empty() const noexcept
Returns true if *this has no contained object, otherwise false.
Definition: any.hpp:123
void(* copy)(const storage_union &src, storage_union &dest)
Definition: any.hpp:189
any & operator=(const any &rhs)
Has the same effect as any(rhs).swap(*this). No effects if an exception is thrown.
Definition: any.hpp:82
void(* move)(storage_union &src, storage_union &dest) noexcept
Definition: any.hpp:193
typename std::aligned_storage< 2 *sizeof(void *), std::alignment_of< void * >::value >::type stack_storage_t
Definition: any.hpp:168
Definition: any.hpp:455
ValueType any_cast(const any &operand)
Performs *any_cast<add_const_t<remove_reference_t<ValueType>>>(&operand), or throws bad_any_cast on f...
Definition: any.hpp:386
void swap(linb::any &lhs, linb::any &rhs) noexcept
Definition: any.hpp:457
any()
Constructs an object of type any with an empty state.
Definition: any.hpp:38
~any()
Same effect as this->clear().
Definition: any.hpp:63
any & operator=(ValueType &&value)
Definition: any.hpp:104
storage_union storage
Definition: any.hpp:339
VTable for dynamically allocated storage.
Definition: any.hpp:201
Definition: any.hpp:23
static void swap(storage_union &lhs, storage_union &rhs) noexcept
Definition: any.hpp:225
static const std::type_info & type() noexcept
Definition: any.hpp:203
static void move(storage_union &src, storage_union &dest) noexcept
Definition: any.hpp:219
static void copy(const storage_union &src, storage_union &dest)
Definition: any.hpp:214
Base VTable specification.
Definition: any.hpp:175
any & operator=(any &&rhs) noexcept
Definition: any.hpp:92
vtable_type * vtable
Definition: any.hpp:340
static void move(storage_union &src, storage_union &dest) noexcept
Definition: any.hpp:251
static void destroy(storage_union &storage) noexcept
Definition: any.hpp:208
typename std::enable_if< Predicate::value >::type * enable_if
Definition: basic_types.h:168
void clear() noexcept
If not empty, destroys the contained object.
Definition: any.hpp:113
stack_storage_t stack
Definition: any.hpp:171
const char * what() const noexceptoverride
Definition: any.hpp:28
any(any &&rhs) noexcept
Definition: any.hpp:53
const std::type_info & type() const noexcept
If *this has a contained object of type T, typeid(T); otherwise typeid(void).
Definition: any.hpp:129
Whether the type T must be dynamically allocated or can be stored on the stack.
Definition: any.hpp:270
ValueType any_cast_move_if_true(typename std::remove_reference< ValueType >::type *p, std::false_type)
Definition: any.hpp:377
void swap(any &rhs) noexcept
Exchange the states of *this and rhs.
Definition: any.hpp:135
static const std::type_info & type() noexcept
Definition: any.hpp:236


behaviotree_cpp_v3
Author(s): Michele Colledanchise, Davide Faconti
autogenerated on Tue May 4 2021 02:56:24