omega_h
Reliable mesh adaptation
Omega_h_any.hpp
1 //
2 // Implementation of N4562 std::experimental::any (merged into C++17) for C++11
3 // compilers.
4 //
5 // See also:
6 // + http://en.cppreference.com/w/cpp/any
7 // + http://en.cppreference.com/w/cpp/experimental/any
8 // + http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4562.html#any
9 // + https://cplusplus.github.io/LWG/lwg-active.html#2509
10 //
11 //
12 // Copyright (c) 2016 Denilson das Merces Amorim
13 //
14 // Distributed under the Boost Software License, Version 1.0.
15 // (See below or copy at http://www.boost.org/LICENSE_1_0.txt)
16 //
17 
18 /*
19 Boost Software License - Version 1.0 - August 17th, 2003
20 
21 Permission is hereby granted, free of charge, to any person or organization
22 obtaining a copy of the software and accompanying documentation covered by
23 this license (the "Software") to use, reproduce, display, distribute,
24 execute, and transmit the Software, and to prepare derivative works of the
25 Software, and to permit third-parties to whom the Software is furnished to
26 do so, all subject to the following:
27 
28 The copyright notices in the Software and this entire statement, including
29 the above license grant, this restriction and the following disclaimer,
30 must be included in all copies of the Software, in whole or in part, and
31 all derivative works of the Software, unless such copies or derivative
32 works are solely in the form of machine-executable object code generated by
33 a source language processor.
34 
35 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
36 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
37 FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
38 SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
39 FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
40 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
41 DEALINGS IN THE SOFTWARE.
42 */
43 
44 // Copied into Omega_h by Dan Ibanez as a stopgap until C++17 can be relied on
45 // Changed to namespace Omega_h to prevent conflicts with other versions
46 
47 #ifndef OMEGA_H_ANY_HPP
48 #define OMEGA_H_ANY_HPP
49 
50 #include <Omega_h_fail.hpp>
51 #include <stdexcept>
52 #include <type_traits>
53 #include <typeinfo>
54 #include <utility>
55 
56 namespace Omega_h {
57 
58 class bad_any_cast : public std::bad_cast {
59  public:
60  const char* what() const noexcept override;
61 };
62 
63 #ifdef __GNUC__
64 #pragma GCC diagnostic push
65 #pragma GCC diagnostic ignored "-Wstrict-aliasing"
66 #endif
67 
68 class any final {
69  public:
71  any() : vtable(nullptr) {}
72 
74  any(const any& rhs) : vtable(rhs.vtable) {
75  if (!rhs.empty()) {
76  rhs.vtable->copy(rhs.storage, this->storage);
77  }
78  }
79 
82  any(any&& rhs) noexcept : vtable(rhs.vtable) {
83  if (!rhs.empty()) {
84  rhs.vtable->move(rhs.storage, this->storage);
85  rhs.vtable = nullptr;
86  }
87  }
88 
90  ~any() { this->clear(); }
91 
98  template <typename ValueType,
99  typename = typename std::enable_if<!std::is_same<
100  typename std::decay<ValueType>::type, any>::value>::type>
101  any(ValueType&& value) {
102  static_assert(
103  std::is_copy_constructible<typename std::decay<ValueType>::type>::value,
104  "T shall satisfy the CopyConstructible requirements.");
105  this->construct(std::forward<ValueType>(value));
106  }
107 
110  any& operator=(const any& rhs) {
111  any(rhs).swap(*this);
112  return *this;
113  }
114 
119  any& operator=(any&& rhs) noexcept {
120  any(std::move(rhs)).swap(*this);
121  return *this;
122  }
123 
130  template <typename ValueType,
131  typename = typename std::enable_if<!std::is_same<
132  typename std::decay<ValueType>::type, any>::value>::type>
133  any& operator=(ValueType&& value) {
134  static_assert(
135  std::is_copy_constructible<typename std::decay<ValueType>::type>::value,
136  "T shall satisfy the CopyConstructible requirements.");
137  any(std::forward<ValueType>(value)).swap(*this);
138  return *this;
139  }
140 
142  void clear() noexcept {
143  if (!empty()) {
144  this->vtable->destroy(storage);
145  this->vtable = nullptr;
146  }
147  }
148 
150  bool empty() const noexcept { return this->vtable == nullptr; }
151 
154  const std::type_info& type() const noexcept {
155  return empty() ? typeid(void) : this->vtable->type();
156  }
157 
159  void swap(any& rhs) noexcept {
160  if (this->vtable != rhs.vtable) {
161  any tmp(std::move(rhs));
162 
163  // move from *this to rhs.
164  rhs.vtable = this->vtable;
165  if (this->vtable != nullptr) {
166  this->vtable->move(this->storage, rhs.storage);
167  // this->vtable = nullptr; -- uneeded, see below
168  }
169 
170  // move from tmp (previously rhs) to *this.
171  this->vtable = tmp.vtable;
172  if (tmp.vtable != nullptr) {
173  tmp.vtable->move(tmp.storage, this->storage);
174  tmp.vtable = nullptr;
175  }
176  } else // same types
177  {
178  if (this->vtable != nullptr)
179  this->vtable->swap(this->storage, rhs.storage);
180  }
181  }
182 
183  private: // Storage and Virtual Method Table
184  union storage_union {
185  using stack_storage_t = typename std::aligned_storage<2 * sizeof(void*),
186  std::alignment_of<void*>::value>::type;
187 
188  void* dynamic;
189  stack_storage_t stack; // 2 words for e.g. shared_ptr
190  };
191 
193  struct vtable_type {
194  // Note: The caller is responssible for doing .vtable = nullptr after
195  // destructful operations such as destroy() and/or move().
196 
198  const std::type_info& (*type)() noexcept;
199 
203  void (*destroy)(storage_union&) noexcept;
204 
208  void (*copy)(const storage_union& src, storage_union& dest);
209 
213  void (*move)(storage_union& src, storage_union& dest) noexcept;
214 
216  void (*swap)(storage_union& lhs, storage_union& rhs) noexcept;
217  };
218 
220  template <typename T>
221  struct vtable_dynamic {
222  static const std::type_info& type() noexcept { return typeid(T); }
223 
224  static void destroy(storage_union& storage) noexcept {
225  // assert(reinterpret_cast<T*>(storage.dynamic));
226  delete reinterpret_cast<T*>(storage.dynamic);
227  }
228 
229  static void copy(const storage_union& src, storage_union& dest) {
230  dest.dynamic = new T(*reinterpret_cast<const T*>(src.dynamic));
231  }
232 
233  static void move(storage_union& src, storage_union& dest) noexcept {
234  dest.dynamic = src.dynamic;
235  src.dynamic = nullptr;
236  }
237 
238  static void swap(storage_union& lhs, storage_union& rhs) noexcept {
239  // just exchage the storage pointers.
240  std::swap(lhs.dynamic, rhs.dynamic);
241  }
242  };
243 
245  template <typename T>
246  struct vtable_stack {
247  static const std::type_info& type() noexcept { return typeid(T); }
248 
249  static void destroy(storage_union& storage) noexcept {
250  reinterpret_cast<T*>(&storage.stack)->~T();
251  }
252 
253  static void copy(const storage_union& src, storage_union& dest) {
254  new (&dest.stack) T(reinterpret_cast<const T&>(src.stack));
255  }
256 
257  static void move(storage_union& src, storage_union& dest) noexcept {
258  // one of the conditions for using vtable_stack is a nothrow move
259  // constructor, so this move constructor will never throw a exception.
260  new (&dest.stack) T(std::move(reinterpret_cast<T&>(src.stack)));
261  destroy(src);
262  }
263 
264  static void swap(storage_union& lhs, storage_union& rhs) noexcept {
265  std::swap(
266  reinterpret_cast<T&>(lhs.stack), reinterpret_cast<T&>(rhs.stack));
267  }
268  };
269 
272  template <typename T>
273  struct requires_allocation
274  : std::integral_constant<bool,
275  !(std::is_nothrow_move_constructible<T>::value // N4562 6.3/3
276  // [any.class]
277  && sizeof(T) <= sizeof(storage_union::stack) &&
278  std::alignment_of<T>::value <=
279  std::alignment_of<storage_union::stack_storage_t>::value)> {
280  };
281 
283  template <typename T>
284  static vtable_type* vtable_for_type() {
285  using VTableType = typename std::conditional<requires_allocation<T>::value,
286  vtable_dynamic<T>, vtable_stack<T>>::type;
287  static vtable_type table = {
288  VTableType::type,
289  VTableType::destroy,
290  VTableType::copy,
291  VTableType::move,
292  VTableType::swap,
293  };
294  return &table;
295  }
296 
297  protected:
298  template <typename T>
299  friend const T* any_cast(const any* operand) noexcept;
300  template <typename T>
301  friend T* any_cast(any* operand) noexcept;
302 
304  bool is_typed(const std::type_info& t) const {
305  return is_same(this->type(), t);
306  }
307 
314  static bool is_same(const std::type_info& a, const std::type_info& b) {
315 #ifdef ANY_IMPL_FAST_TYPE_INFO_COMPARE
316  return &a == &b;
317 #else
318  return a == b;
319 #endif
320  }
321 
323  template <typename T>
324  const T* cast() const noexcept {
325  return requires_allocation<typename std::decay<T>::type>::value
326  ? reinterpret_cast<const T*>(storage.dynamic)
327  : reinterpret_cast<const T*>(&storage.stack);
328  }
329 
331  template <typename T>
332  T* cast() noexcept {
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(
344  ValueType&& value) {
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(
350  ValueType&& value) {
351  new (&storage.stack) T(std::forward<ValueType>(value));
352  }
353 
357  template <typename ValueType>
358  void construct(ValueType&& value) {
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 #ifdef __GNUC__
368 #pragma GCC diagnostic pop
369 #endif
370 
371 namespace detail {
372 template <typename ValueType>
373 inline ValueType any_cast_move_if_true(
374  typename std::remove_reference<ValueType>::type* p, std::true_type) {
375  return std::move(*p);
376 }
377 
378 template <typename ValueType>
379 inline ValueType any_cast_move_if_true(
380  typename std::remove_reference<ValueType>::type* p, std::false_type) {
381  return *p;
382 }
383 } // namespace detail
384 
387 template <typename ValueType>
388 inline ValueType any_cast(const any& operand) {
389  auto p = any_cast<typename std::add_const<
390  typename std::remove_reference<ValueType>::type>::type>(&operand);
391  if (p == nullptr) throw bad_any_cast();
392  return *p;
393 }
394 
397 template <typename ValueType>
398 inline ValueType any_cast(any& operand) {
399  auto p = any_cast<typename std::remove_reference<ValueType>::type>(&operand);
400  if (p == nullptr) throw bad_any_cast();
401  return *p;
402 }
403 
415 template <typename ValueType>
416 inline ValueType any_cast(any&& operand) {
417  // https://cplusplus.github.io/LWG/lwg-active.html#2509
418  using can_move = std::integral_constant<bool,
419  std::is_move_constructible<ValueType>::value &&
420  !std::is_lvalue_reference<ValueType>::value>;
421 
422  auto p = any_cast<typename std::remove_reference<ValueType>::type>(&operand);
423  if (p == nullptr) throw bad_any_cast();
424  return detail::any_cast_move_if_true<ValueType>(p, can_move());
425 }
426 
429 template <typename T>
430 inline const T* any_cast(const any* operand) noexcept {
431  if (operand == nullptr || !operand->is_typed(typeid(T)))
432  return nullptr;
433  else
434  return operand->cast<T>();
435 }
436 
439 template <typename T>
440 inline T* any_cast(any* operand) noexcept {
441  if (operand == nullptr || !operand->is_typed(typeid(T)))
442  return nullptr;
443  else
444  return operand->cast<T>();
445 }
446 
447 template <typename T>
448 T&& move_value(any& a) {
449  auto any_ptr = &(a);
450  auto value_ptr = any_cast<T>(any_ptr);
451  OMEGA_H_CHECK(value_ptr != nullptr);
452  return std::move(*value_ptr);
453 }
454 
455 inline void swap(Omega_h::any& lhs, Omega_h::any& rhs) noexcept {
456  lhs.swap(rhs);
457 }
458 
459 } // end namespace Omega_h
460 
461 #endif
Definition: Omega_h_any.hpp:68
any()
Constructs an object of type any with an empty state.
Definition: Omega_h_any.hpp:71
any & operator=(any &&rhs) noexcept
Definition: Omega_h_any.hpp:119
~any()
Same effect as this->clear().
Definition: Omega_h_any.hpp:90
void swap(any &rhs) noexcept
Exchange the states of *this and rhs.
Definition: Omega_h_any.hpp:159
friend const T * any_cast(const any *operand) noexcept
Definition: Omega_h_any.hpp:430
any(ValueType &&value)
Definition: Omega_h_any.hpp:101
any & operator=(ValueType &&value)
Definition: Omega_h_any.hpp:133
any(any &&rhs) noexcept
Definition: Omega_h_any.hpp:82
void clear() noexcept
If not empty, destroys the contained object.
Definition: Omega_h_any.hpp:142
const std::type_info & type() const noexcept
Definition: Omega_h_any.hpp:154
any(const any &rhs)
Constructs an object of type any with an equivalent state as other.
Definition: Omega_h_any.hpp:74
bool empty() const noexcept
Returns true if *this has no contained object, otherwise false.
Definition: Omega_h_any.hpp:150
any & operator=(const any &rhs)
Definition: Omega_h_any.hpp:110
Definition: Omega_h_any.hpp:58
Definition: amr_mpi_test.cpp:6