diff options
author | HampusM <hampus@hampusmat.com> | 2022-02-27 12:54:10 +0100 |
---|---|---|
committer | HampusM <hampus@hampusmat.com> | 2022-06-13 17:56:53 +0200 |
commit | 5864e5abc43b201c3801fa39a2fcaf9e3a9e8914 (patch) | |
tree | 98e5e324066ef4d1cbd3cc4c792a258fbd86c12d /src/DI | |
parent | e233dc28491c33e8a7dc0a11576d3b8ce91cce2c (diff) |
refactor: use dependency injection
Diffstat (limited to 'src/DI')
-rw-r--r-- | src/DI/auto_wirable.hpp | 28 | ||||
-rw-r--r-- | src/DI/auto_wirable.tpp | 10 | ||||
-rw-r--r-- | src/DI/container.hpp | 65 | ||||
-rw-r--r-- | src/DI/container.tpp | 53 | ||||
-rw-r--r-- | src/DI/function_wrapper.hpp | 20 | ||||
-rw-r--r-- | src/DI/function_wrapper.tpp | 9 | ||||
-rw-r--r-- | src/DI/interfaces/wrapper.hpp | 17 | ||||
-rw-r--r-- | src/DI/object_type.cpp | 18 | ||||
-rw-r--r-- | src/DI/object_type.hpp | 35 | ||||
-rw-r--r-- | src/DI/object_wrapper.hpp | 20 | ||||
-rw-r--r-- | src/DI/object_wrapper.tpp | 9 |
11 files changed, 284 insertions, 0 deletions
diff --git a/src/DI/auto_wirable.hpp b/src/DI/auto_wirable.hpp new file mode 100644 index 0000000..13d252e --- /dev/null +++ b/src/DI/auto_wirable.hpp @@ -0,0 +1,28 @@ +#pragma once + +#include "DI/container.hpp" + +#include <memory> + +// NOLINTNEXTLINE(cppcoreguidelines-special-member-functions) +class IGenericAutoWirable +{ +public: + virtual ~IGenericAutoWirable() = default; +}; + +template <class Interface> +class IAutoWirable : public IGenericAutoWirable +{ +public: + static Interface resolve(); +}; + +template <class Interface, class ObjectImpl, class... Dependencies> +class AutoWirable : public IAutoWirable<Interface> +{ +public: + static std::shared_ptr<Interface> resolve(const Container &container); +}; + +#include "auto_wirable.tpp" diff --git a/src/DI/auto_wirable.tpp b/src/DI/auto_wirable.tpp new file mode 100644 index 0000000..6c0d111 --- /dev/null +++ b/src/DI/auto_wirable.tpp @@ -0,0 +1,10 @@ +#pragma once + +#include "auto_wirable.hpp" + +template <class Interface, class ObjectImpl, class... Dependencies> +std::shared_ptr<Interface> +AutoWirable<Interface, ObjectImpl, Dependencies...>::resolve(const Container &container) +{ + return std::make_shared<ObjectImpl>(container.get<Dependencies>()...); +} diff --git a/src/DI/container.hpp b/src/DI/container.hpp new file mode 100644 index 0000000..2402894 --- /dev/null +++ b/src/DI/container.hpp @@ -0,0 +1,65 @@ +#pragma once + +#include "DI/object_type.hpp" +#include "interfaces/wrapper.hpp" + +#include <functional> +#include <memory> +#include <type_traits> +#include <unordered_map> + +class Container; + +template <typename Interface> +class BindingBuilder +{ +public: + explicit BindingBuilder(Container *container); + + template <class ObjectImpl, + class = std::enable_if_t<std::is_base_of_v<Interface, ObjectImpl>>> + void to(); + + void to_factory(Interface func); + +private: + Container *_container; +}; + +template <typename Satan> +struct is_func : public std::false_type // NOLINT(readability-identifier-naming) +{ +}; + +template <typename Satan, typename... Args> +struct is_func<std::function<Satan(Args...)>> : public std::true_type +{ +}; + +class Container +{ +public: + Container() = default; + + template <class Interface> + BindingBuilder<Interface> bind(); + + template <class Interface, class = std::enable_if_t<std::is_abstract_v<Interface>>> + std::shared_ptr<Interface> get() const; + + /* + template <typename Interface, + typename = std::enable_if_t< + !std::is_abstract_v<Interface> && + std::is_invocable_v<Interface, typename Interface::argument_type>>> + Interface get() const; + */ + + template <typename Interface, typename = std::enable_if_t<is_func<Interface>::value>> + Interface get() const; + + std::unordered_map<BaseObjectType, std::shared_ptr<IGenericWrapper>, ObjectTypeHasher> + bindings; +}; + +#include "container.tpp" diff --git a/src/DI/container.tpp b/src/DI/container.tpp new file mode 100644 index 0000000..21bf81a --- /dev/null +++ b/src/DI/container.tpp @@ -0,0 +1,53 @@ +#pragma once + +#include "container.hpp" + +#include "function_wrapper.hpp" +#include "object_wrapper.hpp" + +template <class Interface> +BindingBuilder<Interface>::BindingBuilder(Container *container) : _container(container) +{ +} + +template <class Interface> +template <class ObjectImpl, class> +void BindingBuilder<Interface>::to() +{ + _container->bindings.emplace( + ObjectType<Interface>(), + std::dynamic_pointer_cast<IGenericWrapper>( + std::make_shared<ObjectWrapper<Interface, ObjectImpl>>(*_container))); +} + +template <class Interface> +void BindingBuilder<Interface>::to_factory(Interface func) +{ + _container->bindings.emplace(ObjectType<Interface>(), + std::dynamic_pointer_cast<IGenericWrapper>( + std::make_shared<FunctionWrapper<Interface>>(func))); +} + +template <class Interface> +BindingBuilder<Interface> Container::bind() +{ + return BindingBuilder<Interface>(this); +} + +template <class Interface, class> +std::shared_ptr<Interface> Container::get() const +{ + auto wrapper = std::dynamic_pointer_cast<IWrapper<std::shared_ptr<Interface>>>( + bindings.at(ObjectType<Interface>())); + + return wrapper->get(); +} + +template <typename Interface, typename> +Interface Container::get() const +{ + auto wrapper = std::dynamic_pointer_cast<IWrapper<Interface>>( + bindings.at(ObjectType<Interface>())); + + return wrapper->get(); +} diff --git a/src/DI/function_wrapper.hpp b/src/DI/function_wrapper.hpp new file mode 100644 index 0000000..e4b6779 --- /dev/null +++ b/src/DI/function_wrapper.hpp @@ -0,0 +1,20 @@ +#pragma once + +#include "DI/container.hpp" +#include "DI/interfaces/wrapper.hpp" + +#include <memory> + +template <class Interface> +class FunctionWrapper : public IWrapper<Interface> +{ +public: + explicit FunctionWrapper(Interface func) : _func(func) {} + + [[nodiscard]] Interface get() const; + +private: + const Interface _func; +}; + +#include "function_wrapper.tpp" diff --git a/src/DI/function_wrapper.tpp b/src/DI/function_wrapper.tpp new file mode 100644 index 0000000..4e09957 --- /dev/null +++ b/src/DI/function_wrapper.tpp @@ -0,0 +1,9 @@ +#pragma once + +#include "function_wrapper.hpp" + +template <class Interface> +Interface FunctionWrapper<Interface>::get() const +{ + return _func; +} diff --git a/src/DI/interfaces/wrapper.hpp b/src/DI/interfaces/wrapper.hpp new file mode 100644 index 0000000..3cc75a0 --- /dev/null +++ b/src/DI/interfaces/wrapper.hpp @@ -0,0 +1,17 @@ +#pragma once + +#include <memory> + +// NOLINTNEXTLINE(cppcoreguidelines-special-member-functions) +class IGenericWrapper +{ +public: + virtual ~IGenericWrapper() = default; +}; + +template <class Interface> +class IWrapper : public IGenericWrapper +{ +public: + [[nodiscard]] virtual Interface get() const = 0; +}; diff --git a/src/DI/object_type.cpp b/src/DI/object_type.cpp new file mode 100644 index 0000000..60c7c78 --- /dev/null +++ b/src/DI/object_type.cpp @@ -0,0 +1,18 @@ +#include "object_type.hpp" + +BaseObjectType::BaseObjectType(const std::type_info &type_info) : _type_info(type_info) {} + +bool BaseObjectType::operator==(const BaseObjectType &object_type) const +{ + return hash() == object_type.hash(); +} + +std::size_t BaseObjectType::hash() const +{ + return _type_info.hash_code(); +} + +std::size_t ObjectTypeHasher::operator()(const BaseObjectType &object_type) const +{ + return object_type.hash(); +} diff --git a/src/DI/object_type.hpp b/src/DI/object_type.hpp new file mode 100644 index 0000000..f690a64 --- /dev/null +++ b/src/DI/object_type.hpp @@ -0,0 +1,35 @@ +#pragma once + +#include <typeinfo> + +class BaseObjectType +{ +public: + explicit BaseObjectType(const std::type_info &type_info); + + bool operator==(const BaseObjectType &object_type) const; + + [[nodiscard]] std::size_t hash() const; + +private: + const std::type_info &_type_info; +}; + +template <class Object> +class ObjectType : public BaseObjectType +{ +public: + ObjectType() : BaseObjectType(typeid(Object)) {} +}; + +class IObjectTypeHasher +{ +public: + virtual std::size_t operator()(const BaseObjectType &object_type) const = 0; +}; + +class ObjectTypeHasher : public IObjectTypeHasher +{ +public: + std::size_t operator()(const BaseObjectType &object_type) const override; +}; diff --git a/src/DI/object_wrapper.hpp b/src/DI/object_wrapper.hpp new file mode 100644 index 0000000..0ae66df --- /dev/null +++ b/src/DI/object_wrapper.hpp @@ -0,0 +1,20 @@ +#pragma once + +#include "DI/container.hpp" +#include "DI/interfaces/wrapper.hpp" + +#include <memory> + +template <class Interface, class ObjectImpl> +class ObjectWrapper : public IWrapper<std::shared_ptr<Interface>> +{ +public: + explicit ObjectWrapper(const Container &container) : _container(container) {} + + [[nodiscard]] std::shared_ptr<Interface> get() const; + +private: + const Container &_container; +}; + +#include "object_wrapper.tpp" diff --git a/src/DI/object_wrapper.tpp b/src/DI/object_wrapper.tpp new file mode 100644 index 0000000..7efefc4 --- /dev/null +++ b/src/DI/object_wrapper.tpp @@ -0,0 +1,9 @@ +#pragma once + +#include "object_wrapper.hpp" + +template <class Interface, class ObjectImpl> +std::shared_ptr<Interface> ObjectWrapper<Interface, ObjectImpl>::get() const +{ + return ObjectImpl::resolve(_container); +} |