Sfoglia il codice sorgente

scheduler/process: factory-like model, first draft, work in progress - see #1257

skypjack 9 mesi fa
parent
commit
41ebe0e779

+ 49 - 7
src/entt/process/process.hpp

@@ -2,6 +2,7 @@
 #define ENTT_PROCESS_PROCESS_HPP
 #define ENTT_PROCESS_PROCESS_HPP
 
 
 #include <cstdint>
 #include <cstdint>
+#include <memory>
 #include <type_traits>
 #include <type_traits>
 #include <utility>
 #include <utility>
 #include "fwd.hpp"
 #include "fwd.hpp"
@@ -56,7 +57,12 @@ namespace entt {
  * @tparam Delta Type to use to provide elapsed time.
  * @tparam Delta Type to use to provide elapsed time.
  */
  */
 template<typename Delta>
 template<typename Delta>
-class process {
+class process: private std::enable_shared_from_this<process<Delta>> {
+    class process_arg_t {
+        friend class process<Delta>;
+        explicit process_arg_t() = default;
+    };
+
     enum class state : std::uint8_t {
     enum class state : std::uint8_t {
         idle = 0,
         idle = 0,
         running,
         running,
@@ -77,11 +83,14 @@ class process {
     virtual void aborted() {}
     virtual void aborted() {}
 
 
 public:
 public:
+    /*! @brief Process constructor token. */
+    using token_type = process_arg_t;
     /*! @brief Type used to provide elapsed time. */
     /*! @brief Type used to provide elapsed time. */
     using delta_type = Delta;
     using delta_type = Delta;
 
 
     /*! @brief Default constructor. */
     /*! @brief Default constructor. */
-    constexpr process() = default;
+    constexpr process(token_type)
+        : current{state::idle} {}
 
 
     /*! @brief Default destructor. */
     /*! @brief Default destructor. */
     virtual ~process() = default;
     virtual ~process() = default;
@@ -104,6 +113,32 @@ public:
      */
      */
     process &operator=(process &&) noexcept = default;
     process &operator=(process &&) noexcept = default;
 
 
+    /**
+     * @brief Factory method.
+     * @tparam Type Type of process to create.
+     * @tparam Args Types of arguments to use to initialize the process.
+     * @param args Parameters to use to initialize the process.
+     * @return A properly initialized process.
+     */
+    template<typename Type, typename... Args>
+    static std::shared_ptr<Type> create(Args &&...args) {
+        return std::make_shared<Type>(process_arg_t{}, std::forward<Args>(args)...);
+    }
+
+    /**
+     * @brief Factory method.
+     * @tparam Type Type of process to create.
+     * @tparam Allocator Type of allocator used to manage memory and elements.
+     * @tparam Args Types of arguments to use to initialize the process.
+     * @param alloc The allocator to use.
+     * @param args Parameters to use to initialize the process.
+     * @return A properly initialized process.
+     */
+    template<typename Type, typename Allocator, typename... Args>
+    static std::shared_ptr<Type> create_with_allocator(std::allocator_arg_t, const Allocator &alloc, Args &&...args) {
+        return std::allocate_shared<Type>(alloc, process_arg_t{}, std::forward<Args>(args)...);
+    }
+
     /**
     /**
      * @brief Aborts a process if it's still alive, otherwise does nothing.
      * @brief Aborts a process if it's still alive, otherwise does nothing.
      * @param immediate Requests an immediate operation.
      * @param immediate Requests an immediate operation.
@@ -222,7 +257,7 @@ public:
     }
     }
 
 
 private:
 private:
-    state current{state::idle};
+    state current;
 };
 };
 
 
 /**
 /**
@@ -265,22 +300,29 @@ private:
  * @tparam Delta Type to use to provide elapsed time.
  * @tparam Delta Type to use to provide elapsed time.
  */
  */
 template<typename Func, typename Delta>
 template<typename Func, typename Delta>
-struct process_adaptor: process<Delta>, private Func {
+struct process_adaptor: public process<Delta>, private Func {
+    /*! @brief Process constructor token. */
+    using token_type = typename process<Delta>::token_type;
+    /*! @brief Type used to provide elapsed time. */
+    using delta_type = typename process<Delta>::delta_type;
+
     /**
     /**
      * @brief Constructs a process adaptor from a lambda or a functor.
      * @brief Constructs a process adaptor from a lambda or a functor.
      * @tparam Args Types of arguments to use to initialize the actual process.
      * @tparam Args Types of arguments to use to initialize the actual process.
+     * @param token Process constructor token.
      * @param args Parameters to use to initialize the actual process.
      * @param args Parameters to use to initialize the actual process.
      */
      */
     template<typename... Args>
     template<typename... Args>
-    process_adaptor(Args &&...args)
-        : Func{std::forward<Args>(args)...} {}
+    process_adaptor(const token_type token, Args &&...args)
+        : process<Delta>{token},
+          Func{std::forward<Args>(args)...} {}
 
 
     /**
     /**
      * @brief Updates a process and its internal state if required.
      * @brief Updates a process and its internal state if required.
      * @param delta Elapsed time.
      * @param delta Elapsed time.
      * @param data Optional data.
      * @param data Optional data.
      */
      */
-    void update(const Delta delta, void *data) override {
+    void update(const delta_type delta, void *data) override {
         Func::operator()(
         Func::operator()(
             delta,
             delta,
             data,
             data,

+ 2 - 2
src/entt/process/scheduler.hpp

@@ -202,7 +202,7 @@ public:
     template<typename Proc, typename... Args>
     template<typename Proc, typename... Args>
     basic_scheduler &attach(Args &&...args) {
     basic_scheduler &attach(Args &&...args) {
         static_assert(std::is_base_of_v<process<Delta>, Proc>, "Invalid process type");
         static_assert(std::is_base_of_v<process<Delta>, Proc>, "Invalid process type");
-        handlers.first().emplace_back().task = std::allocate_shared<Proc>(handlers.second(), std::forward<Args>(args)...);
+        handlers.first().emplace_back().task = process<Delta>::create_with_allocator<Proc>(std::allocator_arg, handlers.second(), std::forward<Args>(args)...);
         return *this;
         return *this;
     }
     }
 
 
@@ -277,7 +277,7 @@ public:
         auto *curr = &handlers.first().back();
         auto *curr = &handlers.first().back();
         for(; curr->next; curr = curr->next.get()) {}
         for(; curr->next; curr = curr->next.get()) {}
         curr->next = std::allocate_shared<handler_type>(handlers.second());
         curr->next = std::allocate_shared<handler_type>(handlers.second());
-        curr->next->task = std::allocate_shared<Proc>(handlers.second(), std::forward<Args>(args)...);
+        curr->next->task = process<Delta>::create_with_allocator<Proc>(std::allocator_arg, handlers.second(), std::forward<Args>(args)...);
         return *this;
         return *this;
     }
     }
 
 

+ 121 - 120
test/entt/process/process.cpp

@@ -5,6 +5,8 @@
 
 
 template<typename Delta>
 template<typename Delta>
 class test_process: public entt::process<Delta> {
 class test_process: public entt::process<Delta> {
+    using entt::process<Delta>::process;
+
     void succeeded() override {
     void succeeded() override {
         succeeded_invoked = true;
         succeeded_invoked = true;
     }
     }
@@ -33,152 +35,152 @@ public:
 };
 };
 
 
 TEST(Process, Basics) {
 TEST(Process, Basics) {
-    test_process<int> process{};
+    auto process = entt::process<int>::create<test_process<int>>();
 
 
-    ASSERT_FALSE(process.alive());
-    ASSERT_FALSE(process.finished());
-    ASSERT_FALSE(process.paused());
-    ASSERT_FALSE(process.rejected());
+    ASSERT_FALSE(process->alive());
+    ASSERT_FALSE(process->finished());
+    ASSERT_FALSE(process->paused());
+    ASSERT_FALSE(process->rejected());
 
 
-    process.succeed();
-    process.fail();
-    process.abort();
-    process.pause();
-    process.unpause();
+    process->succeed();
+    process->fail();
+    process->abort();
+    process->pause();
+    process->unpause();
 
 
-    ASSERT_FALSE(process.alive());
-    ASSERT_FALSE(process.finished());
-    ASSERT_FALSE(process.paused());
-    ASSERT_FALSE(process.rejected());
+    ASSERT_FALSE(process->alive());
+    ASSERT_FALSE(process->finished());
+    ASSERT_FALSE(process->paused());
+    ASSERT_FALSE(process->rejected());
 
 
-    process.tick(0);
+    process->tick(0);
 
 
-    ASSERT_TRUE(process.alive());
-    ASSERT_FALSE(process.finished());
-    ASSERT_FALSE(process.paused());
-    ASSERT_FALSE(process.rejected());
+    ASSERT_TRUE(process->alive());
+    ASSERT_FALSE(process->finished());
+    ASSERT_FALSE(process->paused());
+    ASSERT_FALSE(process->rejected());
 
 
-    process.pause();
+    process->pause();
 
 
-    ASSERT_TRUE(process.alive());
-    ASSERT_FALSE(process.finished());
-    ASSERT_TRUE(process.paused());
-    ASSERT_FALSE(process.rejected());
+    ASSERT_TRUE(process->alive());
+    ASSERT_FALSE(process->finished());
+    ASSERT_TRUE(process->paused());
+    ASSERT_FALSE(process->rejected());
 
 
-    process.unpause();
+    process->unpause();
 
 
-    ASSERT_TRUE(process.alive());
-    ASSERT_FALSE(process.finished());
-    ASSERT_FALSE(process.paused());
-    ASSERT_FALSE(process.rejected());
+    ASSERT_TRUE(process->alive());
+    ASSERT_FALSE(process->finished());
+    ASSERT_FALSE(process->paused());
+    ASSERT_FALSE(process->rejected());
 
 
-    process.fail();
+    process->fail();
 
 
-    ASSERT_FALSE(process.alive());
-    ASSERT_FALSE(process.finished());
-    ASSERT_FALSE(process.paused());
-    ASSERT_FALSE(process.rejected());
+    ASSERT_FALSE(process->alive());
+    ASSERT_FALSE(process->finished());
+    ASSERT_FALSE(process->paused());
+    ASSERT_FALSE(process->rejected());
 
 
-    process.tick(0);
+    process->tick(0);
 
 
-    ASSERT_FALSE(process.alive());
-    ASSERT_FALSE(process.finished());
-    ASSERT_FALSE(process.paused());
-    ASSERT_TRUE(process.rejected());
+    ASSERT_FALSE(process->alive());
+    ASSERT_FALSE(process->finished());
+    ASSERT_FALSE(process->paused());
+    ASSERT_TRUE(process->rejected());
 }
 }
 
 
 TEST(Process, Succeeded) {
 TEST(Process, Succeeded) {
-    test_process<test::empty> process{};
-
-    process.tick({});
-    process.tick({});
-    process.succeed();
-    process.tick({});
-
-    ASSERT_FALSE(process.alive());
-    ASSERT_TRUE(process.finished());
-    ASSERT_FALSE(process.paused());
-    ASSERT_FALSE(process.rejected());
-
-    ASSERT_TRUE(process.update_invoked);
-    ASSERT_TRUE(process.succeeded_invoked);
-    ASSERT_FALSE(process.failed_invoked);
-    ASSERT_FALSE(process.aborted_invoked);
+    auto process = entt::process<test::empty>::create<test_process<test::empty>>();
+
+    process->tick({});
+    process->tick({});
+    process->succeed();
+    process->tick({});
+
+    ASSERT_FALSE(process->alive());
+    ASSERT_TRUE(process->finished());
+    ASSERT_FALSE(process->paused());
+    ASSERT_FALSE(process->rejected());
+
+    ASSERT_TRUE(process->update_invoked);
+    ASSERT_TRUE(process->succeeded_invoked);
+    ASSERT_FALSE(process->failed_invoked);
+    ASSERT_FALSE(process->aborted_invoked);
 }
 }
 
 
 TEST(Process, Fail) {
 TEST(Process, Fail) {
-    test_process<int> process{};
-
-    process.tick(0);
-    process.tick(0);
-    process.fail();
-    process.tick(0);
-
-    ASSERT_FALSE(process.alive());
-    ASSERT_FALSE(process.finished());
-    ASSERT_FALSE(process.paused());
-    ASSERT_TRUE(process.rejected());
-
-    ASSERT_TRUE(process.update_invoked);
-    ASSERT_FALSE(process.succeeded_invoked);
-    ASSERT_TRUE(process.failed_invoked);
-    ASSERT_FALSE(process.aborted_invoked);
+    auto process = entt::process<int>::create<test_process<int>>();
+
+    process->tick(0);
+    process->tick(0);
+    process->fail();
+    process->tick(0);
+
+    ASSERT_FALSE(process->alive());
+    ASSERT_FALSE(process->finished());
+    ASSERT_FALSE(process->paused());
+    ASSERT_TRUE(process->rejected());
+
+    ASSERT_TRUE(process->update_invoked);
+    ASSERT_FALSE(process->succeeded_invoked);
+    ASSERT_TRUE(process->failed_invoked);
+    ASSERT_FALSE(process->aborted_invoked);
 }
 }
 
 
 TEST(Process, Data) {
 TEST(Process, Data) {
-    test_process<test::empty> process{};
+    auto process = entt::process<test::empty>::create<test_process<test::empty>>();
     int value = 0;
     int value = 0;
 
 
-    process.tick({});
-    process.tick({}, &value);
-    process.succeed();
-    process.tick({}, &value);
+    process->tick({});
+    process->tick({}, &value);
+    process->succeed();
+    process->tick({}, &value);
 
 
-    ASSERT_FALSE(process.alive());
-    ASSERT_TRUE(process.finished());
-    ASSERT_FALSE(process.paused());
-    ASSERT_FALSE(process.rejected());
+    ASSERT_FALSE(process->alive());
+    ASSERT_TRUE(process->finished());
+    ASSERT_FALSE(process->paused());
+    ASSERT_FALSE(process->rejected());
 
 
     ASSERT_EQ(value, 1);
     ASSERT_EQ(value, 1);
-    ASSERT_TRUE(process.update_invoked);
-    ASSERT_TRUE(process.succeeded_invoked);
-    ASSERT_FALSE(process.failed_invoked);
-    ASSERT_FALSE(process.aborted_invoked);
+    ASSERT_TRUE(process->update_invoked);
+    ASSERT_TRUE(process->succeeded_invoked);
+    ASSERT_FALSE(process->failed_invoked);
+    ASSERT_FALSE(process->aborted_invoked);
 }
 }
 
 
 TEST(Process, AbortNextTick) {
 TEST(Process, AbortNextTick) {
-    test_process<int> process{};
+    auto process = entt::process<int>::create<test_process<int>>();
 
 
-    process.tick(0);
-    process.abort();
-    process.tick(0);
+    process->tick(0);
+    process->abort();
+    process->tick(0);
 
 
-    ASSERT_FALSE(process.alive());
-    ASSERT_FALSE(process.finished());
-    ASSERT_FALSE(process.paused());
-    ASSERT_TRUE(process.rejected());
+    ASSERT_FALSE(process->alive());
+    ASSERT_FALSE(process->finished());
+    ASSERT_FALSE(process->paused());
+    ASSERT_TRUE(process->rejected());
 
 
-    ASSERT_TRUE(process.update_invoked);
-    ASSERT_FALSE(process.succeeded_invoked);
-    ASSERT_FALSE(process.failed_invoked);
-    ASSERT_TRUE(process.aborted_invoked);
+    ASSERT_TRUE(process->update_invoked);
+    ASSERT_FALSE(process->succeeded_invoked);
+    ASSERT_FALSE(process->failed_invoked);
+    ASSERT_TRUE(process->aborted_invoked);
 }
 }
 
 
 TEST(Process, AbortImmediately) {
 TEST(Process, AbortImmediately) {
-    test_process<test::empty> process{};
+    auto process = entt::process<test::empty>::create<test_process<test::empty>>();
 
 
-    process.tick({});
-    process.abort(true);
+    process->tick({});
+    process->abort(true);
 
 
-    ASSERT_FALSE(process.alive());
-    ASSERT_FALSE(process.finished());
-    ASSERT_FALSE(process.paused());
-    ASSERT_TRUE(process.rejected());
+    ASSERT_FALSE(process->alive());
+    ASSERT_FALSE(process->finished());
+    ASSERT_FALSE(process->paused());
+    ASSERT_TRUE(process->rejected());
 
 
-    ASSERT_TRUE(process.update_invoked);
-    ASSERT_FALSE(process.succeeded_invoked);
-    ASSERT_FALSE(process.failed_invoked);
-    ASSERT_TRUE(process.aborted_invoked);
+    ASSERT_TRUE(process->update_invoked);
+    ASSERT_FALSE(process->succeeded_invoked);
+    ASSERT_FALSE(process->failed_invoked);
+    ASSERT_TRUE(process->aborted_invoked);
 }
 }
 
 
 TEST(ProcessAdaptor, Resolved) {
 TEST(ProcessAdaptor, Resolved) {
@@ -189,12 +191,12 @@ TEST(ProcessAdaptor, Resolved) {
         resolve();
         resolve();
     };
     };
 
 
-    auto process = entt::process_adaptor<decltype(lambda), std::uint64_t>{lambda};
+    auto process = entt::process<std::uint64_t>::create<entt::process_adaptor<decltype(lambda), std::uint64_t>>(lambda);
 
 
-    process.tick(0);
-    process.tick(0);
+    process->tick(0);
+    process->tick(0);
 
 
-    ASSERT_TRUE(process.finished());
+    ASSERT_TRUE(process->finished());
     ASSERT_TRUE(updated);
     ASSERT_TRUE(updated);
 }
 }
 
 
@@ -206,27 +208,26 @@ TEST(ProcessAdaptor, Rejected) {
         rejected();
         rejected();
     };
     };
 
 
-    auto process = entt::process_adaptor<decltype(lambda), std::uint64_t>{lambda};
+    auto process = entt::process<std::uint64_t>::create<entt::process_adaptor<decltype(lambda), std::uint64_t>>(lambda);
 
 
-    process.tick(0);
-    process.tick(0);
+    process->tick(0);
+    process->tick(0);
 
 
-    ASSERT_TRUE(process.rejected());
+    ASSERT_TRUE(process->rejected());
     ASSERT_TRUE(updated);
     ASSERT_TRUE(updated);
 }
 }
 
 
 TEST(ProcessAdaptor, Data) {
 TEST(ProcessAdaptor, Data) {
     int value = 0;
     int value = 0;
-
     auto lambda = [](std::uint64_t, void *data, auto resolve, auto) {
     auto lambda = [](std::uint64_t, void *data, auto resolve, auto) {
         *static_cast<int *>(data) = 2;
         *static_cast<int *>(data) = 2;
         resolve();
         resolve();
     };
     };
 
 
-    auto process = entt::process_adaptor<decltype(lambda), std::uint64_t>{lambda};
+    auto process = entt::process<std::uint64_t>::create<entt::process_adaptor<decltype(lambda), std::uint64_t>>(lambda);
 
 
-    process.tick(0, &value);
+    process->tick(0, &value);
 
 
-    ASSERT_TRUE(process.finished());
+    ASSERT_TRUE(process->finished());
     ASSERT_EQ(value, 2);
     ASSERT_EQ(value, 2);
-}
+}

+ 13 - 2
test/entt/process/scheduler.cpp

@@ -6,6 +6,9 @@
 #include <entt/process/scheduler.hpp>
 #include <entt/process/scheduler.hpp>
 
 
 class foo_process: public entt::process<entt::scheduler::delta_type> {
 class foo_process: public entt::process<entt::scheduler::delta_type> {
+    using base_type = entt::process<entt::scheduler::delta_type>;
+    using token_type = typename base_type::token_type;
+
     void update(const delta_type, void *) override {
     void update(const delta_type, void *) override {
         on_update();
         on_update();
     }
     }
@@ -15,8 +18,10 @@ class foo_process: public entt::process<entt::scheduler::delta_type> {
     }
     }
 
 
 public:
 public:
-    foo_process(std::function<void()> upd, std::function<void()> abort)
-        : on_update{std::move(upd)}, on_aborted{std::move(abort)} {}
+    foo_process(const token_type token, std::function<void()> upd, std::function<void()> abort)
+        : base_type{token},
+          on_update{std::move(upd)},
+          on_aborted{std::move(abort)} {}
 
 
 private:
 private:
     std::function<void()> on_update;
     std::function<void()> on_update;
@@ -28,6 +33,9 @@ class succeeded_process: public entt::process<entt::scheduler::delta_type> {
         ++static_cast<std::pair<int, int> *>(data)->first;
         ++static_cast<std::pair<int, int> *>(data)->first;
         succeed();
         succeed();
     }
     }
+
+public:
+    using entt::process<entt::scheduler::delta_type>::process;
 };
 };
 
 
 class failed_process: public entt::process<entt::scheduler::delta_type> {
 class failed_process: public entt::process<entt::scheduler::delta_type> {
@@ -35,6 +43,9 @@ class failed_process: public entt::process<entt::scheduler::delta_type> {
         ++static_cast<std::pair<int, int> *>(data)->second;
         ++static_cast<std::pair<int, int> *>(data)->second;
         fail();
         fail();
     }
     }
+
+public:
+    using entt::process<entt::scheduler::delta_type>::process;
 };
 };
 
 
 TEST(Scheduler, Functionalities) {
 TEST(Scheduler, Functionalities) {