locator: support to opaque structures (close #956)
This commit is contained in:
@@ -70,40 +70,40 @@ public:
|
||||
* cases, they are discarded.
|
||||
*
|
||||
* @tparam Args Types of arguments to use to construct the fallback service.
|
||||
* @tparam Impl Fallback service type.
|
||||
* @tparam Type Fallback service type.
|
||||
* @param args Parameters to use to construct the fallback service.
|
||||
* @return A reference to a valid service.
|
||||
*/
|
||||
template<typename Impl = Service, typename... Args>
|
||||
template<typename Type = Service, typename... Args>
|
||||
[[nodiscard]] static Service &value_or(Args &&...args) {
|
||||
return service ? *service : emplace<Impl>(std::forward<Args>(args)...);
|
||||
return service ? *service : emplace<Type>(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets or replaces a service.
|
||||
* @tparam Impl Service type.
|
||||
* @tparam Type Service type.
|
||||
* @tparam Args Types of arguments to use to construct the service.
|
||||
* @param args Parameters to use to construct the service.
|
||||
* @return A reference to a valid service.
|
||||
*/
|
||||
template<typename Impl = Service, typename... Args>
|
||||
template<typename Type = Service, typename... Args>
|
||||
static Service &emplace(Args &&...args) {
|
||||
service = std::make_shared<Impl>(std::forward<Args>(args)...);
|
||||
service = std::make_shared<Type>(std::forward<Args>(args)...);
|
||||
return *service;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets or replaces a service using a given allocator.
|
||||
* @tparam Impl Service type.
|
||||
* @tparam Type Service type.
|
||||
* @tparam Allocator Type of allocator used to manage memory and elements.
|
||||
* @tparam Args Types of arguments to use to construct the service.
|
||||
* @param alloc The allocator to use.
|
||||
* @param args Parameters to use to construct the service.
|
||||
* @return A reference to a valid service.
|
||||
*/
|
||||
template<typename Impl = Service, typename Allocator, typename... Args>
|
||||
static Service &allocate_emplace(Allocator alloc, Args &&...args) {
|
||||
service = std::allocate_shared<Impl>(alloc, std::forward<Args>(args)...);
|
||||
template<typename Type = Service, typename Allocator, typename... Args>
|
||||
static Service &emplace(std::allocator_arg_t, Allocator alloc, Args &&...args) {
|
||||
service = std::allocate_shared<Type>(alloc, std::forward<Args>(args)...);
|
||||
return *service;
|
||||
}
|
||||
|
||||
@@ -125,6 +125,18 @@ public:
|
||||
service = other.value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Resets or replaces a service.
|
||||
* @tparam Type Service type.
|
||||
* @tparam Deleter Deleter type.
|
||||
* @param elem A pointer to a service to manage.
|
||||
* @param deleter A deleter to use to destroy the service.
|
||||
*/
|
||||
template<typename Type, typename Deleter = std::default_delete<Type>>
|
||||
static void reset(Type *elem, Deleter deleter = {}) {
|
||||
service = std::shared_ptr<Service>{elem, std::move(deleter)};
|
||||
}
|
||||
|
||||
private:
|
||||
// std::shared_ptr because of its type erased allocator which is useful here
|
||||
inline static std::shared_ptr<Service> service{};
|
||||
|
||||
@@ -5,36 +5,57 @@
|
||||
|
||||
struct base_service {
|
||||
virtual ~base_service() = default;
|
||||
virtual void invoke() {}
|
||||
};
|
||||
|
||||
struct null_service: base_service {
|
||||
void invoke() override {
|
||||
invoked = true;
|
||||
}
|
||||
|
||||
static inline bool invoked{};
|
||||
virtual int invoke(int) = 0;
|
||||
};
|
||||
|
||||
struct derived_service: base_service {
|
||||
void invoke() override {
|
||||
invoked = true;
|
||||
derived_service(int val)
|
||||
: value{val} {}
|
||||
|
||||
int invoke(int other) override {
|
||||
return value + other;
|
||||
}
|
||||
|
||||
static inline bool invoked{};
|
||||
private:
|
||||
int value;
|
||||
};
|
||||
|
||||
TEST(ServiceLocator, Functionalities) {
|
||||
ASSERT_FALSE(entt::locator<base_service>::has_value());
|
||||
ASSERT_FALSE(derived_service::invoked);
|
||||
ASSERT_FALSE(null_service::invoked);
|
||||
struct ServiceLocator: ::testing::Test {
|
||||
void SetUp() override {
|
||||
entt::locator<base_service>::reset();
|
||||
}
|
||||
};
|
||||
|
||||
entt::locator<base_service>::value_or<null_service>().invoke();
|
||||
using ServiceLocatorDeathTest = ServiceLocator;
|
||||
|
||||
TEST_F(ServiceLocator, ValueAndTheLike) {
|
||||
ASSERT_FALSE(entt::locator<base_service>::has_value());
|
||||
ASSERT_EQ(entt::locator<base_service>::value_or<derived_service>(1).invoke(3), 4);
|
||||
ASSERT_TRUE(entt::locator<base_service>::has_value());
|
||||
ASSERT_EQ(entt::locator<base_service>::value().invoke(9), 10);
|
||||
}
|
||||
|
||||
TEST_F(ServiceLocator, Emplace) {
|
||||
ASSERT_FALSE(entt::locator<base_service>::has_value());
|
||||
ASSERT_EQ(entt::locator<base_service>::emplace<derived_service>(5).invoke(1), 6);
|
||||
ASSERT_TRUE(entt::locator<base_service>::has_value());
|
||||
ASSERT_EQ(entt::locator<base_service>::value().invoke(3), 8);
|
||||
|
||||
entt::locator<base_service>::reset();
|
||||
|
||||
ASSERT_FALSE(entt::locator<base_service>::has_value());
|
||||
ASSERT_EQ(entt::locator<base_service>::emplace<derived_service>(std::allocator_arg, std::allocator<derived_service>{}, 5).invoke(1), 6);
|
||||
ASSERT_TRUE(entt::locator<base_service>::has_value());
|
||||
ASSERT_EQ(entt::locator<base_service>::value().invoke(3), 8);
|
||||
}
|
||||
|
||||
TEST_F(ServiceLocator, ResetHandle) {
|
||||
entt::locator<base_service>::emplace<derived_service>(1);
|
||||
auto handle = entt::locator<base_service>::handle();
|
||||
|
||||
ASSERT_TRUE(entt::locator<base_service>::has_value());
|
||||
ASSERT_TRUE(null_service::invoked);
|
||||
ASSERT_EQ(entt::locator<base_service>::value().invoke(3), 4);
|
||||
|
||||
auto handle = entt::locator<base_service>::handle();
|
||||
entt::locator<base_service>::reset();
|
||||
|
||||
ASSERT_FALSE(entt::locator<base_service>::has_value());
|
||||
@@ -42,28 +63,25 @@ TEST(ServiceLocator, Functionalities) {
|
||||
entt::locator<base_service>::reset(handle);
|
||||
|
||||
ASSERT_TRUE(entt::locator<base_service>::has_value());
|
||||
|
||||
entt::locator<base_service>::reset(decltype(handle){});
|
||||
|
||||
ASSERT_FALSE(entt::locator<base_service>::has_value());
|
||||
|
||||
entt::locator<base_service>::emplace<derived_service>();
|
||||
entt::locator<base_service>::value().invoke();
|
||||
|
||||
ASSERT_TRUE(entt::locator<base_service>::has_value());
|
||||
ASSERT_TRUE(derived_service::invoked);
|
||||
|
||||
derived_service::invoked = false;
|
||||
entt::locator<base_service>::allocate_emplace<derived_service>(std::allocator<derived_service>{}).invoke();
|
||||
|
||||
ASSERT_TRUE(entt::locator<base_service>::has_value());
|
||||
ASSERT_TRUE(derived_service::invoked);
|
||||
ASSERT_EQ(entt::locator<base_service>::value().invoke(3), 4);
|
||||
}
|
||||
|
||||
ENTT_DEBUG_TEST(ServiceLocatorDeathTest, UninitializedValue) {
|
||||
ASSERT_NO_FATAL_FAILURE(entt::locator<base_service>::value_or().invoke());
|
||||
TEST_F(ServiceLocator, ElementWithDeleter) {
|
||||
derived_service service{1};
|
||||
entt::locator<base_service>::reset(&service, [](base_service *serv) { *static_cast<derived_service *>(serv) = derived_service{2}; });
|
||||
|
||||
ASSERT_TRUE(entt::locator<base_service>::has_value());
|
||||
ASSERT_EQ(entt::locator<base_service>::value().invoke(1), 2);
|
||||
|
||||
entt::locator<base_service>::reset();
|
||||
|
||||
ASSERT_DEATH(entt::locator<base_service>::value().invoke(), "");
|
||||
ASSERT_EQ(service.invoke(1), 3);
|
||||
}
|
||||
|
||||
ENTT_DEBUG_TEST_F(ServiceLocatorDeathTest, UninitializedValue) {
|
||||
ASSERT_EQ(entt::locator<base_service>::value_or<derived_service>(1).invoke(1), 2);
|
||||
|
||||
entt::locator<base_service>::reset();
|
||||
|
||||
ASSERT_DEATH(entt::locator<base_service>::value().invoke(42), "");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user