diff options
Diffstat (limited to 'src/DI/value_functor.tpp')
-rw-r--r-- | src/DI/value_functor.tpp | 189 |
1 files changed, 189 insertions, 0 deletions
diff --git a/src/DI/value_functor.tpp b/src/DI/value_functor.tpp new file mode 100644 index 0000000..3665f18 --- /dev/null +++ b/src/DI/value_functor.tpp @@ -0,0 +1,189 @@ +#pragma once + +#include "value_functor.hpp" + +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) +#define VALUE_FUNCTOR_TEMPLATE template <class Return, class... Args> + +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) +#define VALUE_FUNCTOR ValueFunctor<Return(Args...)> + +VALUE_FUNCTOR_TEMPLATE +VALUE_FUNCTOR::ValueFunctor() noexcept : _functor(nullptr) {} + +VALUE_FUNCTOR_TEMPLATE +template <class Function, class Allocator> +VALUE_FUNCTOR::ValueFunctor(Function &&function, const Allocator &allocator) + : _functor(nullptr) +{ + using AllocTraits = std::allocator_traits<Allocator>; + + using Functor = CopyableFunctor<Function, Allocator, Return(Args...)>; + + using FunctorAlloc = typename RebindAllocHelper<AllocTraits, Functor>::type; + + if (not_null(function)) + { + auto functor_alloc = FunctorAlloc(allocator); + + if (sizeof(Functor) <= sizeof(_buf) && + std::is_nothrow_copy_constructible<Function>::value && + std::is_nothrow_copy_constructible<FunctorAlloc>::value) + { + // NOLINTNEXTLINE(cppcoreguidelines-owning-memory) + _functor = ::new (static_cast<void *>(&_buf)) + Functor(std::forward<Function>(function), Allocator(functor_alloc)); + } + else + { + using Destructor = AllocDestructor<FunctorAlloc>; + + auto hold = std::unique_ptr<TargetFunctor, Destructor>( + functor_alloc.allocate(1), Destructor(functor_alloc, 1)); + + ::new (static_cast<void *>(hold.get())) + Functor(std::forward<Function>(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<void *>(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<void *>(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<void *>(_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<void *>(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<void *>(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>(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 <typename Target> +auto VALUE_FUNCTOR::target() const noexcept -> const Target * +{ + if (_functor == nullptr) + { + return nullptr; + } + + return static_cast<const Target *>(_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<TargetFunctor *>(function_ptr); +} |