Simulant  21.12-1292
A portable game engine for Windows, OSX, Linux, Dreamcast, and PSP
any.h
1 /* * Copyright (c) 2011-2017 Luke Benstead https://simulant-engine.appspot.com
2  *
3  * This file is part of Simulant.
4  *
5  * Simulant is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU Lesser General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * Simulant is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public License
16  * along with Simulant. If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 #ifndef CORE_ANY_HPP
20 #define CORE_ANY_HPP
21 
22 #include <stdexcept>
23 #include <typeinfo>
24 #include <memory>
25 
26 #if defined(_MSC_VER)
27 #if __cplusplus >= 202002L
28  // C++20 (and later) code
29 #include <version>
30 #else
31 #include <ciso646>
32 #endif
33 #endif
34 
35 #include "type_traits.h"
36 #include "utility.h"
37 
38 namespace smlt {
39 inline namespace v1 {
40 namespace _any_impl {
41 
42 using data_type = add_pointer_t<void>;
43 
44 template <class Type>
45 using is_small = ::std::integral_constant<
46  bool,
47  sizeof(decay_t<Type>) <= sizeof(void*)
48 >;
49 
50 struct any_dispatch {
51  using destroy_function = void (*)(data_type&);
52  using clone_function = void(*)(data_type const&, data_type&);
53  using type_function = ::std::type_info const& (*)();
54 
55  destroy_function const destroy;
56  clone_function const clone;
57  type_function const type;
58 };
59 
60 template <class Type, bool=is_small<Type>::value>
62 
63 template <class Type>
64 struct any_dispatch_select<Type, true> {
65  using allocator_type = ::std::allocator<Type>;
66  using allocator_traits = ::std::allocator_traits<allocator_type>;
67 
68  static void clone (data_type const& source, data_type& data) {
69  allocator_type alloc { };
70  auto const& value = reinterpret_cast<Type const&>(source);
71  auto& ref = reinterpret_cast<Type&>(data);
72  allocator_traits::construct(alloc, ::std::addressof(ref), value);
73  }
74 
75  static void destroy (data_type& data) {
76  allocator_type alloc { };
77  auto& ref = reinterpret_cast<Type&>(data);
78  allocator_traits::destroy(alloc, ::std::addressof(ref));
79  }
80 };
81 
82 template <class Type>
83 struct any_dispatch_select<Type, false> {
84  using allocator_type = ::std::allocator<Type>;
85  using allocator_traits = ::std::allocator_traits<allocator_type>;
86 
87  static void clone (data_type const& source, data_type& data) {
88  allocator_type alloc { };
89  auto const& value = *static_cast<Type* const>(source);
90  auto pointer = allocator_traits::allocate(alloc, 1);
91  auto scope = make_scope_guard([&alloc, pointer] {
92  allocator_traits::deallocate(alloc, pointer, 1);
93  });
94  allocator_traits::construct(alloc, pointer, value);
95  scope.dismiss();
96  data = pointer;
97  }
98 
99  static void destroy (data_type& data) {
100  allocator_type alloc { };
101  auto value = static_cast<Type*>(data);
102  allocator_traits::destroy(alloc, value);
103  allocator_traits::deallocate(alloc, value, 1);
104  }
105 };
106 
107 template <class Type>
108 any_dispatch const* get_any_dispatch () {
109  static any_dispatch const instance = {
112  [] () -> ::std::type_info const& { return typeid(Type); }
113  };
114  return ::std::addressof(instance);
115 }
116 
117 template <>
118 inline any_dispatch const* get_any_dispatch<void> () {
119  static any_dispatch const instance = {
120  [] (data_type&) { },
121  [] (data_type const&, data_type&) { },
122  [] () -> ::std::type_info const& { return typeid(void); }
123  };
124  return ::std::addressof(instance);
125 }
126 
127 } /* namespace impl */
128 
129 class bad_any_cast final : public ::std::bad_cast {
130 public:
131  virtual char const* what () const noexcept override {
132  return "bad any cast";
133  }
134 };
135 
136 class any final {
137  template <class ValueType>
138  friend ValueType const* any_cast (any const*) noexcept;
139  template <class ValueType> friend ValueType* any_cast (any*) noexcept;
140 
141  _any_impl::any_dispatch const* table;
142  _any_impl::data_type data;
143 
144  template <class ValueType>
145  any (ValueType&& value, ::std::true_type&&) :
146  table { _any_impl::get_any_dispatch<decay_t<ValueType>>() },
147  data { nullptr }
148  {
149  using value_type = decay_t<ValueType>;
150  using allocator_type = ::std::allocator<value_type>;
151  allocator_type alloc { };
152  auto pointer = reinterpret_cast<value_type*>(::std::addressof(this->data));
153  ::std::allocator_traits<allocator_type>::construct(
154  alloc, pointer, ::std::forward<ValueType>(value)
155  );
156  }
157 
158  template <class ValueType>
159  any (ValueType&& value, ::std::false_type&&) :
160  table { _any_impl::get_any_dispatch<decay_t<ValueType>>() },
161  data { nullptr }
162  {
163  using value_type = decay_t<ValueType>;
164  using allocator_type = ::std::allocator<value_type>;
165  allocator_type alloc { };
166  auto pointer = ::std::allocator_traits<allocator_type>::allocate(alloc, 1);
167  ::std::allocator_traits<allocator_type>::construct(
168  alloc, pointer, ::std::forward<ValueType>(value)
169  );
170  this->data = pointer;
171  }
172 
173  template <class ValueType>
174  ValueType const* cast (::std::true_type&&) const {
175  return reinterpret_cast<ValueType const*>(::std::addressof(this->data));
176  }
177 
178  template <class ValueType>
179  ValueType* cast (::std::true_type&&) {
180  return reinterpret_cast<ValueType*>(::std::addressof(this->data));
181  }
182 
183  template <class ValueType>
184  ValueType const* cast (::std::false_type&&) const {
185  return static_cast<ValueType const*>(this->data);
186  }
187 
188  template <class ValueType>
189  ValueType* cast (::std::false_type&&) {
190  return static_cast<ValueType*>(this->data);
191  }
192 
193 public:
194  any (any const& that) :
195  table { that.table },
196  data { nullptr }
197  { this->table->clone(that.data, this->data); }
198 
199  any (any&& that) noexcept :
200  table { that.table },
201  data { that.data }
202  {
203  that.table = _any_impl::get_any_dispatch<void>();
204  that.data = nullptr;
205  }
206 
207  any () noexcept :
208  table { _any_impl::get_any_dispatch<void>() },
209  data { nullptr }
210  { }
211 
212  template <
213  class ValueType,
214  class=enable_if_t<! ::std::is_same<any, decay_t<ValueType>>::value>
215  > any (ValueType&& value) :
216  any { ::std::forward<ValueType>(value), _any_impl::is_small<ValueType> { } }
217  { }
218 
219  ~any () noexcept { this->clear(); }
220 
221  any& operator = (any const& that) {
222  any { that }.swap(*this);
223  return *this;
224  }
225 
226  any& operator = (any&& that) noexcept {
227  any { ::std::move(that) }.swap(*this);
228  return *this;
229  }
230 
231  template <
232  class ValueType,
233  class=enable_if_t<! ::std::is_same<any, decay_t<ValueType>>::value>
234  > any& operator = (ValueType&& value) {
235  any {
236  ::std::forward<ValueType>(value),
237  _any_impl::is_small<ValueType> { }
238  }.swap(*this);
239  return *this;
240  }
241 
242  void swap (any& that) noexcept {
243  using ::std::swap;
244  swap(this->table, that.table);
245  swap(this->data, that.data);
246  }
247 
248  void clear () noexcept {
249  this->table->destroy(this->data);
250  this->table = _any_impl::get_any_dispatch<void>();
251  }
252 
253  ::std::type_info const& type () const noexcept {
254  return this->table->type();
255  }
256 
257  bool empty () const noexcept {
258  return this->table == _any_impl::get_any_dispatch<void>();
259  }
260 
261 };
262 
263 template <class ValueType>
264 ValueType const* any_cast (any const* operand) noexcept {
265  return operand && operand->type() == typeid(ValueType)
266  ? operand->cast<ValueType>(_any_impl::is_small<ValueType> { })
267  : nullptr;
268 }
269 
270 template <class ValueType>
271 ValueType* any_cast (any* operand) noexcept {
272  return operand && operand->type() == typeid(ValueType)
273  ? operand->cast<ValueType>(_any_impl::is_small<ValueType> { })
274  : nullptr;
275 }
276 
277 template <
278  class ValueType,
279  class=enable_if_t<
280  ::std::is_reference<ValueType>::value or
281  ::std::is_copy_constructible<ValueType>::value
282  >
283 > ValueType any_cast (any const& operand) {
284  using type = remove_reference_t<ValueType>;
285  auto pointer = any_cast<add_const_t<type>>(::std::addressof(operand));
286  if (!pointer) { throw bad_any_cast { }; }
287  return *pointer;
288 }
289 
290 template <
291  class ValueType,
292  class=enable_if_t<
293  ::std::is_reference<ValueType>::value or
294  ::std::is_copy_constructible<ValueType>::value
295  >
296 > ValueType any_cast (any&& operand) {
297  using type = remove_reference_t<ValueType>;
298  auto pointer = any_cast<type>(::std::addressof(operand));
299  if (!pointer) { throw bad_any_cast { }; }
300  return *pointer;
301 }
302 
303 template <
304  class ValueType,
305  class=enable_if_t<
306  ::std::is_reference<ValueType>::value or
307  ::std::is_copy_constructible<ValueType>::value
308  >
309 > ValueType any_cast (any& operand) {
310  using type = remove_reference_t<ValueType>;
311  auto pointer = any_cast<type>(::std::addressof(operand));
312  if (!pointer) { throw bad_any_cast { }; }
313  return *pointer;
314 }
315 
316 inline void swap (any& lhs, any& rhs) noexcept { lhs.swap(rhs); }
317 
318 }} /* namespace core::v1 */
319 
320 #endif /* CORE_ANY_HPP */
smlt::v1::_any_impl::any_dispatch_select
Definition: any.h:61
smlt::v1::bad_any_cast
Definition: any.h:129
smlt::v1::any
Definition: any.h:136
smlt
Definition: animation.cpp:25
smlt::v1::_any_impl::any_dispatch
Definition: any.h:50