any.hpp
Go to the documentation of this file.
1 
14 #ifndef CORE_ANY_HPP
15 #define CORE_ANY_HPP
16 
17 #include <memory>
18 
19 #include <cstdlib>
20 #include <cstring>
21 
22 #include "type_traits.hpp"
23 #include "algorithm.hpp"
24 #include "typeinfo.hpp"
25 #include "utility.hpp"
26 
27 #ifndef CORE_NO_EXCEPTIONS
28 #include <stdexcept>
29 #endif /* CORE_NO_EXCEPTIONS */
30 
31 namespace core {
32 inline namespace v2 {
33 namespace impl {
34 
36 
37 template <class T>
38 struct is_small final : meta::all_t<
39  sizeof(decay_t<T>) <= sizeof(data_type),
40  alignof(decay_t<T>) <= alignof(data_type),
41  ::std::is_nothrow_copy_constructible<decay_t<T>>::value
42 > { };
43 template <> struct is_small<void> final : ::std::true_type { };
44 
45 template <class T=void, bool=is_small<T>::value> struct dispatch;
46 template <> struct dispatch<void, true> {
47  dispatch () noexcept = default;
48  virtual ~dispatch () noexcept = default;
49 
50  virtual void clone (data_type const&, data_type&) const { }
51  virtual void move (data_type&, data_type&) const noexcept { }
52  virtual void destroy (data_type&) const noexcept { }
53  virtual type_info const& type () const noexcept { return type_of<void>(); }
54 };
55 
56 template <class T>
57 struct dispatch<T, true> final : dispatch<> {
58  using value_type = T;
59  using const_pointer = add_pointer_t<add_const_t<value_type>>;
60  using pointer = add_pointer_t<value_type>;
61  using allocator_type = ::std::allocator<value_type>;
62  using allocator_traits = ::std::allocator_traits<allocator_type>;
63 
64  virtual void clone (data_type const& src, data_type& dst) const final {
65  allocator_type alloc { };
66  auto val = reinterpret_cast<add_const_t<const_pointer>>(&src);
67  auto ptr = reinterpret_cast<pointer>(&dst);
68  allocator_traits::construct(alloc, ptr, *val);
69  }
70 
71  virtual void move (data_type& src, data_type& dst) const noexcept final {
72  allocator_type alloc { };
73  auto val = reinterpret_cast<pointer>(&src);
74  auto ptr = reinterpret_cast<pointer>(&dst);
75  allocator_traits::construct(alloc, ptr, ::core::move(*val));
76  }
77 
78  virtual void destroy (data_type& src) const noexcept final {
79  allocator_type alloc { };
80  auto ptr = reinterpret_cast<pointer>(&src);
81  allocator_traits::destroy(alloc, ptr);
82  }
83 
84  virtual type_info const& type () const noexcept final {
85  return type_of<value_type>();
86  }
87 };
88 
89 template <class T>
90 struct dispatch<T, false> final : dispatch<> {
91  using value_type = T;
92  using pointer = add_pointer_t<value_type>;
93  using allocator_type = ::std::allocator<value_type>;
94  using allocator_traits = ::std::allocator_traits<allocator_type>;
95 
96  virtual void clone (data_type const& src, data_type& dst) const final {
97  allocator_type alloc { };
98  auto const& value = *static_cast<add_const_t<pointer>>(src);
99  auto ptr = allocator_traits::allocate(alloc, 1);
100  auto scope = make_scope_guard([&alloc, ptr] {
101  allocator_traits::deallocate(alloc, ptr, 1);
102  });
103  allocator_traits::construct(alloc, ptr, value);
104  scope.dismiss();
105  dst = ptr;
106  }
107 
108  virtual void move (data_type& src, data_type& dst) const noexcept final {
109  allocator_type alloc { };
110  auto& value = *static_cast<pointer>(src);
111  auto ptr = allocator_traits::allocate(alloc, 1);
112  auto scope = make_scope_guard([&alloc, ptr] {
113  allocator_traits::deallocate(alloc, ptr, 1);
114  });
115  allocator_traits::construct(alloc, ptr, ::core::move(value));
116  scope.dismiss();
117  dst = ptr;
118  }
119 
120  virtual void destroy (data_type& src) const noexcept final {
121  allocator_type alloc { };
122  auto ptr = static_cast<pointer>(src);
123  allocator_traits::destroy(alloc, ptr);
124  allocator_traits::deallocate(alloc, ptr, 1);
125  }
126 
127  virtual type_info const& type () const noexcept final {
128  return type_of<value_type>();
129  }
130 };
131 
132 template <class T> dispatch<> const* lookup () noexcept {
133  static dispatch<T> instance;
134  return ::std::addressof(instance);
135 }
136 
137 template <> inline dispatch<> const* lookup<void> () noexcept {
138  static dispatch<> instance;
139  return ::std::addressof(instance);
140 }
141 
142 } /* namespace impl */
143 
144 #ifndef CORE_NO_EXCEPTIONS
145 class bad_any_cast final : public ::std::bad_cast {
146 public:
147  virtual char const* what () const noexcept override {
148  return "bad any cast";
149  }
150 };
151 
152 [[noreturn]] inline void throw_bad_any_cast () { throw bad_any_cast { }; }
153 #else /* CORE_NO_EXCEPTIONS */
154 [[noreturn]] inline void throw_bad_any_cast () { ::std::abort(); }
155 #endif /* CORE_NO_EXCEPTIONS */
156 
157 struct any final {
158 
159  template <class T> friend T const* any_cast (any const*) noexcept;
160  template <class T> friend T* any_cast (any*) noexcept;
161 
162  any (any const& that) :
163  table { that.table },
164  data { nullptr }
165  { this->table->clone(that.data, this->data); }
166 
167  any (any&& that) noexcept :
168  table { that.table },
169  data { nullptr }
170  { this->table->move(that.data, this->data); }
171 
172  any () noexcept :
173  table { impl::lookup<void>() },
174  data { nullptr }
175  { }
176 
177  template <
178  class T,
180  > any (T&& value) :
181  any { ::std::forward<T>(value), impl::is_small<T> { } }
182  { }
183 
184  ~any () noexcept { this->clear(); }
185 
186  any& operator = (any const& that) {
187  any { that }.swap(*this);
188  return *this;
189  }
190 
191  any& operator = (any&& that) noexcept {
192  any { ::std::move(that) }.swap(*this);
193  return *this;
194  }
195 
196  template <
197  class T,
199  > any& operator = (T&& value) {
200  any {
201  ::std::forward<T>(value),
202  impl::is_small<T> { }
203  }.swap(*this);
204  return *this;
205  }
206 
207  void swap (any& that) noexcept {
209  swap(this->table, that.table);
210  swap(this->data, that.data);
211  }
212 
213  void clear () noexcept {
214  this->table->destroy(this->data);
215  this->table = impl::lookup<void>();
216  }
217 
218  type_info const& type () const noexcept { return this->table->type(); }
219 
220  bool empty () const noexcept { return this->table == impl::lookup<void>(); }
221 
222 private:
223  impl::dispatch<> const* table;
225 
226  template <class T>
227  any (T&& value, ::std::true_type&&) :
228  table { impl::lookup<decay_t<T>>() },
229  data { nullptr }
230  {
231  using value_type = decay_t<T>;
232  using allocator_type = ::std::allocator<value_type>;
233  using allocator_traits = ::std::allocator_traits<allocator_type>;
234  allocator_type alloc { };
235  auto pointer = reinterpret_cast<value_type*>(::std::addressof(this->data));
236  allocator_traits::construct(alloc, pointer, ::core::forward<T>(value));
237  }
238 
239  template <class T>
240  any (T&& value, ::std::false_type&&) :
241  table { impl::lookup<decay_t<T>>() },
242  data { nullptr }
243  {
244  using value_type = decay_t<T>;
245  using allocator_type = ::std::allocator<value_type>;
246  using allocator_traits = ::std::allocator_traits<allocator_type>;
247  allocator_type alloc { };
248  auto pointer = allocator_traits::allocate(alloc, 1);
249  allocator_traits::construct(alloc, pointer, ::core::forward<T>(value));
250  this->data = pointer;
251  }
252 
253  template <class T>
254  T const* cast (::std::true_type&&) const {
255  return reinterpret_cast<T const*>(::std::addressof(this->data));
256  }
257 
258  template <class T>
259  T* cast (::std::true_type&&) {
260  return reinterpret_cast<T*>(::std::addressof(this->data));
261  }
262 
263  template <class T>
264  T const* cast (::std::false_type&&) const {
265  return static_cast<T const*>(this->data);
266  }
267 
268  template <class T>
269  T* cast (::std::false_type&&) {
270  return static_cast<T*>(this->data);
271  }
272 };
273 
274 template <class T>
275 T const* any_cast (any const* operand) noexcept {
276  return operand and operand->type() == type_of<T>()
277  ? operand->cast<T>(impl::is_small<T> { })
278  : nullptr;
279 }
280 
281 template <class T>
282 T* any_cast (any* operand) noexcept {
283  return operand and operand->type() == type_of<T>()
284  ? operand->cast<T>(impl::is_small<T> { })
285  : nullptr;
286 }
287 
288 template <
289  class T,
290  class=meta::when<
291  meta::any<
292  ::std::is_reference<T>::value,
293  ::std::is_copy_constructible<T>::value
294  >()
295  >
296 > T any_cast (any const& operand) {
297  using type = remove_reference_t<T>;
298  auto pointer = any_cast<add_const_t<type>>(::std::addressof(operand));
299  if (not pointer) { throw_bad_any_cast(); }
300  return *pointer;
301 }
302 
303 template <
304  class T,
305  class=meta::when<
306  meta::any<
307  ::std::is_reference<T>::value,
308  ::std::is_copy_constructible<T>::value
309  >()
310  >
311 > T any_cast (any&& operand) {
312  using type = remove_reference_t<T>;
313  auto pointer = any_cast<type>(::std::addressof(operand));
314  if (not pointer) { throw_bad_any_cast(); }
315  return *pointer;
316 }
317 
318 template <
319  class T,
320  class=meta::when<
321  meta::any<
322  ::std::is_reference<T>::value,
323  ::std::is_copy_constructible<T>::value
324  >()
325  >
326 > T any_cast (any& operand) {
327  using type = remove_reference_t<T>;
328  auto pointer = any_cast<type>(::std::addressof(operand));
329  if (not pointer) { throw_bad_any_cast(); }
330  return *pointer;
331 }
332 
333 inline void swap (any& lhs, any& rhs) noexcept { lhs.swap(rhs); }
334 
335 }} /* namespace core::v2 */
336 
337 #endif /* CORE_ANY_HPP */
constexpr bool any() noexcept
Definition: meta.hpp:282
T const * any_cast(any const *operand) noexcept
Definition: any.hpp:275
Copyright © 2013 - 2015 MNMLSTC.
Definition: algorithm.hpp:23
type_info const & type() const noexcept
Definition: any.hpp:218
typename ::std::remove_reference< T >::type remove_reference_t
any(T &&value)
Definition: any.hpp:180
constexpr auto data(Container const &container) noexcept -> decltype(container.data())
Definition: iterator.hpp:79
bool empty() const noexcept
Definition: any.hpp:220
typename ::std::add_const< T >::type add_const_t
typename ::std::enable_if< B, T >::type when
Definition: meta.hpp:193
void swap(any &lhs, any &rhs) noexcept
Definition: any.hpp:333
any() noexcept
Definition: any.hpp:172
void throw_bad_any_cast()
Definition: any.hpp:152
::std::type_info type_info
Definition: typeinfo.hpp:29
typename ::std::add_pointer< T >::type add_pointer_t
void clear() noexcept
Definition: any.hpp:213
void swap(any &that) noexcept
Definition: any.hpp:207
impl::decay_t< T > decay_t
add_pointer_t< void > data_type
Definition: any.hpp:35
~any() noexcept
Definition: any.hpp:184
typename ::std::enable_if< B, T >::type enable_if_t
auto move(Range &&rng, OutputIt &&it) -> enable_if_t< is_range< Range >::value, decay_t< OutputIt > >
Definition: algorithm.hpp:736