diff options
| -rw-r--r-- | CMakeLists.txt | 2 | ||||
| -rw-r--r-- | include/yacppdic/auto_wirable.hpp | 11 | ||||
| -rw-r--r-- | include/yacppdic/container.hpp | 36 | ||||
| -rw-r--r-- | include/yacppdic/detail/auto_wirable-impl.hpp | 23 | ||||
| -rw-r--r-- | include/yacppdic/detail/container-impl.hpp | 94 | ||||
| -rw-r--r-- | include/yacppdic/detail/internal/hash.hpp | 14 | ||||
| -rw-r--r-- | include/yacppdic/object_type.hpp | 12 | ||||
| -rw-r--r-- | include/yacppdic/tagged.hpp | 43 | ||||
| -rw-r--r-- | src/container.cpp | 13 | ||||
| -rw-r--r-- | src/object_type.cpp | 22 | 
10 files changed, 250 insertions, 20 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 49370d9..af8fc8a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,7 +3,7 @@ cmake_minimum_required(VERSION 3.2.0)  set(CMAKE_EXPORT_COMPILE_COMMANDS 1)  set(CMAKE_CXX_STANDARD 20)  set(CMAKE_CXX_STANDARD_REQUIRED ON) -set(CMAKE_CXX_EXTENSIONS OFF) +set(CMAKE_CXX_EXTENSIONS ON)  project(yacppdic CXX) diff --git a/include/yacppdic/auto_wirable.hpp b/include/yacppdic/auto_wirable.hpp index 09cef65..c10ba18 100644 --- a/include/yacppdic/auto_wirable.hpp +++ b/include/yacppdic/auto_wirable.hpp @@ -1,18 +1,27 @@  #pragma once  #include "yacppdic/container.hpp" +#include "yacppdic/tagged.hpp"  #include <memory>  namespace yacppdic  { -template <class Interface, class ObjectImpl, class... Dependencies> +template <typename Interface, typename ObjectImpl, typename... Dependencies>  class AutoWirable  {  public:  	static auto resolve(const Container &container) noexcept  		-> std::unique_ptr<Interface>; + +private: +	template <typename Dependency> +	requires IsTagged<Dependency> +	static auto _get_dependency(const Container &container) noexcept; + +	template <typename Dependency> +	static auto _get_dependency(const Container &container) noexcept;  };  } // namespace yacppdic diff --git a/include/yacppdic/container.hpp b/include/yacppdic/container.hpp index f8ffb90..c206d39 100644 --- a/include/yacppdic/container.hpp +++ b/include/yacppdic/container.hpp @@ -9,6 +9,7 @@  #include <concepts>  #include <functional>  #include <memory> +#include <string_view>  #include <unordered_map>  namespace yacppdic @@ -17,6 +18,22 @@ namespace yacppdic  class Container;  template <typename Interface> +class BindingWhen +{ +public: +	explicit BindingWhen( +		Container *container, +		const BaseObjectType &object_type +	) noexcept; + +	void when_tagged(std::string_view tag) noexcept; + +private: +	Container *_container; +	BaseObjectType _object_type; +}; + +template <typename Interface>  class BindingBuilder  {  public: @@ -24,11 +41,11 @@ public:  	template <typename Impl>  	requires Abstract<Interface> && std::derived_from<Impl, Interface> -	void to() noexcept; +	auto to() noexcept -> BindingWhen<Interface>;  	template <typename FactoryFunc>  	requires IsFactory<Interface> && std::constructible_from<Interface, FactoryFunc> -	void to_factory(FactoryFunc factory) noexcept; +	auto to_factory(FactoryFunc factory) noexcept -> BindingWhen<Interface>;  private:  	Container *_container; @@ -53,7 +70,20 @@ public:  	requires IsFactory<AFactory>  	auto get() const noexcept -> AFactory; -	void add(BaseObjectType type, const WrapperPtr<IGenericWrapper> &wrapper) noexcept; +	template <class Interface> +	requires Abstract<Interface> +	auto get_tagged(const char *tag) const noexcept -> std::unique_ptr<Interface>; + +	template <typename AFactory> +	requires IsFactory<AFactory> +	auto get_tagged(const char *tag) const noexcept -> AFactory; + +	void +	add(const BaseObjectType &type, const WrapperPtr<IGenericWrapper> &wrapper) noexcept; + +	void remove(const BaseObjectType &type) noexcept; + +	WrapperPtr<IGenericWrapper> at(const BaseObjectType &type) const noexcept;  private:  	std::unordered_map<BaseObjectType, WrapperPtr<IGenericWrapper>, ObjectTypeHasher> diff --git a/include/yacppdic/detail/auto_wirable-impl.hpp b/include/yacppdic/detail/auto_wirable-impl.hpp index e2dafa9..e81f34c 100644 --- a/include/yacppdic/detail/auto_wirable-impl.hpp +++ b/include/yacppdic/detail/auto_wirable-impl.hpp @@ -5,12 +5,31 @@  namespace yacppdic  { -template <class Interface, class ObjectImpl, class... Dependencies> +template <typename Interface, typename ObjectImpl, typename... Dependencies>  auto AutoWirable<Interface, ObjectImpl, Dependencies...>::resolve(  	const Container &container  ) noexcept -> std::unique_ptr<Interface>  { -	return std::make_unique<ObjectImpl>(container.get<Dependencies>()...); +	return std::make_unique<ObjectImpl>(_get_dependency<Dependencies>(container)...); +} + +template <typename Interface, typename ObjectImpl, typename... Dependencies> +template <typename Dependency> +requires IsTagged<Dependency> +auto AutoWirable<Interface, ObjectImpl, Dependencies...>::_get_dependency( +	const Container &container +) noexcept +{ +	return container.get_tagged<typename Dependency::Target>(Dependency::get_tag()); +} + +template <typename Interface, typename ObjectImpl, typename... Dependencies> +template <typename Dependency> +auto AutoWirable<Interface, ObjectImpl, Dependencies...>::_get_dependency( +	const Container &container +) noexcept +{ +	return container.get<Dependency>();  }  } // namespace yacppdic diff --git a/include/yacppdic/detail/container-impl.hpp b/include/yacppdic/detail/container-impl.hpp index 584c0d0..952d510 100644 --- a/include/yacppdic/detail/container-impl.hpp +++ b/include/yacppdic/detail/container-impl.hpp @@ -10,6 +10,27 @@ namespace yacppdic  {  template <typename Interface> +BindingWhen<Interface>::BindingWhen( +	Container *container, +	const BaseObjectType &object_type +) noexcept +	: _container(container), _object_type(object_type) +{ +} + +template <typename Interface> +void BindingWhen<Interface>::when_tagged(std::string_view tag) noexcept +{ +	auto wrapped = _container->at(_object_type); + +	_container->remove(_object_type); + +	auto object_type = ObjectType<Interface>(tag); + +	_container->add(object_type, wrapped); +} + +template <typename Interface>  BindingBuilder<Interface>::BindingBuilder(Container *container) noexcept  	: _container(container)  { @@ -18,31 +39,34 @@ BindingBuilder<Interface>::BindingBuilder(Container *container) noexcept  template <typename Interface>  template <typename Impl>  requires Abstract<Interface> && std::derived_from<Impl, Interface> -void BindingBuilder<Interface>::to() noexcept +auto BindingBuilder<Interface>::to() noexcept -> BindingWhen<Interface>  {  	using Wrapper = internal::ObjectWrapper<Interface, Impl>;  	auto wrapper = Container::WrapperPtr<Wrapper>(new Wrapper(*_container)); -	_container->add( -		ObjectType<Interface>(), -		std::dynamic_pointer_cast<IGenericWrapper>(wrapper) -	); +	auto object_type = ObjectType<Interface>(); + +	_container->add(object_type, std::dynamic_pointer_cast<IGenericWrapper>(wrapper)); + +	return BindingWhen<Interface>(_container, object_type);  }  template <typename Interface>  template <typename FactoryFunc>  requires IsFactory<Interface> && std::constructible_from<Interface, FactoryFunc> -void BindingBuilder<Interface>::to_factory(FactoryFunc factory) noexcept +auto BindingBuilder<Interface>::to_factory(FactoryFunc factory) noexcept +	-> BindingWhen<Interface>  {  	using Wrapper = internal::FunctionWrapper<Interface>;  	auto wrapper = Container::WrapperPtr<Wrapper>(new Wrapper(factory)); -	_container->add( -		ObjectType<Interface>(), -		std::dynamic_pointer_cast<IGenericWrapper>(wrapper) -	); +	auto object_type = ObjectType<Interface>(); + +	_container->add(object_type, std::dynamic_pointer_cast<IGenericWrapper>(wrapper)); + +	return BindingWhen<Interface>(_container, object_type);  }  template <typename Interface> @@ -76,11 +100,59 @@ template <typename AFactory>  requires IsFactory<AFactory>  auto Container::get() const noexcept -> AFactory  { +	BaseObjectType type = ObjectType<AFactory>(); + +	if (_bindings.count(type) == 0) +	{ +		std::cerr +			<< "Error: Tried to get a item from the container using unbound interface '" +			<< type.name() << "'" << std::endl; +		exit(EXIT_FAILURE); +	} + +	auto wrapper = std::dynamic_pointer_cast<IWrapper<AFactory>>(_bindings.at(type)); + +	return wrapper->get(); +} + +template <class Interface> +requires Abstract<Interface> +auto Container::get_tagged(const char *tag) const noexcept -> std::unique_ptr<Interface> +{ +	BaseObjectType type = ObjectType<Interface>(tag); + +	if (_bindings.count(type) == 0) +	{ +		std::cerr +			<< "Error: Tried to get a item from the container using unbound interface '" +			<< type.name() << "' with tag '" << type.tag() << "'" << std::endl; +		exit(EXIT_FAILURE); +	} +  	auto wrapper = -		std::dynamic_pointer_cast<IWrapper<AFactory>>(_bindings.at(ObjectType<AFactory>()) +		std::dynamic_pointer_cast<IWrapper<std::unique_ptr<Interface>>>(_bindings.at(type)  		);  	return wrapper->get();  } +template <typename AFactory> +requires IsFactory<AFactory> +auto Container::get_tagged(const char *tag) const noexcept -> AFactory +{ +	BaseObjectType type = ObjectType<AFactory>(tag); + +	if (_bindings.count(type) == 0) +	{ +		std::cerr +			<< "Error: Tried to get a item from the container using unbound interface '" +			<< type.name() << "' With tag '" << type.tag() << "'" << std::endl; +		exit(EXIT_FAILURE); +	} + +	auto wrapper = std::dynamic_pointer_cast<IWrapper<AFactory>>(_bindings.at(type)); + +	return wrapper->get(); +} +  } // namespace yacppdic diff --git a/include/yacppdic/detail/internal/hash.hpp b/include/yacppdic/detail/internal/hash.hpp new file mode 100644 index 0000000..145f048 --- /dev/null +++ b/include/yacppdic/detail/internal/hash.hpp @@ -0,0 +1,14 @@ +#pragma once + +#include <cstddef> + +constexpr auto GOLDEN_RATIO = 0x9e3779b9; + +constexpr std::size_t combine_hashes(std::size_t hash_one, std::size_t hash_two) noexcept +{ +	auto combined = hash_one; + +	combined ^= hash_two + GOLDEN_RATIO + (hash_one << 6) + (hash_one >> 2); + +	return combined; +} diff --git a/include/yacppdic/object_type.hpp b/include/yacppdic/object_type.hpp index 5107dbf..c1e2e27 100644 --- a/include/yacppdic/object_type.hpp +++ b/include/yacppdic/object_type.hpp @@ -8,14 +8,22 @@ class BaseObjectType  public:  	explicit BaseObjectType(const std::type_info &type_info) noexcept; +	explicit BaseObjectType( +		const std::type_info &type_info, +		const std::string_view tag +	) noexcept; +  	auto operator==(const BaseObjectType &object_type) const noexcept -> bool;  	[[nodiscard]] auto hash() const noexcept -> std::size_t;  	[[nodiscard]] auto name() const noexcept -> std::string_view; +	[[nodiscard]] auto tag() const noexcept -> std::string_view; +  private:  	const std::type_info &_type_info; +	const std::string_view _tag;  };  template <class Object> @@ -23,6 +31,10 @@ class ObjectType : public BaseObjectType  {  public:  	ObjectType() noexcept : BaseObjectType(typeid(Object)) {} + +	ObjectType(const std::string_view &tag) noexcept : BaseObjectType(typeid(Object), tag) +	{ +	}  };  class ObjectTypeHasher diff --git a/include/yacppdic/tagged.hpp b/include/yacppdic/tagged.hpp new file mode 100644 index 0000000..66c0592 --- /dev/null +++ b/include/yacppdic/tagged.hpp @@ -0,0 +1,43 @@ +#pragma once + +#include <utility> + +namespace yacppdic +{ + +template <typename TargetType, char const *tag> +class Tagged +{ +public: +	using Target = TargetType; + +	Tagged() noexcept = delete; +	Tagged(const Tagged &tagged) noexcept = delete; +	Tagged(Tagged &&tagged) noexcept = delete; + +	static constexpr char const *get_tag() noexcept +	{ +		return tag; +	} + +	Tagged &operator=(const Tagged &tagged) noexcept = delete; +	Tagged &operator=(Tagged &&tagged) noexcept = delete; +}; + +template <typename> +struct is_tagged : public std::false_type // NOLINT(readability-identifier-naming) +{ +}; + +template <typename TargetType, char const *tag> +struct is_tagged<Tagged<TargetType, tag>> : public std::true_type +{ +}; + +template <typename PossiblyTagged> +inline constexpr bool is_tagged_v = is_tagged<PossiblyTagged>::value; + +template <typename PossiblyTagged> +concept IsTagged = is_tagged_v<PossiblyTagged>; + +} // namespace yacppdic diff --git a/src/container.cpp b/src/container.cpp index d906f1e..00efc27 100644 --- a/src/container.cpp +++ b/src/container.cpp @@ -7,11 +7,22 @@ namespace yacppdic  {  void Container::add( -	BaseObjectType type, +	const BaseObjectType &type,  	const WrapperPtr<IGenericWrapper> &wrapper  ) noexcept  {  	_bindings.insert({ type, wrapper });  } +void Container::remove(const BaseObjectType &type) noexcept +{ +	_bindings.erase(type); +} + +Container::WrapperPtr<IGenericWrapper> Container::at(const BaseObjectType &type +) const noexcept +{ +	return _bindings.at(type); +} +  } // namespace yacppdic diff --git a/src/object_type.cpp b/src/object_type.cpp index 4384e37..ee0fe66 100644 --- a/src/object_type.cpp +++ b/src/object_type.cpp @@ -1,10 +1,22 @@  #include "yacppdic/object_type.hpp" +#include "yacppdic/detail/internal/hash.hpp" + +#include <functional> +  BaseObjectType::BaseObjectType(const std::type_info &type_info) noexcept  	: _type_info(type_info)  {  } +BaseObjectType::BaseObjectType( +	const std::type_info &type_info, +	const std::string_view tag +) noexcept +	: _type_info(type_info), _tag(tag) +{ +} +  auto BaseObjectType::operator==(const BaseObjectType &object_type) const noexcept -> bool  {  	return hash() == object_type.hash(); @@ -12,7 +24,10 @@ auto BaseObjectType::operator==(const BaseObjectType &object_type) const noexcep  auto BaseObjectType::hash() const noexcept -> std::size_t  { -	return _type_info.hash_code(); +	const auto type_hash = _type_info.hash_code(); + +	return _tag == "" ? type_hash +					  : combine_hashes(type_hash, std::hash<std::string_view>()(_tag));  }  auto BaseObjectType::name() const noexcept -> std::string_view @@ -20,6 +35,11 @@ auto BaseObjectType::name() const noexcept -> std::string_view  	return { _type_info.name() };  } +auto BaseObjectType::tag() const noexcept -> std::string_view +{ +	return _tag; +} +  auto ObjectTypeHasher::operator()(const BaseObjectType &object_type) const noexcept  	-> std::size_t  {  | 
