From d8ea3721d83254e91c5617d83f2aac5a897107fb Mon Sep 17 00:00:00 2001 From: HampusM Date: Fri, 6 May 2022 18:23:11 +0200 Subject: feat: implement tagging in container --- CMakeLists.txt | 2 +- include/yacppdic/auto_wirable.hpp | 11 +++- include/yacppdic/container.hpp | 36 +++++++++- include/yacppdic/detail/auto_wirable-impl.hpp | 23 ++++++- include/yacppdic/detail/container-impl.hpp | 94 +++++++++++++++++++++++---- include/yacppdic/detail/internal/hash.hpp | 14 ++++ include/yacppdic/object_type.hpp | 12 ++++ include/yacppdic/tagged.hpp | 43 ++++++++++++ src/container.cpp | 13 +++- src/object_type.cpp | 22 ++++++- 10 files changed, 250 insertions(+), 20 deletions(-) create mode 100644 include/yacppdic/detail/internal/hash.hpp create mode 100644 include/yacppdic/tagged.hpp 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 namespace yacppdic { -template +template class AutoWirable { public: static auto resolve(const Container &container) noexcept -> std::unique_ptr; + +private: + template + requires IsTagged + static auto _get_dependency(const Container &container) noexcept; + + template + 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 #include #include +#include #include namespace yacppdic @@ -16,6 +17,22 @@ namespace yacppdic class Container; +template +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 class BindingBuilder { @@ -24,11 +41,11 @@ public: template requires Abstract && std::derived_from - void to() noexcept; + auto to() noexcept -> BindingWhen; template requires IsFactory && std::constructible_from - void to_factory(FactoryFunc factory) noexcept; + auto to_factory(FactoryFunc factory) noexcept -> BindingWhen; private: Container *_container; @@ -53,7 +70,20 @@ public: requires IsFactory auto get() const noexcept -> AFactory; - void add(BaseObjectType type, const WrapperPtr &wrapper) noexcept; + template + requires Abstract + auto get_tagged(const char *tag) const noexcept -> std::unique_ptr; + + template + requires IsFactory + auto get_tagged(const char *tag) const noexcept -> AFactory; + + void + add(const BaseObjectType &type, const WrapperPtr &wrapper) noexcept; + + void remove(const BaseObjectType &type) noexcept; + + WrapperPtr at(const BaseObjectType &type) const noexcept; private: std::unordered_map, 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 +template auto AutoWirable::resolve( const Container &container ) noexcept -> std::unique_ptr { - return std::make_unique(container.get()...); + return std::make_unique(_get_dependency(container)...); +} + +template +template +requires IsTagged +auto AutoWirable::_get_dependency( + const Container &container +) noexcept +{ + return container.get_tagged(Dependency::get_tag()); +} + +template +template +auto AutoWirable::_get_dependency( + const Container &container +) noexcept +{ + return container.get(); } } // 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 @@ -9,6 +9,27 @@ namespace yacppdic { +template +BindingWhen::BindingWhen( + Container *container, + const BaseObjectType &object_type +) noexcept + : _container(container), _object_type(object_type) +{ +} + +template +void BindingWhen::when_tagged(std::string_view tag) noexcept +{ + auto wrapped = _container->at(_object_type); + + _container->remove(_object_type); + + auto object_type = ObjectType(tag); + + _container->add(object_type, wrapped); +} + template BindingBuilder::BindingBuilder(Container *container) noexcept : _container(container) @@ -18,31 +39,34 @@ BindingBuilder::BindingBuilder(Container *container) noexcept template template requires Abstract && std::derived_from -void BindingBuilder::to() noexcept +auto BindingBuilder::to() noexcept -> BindingWhen { using Wrapper = internal::ObjectWrapper; auto wrapper = Container::WrapperPtr(new Wrapper(*_container)); - _container->add( - ObjectType(), - std::dynamic_pointer_cast(wrapper) - ); + auto object_type = ObjectType(); + + _container->add(object_type, std::dynamic_pointer_cast(wrapper)); + + return BindingWhen(_container, object_type); } template template requires IsFactory && std::constructible_from -void BindingBuilder::to_factory(FactoryFunc factory) noexcept +auto BindingBuilder::to_factory(FactoryFunc factory) noexcept + -> BindingWhen { using Wrapper = internal::FunctionWrapper; auto wrapper = Container::WrapperPtr(new Wrapper(factory)); - _container->add( - ObjectType(), - std::dynamic_pointer_cast(wrapper) - ); + auto object_type = ObjectType(); + + _container->add(object_type, std::dynamic_pointer_cast(wrapper)); + + return BindingWhen(_container, object_type); } template @@ -76,11 +100,59 @@ template requires IsFactory auto Container::get() const noexcept -> AFactory { + BaseObjectType type = ObjectType(); + + 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>(_bindings.at(type)); + + return wrapper->get(); +} + +template +requires Abstract +auto Container::get_tagged(const char *tag) const noexcept -> std::unique_ptr +{ + BaseObjectType type = ObjectType(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>(_bindings.at(ObjectType()) + std::dynamic_pointer_cast>>(_bindings.at(type) ); return wrapper->get(); } +template +requires IsFactory +auto Container::get_tagged(const char *tag) const noexcept -> AFactory +{ + BaseObjectType type = ObjectType(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>(_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 + +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 @@ -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 + +namespace yacppdic +{ + +template +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 +struct is_tagged : public std::false_type // NOLINT(readability-identifier-naming) +{ +}; + +template +struct is_tagged> : public std::true_type +{ +}; + +template +inline constexpr bool is_tagged_v = is_tagged::value; + +template +concept IsTagged = is_tagged_v; + +} // 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 &wrapper ) noexcept { _bindings.insert({ type, wrapper }); } +void Container::remove(const BaseObjectType &type) noexcept +{ + _bindings.erase(type); +} + +Container::WrapperPtr 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 + 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()(_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 { -- cgit v1.2.3-18-g5258