aboutsummaryrefslogtreecommitdiff
path: root/src/DI/value_functor.tpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/DI/value_functor.tpp')
-rw-r--r--src/DI/value_functor.tpp189
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);
+}