Simulant  21.12-574
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 #include "type_traits.h"
27 #include "utility.h"
28 
29 namespace smlt {
30 inline namespace v1 {
31 namespace impl {
32 
33 using data_type = add_pointer_t<void>;
34 
35 template <class Type>
36 using is_small = ::std::integral_constant<
37  bool,
38  sizeof(decay_t<Type>) <= sizeof(void*)
39 >;
40 
41 struct any_dispatch {
42  using destroy_function = void (*)(data_type&);
43  using clone_function = void(*)(data_type const&, data_type&);
44  using type_function = ::std::type_info const& (*)();
45 
46  destroy_function const destroy;
47  clone_function const clone;
48  type_function const type;
49 };
50 
51 template <class Type, bool=is_small<Type>::value>
53 
54 template <class Type>
55 struct any_dispatch_select<Type, true> {
56  using allocator_type = ::std::allocator<Type>;
57  using allocator_traits = ::std::allocator_traits<allocator_type>;
58 
59  static void clone (data_type const& source, data_type& data) {
60  allocator_type alloc { };
61  auto const& value = reinterpret_cast<Type const&>(source);
62  auto& ref = reinterpret_cast<Type&>(data);
63  allocator_traits::construct(alloc, ::std::addressof(ref), value);
64  }
65 
66  static void destroy (data_type& data) {
67  allocator_type alloc { };
68  auto& ref = reinterpret_cast<Type&>(data);
69  allocator_traits::destroy(alloc, ::std::addressof(ref));
70  }
71 };
72 
73 template <class Type>
74 struct any_dispatch_select<Type, false> {
75  using allocator_type = ::std::allocator<Type>;
76  using allocator_traits = ::std::allocator_traits<allocator_type>;
77 
78  static void clone (data_type const& source, data_type& data) {
79  allocator_type alloc { };
80  auto const& value = *static_cast<Type* const>(source);
81  auto pointer = allocator_traits::allocate(alloc, 1);
82  auto scope = make_scope_guard([&alloc, pointer] {
83  allocator_traits::deallocate(alloc, pointer, 1);
84  });
85  allocator_traits::construct(alloc, pointer, value);
86  scope.dismiss();
87  data = pointer;
88  }
89 
90  static void destroy (data_type& data) {
91  allocator_type alloc { };
92  auto value = static_cast<Type*>(data);
93  allocator_traits::destroy(alloc, value);
94  allocator_traits::deallocate(alloc, value, 1);
95  }
96 };
97 
98 template <class Type>
99 any_dispatch const* get_any_dispatch () {
100  static any_dispatch const instance = {
103  [] () -> ::std::type_info const& { return typeid(Type); }
104  };
105  return ::std::addressof(instance);
106 }
107 
108 template <>
109 inline any_dispatch const* get_any_dispatch<void> () {
110  static any_dispatch const instance = {
111  [] (data_type&) { },
112  [] (data_type const&, data_type&) { },
113  [] () -> ::std::type_info const& { return typeid(void); }
114  };
115  return ::std::addressof(instance);
116 }
117 
118 } /* namespace impl */
119 
120 class bad_any_cast final : public ::std::bad_cast {
121 public:
122  virtual char const* what () const noexcept override {
123  return "bad any cast";
124  }
125 };
126 
127 class any final {
128  template <class ValueType>
129  friend ValueType const* any_cast (any const*) noexcept;
130  template <class ValueType> friend ValueType* any_cast (any*) noexcept;
131 
132  impl::any_dispatch const* table;
133  impl::data_type data;
134 
135  template <class ValueType>
136  any (ValueType&& value, ::std::true_type&&) :
137  table { impl::get_any_dispatch<decay_t<ValueType>>() },
138  data { nullptr }
139  {
140  using value_type = decay_t<ValueType>;
141  using allocator_type = ::std::allocator<value_type>;
142  allocator_type alloc { };
143  auto pointer = reinterpret_cast<value_type*>(::std::addressof(this->data));
144  ::std::allocator_traits<allocator_type>::construct(
145  alloc, pointer, ::std::forward<ValueType>(value)
146  );
147  }
148 
149  template <class ValueType>
150  any (ValueType&& value, ::std::false_type&&) :
151  table { impl::get_any_dispatch<decay_t<ValueType>>() },
152  data { nullptr }
153  {
154  using value_type = decay_t<ValueType>;
155  using allocator_type = ::std::allocator<value_type>;
156  allocator_type alloc { };
157  auto pointer = ::std::allocator_traits<allocator_type>::allocate(alloc, 1);
158  ::std::allocator_traits<allocator_type>::construct(
159  alloc, pointer, ::std::forward<ValueType>(value)
160  );
161  this->data = pointer;
162  }
163 
164  template <class ValueType>
165  ValueType const* cast (::std::true_type&&) const {
166  return reinterpret_cast<ValueType const*>(::std::addressof(this->data));
167  }
168 
169  template <class ValueType>
170  ValueType* cast (::std::true_type&&) {
171  return reinterpret_cast<ValueType*>(::std::addressof(this->data));
172  }
173 
174  template <class ValueType>
175  ValueType const* cast (::std::false_type&&) const {
176  return static_cast<ValueType const*>(this->data);
177  }
178 
179  template <class ValueType>
180  ValueType* cast (::std::false_type&&) {
181  return static_cast<ValueType*>(this->data);
182  }
183 
184 public:
185  any (any const& that) :
186  table { that.table },
187  data { nullptr }
188  { this->table->clone(that.data, this->data); }
189 
190  any (any&& that) noexcept :
191  table { that.table },
192  data { that.data }
193  {
194  that.table = impl::get_any_dispatch<void>();
195  that.data = nullptr;
196  }
197 
198  any () noexcept :
199  table { impl::get_any_dispatch<void>() },
200  data { nullptr }
201  { }
202 
203  template <
204  class ValueType,
205  class=enable_if_t<! ::std::is_same<any, decay_t<ValueType>>::value>
206  > any (ValueType&& value) :
207  any { ::std::forward<ValueType>(value), impl::is_small<ValueType> { } }
208  { }
209 
210  ~any () noexcept { this->clear(); }
211 
212  any& operator = (any const& that) {
213  any { that }.swap(*this);
214  return *this;
215  }
216 
217  any& operator = (any&& that) noexcept {
218  any { ::std::move(that) }.swap(*this);
219  return *this;
220  }
221 
222  template <
223  class ValueType,
224  class=enable_if_t<! ::std::is_same<any, decay_t<ValueType>>::value>
225  > any& operator = (ValueType&& value) {
226  any {
227  ::std::forward<ValueType>(value),
228  impl::is_small<ValueType> { }
229  }.swap(*this);
230  return *this;
231  }
232 
233  void swap (any& that) noexcept {
234  using ::std::swap;
235  swap(this->table, that.table);
236  swap(this->data, that.data);
237  }
238 
239  void clear () noexcept {
240  this->table->destroy(this->data);
241  this->table = impl::get_any_dispatch<void>();
242  }
243 
244  ::std::type_info const& type () const noexcept {
245  return this->table->type();
246  }
247 
248  bool empty () const noexcept {
249  return this->table == impl::get_any_dispatch<void>();
250  }
251 
252 };
253 
254 template <class ValueType>
255 ValueType const* any_cast (any const* operand) noexcept {
256  return operand && operand->type() == typeid(ValueType)
257  ? operand->cast<ValueType>(impl::is_small<ValueType> { })
258  : nullptr;
259 }
260 
261 template <class ValueType>
262 ValueType* any_cast (any* operand) noexcept {
263  return operand && operand->type() == typeid(ValueType)
264  ? operand->cast<ValueType>(impl::is_small<ValueType> { })
265  : nullptr;
266 }
267 
268 template <
269  class ValueType,
270  class=enable_if_t<
271  ::std::is_reference<ValueType>::value or
272  ::std::is_copy_constructible<ValueType>::value
273  >
274 > ValueType any_cast (any const& operand) {
275  using type = remove_reference_t<ValueType>;
276  auto pointer = any_cast<add_const_t<type>>(::std::addressof(operand));
277  if (!pointer) { throw bad_any_cast { }; }
278  return *pointer;
279 }
280 
281 template <
282  class ValueType,
283  class=enable_if_t<
284  ::std::is_reference<ValueType>::value or
285  ::std::is_copy_constructible<ValueType>::value
286  >
287 > ValueType any_cast (any&& operand) {
288  using type = remove_reference_t<ValueType>;
289  auto pointer = any_cast<type>(::std::addressof(operand));
290  if (!pointer) { throw bad_any_cast { }; }
291  return *pointer;
292 }
293 
294 template <
295  class ValueType,
296  class=enable_if_t<
297  ::std::is_reference<ValueType>::value or
298  ::std::is_copy_constructible<ValueType>::value
299  >
300 > ValueType any_cast (any& operand) {
301  using type = remove_reference_t<ValueType>;
302  auto pointer = any_cast<type>(::std::addressof(operand));
303  if (!pointer) { throw bad_any_cast { }; }
304  return *pointer;
305 }
306 
307 inline void swap (any& lhs, any& rhs) noexcept { lhs.swap(rhs); }
308 
309 }} /* namespace core::v1 */
310 
311 #endif /* CORE_ANY_HPP */
smlt::v1::bad_any_cast
Definition: any.h:120
smlt::v1::impl::any_dispatch_select
Definition: any.h:52
smlt::v1::any
Definition: any.h:127
smlt
Definition: animation.cpp:25
smlt::v1::impl::any_dispatch
Definition: any.h:41