diff options
Diffstat (limited to 'src/DI/factory.hpp')
-rw-r--r-- | src/DI/factory.hpp | 189 |
1 files changed, 189 insertions, 0 deletions
diff --git a/src/DI/factory.hpp b/src/DI/factory.hpp new file mode 100644 index 0000000..13d0eb5 --- /dev/null +++ b/src/DI/factory.hpp @@ -0,0 +1,189 @@ +#pragma once + +#include "DI/interfaces/copyable_functor.hpp" + +#include "DI/alloc_functor.hpp" +#include "DI/allocation.hpp" +#include "DI/copyable_functor.hpp" +#include "DI/extra_concepts.hpp" +#include "DI/strip_signature.hpp" +#include "DI/value_functor.hpp" + +#include <type_traits> +#include <utility> + +template <class> +class Factory; + +template <class Return> +// NOLINTNEXTLINE(readability-identifier-naming) +struct maybe_derive_from_unary_function +{ +}; + +template <class Return, class Arg> +struct maybe_derive_from_unary_function<Return(Arg)> + : public std::unary_function<Arg, Return> +{ +}; + +template <class Return> +// NOLINTNEXTLINE(readability-identifier-naming) +struct maybe_derive_from_binary_function +{ +}; + +template <class Return, class ArgOne, class ArgTwo> +struct maybe_derive_from_binary_function<Return(ArgOne, ArgTwo)> + : public std::binary_function<ArgOne, ArgTwo, Return> +{ +}; + +template <class Function> +auto not_null(Function const & /*unused*/) -> bool +{ + return true; +} + +template <class Function> +auto not_null(Function *function_ptr) -> bool +{ + return function_ptr; +} + +template <class Return, class Class> +auto not_null(Return Class::*method_ptr) -> bool +{ + return method_ptr; +} + +template <class Function> +auto not_null(Factory<Function> const &factory) -> bool +{ + return !!factory; +} + +template <class Type> +// NOLINTNEXTLINE(readability-identifier-naming) +struct uncvref +{ + using type = + typename std::remove_cv<typename std::remove_reference<Type>::type>::type; +}; + +template <class Type> +// NOLINTNEXTLINE(readability-identifier-naming) +using uncvref_t = typename uncvref<Type>::type; + +template <class Tp, class Up, class = void> +// NOLINTNEXTLINE(readability-identifier-naming) +struct is_core_convertible : public std::false_type +{ +}; + +template <class Tp, class Up> +struct is_core_convertible< + Tp, Up, decltype(static_cast<void (*)(Up)>(0)(static_cast<Tp (*)()>(0)()))> + : public std::true_type +{ +}; + +template <class Tp, class Up> +constexpr bool is_core_convertible_v = is_core_convertible<Tp, Up>::value; + +template <typename Function, typename Return, typename... Args> +concept Callable = !std::is_same_v<uncvref_t<Function>, Factory<Return(Args...)>> && + std::is_invocable_v<Function, Args...> && + is_core_convertible_v<std::invoke_result_t<Function, Args...>, Return>; + +template <class Return, class... Args> +class Factory<Return(Args...)> : public maybe_derive_from_unary_function<Return(Args...)>, + public maybe_derive_from_binary_function<Return(Args...)> +{ +public: + using Result = Return; + + Factory() noexcept = default; + + explicit Factory(std::nullptr_t) noexcept {} + + Factory(const Factory &factory); + + Factory(Factory &&factory) noexcept; + + template <class Function> + requires Callable<Function, Return, Args...> + // NOLINTNEXTLINE(google-explicit-constructor) + Factory(Function function) : _functor(std::move(function)) + { + } + + auto operator=(const Factory &factory) = delete; + + auto operator=(Factory &&factory) noexcept -> Factory &; + + auto operator=(std::nullptr_t) noexcept -> Factory &; + + ~Factory(); + + explicit operator bool() const noexcept; + + // deleted overloads close possible hole in the type system + template <class RhsReturn, class... RhsArgs> + auto operator==(const Factory<RhsReturn(RhsArgs...)> &) const -> bool = delete; + + template <class RhsReturn, class... RhsArgs> + auto operator!=(const Factory<RhsReturn(RhsArgs...)> &) const -> bool = delete; + + auto operator()(Args... args) const -> Return; + + [[nodiscard]] auto target_type() const noexcept -> const std::type_info &; + + template <typename Tp> + auto target() noexcept -> Tp *; + + template <typename Tp> + auto target() const noexcept -> const Tp *; + +private: + using ValFunctor = ValueFunctor<Return(Args...)>; + + ValFunctor _functor; +}; + +template <class Return, class... Args> +Factory(Return (*)(Args...)) -> Factory<Return(Args...)>; + +template <class Function, + class Stripped = strip_signature_t<decltype(&Function::operator())>> +Factory(Function) -> Factory<Stripped>; + +template <class Return, class... Args> +inline auto operator==(const Factory<Return(Args...)> &factory, std::nullptr_t) noexcept + -> bool +{ + return !factory; +} + +template <class Return, class... Args> +inline auto operator==(std::nullptr_t, const Factory<Return(Args...)> &factory) noexcept + -> bool +{ + return !factory; +} + +template <class Return, class... Args> +inline auto operator!=(const Factory<Return(Args...)> &factory, std::nullptr_t) noexcept + -> bool +{ + return static_cast<bool>(factory); +} + +template <class Return, class... Args> +inline auto operator!=(std::nullptr_t, const Factory<Return(Args...)> &factory) noexcept + -> bool +{ + return static_cast<bool>(factory); +} + +#include "factory.tpp" |