19 template <std::
size_t SmallObjectOptimisationSize = sizeof(std::
size_t)>
23 using ptr_type =
void*;
24 using aligned_storage_type = std::aligned_storage_t<SmallObjectOptimisationSize>;
27 constexpr
static bool use_internal_storage = (
sizeof(T) <=
sizeof(aligned_storage_type));
44 typename = std::enable_if_t<use_internal_storage<T> &&
49 using value_type = std::decay_t<T>;
52 new (&storage_.buffer) value_type(std::forward<T>(value));
54 copier_ = [](
const storage_type& storage) ->
unsafe_any_t {
55 return *
reinterpret_cast<const value_type*
>(&storage.buffer);
57 destroyer_ = [](storage_type& storage) {
58 auto ptr =
reinterpret_cast<value_type*
>(&storage.buffer);
74 typename = std::enable_if_t<!use_internal_storage<T> &&
79 using value_type = std::decay_t<T>;
82 storage_.ptr = alloc.allocate(1);
83 new (storage_.ptr) value_type(std::forward<T>(value));
85 copier_ = [](
const storage_type& storage) ->
unsafe_any_t {
86 return *
reinterpret_cast<const value_type*
>(storage.ptr);
88 destroyer_ = [alloc = std::move(alloc)](storage_type& storage)
mutable noexcept {
89 auto s_ptr =
reinterpret_cast<value_type*
>(storage.ptr);
91 std::allocator_traits<Allocator>::destroy(alloc, s_ptr);
92 alloc.deallocate(s_ptr, 1);
93 storage.ptr =
nullptr;
110 auto new_any = other.copier_(other.storage_);
111 swap(*
this, new_any);
130 destroyer_(storage_);
139 [[nodiscard]]
bool has_value() const noexcept {
return !!destroyer_; }
147 template <
typename T,
typename DecayType = std::decay_t<T>>
148 [[nodiscard]] std::decay_t<T>&
get() noexcept
150 using value_type = std::decay_t<T>;
152 if constexpr (use_internal_storage<value_type>) {
153 return *
reinterpret_cast<value_type*
>(&storage_.buffer);
155 return *
reinterpret_cast<value_type*
>(storage_.ptr);
166 template <
typename T>
167 [[nodiscard]]
auto get() const noexcept
168 -> std::conditional_t<(sizeof(T) <= sizeof(std::
size_t)) && std::is_copy_constructible_v<T>,
170 const std::decay_t<T>&>
172 using value_type = std::decay_t<T>;
174 if constexpr (use_internal_storage<value_type>) {
175 return *
reinterpret_cast<const value_type*
>(&storage_.buffer);
177 return *
reinterpret_cast<const value_type*
>(storage_.ptr);
190 swap(a.storage_, b.storage_);
191 swap(a.copier_, b.copier_);
192 swap(a.destroyer_, b.destroyer_);
197 constexpr storage_type() noexcept : ptr{
nullptr} {}
200 aligned_storage_type buffer;
203 storage_type storage_;
204 std::function<
unsafe_any_t(
const storage_type&)> copier_;
205 std::function<void(storage_type&)> destroyer_;
unsafe_any_t & operator=(unsafe_any_t other) noexcept
bool has_value() const noexcept
unsafe_any_t(unsafe_any_t &&other) noexcept
unsafe_any_t(T &&value, Allocator alloc=Allocator{})
auto get() const noexcept -> std::conditional_t<(sizeof(T)<=sizeof(std::size_t)) &&std::is_copy_constructible_v< T >, std::decay_t< T >, const std::decay_t< T > & >
unsafe_any_t(const unsafe_any_t &other)
std::decay_t< T > & get() noexcept
unsafe_any_t(T &&value) noexcept
constexpr unsafe_any_t()=default
friend void swap(unsafe_any_t &a, unsafe_any_t &b) noexcept
std::allocator< T > allocator