diff options
author | HampusM <hampus@hampusmat.com> | 2022-05-06 18:23:11 +0200 |
---|---|---|
committer | HampusM <hampus@hampusmat.com> | 2022-05-06 18:23:11 +0200 |
commit | d8ea3721d83254e91c5617d83f2aac5a897107fb (patch) | |
tree | 19b90c6d27e9bc75457ae6a5385db6b252d77b21 | |
parent | b83e94a05efd4dc4d0836bbb59cb500d0c0b219a (diff) |
feat: implement tagging in container
-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 { |