From b36d072ad7a7b9c6e30fcb25d6bbb001a8393468 Mon Sep 17 00:00:00 2001 From: HampusM Date: Sun, 10 Apr 2022 17:20:49 +0200 Subject: refactor: add factory class & make DI container return unique ptrs --- src/DI/alloc_functor.hpp | 84 +++++++++++++++ src/DI/alloc_functor.tpp | 165 ++++++++++++++++++++++++++++ src/DI/allocation.hpp | 32 ++++++ src/DI/allocation.tpp | 16 +++ src/DI/auto_wirable.hpp | 12 +-- src/DI/auto_wirable.tpp | 4 +- src/DI/compressed_pair.hpp | 188 ++++++++++++++++++++++++++++++++ src/DI/concepts.hpp | 4 +- src/DI/container.cpp | 2 +- src/DI/container.hpp | 23 ++-- src/DI/container.tpp | 26 ++--- src/DI/copyable_functor.hpp | 47 ++++++++ src/DI/copyable_functor.tpp | 105 ++++++++++++++++++ src/DI/extra_concepts.hpp | 6 ++ src/DI/factory.hpp | 189 +++++++++++++++++++++++++++++++++ src/DI/factory.tpp | 65 ++++++++++++ src/DI/function_wrapper.tpp | 4 +- src/DI/interfaces/copyable_functor.hpp | 41 +++++++ src/DI/object_wrapper.hpp | 4 +- src/DI/object_wrapper.tpp | 3 +- src/DI/strip_signature.hpp | 103 ++++++++++++++++++ src/DI/type_traits.hpp | 12 ++- src/DI/value_functor.hpp | 65 ++++++++++++ src/DI/value_functor.tpp | 189 +++++++++++++++++++++++++++++++++ 24 files changed, 1345 insertions(+), 44 deletions(-) create mode 100644 src/DI/alloc_functor.hpp create mode 100644 src/DI/alloc_functor.tpp create mode 100644 src/DI/allocation.hpp create mode 100644 src/DI/allocation.tpp create mode 100644 src/DI/compressed_pair.hpp create mode 100644 src/DI/copyable_functor.hpp create mode 100644 src/DI/copyable_functor.tpp create mode 100644 src/DI/extra_concepts.hpp create mode 100644 src/DI/factory.hpp create mode 100644 src/DI/factory.tpp create mode 100644 src/DI/interfaces/copyable_functor.hpp create mode 100644 src/DI/strip_signature.hpp create mode 100644 src/DI/value_functor.hpp create mode 100644 src/DI/value_functor.tpp (limited to 'src/DI') diff --git a/src/DI/alloc_functor.hpp b/src/DI/alloc_functor.hpp new file mode 100644 index 0000000..ea40b22 --- /dev/null +++ b/src/DI/alloc_functor.hpp @@ -0,0 +1,84 @@ +#pragma once + +#include "DI/allocation.hpp" +#include "DI/compressed_pair.hpp" + +#include +#include +#include + +template +struct InvokeReturnWrapper +{ + template + static auto call(Args &&...args) -> Return; +}; + +/** + * Holds a functor and a allocator. + */ +template +class AllocFunctor; + +template +class AllocFunctor +{ +public: + using Target = Function; + using Alloc = Allocator; + + explicit AllocFunctor(Target &&function); + + explicit AllocFunctor(const Target &function, const Alloc &allocator); + + explicit AllocFunctor(const Target &function, Alloc &&allocator); + + explicit AllocFunctor(Target &&function, Alloc &&allocator); + + auto operator()(Args &&...args) -> Return; + + [[nodiscard]] auto target() const -> const Target &; + + [[nodiscard]] auto get_allocator() const -> const Alloc &; + + [[nodiscard]] auto clone() const -> AllocFunctor *; + + void destroy() noexcept; + + static void destroy_and_delete(AllocFunctor *functor); + +private: + CompressedPair _function; +}; + +/** + * Holds a functor and a allocator. + */ +template +class DefaultAllocFunctor; + +template +class DefaultAllocFunctor +{ +public: + using Target = Function; + + explicit DefaultAllocFunctor(Target &&function); + + explicit DefaultAllocFunctor(const Target &function); + + auto operator()(Args &&...args) -> Return; + + auto target() const -> const Target &; + + auto clone() const -> DefaultAllocFunctor *; + + void destroy() noexcept; + + static void destroy_and_delete(DefaultAllocFunctor *function); + +private: + Function _function; +}; + +#include "alloc_functor.tpp" diff --git a/src/DI/alloc_functor.tpp b/src/DI/alloc_functor.tpp new file mode 100644 index 0000000..d3f6946 --- /dev/null +++ b/src/DI/alloc_functor.tpp @@ -0,0 +1,165 @@ +#pragma once + +#include "alloc_functor.hpp" + +template +template +auto InvokeReturnWrapper::call(Args &&...args) -> Return +{ + return std::invoke(std::forward(args)...); +} + +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) +#define ALLOC_FUNCTOR_TEMPLATE \ + template + +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) +#define ALLOC_FUNCTOR AllocFunctor + +ALLOC_FUNCTOR_TEMPLATE +ALLOC_FUNCTOR::AllocFunctor(Target &&function) + : _function(std::piecewise_construct, std::forward_as_tuple(std::move(function)), + std::forward_as_tuple()) +{ +} + +ALLOC_FUNCTOR_TEMPLATE +ALLOC_FUNCTOR::AllocFunctor(const Target &function, const Alloc &allocator) + : _function(std::piecewise_construct, std::forward_as_tuple(function), + std::forward_as_tuple(allocator)) +{ +} + +ALLOC_FUNCTOR_TEMPLATE +ALLOC_FUNCTOR::AllocFunctor(const Target &function, Alloc &&allocator) + : _function(std::piecewise_construct, std::forward_as_tuple(function), + std::forward_as_tuple(std::move(allocator))) +{ +} + +ALLOC_FUNCTOR_TEMPLATE +ALLOC_FUNCTOR::AllocFunctor(Target &&function, Alloc &&allocator) + : _function(std::piecewise_construct, std::forward_as_tuple(std::move(function)), + std::forward_as_tuple(std::move(allocator))) +{ +} + +ALLOC_FUNCTOR_TEMPLATE +auto ALLOC_FUNCTOR::operator()(Args &&...args) -> Return +{ + using Invoker = InvokeReturnWrapper; + + return Invoker::call(_function.first(), std::forward(args)...); +} + +ALLOC_FUNCTOR_TEMPLATE +auto ALLOC_FUNCTOR::target() const -> const Target & +{ + return _function.first(); +} + +ALLOC_FUNCTOR_TEMPLATE +auto ALLOC_FUNCTOR::get_allocator() const -> const Alloc & +{ + return _function.second(); +} + +ALLOC_FUNCTOR_TEMPLATE +auto ALLOC_FUNCTOR::clone() const -> AllocFunctor * +{ + using AllocTraits = std::allocator_traits; + + using AllocHelper = typename RebindAllocHelper::type; + + auto alloc_helper = AllocHelper(_function.second()); + + using Destructor = AllocDestructor; + + auto hold = std::unique_ptr(alloc_helper.allocate(1), + _Dp(alloc_helper, 1)); + + ::new (static_cast(hold.get())) + AllocFunctor(_function.first(), _Alloc(alloc_helper)); + + return hold.release(); +} + +ALLOC_FUNCTOR_TEMPLATE +void ALLOC_FUNCTOR::destroy() noexcept +{ + _function.~CompressedPair(); +} + +ALLOC_FUNCTOR_TEMPLATE +void ALLOC_FUNCTOR::destroy_and_delete(AllocFunctor *functor) +{ + using AllocTraits = std::allocator_traits; + + using FunctorAlloc = typename RebindAllocHelper::type; + + auto functor_alloc = FunctorAlloc(functor->get_allocator()); + + functor->destroy(); + functor_alloc.deallocate(functor, 1); +} + +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) +#define DEFAULT_ALLOC_FUNCTOR_TEMPLATE \ + template + +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) +#define DEFAULT_ALLOC_FUNCTOR DefaultAllocFunctor + +DEFAULT_ALLOC_FUNCTOR_TEMPLATE +DEFAULT_ALLOC_FUNCTOR::DefaultAllocFunctor(Target &&function) + : _function(std::move(function)) +{ +} + +DEFAULT_ALLOC_FUNCTOR_TEMPLATE +DEFAULT_ALLOC_FUNCTOR::DefaultAllocFunctor(const Target &function) : _function(function) +{ +} + +DEFAULT_ALLOC_FUNCTOR_TEMPLATE +auto DEFAULT_ALLOC_FUNCTOR::operator()(Args &&...args) -> Return +{ + using Invoker = InvokeReturnWrapper; + + return Invoker::call(_function, std::forward(args)...); +} + +DEFAULT_ALLOC_FUNCTOR_TEMPLATE +auto DEFAULT_ALLOC_FUNCTOR::target() const -> const Target & +{ + return _function; +} + +DEFAULT_ALLOC_FUNCTOR_TEMPLATE +auto DEFAULT_ALLOC_FUNCTOR::clone() const -> DefaultAllocFunctor * +{ + std::allocator allocator; + + DefaultAllocFunctor *functor_ptr = allocator.allocate(1); + + // NOLINTNEXTLINE(cppcoreguidelines-owning-memory) + auto *res = ::new (static_cast(functor_ptr)) DefaultAllocFunctor(_function); + + return res; +} + +DEFAULT_ALLOC_FUNCTOR_TEMPLATE +void DEFAULT_ALLOC_FUNCTOR::destroy() noexcept +{ + _function.~_Target(); +} + +DEFAULT_ALLOC_FUNCTOR_TEMPLATE +void DEFAULT_ALLOC_FUNCTOR::destroy_and_delete(DefaultAllocFunctor *function) +{ + function->destroy(); + + std::allocator allocator; + + allocator.deallocate(function, 1); +} diff --git a/src/DI/allocation.hpp b/src/DI/allocation.hpp new file mode 100644 index 0000000..ac0fa38 --- /dev/null +++ b/src/DI/allocation.hpp @@ -0,0 +1,32 @@ +#pragma once + +#include + +template +struct RebindAllocHelper +{ + using type = typename Traits::template rebind_alloc; +}; + +template +class AllocDestructor +{ + using _alloc_traits = std::allocator_traits; + +public: + using Pointer = typename _alloc_traits::pointer; + using Size = typename _alloc_traits::size_type; + + using pointer = Pointer; + using size = Size; + + AllocDestructor(Allocator &allocator, Size alloc_size) noexcept; + + void operator()(Pointer ptr) noexcept; + +private: + Allocator &_allocator; + Size _size; +}; + +#include "allocation.tpp" diff --git a/src/DI/allocation.tpp b/src/DI/allocation.tpp new file mode 100644 index 0000000..245ce99 --- /dev/null +++ b/src/DI/allocation.tpp @@ -0,0 +1,16 @@ +#pragma once + +#include "allocation.hpp" + +template +AllocDestructor::AllocDestructor(Allocator &allocator, + Size alloc_size) noexcept + : _allocator(allocator), _size(alloc_size) +{ +} + +template +void AllocDestructor::operator()(Pointer ptr) noexcept +{ + _alloc_traits::deallocate(_allocator, ptr, _size); +} diff --git a/src/DI/auto_wirable.hpp b/src/DI/auto_wirable.hpp index 54a291e..7c94074 100644 --- a/src/DI/auto_wirable.hpp +++ b/src/DI/auto_wirable.hpp @@ -4,18 +4,12 @@ #include -template -class IAutoWirable -{ -public: - static auto resolve() noexcept -> Interface; -}; - template -class AutoWirable : public IAutoWirable +class AutoWirable { public: - static auto resolve(const Container &container) noexcept -> std::shared_ptr; + static auto resolve(const Container &container) noexcept + -> std::unique_ptr; }; #include "auto_wirable.tpp" diff --git a/src/DI/auto_wirable.tpp b/src/DI/auto_wirable.tpp index 3b42cc4..0a9ca93 100644 --- a/src/DI/auto_wirable.tpp +++ b/src/DI/auto_wirable.tpp @@ -4,7 +4,7 @@ template auto AutoWirable::resolve( - const Container &container) noexcept -> std::shared_ptr + const Container &container) noexcept -> std::unique_ptr { - return std::make_shared(container.get()...); + return std::make_unique(container.get()...); } diff --git a/src/DI/compressed_pair.hpp b/src/DI/compressed_pair.hpp new file mode 100644 index 0000000..6e05e29 --- /dev/null +++ b/src/DI/compressed_pair.hpp @@ -0,0 +1,188 @@ +#pragma once + +#include "DI/extra_concepts.hpp" + +#include +#include +#include +#include + +// Tag used to default initialize one or both of the pair's elements. +struct DefaultInitTag +{ +}; + +struct ValueInitTag +{ +}; + +template +struct TupleIndices +{ +}; + +template +struct IntegerSequence +{ + template