Forráskód Böngészése

locator: support to opaque structures (close #956)

Michele Caini 2 éve
szülő
commit
fed6831cdc
2 módosított fájl, 68 hozzáadás és 38 törlés
  1. 22 10
      src/entt/locator/locator.hpp
  2. 46 28
      test/entt/locator/locator.cpp

+ 22 - 10
src/entt/locator/locator.hpp

@@ -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{};

+ 46 - 28
test/entt/locator/locator.cpp

@@ -5,65 +5,83 @@
 
 struct base_service {
     virtual ~base_service() = default;
-    virtual void invoke() {}
+    virtual int invoke(int) = 0;
 };
 
-struct null_service: base_service {
-    void invoke() override {
-        invoked = true;
+struct derived_service: base_service {
+    derived_service(int val)
+        : value{val} {}
+
+    int invoke(int other) override {
+        return value + other;
     }
 
-    static inline bool invoked{};
+private:
+    int value;
 };
 
-struct derived_service: base_service {
-    void invoke() override {
-        invoked = true;
+struct ServiceLocator: ::testing::Test {
+    void SetUp() override {
+        entt::locator<base_service>::reset();
     }
-
-    static inline bool invoked{};
 };
 
-TEST(ServiceLocator, Functionalities) {
-    ASSERT_FALSE(entt::locator<base_service>::has_value());
-    ASSERT_FALSE(derived_service::invoked);
-    ASSERT_FALSE(null_service::invoked);
+using ServiceLocatorDeathTest = ServiceLocator;
 
-    entt::locator<base_service>::value_or<null_service>().invoke();
+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_TRUE(null_service::invoked);
+    ASSERT_EQ(entt::locator<base_service>::value().invoke(3), 8);
 
-    auto handle = entt::locator<base_service>::handle();
     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);
+}
 
-    entt::locator<base_service>::reset(handle);
+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_EQ(entt::locator<base_service>::value().invoke(3), 4);
 
-    entt::locator<base_service>::reset(decltype(handle){});
+    entt::locator<base_service>::reset();
 
     ASSERT_FALSE(entt::locator<base_service>::has_value());
 
-    entt::locator<base_service>::emplace<derived_service>();
-    entt::locator<base_service>::value().invoke();
+    entt::locator<base_service>::reset(handle);
 
     ASSERT_TRUE(entt::locator<base_service>::has_value());
-    ASSERT_TRUE(derived_service::invoked);
+    ASSERT_EQ(entt::locator<base_service>::value().invoke(3), 4);
+}
 
-    derived_service::invoked = false;
-    entt::locator<base_service>::allocate_emplace<derived_service>(std::allocator<derived_service>{}).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_TRUE(derived_service::invoked);
+    ASSERT_EQ(entt::locator<base_service>::value().invoke(1), 2);
+
+    entt::locator<base_service>::reset();
+
+    ASSERT_EQ(service.invoke(1), 3);
 }
 
-ENTT_DEBUG_TEST(ServiceLocatorDeathTest, UninitializedValue) {
-    ASSERT_NO_FATAL_FAILURE(entt::locator<base_service>::value_or().invoke());
+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(), "");
+    ASSERT_DEATH(entt::locator<base_service>::value().invoke(42), "");
 }