aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt2
-rw-r--r--include/yacppdic/auto_wirable.hpp11
-rw-r--r--include/yacppdic/container.hpp36
-rw-r--r--include/yacppdic/detail/auto_wirable-impl.hpp23
-rw-r--r--include/yacppdic/detail/container-impl.hpp94
-rw-r--r--include/yacppdic/detail/internal/hash.hpp14
-rw-r--r--include/yacppdic/object_type.hpp12
-rw-r--r--include/yacppdic/tagged.hpp43
-rw-r--r--src/container.cpp13
-rw-r--r--src/object_type.cpp22
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
{