mirror of
https://github.com/zhenyan121/Cubed.git
synced 2026-08-08 17:57:02 +08:00
build: add EnTT library
This commit is contained in:
316
include/entt/process/process.hpp
Normal file
316
include/entt/process/process.hpp
Normal file
@@ -0,0 +1,316 @@
|
||||
#ifndef ENTT_PROCESS_PROCESS_HPP
|
||||
#define ENTT_PROCESS_PROCESS_HPP
|
||||
|
||||
#include "../core/compressed_pair.hpp"
|
||||
#include "../core/type_traits.hpp"
|
||||
#include "../stl/cstdint.hpp"
|
||||
#include "../stl/memory.hpp"
|
||||
#include "../stl/type_traits.hpp"
|
||||
#include "../stl/utility.hpp"
|
||||
#include "fwd.hpp"
|
||||
|
||||
namespace entt {
|
||||
|
||||
/*! @cond ENTT_INTERNAL */
|
||||
namespace internal {
|
||||
|
||||
template<typename, typename, typename>
|
||||
struct process_adaptor;
|
||||
|
||||
} // namespace internal
|
||||
/*! @endcond */
|
||||
|
||||
/**
|
||||
* @brief Base class for processes.
|
||||
*
|
||||
* Derived classes must specify what's the intended type for elapsed times.<br/>
|
||||
* A process can implement the following member functions whether required:
|
||||
*
|
||||
* * @code{.cpp}
|
||||
* void update(Delta, void *) override;
|
||||
* @endcode
|
||||
*
|
||||
* It's invoked once per tick until a process is explicitly aborted or it
|
||||
* terminates either with or without errors. Even though it's not mandatory to
|
||||
* declare this member function, as a rule of thumb each process should at
|
||||
* least define it to work properly. The `void *` parameter is an opaque
|
||||
* pointer to user data (if any) forwarded directly to the process during an
|
||||
* update.
|
||||
*
|
||||
* * @code{.cpp}
|
||||
* void succeeded() override;
|
||||
* @endcode
|
||||
*
|
||||
* It's invoked in case of success, immediately after an update and during the
|
||||
* same tick.
|
||||
*
|
||||
* * @code{.cpp}
|
||||
* void failed() override;
|
||||
* @endcode
|
||||
*
|
||||
* It's invoked in case of errors, immediately after an update and during the
|
||||
* same tick.
|
||||
*
|
||||
* * @code{.cpp}
|
||||
* void aborted() override;
|
||||
* @endcode
|
||||
*
|
||||
* It's invoked only if a process is explicitly aborted. There is no guarantee
|
||||
* that it executes in the same tick, this depends solely on whether the
|
||||
* process is aborted immediately or not.
|
||||
*
|
||||
* Derived classes can change the internal state of a process by invoking the
|
||||
* `succeed` and `fail` member functions and even pause or unpause the process
|
||||
* itself.
|
||||
*
|
||||
* @sa scheduler
|
||||
*
|
||||
* @tparam Delta Type to use to provide elapsed time.
|
||||
* @tparam Allocator Type of allocator used to manage memory and elements.
|
||||
*/
|
||||
template<typename Delta, typename Allocator>
|
||||
class basic_process: public stl::enable_shared_from_this<basic_process<Delta, Allocator>> {
|
||||
enum class state : stl::uint8_t {
|
||||
idle = 0,
|
||||
running,
|
||||
paused,
|
||||
succeeded,
|
||||
failed,
|
||||
aborted,
|
||||
finished,
|
||||
rejected
|
||||
};
|
||||
|
||||
virtual void update(const Delta, void *) {
|
||||
abort();
|
||||
}
|
||||
|
||||
virtual void succeeded() {}
|
||||
virtual void failed() {}
|
||||
virtual void aborted() {}
|
||||
|
||||
public:
|
||||
/*! @brief Allocator type. */
|
||||
using allocator_type = Allocator;
|
||||
/*! @brief Type used to provide elapsed time. */
|
||||
using delta_type = Delta;
|
||||
/*! @brief Handle type. */
|
||||
using handle_type = stl::shared_ptr<basic_process>;
|
||||
|
||||
/*! @brief Default constructor. */
|
||||
basic_process()
|
||||
: basic_process{allocator_type{}} {}
|
||||
|
||||
/**
|
||||
* @brief Constructs a scheduler with a given allocator.
|
||||
* @param allocator The allocator to use.
|
||||
*/
|
||||
explicit basic_process(const allocator_type &allocator)
|
||||
: next{nullptr, allocator},
|
||||
current{state::idle} {}
|
||||
|
||||
/*! @brief Default copy constructor, deleted on purpose. */
|
||||
basic_process(const basic_process &) = delete;
|
||||
|
||||
/*! @brief Default move constructor, deleted on purpose. */
|
||||
basic_process(basic_process &&) = delete;
|
||||
|
||||
/*! @brief Default destructor. */
|
||||
virtual ~basic_process() = default;
|
||||
|
||||
/**
|
||||
* @brief Default copy assignment operator, deleted on purpose.
|
||||
* @return This process scheduler.
|
||||
*/
|
||||
basic_process &operator=(const basic_process &) = delete;
|
||||
|
||||
/**
|
||||
* @brief Default move assignment operator, deleted on purpose.
|
||||
* @return This process scheduler.
|
||||
*/
|
||||
basic_process &operator=(basic_process &&) = delete;
|
||||
|
||||
/**
|
||||
* @brief Returns the associated allocator.
|
||||
* @return The associated allocator.
|
||||
*/
|
||||
[[nodiscard]] constexpr allocator_type get_allocator() const noexcept {
|
||||
return next.second();
|
||||
}
|
||||
|
||||
/*! @brief Aborts a process if it's still alive, otherwise does nothing. */
|
||||
void abort() {
|
||||
if(alive()) {
|
||||
current = state::aborted;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Terminates a process with success if it's still alive, otherwise
|
||||
* does nothing.
|
||||
*/
|
||||
void succeed() noexcept {
|
||||
if(alive()) {
|
||||
current = state::succeeded;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Terminates a process with errors if it's still alive, otherwise
|
||||
* does nothing.
|
||||
*/
|
||||
void fail() noexcept {
|
||||
if(alive()) {
|
||||
current = state::failed;
|
||||
}
|
||||
}
|
||||
|
||||
/*! @brief Stops a process if it's running, otherwise does nothing. */
|
||||
void pause() noexcept {
|
||||
if(alive()) {
|
||||
current = state::paused;
|
||||
}
|
||||
}
|
||||
|
||||
/*! @brief Restarts a process if it's paused, otherwise does nothing. */
|
||||
void unpause() noexcept {
|
||||
if(alive()) {
|
||||
current = state::running;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns true if a process is either running or paused.
|
||||
* @return True if the process is still alive, false otherwise.
|
||||
*/
|
||||
[[nodiscard]] bool alive() const noexcept {
|
||||
return current == state::running || current == state::paused;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns true if a process is already terminated.
|
||||
* @return True if the process is terminated, false otherwise.
|
||||
*/
|
||||
[[nodiscard]] bool finished() const noexcept {
|
||||
return current == state::finished;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns true if a process is currently paused.
|
||||
* @return True if the process is paused, false otherwise.
|
||||
*/
|
||||
[[nodiscard]] bool paused() const noexcept {
|
||||
return current == state::paused;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns true if a process terminated with errors.
|
||||
* @return True if the process terminated with errors, false otherwise.
|
||||
*/
|
||||
[[nodiscard]] bool rejected() const noexcept {
|
||||
return current == state::rejected;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Assigns a child process to run in case of success.
|
||||
* @tparam Type Type of child process to create.
|
||||
* @tparam Args Types of arguments to use to initialize the child process.
|
||||
* @param args Parameters to use to initialize the child process.
|
||||
* @return A reference to the newly created child process.
|
||||
*/
|
||||
template<typename Type, typename... Args>
|
||||
basic_process &then(Args &&...args) {
|
||||
const auto &allocator = next.second();
|
||||
return *(next.first() = stl::allocate_shared<Type>(allocator, allocator, stl::forward<Args>(args)...));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Assigns a child process to run in case of success.
|
||||
* @tparam Func Type of child process to create.
|
||||
* @param func Either a lambda or a functor to use as a child process.
|
||||
* @return A reference to the newly created child process.
|
||||
*/
|
||||
template<typename Func>
|
||||
basic_process &then(Func func) {
|
||||
const auto &allocator = next.second();
|
||||
using process_type = internal::process_adaptor<delta_type, Func, allocator_type>;
|
||||
return *(next.first() = stl::allocate_shared<process_type>(allocator, allocator, stl::move(func)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the child process without releasing ownership, if any.
|
||||
* @return The child process attached to the object, if any.
|
||||
*/
|
||||
handle_type peek() {
|
||||
return next.first();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Updates a process and its internal state, if required.
|
||||
* @param delta Elapsed time.
|
||||
* @param data Optional data.
|
||||
*/
|
||||
void tick(const Delta delta, void *data = nullptr) {
|
||||
switch(current) {
|
||||
case state::idle:
|
||||
case state::running:
|
||||
current = state::running;
|
||||
update(delta, data);
|
||||
break;
|
||||
default:
|
||||
// suppress warnings
|
||||
break;
|
||||
}
|
||||
|
||||
// if it's dead, it must be notified and removed immediately
|
||||
switch(current) {
|
||||
case state::succeeded:
|
||||
succeeded();
|
||||
current = state::finished;
|
||||
break;
|
||||
case state::failed:
|
||||
failed();
|
||||
current = state::rejected;
|
||||
break;
|
||||
case state::aborted:
|
||||
aborted();
|
||||
current = state::rejected;
|
||||
break;
|
||||
default:
|
||||
// suppress warnings
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
compressed_pair<handle_type, allocator_type> next;
|
||||
state current;
|
||||
};
|
||||
|
||||
/*! @cond ENTT_INTERNAL */
|
||||
namespace internal {
|
||||
|
||||
template<typename Delta, typename Func, typename Allocator>
|
||||
struct process_adaptor: public basic_process<Delta, Allocator> {
|
||||
using allocator_type = Allocator;
|
||||
using base_type = basic_process<Delta, Allocator>;
|
||||
using delta_type = base_type::delta_type;
|
||||
|
||||
process_adaptor(const allocator_type &allocator, Func proc)
|
||||
: base_type{allocator},
|
||||
func{stl::move(proc)} {}
|
||||
|
||||
void update(const delta_type delta, void *data) override {
|
||||
func(*this, delta, data);
|
||||
}
|
||||
|
||||
private:
|
||||
Func func;
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
/*! @endcond */
|
||||
|
||||
} // namespace entt
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user