27 #if __cplusplus >= 202002L
35 #include "type_traits.h"
42 using data_type = add_pointer_t<void>;
45 using is_small = ::std::integral_constant<
47 sizeof(decay_t<Type>) <=
sizeof(
void*)
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& (*)();
55 destroy_function
const destroy;
56 clone_function
const clone;
57 type_function
const type;
60 template <class Type, bool=is_small<Type>::value>
65 using allocator_type = ::std::allocator<Type>;
66 using allocator_traits = ::std::allocator_traits<allocator_type>;
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);
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));
84 using allocator_type = ::std::allocator<Type>;
85 using allocator_traits = ::std::allocator_traits<allocator_type>;
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);
94 allocator_traits::construct(alloc, pointer, value);
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);
107 template <
class Type>
112 [] () -> ::std::type_info
const& {
return typeid(Type); }
114 return ::std::addressof(instance);
118 inline any_dispatch
const* get_any_dispatch<void> () {
119 static any_dispatch
const instance = {
121 [] (data_type
const&, data_type&) { },
122 [] () -> ::std::type_info
const& {
return typeid(void); }
124 return ::std::addressof(instance);
131 virtual char const* what ()
const noexcept
override {
132 return "bad any cast";
137 template <
class ValueType>
138 friend ValueType
const* any_cast (
any const*) noexcept;
139 template <
class ValueType>
friend ValueType* any_cast (
any*) noexcept;
141 _any_impl::any_dispatch
const* table;
142 _any_impl::data_type data;
144 template <
class ValueType>
145 any (ValueType&& value, ::std::true_type&&) :
146 table { _any_impl::get_any_dispatch<decay_t<ValueType>>() },
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)
158 template <
class ValueType>
159 any (ValueType&& value, ::std::false_type&&) :
160 table { _any_impl::get_any_dispatch<decay_t<ValueType>>() },
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)
170 this->data = pointer;
173 template <
class ValueType>
174 ValueType
const* cast (::std::true_type&&)
const {
175 return reinterpret_cast<ValueType const*
>(::std::addressof(this->data));
178 template <
class ValueType>
179 ValueType* cast (::std::true_type&&) {
180 return reinterpret_cast<ValueType*
>(::std::addressof(this->data));
183 template <
class ValueType>
184 ValueType
const* cast (::std::false_type&&)
const {
185 return static_cast<ValueType const*
>(this->data);
188 template <
class ValueType>
189 ValueType* cast (::std::false_type&&) {
190 return static_cast<ValueType*
>(this->data);
195 table { that.table },
197 { this->table->clone(that.data, this->data); }
199 any (
any&& that) noexcept :
200 table { that.table },
203 that.table = _any_impl::get_any_dispatch<void>();
208 table { _any_impl::get_any_dispatch<void>() },
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> { } }
219 ~
any () noexcept { this->clear(); }
221 any& operator = (
any const& that) {
222 any { that }.swap(*
this);
226 any& operator = (
any&& that) noexcept {
227 any { ::std::move(that) }.swap(*
this);
233 class=enable_if_t<! ::std::is_same<any, decay_t<ValueType>>::value>
234 >
any& operator = (ValueType&& value) {
236 ::std::forward<ValueType>(value),
237 _any_impl::is_small<ValueType> { }
242 void swap (
any& that) noexcept {
244 swap(this->table, that.table);
245 swap(this->data, that.data);
248 void clear () noexcept {
249 this->table->destroy(this->data);
250 this->table = _any_impl::get_any_dispatch<void>();
253 ::std::type_info
const& type ()
const noexcept {
254 return this->table->type();
257 bool empty ()
const noexcept {
258 return this->table == _any_impl::get_any_dispatch<void>();
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> { })
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> { })
280 ::std::is_reference<ValueType>::value or
281 ::std::is_copy_constructible<ValueType>::value
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 { }; }
293 ::std::is_reference<ValueType>::value or
294 ::std::is_copy_constructible<ValueType>::value
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 { }; }
306 ::std::is_reference<ValueType>::value or
307 ::std::is_copy_constructible<ValueType>::value
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 { }; }
316 inline void swap (any& lhs, any& rhs) noexcept { lhs.swap(rhs); }