scheduler: review internals to use peek/release/whatever - see #1257

This commit is contained in:
skypjack
2025-06-27 11:27:12 +02:00
parent 01e12fa011
commit 3126b3efbf
+24 -45
View File
@@ -13,19 +13,6 @@
namespace entt {
/*! @cond TURN_OFF_DOXYGEN */
namespace internal {
template<typename Type>
struct process_handler {
// std::shared_ptr because of its type erased allocator which is useful here
std::shared_ptr<process_handler> next{};
std::shared_ptr<Type> task{};
};
} // namespace internal
/*! @endcond */
/**
* @brief Cooperative scheduler for processes.
*
@@ -55,23 +42,9 @@ struct process_handler {
*/
template<typename Delta, typename Allocator>
class basic_scheduler {
using process_type = basic_process<Delta>;
using alloc_traits = std::allocator_traits<Allocator>;
using handler_type = internal::process_handler<process_type>;
using container_allocator = typename alloc_traits::template rebind_alloc<handler_type>;
using container_type = std::vector<handler_type, container_allocator>;
bool update(const std::size_t pos, const Delta delta, void *data) {
handlers.first()[pos].task->tick(delta, data);
// callbacks can insert or erase tasks, invalidating the reference
auto &elem = handlers.first()[pos];
if(elem.task->rejected()) {
elem.next.reset();
}
return (elem.task->rejected() || elem.task->finished());
}
using container_allocator = typename alloc_traits::template rebind_alloc<std::shared_ptr<basic_process<Delta>>>;
using container_type = std::vector<std::shared_ptr<basic_process<Delta>>, container_allocator>;
public:
/*! @brief Allocator type. */
@@ -202,7 +175,7 @@ public:
*/
template<typename Proc, typename... Args>
basic_scheduler &attach(Args &&...args) {
handlers.first().emplace_back().task = std::allocate_shared<Proc>(handlers.second(), std::forward<Args>(args)...);
handlers.first().emplace_back(std::allocate_shared<Proc>(handlers.second(), std::forward<Args>(args)...));
return *this;
}
@@ -273,10 +246,13 @@ public:
template<typename Proc, typename... Args>
basic_scheduler &then(Args &&...args) {
ENTT_ASSERT(!handlers.first().empty(), "Process not available");
auto *curr = &handlers.first().back();
for(; curr->next; curr = curr->next.get()) {}
curr->next = std::allocate_shared<handler_type>(handlers.second());
curr->next->task = std::allocate_shared<Proc>(handlers.second(), std::forward<Args>(args)...);
auto curr = handlers.first().back();
for(auto child = curr->peek(); child; child = curr->peek()) {
curr = child;
}
curr->then(std::allocate_shared<Proc>(handlers.second(), std::forward<Args>(args)...));
return *this;
}
@@ -305,15 +281,18 @@ public:
*/
void update(const delta_type delta, void *data = nullptr) {
for(auto next = handlers.first().size(); next; --next) {
if(const auto pos = next - 1u; update(pos, delta, data)) {
// updating might spawn/reallocate, cannot hold refs until here
if(auto &curr = handlers.first()[pos]; curr.next) {
auto elem = curr.next;
curr = std::move(*elem);
} else {
curr = std::move(handlers.first().back());
handlers.first().pop_back();
}
const auto pos = next - 1u;
handlers.first()[pos]->tick(delta, data);
// updating might spawn/reallocate, cannot hold refs until here
auto &elem = handlers.first()[pos];
if(elem->finished()) {
elem = std::move(elem->release());
}
if(!elem || elem->rejected()) {
elem = std::move(handlers.first().back());
handlers.first().pop_back();
}
}
}
@@ -330,10 +309,10 @@ public:
*/
void abort(const bool immediate = false) {
for(auto &&curr: handlers.first()) {
curr.task->abort();
curr->abort();
if(immediate) {
curr.task->tick({});
curr->tick({});
}
}
}