#pragma once #include "value_functor.hpp" // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) #define VALUE_FUNCTOR_TEMPLATE template // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) #define VALUE_FUNCTOR ValueFunctor VALUE_FUNCTOR_TEMPLATE VALUE_FUNCTOR::ValueFunctor() noexcept : _functor(nullptr) {} VALUE_FUNCTOR_TEMPLATE template VALUE_FUNCTOR::ValueFunctor(Function &&function, const Allocator &allocator) : _functor(nullptr) { using AllocTraits = std::allocator_traits; using Functor = CopyableFunctor; using FunctorAlloc = typename RebindAllocHelper::type; if (not_null(function)) { auto functor_alloc = FunctorAlloc(allocator); if (sizeof(Functor) <= sizeof(_buf) && std::is_nothrow_copy_constructible::value && std::is_nothrow_copy_constructible::value) { // NOLINTNEXTLINE(cppcoreguidelines-owning-memory) _functor = ::new (static_cast(&_buf)) Functor(std::forward(function), Allocator(functor_alloc)); } else { using Destructor = AllocDestructor; auto hold = std::unique_ptr( functor_alloc.allocate(1), Destructor(functor_alloc, 1) ); ::new (static_cast(hold.get())) Functor(std::forward(function), Allocator(allocator)); _functor = hold.release(); } } } VALUE_FUNCTOR_TEMPLATE VALUE_FUNCTOR::ValueFunctor(const ValueFunctor &val_functor) { if (val_functor._functor == nullptr) { _functor = nullptr; } else if (static_cast(val_functor._functor) == &val_functor._buf) { _functor = _as_copyable_functor(&_buf); val_functor._functor->clone(_functor); } else { _functor = val_functor._functor->clone(); } } VALUE_FUNCTOR_TEMPLATE VALUE_FUNCTOR::ValueFunctor(ValueFunctor &&val_functor) noexcept { if (val_functor._functor == nullptr) { _functor = nullptr; } else if (static_cast(val_functor._functor) == &val_functor._buf) { _functor = _as_copyable_functor(&_buf); val_functor._functor->clone(_functor); } else { _functor = val_functor._functor; val_functor._functor = nullptr; } } VALUE_FUNCTOR_TEMPLATE VALUE_FUNCTOR::~ValueFunctor() { if (static_cast(_functor) == &_buf) { _functor->destroy(); } else if (_functor) { _functor->destroy_deallocate(); } } VALUE_FUNCTOR_TEMPLATE auto VALUE_FUNCTOR::operator=(ValueFunctor &&val_functor) noexcept -> ValueFunctor & { *this = nullptr; if (val_functor._functor == nullptr) { _functor = nullptr; } else if (static_cast(val_functor._functor) == &val_functor._buf) { _functor = _as_copyable_functor(&_buf); val_functor._functor->clone(_functor); } else { _functor = val_functor._functor; val_functor._functor = nullptr; } return *this; } VALUE_FUNCTOR_TEMPLATE auto VALUE_FUNCTOR::operator=(std::nullptr_t) -> ValueFunctor & { TargetFunctor *old_functor = _functor; _functor = nullptr; if (static_cast(old_functor) == &_buf) { old_functor->destroy(); } else if (old_functor) { old_functor->destroy_deallocate(); } return *this; } VALUE_FUNCTOR_TEMPLATE auto VALUE_FUNCTOR::operator()(Args &&...args) const -> Return { if (_functor == nullptr) { std::abort(); } return (*_functor)(std::forward(args)...); } VALUE_FUNCTOR_TEMPLATE VALUE_FUNCTOR::operator bool() const noexcept { return _functor != nullptr; } VALUE_FUNCTOR_TEMPLATE auto VALUE_FUNCTOR::target_type() const noexcept -> const std::type_info & { if (_functor == nullptr) { return typeid(void); } return _functor->target_type(); } VALUE_FUNCTOR_TEMPLATE template auto VALUE_FUNCTOR::target() const noexcept -> const Target * { if (_functor == nullptr) { return nullptr; } return static_cast(_functor->target(typeid(Target))); } VALUE_FUNCTOR_TEMPLATE auto VALUE_FUNCTOR::_as_copyable_functor(void *function_ptr) -> TargetFunctor * { // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) return reinterpret_cast(function_ptr); }