81 static constexpr size_t SBO_SIZE =
sizeof(
void*) * 2;
90 union storage_internal {
91 storage_internal()
noexcept =
default;
92 storage_internal(
const storage_internal&) =
delete;
93 storage_internal& operator=(
const storage_internal&) =
delete;
103 enum class operation :
uint8_t {
118 reflect::type_id type_id_val_;
121 using manage_func = void (*)(operation,
const meta_any*, arg_t*);
128 template <
typename T>
129 struct internal_manage {
130 NEFORCE_NODISCARD
static reflect::type_id type_id_val() noexcept {
return type_id_for<T>(); }
132 template <
typename... Args>
133 static void create(storage_internal& storage, Args&&... args) {
134 void* addr =
const_cast<void*
>(
static_cast<const void*
>(&storage.buffer_));
135 ::new (addr) T(_NEFORCE forward<Args>(args)...);
138 static T* access(
const storage_internal& storage)
noexcept {
139 const void* addr = &storage.buffer_;
140 return static_cast<T*
>(
const_cast<void*
>(addr));
143 template <
typename U = T, enable_if_t<is_copy_constructible_v<U>,
int> = 0>
144 static void copy_op(
const meta_any* self, arg_t* arg) {
145 auto* ptr = access(self->storage_);
146 create(arg->any_ptr_->storage_, *ptr);
147 arg->any_ptr_->manage_ = &manage;
148 arg->any_ptr_->type_id_ = type_id_val();
151 template <
typename U = T, enable_if_t<!is_copy_constructible_v<U>,
int> = 0>
152 static void copy_op(
const meta_any* , arg_t* ) {}
154 template <
typename U = T, enable_if_t<is_move_constructible_v<U>,
int> = 0>
155 static void move_op(
const meta_any* self, arg_t* arg) {
156 auto* ptr = access(self->storage_);
157 create(arg->any_ptr_->storage_, _NEFORCE
move(*ptr));
159 arg->any_ptr_->manage_ = &manage;
160 arg->any_ptr_->type_id_ = type_id_val();
163 template <
typename U = T, enable_if_t<!is_move_constructible_v<U>,
int> = 0>
164 static void move_op(
const meta_any* , arg_t* ) {}
166 static void manage(
const operation op,
const meta_any* self, arg_t* arg) {
167 auto* ptr = access(self->storage_);
169 case operation::ACCESS: {
170 arg->obj_ptr_ =
static_cast<void*
>(ptr);
173 case operation::GET_TYPE_ID: {
174 arg->type_id_val_ = type_id_val();
177 case operation::COPY: {
181 case operation::DESTROY: {
185 case operation::MOVE: {
198 template <
typename T>
199 struct external_manage {
200 NEFORCE_NODISCARD
static reflect::type_id type_id_val() noexcept {
return type_id_for<T>(); }
202 template <
typename... Args>
203 static void create(storage_internal& storage, Args&&... args) {
204 storage.ptr_ =
new T(_NEFORCE forward<Args>(args)...);
207 static T* access(
const storage_internal& storage)
noexcept {
return static_cast<T*
>(storage.ptr_); }
209 template <
typename U = T, enable_if_t<is_copy_constructible_v<U>,
int> = 0>
210 static void copy_op(
const meta_any* self, arg_t* arg) {
211 auto* ptr = access(self->storage_);
212 create(arg->any_ptr_->storage_, *ptr);
213 arg->any_ptr_->manage_ = &manage;
214 arg->any_ptr_->type_id_ = type_id_val();
217 template <
typename U = T, enable_if_t<!is_copy_constructible_v<U>,
int> = 0>
218 static void copy_op(
const meta_any* , arg_t* ) {}
220 static void manage(
const operation op,
const meta_any* self, arg_t* arg) {
221 auto* ptr = access(self->storage_);
223 case operation::ACCESS: {
224 arg->obj_ptr_ =
static_cast<void*
>(ptr);
227 case operation::GET_TYPE_ID: {
228 arg->type_id_val_ = type_id_val();
231 case operation::COPY: {
235 case operation::DESTROY: {
239 case operation::MOVE: {
240 arg->any_ptr_->storage_.ptr_ = self->storage_.ptr_;
241 arg->any_ptr_->manage_ = &manage;
242 arg->any_ptr_->type_id_ = type_id_val();
252 template <
typename T>
253 struct use_internal_storage :
bool_constant<is_nothrow_move_constructible_v<T> && sizeof(T) <= SBO_SIZE &&
254 alignof(T) <= alignof(storage_internal)> {};
256 template <typename T>
257 using manage_t = conditional_t<use_internal_storage<T>::value, internal_manage<T>, external_manage<T>>;
259 manage_func manage_ = nullptr;
260 storage_internal storage_;
261 reflect::type_id type_id_ = 0;
263 void reset_internal() noexcept {
264 if (manage_ != nullptr) {
265 manage_(operation::DESTROY, this, nullptr);
271 template <typename T, typename... Args, typename Manager = manage_t<decay_t<T>>>
272 void emplace_impl(Args&&... args) {
274 Manager::create(storage_, _NEFORCE forward<Args>(args)...);
275 manage_ = &Manager::manage;
276 type_id_ = Manager::type_id_val();
283 meta_any() noexcept = default;
290 template <typename T, typename DecayT = decay_t<T>, typename = enable_if_t<!is_same_v<DecayT, meta_any>>,
291 typename = enable_if_t<is_copy_constructible_v<DecayT>>>
292 meta_any(T&& value) {
293 emplace_impl<T>(_NEFORCE forward<T>(value));
304 template <typename T, typename... Args>
305 void emplace(Args&&... args) {
306 emplace_impl<T>(_NEFORCE forward<Args>(args)...);
313 meta_any(const meta_any& other) {
314 if (other.manage_ != nullptr) {
317 other.manage_(operation::COPY, &other, &arg);
325 meta_any(meta_any&& other) noexcept {
326 if (other.manage_ != nullptr) {
329 other.manage_(operation::MOVE, &other, &arg);
330 other.manage_ = nullptr;
338 ~meta_any() { reset_internal(); }
345 meta_any& operator=(const meta_any& other) {
346 if (_NEFORCE addressof(other) == this) {
350 if (other.manage_ != nullptr) {
353 other.manage_(operation::COPY, &other, &arg);
363 meta_any& operator=(meta_any&& other) noexcept {
364 if (_NEFORCE addressof(other) == this) {
368 if (other.manage_ != nullptr) {
371 other.manage_(operation::MOVE, &other, &arg);
372 other.manage_ = nullptr;
382 NEFORCE_NODISCARD reflect::type_id type_id() const noexcept { return type_id_; }
388 NEFORCE_NODISCARD bool has_value() const noexcept { return manage_ != nullptr; }
394 explicit operator bool() const noexcept { return has_value(); }
401 template <typename T>
402 NEFORCE_NODISCARD T* cast() noexcept {
403 if (!manage_ || type_id_ != type_id_for<T>()) {
407 manage_(operation::ACCESS, this, &arg);
408 return static_cast<T*>(arg.obj_ptr_);
416 template <typename T>
417 NEFORCE_NODISCARD const T* cast() const noexcept {
418 if (!manage_ || type_id_ != type_id_for<T>()) {
422 manage_(operation::ACCESS, this, &arg);
423 return static_cast<const T*>(arg.obj_ptr_);
432 template <typename T>
433 NEFORCE_NODISCARD T& get() {
434 if (auto* ptr = cast<T>()) {
437 NEFORCE_THROW_EXCEPTION(typecast_exception("Not a valid type"));
447 template <typename T>
448 NEFORCE_NODISCARD const T& get() const {
449 if (auto* ptr = cast<T>()) {
452 NEFORCE_THROW_EXCEPTION(typecast_exception("Not a valid type"));
461 template <typename T>
462 NEFORCE_NODISCARD bool can_cast() const noexcept {
463 return cast<T>() != nullptr;
472 template <typename T>
473 NEFORCE_NODISCARD T convert() const {
474 if (auto* ptr = cast<T>()) {
477 NEFORCE_THROW_EXCEPTION(typecast_exception("Not a valid type"));
485 NEFORCE_NODISCARD void* raw() noexcept {
486 if (manage_ == nullptr) {
490 manage_(operation::ACCESS, this, &arg);
497 NEFORCE_NODISCARD const void* raw() const noexcept {
498 if (manage_ == nullptr) {
502 manage_(operation::ACCESS, this, &arg);
509 void reset() noexcept { reset_internal(); }
515 void swap(meta_any& other) noexcept {
516 if (_NEFORCE addressof(other) == this) {
519 meta_any tmp(_NEFORCE move(*this));
520 *this = _NEFORCE move(other);
521 other = _NEFORCE move(tmp);