diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 000000000..533fba78a --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "external/entt"] + path = external/entt + url = git://github.com/Unarelith/entt.git diff --git a/CMakeLists.txt b/CMakeLists.txt index 25af3a8be..d50dd9470 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -22,7 +22,7 @@ set(DEBUG_GCC_FLAGS -g -Og -Wall -Wextra -Wfatal-errors -Wno-variadic-macros) set(RELEASE_GCC_FLAGS -O3) set(RELWITHDEB_GCC_FLAGS -g -O3 -Wall -Wextra -Wfatal-errors -Wno-variadic-macros) -set(CMAKE_CXX_STANDARD 14) +set(CMAKE_CXX_STANDARD 17) #------------------------------------------------------------------------------ # Setting default build type @@ -185,6 +185,8 @@ endif () #------------------------------------------------------------------------------ # Subdirectories #------------------------------------------------------------------------------ +add_subdirectory(external/entt) + add_subdirectory(source/common) add_subdirectory(source/server) add_subdirectory(source/client) diff --git a/README.md b/README.md index 6ad6d64d7..1adfa8eb1 100644 --- a/README.md +++ b/README.md @@ -69,6 +69,7 @@ The long-term goal of this project is to provide a viable alternative to Minecra - [SFML](https://www.sfml-dev.org/) (only used for network) - [Lua](http://www.lua.org) - _Linux users: Check your distribution repositories for packages._ +- Run `git submodule update --init --recursive` - Run `cmake .` - Run `make -j8` - Run the client with `./openminer` diff --git a/external/entt b/external/entt new file mode 160000 index 000000000..76707f0c1 --- /dev/null +++ b/external/entt @@ -0,0 +1 @@ +Subproject commit 76707f0c1a73bf5918c56ffd860c3b83b6a9d120 diff --git a/external/entt/config/config.h b/external/entt/config/config.h deleted file mode 100644 index 367798c01..000000000 --- a/external/entt/config/config.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef ENTT_CONFIG_CONFIG_H -#define ENTT_CONFIG_CONFIG_H - - -#ifndef ENTT_NOEXCEPT -#define ENTT_NOEXCEPT noexcept -#endif // ENTT_NOEXCEPT - - -#ifndef ENTT_HS_SUFFIX -#define ENTT_HS_SUFFIX _hs -#endif // ENTT_HS_SUFFIX - - - -#endif // ENTT_CONFIG_CONFIG_H diff --git a/external/entt/core/algorithm.hpp b/external/entt/core/algorithm.hpp deleted file mode 100644 index 9ac0a9068..000000000 --- a/external/entt/core/algorithm.hpp +++ /dev/null @@ -1,111 +0,0 @@ -#ifndef ENTT_CORE_ALGORITHM_HPP -#define ENTT_CORE_ALGORITHM_HPP - - -#include -#include -#include - - -namespace entt { - - -/** - * @brief Function object to wrap `std::sort` in a class type. - * - * Unfortunately, `std::sort` cannot be passed as template argument to a class - * template or a function template.
- * This class fills the gap by wrapping some flavors of `std::sort` in a - * function object. - */ -struct StdSort final { - /** - * @brief Sorts the elements in a range. - * - * Sorts the elements in a range using the given binary comparison function. - * - * @tparam It Type of random access iterator. - * @tparam Compare Type of comparison function object. - * @tparam Args Types of arguments to forward to the sort function. - * @param first An iterator to the first element of the range to sort. - * @param last An iterator past the last element of the range to sort. - * @param compare A valid comparison function object. - * @param args Arguments to forward to the sort function, if any. - */ - template, typename... Args> - void operator()(It first, It last, Compare compare = Compare{}, Args &&... args) const { - std::sort(std::forward(args)..., std::move(first), std::move(last), std::move(compare)); - } -}; - - -/*! @brief Function object for performing insertion sort. */ -struct InsertionSort final { - /** - * @brief Sorts the elements in a range. - * - * Sorts the elements in a range using the given binary comparison function. - * - * @tparam It Type of random access iterator. - * @tparam Compare Type of comparison function object. - * @param first An iterator to the first element of the range to sort. - * @param last An iterator past the last element of the range to sort. - * @param compare A valid comparison function object. - */ - template> - void operator()(It first, It last, Compare compare = Compare{}) const { - auto it = first + 1; - - while(it != last) { - auto value = *it; - auto pre = it; - - while(pre != first && compare(value, *(pre-1))) { - *pre = *(pre-1); - --pre; - } - - *pre = value; - ++it; - } - } -}; - - -/*! @brief Function object for performing bubble sort (single iteration). */ -struct OneShotBubbleSort final { - /** - * @brief Tries to sort the elements in a range. - * - * Performs a single iteration to sort the elements in a range using the - * given binary comparison function. The range may not be completely sorted - * after running this function. - * - * @tparam It Type of random access iterator. - * @tparam Compare Type of comparison function object. - * @param first An iterator to the first element of the range to sort. - * @param last An iterator past the last element of the range to sort. - * @param compare A valid comparison function object. - */ - template> - void operator()(It first, It last, Compare compare = Compare{}) const { - if(first != last) { - auto it = first++; - - while(first != last) { - if(compare(*first, *it)) { - using std::swap; - std::swap(*first, *it); - } - - it = first++; - } - } - } -}; - - -} - - -#endif // ENTT_CORE_ALGORITHM_HPP diff --git a/external/entt/core/family.hpp b/external/entt/core/family.hpp deleted file mode 100644 index 11cf82f99..000000000 --- a/external/entt/core/family.hpp +++ /dev/null @@ -1,53 +0,0 @@ -#ifndef ENTT_CORE_FAMILY_HPP -#define ENTT_CORE_FAMILY_HPP - - -#include -#include -#include -#include "../config/config.h" - - -namespace entt { - - -/** - * @brief Dynamic identifier generator. - * - * Utility class template that can be used to assign unique identifiers to types - * at runtime. Use different specializations to create separate sets of - * identifiers. - */ -template -class Family { - static std::atomic identifier; - - template - static std::size_t family() ENTT_NOEXCEPT { - static const std::size_t value = identifier.fetch_add(1); - return value; - } - -public: - /*! @brief Unsigned integer type. */ - using family_type = std::size_t; - - /** - * @brief Returns an unique identifier for the given type. - * @return Statically generated unique identifier for the given type. - */ - template - inline static family_type type() ENTT_NOEXCEPT { - return family...>(); - } -}; - - -template -std::atomic Family::identifier{}; - - -} - - -#endif // ENTT_CORE_FAMILY_HPP diff --git a/external/entt/core/hashed_string.hpp b/external/entt/core/hashed_string.hpp deleted file mode 100644 index bea5db0ab..000000000 --- a/external/entt/core/hashed_string.hpp +++ /dev/null @@ -1,121 +0,0 @@ -#ifndef ENTT_CORE_HASHED_STRING_HPP -#define ENTT_CORE_HASHED_STRING_HPP - - -#include -#include -#include "../config/config.h" - - -namespace entt { - - -/** - * @brief Zero overhead resource identifier. - * - * A hashed string is a compile-time tool that allows users to use - * human-readable identifers in the codebase while using their numeric - * counterparts at runtime.
- * Because of that, a hashed string can also be used in constant expressions if - * required. - */ -class HashedString final { - struct ConstCharWrapper final { - // non-explicit constructor on purpose - constexpr ConstCharWrapper(const char *str) ENTT_NOEXCEPT: str{str} {} - const char *str; - }; - - static constexpr std::uint64_t offset = 14695981039346656037ull; - static constexpr std::uint64_t prime = 1099511628211ull; - - // Fowler–Noll–Vo hash function v. 1a - the good - static constexpr std::uint64_t helper(std::uint64_t partial, const char *str) ENTT_NOEXCEPT { - return str[0] == 0 ? partial : helper((partial^str[0])*prime, str+1); - } - -public: - /*! @brief Unsigned integer type. */ - using hash_type = std::uint64_t; - - /** - * @brief Constructs a hashed string from an array of const chars. - * - * Forcing template resolution avoids implicit conversions. An - * human-readable identifier can be anything but a plain, old bunch of - * characters.
- * Example of use: - * @code{.cpp} - * HashedString sh{"my.png"}; - * @endcode - * - * @tparam N Number of characters of the identifier. - * @param str Human-readable identifer. - */ - template - constexpr HashedString(const char (&str)[N]) ENTT_NOEXCEPT - : hash{helper(offset, str)}, str{str} - {} - - /** - * @brief Explicit constructor on purpose to avoid constructing a hashed - * string directly from a `const char *`. - * - * @param wrapper Helps achieving the purpose by relying on overloading. - */ - explicit constexpr HashedString(ConstCharWrapper wrapper) ENTT_NOEXCEPT - : hash{helper(offset, wrapper.str)}, str{wrapper.str} - {} - - /** - * @brief Returns the human-readable representation of a hashed string. - * @return The string used to initialize the instance. - */ - constexpr operator const char *() const ENTT_NOEXCEPT { return str; } - - /** - * @brief Returns the numeric representation of a hashed string. - * @return The numeric representation of the instance. - */ - constexpr operator hash_type() const ENTT_NOEXCEPT { return hash; } - - /** - * @brief Compares two hashed strings. - * @param other Hashed string with which to compare. - * @return True if the two hashed strings are identical, false otherwise. - */ - constexpr bool operator==(const HashedString &other) const ENTT_NOEXCEPT { - return hash == other.hash; - } - -private: - const hash_type hash; - const char *str; -}; - - -/** - * @brief Compares two hashed strings. - * @param lhs A valid hashed string. - * @param rhs A valid hashed string. - * @return True if the two hashed strings are identical, false otherwise. - */ -constexpr bool operator!=(const HashedString &lhs, const HashedString &rhs) ENTT_NOEXCEPT { - return !(lhs == rhs); -} - - -} - - -/** - * @brief User defined literal for hashed strings. - * @param str The literal without its suffix. - * @return A properly initialized hashed string. - */ -constexpr entt::HashedString operator"" ENTT_HS_SUFFIX(const char *str, std::size_t) ENTT_NOEXCEPT { - return entt::HashedString{str}; -} - - -#endif // ENTT_CORE_HASHED_STRING_HPP diff --git a/external/entt/core/ident.hpp b/external/entt/core/ident.hpp deleted file mode 100644 index 42503d876..000000000 --- a/external/entt/core/ident.hpp +++ /dev/null @@ -1,104 +0,0 @@ -#ifndef ENTT_CORE_IDENT_HPP -#define ENTT_CORE_IDENT_HPP - - -#include -#include -#include -#include -#include "../config/config.h" - - -namespace entt { - - -/** - * @cond TURN_OFF_DOXYGEN - * Internal details not to be documented. - */ - - -namespace internal { - - -template -struct IsPartOf; - -template -struct IsPartOf: std::conditional_t::value, std::true_type, IsPartOf> {}; - -template -struct IsPartOf: std::false_type {}; - - -} - - -/** - * Internal details not to be documented. - * @endcond TURN_OFF_DOXYGEN - */ - - -/** - * @brief Types identifiers. - * - * Variable template used to generate identifiers at compile-time for the given - * types. Use the `get` member function to know what's the identifier associated - * to the specific type. - * - * @note - * Identifiers are constant expression and can be used in any context where such - * an expression is required. As an example: - * @code{.cpp} - * using ID = entt::Identifier; - * - * switch(aTypeIdentifier) { - * case ID::get(): - * // ... - * break; - * case ID::get(): - * // ... - * break; - * default: - * // ... - * } - * @endcode - * - * @tparam Types List of types for which to generate identifiers. - */ -template -class Identifier final { - using tuple_type = std::tuple...>; - - template - static constexpr std::size_t get(std::index_sequence) ENTT_NOEXCEPT { - static_assert(internal::IsPartOf::value, "!"); - - std::size_t max{}; - using accumulator_type = std::size_t[]; - accumulator_type accumulator = { (max = std::is_same>::value ? Indexes : max)... }; - (void)accumulator; - return max; - } - -public: - /*! @brief Unsigned integer type. */ - using identifier_type = std::size_t; - - /** - * @brief Returns the identifier associated with a given type. - * @tparam Type of which to return the identifier. - * @return The identifier associated with the given type. - */ - template - static constexpr identifier_type get() ENTT_NOEXCEPT { - return get>(std::make_index_sequence{}); - } -}; - - -} - - -#endif // ENTT_CORE_IDENT_HPP diff --git a/external/entt/core/monostate.hpp b/external/entt/core/monostate.hpp deleted file mode 100644 index f0fa47fc0..000000000 --- a/external/entt/core/monostate.hpp +++ /dev/null @@ -1,61 +0,0 @@ -#ifndef ENTT_CORE_MONOSTATE_HPP -#define ENTT_CORE_MONOSTATE_HPP - - -#include -#include -#include "family.hpp" -#include "hashed_string.hpp" - - -namespace entt { - - -/** - * @brief Minimal implementation of the monostate pattern. - * - * A minimal, yet complete configuration system built on top of the monostate - * pattern. Thread safe by design, it works only with basic types like `int`s or - * `bool`s.
- * Multiple types and therefore more than one value can be associated with a - * single key. Because of this, users must pay attention to use the same type - * both during an assignment and when they try to read back their data. - * Otherwise, they can incur in unexpected results. - */ -template -struct Monostate { - /** - * @brief Assigns a value of a specific type to a given key. - * @tparam Type Type of the value to assign. - * @param val User data to assign to the given key. - */ - template - void operator=(Type val) const ENTT_NOEXCEPT { - Monostate::value = val; - } - - /** - * @brief Gets a value of a specific type for a given key. - * @tparam Type Type of the value to get. - * @return Stored value, if any. - */ - template - operator Type() const ENTT_NOEXCEPT { - return Monostate::value; - } - -private: - template - static std::atomic value; -}; - - -template -template -std::atomic Monostate::value{}; - - -} - - -#endif // ENTT_CORE_MONOSTATE_HPP diff --git a/external/entt/entity/actor.hpp b/external/entt/entity/actor.hpp deleted file mode 100644 index f1c8d99a1..000000000 --- a/external/entt/entity/actor.hpp +++ /dev/null @@ -1,243 +0,0 @@ -#ifndef ENTT_ENTITY_ACTOR_HPP -#define ENTT_ENTITY_ACTOR_HPP - - -#include -#include -#include "../config/config.h" -#include "registry.hpp" -#include "entity.hpp" - - -namespace entt { - - -/** - * @brief Dedicated to those who aren't confident with entity-component systems. - * - * Tiny wrapper around a registry, for all those users that aren't confident - * with entity-component systems and prefer to iterate objects directly. - * - * @tparam Entity A valid entity type (see entt_traits for more details). - */ -template -struct Actor { - /*! @brief Type of registry used internally. */ - using registry_type = Registry; - /*! @brief Underlying entity identifier. */ - using entity_type = Entity; - - /** - * @brief Constructs an actor by using the given registry. - * @param reg An entity-component system properly initialized. - */ - Actor(Registry ®) - : reg{®}, entt{reg.create()} - {} - - /*! @brief Default destructor. */ - virtual ~Actor() { - reg->destroy(entt); - } - - /*! @brief Copying an actor isn't allowed. */ - Actor(const Actor &) = delete; - - /** - * @brief Move constructor. - * - * After actor move construction, instances that have been moved from are - * placed in a valid but unspecified state. It's highly discouraged to - * continue using them. - * - * @param other The instance to move from. - */ - Actor(Actor &&other) - : reg{other.reg}, entt{other.entt} - { - other.entt = entt::null; - } - - /*! @brief Default copy assignment operator. @return This actor. */ - Actor & operator=(const Actor &) = delete; - - /** - * @brief Move assignment operator. - * - * After actor move assignment, instances that have been moved from are - * placed in a valid but unspecified state. It's highly discouraged to - * continue using them. - * - * @param other The instance to move from. - * @return This actor. - */ - Actor & operator=(Actor &&other) { - if(this != &other) { - auto tmp{std::move(other)}; - std::swap(reg, tmp.reg); - std::swap(entt, tmp.entt); - } - - return *this; - } - - /** - * @brief Assigns the given tag to an actor. - * - * A new instance of the given tag is created and initialized with the - * arguments provided (the tag must have a proper constructor or be of - * aggregate type). Then the tag is removed from its previous owner (if any) - * and assigned to the actor. - * - * @tparam Tag Type of the tag to create. - * @tparam Args Types of arguments to use to construct the tag. - * @param args Parameters to use to initialize the tag. - * @return A reference to the newly created tag. - */ - template - Tag & assign(tag_t, Args &&... args) { - return (reg->template remove(), reg->template assign(tag_t{}, entt, std::forward(args)...)); - } - - /** - * @brief Assigns the given component to an actor. - * - * A new instance of the given component is created and initialized with the - * arguments provided (the component must have a proper constructor or be of - * aggregate type). Then the component is assigned to the actor.
- * In case the actor already has a component of the given type, it's - * replaced with the new one. - * - * @tparam Component Type of the component to create. - * @tparam Args Types of arguments to use to construct the component. - * @param args Parameters to use to initialize the component. - * @return A reference to the newly created component. - */ - template - Component & assign(Args &&... args) { - return reg->template accommodate(entt, std::forward(args)...); - } - - /** - * @brief Removes the given tag from an actor. - * @tparam Tag Type of the tag to remove. - */ - template - void remove(tag_t) { - assert(has(tag_t{})); - reg->template remove(); - } - - /** - * @brief Removes the given component from an actor. - * @tparam Component Type of the component to remove. - */ - template - void remove() { - reg->template remove(entt); - } - - /** - * @brief Checks if an actor owns the given tag. - * @tparam Tag Type of the tag for which to perform the check. - * @return True if the actor owns the tag, false otherwise. - */ - template - bool has(tag_t) const ENTT_NOEXCEPT { - return (reg->template has() && (reg->template attachee() == entt)); - } - - /** - * @brief Checks if an actor has the given component. - * @tparam Component Type of the component for which to perform the check. - * @return True if the actor has the component, false otherwise. - */ - template - bool has() const ENTT_NOEXCEPT { - return reg->template has(entt); - } - - /** - * @brief Returns a reference to the given tag for an actor. - * @tparam Tag Type of the tag to get. - * @return A reference to the instance of the tag owned by the actor. - */ - template - const Tag & get(tag_t) const ENTT_NOEXCEPT { - assert(has(tag_t{})); - return reg->template get(); - } - - /** - * @brief Returns a reference to the given tag for an actor. - * @tparam Tag Type of the tag to get. - * @return A reference to the instance of the tag owned by the actor. - */ - template - inline Tag & get(tag_t) ENTT_NOEXCEPT { - return const_cast(const_cast(this)->get(tag_t{})); - } - - /** - * @brief Returns a reference to the given component for an actor. - * @tparam Component Type of the component to get. - * @return A reference to the instance of the component owned by the actor. - */ - template - const Component & get() const ENTT_NOEXCEPT { - return reg->template get(entt); - } - - /** - * @brief Returns a reference to the given component for an actor. - * @tparam Component Type of the component to get. - * @return A reference to the instance of the component owned by the actor. - */ - template - inline Component & get() ENTT_NOEXCEPT { - return const_cast(const_cast(this)->get()); - } - - /** - * @brief Returns a reference to the underlying registry. - * @return A reference to the underlying registry. - */ - inline const registry_type & registry() const ENTT_NOEXCEPT { - return *reg; - } - - /** - * @brief Returns a reference to the underlying registry. - * @return A reference to the underlying registry. - */ - inline registry_type & registry() ENTT_NOEXCEPT { - return const_cast(const_cast(this)->registry()); - } - - /** - * @brief Returns the entity associated with an actor. - * @return The entity associated with the actor. - */ - inline entity_type entity() const ENTT_NOEXCEPT { - return entt; - } - -private: - registry_type * reg; - Entity entt; -}; - - -/** - * @brief Default actor class. - * - * The default actor is the best choice for almost all the applications.
- * Users should have a really good reason to choose something different. - */ -using actor = Actor; - - -} - - -#endif // ENTT_ENTITY_ACTOR_HPP diff --git a/external/entt/entity/attachee.hpp b/external/entt/entity/attachee.hpp deleted file mode 100644 index b972c7d38..000000000 --- a/external/entt/entity/attachee.hpp +++ /dev/null @@ -1,230 +0,0 @@ -#ifndef ENTT_ENTITY_ATTACHEE_HPP -#define ENTT_ENTITY_ATTACHEE_HPP - - -#include -#include -#include -#include "../config/config.h" -#include "entity.hpp" - - -namespace entt { - - -/** - * @brief Attachee. - * - * Primary template isn't defined on purpose. All the specializations give a - * compile-time error, but for a few reasonable cases. - */ -template -class Attachee; - - -/** - * @brief Basic attachee implementation. - * - * Convenience data structure used to store single instance components. - * - * @tparam Entity A valid entity type (see entt_traits for more details). - */ -template -class Attachee { -public: - /*! @brief Underlying entity identifier. */ - using entity_type = Entity; - - /*! @brief Default constructor. */ - Attachee() ENTT_NOEXCEPT - : owner{null} - {} - - /*! @brief Default copy constructor. */ - Attachee(const Attachee &) = default; - /*! @brief Default move constructor. */ - Attachee(Attachee &&) = default; - - /*! @brief Default copy assignment operator. @return This attachee. */ - Attachee & operator=(const Attachee &) = default; - /*! @brief Default move assignment operator. @return This attachee. */ - Attachee & operator=(Attachee &&) = default; - - /*! @brief Default destructor. */ - virtual ~Attachee() ENTT_NOEXCEPT = default; - - /** - * @brief Returns the owner of an attachee. - * @return A valid entity identifier if an owner exists, the null entity - * identifier otherwise. - */ - inline entity_type get() const ENTT_NOEXCEPT { - return owner; - } - - /** - * @brief Assigns an entity to an attachee. - * - * @warning - * Attempting to assigns an entity to an attachee that already has an owner - * results in undefined behavior.
- * An assertion will abort the execution at runtime in debug mode in case - * the attachee already has an owner. - * - * @param entity A valid entity identifier. - */ - inline void construct(const entity_type entity) ENTT_NOEXCEPT { - assert(owner == null); - owner = entity; - } - - /** - * @brief Removes an entity from an attachee. - * - * @warning - * Attempting to free an empty attachee results in undefined behavior.
- * An assertion will abort the execution at runtime in debug mode if the - * attachee is already empty. - */ - virtual void destroy() ENTT_NOEXCEPT { - assert(owner != null); - owner = null; - } - -private: - entity_type owner; -}; - - -/** - * @brief Extended attachee implementation. - * - * This specialization of an attachee associates an object to an entity. The - * main purpose of this class is to use attachees to store tags in a Registry. - * It guarantees fast access both to the element and to the entity. - * - * @sa Attachee - * - * @tparam Entity A valid entity type (see entt_traits for more details). - * @tparam Type Type of object assigned to the entity. - */ -template -class Attachee: public Attachee { - using underlying_type = Attachee; - -public: - /*! @brief Type of the object associated to the attachee. */ - using object_type = Type; - /*! @brief Underlying entity identifier. */ - using entity_type = typename underlying_type::entity_type; - - /*! @brief Default constructor. */ - Attachee() ENTT_NOEXCEPT = default; - - /*! @brief Copying an attachee isn't allowed. */ - Attachee(const Attachee &) = delete; - /*! @brief Moving an attachee isn't allowed. */ - Attachee(Attachee &&) = delete; - - /*! @brief Copying an attachee isn't allowed. @return This attachee. */ - Attachee & operator=(const Attachee &) = delete; - /*! @brief Moving an attachee isn't allowed. @return This attachee. */ - Attachee & operator=(Attachee &&) = delete; - - /*! @brief Default destructor. */ - ~Attachee() { - if(underlying_type::get() != null) { - reinterpret_cast(&storage)->~Type(); - } - } - - /** - * @brief Returns the object associated to an attachee. - * - * @warning - * Attempting to query an empty attachee results in undefined behavior.
- * An assertion will abort the execution at runtime in debug mode if the - * attachee is empty. - * - * @return The object associated to the attachee. - */ - const Type & get() const ENTT_NOEXCEPT { - assert(underlying_type::get() != null); - return *reinterpret_cast(&storage); - } - - /** - * @brief Returns the object associated to an attachee. - * - * @warning - * Attempting to query an empty attachee results in undefined behavior.
- * An assertion will abort the execution at runtime in debug mode if the - * attachee is empty. - * - * @return The object associated to the attachee. - */ - Type & get() ENTT_NOEXCEPT { - return const_cast(const_cast(this)->get()); - } - - /** - * @brief Assigns an entity to an attachee and constructs its object. - * - * @warning - * Attempting to assigns an entity to an attachee that already has an owner - * results in undefined behavior.
- * An assertion will abort the execution at runtime in debug mode in case - * the attachee already has an owner. - * - * @tparam Args Types of arguments to use to construct the object. - * @param entity A valid entity identifier. - * @param args Parameters to use to construct an object for the entity. - * @return The object associated to the attachee. - */ - template - Type & construct(entity_type entity, Args &&... args) ENTT_NOEXCEPT { - underlying_type::construct(entity); - new (&storage) Type{std::forward(args)...}; - return *reinterpret_cast(&storage); - } - - /** - * @brief Removes an entity from an attachee and destroies its object. - * - * @warning - * Attempting to free an empty attachee results in undefined behavior.
- * An assertion will abort the execution at runtime in debug mode if the - * attachee is already empty. - */ - void destroy() ENTT_NOEXCEPT override { - reinterpret_cast(&storage)->~Type(); - underlying_type::destroy(); - } - - /** - * @brief Changes the owner of an attachee. - * - * The ownership of the attachee is transferred from one entity to another. - * - * @warning - * Attempting to transfer the ownership of an attachee that hasn't an owner - * results in undefined behavior.
- * An assertion will abort the execution at runtime in debug mode in case - * the attachee hasn't an owner yet. - * - * @param entity A valid entity identifier. - */ - void move(const entity_type entity) ENTT_NOEXCEPT { - underlying_type::destroy(); - underlying_type::construct(entity); - } - -private: - std::aligned_storage_t storage; -}; - - -} - - -#endif // ENTT_ENTITY_ATTACHEE_HPP diff --git a/external/entt/entity/entity.hpp b/external/entt/entity/entity.hpp deleted file mode 100644 index 4ef2265bc..000000000 --- a/external/entt/entity/entity.hpp +++ /dev/null @@ -1,84 +0,0 @@ -#ifndef ENTT_ENTITY_ENTITY_HPP -#define ENTT_ENTITY_ENTITY_HPP - - -#include "../config/config.h" -#include "entt_traits.hpp" - - -namespace entt { - - -/** - * @cond TURN_OFF_DOXYGEN - * Internal details not to be documented. - */ - - -namespace internal { - - -struct Null { - explicit constexpr Null() = default; - - template - constexpr operator Entity() const ENTT_NOEXCEPT { - using traits_type = entt::entt_traits; - return traits_type::entity_mask | (traits_type::version_mask << traits_type::entity_shift); - } - - constexpr bool operator==(Null) const ENTT_NOEXCEPT { - return true; - } - - constexpr bool operator!=(Null) const ENTT_NOEXCEPT { - return false; - } - - template - constexpr bool operator==(const Entity entity) const ENTT_NOEXCEPT { - return entity == static_cast(*this); - } - - template - constexpr bool operator!=(const Entity entity) const ENTT_NOEXCEPT { - return entity != static_cast(*this); - } -}; - - -template -constexpr bool operator==(const Entity entity, Null null) ENTT_NOEXCEPT { - return null == entity; -} - - -template -constexpr bool operator!=(const Entity entity, Null null) ENTT_NOEXCEPT { - return null != entity; -} - - -} - - -/** - * Internal details not to be documented. - * @endcond TURN_OFF_DOXYGEN - */ - - -/** - * @brief Null entity. - * - * There exist implicit conversions from this variable to entity identifiers of - * any allowed type. Similarly, there exist comparision operators between the - * null entity and any other entity identifier. - */ -constexpr auto null = internal::Null{}; - - -} - - -#endif // ENTT_ENTITY_ENTITY_HPP diff --git a/external/entt/entity/entt_traits.hpp b/external/entt/entity/entt_traits.hpp deleted file mode 100644 index df2cb60d9..000000000 --- a/external/entt/entity/entt_traits.hpp +++ /dev/null @@ -1,102 +0,0 @@ -#ifndef ENTT_ENTITY_ENTT_TRAITS_HPP -#define ENTT_ENTITY_ENTT_TRAITS_HPP - - -#include - - -namespace entt { - - -/** - * @brief Entity traits. - * - * Primary template isn't defined on purpose. All the specializations give a - * compile-time error unless the template parameter is an accepted entity type. - */ -template -struct entt_traits; - - -/** - * @brief Entity traits for a 16 bits entity identifier. - * - * A 16 bits entity identifier guarantees: - * - * * 12 bits for the entity number (up to 4k entities). - * * 4 bit for the version (resets in [0-15]). - */ -template<> -struct entt_traits { - /*! @brief Underlying entity type. */ - using entity_type = std::uint16_t; - /*! @brief Underlying version type. */ - using version_type = std::uint8_t; - /*! @brief Difference type. */ - using difference_type = std::int32_t; - - /*! @brief Mask to use to get the entity number out of an identifier. */ - static constexpr std::uint16_t entity_mask = 0xFFF; - /*! @brief Mask to use to get the version out of an identifier. */ - static constexpr std::uint16_t version_mask = 0xF; - /*! @brief Extent of the entity number within an identifier. */ - static constexpr auto entity_shift = 12; -}; - - -/** - * @brief Entity traits for a 32 bits entity identifier. - * - * A 32 bits entity identifier guarantees: - * - * * 20 bits for the entity number (suitable for almost all the games). - * * 12 bit for the version (resets in [0-4095]). - */ -template<> -struct entt_traits { - /*! @brief Underlying entity type. */ - using entity_type = std::uint32_t; - /*! @brief Underlying version type. */ - using version_type = std::uint16_t; - /*! @brief Difference type. */ - using difference_type = std::int64_t; - - /*! @brief Mask to use to get the entity number out of an identifier. */ - static constexpr std::uint32_t entity_mask = 0xFFFFF; - /*! @brief Mask to use to get the version out of an identifier. */ - static constexpr std::uint32_t version_mask = 0xFFF; - /*! @brief Extent of the entity number within an identifier. */ - static constexpr auto entity_shift = 20; -}; - - -/** - * @brief Entity traits for a 64 bits entity identifier. - * - * A 64 bits entity identifier guarantees: - * - * * 32 bits for the entity number (an indecently large number). - * * 32 bit for the version (an indecently large number). - */ -template<> -struct entt_traits { - /*! @brief Underlying entity type. */ - using entity_type = std::uint64_t; - /*! @brief Underlying version type. */ - using version_type = std::uint32_t; - /*! @brief Difference type. */ - using difference_type = std::int64_t; - - /*! @brief Mask to use to get the entity number out of an identifier. */ - static constexpr std::uint64_t entity_mask = 0xFFFFFFFF; - /*! @brief Mask to use to get the version out of an identifier. */ - static constexpr std::uint64_t version_mask = 0xFFFFFFFF; - /*! @brief Extent of the entity number within an identifier. */ - static constexpr auto entity_shift = 32; -}; - - -} - - -#endif // ENTT_ENTITY_ENTT_TRAITS_HPP diff --git a/external/entt/entity/helper.hpp b/external/entt/entity/helper.hpp deleted file mode 100644 index 7445f15f1..000000000 --- a/external/entt/entity/helper.hpp +++ /dev/null @@ -1,105 +0,0 @@ -#ifndef ENTT_ENTITY_HELPER_HPP -#define ENTT_ENTITY_HELPER_HPP - - -#include -#include "../core/hashed_string.hpp" -#include "../signal/sigh.hpp" -#include "registry.hpp" -#include "utility.hpp" - - -namespace entt { - - -/** - * @brief Dependency function prototype. - * - * A _dependency function_ is a built-in listener to use to automatically assign - * components to an entity when a type has a dependency on some other types. - * - * This is a prototype function to use to create dependencies.
- * It isn't intended for direct use, although nothing forbids using it freely. - * - * @tparam Entity A valid entity type (see entt_traits for more details). - * @tparam Component Types of components to assign to an entity if triggered. - * @param registry A valid reference to a registry. - * @param entity A valid entity identifier. - */ -template -void dependency(Registry ®istry, const Entity entity) { - using accumulator_type = int[]; - accumulator_type accumulator = { ((registry.template has(entity) ? void() : (registry.template assign(entity), void())), 0)... }; - (void)accumulator; -} - - -/** - * @brief Connects a dependency function to the given sink. - * - * A _dependency function_ is a built-in listener to use to automatically assign - * components to an entity when a type has a dependency on some other types. - * - * The following adds components `AType` and `AnotherType` whenever `MyType` is - * assigned to an entity: - * @code{.cpp} - * entt::registry registry; - * entt::connect(registry.construction()); - * @endcode - * - * @tparam Dependency Types of components to assign to an entity if triggered. - * @tparam Entity A valid entity type (see entt_traits for more details). - * @param sink A sink object properly initialized. - */ -template -inline void connect(Sink &, const Entity)> sink) { - sink.template connect>(); -} - - -/** - * @brief Disconnects a dependency function from the given sink. - * - * A _dependency function_ is a built-in listener to use to automatically assign - * components to an entity when a type has a dependency on some other types. - * - * The following breaks the dependency between the component `MyType` and the - * components `AType` and `AnotherType`: - * @code{.cpp} - * entt::registry registry; - * entt::disconnect(registry.construction()); - * @endcode - * - * @tparam Dependency Types of components used to create the dependency. - * @tparam Entity A valid entity type (see entt_traits for more details). - * @param sink A sink object properly initialized. - */ -template -inline void disconnect(Sink &, const Entity)> sink) { - sink.template disconnect>(); -} - - -/** - * @brief Alias template to ease the assignment of labels to entities. - * - * If used in combination with hashed strings, it simplifies the assignment of - * labels to entities and the use of labels in general where a type would be - * required otherwise.
- * As an example and where the user defined literal for hashed strings hasn't - * been changed: - * @code{.cpp} - * entt::registry registry; - * registry.assign>(entity); - * @endcode - * - * @tparam Value The numeric representation of an instance of hashed string. - */ -template -using label = std::integral_constant; - - -} - - -#endif // ENTT_ENTITY_HELPER_HPP diff --git a/external/entt/entity/prototype.hpp b/external/entt/entity/prototype.hpp deleted file mode 100644 index cac3d80c5..000000000 --- a/external/entt/entity/prototype.hpp +++ /dev/null @@ -1,497 +0,0 @@ -#ifndef ENTT_ENTITY_PROTOTYPE_HPP -#define ENTT_ENTITY_PROTOTYPE_HPP - - -#include -#include -#include -#include -#include -#include "../config/config.h" -#include "registry.hpp" -#include "entity.hpp" - - -namespace entt { - - -/** - * @brief Prototype container for _concepts_. - * - * A prototype is used to define a _concept_ in terms of components.
- * Prototypes act as templates for those specific types of an application which - * users would otherwise define through a series of component assignments to - * entities. In other words, prototypes can be used to assign components to - * entities of a registry at once. - * - * @note - * Components used along with prototypes must be copy constructible. Prototypes - * wrap component types with custom types, so they do not interfere with other - * users of the registry they were built with. - * - * @warning - * Prototypes directly use their underlying registries to store entities and - * components for their purposes. Users must ensure that the lifetime of a - * registry and its contents exceed that of the prototypes that use it. - * - * @tparam Entity A valid entity type (see entt_traits for more details). - */ -template -class Prototype final { - using basic_fn_type = void(const Prototype &, Registry &, const Entity); - using component_type = typename Registry::component_type; - - template - struct Wrapper { Component component; }; - - struct Handler { - basic_fn_type *accommodate; - basic_fn_type *assign; - }; - - void release() { - if(registry->valid(entity)) { - registry->destroy(entity); - } - } - -public: - /*! @brief Registry type. */ - using registry_type = Registry; - /*! @brief Underlying entity identifier. */ - using entity_type = Entity; - /*! @brief Unsigned integer type. */ - using size_type = std::size_t; - - /** - * @brief Constructs a prototype that is bound to a given registry. - * @param registry A valid reference to a registry. - */ - Prototype(Registry ®istry) - : registry{®istry}, - entity{registry.create()} - {} - - /** - * @brief Releases all its resources. - */ - ~Prototype() { - release(); - } - - /*! @brief Copying a prototype isn't allowed. */ - Prototype(const Prototype &) = delete; - - /** - * @brief Move constructor. - * - * After prototype move construction, instances that have been moved from - * are placed in a valid but unspecified state. It's highly discouraged to - * continue using them. - * - * @param other The instance to move from. - */ - Prototype(Prototype &&other) - : handlers{std::move(other.handlers)}, - registry{other.registry}, - entity{other.entity} - { - other.entity = entt::null; - } - - /*! @brief Copying a prototype isn't allowed. @return This Prototype. */ - Prototype & operator=(const Prototype &) = delete; - - /** - * @brief Move assignment operator. - * - * After prototype move assignment, instances that have been moved from are - * placed in a valid but unspecified state. It's highly discouraged to - * continue using them. - * - * @param other The instance to move from. - * @return This Prototype. - */ - Prototype & operator=(Prototype &&other) { - if(this != &other) { - auto tmp{std::move(other)}; - handlers.swap(tmp.handlers); - std::swap(registry, tmp.registry); - std::swap(entity, tmp.entity); - } - - return *this; - } - - /** - * @brief Assigns to or replaces the given component of a prototype. - * @tparam Component Type of component to assign or replace. - * @tparam Args Types of arguments to use to construct the component. - * @param args Parameters to use to initialize the component. - * @return A reference to the newly created component. - */ - template - Component & set(Args &&... args) { - basic_fn_type *accommodate = [](const Prototype &prototype, Registry &other, const Entity dst) { - const auto &wrapper = prototype.registry->template get>(prototype.entity); - other.template accommodate(dst, wrapper.component); - }; - - basic_fn_type *assign = [](const Prototype &prototype, Registry &other, const Entity dst) { - if(!other.template has(dst)) { - const auto &wrapper = prototype.registry->template get>(prototype.entity); - other.template assign(dst, wrapper.component); - } - }; - - handlers[registry->template type()] = Handler{accommodate, assign}; - auto &wrapper = registry->template accommodate>(entity, Component{std::forward(args)...}); - return wrapper.component; - } - - /** - * @brief Removes the given component from a prototype. - * @tparam Component Type of component to remove. - */ - template - void unset() ENTT_NOEXCEPT { - registry->template reset>(entity); - handlers.erase(registry->template type()); - } - - /** - * @brief Checks if a prototype owns all the given components. - * @tparam Component Components for which to perform the check. - * @return True if the prototype owns all the components, false otherwise. - */ - template - bool has() const ENTT_NOEXCEPT { - return registry->template has...>(entity); - } - - /** - * @brief Returns a reference to the given component. - * - * @warning - * Attempting to get a component from a prototype that doesn't own it - * results in undefined behavior.
- * An assertion will abort the execution at runtime in debug mode if the - * prototype doesn't own an instance of the given component. - * - * @tparam Component Type of component to get. - * @return A reference to the component owned by the prototype. - */ - template - const Component & get() const ENTT_NOEXCEPT { - return registry->template get>(entity).component; - } - - /** - * @brief Returns a reference to the given component. - * - * @warning - * Attempting to get a component from a prototype that doesn't own it - * results in undefined behavior.
- * An assertion will abort the execution at runtime in debug mode if the - * prototype doesn't own an instance of the given component. - * - * @tparam Component Type of component to get. - * @return A reference to the component owned by the prototype. - */ - template - inline Component & get() ENTT_NOEXCEPT { - return const_cast(const_cast(this)->get()); - } - - /** - * @brief Returns a reference to the given components. - * - * @warning - * Attempting to get components from a prototype that doesn't own them - * results in undefined behavior.
- * An assertion will abort the execution at runtime in debug mode if the - * prototype doesn't own instances of the given components. - * - * @tparam Component Type of components to get. - * @return References to the components owned by the prototype. - */ - template - inline std::enable_if_t<(sizeof...(Component) > 1), std::tuple> - get() const ENTT_NOEXCEPT { - return std::tuple{get()...}; - } - - /** - * @brief Returns a reference to the given components. - * - * @warning - * Attempting to get components from a prototype that doesn't own them - * results in undefined behavior.
- * An assertion will abort the execution at runtime in debug mode if the - * prototype doesn't own instances of the given components. - * - * @tparam Component Type of components to get. - * @return References to the components owned by the prototype. - */ - template - inline std::enable_if_t<(sizeof...(Component) > 1), std::tuple> - get() ENTT_NOEXCEPT { - return std::tuple{get()...}; - } - - /** - * @brief Creates a new entity using a given prototype. - * - * Utility shortcut, equivalent to the following snippet: - * - * @code{.cpp} - * const auto entity = registry.create(); - * prototype(registry, entity); - * @endcode - * - * @note - * The registry may or may not be different from the one already used by - * the prototype. There is also an overload that directly uses the - * underlying registry. - * - * @param other A valid reference to a registry. - * @return A valid entity identifier. - */ - entity_type create(registry_type &other) const { - const auto entity = other.create(); - assign(other, entity); - return entity; - } - - /** - * @brief Creates a new entity using a given prototype. - * - * Utility shortcut, equivalent to the following snippet: - * - * @code{.cpp} - * const auto entity = registry.create(); - * prototype(entity); - * @endcode - * - * @note - * This overload directly uses the underlying registry as a working space. - * Therefore, the components of the prototype and of the entity will share - * the same registry. - * - * @return A valid entity identifier. - */ - inline entity_type create() const { - return create(*registry); - } - - /** - * @brief Assigns the components of a prototype to a given entity. - * - * Assigning a prototype to an entity won't overwrite existing components - * under any circumstances.
- * In other words, only those components that the entity doesn't own yet are - * copied over. All the other components remain unchanged. - * - * @note - * The registry may or may not be different from the one already used by - * the prototype. There is also an overload that directly uses the - * underlying registry. - * - * @warning - * Attempting to use an invalid entity results in undefined behavior.
- * An assertion will abort the execution at runtime in debug mode in case of - * invalid entity. - * - * @param other A valid reference to a registry. - * @param dst A valid entity identifier. - */ - void assign(registry_type &other, const entity_type dst) const { - for(auto &handler: handlers) { - handler.second.assign(*this, other, dst); - } - } - - /** - * @brief Assigns the components of a prototype to a given entity. - * - * Assigning a prototype to an entity won't overwrite existing components - * under any circumstances.
- * In other words, only those components that the entity doesn't own yet are - * copied over. All the other components remain unchanged. - * - * @note - * This overload directly uses the underlying registry as a working space. - * Therefore, the components of the prototype and of the entity will share - * the same registry. - * - * @warning - * Attempting to use an invalid entity results in undefined behavior.
- * An assertion will abort the execution at runtime in debug mode in case of - * invalid entity. - * - * @param dst A valid entity identifier. - */ - inline void assign(const entity_type dst) const { - assign(*registry, dst); - } - - /** - * @brief Assigns or replaces the components of a prototype for an entity. - * - * Existing components are overwritten, if any. All the other components - * will be copied over to the target entity. - * - * @note - * The registry may or may not be different from the one already used by - * the prototype. There is also an overload that directly uses the - * underlying registry. - * - * @warning - * Attempting to use an invalid entity results in undefined behavior.
- * An assertion will abort the execution at runtime in debug mode in case of - * invalid entity. - * - * @param other A valid reference to a registry. - * @param dst A valid entity identifier. - */ - void accommodate(registry_type &other, const entity_type dst) const { - for(auto &handler: handlers) { - handler.second.accommodate(*this, other, dst); - } - } - - /** - * @brief Assigns or replaces the components of a prototype for an entity. - * - * Existing components are overwritten, if any. All the other components - * will be copied over to the target entity. - * - * @note - * This overload directly uses the underlying registry as a working space. - * Therefore, the components of the prototype and of the entity will share - * the same registry. - * - * @warning - * Attempting to use an invalid entity results in undefined behavior.
- * An assertion will abort the execution at runtime in debug mode in case of - * invalid entity. - * - * @param dst A valid entity identifier. - */ - inline void accommodate(const entity_type dst) const { - accommodate(*registry, dst); - } - - /** - * @brief Assigns the components of a prototype to an entity. - * - * Assigning a prototype to an entity won't overwrite existing components - * under any circumstances.
- * In other words, only the components that the entity doesn't own yet are - * copied over. All the other components remain unchanged. - * - * @note - * The registry may or may not be different from the one already used by - * the prototype. There is also an overload that directly uses the - * underlying registry. - * - * @warning - * Attempting to use an invalid entity results in undefined behavior.
- * An assertion will abort the execution at runtime in debug mode in case of - * invalid entity. - * - * @param other A valid reference to a registry. - * @param dst A valid entity identifier. - */ - inline void operator()(registry_type &other, const entity_type dst) const ENTT_NOEXCEPT { - assign(other, dst); - } - - /** - * @brief Assigns the components of a prototype to an entity. - * - * Assigning a prototype to an entity won't overwrite existing components - * under any circumstances.
- * In other words, only the components that the entity doesn't own yet are - * copied over. All the other components remain unchanged. - * - * @note - * This overload directly uses the underlying registry as a working space. - * Therefore, the components of the prototype and of the entity will share - * the same registry. - * - * @warning - * Attempting to use an invalid entity results in undefined behavior.
- * An assertion will abort the execution at runtime in debug mode in case of - * invalid entity. - * - * @param dst A valid entity identifier. - */ - inline void operator()(const entity_type dst) const ENTT_NOEXCEPT { - assign(*registry, dst); - } - - /** - * @brief Creates a new entity using a given prototype. - * - * Utility shortcut, equivalent to the following snippet: - * - * @code{.cpp} - * const auto entity = registry.create(); - * prototype(registry, entity); - * @endcode - * - * @note - * The registry may or may not be different from the one already used by - * the prototype. There is also an overload that directly uses the - * underlying registry. - * - * @param other A valid reference to a registry. - * @return A valid entity identifier. - */ - inline entity_type operator()(registry_type &other) const ENTT_NOEXCEPT { - return create(other); - } - - /** - * @brief Creates a new entity using a given prototype. - * - * Utility shortcut, equivalent to the following snippet: - * - * @code{.cpp} - * const auto entity = registry.create(); - * prototype(entity); - * @endcode - * - * @note - * This overload directly uses the underlying registry as a working space. - * Therefore, the components of the prototype and of the entity will share - * the same registry. - * - * @return A valid entity identifier. - */ - inline entity_type operator()() const ENTT_NOEXCEPT { - return create(*registry); - } - -private: - std::unordered_map handlers; - Registry *registry; - entity_type entity; -}; - - -/** - * @brief Default prototype - * - * The default prototype is the best choice for almost all the - * applications.
- * Users should have a really good reason to choose something different. - */ -using prototype = Prototype; - - -} - - -#endif // ENTT_ENTITY_PROTOTYPE_HPP diff --git a/external/entt/entity/registry.hpp b/external/entt/entity/registry.hpp deleted file mode 100644 index a472267a1..000000000 --- a/external/entt/entity/registry.hpp +++ /dev/null @@ -1,1662 +0,0 @@ -#ifndef ENTT_ENTITY_REGISTRY_HPP -#define ENTT_ENTITY_REGISTRY_HPP - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "../config/config.h" -#include "../core/algorithm.hpp" -#include "../core/family.hpp" -#include "../signal/sigh.hpp" -#include "attachee.hpp" -#include "entity.hpp" -#include "entt_traits.hpp" -#include "snapshot.hpp" -#include "sparse_set.hpp" -#include "utility.hpp" -#include "view.hpp" - - -namespace entt { - - -/** - * @brief Fast and reliable entity-component system. - * - * The registry is the core class of the entity-component framework.
- * It stores entities and arranges pools of components on a per request basis. - * By means of a registry, users can manage entities and components and thus - * create views to iterate them. - * - * @tparam Entity A valid entity type (see entt_traits for more details). - */ -template -class Registry { - using tag_family = Family; - using component_family = Family; - using handler_family = Family; - using signal_type = SigH; - using traits_type = entt_traits; - - template - struct Pool: SparseSet { - Pool(Registry *registry) ENTT_NOEXCEPT - : registry{registry} - {} - - template - Component & construct(const Entity entity, Args &&... args) { - auto &component = SparseSet::construct(entity, std::forward(args)...); - ctor.publish(*registry, entity); - return component; - } - - void destroy(const Entity entity) override { - dtor.publish(*registry, entity); - SparseSet::destroy(entity); - } - - typename signal_type::sink_type construction() ENTT_NOEXCEPT { - return ctor.sink(); - } - - typename signal_type::sink_type destruction() ENTT_NOEXCEPT { - return dtor.sink(); - } - - private: - Registry *registry; - signal_type ctor; - signal_type dtor; - }; - - template - struct Attaching: Attachee { - Attaching(Registry *registry) - : registry{registry} - {} - - template - Tag & construct(const Entity entity, Args &&... args) ENTT_NOEXCEPT { - auto &tag = Attachee::construct(entity, std::forward(args)...); - ctor.publish(*registry, entity); - return tag; - } - - void destroy() ENTT_NOEXCEPT override { - dtor.publish(*registry, Attachee::get()); - Attachee::destroy(); - } - - Entity move(const Entity entity) ENTT_NOEXCEPT { - const auto owner = Attachee::get(); - dtor.publish(*registry, owner); - Attachee::move(entity); - ctor.publish(*registry, entity); - return owner; - } - - typename signal_type::sink_type construction() ENTT_NOEXCEPT { - return ctor.sink(); - } - - typename signal_type::sink_type destruction() ENTT_NOEXCEPT { - return dtor.sink(); - } - - private: - Registry *registry; - signal_type ctor; - signal_type dtor; - }; - - template - static void creating(Registry ®istry, const Entity entity) { - if(registry.has(entity)) { - registry.handlers[Type()]->construct(entity); - } - } - - template - static void destroying(Registry ®istry, const Entity entity) { - auto &handler = *registry.handlers[handler_family::type()]; - return handler.has(entity) ? handler.destroy(entity) : void(); - } - - template - inline bool managed(tag_t) const ENTT_NOEXCEPT { - const auto ttype = tag_family::type(); - return ttype < tags.size() && tags[ttype]; - } - - template - inline bool managed() const ENTT_NOEXCEPT { - const auto ctype = component_family::type(); - return ctype < pools.size() && pools[ctype]; - } - - template - inline const Attaching & pool(tag_t) const ENTT_NOEXCEPT { - assert(managed(tag_t{})); - return static_cast &>(*tags[tag_family::type()]); - } - - template - inline Attaching & pool(tag_t) ENTT_NOEXCEPT { - return const_cast &>(const_cast(this)->pool(tag_t{})); - } - - template - inline const Pool & pool() const ENTT_NOEXCEPT { - assert(managed()); - return static_cast &>(*pools[component_family::type()]); - } - - template - inline Pool & pool() ENTT_NOEXCEPT { - return const_cast &>(const_cast(this)->pool()); - } - - template - void connect(std::index_sequence) { - pool().construction().template connect<&Registry::creating<&handler_family::type, std::tuple_element_t<(Indexes < Pivot ? Indexes : (Indexes+1)), std::tuple>...>>(); - pool().destruction().template connect<&Registry::destroying>(); - } - - template - void connect(std::index_sequence) { - using accumulator_type = int[]; - accumulator_type accumulator = { (assure(), connect(std::make_index_sequence{}), 0)... }; - (void)accumulator; - } - - template - void disconnect(std::index_sequence) { - pool().construction().template disconnect<&Registry::creating<&handler_family::type, std::tuple_element_t<(Indexes < Pivot ? Indexes : (Indexes+1)), std::tuple>...>>(); - pool().destruction().template disconnect<&Registry::destroying>(); - } - - template - void disconnect(std::index_sequence) { - using accumulator_type = int[]; - // if a set exists, pools have already been created for it - accumulator_type accumulator = { (disconnect(std::make_index_sequence{}), 0)... }; - (void)accumulator; - } - - template - void assure() { - const auto ctype = component_family::type(); - - if(!(ctype < pools.size())) { - pools.resize(ctype + 1); - } - - if(!pools[ctype]) { - pools[ctype] = std::make_unique>(this); - } - } - - template - void assure(tag_t) { - const auto ttype = tag_family::type(); - - if(!(ttype < tags.size())) { - tags.resize(ttype + 1); - } - - if(!tags[ttype]) { - tags[ttype] = std::make_unique>(this); - } - } - -public: - /*! @brief Underlying entity identifier. */ - using entity_type = typename traits_type::entity_type; - /*! @brief Underlying version type. */ - using version_type = typename traits_type::version_type; - /*! @brief Unsigned integer type. */ - using size_type = std::size_t; - /*! @brief Unsigned integer type. */ - using tag_type = typename tag_family::family_type; - /*! @brief Unsigned integer type. */ - using component_type = typename component_family::family_type; - /*! @brief Type of sink for the given component. */ - using sink_type = typename signal_type::sink_type; - - /*! @brief Default constructor. */ - Registry() = default; - - /*! @brief Copying a registry isn't allowed. */ - Registry(const Registry &) = delete; - /*! @brief Default move constructor. */ - Registry(Registry &&) = default; - - /*! @brief Copying a registry isn't allowed. @return This registry. */ - Registry & operator=(const Registry &) = delete; - /*! @brief Default move assignment operator. @return This registry. */ - Registry & operator=(Registry &&) = default; - - /** - * @brief Returns the numeric identifier of a type of tag at runtime. - * - * The given tag doesn't need to be necessarily in use. However, the - * registry could decide to prepare internal data structures for it for - * later uses.
- * Do not use this functionality to provide numeric identifiers to types at - * runtime. - * - * @tparam Tag Type of tag to query. - * @return Runtime numeric identifier of the given type of tag. - */ - template - static tag_type type(tag_t) ENTT_NOEXCEPT { - return tag_family::type(); - } - - /** - * @brief Returns the numeric identifier of a type of component at runtime. - * - * The given component doesn't need to be necessarily in use. However, the - * registry could decide to prepare internal data structures for it for - * later uses.
- * Do not use this functionality to provide numeric identifiers to types at - * runtime. - * - * @tparam Component Type of component to query. - * @return Runtime numeric identifier of the given type of component. - */ - template - static component_type type() ENTT_NOEXCEPT { - return component_family::type(); - } - - /** - * @brief Returns the number of existing components of the given type. - * @tparam Component Type of component of which to return the size. - * @return Number of existing components of the given type. - */ - template - size_type size() const ENTT_NOEXCEPT { - return managed() ? pool().size() : size_type{}; - } - - /** - * @brief Returns the number of entities created so far. - * @return Number of entities created so far. - */ - size_type size() const ENTT_NOEXCEPT { - return entities.size(); - } - - /** - * @brief Returns the number of entities still in use. - * @return Number of entities still in use. - */ - size_type alive() const ENTT_NOEXCEPT { - return entities.size() - available; - } - - /** - * @brief Increases the capacity of the pool for the given component. - * - * If the new capacity is greater than the current capacity, new storage is - * allocated, otherwise the method does nothing. - * - * @tparam Component Type of component for which to reserve storage. - * @param cap Desired capacity. - */ - template - void reserve(const size_type cap) { - assure(); - pool().reserve(cap); - } - - /** - * @brief Increases the capacity of a registry in terms of entities. - * - * If the new capacity is greater than the current capacity, new storage is - * allocated, otherwise the method does nothing. - * - * @param cap Desired capacity. - */ - void reserve(const size_type cap) { - entities.reserve(cap); - } - - /** - * @brief Returns the capacity of the pool for the given component. - * @tparam Component Type of component in which one is interested. - * @return Capacity of the pool of the given component. - */ - template - size_type capacity() const ENTT_NOEXCEPT { - return managed() ? pool().capacity() : size_type{}; - } - - /** - * @brief Returns the number of entities that a registry has currently - * allocated space for. - * @return Capacity of the registry. - */ - size_type capacity() const ENTT_NOEXCEPT { - return entities.capacity(); - } - - /** - * @brief Checks whether the pool of the given component is empty. - * @tparam Component Type of component in which one is interested. - * @return True if the pool of the given component is empty, false - * otherwise. - */ - template - bool empty() const ENTT_NOEXCEPT { - return !managed() || pool().empty(); - } - - /** - * @brief Checks if there exists at least an entity still in use. - * @return True if at least an entity is still in use, false otherwise. - */ - bool empty() const ENTT_NOEXCEPT { - return entities.size() == available; - } - - /** - * @brief Direct access to the list of components of a given pool. - * - * The returned pointer is such that range - * `[raw(), raw() + size()]` is always a - * valid range, even if the container is empty. - * - * @note - * There are no guarantees on the order of the components. Use a view if you - * want to iterate entities and components in the expected order. - * - * @tparam Component Type of component in which one is interested. - * @return A pointer to the array of components of the given type. - */ - template - const Component * raw() const ENTT_NOEXCEPT { - return managed() ? pool().raw() : nullptr; - } - - /** - * @brief Direct access to the list of components of a given pool. - * - * The returned pointer is such that range - * `[raw(), raw() + size()]` is always a - * valid range, even if the container is empty. - * - * @note - * There are no guarantees on the order of the components. Use a view if you - * want to iterate entities and components in the expected order. - * - * @tparam Component Type of component in which one is interested. - * @return A pointer to the array of components of the given type. - */ - template - inline Component * raw() ENTT_NOEXCEPT { - return const_cast(const_cast(this)->raw()); - } - - /** - * @brief Direct access to the list of entities of a given pool. - * - * The returned pointer is such that range - * `[data(), data() + size()]` is always a - * valid range, even if the container is empty. - * - * @note - * There are no guarantees on the order of the entities. Use a view if you - * want to iterate entities and components in the expected order. - * - * @tparam Component Type of component in which one is interested. - * @return A pointer to the array of entities. - */ - template - const entity_type * data() const ENTT_NOEXCEPT { - return managed() ? pool().data() : nullptr; - } - - /** - * @brief Checks if an entity identifier refers to a valid entity. - * @param entity An entity identifier, either valid or not. - * @return True if the identifier is valid, false otherwise. - */ - bool valid(const entity_type entity) const ENTT_NOEXCEPT { - const auto pos = size_type(entity & traits_type::entity_mask); - return (pos < entities.size() && entities[pos] == entity); - } - - /** - * @brief Checks if an entity identifier refers to a valid entity. - * - * Alternative version of `valid`. It accesses the internal data structures - * without bounds checking and thus it's both unsafe and risky to use.
- * You should not invoke directly this function unless you know exactly what - * you are doing. Prefer the `valid` member function instead. - * - * @warning - * Attempting to use an entity that doesn't belong to the registry can - * result in undefined behavior.
- * An assertion will abort the execution at runtime in debug mode in case of - * bounds violation. - * - * @param entity A valid entity identifier. - * @return True if the identifier is valid, false otherwise. - */ - bool fast(const entity_type entity) const ENTT_NOEXCEPT { - const auto pos = size_type(entity & traits_type::entity_mask); - assert(pos < entities.size()); - return (entities[pos] == entity); - } - - /** - * @brief Returns the entity identifier without the version. - * @param entity An entity identifier, either valid or not. - * @return The entity identifier without the version. - */ - entity_type entity(const entity_type entity) const ENTT_NOEXCEPT { - return entity & traits_type::entity_mask; - } - - /** - * @brief Returns the version stored along with an entity identifier. - * @param entity An entity identifier, either valid or not. - * @return The version stored along with the given entity identifier. - */ - version_type version(const entity_type entity) const ENTT_NOEXCEPT { - return version_type(entity >> traits_type::entity_shift); - } - - /** - * @brief Returns the actual version for an entity identifier. - * - * In case entity identifers are stored around, this function can be used to - * know if they are still valid or the entity has been destroyed and - * potentially recycled. - * - * @warning - * Attempting to use an entity that doesn't belong to the registry results - * in undefined behavior. An entity belongs to the registry even if it has - * been previously destroyed and/or recycled.
- * An assertion will abort the execution at runtime in debug mode if the - * registry doesn't own the given entity. - * - * @param entity A valid entity identifier. - * @return Actual version for the given entity identifier. - */ - version_type current(const entity_type entity) const ENTT_NOEXCEPT { - const auto pos = size_type(entity & traits_type::entity_mask); - assert(pos < entities.size()); - return version_type(entities[pos] >> traits_type::entity_shift); - } - - /** - * @brief Creates a new entity and returns it. - * - * There are two kinds of entity identifiers: - * - * * Newly created ones in case no entities have been previously destroyed. - * * Recycled ones with updated versions. - * - * Users should not care about the type of the returned entity identifier. - * In case entity identifers are stored around, the `valid` member - * function can be used to know if they are still valid or the entity has - * been destroyed and potentially recycled. - * - * The returned entity has no components nor tags assigned. - * - * @return A valid entity identifier. - */ - entity_type create() { - entity_type entity; - - if(available) { - const auto entt = next; - const auto version = entities[entt] & (traits_type::version_mask << traits_type::entity_shift); - next = entities[entt] & traits_type::entity_mask; - entity = entt | version; - entities[entt] = entity; - --available; - } else { - entity = entity_type(entities.size()); - entities.push_back(entity); - // traits_type::entity_mask is reserved to allow for null identifiers - assert(entity < traits_type::entity_mask); - } - - return entity; - } - - /** - * @brief Destroys the entity that owns the given tag, if any. - * - * Convenient shortcut to destroy an entity by means of a tag type.
- * Syntactic sugar for the following snippet: - * - * @code{.cpp} - * if(registry.has()) { - * registry.destroy(registry.attachee()); - * } - * @endcode - * - * @tparam Tag Type of tag to use to search for the entity. - */ - template - void destroy(tag_t) { - return has() ? destroy(attachee()) : void(); - } - - /** - * @brief Destroys an entity and lets the registry recycle the identifier. - * - * When an entity is destroyed, its version is updated and the identifier - * can be recycled at any time. In case entity identifers are stored around, - * the `valid` member function can be used to know if they are still valid - * or the entity has been destroyed and potentially recycled. - * - * @warning - * In case there are listeners that observe the destruction of components - * and assign other components to the entity in their bodies, the result of - * invoking this function may not be as expected. In the worst case, it - * could lead to undefined behavior. An assertion will abort the execution - * at runtime in debug mode if a violation is detected. - * - * @warning - * Attempting to use an invalid entity results in undefined behavior.
- * An assertion will abort the execution at runtime in debug mode in case of - * invalid entity. - * - * @param entity A valid entity identifier. - */ - void destroy(const entity_type entity) { - assert(valid(entity)); - - for(auto pos = pools.size(); pos; --pos) { - auto &cpool = pools[pos-1]; - - if(cpool && cpool->has(entity)) { - cpool->destroy(entity); - } - }; - - for(auto pos = tags.size(); pos; --pos) { - auto &tag = tags[pos-1]; - - if(tag && tag->get() == entity) { - tag->destroy(); - } - }; - - // just a way to protect users from listeners that attach components - assert(orphan(entity)); - - // lengthens the implicit list of destroyed entities - const auto entt = entity & traits_type::entity_mask; - const auto version = ((entity >> traits_type::entity_shift) + 1) << traits_type::entity_shift; - const auto node = (available ? next : ((entt + 1) & traits_type::entity_mask)) | version; - entities[entt] = node; - next = entt; - ++available; - } - - /** - * @brief Destroys the entities that own the given components, if any. - * - * Convenient shortcut to destroy a set of entities at once.
- * Syntactic sugar for the following snippet: - * - * @code{.cpp} - * for(const auto entity: registry.view(Type{}...)) { - * registry.destroy(entity); - * } - * @endcode - * - * @tparam Component Types of components to use to search for the entities. - * @tparam Type Type of view to use or empty to use a standard view. - */ - template - void destroy(Type...) { - for(const auto entity: view(Type{}...)) { - destroy(entity); - } - } - - /** - * @brief Attaches the given tag to an entity. - * - * Usually, pools of components allocate enough memory to store a bunch of - * elements even if only one of them is used. On the other hand, there are - * cases where all what is needed is a single instance component to attach - * to an entity.
- * Tags are the right tool to achieve the purpose. - * - * @warning - * Attempting to use an invalid entity or to attach to an entity a tag that - * already has an owner results in undefined behavior.
- * An assertion will abort the execution at runtime in debug mode in case of - * invalid entity or if the tag has been already attached to another entity. - * - * @tparam Tag Type of tag to create. - * @tparam Args Types of arguments to use to construct the tag. - * @param entity A valid entity identifier. - * @param args Parameters to use to initialize the tag. - * @return A reference to the newly created tag. - */ - template - Tag & assign(tag_t, const entity_type entity, Args &&... args) { - assert(valid(entity)); - assert(!has()); - assure(tag_t{}); - return pool(tag_t{}).construct(entity, std::forward(args)...); - } - - /** - * @brief Assigns the given component to an entity. - * - * A new instance of the given component is created and initialized with the - * arguments provided (the component must have a proper constructor or be of - * aggregate type). Then the component is assigned to the given entity. - * - * @warning - * Attempting to use an invalid entity or to assign a component to an entity - * that already owns it results in undefined behavior.
- * An assertion will abort the execution at runtime in debug mode in case of - * invalid entity or if the entity already owns an instance of the given - * component. - * - * @tparam Component Type of component to create. - * @tparam Args Types of arguments to use to construct the component. - * @param entity A valid entity identifier. - * @param args Parameters to use to initialize the component. - * @return A reference to the newly created component. - */ - template - Component & assign(const entity_type entity, Args &&... args) { - assert(valid(entity)); - assure(); - return pool().construct(entity, std::forward(args)...); - } - - /** - * @brief Removes the given tag from its owner, if any. - * @tparam Tag Type of tag to remove. - */ - template - void remove() { - return has() ? pool(tag_t{}).destroy() : void(); - } - - /** - * @brief Removes the given component from an entity. - * - * @warning - * Attempting to use an invalid entity or to remove a component from an - * entity that doesn't own it results in undefined behavior.
- * An assertion will abort the execution at runtime in debug mode in case of - * invalid entity or if the entity doesn't own an instance of the given - * component. - * - * @tparam Component Type of component to remove. - * @param entity A valid entity identifier. - */ - template - void remove(const entity_type entity) { - assert(valid(entity)); - assert(managed()); - pool().destroy(entity); - } - - /** - * @brief Checks if the given tag has an owner. - * @tparam Tag Type of tag for which to perform the check. - * @return True if the tag already has an owner, false otherwise. - */ - template - bool has() const ENTT_NOEXCEPT { - return managed(tag_t{}) && tags[tag_family::type()]->get() != null; - } - - /** - * @brief Checks if an entity owns the given tag. - * - * Syntactic sugar for the following snippet: - * - * @code{.cpp} - * registry.has() && registry.attachee() == entity - * @endcode - * - * @tparam Tag Type of tag for which to perform the check. - * @param entity A valid entity identifier. - * @return True if the entity owns the tag, false otherwise. - */ - template - bool has(tag_t, const entity_type entity) const ENTT_NOEXCEPT { - return has() && attachee() == entity; - } - - /** - * @brief Checks if an entity has all the given components. - * - * @warning - * Attempting to use an invalid entity results in undefined behavior.
- * An assertion will abort the execution at runtime in debug mode in case of - * invalid entity. - * - * @tparam Component Components for which to perform the check. - * @param entity A valid entity identifier. - * @return True if the entity has all the components, false otherwise. - */ - template - bool has(const entity_type entity) const ENTT_NOEXCEPT { - assert(valid(entity)); - bool all = true; - using accumulator_type = bool[]; - accumulator_type accumulator = { all, (all = all && managed() && pool().has(entity))... }; - (void)accumulator; - return all; - } - - /** - * @brief Returns a reference to the given tag. - * - * @warning - * Attempting to get a tag that hasn't an owner results in undefined - * behavior.
- * An assertion will abort the execution at runtime in debug mode if the - * tag hasn't been previously attached to an entity. - * - * @tparam Tag Type of tag to get. - * @return A reference to the tag. - */ - template - const Tag & get() const ENTT_NOEXCEPT { - assert(has()); - return pool(tag_t{}).get(); - } - - /** - * @brief Returns a reference to the given tag. - * - * @warning - * Attempting to get a tag that hasn't an owner results in undefined - * behavior.
- * An assertion will abort the execution at runtime in debug mode if the - * tag hasn't been previously attached to an entity. - * - * @tparam Tag Type of tag to get. - * @return A reference to the tag. - */ - template - inline Tag & get() ENTT_NOEXCEPT { - return const_cast(const_cast(this)->get()); - } - - /** - * @brief Returns a reference to the given component for an entity. - * - * @warning - * Attempting to use an invalid entity or to get a component from an entity - * that doesn't own it results in undefined behavior.
- * An assertion will abort the execution at runtime in debug mode in case of - * invalid entity or if the entity doesn't own an instance of the given - * component. - * - * @tparam Component Type of component to get. - * @param entity A valid entity identifier. - * @return A reference to the component owned by the entity. - */ - template - const Component & get(const entity_type entity) const ENTT_NOEXCEPT { - assert(valid(entity)); - assert(managed()); - return pool().get(entity); - } - - /** - * @brief Returns a reference to the given component for an entity. - * - * @warning - * Attempting to use an invalid entity or to get a component from an entity - * that doesn't own it results in undefined behavior.
- * An assertion will abort the execution at runtime in debug mode in case of - * invalid entity or if the entity doesn't own an instance of the given - * component. - * - * @tparam Component Type of component to get. - * @param entity A valid entity identifier. - * @return A reference to the component owned by the entity. - */ - template - inline Component & get(const entity_type entity) ENTT_NOEXCEPT { - return const_cast(const_cast(this)->get(entity)); - } - - /** - * @brief Returns a reference to the given components for an entity. - * - * @warning - * Attempting to use an invalid entity or to get components from an entity - * that doesn't own them results in undefined behavior.
- * An assertion will abort the execution at runtime in debug mode in case of - * invalid entity or if the entity doesn't own instances of the given - * components. - * - * @tparam Component Type of components to get. - * @param entity A valid entity identifier. - * @return References to the components owned by the entity. - */ - template - inline std::enable_if_t<(sizeof...(Component) > 1), std::tuple> - get(const entity_type entity) const ENTT_NOEXCEPT { - return std::tuple{get(entity)...}; - } - - /** - * @brief Returns a reference to the given components for an entity. - * - * @warning - * Attempting to use an invalid entity or to get components from an entity - * that doesn't own them results in undefined behavior.
- * An assertion will abort the execution at runtime in debug mode in case of - * invalid entity or if the entity doesn't own instances of the given - * components. - * - * @tparam Component Type of components to get. - * @param entity A valid entity identifier. - * @return References to the components owned by the entity. - */ - template - inline std::enable_if_t<(sizeof...(Component) > 1), std::tuple> - get(const entity_type entity) ENTT_NOEXCEPT { - return std::tuple{get(entity)...}; - } - - /** - * @brief Replaces the given tag. - * - * A new instance of the given tag is created and initialized with the - * arguments provided (the tag must have a proper constructor or be of - * aggregate type). - * - * @warning - * Attempting to replace a tag that hasn't an owner results in undefined - * behavior.
- * An assertion will abort the execution at runtime in debug mode if the - * tag hasn't been previously attached to an entity. - * - * @tparam Tag Type of tag to replace. - * @tparam Args Types of arguments to use to construct the tag. - * @param args Parameters to use to initialize the tag. - * @return A reference to the tag. - */ - template - Tag & replace(tag_t, Args &&... args) { - return (get() = Tag{std::forward(args)...}); - } - - /** - * @brief Replaces the given component for an entity. - * - * A new instance of the given component is created and initialized with the - * arguments provided (the component must have a proper constructor or be of - * aggregate type). Then the component is assigned to the given entity. - * - * @warning - * Attempting to use an invalid entity or to replace a component of an - * entity that doesn't own it results in undefined behavior.
- * An assertion will abort the execution at runtime in debug mode in case of - * invalid entity or if the entity doesn't own an instance of the given - * component. - * - * @tparam Component Type of component to replace. - * @tparam Args Types of arguments to use to construct the component. - * @param entity A valid entity identifier. - * @param args Parameters to use to initialize the component. - * @return A reference to the newly created component. - */ - template - Component & replace(const entity_type entity, Args &&... args) { - return (get(entity) = Component{std::forward(args)...}); - } - - /** - * @brief Changes the owner of the given tag. - * - * The ownership of the tag is transferred from one entity to another. - * - * @warning - * Attempting to use an invalid entity or to transfer the ownership of a tag - * that hasn't an owner results in undefined behavior.
- * An assertion will abort the execution at runtime in debug mode in case of - * invalid entity or if the tag hasn't been previously attached to an - * entity. - * - * @tparam Tag Type of tag of which to transfer the ownership. - * @param entity A valid entity identifier. - * @return A valid entity identifier. - */ - template - entity_type move(const entity_type entity) ENTT_NOEXCEPT { - assert(valid(entity)); - assert(has()); - return pool(tag_t{}).move(entity); - } - - /** - * @brief Gets the owner of the given tag, if any. - * @tparam Tag Type of tag of which to get the owner. - * @return A valid entity identifier if an owner exists, the null entity - * identifier otherwise. - */ - template - entity_type attachee() const ENTT_NOEXCEPT { - return managed(tag_t{}) ? tags[tag_family::type()]->get() : null; - } - - /** - * @brief Assigns or replaces the given component for an entity. - * - * Equivalent to the following snippet (pseudocode): - * - * @code{.cpp} - * if(registry.has(entity)) { - * registry.replace(entity, args...); - * } else { - * registry.assign(entity, args...); - * } - * @endcode - * - * Prefer this function anyway because it has slightly better performance. - * - * @warning - * Attempting to use an invalid entity results in undefined behavior.
- * An assertion will abort the execution at runtime in debug mode in case of - * invalid entity. - * - * @tparam Component Type of component to assign or replace. - * @tparam Args Types of arguments to use to construct the component. - * @param entity A valid entity identifier. - * @param args Parameters to use to initialize the component. - * @return A reference to the newly created component. - */ - template - Component & accommodate(const entity_type entity, Args &&... args) { - assure(); - auto &cpool = pool(); - - return cpool.has(entity) - ? cpool.get(entity) = Component{std::forward(args)...} - : cpool.construct(entity, std::forward(args)...); - } - - /** - * @brief Returns a sink object for the given tag. - * - * A sink is an opaque object used to connect listeners to tags.
- * The sink returned by this function can be used to receive notifications - * whenever a new instance of the given tag is created and assigned to an - * entity. - * - * The function type for a listener is: - * @code{.cpp} - * void(Registry &, Entity); - * @endcode - * - * Listeners are invoked **after** the tag has been assigned to the entity. - * The order of invocation of the listeners isn't guaranteed.
- * Note also that the greater the number of listeners, the greater the - * performance hit when a new tag is created. - * - * @sa SigH::Sink - * - * @tparam Tag Type of tag of which to get the sink. - * @return A temporary sink object. - */ - template - sink_type construction(tag_t) ENTT_NOEXCEPT { - assure(tag_t{}); - return pool(tag_t{}).construction(); - } - - /** - * @brief Returns a sink object for the given component. - * - * A sink is an opaque object used to connect listeners to components.
- * The sink returned by this function can be used to receive notifications - * whenever a new instance of the given component is created and assigned to - * an entity. - * - * The function type for a listener is: - * @code{.cpp} - * void(Registry &, Entity); - * @endcode - * - * Listeners are invoked **after** the component has been assigned to the - * entity. The order of invocation of the listeners isn't guaranteed.
- * Note also that the greater the number of listeners, the greater the - * performance hit when a new component is created. - * - * @sa SigH::Sink - * - * @tparam Component Type of component of which to get the sink. - * @return A temporary sink object. - */ - template - sink_type construction() ENTT_NOEXCEPT { - assure(); - return pool().construction(); - } - - /** - * @brief Returns a sink object for the given tag. - * - * A sink is an opaque object used to connect listeners to tag.
- * The sink returned by this function can be used to receive notifications - * whenever an instance of the given tag is removed from an entity and thus - * destroyed. - * - * The function type for a listener is: - * @code{.cpp} - * void(Registry &, Entity); - * @endcode - * - * Listeners are invoked **before** the tag has been removed from the - * entity. The order of invocation of the listeners isn't guaranteed.
- * Note also that the greater the number of listeners, the greater the - * performance hit when a tag is destroyed. - * - * @sa SigH::Sink - * - * @tparam Tag Type of tag of which to get the sink. - * @return A temporary sink object. - */ - template - sink_type destruction(tag_t) ENTT_NOEXCEPT { - assure(tag_t{}); - return pool(tag_t{}).destruction(); - } - - /** - * @brief Returns a sink object for the given component. - * - * A sink is an opaque object used to connect listeners to components.
- * The sink returned by this function can be used to receive notifications - * whenever an instance of the given component is removed from an entity and - * thus destroyed. - * - * The function type for a listener is: - * @code{.cpp} - * void(Registry &, Entity); - * @endcode - * - * Listeners are invoked **before** the component has been removed from the - * entity. The order of invocation of the listeners isn't guaranteed.
- * Note also that the greater the number of listeners, the greater the - * performance hit when a component is destroyed. - * - * @sa SigH::Sink - * - * @tparam Component Type of component of which to get the sink. - * @return A temporary sink object. - */ - template - sink_type destruction() ENTT_NOEXCEPT { - assure(); - return pool().destruction(); - } - - /** - * @brief Sorts the pool of entities for the given component. - * - * The order of the elements in a pool is highly affected by assignments - * of components to entities and deletions. Components are arranged to - * maximize the performance during iterations and users should not make any - * assumption on the order.
- * This function can be used to impose an order to the elements in the pool - * of the given component. The order is kept valid until a component of the - * given type is assigned or removed from an entity. - * - * The comparison function object must return `true` if the first element - * is _less_ than the second one, `false` otherwise. The signature of the - * comparison function should be equivalent to the following: - * - * @code{.cpp} - * bool(const Component &, const Component &) - * @endcode - * - * Moreover, the comparison function object shall induce a - * _strict weak ordering_ on the values. - * - * The sort function oject must offer a member function template - * `operator()` that accepts three arguments: - * - * * An iterator to the first element of the range to sort. - * * An iterator past the last element of the range to sort. - * * A comparison function to use to compare the elements. - * - * The comparison funtion object received by the sort function object hasn't - * necessarily the type of the one passed along with the other parameters to - * this member function. - * - * @tparam Component Type of components to sort. - * @tparam Compare Type of comparison function object. - * @tparam Sort Type of sort function object. - * @tparam Args Types of arguments to forward to the sort function object. - * @param compare A valid comparison function object. - * @param sort A valid sort function object. - * @param args Arguments to forward to the sort function object, if any. - */ - template - void sort(Compare compare, Sort sort = Sort{}, Args &&... args) { - assure(); - pool().sort(std::move(compare), std::move(sort), std::forward(args)...); - } - - /** - * @brief Sorts two pools of components in the same way. - * - * The order of the elements in a pool is highly affected by assignments - * of components to entities and deletions. Components are arranged to - * maximize the performance during iterations and users should not make any - * assumption on the order. - * - * It happens that different pools of components must be sorted the same way - * because of runtime and/or performance constraints. This function can be - * used to order a pool of components according to the order between the - * entities in another pool of components. - * - * @b How @b it @b works - * - * Being `A` and `B` the two sets where `B` is the master (the one the order - * of which rules) and `A` is the slave (the one to sort), after a call to - * this function an iterator for `A` will return the entities according to - * the following rules: - * - * * All the entities in `A` that are also in `B` are returned first - * according to the order they have in `B`. - * * All the entities in `A` that are not in `B` are returned in no - * particular order after all the other entities. - * - * Any subsequent change to `B` won't affect the order in `A`. - * - * @tparam To Type of components to sort. - * @tparam From Type of components to use to sort. - */ - template - void sort() { - assure(); - assure(); - pool().respect(pool()); - } - - /** - * @brief Resets the given component for an entity. - * - * If the entity has an instance of the component, this function removes the - * component from the entity. Otherwise it does nothing. - * - * @warning - * Attempting to use an invalid entity results in undefined behavior.
- * An assertion will abort the execution at runtime in debug mode in case of - * invalid entity. - * - * @tparam Component Type of component to reset. - * @param entity A valid entity identifier. - */ - template - void reset(const entity_type entity) { - assert(valid(entity)); - assure(); - auto &cpool = pool(); - - if(cpool.has(entity)) { - cpool.destroy(entity); - } - } - - /** - * @brief Resets the pool of the given component. - * - * For each entity that has an instance of the given component, the - * component itself is removed and thus destroyed. - * - * @tparam Component Type of component whose pool must be reset. - */ - template - void reset() { - assure(); - auto &cpool = pool(); - - for(const auto entity: static_cast &>(cpool)) { - cpool.destroy(entity); - } - } - - /** - * @brief Resets a whole registry. - * - * Destroys all the entities. After a call to `reset`, all the entities - * still in use are recycled with a new version number. In case entity - * identifers are stored around, the `valid` member function can be used - * to know if they are still valid. - */ - void reset() { - each([this](const auto entity) { - // useless this-> used to suppress a warning with clang - this->destroy(entity); - }); - } - - /** - * @brief Iterates all the entities that are still in use. - * - * The function object is invoked for each entity that is still in use.
- * The signature of the function should be equivalent to the following: - * - * @code{.cpp} - * void(const entity_type); - * @endcode - * - * This function is fairly slow and should not be used frequently.
- * Consider using a view if the goal is to iterate entities that have a - * determinate set of components. A view is usually faster than combining - * this function with a bunch of custom tests.
- * On the other side, this function can be used to iterate all the entities - * that are in use, regardless of their components. - * - * @tparam Func Type of the function object to invoke. - * @param func A valid function object. - */ - template - void each(Func func) const { - if(available) { - for(auto pos = entities.size(); pos; --pos) { - const auto curr = entity_type(pos - 1); - const auto entity = entities[curr]; - const auto entt = entity & traits_type::entity_mask; - - if(curr == entt) { - func(entity); - } - } - } else { - for(auto pos = entities.size(); pos; --pos) { - func(entities[pos-1]); - } - } - } - - /** - * @brief Checks if an entity is an orphan. - * - * An orphan is an entity that has neither assigned components nor - * tags. - * - * @param entity A valid entity identifier. - * @return True if the entity is an orphan, false otherwise. - */ - bool orphan(const entity_type entity) const { - assert(valid(entity)); - bool orphan = true; - - for(std::size_t i = 0; i < pools.size() && orphan; ++i) { - const auto &cpool = pools[i]; - orphan = !(cpool && cpool->has(entity)); - } - - for(std::size_t i = 0; i < tags.size() && orphan; ++i) { - const auto &tag = tags[i]; - orphan = !(tag && (tag->get() == entity)); - } - - return orphan; - } - - /** - * @brief Iterates orphans and applies them the given function object. - * - * The function object is invoked for each entity that is still in use and - * has neither assigned components nor tags.
- * The signature of the function should be equivalent to the following: - * - * @code{.cpp} - * void(const entity_type); - * @endcode - * - * This function can be very slow and should not be used frequently. - * - * @tparam Func Type of the function object to invoke. - * @param func A valid function object. - */ - template - void orphans(Func func) const { - each([func = std::move(func), this](const auto entity) { - if(orphan(entity)) { - func(entity); - } - }); - } - - /** - * @brief Returns a standard view for the given components. - * - * This kind of views are created on the fly and share with the registry its - * internal data structures.
- * Feel free to discard a view after the use. Creating and destroying a view - * is an incredibly cheap operation because they do not require any type of - * initialization.
- * As a rule of thumb, storing a view should never be an option. - * - * Standard views do their best to iterate the smallest set of candidate - * entities. In particular: - * - * * Single component views are incredibly fast and iterate a packed array - * of entities, all of which has the given component. - * * Multi component views look at the number of entities available for each - * component and pick up a reference to the smallest set of candidates to - * test for the given components. - * - * @note - * Multi component views are pretty fast. However their performance tend to - * degenerate when the number of components to iterate grows up and the most - * of the entities have all the given components.
- * To get a performance boost, consider using a PersistentView instead. - * - * @see View - * @see View - * @see PersistentView - * @see RawView - * @see RuntimeView - * - * @tparam Component Type of components used to construct the view. - * @return A newly created standard view. - */ - template - View view() { - return View{(assure(), pool())...}; - } - - /** - * @brief Prepares the internal data structures used by persistent views. - * - * Persistent views are an incredibly fast tool used to iterate a packed - * array of entities all of which have specific components.
- * The initialization of a persistent view is also a pretty cheap operation, - * but for the first time they are created. That's mainly because of the - * internal data structures of the registry that are dedicated to this kind - * of views and that don't exist yet the very first time they are - * requested.
- * To avoid costly operations, internal data structures for persistent views - * can be prepared with this function. Just use the same set of components - * that would have been used otherwise to construct the view. - * - * @tparam Component Types of components used to prepare the view. - */ - template - void prepare() { - static_assert(sizeof...(Component) > 1, "!"); - const auto htype = handler_family::type(); - - if(!(htype < handlers.size())) { - handlers.resize(htype + 1); - } - - if(!handlers[htype]) { - connect(std::make_index_sequence{}); - handlers[htype] = std::make_unique>(); - auto &handler = *handlers[htype]; - - for(auto entity: view()) { - handler.construct(entity); - } - } - } - - /** - * @brief Discards all the data structures used for a given persitent view. - * - * Persistent views occupy memory, no matter if they are in use or not.
- * This function can be used to discard all the internal data structures - * dedicated to a specific persistent view, with the goal of reducing the - * memory pressure. - * - * @warning - * Attempting to use a persistent view created before calling this function - * results in undefined behavior. No assertion available in this case, - * neither in debug mode nor in release mode. - * - * @tparam Component Types of components of the persistent view. - */ - template - void discard() { - if(contains()) { - disconnect(std::make_index_sequence{}); - handlers[handler_family::type()].reset(); - } - } - - /** - * @brief Checks if a persistent view has already been prepared. - * @tparam Component Types of components of the persistent view. - * @return True if the view has already been prepared, false otherwise. - */ - template - bool contains() const ENTT_NOEXCEPT { - static_assert(sizeof...(Component) > 1, "!"); - const auto htype = handler_family::type(); - return (htype < handlers.size() && handlers[htype]); - } - - /** - * @brief Returns a persistent view for the given components. - * - * This kind of views are created on the fly and share with the registry its - * internal data structures.
- * Feel free to discard a view after the use. Creating and destroying a view - * is an incredibly cheap operation because they do not require any type of - * initialization.
- * As a rule of thumb, storing a view should never be an option. - * - * Persistent views are the right choice to iterate entities when the number - * of components grows up and the most of the entities have all the given - * components.
- * However they have also drawbacks: - * - * * Each kind of persistent view requires a dedicated data structure that - * is allocated within the registry and it increases memory pressure. - * * Internal data structures used to construct persistent views must be - * kept updated and it affects slightly construction and destruction of - * entities and components. - * - * That being said, persistent views are an incredibly powerful tool if used - * with care and offer a boost of performance undoubtedly. - * - * @note - * Consider to use the `prepare` member function to initialize the internal - * data structures used by persistent views when the registry is still - * empty. Initialization could be a costly operation otherwise and it will - * be performed the very first time each view is created. - * - * @see View - * @see View - * @see PersistentView - * @see RawView - * @see RuntimeView - * - * @tparam Component Types of components used to construct the view. - * @return A newly created persistent view. - */ - template - PersistentView view(persistent_t) { - prepare(); - const auto htype = handler_family::type(); - return PersistentView{*handlers[htype], (assure(), pool())...}; - } - - /** - * @brief Returns a raw view for the given component. - * - * This kind of views are created on the fly and share with the registry its - * internal data structures.
- * Feel free to discard a view after the use. Creating and destroying a view - * is an incredibly cheap operation because they do not require any type of - * initialization.
- * As a rule of thumb, storing a view should never be an option. - * - * Raw views are incredibly fast and must be considered the best tool to - * iterate components whenever knowing the entities to which they belong - * isn't required. - * - * @see View - * @see View - * @see PersistentView - * @see RawView - * @see RuntimeView - * - * @tparam Component Type of component used to construct the view. - * @return A newly created raw view. - */ - template - RawView view(raw_t) { - assure(); - return RawView{pool()}; - } - - /** - * @brief Returns a runtime view for the given components. - * - * This kind of views are created on the fly and share with the registry its - * internal data structures.
- * Users should throw away the view after use. Fortunately, creating and - * destroying a view is an incredibly cheap operation because they do not - * require any type of initialization.
- * As a rule of thumb, storing a view should never be an option. - * - * Runtime views are well suited when users want to construct a view from - * some external inputs and don't know at compile-time what are the required - * components.
- * This is particularly well suited to plugin systems and mods in general. - * - * @see View - * @see View - * @see PersistentView - * @see RawView - * @see RuntimeView - * - * @tparam It Type of forward iterator. - * @param first An iterator to the first element of the range of components. - * @param last An iterator past the last element of the range of components. - * @return A newly created runtime view. - */ - template - RuntimeView view(It first, It last) { - static_assert(std::is_convertible::value_type, component_type>::value, "!"); - std::vector *> set(last - first); - - std::transform(first, last, set.begin(), [this](const component_type ctype) { - return ctype < pools.size() ? pools[ctype].get() : nullptr; - }); - - return RuntimeView{std::move(set)}; - } - - /** - * @brief Returns a temporary object to use to create snapshots. - * - * A snapshot is either a full or a partial dump of a registry.
- * It can be used to save and restore its internal state or to keep two or - * more instances of this class in sync, as an example in a client-server - * architecture. - * - * @return A temporary object to use to take snasphosts. - */ - Snapshot snapshot() const ENTT_NOEXCEPT { - using follow_fn_type = entity_type(const Registry &, const entity_type); - const entity_type seed = available ? (next | (entities[next] & (traits_type::version_mask << traits_type::entity_shift))) : next; - - follow_fn_type *follow = [](const Registry ®istry, const entity_type entity) -> entity_type { - const auto &entities = registry.entities; - const auto entt = entity & traits_type::entity_mask; - const auto next = entities[entt] & traits_type::entity_mask; - return (next | (entities[next] & (traits_type::version_mask << traits_type::entity_shift))); - }; - - return { *this, seed, follow }; - } - - /** - * @brief Returns a temporary object to use to load snapshots. - * - * A snapshot is either a full or a partial dump of a registry.
- * It can be used to save and restore its internal state or to keep two or - * more instances of this class in sync, as an example in a client-server - * architecture. - * - * @warning - * The loader returned by this function requires that the registry be empty. - * In case it isn't, all the data will be automatically deleted before to - * return. - * - * @return A temporary object to use to load snasphosts. - */ - SnapshotLoader restore() ENTT_NOEXCEPT { - using assure_fn_type = void(Registry &, const entity_type, const bool); - - assure_fn_type *assure = [](Registry ®istry, const entity_type entity, const bool destroyed) { - using promotion_type = std::conditional_t= sizeof(entity_type), size_type, entity_type>; - // explicit promotion to avoid warnings with std::uint16_t - const auto entt = promotion_type{entity} & traits_type::entity_mask; - auto &entities = registry.entities; - - if(!(entt < entities.size())) { - auto curr = entities.size(); - entities.resize(entt + 1); - std::iota(entities.data() + curr, entities.data() + entt, entity_type(curr)); - } - - entities[entt] = entity; - - if(destroyed) { - registry.destroy(entity); - const auto version = entity & (traits_type::version_mask << traits_type::entity_shift); - entities[entt] = ((entities[entt] & traits_type::entity_mask) | version); - } - }; - - return { (*this = {}), assure }; - } - -private: - std::vector>> handlers; - std::vector>> pools; - std::vector>> tags; - std::vector entities; - size_type available{}; - entity_type next{}; -}; - - -/** - * @brief Default registry class. - * - * The default registry is the best choice for almost all the applications.
- * Users should have a really good reason to choose something different. - */ -using registry = Registry; - - -} - - -#endif // ENTT_ENTITY_REGISTRY_HPP diff --git a/external/entt/entity/snapshot.hpp b/external/entt/entity/snapshot.hpp deleted file mode 100644 index e9d1128fa..000000000 --- a/external/entt/entity/snapshot.hpp +++ /dev/null @@ -1,724 +0,0 @@ -#ifndef ENTT_ENTITY_SNAPSHOT_HPP -#define ENTT_ENTITY_SNAPSHOT_HPP - - -#include -#include -#include -#include -#include -#include -#include -#include "../config/config.h" -#include "entt_traits.hpp" -#include "utility.hpp" - - -namespace entt { - - -/** - * @brief Forward declaration of the registry class. - */ -template -class Registry; - - -/** - * @brief Utility class to create snapshots from a registry. - * - * A _snapshot_ can be either a dump of the entire registry or a narrower - * selection of components and tags of interest.
- * This type can be used in both cases if provided with a correctly configured - * output archive. - * - * @tparam Entity A valid entity type (see entt_traits for more details). - */ -template -class Snapshot final { - /*! @brief A registry is allowed to create snapshots. */ - friend class Registry; - - using follow_fn_type = Entity(const Registry &, const Entity); - - Snapshot(const Registry ®istry, Entity seed, follow_fn_type *follow) ENTT_NOEXCEPT - : registry{registry}, - seed{seed}, - follow{follow} - {} - - template - void get(Archive &archive, std::size_t sz, It first, It last) const { - archive(static_cast(sz)); - - while(first != last) { - const auto entity = *(first++); - - if(registry.template has(entity)) { - archive(entity, registry.template get(entity)); - } - } - } - - template - void component(Archive &archive, It first, It last, std::index_sequence) const { - std::array size{}; - auto begin = first; - - while(begin != last) { - const auto entity = *(begin++); - using accumulator_type = std::size_t[]; - accumulator_type accumulator = { (registry.template has(entity) ? ++size[Indexes] : size[Indexes])... }; - (void)accumulator; - } - - using accumulator_type = int[]; - accumulator_type accumulator = { (get(archive, size[Indexes], first, last), 0)... }; - (void)accumulator; - } - -public: - /*! @brief Copying a snapshot isn't allowed. */ - Snapshot(const Snapshot &) = delete; - /*! @brief Default move constructor. */ - Snapshot(Snapshot &&) = default; - - /*! @brief Copying a snapshot isn't allowed. @return This snapshot. */ - Snapshot & operator=(const Snapshot &) = delete; - /*! @brief Default move assignment operator. @return This snapshot. */ - Snapshot & operator=(Snapshot &&) = default; - - /** - * @brief Puts aside all the entities that are still in use. - * - * Entities are serialized along with their versions. Destroyed entities are - * not taken in consideration by this function. - * - * @tparam Archive Type of output archive. - * @param archive A valid reference to an output archive. - * @return An object of this type to continue creating the snapshot. - */ - template - const Snapshot & entities(Archive &archive) const { - archive(static_cast(registry.alive())); - registry.each([&archive](const auto entity) { archive(entity); }); - return *this; - } - - /** - * @brief Puts aside destroyed entities. - * - * Entities are serialized along with their versions. Entities that are - * still in use are not taken in consideration by this function. - * - * @tparam Archive Type of output archive. - * @param archive A valid reference to an output archive. - * @return An object of this type to continue creating the snapshot. - */ - template - const Snapshot & destroyed(Archive &archive) const { - auto size = registry.size() - registry.alive(); - archive(static_cast(size)); - - if(size) { - auto curr = seed; - archive(curr); - - for(--size; size; --size) { - curr = follow(registry, curr); - archive(curr); - } - } - - return *this; - } - - /** - * @brief Puts aside the given component. - * - * Each instance is serialized together with the entity to which it belongs. - * Entities are serialized along with their versions. - * - * @tparam Component Type of component to serialize. - * @tparam Archive Type of output archive. - * @param archive A valid reference to an output archive. - * @return An object of this type to continue creating the snapshot. - */ - template - const Snapshot & component(Archive &archive) const { - const auto sz = registry.template size(); - const auto *entities = registry.template data(); - - archive(static_cast(sz)); - - for(std::remove_const_t i{}; i < sz; ++i) { - const auto entity = entities[i]; - archive(entity, registry.template get(entity)); - }; - - return *this; - } - - /** - * @brief Puts aside the given components. - * - * Each instance is serialized together with the entity to which it belongs. - * Entities are serialized along with their versions. - * - * @tparam Component Types of components to serialize. - * @tparam Archive Type of output archive. - * @param archive A valid reference to an output archive. - * @return An object of this type to continue creating the snapshot. - */ - template - std::enable_if_t<(sizeof...(Component) > 1), const Snapshot &> - component(Archive &archive) const { - using accumulator_type = int[]; - accumulator_type accumulator = { 0, (component(archive), 0)... }; - (void)accumulator; - return *this; - } - - /** - * @brief Puts aside the given components for the entities in a range. - * - * Each instance is serialized together with the entity to which it belongs. - * Entities are serialized along with their versions. - * - * @tparam Component Types of components to serialize. - * @tparam Archive Type of output archive. - * @tparam It Type of input iterator. - * @param archive A valid reference to an output archive. - * @param first An iterator to the first element of the range to serialize. - * @param last An iterator past the last element of the range to serialize. - * @return An object of this type to continue creating the snapshot. - */ - template - const Snapshot & component(Archive &archive, It first, It last) const { - component(archive, first, last, std::make_index_sequence{}); - return *this; - } - - /** - * @brief Puts aside the given tag. - * - * Each instance is serialized together with the entity to which it belongs. - * Entities are serialized along with their versions. - * - * @tparam Tag Type of tag to serialize. - * @tparam Archive Type of output archive. - * @param archive A valid reference to an output archive. - * @return An object of this type to continue creating the snapshot. - */ - template - const Snapshot & tag(Archive &archive) const { - const bool has = registry.template has(); - - // numerical length is forced for tags to facilitate loading - archive(has ? Entity(1): Entity{}); - - if(has) { - archive(registry.template attachee(), registry.template get()); - } - - return *this; - } - - /** - * @brief Puts aside the given tags. - * - * Each instance is serialized together with the entity to which it belongs. - * Entities are serialized along with their versions. - * - * @tparam Tag Types of tags to serialize. - * @tparam Archive Type of output archive. - * @param archive A valid reference to an output archive. - * @return An object of this type to continue creating the snapshot. - */ - template - std::enable_if_t<(sizeof...(Tag) > 1), const Snapshot &> - tag(Archive &archive) const { - using accumulator_type = int[]; - accumulator_type accumulator = { 0, (tag(archive), 0)... }; - (void)accumulator; - return *this; - } - -private: - const Registry ®istry; - const Entity seed; - follow_fn_type *follow; -}; - - -/** - * @brief Utility class to restore a snapshot as a whole. - * - * A snapshot loader requires that the destination registry be empty and loads - * all the data at once while keeping intact the identifiers that the entities - * originally had.
- * An example of use is the implementation of a save/restore utility. - * - * @tparam Entity A valid entity type (see entt_traits for more details). - */ -template -class SnapshotLoader final { - /*! @brief A registry is allowed to create snapshot loaders. */ - friend class Registry; - - using assure_fn_type = void(Registry &, const Entity, const bool); - - SnapshotLoader(Registry ®istry, assure_fn_type *assure_fn) ENTT_NOEXCEPT - : registry{registry}, - assure_fn{assure_fn} - { - // restore a snapshot as a whole requires a clean registry - assert(!registry.capacity()); - } - - template - void assure(Archive &archive, bool destroyed) const { - Entity length{}; - archive(length); - - while(length--) { - Entity entity{}; - archive(entity); - assure_fn(registry, entity, destroyed); - } - } - - template - void assign(Archive &archive, Args... args) const { - Entity length{}; - archive(length); - - while(length--) { - Entity entity{}; - Type instance{}; - archive(entity, instance); - static constexpr auto destroyed = false; - assure_fn(registry, entity, destroyed); - registry.template assign(args..., entity, static_cast(instance)); - } - } - -public: - /*! @brief Copying a snapshot loader isn't allowed. */ - SnapshotLoader(const SnapshotLoader &) = delete; - /*! @brief Default move constructor. */ - SnapshotLoader(SnapshotLoader &&) = default; - - /*! @brief Copying a snapshot loader isn't allowed. @return This loader. */ - SnapshotLoader & operator=(const SnapshotLoader &) = delete; - /*! @brief Default move assignment operator. @return This loader. */ - SnapshotLoader & operator=(SnapshotLoader &&) = default; - - /** - * @brief Restores entities that were in use during serialization. - * - * This function restores the entities that were in use during serialization - * and gives them the versions they originally had. - * - * @tparam Archive Type of input archive. - * @param archive A valid reference to an input archive. - * @return A valid loader to continue restoring data. - */ - template - const SnapshotLoader & entities(Archive &archive) const { - static constexpr auto destroyed = false; - assure(archive, destroyed); - return *this; - } - - /** - * @brief Restores entities that were destroyed during serialization. - * - * This function restores the entities that were destroyed during - * serialization and gives them the versions they originally had. - * - * @tparam Archive Type of input archive. - * @param archive A valid reference to an input archive. - * @return A valid loader to continue restoring data. - */ - template - const SnapshotLoader & destroyed(Archive &archive) const { - static constexpr auto destroyed = true; - assure(archive, destroyed); - return *this; - } - - /** - * @brief Restores components and assigns them to the right entities. - * - * The template parameter list must be exactly the same used during - * serialization. In the event that the entity to which the component is - * assigned doesn't exist yet, the loader will take care to create it with - * the version it originally had. - * - * @tparam Component Types of components to restore. - * @tparam Archive Type of input archive. - * @param archive A valid reference to an input archive. - * @return A valid loader to continue restoring data. - */ - template - const SnapshotLoader & component(Archive &archive) const { - using accumulator_type = int[]; - accumulator_type accumulator = { 0, (assign(archive), 0)... }; - (void)accumulator; - return *this; - } - - /** - * @brief Restores tags and assigns them to the right entities. - * - * The template parameter list must be exactly the same used during - * serialization. In the event that the entity to which the tag is assigned - * doesn't exist yet, the loader will take care to create it with the - * version it originally had. - * - * @tparam Tag Types of tags to restore. - * @tparam Archive Type of input archive. - * @param archive A valid reference to an input archive. - * @return A valid loader to continue restoring data. - */ - template - const SnapshotLoader & tag(Archive &archive) const { - using accumulator_type = int[]; - accumulator_type accumulator = { 0, (assign(archive, tag_t{}), 0)... }; - (void)accumulator; - return *this; - } - - /** - * @brief Destroys those entities that have neither components nor tags. - * - * In case all the entities were serialized but only part of the components - * and tags was saved, it could happen that some of the entities have - * neither components nor tags once restored.
- * This functions helps to identify and destroy those entities. - * - * @return A valid loader to continue restoring data. - */ - const SnapshotLoader & orphans() const { - registry.orphans([this](const auto entity) { - registry.destroy(entity); - }); - - return *this; - } - -private: - Registry ®istry; - assure_fn_type *assure_fn; -}; - - -/** - * @brief Utility class for _continuous loading_. - * - * A _continuous loader_ is designed to load data from a source registry to a - * (possibly) non-empty destination. The loader can accomodate in a registry - * more than one snapshot in a sort of _continuous loading_ that updates the - * destination one step at a time.
- * Identifiers that entities originally had are not transferred to the target. - * Instead, the loader maps remote identifiers to local ones while restoring a - * snapshot.
- * An example of use is the implementation of a client-server applications with - * the requirement of transferring somehow parts of the representation side to - * side. - * - * @tparam Entity A valid entity type (see entt_traits for more details). - */ -template -class ContinuousLoader final { - using traits_type = entt_traits; - - void destroy(Entity entity) { - const auto it = remloc.find(entity); - - if(it == remloc.cend()) { - const auto local = registry.create(); - remloc.emplace(entity, std::make_pair(local, true)); - registry.destroy(local); - } - } - - void restore(Entity entity) { - const auto it = remloc.find(entity); - - if(it == remloc.cend()) { - const auto local = registry.create(); - remloc.emplace(entity, std::make_pair(local, true)); - } else { - remloc[entity].first = - registry.valid(remloc[entity].first) - ? remloc[entity].first - : registry.create(); - - // set the dirty flag - remloc[entity].second = true; - } - } - - template - std::enable_if_t::value> - update(Type &instance, Member Type:: *member) { - instance.*member = map(instance.*member); - } - - template - std::enable_if_t::value_type, Entity>::value> - update(Type &instance, Member Type:: *member) { - for(auto &entity: instance.*member) { - entity = map(entity); - } - } - - template - std::enable_if_t::value> - update(Other &, Member Type:: *) {} - - template - void assure(Archive &archive, void(ContinuousLoader:: *member)(Entity)) { - Entity length{}; - archive(length); - - while(length--) { - Entity entity{}; - archive(entity); - (this->*member)(entity); - } - } - - template - void reset() { - for(auto &&ref: remloc) { - const auto local = ref.second.first; - - if(registry.valid(local)) { - registry.template reset(local); - } - } - } - - template - void assign(Archive &archive, Func func, Member Type:: *... member) { - Entity length{}; - archive(length); - - while(length--) { - Entity entity{}; - Other instance{}; - - archive(entity, instance); - restore(entity); - - using accumulator_type = int[]; - accumulator_type accumulator = { 0, (update(instance, member), 0)... }; - (void)accumulator; - - func(map(entity), instance); - } - } - -public: - /*! @brief Underlying entity identifier. */ - using entity_type = Entity; - - /** - * @brief Constructs a loader that is bound to a given registry. - * @param registry A valid reference to a registry. - */ - ContinuousLoader(Registry ®istry) ENTT_NOEXCEPT - : registry{registry} - {} - - /*! @brief Copying a snapshot loader isn't allowed. */ - ContinuousLoader(const ContinuousLoader &) = delete; - /*! @brief Default move constructor. */ - ContinuousLoader(ContinuousLoader &&) = default; - - /*! @brief Copying a snapshot loader isn't allowed. @return This loader. */ - ContinuousLoader & operator=(const ContinuousLoader &) = delete; - /*! @brief Default move assignment operator. @return This loader. */ - ContinuousLoader & operator=(ContinuousLoader &&) = default; - - /** - * @brief Restores entities that were in use during serialization. - * - * This function restores the entities that were in use during serialization - * and creates local counterparts for them if required. - * - * @tparam Archive Type of input archive. - * @param archive A valid reference to an input archive. - * @return A non-const reference to this loader. - */ - template - ContinuousLoader & entities(Archive &archive) { - assure(archive, &ContinuousLoader::restore); - return *this; - } - - /** - * @brief Restores entities that were destroyed during serialization. - * - * This function restores the entities that were destroyed during - * serialization and creates local counterparts for them if required. - * - * @tparam Archive Type of input archive. - * @param archive A valid reference to an input archive. - * @return A non-const reference to this loader. - */ - template - ContinuousLoader & destroyed(Archive &archive) { - assure(archive, &ContinuousLoader::destroy); - return *this; - } - - /** - * @brief Restores components and assigns them to the right entities. - * - * The template parameter list must be exactly the same used during - * serialization. In the event that the entity to which the component is - * assigned doesn't exist yet, the loader will take care to create a local - * counterpart for it.
- * Members can be either data members of type entity_type or containers of - * entities. In both cases, the loader will visit them and update the - * entities by replacing each one with its local counterpart. - * - * @tparam Component Type of component to restore. - * @tparam Archive Type of input archive. - * @tparam Type Types of components to update with local counterparts. - * @tparam Member Types of members to update with their local counterparts. - * @param archive A valid reference to an input archive. - * @param member Members to update with their local counterparts. - * @return A non-const reference to this loader. - */ - template - ContinuousLoader & component(Archive &archive, Member Type:: *... member) { - auto apply = [this](const auto entity, const auto &component) { - registry.template accommodate>(entity, component); - }; - - using accumulator_type = int[]; - accumulator_type accumulator = { 0, (reset(), assign(archive, apply, member...), 0)... }; - (void)accumulator; - return *this; - } - - /** - * @brief Restores tags and assigns them to the right entities. - * - * The template parameter list must be exactly the same used during - * serialization. In the event that the entity to which the tag is assigned - * doesn't exist yet, the loader will take care to create a local - * counterpart for it.
- * Members can be either data members of type entity_type or containers of - * entities. In both cases, the loader will visit them and update the - * entities by replacing each one with its local counterpart. - * - * @tparam Tag Type of tag to restore. - * @tparam Archive Type of input archive. - * @tparam Type Types of components to update with local counterparts. - * @tparam Member Types of members to update with their local counterparts. - * @param archive A valid reference to an input archive. - * @param member Members to update with their local counterparts. - * @return A non-const reference to this loader. - */ - template - ContinuousLoader & tag(Archive &archive, Member Type:: *... member) { - auto apply = [this](const auto entity, const auto &tag) { - registry.template assign>(tag_t{}, entity, tag); - }; - - using accumulator_type = int[]; - accumulator_type accumulator = { 0, (registry.template remove(), assign(archive, apply, member...), 0)... }; - (void)accumulator; - return *this; - } - - /** - * @brief Helps to purge entities that no longer have a conterpart. - * - * Users should invoke this member function after restoring each snapshot, - * unless they know exactly what they are doing. - * - * @return A non-const reference to this loader. - */ - ContinuousLoader & shrink() { - auto it = remloc.begin(); - - while(it != remloc.cend()) { - const auto local = it->second.first; - bool &dirty = it->second.second; - - if(dirty) { - dirty = false; - ++it; - } else { - if(registry.valid(local)) { - registry.destroy(local); - } - - it = remloc.erase(it); - } - } - - return *this; - } - - /** - * @brief Destroys those entities that have neither components nor tags. - * - * In case all the entities were serialized but only part of the components - * and tags was saved, it could happen that some of the entities have - * neither components nor tags once restored.
- * This functions helps to identify and destroy those entities. - * - * @return A non-const reference to this loader. - */ - ContinuousLoader & orphans() { - registry.orphans([this](const auto entity) { - registry.destroy(entity); - }); - - return *this; - } - - /** - * @brief Tests if a loader knows about a given entity. - * @param entity An entity identifier. - * @return True if `entity` is managed by the loader, false otherwise. - */ - bool has(entity_type entity) const ENTT_NOEXCEPT { - return (remloc.find(entity) != remloc.cend()); - } - - /** - * @brief Returns the identifier to which an entity refers. - * - * @warning - * Attempting to use an entity that isn't managed by the loader results in - * undefined behavior.
- * An assertion will abort the execution at runtime in debug mode if the - * loader doesn't knows about the entity. - * - * @param entity An entity identifier. - * @return The identifier to which `entity` refers in the target registry. - */ - entity_type map(entity_type entity) const ENTT_NOEXCEPT { - assert(has(entity)); - return remloc.find(entity)->second.first; - } - -private: - std::unordered_map> remloc; - Registry ®istry; -}; - - -} - - -#endif // ENTT_ENTITY_SNAPSHOT_HPP diff --git a/external/entt/entity/sparse_set.hpp b/external/entt/entity/sparse_set.hpp deleted file mode 100644 index fc0e32ceb..000000000 --- a/external/entt/entity/sparse_set.hpp +++ /dev/null @@ -1,1120 +0,0 @@ -#ifndef ENTT_ENTITY_SPARSE_SET_HPP -#define ENTT_ENTITY_SPARSE_SET_HPP - - -#include -#include -#include -#include -#include -#include -#include -#include -#include "../config/config.h" -#include "../core/algorithm.hpp" -#include "entt_traits.hpp" -#include "entity.hpp" - - -namespace entt { - - -/** - * @brief Sparse set. - * - * Primary template isn't defined on purpose. All the specializations give a - * compile-time error, but for a few reasonable cases. - */ -template -class SparseSet; - - -/** - * @brief Basic sparse set implementation. - * - * Sparse set or packed array or whatever is the name users give it.
- * Two arrays: an _external_ one and an _internal_ one; a _sparse_ one and a - * _packed_ one; one used for direct access through contiguous memory, the other - * one used to get the data through an extra level of indirection.
- * This is largely used by the Registry to offer users the fastest access ever - * to the components. View and PersistentView are entirely designed around - * sparse sets. - * - * This type of data structure is widely documented in the literature and on the - * web. This is nothing more than a customized implementation suitable for the - * purpose of the framework. - * - * @note - * There are no guarantees that entities are returned in the insertion order - * when iterate a sparse set. Do not make assumption on the order in any case. - * - * @note - * Internal data structures arrange elements to maximize performance. Because of - * that, there are no guarantees that elements have the expected order when - * iterate directly the internal packed array (see `data` and `size` member - * functions for that). Use `begin` and `end` instead. - * - * @tparam Entity A valid entity type (see entt_traits for more details). - */ -template -class SparseSet { - using traits_type = entt_traits; - - class Iterator final { - friend class SparseSet; - - using direct_type = const std::vector; - using index_type = typename traits_type::difference_type; - - Iterator(direct_type *direct, index_type index) ENTT_NOEXCEPT - : direct{direct}, index{index} - {} - - public: - using difference_type = index_type; - using value_type = const Entity; - using pointer = value_type *; - using reference = value_type &; - using iterator_category = std::random_access_iterator_tag; - - Iterator() ENTT_NOEXCEPT = default; - - Iterator(const Iterator &) ENTT_NOEXCEPT = default; - Iterator & operator=(const Iterator &) ENTT_NOEXCEPT = default; - - Iterator & operator++() ENTT_NOEXCEPT { - return --index, *this; - } - - Iterator operator++(int) ENTT_NOEXCEPT { - Iterator orig = *this; - return ++(*this), orig; - } - - Iterator & operator--() ENTT_NOEXCEPT { - return ++index, *this; - } - - Iterator operator--(int) ENTT_NOEXCEPT { - Iterator orig = *this; - return --(*this), orig; - } - - Iterator & operator+=(const difference_type value) ENTT_NOEXCEPT { - index -= value; - return *this; - } - - Iterator operator+(const difference_type value) const ENTT_NOEXCEPT { - return Iterator{direct, index-value}; - } - - inline Iterator & operator-=(const difference_type value) ENTT_NOEXCEPT { - return (*this += -value); - } - - inline Iterator operator-(const difference_type value) const ENTT_NOEXCEPT { - return (*this + -value); - } - - difference_type operator-(const Iterator &other) const ENTT_NOEXCEPT { - return other.index - index; - } - - reference operator[](const difference_type value) const ENTT_NOEXCEPT { - const auto pos = size_type(index-value-1); - return (*direct)[pos]; - } - - bool operator==(const Iterator &other) const ENTT_NOEXCEPT { - return other.index == index; - } - - inline bool operator!=(const Iterator &other) const ENTT_NOEXCEPT { - return !(*this == other); - } - - bool operator<(const Iterator &other) const ENTT_NOEXCEPT { - return index > other.index; - } - - bool operator>(const Iterator &other) const ENTT_NOEXCEPT { - return index < other.index; - } - - inline bool operator<=(const Iterator &other) const ENTT_NOEXCEPT { - return !(*this > other); - } - - inline bool operator>=(const Iterator &other) const ENTT_NOEXCEPT { - return !(*this < other); - } - - pointer operator->() const ENTT_NOEXCEPT { - const auto pos = size_type(index-1); - return &(*direct)[pos]; - } - - inline reference operator*() const ENTT_NOEXCEPT { - return *operator->(); - } - - private: - direct_type *direct; - index_type index; - }; - -public: - /*! @brief Underlying entity identifier. */ - using entity_type = Entity; - /*! @brief Unsigned integer type. */ - using size_type = std::size_t; - /*! @brief Input iterator type. */ - using iterator_type = Iterator; - /*! @brief Constant input iterator type. */ - using const_iterator_type = Iterator; - - /*! @brief Default constructor. */ - SparseSet() ENTT_NOEXCEPT = default; - - /*! @brief Default destructor. */ - virtual ~SparseSet() ENTT_NOEXCEPT = default; - - /*! @brief Copying a sparse set isn't allowed. */ - SparseSet(const SparseSet &) = delete; - /*! @brief Default move constructor. */ - SparseSet(SparseSet &&) = default; - - /*! @brief Copying a sparse set isn't allowed. @return This sparse set. */ - SparseSet & operator=(const SparseSet &) = delete; - /*! @brief Default move assignment operator. @return This sparse set. */ - SparseSet & operator=(SparseSet &&) = default; - - /** - * @brief Increases the capacity of a sparse set. - * - * If the new capacity is greater than the current capacity, new storage is - * allocated, otherwise the method does nothing. - * - * @param cap Desired capacity. - */ - void reserve(const size_type cap) { - direct.reserve(cap); - } - - /** - * @brief Returns the number of elements that a sparse set has currently - * allocated space for. - * @return Capacity of the sparse set. - */ - size_type capacity() const ENTT_NOEXCEPT { - return direct.capacity(); - } - - /** - * @brief Returns the extent of a sparse set. - * - * The extent of a sparse set is also the size of the internal sparse array. - * There is no guarantee that the internal packed array has the same size. - * Usually the size of the internal sparse array is equal or greater than - * the one of the internal packed array. - * - * @return Extent of the sparse set. - */ - size_type extent() const ENTT_NOEXCEPT { - return reverse.size(); - } - - /** - * @brief Returns the number of elements in a sparse set. - * - * The number of elements is also the size of the internal packed array. - * There is no guarantee that the internal sparse array has the same size. - * Usually the size of the internal sparse array is equal or greater than - * the one of the internal packed array. - * - * @return Number of elements. - */ - size_type size() const ENTT_NOEXCEPT { - return direct.size(); - } - - /** - * @brief Checks whether a sparse set is empty. - * @return True if the sparse set is empty, false otherwise. - */ - bool empty() const ENTT_NOEXCEPT { - return direct.empty(); - } - - /** - * @brief Direct access to the internal packed array. - * - * The returned pointer is such that range `[data(), data() + size()]` is - * always a valid range, even if the container is empty. - * - * @note - * There are no guarantees on the order, even though `respect` has been - * previously invoked. Internal data structures arrange elements to maximize - * performance. Accessing them directly gives a performance boost but less - * guarantees. Use `begin` and `end` if you want to iterate the sparse set - * in the expected order. - * - * @return A pointer to the internal packed array. - */ - const entity_type * data() const ENTT_NOEXCEPT { - return direct.data(); - } - - /** - * @brief Returns an iterator to the beginning. - * - * The returned iterator points to the first entity of the internal packed - * array. If the sparse set is empty, the returned iterator will be equal to - * `end()`. - * - * @note - * Input iterators stay true to the order imposed by a call to `respect`. - * - * @return An iterator to the first entity of the internal packed array. - */ - const_iterator_type cbegin() const ENTT_NOEXCEPT { - const typename traits_type::difference_type pos = direct.size(); - return const_iterator_type{&direct, pos}; - } - - /** - * @brief Returns an iterator to the beginning. - * - * The returned iterator points to the first entity of the internal packed - * array. If the sparse set is empty, the returned iterator will be equal to - * `end()`. - * - * @note - * Input iterators stay true to the order imposed by a call to `respect`. - * - * @return An iterator to the first entity of the internal packed array. - */ - inline const_iterator_type begin() const ENTT_NOEXCEPT { - return cbegin(); - } - - /** - * @brief Returns an iterator to the beginning. - * - * The returned iterator points to the first entity of the internal packed - * array. If the sparse set is empty, the returned iterator will be equal to - * `end()`. - * - * @note - * Input iterators stay true to the order imposed by a call to `respect`. - * - * @return An iterator to the first entity of the internal packed array. - */ - inline iterator_type begin() ENTT_NOEXCEPT { - return cbegin(); - } - - /** - * @brief Returns an iterator to the end. - * - * The returned iterator points to the element following the last entity in - * the internal packed array. Attempting to dereference the returned - * iterator results in undefined behavior. - * - * @note - * Input iterators stay true to the order imposed by a call to `respect`. - * - * @return An iterator to the element following the last entity of the - * internal packed array. - */ - const_iterator_type cend() const ENTT_NOEXCEPT { - return const_iterator_type{&direct, {}}; - } - - /** - * @brief Returns an iterator to the end. - * - * The returned iterator points to the element following the last entity in - * the internal packed array. Attempting to dereference the returned - * iterator results in undefined behavior. - * - * @note - * Input iterators stay true to the order imposed by a call to `respect`. - * - * @return An iterator to the element following the last entity of the - * internal packed array. - */ - inline const_iterator_type end() const ENTT_NOEXCEPT { - return cend(); - } - - /** - * @brief Returns an iterator to the end. - * - * The returned iterator points to the element following the last entity in - * the internal packed array. Attempting to dereference the returned - * iterator results in undefined behavior. - * - * @note - * Input iterators stay true to the order imposed by a call to `respect`. - * - * @return An iterator to the element following the last entity of the - * internal packed array. - */ - inline iterator_type end() ENTT_NOEXCEPT { - return cend(); - } - - /** - * @brief Returns a reference to the element at the given position. - * @param pos Position of the element to return. - * @return A reference to the requested element. - */ - inline const entity_type & operator[](const size_type pos) const ENTT_NOEXCEPT { - return cbegin()[pos]; - } - - /** - * @brief Checks if a sparse set contains an entity. - * @param entity A valid entity identifier. - * @return True if the sparse set contains the entity, false otherwise. - */ - bool has(const entity_type entity) const ENTT_NOEXCEPT { - const auto pos = size_type(entity & traits_type::entity_mask); - // testing against null permits to avoid accessing the direct vector - return (pos < reverse.size()) && (reverse[pos] != null); - } - - /** - * @brief Checks if a sparse set contains an entity (unsafe). - * - * Alternative version of `has`. It accesses the underlying data structures - * without bounds checking and thus it's both unsafe and risky to use.
- * You should not invoke directly this function unless you know exactly what - * you are doing. Prefer the `has` member function instead. - * - * @warning - * Attempting to use an entity that doesn't belong to the sparse set can - * result in undefined behavior.
- * An assertion will abort the execution at runtime in debug mode in case of - * bounds violation. - * - * @param entity A valid entity identifier. - * @return True if the sparse set contains the entity, false otherwise. - */ - bool fast(const entity_type entity) const ENTT_NOEXCEPT { - const auto pos = size_type(entity & traits_type::entity_mask); - assert(pos < reverse.size()); - // testing against null permits to avoid accessing the direct vector - return (reverse[pos] != null); - } - - /** - * @brief Returns the position of an entity in a sparse set. - * - * @warning - * Attempting to get the position of an entity that doesn't belong to the - * sparse set results in undefined behavior.
- * An assertion will abort the execution at runtime in debug mode if the - * sparse set doesn't contain the given entity. - * - * @param entity A valid entity identifier. - * @return The position of the entity in the sparse set. - */ - size_type get(const entity_type entity) const ENTT_NOEXCEPT { - assert(has(entity)); - const auto pos = size_type(entity & traits_type::entity_mask); - return size_type(reverse[pos]); - } - - /** - * @brief Assigns an entity to a sparse set. - * - * @warning - * Attempting to assign an entity that already belongs to the sparse set - * results in undefined behavior.
- * An assertion will abort the execution at runtime in debug mode if the - * sparse set already contains the given entity. - * - * @param entity A valid entity identifier. - */ - void construct(const entity_type entity) { - assert(!has(entity)); - const auto pos = size_type(entity & traits_type::entity_mask); - - if(!(pos < reverse.size())) { - // null is safe in all cases for our purposes - reverse.resize(pos+1, null); - } - - reverse[pos] = entity_type(direct.size()); - direct.push_back(entity); - } - - /** - * @brief Removes an entity from a sparse set. - * - * @warning - * Attempting to remove an entity that doesn't belong to the sparse set - * results in undefined behavior.
- * An assertion will abort the execution at runtime in debug mode if the - * sparse set doesn't contain the given entity. - * - * @param entity A valid entity identifier. - */ - virtual void destroy(const entity_type entity) { - assert(has(entity)); - const auto back = direct.back(); - auto &candidate = reverse[size_type(entity & traits_type::entity_mask)]; - // swapping isn't required here, we are getting rid of the last element - reverse[back & traits_type::entity_mask] = candidate; - direct[size_type(candidate)] = back; - candidate = null; - direct.pop_back(); - } - - /** - * @brief Swaps the position of two entities in the internal packed array. - * - * For what it's worth, this function affects both the internal sparse array - * and the internal packed array. Users should not care of that anyway. - * - * @warning - * Attempting to swap entities that don't belong to the sparse set results - * in undefined behavior.
- * An assertion will abort the execution at runtime in debug mode if the - * sparse set doesn't contain the given entities. - * - * @param lhs A valid position within the sparse set. - * @param rhs A valid position within the sparse set. - */ - void swap(const size_type lhs, const size_type rhs) ENTT_NOEXCEPT { - assert(lhs < direct.size()); - assert(rhs < direct.size()); - auto &src = direct[lhs]; - auto &dst = direct[rhs]; - std::swap(reverse[src & traits_type::entity_mask], reverse[dst & traits_type::entity_mask]); - std::swap(src, dst); - } - - /** - * @brief Sort entities according to their order in another sparse set. - * - * Entities that are part of both the sparse sets are ordered internally - * according to the order they have in `other`. All the other entities goes - * to the end of the list and there are no guarantess on their order.
- * In other terms, this function can be used to impose the same order on two - * sets by using one of them as a master and the other one as a slave. - * - * Iterating the sparse set with a couple of iterators returns elements in - * the expected order after a call to `respect`. See `begin` and `end` for - * more details. - * - * @note - * Attempting to iterate elements using the raw pointer returned by `data` - * gives no guarantees on the order, even though `respect` has been invoked. - * - * @param other The sparse sets that imposes the order of the entities. - */ - void respect(const SparseSet &other) ENTT_NOEXCEPT { - auto from = other.cbegin(); - auto to = other.cend(); - - size_type pos = direct.size() - 1; - - while(pos && from != to) { - if(has(*from)) { - if(*from != direct[pos]) { - swap(pos, get(*from)); - } - - --pos; - } - - ++from; - } - } - - /** - * @brief Resets a sparse set. - */ - virtual void reset() { - reverse.clear(); - direct.clear(); - } - -private: - std::vector reverse; - std::vector direct; -}; - - -/** - * @brief Extended sparse set implementation. - * - * This specialization of a sparse set associates an object to an entity. The - * main purpose of this class is to use sparse sets to store components in a - * Registry. It guarantees fast access both to the elements and to the entities. - * - * @note - * Entities and objects have the same order. It's guaranteed both in case of raw - * access (either to entities or objects) and when using input iterators. - * - * @note - * Internal data structures arrange elements to maximize performance. Because of - * that, there are no guarantees that elements have the expected order when - * iterate directly the internal packed array (see `raw` and `size` member - * functions for that). Use `begin` and `end` instead. - * - * @sa SparseSet - * - * @tparam Entity A valid entity type (see entt_traits for more details). - * @tparam Type Type of objects assigned to the entities. - */ -template -class SparseSet: public SparseSet { - using underlying_type = SparseSet; - using traits_type = entt_traits; - - template - class Iterator final { - friend class SparseSet; - - using instance_type = std::conditional_t, std::vector>; - using index_type = typename traits_type::difference_type; - - Iterator(instance_type *instances, index_type index) ENTT_NOEXCEPT - : instances{instances}, index{index} - {} - - public: - using difference_type = index_type; - using value_type = std::conditional_t; - using pointer = value_type *; - using reference = value_type &; - using iterator_category = std::random_access_iterator_tag; - - Iterator() ENTT_NOEXCEPT = default; - - Iterator(const Iterator &) ENTT_NOEXCEPT = default; - Iterator & operator=(const Iterator &) ENTT_NOEXCEPT = default; - - Iterator & operator++() ENTT_NOEXCEPT { - return --index, *this; - } - - Iterator operator++(int) ENTT_NOEXCEPT { - Iterator orig = *this; - return ++(*this), orig; - } - - Iterator & operator--() ENTT_NOEXCEPT { - return ++index, *this; - } - - Iterator operator--(int) ENTT_NOEXCEPT { - Iterator orig = *this; - return --(*this), orig; - } - - Iterator & operator+=(const difference_type value) ENTT_NOEXCEPT { - index -= value; - return *this; - } - - Iterator operator+(const difference_type value) const ENTT_NOEXCEPT { - return Iterator{instances, index-value}; - } - - inline Iterator & operator-=(const difference_type value) ENTT_NOEXCEPT { - return (*this += -value); - } - - inline Iterator operator-(const difference_type value) const ENTT_NOEXCEPT { - return (*this + -value); - } - - difference_type operator-(const Iterator &other) const ENTT_NOEXCEPT { - return other.index - index; - } - - reference operator[](const difference_type value) const ENTT_NOEXCEPT { - const auto pos = size_type(index-value-1); - return (*instances)[pos]; - } - - bool operator==(const Iterator &other) const ENTT_NOEXCEPT { - return other.index == index; - } - - inline bool operator!=(const Iterator &other) const ENTT_NOEXCEPT { - return !(*this == other); - } - - bool operator<(const Iterator &other) const ENTT_NOEXCEPT { - return index > other.index; - } - - bool operator>(const Iterator &other) const ENTT_NOEXCEPT { - return index < other.index; - } - - inline bool operator<=(const Iterator &other) const ENTT_NOEXCEPT { - return !(*this > other); - } - - inline bool operator>=(const Iterator &other) const ENTT_NOEXCEPT { - return !(*this < other); - } - - pointer operator->() const ENTT_NOEXCEPT { - const auto pos = size_type(index-1); - return &(*instances)[pos]; - } - - inline reference operator*() const ENTT_NOEXCEPT { - return *operator->(); - } - - private: - instance_type *instances; - index_type index; - }; - -public: - /*! @brief Type of the objects associated to the entities. */ - using object_type = Type; - /*! @brief Underlying entity identifier. */ - using entity_type = typename underlying_type::entity_type; - /*! @brief Unsigned integer type. */ - using size_type = typename underlying_type::size_type; - /*! @brief Input iterator type. */ - using iterator_type = Iterator; - /*! @brief Constant input iterator type. */ - using const_iterator_type = Iterator; - - /*! @brief Default constructor. */ - SparseSet() ENTT_NOEXCEPT = default; - - /*! @brief Copying a sparse set isn't allowed. */ - SparseSet(const SparseSet &) = delete; - /*! @brief Default move constructor. */ - SparseSet(SparseSet &&) = default; - - /*! @brief Copying a sparse set isn't allowed. @return This sparse set. */ - SparseSet & operator=(const SparseSet &) = delete; - /*! @brief Default move assignment operator. @return This sparse set. */ - SparseSet & operator=(SparseSet &&) = default; - - /** - * @brief Increases the capacity of a sparse set. - * - * If the new capacity is greater than the current capacity, new storage is - * allocated, otherwise the method does nothing. - * - * @param cap Desired capacity. - */ - void reserve(const size_type cap) { - underlying_type::reserve(cap); - instances.reserve(cap); - } - - /** - * @brief Direct access to the array of objects. - * - * The returned pointer is such that range `[raw(), raw() + size()]` is - * always a valid range, even if the container is empty. - * - * @note - * There are no guarantees on the order, even though either `sort` or - * `respect` has been previously invoked. Internal data structures arrange - * elements to maximize performance. Accessing them directly gives a - * performance boost but less guarantees. Use `begin` and `end` if you want - * to iterate the sparse set in the expected order. - * - * @return A pointer to the array of objects. - */ - const object_type * raw() const ENTT_NOEXCEPT { - return instances.data(); - } - - /** - * @brief Direct access to the array of objects. - * - * The returned pointer is such that range `[raw(), raw() + size()]` is - * always a valid range, even if the container is empty. - * - * @note - * There are no guarantees on the order, even though either `sort` or - * `respect` has been previously invoked. Internal data structures arrange - * elements to maximize performance. Accessing them directly gives a - * performance boost but less guarantees. Use `begin` and `end` if you want - * to iterate the sparse set in the expected order. - * - * @return A pointer to the array of objects. - */ - object_type * raw() ENTT_NOEXCEPT { - return instances.data(); - } - - /** - * @brief Returns an iterator to the beginning. - * - * The returned iterator points to the first instance of the given type. If - * the sparse set is empty, the returned iterator will be equal to `end()`. - * - * @note - * Input iterators stay true to the order imposed by a call to either `sort` - * or `respect`. - * - * @return An iterator to the first instance of the given type. - */ - const_iterator_type cbegin() const ENTT_NOEXCEPT { - const typename traits_type::difference_type pos = instances.size(); - return const_iterator_type{&instances, pos}; - } - - /** - * @brief Returns an iterator to the beginning. - * - * The returned iterator points to the first instance of the given type. If - * the sparse set is empty, the returned iterator will be equal to `end()`. - * - * @note - * Input iterators stay true to the order imposed by a call to either `sort` - * or `respect`. - * - * @return An iterator to the first instance of the given type. - */ - inline const_iterator_type begin() const ENTT_NOEXCEPT { - return cbegin(); - } - - /** - * @brief Returns an iterator to the beginning. - * - * The returned iterator points to the first instance of the given type. If - * the sparse set is empty, the returned iterator will be equal to `end()`. - * - * @note - * Input iterators stay true to the order imposed by a call to either `sort` - * or `respect`. - * - * @return An iterator to the first instance of the given type. - */ - iterator_type begin() ENTT_NOEXCEPT { - const typename traits_type::difference_type pos = instances.size(); - return iterator_type{&instances, pos}; - } - - /** - * @brief Returns an iterator to the end. - * - * The returned iterator points to the element following the last instance - * of the given type. Attempting to dereference the returned iterator - * results in undefined behavior. - * - * @note - * Input iterators stay true to the order imposed by a call to either `sort` - * or `respect`. - * - * @return An iterator to the element following the last instance of the - * given type. - */ - const_iterator_type cend() const ENTT_NOEXCEPT { - return const_iterator_type{&instances, {}}; - } - - /** - * @brief Returns an iterator to the end. - * - * The returned iterator points to the element following the last instance - * of the given type. Attempting to dereference the returned iterator - * results in undefined behavior. - * - * @note - * Input iterators stay true to the order imposed by a call to either `sort` - * or `respect`. - * - * @return An iterator to the element following the last instance of the - * given type. - */ - inline const_iterator_type end() const ENTT_NOEXCEPT { - return cend(); - } - - /** - * @brief Returns an iterator to the end. - * - * The returned iterator points to the element following the last instance - * of the given type. Attempting to dereference the returned iterator - * results in undefined behavior. - * - * @note - * Input iterators stay true to the order imposed by a call to either `sort` - * or `respect`. - * - * @return An iterator to the element following the last instance of the - * given type. - */ - iterator_type end() ENTT_NOEXCEPT { - return iterator_type{&instances, {}}; - } - - /** - * @brief Returns a reference to the element at the given position. - * @param pos Position of the element to return. - * @return A reference to the requested element. - */ - inline const object_type & operator[](const size_type pos) const ENTT_NOEXCEPT { - return cbegin()[pos]; - } - - /** - * @brief Returns a reference to the element at the given position. - * @param pos Position of the element to return. - * @return A reference to the requested element. - */ - inline object_type & operator[](const size_type pos) ENTT_NOEXCEPT { - return const_cast(const_cast(this)->operator[](pos)); - } - - /** - * @brief Returns the object associated to an entity. - * - * @warning - * Attempting to use an entity that doesn't belong to the sparse set results - * in undefined behavior.
- * An assertion will abort the execution at runtime in debug mode if the - * sparse set doesn't contain the given entity. - * - * @param entity A valid entity identifier. - * @return The object associated to the entity. - */ - const object_type & get(const entity_type entity) const ENTT_NOEXCEPT { - return instances[underlying_type::get(entity)]; - } - - /** - * @brief Returns the object associated to an entity. - * - * @warning - * Attempting to use an entity that doesn't belong to the sparse set results - * in undefined behavior.
- * An assertion will abort the execution at runtime in debug mode if the - * sparse set doesn't contain the given entity. - * - * @param entity A valid entity identifier. - * @return The object associated to the entity. - */ - inline object_type & get(const entity_type entity) ENTT_NOEXCEPT { - return const_cast(const_cast(this)->get(entity)); - } - - /** - * @brief Assigns an entity to a sparse set and constructs its object. - * - * @note - * _Sfinae'd_ function.
- * This version is used for types that can be constructed in place directly. - * It doesn't work well with aggregates because of the placement new usually - * performed under the hood during an _emplace back_. - * - * @warning - * Attempting to use an entity that already belongs to the sparse set - * results in undefined behavior.
- * An assertion will abort the execution at runtime in debug mode if the - * sparse set already contains the given entity. - * - * @tparam Args Types of arguments to use to construct the object. - * @param entity A valid entity identifier. - * @param args Parameters to use to construct an object for the entity. - * @return The object associated to the entity. - */ - template - std::enable_if_t::value, object_type &> - construct(const entity_type entity, Args &&... args) { - underlying_type::construct(entity); - instances.emplace_back(std::forward(args)...); - return instances.back(); - } - - /** - * @brief Assigns an entity to a sparse set and constructs its object. - * - * @note - * _Sfinae'd_ function.
- * Fallback for aggregates and types in general that do not work well with a - * placement new as performed usually under the hood during an - * _emplace back_. - * - * @warning - * Attempting to use an entity that already belongs to the sparse set - * results in undefined behavior.
- * An assertion will abort the execution at runtime in debug mode if the - * sparse set already contains the given entity. - * - * @tparam Args Types of arguments to use to construct the object. - * @param entity A valid entity identifier. - * @param args Parameters to use to construct an object for the entity. - * @return The object associated to the entity. - */ - template - std::enable_if_t::value, object_type &> - construct(const entity_type entity, Args &&... args) { - underlying_type::construct(entity); - instances.emplace_back(Type{std::forward(args)...}); - return instances.back(); - } - - /** - * @brief Removes an entity from a sparse set and destroies its object. - * - * @warning - * Attempting to use an entity that doesn't belong to the sparse set results - * in undefined behavior.
- * An assertion will abort the execution at runtime in debug mode if the - * sparse set doesn't contain the given entity. - * - * @param entity A valid entity identifier. - */ - void destroy(const entity_type entity) override { - // swapping isn't required here, we are getting rid of the last element - // however, we must protect ourselves from self assignments (see #37) - auto tmp = std::move(instances.back()); - instances[underlying_type::get(entity)] = std::move(tmp); - instances.pop_back(); - underlying_type::destroy(entity); - } - - /** - * @brief Sort components according to the given comparison function. - * - * Sort the elements so that iterating the sparse set with a couple of - * iterators returns them in the expected order. See `begin` and `end` for - * more details. - * - * The comparison function object must return `true` if the first element - * is _less_ than the second one, `false` otherwise. The signature of the - * comparison function should be equivalent to the following: - * - * @code{.cpp} - * bool(const Type &, const Type &) - * @endcode - * - * Moreover, the comparison function object shall induce a - * _strict weak ordering_ on the values. - * - * The sort function oject must offer a member function template - * `operator()` that accepts three arguments: - * - * * An iterator to the first element of the range to sort. - * * An iterator past the last element of the range to sort. - * * A comparison function to use to compare the elements. - * - * The comparison funtion object received by the sort function object hasn't - * necessarily the type of the one passed along with the other parameters to - * this member function. - * - * @note - * Attempting to iterate elements using a raw pointer returned by a call to - * either `data` or `raw` gives no guarantees on the order, even though - * `sort` has been invoked. - * - * @tparam Compare Type of comparison function object. - * @tparam Sort Type of sort function object. - * @tparam Args Types of arguments to forward to the sort function object. - * @param compare A valid comparison function object. - * @param sort A valid sort function object. - * @param args Arguments to forward to the sort function object, if any. - */ - template - void sort(Compare compare, Sort sort = Sort{}, Args &&... args) { - std::vector copy(instances.size()); - std::iota(copy.begin(), copy.end(), 0); - - sort(copy.begin(), copy.end(), [this, compare = std::move(compare)](const auto lhs, const auto rhs) { - return compare(const_cast(instances[rhs]), const_cast(instances[lhs])); - }, std::forward(args)...); - - for(size_type pos = 0, last = copy.size(); pos < last; ++pos) { - auto curr = pos; - auto next = copy[curr]; - - while(curr != next) { - const auto lhs = copy[curr]; - const auto rhs = copy[next]; - std::swap(instances[lhs], instances[rhs]); - underlying_type::swap(lhs, rhs); - copy[curr] = curr; - curr = next; - next = copy[curr]; - } - } - } - - /** - * @brief Sort components according to the order of the entities in another - * sparse set. - * - * Entities that are part of both the sparse sets are ordered internally - * according to the order they have in `other`. All the other entities goes - * to the end of the list and there are no guarantess on their order. - * Components are sorted according to the entities to which they - * belong.
- * In other terms, this function can be used to impose the same order on two - * sets by using one of them as a master and the other one as a slave. - * - * Iterating the sparse set with a couple of iterators returns elements in - * the expected order after a call to `respect`. See `begin` and `end` for - * more details. - * - * @note - * Attempting to iterate elements using a raw pointer returned by a call to - * either `data` or `raw` gives no guarantees on the order, even though - * `respect` has been invoked. - * - * @param other The sparse sets that imposes the order of the entities. - */ - void respect(const SparseSet &other) ENTT_NOEXCEPT { - auto from = other.cbegin(); - auto to = other.cend(); - - size_type pos = underlying_type::size() - 1; - const auto *local = underlying_type::data(); - - while(pos && from != to) { - const auto curr = *from; - - if(underlying_type::has(curr)) { - if(curr != *(local + pos)) { - auto candidate = underlying_type::get(curr); - std::swap(instances[pos], instances[candidate]); - underlying_type::swap(pos, candidate); - } - - --pos; - } - - ++from; - } - } - - /** - * @brief Resets a sparse set. - */ - void reset() override { - underlying_type::reset(); - instances.clear(); - } - -private: - std::vector instances; -}; - - -} - - -#endif // ENTT_ENTITY_SPARSE_SET_HPP diff --git a/external/entt/entity/utility.hpp b/external/entt/entity/utility.hpp deleted file mode 100644 index 31f138e32..000000000 --- a/external/entt/entity/utility.hpp +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef ENTT_ENTITY_UTILITY_HPP -#define ENTT_ENTITY_UTILITY_HPP - - -namespace entt { - - -/*! @brief Tag class type used to disambiguate overloads. */ -struct tag_t final {}; - - -/*! @brief Persistent view type used to disambiguate overloads. */ -struct persistent_t final {}; - - -/*! @brief Raw view type used to disambiguate overloads. */ -struct raw_t final {}; - - -} - - -#endif // ENTT_ENTITY_UTILITY_HPP diff --git a/external/entt/entity/view.hpp b/external/entt/entity/view.hpp deleted file mode 100644 index 214f862af..000000000 --- a/external/entt/entity/view.hpp +++ /dev/null @@ -1,1889 +0,0 @@ -#ifndef ENTT_ENTITY_VIEW_HPP -#define ENTT_ENTITY_VIEW_HPP - - -#include -#include -#include -#include -#include -#include -#include -#include -#include "../config/config.h" -#include "entt_traits.hpp" -#include "sparse_set.hpp" - - -namespace entt { - - -/** - * @brief Forward declaration of the registry class. - */ -template -class Registry; - - -/** - * @brief Persistent view. - * - * A persistent view returns all the entities and only the entities that have - * at least the given components. Moreover, it's guaranteed that the entity list - * is tightly packed in memory for fast iterations.
- * In general, persistent views don't stay true to the order of any set of - * components unless users explicitly sort them. - * - * @b Important - * - * Iterators aren't invalidated if: - * - * * New instances of the given components are created and assigned to entities. - * * The entity currently pointed is modified (as an example, if one of the - * given components is removed from the entity to which the iterator points). - * - * In all the other cases, modifying the pools of the given components in any - * way invalidates all the iterators and using them results in undefined - * behavior. - * - * @note - * Views share references to the underlying data structures with the Registry - * that generated them. Therefore any change to the entities and to the - * components made by means of the registry are immediately reflected by - * views.
- * Moreover, sorting a persistent view affects all the other views of the same - * type (it means that users don't have to call `sort` on each view to sort all - * of them because they share the set of entities). - * - * @warning - * Lifetime of a view must overcome the one of the registry that generated it. - * In any other case, attempting to use a view results in undefined behavior. - * - * @sa View - * @sa View - * @sa RawView - * @sa RuntimeView - * - * @tparam Entity A valid entity type (see entt_traits for more details). - * @tparam Component Types of components iterated by the view. - */ -template -class PersistentView final { - static_assert(sizeof...(Component) > 1, "!"); - - /*! @brief A registry is allowed to create views. */ - friend class Registry; - - template - using pool_type = SparseSet; - - using view_type = SparseSet; - using pattern_type = std::tuple &...>; - - PersistentView(view_type &view, pool_type &... pools) ENTT_NOEXCEPT - : view{view}, pools{pools...} - {} - -public: - /*! @brief Underlying entity identifier. */ - using entity_type = typename view_type::entity_type; - /*! @brief Unsigned integer type. */ - using size_type = typename view_type::size_type; - /*! @brief Input iterator type. */ - using iterator_type = typename view_type::iterator_type; - /*! @brief Constant input iterator type. */ - using const_iterator_type = typename view_type::const_iterator_type; - - /** - * @brief Returns the number of entities that have the given components. - * @return Number of entities that have the given components. - */ - size_type size() const ENTT_NOEXCEPT { - return view.size(); - } - - /** - * @brief Checks whether the view is empty. - * @return True if the view is empty, false otherwise. - */ - bool empty() const ENTT_NOEXCEPT { - return view.empty(); - } - - /** - * @brief Direct access to the list of entities. - * - * The returned pointer is such that range `[data(), data() + size()]` is - * always a valid range, even if the container is empty. - * - * @note - * There are no guarantees on the order of the entities. Use `begin` and - * `end` if you want to iterate the view in the expected order. - * - * @return A pointer to the array of entities. - */ - const entity_type * data() const ENTT_NOEXCEPT { - return view.data(); - } - - /** - * @brief Returns an iterator to the first entity that has the given - * components. - * - * The returned iterator points to the first entity that has the given - * components. If the view is empty, the returned iterator will be equal to - * `end()`. - * - * @note - * Input iterators stay true to the order imposed to the underlying data - * structures. - * - * @return An iterator to the first entity that has the given components. - */ - const_iterator_type cbegin() const ENTT_NOEXCEPT { - return view.cbegin(); - } - - /** - * @brief Returns an iterator to the first entity that has the given - * components. - * - * The returned iterator points to the first entity that has the given - * components. If the view is empty, the returned iterator will be equal to - * `end()`. - * - * @note - * Input iterators stay true to the order imposed to the underlying data - * structures. - * - * @return An iterator to the first entity that has the given components. - */ - inline const_iterator_type begin() const ENTT_NOEXCEPT { - return cbegin(); - } - - /** - * @brief Returns an iterator to the first entity that has the given - * components. - * - * The returned iterator points to the first entity that has the given - * components. If the view is empty, the returned iterator will be equal to - * `end()`. - * - * @note - * Input iterators stay true to the order imposed to the underlying data - * structures. - * - * @return An iterator to the first entity that has the given components. - */ - iterator_type begin() ENTT_NOEXCEPT { - return view.begin(); - } - - /** - * @brief Returns an iterator that is past the last entity that has the - * given components. - * - * The returned iterator points to the entity following the last entity that - * has the given components. Attempting to dereference the returned iterator - * results in undefined behavior. - * - * @note - * Input iterators stay true to the order imposed to the underlying data - * structures. - * - * @return An iterator to the entity following the last entity that has the - * given components. - */ - const_iterator_type cend() const ENTT_NOEXCEPT { - return view.cend(); - } - - /** - * @brief Returns an iterator that is past the last entity that has the - * given components. - * - * The returned iterator points to the entity following the last entity that - * has the given components. Attempting to dereference the returned iterator - * results in undefined behavior. - * - * @note - * Input iterators stay true to the order imposed to the underlying data - * structures. - * - * @return An iterator to the entity following the last entity that has the - * given components. - */ - inline const_iterator_type end() const ENTT_NOEXCEPT { - return cend(); - } - - /** - * @brief Returns an iterator that is past the last entity that has the - * given components. - * - * The returned iterator points to the entity following the last entity that - * has the given components. Attempting to dereference the returned iterator - * results in undefined behavior. - * - * @note - * Input iterators stay true to the order imposed to the underlying data - * structures. - * - * @return An iterator to the entity following the last entity that has the - * given components. - */ - iterator_type end() ENTT_NOEXCEPT { - return view.end(); - } - - /** - * @brief Returns a reference to the element at the given position. - * @param pos Position of the element to return. - * @return A reference to the requested element. - */ - const entity_type & operator[](const size_type pos) const ENTT_NOEXCEPT { - return view[pos]; - } - - /** - * @brief Checks if a view contains an entity. - * @param entity A valid entity identifier. - * @return True if the view contains the given entity, false otherwise. - */ - bool contains(const entity_type entity) const ENTT_NOEXCEPT { - return view.has(entity) && (view.data()[view.get(entity)] == entity); - } - - /** - * @brief Returns the component assigned to the given entity. - * - * Prefer this function instead of `Registry::get` during iterations. It has - * far better performance than its companion function. - * - * @warning - * Attempting to use an invalid component type results in a compilation - * error. Attempting to use an entity that doesn't belong to the view - * results in undefined behavior.
- * An assertion will abort the execution at runtime in debug mode if the - * view doesn't contain the given entity. - * - * @tparam Comp Type of component to get. - * @param entity A valid entity identifier. - * @return The component assigned to the entity. - */ - template - const Comp & get(const entity_type entity) const ENTT_NOEXCEPT { - assert(contains(entity)); - return std::get &>(pools).get(entity); - } - - /** - * @brief Returns the component assigned to the given entity. - * - * Prefer this function instead of `Registry::get` during iterations. It has - * far better performance than its companion function. - * - * @warning - * Attempting to use an invalid component type results in a compilation - * error. Attempting to use an entity that doesn't belong to the view - * results in undefined behavior.
- * An assertion will abort the execution at runtime in debug mode if the - * view doesn't contain the given entity. - * - * @tparam Comp Type of component to get. - * @param entity A valid entity identifier. - * @return The component assigned to the entity. - */ - template - inline Comp & get(const entity_type entity) ENTT_NOEXCEPT { - return const_cast(const_cast(this)->get(entity)); - } - - /** - * @brief Returns the components assigned to the given entity. - * - * Prefer this function instead of `Registry::get` during iterations. It has - * far better performance than its companion function. - * - * @warning - * Attempting to use invalid component types results in a compilation error. - * Attempting to use an entity that doesn't belong to the view results in - * undefined behavior.
- * An assertion will abort the execution at runtime in debug mode if the - * view doesn't contain the given entity. - * - * @tparam Comp Types of the components to get. - * @param entity A valid entity identifier. - * @return The components assigned to the entity. - */ - template - inline std::enable_if_t<(sizeof...(Comp) > 1), std::tuple> - get(const entity_type entity) const ENTT_NOEXCEPT { - assert(contains(entity)); - return std::tuple{get(entity)...}; - } - - /** - * @brief Returns the components assigned to the given entity. - * - * Prefer this function instead of `Registry::get` during iterations. It has - * far better performance than its companion function. - * - * @warning - * Attempting to use invalid component types results in a compilation error. - * Attempting to use an entity that doesn't belong to the view results in - * undefined behavior.
- * An assertion will abort the execution at runtime in debug mode if the - * view doesn't contain the given entity. - * - * @tparam Comp Types of the components to get. - * @param entity A valid entity identifier. - * @return The components assigned to the entity. - */ - template - inline std::enable_if_t<(sizeof...(Comp) > 1), std::tuple> - get(const entity_type entity) ENTT_NOEXCEPT { - assert(contains(entity)); - return std::tuple{get(entity)...}; - } - - /** - * @brief Iterates entities and components and applies the given function - * object to them. - * - * The function object is invoked for each entity. It is provided with the - * entity itself and a set of const references to all the components of the - * view.
- * The signature of the function should be equivalent to the following: - * - * @code{.cpp} - * void(const entity_type, const Component &...); - * @endcode - * - * @tparam Func Type of the function object to invoke. - * @param func A valid function object. - */ - template - void each(Func func) const { - std::for_each(view.cbegin(), view.cend(), [&func, this](const auto entity) { - func(entity, std::get &>(pools).get(entity)...); - }); - } - - /** - * @brief Iterates entities and components and applies the given function - * object to them. - * - * The function object is invoked for each entity. It is provided with the - * entity itself and a set of references to all the components of the - * view.
- * The signature of the function should be equivalent to the following: - * - * @code{.cpp} - * void(const entity_type, Component &...); - * @endcode - * - * @tparam Func Type of the function object to invoke. - * @param func A valid function object. - */ - template - inline void each(Func func) { - const_cast(this)->each([&func](const entity_type entity, const Component &... component) { - func(entity, const_cast(component)...); - }); - } - - /** - * @brief Sort the shared pool of entities according to the given component. - * - * Persistent views of the same type share with the Registry a pool of - * entities with its own order that doesn't depend on the order of any pool - * of components. Users can order the underlying data structure so that it - * respects the order of the pool of the given component. - * - * @note - * The shared pool of entities and thus its order is affected by the changes - * to each and every pool that it tracks. Therefore changes to those pools - * can quickly ruin the order imposed to the pool of entities shared between - * the persistent views. - * - * @tparam Comp Type of component to use to impose the order. - */ - template - void sort() { - view.respect(std::get &>(pools)); - } - -private: - view_type &view; - const pattern_type pools; -}; - - -/** - * @brief Multi component view. - * - * Multi component views iterate over those entities that have at least all the - * given components in their bags. During initialization, a multi component view - * looks at the number of entities available for each component and picks up a - * reference to the smallest set of candidate entities in order to get a - * performance boost when iterate.
- * Order of elements during iterations are highly dependent on the order of the - * underlying data structures. See SparseSet and its specializations for more - * details. - * - * @b Important - * - * Iterators aren't invalidated if: - * - * * New instances of the given components are created and assigned to entities. - * * The entity currently pointed is modified (as an example, if one of the - * given components is removed from the entity to which the iterator points). - * - * In all the other cases, modifying the pools of the given components in any - * way invalidates all the iterators and using them results in undefined - * behavior. - * - * @note - * Views share references to the underlying data structures with the Registry - * that generated them. Therefore any change to the entities and to the - * components made by means of the registry are immediately reflected by views. - * - * @warning - * Lifetime of a view must overcome the one of the registry that generated it. - * In any other case, attempting to use a view results in undefined behavior. - * - * @sa View - * @sa PersistentView - * @sa RawView - * @sa RuntimeView - * - * @tparam Entity A valid entity type (see entt_traits for more details). - * @tparam Component Types of components iterated by the view. - */ -template -class View final { - static_assert(sizeof...(Component) > 1, "!"); - - /*! @brief A registry is allowed to create views. */ - friend class Registry; - - template - using pool_type = SparseSet; - - template - using component_iterator_type = typename pool_type::const_iterator_type; - - using view_type = SparseSet; - using underlying_iterator_type = typename view_type::const_iterator_type; - using unchecked_type = std::array; - using pattern_type = std::tuple &...>; - using traits_type = entt_traits; - - class Iterator { - friend class View; - - using extent_type = typename view_type::size_type; - - Iterator(unchecked_type unchecked, underlying_iterator_type begin, underlying_iterator_type end) ENTT_NOEXCEPT - : unchecked{unchecked}, - begin{begin}, - end{end}, - extent{min(std::make_index_sequence{})} - { - if(begin != end && !valid()) { - ++(*this); - } - } - - template - extent_type min(std::index_sequence) const ENTT_NOEXCEPT { - return std::min({ std::get(unchecked)->extent()... }); - } - - bool valid() const ENTT_NOEXCEPT { - const auto entity = *begin; - const auto sz = size_type(entity & traits_type::entity_mask); - - return sz < extent && std::all_of(unchecked.cbegin(), unchecked.cend(), [entity](const view_type *view) { - return view->fast(entity); - }); - } - - public: - using difference_type = typename underlying_iterator_type::difference_type; - using value_type = typename underlying_iterator_type::value_type; - using pointer = typename underlying_iterator_type::pointer; - using reference = typename underlying_iterator_type::reference; - using iterator_category = std::forward_iterator_tag; - - Iterator() ENTT_NOEXCEPT = default; - - Iterator(const Iterator &) ENTT_NOEXCEPT = default; - Iterator & operator=(const Iterator &) ENTT_NOEXCEPT = default; - - Iterator & operator++() ENTT_NOEXCEPT { - return (++begin != end && !valid()) ? ++(*this) : *this; - } - - Iterator operator++(int) ENTT_NOEXCEPT { - Iterator orig = *this; - return ++(*this), orig; - } - - bool operator==(const Iterator &other) const ENTT_NOEXCEPT { - return other.begin == begin; - } - - inline bool operator!=(const Iterator &other) const ENTT_NOEXCEPT { - return !(*this == other); - } - - pointer operator->() const ENTT_NOEXCEPT { - return begin.operator->(); - } - - inline reference operator*() const ENTT_NOEXCEPT { - return *operator->(); - } - - private: - unchecked_type unchecked; - underlying_iterator_type begin; - underlying_iterator_type end; - extent_type extent; - }; - - View(pool_type &... pools) ENTT_NOEXCEPT - : pools{pools...} - {} - - template - const pool_type & pool() const ENTT_NOEXCEPT { - return std::get &>(pools); - } - - const view_type * candidate() const ENTT_NOEXCEPT { - return std::min({ static_cast(&pool())... }, [](const auto *lhs, const auto *rhs) { - return lhs->size() < rhs->size(); - }); - } - - unchecked_type unchecked(const view_type *view) const ENTT_NOEXCEPT { - unchecked_type other{}; - std::size_t pos{}; - using accumulator_type = const view_type *[]; - accumulator_type accumulator = { (&pool() == view ? view : other[pos++] = &pool())... }; - (void)accumulator; - return other; - } - - template - inline std::enable_if_t::value, const Other &> - get(const component_iterator_type &it, const Entity) const ENTT_NOEXCEPT { return *it; } - - template - inline std::enable_if_t::value, const Other &> - get(const component_iterator_type &, const Entity entity) const ENTT_NOEXCEPT { return pool().get(entity); } - - template - void each(const pool_type &cpool, Func func, std::index_sequence) const { - const auto other = unchecked(&cpool); - std::array data{{std::get(other)->cbegin()...}}; - const auto extent = std::min({ pool().extent()... }); - auto raw = std::make_tuple(pool().cbegin()...); - const auto end = cpool.view_type::cend(); - auto begin = cpool.view_type::cbegin(); - - // we can directly use the raw iterators if pools are ordered - while(begin != end && std::min({ (*(std::get(data)++) == *begin)... })) { - func(*(begin++), *(std::get>(raw)++)...); - } - - // fallback to visit what remains using indirections - while(begin != end) { - const auto entity = *(begin++); - const auto it = std::get>(raw)++; - const auto sz = size_type(entity & traits_type::entity_mask); - - if(sz < extent && std::all_of(other.cbegin(), other.cend(), [entity](const view_type *view) { return view->fast(entity); })) { - // avoided at least the indirection due to the sparse set for the pivot type (see get for more details) - func(entity, get(it, entity)...); - } - } - } - -public: - /*! @brief Underlying entity identifier. */ - using entity_type = typename view_type::entity_type; - /*! @brief Unsigned integer type. */ - using size_type = typename view_type::size_type; - /*! @brief Input iterator type. */ - using iterator_type = Iterator; - /*! @brief Constant input iterator type. */ - using const_iterator_type = Iterator; - - /** - * @brief Estimates the number of entities that have the given components. - * @return Estimated number of entities that have the given components. - */ - size_type size() const ENTT_NOEXCEPT { - return std::min({ pool().size()... }); - } - - /** - * @brief Checks if the view is definitely empty. - * @return True if the view is definitely empty, false otherwise. - */ - bool empty() const ENTT_NOEXCEPT { - return std::max({ pool().empty()... }); - } - - /** - * @brief Returns an iterator to the first entity that has the given - * components. - * - * The returned iterator points to the first entity that has the given - * components. If the view is empty, the returned iterator will be equal to - * `end()`. - * - * @note - * Input iterators stay true to the order imposed to the underlying data - * structures. - * - * @return An iterator to the first entity that has the given components. - */ - const_iterator_type cbegin() const ENTT_NOEXCEPT { - const auto *view = candidate(); - return const_iterator_type{unchecked(view), view->cbegin(), view->cend()}; - } - - /** - * @brief Returns an iterator to the first entity that has the given - * components. - * - * The returned iterator points to the first entity that has the given - * components. If the view is empty, the returned iterator will be equal to - * `end()`. - * - * @note - * Input iterators stay true to the order imposed to the underlying data - * structures. - * - * @return An iterator to the first entity that has the given components. - */ - inline const_iterator_type begin() const ENTT_NOEXCEPT { - return cbegin(); - } - - /** - * @brief Returns an iterator to the first entity that has the given - * components. - * - * The returned iterator points to the first entity that has the given - * components. If the view is empty, the returned iterator will be equal to - * `end()`. - * - * @note - * Input iterators stay true to the order imposed to the underlying data - * structures. - * - * @return An iterator to the first entity that has the given components. - */ - inline iterator_type begin() ENTT_NOEXCEPT { - return cbegin(); - } - - /** - * @brief Returns an iterator that is past the last entity that has the - * given components. - * - * The returned iterator points to the entity following the last entity that - * has the given components. Attempting to dereference the returned iterator - * results in undefined behavior. - * - * @note - * Input iterators stay true to the order imposed to the underlying data - * structures. - * - * @return An iterator to the entity following the last entity that has the - * given components. - */ - const_iterator_type cend() const ENTT_NOEXCEPT { - const auto *view = candidate(); - return const_iterator_type{unchecked(view), view->cend(), view->cend()}; - } - - /** - * @brief Returns an iterator that is past the last entity that has the - * given components. - * - * The returned iterator points to the entity following the last entity that - * has the given components. Attempting to dereference the returned iterator - * results in undefined behavior. - * - * @note - * Input iterators stay true to the order imposed to the underlying data - * structures. - * - * @return An iterator to the entity following the last entity that has the - * given components. - */ - inline const_iterator_type end() const ENTT_NOEXCEPT { - return cend(); - } - - /** - * @brief Returns an iterator that is past the last entity that has the - * given components. - * - * The returned iterator points to the entity following the last entity that - * has the given components. Attempting to dereference the returned iterator - * results in undefined behavior. - * - * @note - * Input iterators stay true to the order imposed to the underlying data - * structures. - * - * @return An iterator to the entity following the last entity that has the - * given components. - */ - inline iterator_type end() ENTT_NOEXCEPT { - return cend(); - } - - /** - * @brief Checks if a view contains an entity. - * @param entity A valid entity identifier. - * @return True if the view contains the given entity, false otherwise. - */ - bool contains(const entity_type entity) const ENTT_NOEXCEPT { - const auto sz = size_type(entity & traits_type::entity_mask); - const auto extent = std::min({ pool().extent()... }); - return sz < extent && std::min({ (pool().has(entity) && (pool().data()[pool().view_type::get(entity)] == entity))... }); - } - - /** - * @brief Returns the component assigned to the given entity. - * - * Prefer this function instead of `Registry::get` during iterations. It has - * far better performance than its companion function. - * - * @warning - * Attempting to use an invalid component type results in a compilation - * error. Attempting to use an entity that doesn't belong to the view - * results in undefined behavior.
- * An assertion will abort the execution at runtime in debug mode if the - * view doesn't contain the given entity. - * - * @tparam Comp Type of component to get. - * @param entity A valid entity identifier. - * @return The component assigned to the entity. - */ - template - const Comp & get(const entity_type entity) const ENTT_NOEXCEPT { - assert(contains(entity)); - return pool().get(entity); - } - - /** - * @brief Returns the component assigned to the given entity. - * - * Prefer this function instead of `Registry::get` during iterations. It has - * far better performance than its companion function. - * - * @warning - * Attempting to use an invalid component type results in a compilation - * error. Attempting to use an entity that doesn't belong to the view - * results in undefined behavior.
- * An assertion will abort the execution at runtime in debug mode if the - * view doesn't contain the given entity. - * - * @tparam Comp Type of component to get. - * @param entity A valid entity identifier. - * @return The component assigned to the entity. - */ - template - inline Comp & get(const entity_type entity) ENTT_NOEXCEPT { - return const_cast(const_cast(this)->get(entity)); - } - - /** - * @brief Returns the components assigned to the given entity. - * - * Prefer this function instead of `Registry::get` during iterations. It has - * far better performance than its companion function. - * - * @warning - * Attempting to use invalid component types results in a compilation error. - * Attempting to use an entity that doesn't belong to the view results in - * undefined behavior.
- * An assertion will abort the execution at runtime in debug mode if the - * view doesn't contain the given entity. - * - * @tparam Comp Types of the components to get. - * @param entity A valid entity identifier. - * @return The components assigned to the entity. - */ - template - inline std::enable_if_t<(sizeof...(Comp) > 1), std::tuple> - get(const entity_type entity) const ENTT_NOEXCEPT { - assert(contains(entity)); - return std::tuple{get(entity)...}; - } - - /** - * @brief Returns the components assigned to the given entity. - * - * Prefer this function instead of `Registry::get` during iterations. It has - * far better performance than its companion function. - * - * @warning - * Attempting to use invalid component types results in a compilation error. - * Attempting to use an entity that doesn't belong to the view results in - * undefined behavior.
- * An assertion will abort the execution at runtime in debug mode if the - * view doesn't contain the given entity. - * - * @tparam Comp Types of the components to get. - * @param entity A valid entity identifier. - * @return The components assigned to the entity. - */ - template - inline std::enable_if_t<(sizeof...(Comp) > 1), std::tuple> - get(const entity_type entity) ENTT_NOEXCEPT { - assert(contains(entity)); - return std::tuple{get(entity)...}; - } - - /** - * @brief Iterates entities and components and applies the given function - * object to them. - * - * The function object is invoked for each entity. It is provided with the - * entity itself and a set of const references to all the components of the - * view.
- * The signature of the function should be equivalent to the following: - * - * @code{.cpp} - * void(const entity_type, const Component &...); - * @endcode - * - * @tparam Func Type of the function object to invoke. - * @param func A valid function object. - */ - template - void each(Func func) const { - const auto *view = candidate(); - using accumulator_type = int[]; - accumulator_type accumulator = { (&pool() == view ? (each(pool(), std::move(func), std::make_index_sequence{}), 0) : 0)... }; - (void)accumulator; - } - - /** - * @brief Iterates entities and components and applies the given function - * object to them. - * - * The function object is invoked for each entity. It is provided with the - * entity itself and a set of references to all the components of the - * view.
- * The signature of the function should be equivalent to the following: - * - * @code{.cpp} - * void(const entity_type, Component &...); - * @endcode - * - * @tparam Func Type of the function object to invoke. - * @param func A valid function object. - */ - template - inline void each(Func func) { - const_cast(this)->each([&func](const entity_type entity, const Component &... component) { - func(entity, const_cast(component)...); - }); - } - -private: - const pattern_type pools; -}; - - -/** - * @brief Single component view specialization. - * - * Single component views are specialized in order to get a boost in terms of - * performance. This kind of views can access the underlying data structure - * directly and avoid superfluous checks.
- * Order of elements during iterations are highly dependent on the order of the - * underlying data structure. See SparseSet and its specializations for more - * details. - * - * @b Important - * - * Iterators aren't invalidated if: - * - * * New instances of the given component are created and assigned to entities. - * * The entity currently pointed is modified (as an example, the given - * component is removed from the entity to which the iterator points). - * - * In all the other cases, modifying the pool of the given component in any way - * invalidates all the iterators and using them results in undefined behavior. - * - * @note - * Views share a reference to the underlying data structure with the Registry - * that generated them. Therefore any change to the entities and to the - * components made by means of the registry are immediately reflected by views. - * - * @warning - * Lifetime of a view must overcome the one of the registry that generated it. - * In any other case, attempting to use a view results in undefined behavior. - * - * @sa View - * @sa PersistentView - * @sa RawView - * @sa RuntimeView - * - * @tparam Entity A valid entity type (see entt_traits for more details). - * @tparam Component Type of component iterated by the view. - */ -template -class View final { - /*! @brief A registry is allowed to create views. */ - friend class Registry; - - using view_type = SparseSet; - using pool_type = SparseSet; - - View(pool_type &pool) ENTT_NOEXCEPT - : pool{pool} - {} - -public: - /*! @brief Type of component iterated by the view. */ - using raw_type = typename pool_type::object_type; - /*! @brief Underlying entity identifier. */ - using entity_type = typename pool_type::entity_type; - /*! @brief Unsigned integer type. */ - using size_type = typename pool_type::size_type; - /*! @brief Input iterator type. */ - using iterator_type = typename view_type::iterator_type; - /*! @brief Constant input iterator type. */ - using const_iterator_type = typename view_type::const_iterator_type; - - /** - * @brief Returns the number of entities that have the given component. - * @return Number of entities that have the given component. - */ - size_type size() const ENTT_NOEXCEPT { - return pool.size(); - } - - /** - * @brief Checks whether the view is empty. - * @return True if the view is empty, false otherwise. - */ - bool empty() const ENTT_NOEXCEPT { - return pool.empty(); - } - - /** - * @brief Direct access to the list of components. - * - * The returned pointer is such that range `[raw(), raw() + size()]` is - * always a valid range, even if the container is empty. - * - * @note - * There are no guarantees on the order of the components. Use `begin` and - * `end` if you want to iterate the view in the expected order. - * - * @return A pointer to the array of components. - */ - const raw_type * raw() const ENTT_NOEXCEPT { - return pool.raw(); - } - - /** - * @brief Direct access to the list of components. - * - * The returned pointer is such that range `[raw(), raw() + size()]` is - * always a valid range, even if the container is empty. - * - * @note - * There are no guarantees on the order of the components. Use `begin` and - * `end` if you want to iterate the view in the expected order. - * - * @return A pointer to the array of components. - */ - inline raw_type * raw() ENTT_NOEXCEPT { - return const_cast(const_cast(this)->raw()); - } - - /** - * @brief Direct access to the list of entities. - * - * The returned pointer is such that range `[data(), data() + size()]` is - * always a valid range, even if the container is empty. - * - * @note - * There are no guarantees on the order of the entities. Use `begin` and - * `end` if you want to iterate the view in the expected order. - * - * @return A pointer to the array of entities. - */ - const entity_type * data() const ENTT_NOEXCEPT { - return pool.data(); - } - - /** - * @brief Returns an iterator to the first entity that has the given - * component. - * - * The returned iterator points to the first entity that has the given - * component. If the view is empty, the returned iterator will be equal to - * `end()`. - * - * @note - * Input iterators stay true to the order imposed to the underlying data - * structures. - * - * @return An iterator to the first entity that has the given component. - */ - const_iterator_type cbegin() const ENTT_NOEXCEPT { - return pool.view_type::cbegin(); - } - - /** - * @brief Returns an iterator to the first entity that has the given - * component. - * - * The returned iterator points to the first entity that has the given - * component. If the view is empty, the returned iterator will be equal to - * `end()`. - * - * @note - * Input iterators stay true to the order imposed to the underlying data - * structures. - * - * @return An iterator to the first entity that has the given component. - */ - inline const_iterator_type begin() const ENTT_NOEXCEPT { - return cbegin(); - } - - /** - * @brief Returns an iterator to the first entity that has the given - * component. - * - * The returned iterator points to the first entity that has the given - * component. If the view is empty, the returned iterator will be equal to - * `end()`. - * - * @note - * Input iterators stay true to the order imposed to the underlying data - * structures. - * - * @return An iterator to the first entity that has the given component. - */ - iterator_type begin() ENTT_NOEXCEPT { - return pool.view_type::begin(); - } - - /** - * @brief Returns an iterator that is past the last entity that has the - * given component. - * - * The returned iterator points to the entity following the last entity that - * has the given component. Attempting to dereference the returned iterator - * results in undefined behavior. - * - * @note - * Input iterators stay true to the order imposed to the underlying data - * structures. - * - * @return An iterator to the entity following the last entity that has the - * given component. - */ - const_iterator_type cend() const ENTT_NOEXCEPT { - return pool.view_type::cend(); - } - - /** - * @brief Returns an iterator that is past the last entity that has the - * given component. - * - * The returned iterator points to the entity following the last entity that - * has the given component. Attempting to dereference the returned iterator - * results in undefined behavior. - * - * @note - * Input iterators stay true to the order imposed to the underlying data - * structures. - * - * @return An iterator to the entity following the last entity that has the - * given component. - */ - inline const_iterator_type end() const ENTT_NOEXCEPT { - return cend(); - } - - /** - * @brief Returns an iterator that is past the last entity that has the - * given component. - * - * The returned iterator points to the entity following the last entity that - * has the given component. Attempting to dereference the returned iterator - * results in undefined behavior. - * - * @note - * Input iterators stay true to the order imposed to the underlying data - * structures. - * - * @return An iterator to the entity following the last entity that has the - * given component. - */ - iterator_type end() ENTT_NOEXCEPT { - return pool.view_type::end(); - } - - /** - * @brief Returns a reference to the element at the given position. - * @param pos Position of the element to return. - * @return A reference to the requested element. - */ - const entity_type & operator[](const size_type pos) const ENTT_NOEXCEPT { - return pool.view_type::operator[](pos); - } - - /** - * @brief Checks if a view contains an entity. - * @param entity A valid entity identifier. - * @return True if the view contains the given entity, false otherwise. - */ - bool contains(const entity_type entity) const ENTT_NOEXCEPT { - return pool.has(entity) && (pool.data()[pool.view_type::get(entity)] == entity); - } - - /** - * @brief Returns the component assigned to the given entity. - * - * Prefer this function instead of `Registry::get` during iterations. It has - * far better performance than its companion function. - * - * @warning - * Attempting to use an entity that doesn't belong to the view results in - * undefined behavior.
- * An assertion will abort the execution at runtime in debug mode if the - * view doesn't contain the given entity. - * - * @param entity A valid entity identifier. - * @return The component assigned to the entity. - */ - const Component & get(const entity_type entity) const ENTT_NOEXCEPT { - assert(contains(entity)); - return pool.get(entity); - } - - /** - * @brief Returns the component assigned to the given entity. - * - * Prefer this function instead of `Registry::get` during iterations. It has - * far better performance than its companion function. - * - * @warning - * Attempting to use an entity that doesn't belong to the view results in - * undefined behavior.
- * An assertion will abort the execution at runtime in debug mode if the - * view doesn't contain the given entity. - * - * @param entity A valid entity identifier. - * @return The component assigned to the entity. - */ - inline Component & get(const entity_type entity) ENTT_NOEXCEPT { - return const_cast(const_cast(this)->get(entity)); - } - - /** - * @brief Iterates entities and components and applies the given function - * object to them. - * - * The function object is invoked for each entity. It is provided with the - * entity itself and a const reference to the component of the view.
- * The signature of the function should be equivalent to the following: - * - * @code{.cpp} - * void(const entity_type, const Component &); - * @endcode - * - * @tparam Func Type of the function object to invoke. - * @param func A valid function object. - */ - template - void each(Func func) const { - std::for_each(pool.view_type::cbegin(), pool.view_type::cend(), [&func, raw = pool.cbegin()](const auto entity) mutable { - func(entity, *(raw++)); - }); - } - - /** - * @brief Iterates entities and components and applies the given function - * object to them. - * - * The function object is invoked for each entity. It is provided with the - * entity itself and a reference to the component of the view.
- * The signature of the function should be equivalent to the following: - * - * @code{.cpp} - * void(const entity_type, Component &); - * @endcode - * - * @tparam Func Type of the function object to invoke. - * @param func A valid function object. - */ - template - inline void each(Func func) { - const_cast(this)->each([&func](const entity_type entity, const Component &component) { - func(entity, const_cast(component)); - }); - } - -private: - pool_type &pool; -}; - - -/** - * @brief Raw view. - * - * Raw views are meant to easily iterate components without having to resort to - * using any other member function, so as to further increase the performance. - * Whenever knowing the entity to which a component belongs isn't required, this - * should be the preferred tool.
- * Order of elements during iterations are highly dependent on the order of the - * underlying data structure. See SparseSet and its specializations for more - * details. - * - * @b Important - * - * Iterators aren't invalidated if: - * - * * New instances of the given component are created and assigned to entities. - * * The entity to which the component belongs is modified (as an example, the - * given component is destroyed). - * - * In all the other cases, modifying the pool of the given component in any way - * invalidates all the iterators and using them results in undefined behavior. - * - * @note - * Views share a reference to the underlying data structure with the Registry - * that generated them. Therefore any change to the entities and to the - * components made by means of the registry are immediately reflected by views. - * - * @warning - * Lifetime of a view must overcome the one of the registry that generated it. - * In any other case, attempting to use a view results in undefined behavior. - * - * @sa View - * @sa View - * @sa PersistentView - * @sa RuntimeView - * - * @tparam Entity A valid entity type (see entt_traits for more details). - * @tparam Component Type of component iterated by the view. - */ -template -class RawView final { - /*! @brief A registry is allowed to create views. */ - friend class Registry; - - using pool_type = SparseSet; - - RawView(pool_type &pool) ENTT_NOEXCEPT - : pool{pool} - {} - -public: - /*! @brief Type of component iterated by the view. */ - using raw_type = typename pool_type::object_type; - /*! @brief Underlying entity identifier. */ - using entity_type = typename pool_type::entity_type; - /*! @brief Unsigned integer type. */ - using size_type = typename pool_type::size_type; - /*! @brief Input iterator type. */ - using iterator_type = typename pool_type::iterator_type; - /*! @brief Constant input iterator type. */ - using const_iterator_type = typename pool_type::const_iterator_type; - - /** - * @brief Returns the number of instances of the given type. - * @return Number of instances of the given component. - */ - size_type size() const ENTT_NOEXCEPT { - return pool.size(); - } - - /** - * @brief Checks whether the view is empty. - * @return True if the view is empty, false otherwise. - */ - bool empty() const ENTT_NOEXCEPT { - return pool.empty(); - } - - /** - * @brief Direct access to the list of components. - * - * The returned pointer is such that range `[raw(), raw() + size()]` is - * always a valid range, even if the container is empty. - * - * @note - * There are no guarantees on the order of the components. Use `begin` and - * `end` if you want to iterate the view in the expected order. - * - * @return A pointer to the array of components. - */ - const raw_type * raw() const ENTT_NOEXCEPT { - return pool.raw(); - } - - /** - * @brief Direct access to the list of components. - * - * The returned pointer is such that range `[raw(), raw() + size()]` is - * always a valid range, even if the container is empty. - * - * @note - * There are no guarantees on the order of the components. Use `begin` and - * `end` if you want to iterate the view in the expected order. - * - * @return A pointer to the array of components. - */ - inline raw_type * raw() ENTT_NOEXCEPT { - return const_cast(const_cast(this)->raw()); - } - - /** - * @brief Direct access to the list of entities. - * - * The returned pointer is such that range `[data(), data() + size()]` is - * always a valid range, even if the container is empty. - * - * @note - * There are no guarantees on the order of the entities. Use `begin` and - * `end` if you want to iterate the view in the expected order. - * - * @return A pointer to the array of entities. - */ - const entity_type * data() const ENTT_NOEXCEPT { - return pool.data(); - } - - /** - * @brief Returns an iterator to the first instance of the given type. - * - * The returned iterator points to the first instance of the given type. If - * the view is empty, the returned iterator will be equal to `end()`. - * - * @note - * Input iterators stay true to the order imposed to the underlying data - * structures. - * - * @return An iterator to the first instance of the given type. - */ - const_iterator_type cbegin() const ENTT_NOEXCEPT { - return pool.cbegin(); - } - - /** - * @brief Returns an iterator to the first instance of the given type. - * - * The returned iterator points to the first instance of the given type. If - * the view is empty, the returned iterator will be equal to `end()`. - * - * @note - * Input iterators stay true to the order imposed to the underlying data - * structures. - * - * @return An iterator to the first instance of the given type. - */ - inline const_iterator_type begin() const ENTT_NOEXCEPT { - return cbegin(); - } - - /** - * @brief Returns an iterator to the first instance of the given type. - * - * The returned iterator points to the first instance of the given type. If - * the view is empty, the returned iterator will be equal to `end()`. - * - * @note - * Input iterators stay true to the order imposed to the underlying data - * structures. - * - * @return An iterator to the first instance of the given type. - */ - iterator_type begin() ENTT_NOEXCEPT { - return pool.begin(); - } - - /** - * @brief Returns an iterator that is past the last instance of the given - * type. - * - * The returned iterator points to the element following the last instance - * of the given type. Attempting to dereference the returned iterator - * results in undefined behavior. - * - * @note - * Input iterators stay true to the order imposed to the underlying data - * structures. - * - * @return An iterator to the element following the last instance of the - * given type. - */ - const_iterator_type cend() const ENTT_NOEXCEPT { - return pool.cend(); - } - - /** - * @brief Returns an iterator that is past the last instance of the given - * type. - * - * The returned iterator points to the element following the last instance - * of the given type. Attempting to dereference the returned iterator - * results in undefined behavior. - * - * @note - * Input iterators stay true to the order imposed to the underlying data - * structures. - * - * @return An iterator to the element following the last instance of the - * given type. - */ - inline const_iterator_type end() const ENTT_NOEXCEPT { - return cend(); - } - - /** - * @brief Returns an iterator that is past the last instance of the given - * type. - * - * The returned iterator points to the element following the last instance - * of the given type. Attempting to dereference the returned iterator - * results in undefined behavior. - * - * @note - * Input iterators stay true to the order imposed to the underlying data - * structures. - * - * @return An iterator to the element following the last instance of the - * given type. - */ - iterator_type end() ENTT_NOEXCEPT { - return pool.end(); - } - - /** - * @brief Returns a reference to the element at the given position. - * @param pos Position of the element to return. - * @return A reference to the requested element. - */ - const raw_type & operator[](const size_type pos) const ENTT_NOEXCEPT { - return pool[pos]; - } - - /** - * @brief Returns a reference to the element at the given position. - * @param pos Position of the element to return. - * @return A reference to the requested element. - */ - inline raw_type & operator[](const size_type pos) ENTT_NOEXCEPT { - return const_cast(const_cast(this)->operator[](pos)); - } - - /** - * @brief Iterates components and applies the given function object to them. - * - * The function object is provided with a const reference to each component - * of the view.
- * The signature of the function should be equivalent to the following: - * - * @code{.cpp} - * void(const Component &); - * @endcode - * - * @tparam Func Type of the function object to invoke. - * @param func A valid function object. - */ - template - void each(Func func) const { - std::for_each(pool.cbegin(), pool.cend(), func); - } - - /** - * @brief Iterates components and applies the given function object to them. - * - * The function object is provided with a reference to each component of the - * view.
- * The signature of the function should be equivalent to the following: - * - * @code{.cpp} - * void(Component &); - * @endcode - * - * @tparam Func Type of the function object to invoke. - * @param func A valid function object. - */ - template - void each(Func func) { - std::for_each(pool.begin(), pool.end(), func); - } - -private: - pool_type &pool; -}; - - -/** - * @brief Runtime view. - * - * Runtime views iterate over those entities that have at least all the given - * components in their bags. During initialization, a runtime view looks at the - * number of entities available for each component and picks up a reference to - * the smallest set of candidate entities in order to get a performance boost - * when iterate.
- * Order of elements during iterations are highly dependent on the order of the - * underlying data structures. See SparseSet and its specializations for more - * details. - * - * @b Important - * - * Iterators aren't invalidated if: - * - * * New instances of the given components are created and assigned to entities. - * * The entity currently pointed is modified (as an example, if one of the - * given components is removed from the entity to which the iterator points). - * - * In all the other cases, modifying the pools of the given components in any - * way invalidates all the iterators and using them results in undefined - * behavior. - * - * @note - * Views share references to the underlying data structures with the Registry - * that generated them. Therefore any change to the entities and to the - * components made by means of the registry are immediately reflected by views, - * unless a pool wasn't missing when the view was built (in this case, the view - * won't have a valid reference and won't be updated accordingly). - * - * @warning - * Lifetime of a view must overcome the one of the registry that generated it. - * In any other case, attempting to use a view results in undefined behavior. - * - * @sa View - * @sa View - * @sa PersistentView - * @sa RawView - * - * @tparam Entity A valid entity type (see entt_traits for more details). - */ -template -class RuntimeView { - /*! @brief A registry is allowed to create views. */ - friend class Registry; - - using view_type = SparseSet; - using underlying_iterator_type = typename view_type::const_iterator_type; - using pattern_type = std::vector; - using extent_type = typename view_type::size_type; - using traits_type = entt_traits; - - class Iterator { - friend class RuntimeView; - - Iterator(underlying_iterator_type begin, underlying_iterator_type end, const view_type * const *first, const view_type * const *last, extent_type extent) ENTT_NOEXCEPT - : begin{begin}, - end{end}, - first{first}, - last{last}, - extent{extent} - { - if(begin != end && !valid()) { - ++(*this); - } - } - - bool valid() const ENTT_NOEXCEPT { - const auto entity = *begin; - const auto sz = size_type(entity & traits_type::entity_mask); - - return sz < extent && std::all_of(first, last, [entity](const auto *view) { - return view->fast(entity); - }); - } - - public: - using difference_type = typename underlying_iterator_type::difference_type; - using value_type = typename underlying_iterator_type::value_type; - using pointer = typename underlying_iterator_type::pointer; - using reference = typename underlying_iterator_type::reference; - using iterator_category = std::forward_iterator_tag; - - Iterator() ENTT_NOEXCEPT = default; - - Iterator(const Iterator &) ENTT_NOEXCEPT = default; - Iterator & operator=(const Iterator &) ENTT_NOEXCEPT = default; - - Iterator & operator++() ENTT_NOEXCEPT { - return (++begin != end && !valid()) ? ++(*this) : *this; - } - - Iterator operator++(int) ENTT_NOEXCEPT { - Iterator orig = *this; - return ++(*this), orig; - } - - bool operator==(const Iterator &other) const ENTT_NOEXCEPT { - return other.begin == begin; - } - - inline bool operator!=(const Iterator &other) const ENTT_NOEXCEPT { - return !(*this == other); - } - - pointer operator->() const ENTT_NOEXCEPT { - return begin.operator->(); - } - - inline reference operator*() const ENTT_NOEXCEPT { - return *operator->(); - } - - private: - underlying_iterator_type begin; - underlying_iterator_type end; - const view_type * const *first; - const view_type * const *last; - extent_type extent; - }; - - RuntimeView(pattern_type others) ENTT_NOEXCEPT - : pools{std::move(others)} - { - const auto it = std::min_element(pools.begin(), pools.end(), [](const auto *lhs, const auto *rhs) { - return (!lhs && rhs) || (lhs && rhs && lhs->size() < rhs->size()); - }); - - // brings the best candidate (if any) on front of the vector - std::rotate(pools.begin(), it, pools.end()); - } - - extent_type min() const ENTT_NOEXCEPT { - extent_type extent{}; - - if(valid()) { - const auto it = std::min_element(pools.cbegin(), pools.cend(), [](const auto *lhs, const auto *rhs) { - return lhs->extent() < rhs->extent(); - }); - - extent = (*it)->extent(); - } - - return extent; - } - - inline bool valid() const ENTT_NOEXCEPT { - return !pools.empty() && pools.front(); - } - -public: - /*! @brief Underlying entity identifier. */ - using entity_type = typename view_type::entity_type; - /*! @brief Unsigned integer type. */ - using size_type = typename view_type::size_type; - /*! @brief Input iterator type. */ - using iterator_type = Iterator; - /*! @brief Constant input iterator type. */ - using const_iterator_type = Iterator; - - /** - * @brief Estimates the number of entities that have the given components. - * @return Estimated number of entities that have the given components. - */ - size_type size() const ENTT_NOEXCEPT { - return valid() ? pools.front()->size() : size_type{}; - } - - /** - * @brief Checks if the view is definitely empty. - * @return True if the view is definitely empty, false otherwise. - */ - bool empty() const ENTT_NOEXCEPT { - return !valid() || pools.front()->empty(); - } - - /** - * @brief Returns an iterator to the first entity that has the given - * components. - * - * The returned iterator points to the first entity that has the given - * components. If the view is empty, the returned iterator will be equal to - * `end()`. - * - * @note - * Input iterators stay true to the order imposed to the underlying data - * structures. - * - * @return An iterator to the first entity that has the given components. - */ - const_iterator_type cbegin() const ENTT_NOEXCEPT { - const_iterator_type it{}; - - if(valid()) { - const auto &pool = *pools.front(); - const auto * const *data = pools.data(); - it = { pool.cbegin(), pool.cend(), data + 1, data + pools.size(), min() }; - } - - return it; - } - - /** - * @brief Returns an iterator to the first entity that has the given - * components. - * - * The returned iterator points to the first entity that has the given - * components. If the view is empty, the returned iterator will be equal to - * `end()`. - * - * @note - * Input iterators stay true to the order imposed to the underlying data - * structures. - * - * @return An iterator to the first entity that has the given components. - */ - inline const_iterator_type begin() const ENTT_NOEXCEPT { - return cbegin(); - } - - /** - * @brief Returns an iterator to the first entity that has the given - * components. - * - * The returned iterator points to the first entity that has the given - * components. If the view is empty, the returned iterator will be equal to - * `end()`. - * - * @note - * Input iterators stay true to the order imposed to the underlying data - * structures. - * - * @return An iterator to the first entity that has the given components. - */ - inline iterator_type begin() ENTT_NOEXCEPT { - return cbegin(); - } - - /** - * @brief Returns an iterator that is past the last entity that has the - * given components. - * - * The returned iterator points to the entity following the last entity that - * has the given components. Attempting to dereference the returned iterator - * results in undefined behavior. - * - * @note - * Input iterators stay true to the order imposed to the underlying data - * structures. - * - * @return An iterator to the entity following the last entity that has the - * given components. - */ - const_iterator_type cend() const ENTT_NOEXCEPT { - const_iterator_type it{}; - - if(valid()) { - const auto &pool = *pools.front(); - it = { pool.cend(), pool.cend(), nullptr, nullptr, min() }; - } - - return it; - } - - /** - * @brief Returns an iterator that is past the last entity that has the - * given components. - * - * The returned iterator points to the entity following the last entity that - * has the given components. Attempting to dereference the returned iterator - * results in undefined behavior. - * - * @note - * Input iterators stay true to the order imposed to the underlying data - * structures. - * - * @return An iterator to the entity following the last entity that has the - * given components. - */ - inline const_iterator_type end() const ENTT_NOEXCEPT { - return cend(); - } - - /** - * @brief Returns an iterator that is past the last entity that has the - * given components. - * - * The returned iterator points to the entity following the last entity that - * has the given components. Attempting to dereference the returned iterator - * results in undefined behavior. - * - * @note - * Input iterators stay true to the order imposed to the underlying data - * structures. - * - * @return An iterator to the entity following the last entity that has the - * given components. - */ - inline iterator_type end() ENTT_NOEXCEPT { - return cend(); - } - - /** - * @brief Checks if a view contains an entity. - * @param entity A valid entity identifier. - * @return True if the view contains the given entity, false otherwise. - */ - bool contains(const entity_type entity) const ENTT_NOEXCEPT { - return valid() && std::all_of(pools.cbegin(), pools.cend(), [entity](const auto *view) { - return view->has(entity) && view->data()[view->get(entity)] == entity; - }); - } - - /** - * @brief Iterates entities and applies the given function object to them. - * - * The function object is invoked for each entity. It is provided only with - * the entity itself. To get the components, users can use the registry with - * which the view was built.
- * The signature of the function should be equivalent to the following: - * - * @code{.cpp} - * void(const entity_type); - * @endcode - * - * @tparam Func Type of the function object to invoke. - * @param func A valid function object. - */ - template - void each(Func func) const { - std::for_each(cbegin(), cend(), func); - } - -private: - pattern_type pools; -}; - - -} - - -#endif // ENTT_ENTITY_VIEW_HPP diff --git a/external/entt/entt.hpp b/external/entt/entt.hpp deleted file mode 100644 index ceb1fefa4..000000000 --- a/external/entt/entt.hpp +++ /dev/null @@ -1,26 +0,0 @@ -#include "core/algorithm.hpp" -#include "core/family.hpp" -#include "core/hashed_string.hpp" -#include "core/ident.hpp" -#include "core/monostate.hpp" -#include "entity/actor.hpp" -#include "entity/attachee.hpp" -#include "entity/entity.hpp" -#include "entity/entt_traits.hpp" -#include "entity/helper.hpp" -#include "entity/prototype.hpp" -#include "entity/registry.hpp" -#include "entity/snapshot.hpp" -#include "entity/sparse_set.hpp" -#include "entity/utility.hpp" -#include "entity/view.hpp" -#include "locator/locator.hpp" -#include "process/process.hpp" -#include "process/scheduler.hpp" -#include "resource/cache.hpp" -#include "resource/handle.hpp" -#include "resource/loader.hpp" -#include "signal/delegate.hpp" -#include "signal/dispatcher.hpp" -#include "signal/emitter.hpp" -#include "signal/sigh.hpp" diff --git a/external/entt/locator/locator.hpp b/external/entt/locator/locator.hpp deleted file mode 100644 index 2c66ca388..000000000 --- a/external/entt/locator/locator.hpp +++ /dev/null @@ -1,116 +0,0 @@ -#ifndef ENTT_LOCATOR_LOCATOR_HPP -#define ENTT_LOCATOR_LOCATOR_HPP - - -#include -#include -#include -#include "../config/config.h" - - -namespace entt { - - -/** - * @brief Service locator, nothing more. - * - * A service locator can be used to do what it promises: locate services.
- * Usually service locators are tightly bound to the services they expose and - * thus it's hard to define a general purpose class to do that. This template - * based implementation tries to fill the gap and to get rid of the burden of - * defining a different specific locator for each application. - * - * @tparam Service Type of service managed by the locator. - */ -template -struct ServiceLocator final { - /*! @brief Type of service offered. */ - using service_type = Service; - - /*! @brief Default constructor, deleted on purpose. */ - ServiceLocator() = delete; - /*! @brief Default destructor, deleted on purpose. */ - ~ServiceLocator() = delete; - - /** - * @brief Tests if a valid service implementation is set. - * @return True if the service is set, false otherwise. - */ - inline static bool empty() ENTT_NOEXCEPT { - return !static_cast(service); - } - - /** - * @brief Returns a weak pointer to a service implementation, if any. - * - * Clients of a service shouldn't retain references to it. The recommended - * way is to retrieve the service implementation currently set each and - * every time the need of using it arises. Otherwise users can incur in - * unexpected behaviors. - * - * @return A reference to the service implementation currently set, if any. - */ - inline static std::weak_ptr get() ENTT_NOEXCEPT { - return service; - } - - /** - * @brief Returns a weak reference to a service implementation, if any. - * - * Clients of a service shouldn't retain references to it. The recommended - * way is to retrieve the service implementation currently set each and - * every time the need of using it arises. Otherwise users can incur in - * unexpected behaviors. - * - * @warning - * In case no service implementation has been set, a call to this function - * results in undefined behavior. - * - * @return A reference to the service implementation currently set, if any. - */ - inline static Service & ref() ENTT_NOEXCEPT { - return *service; - } - - /** - * @brief Sets or replaces a service. - * @tparam Impl Type of the new service to use. - * @tparam Args Types of arguments to use to construct the service. - * @param args Parameters to use to construct the service. - */ - template - inline static void set(Args &&... args) { - service = std::make_shared(std::forward(args)...); - } - - /** - * @brief Sets or replaces a service. - * @param ptr Service to use to replace the current one. - */ - inline static void set(std::shared_ptr ptr) { - assert(static_cast(ptr)); - service = std::move(ptr); - } - - /** - * @brief Resets a service. - * - * The service is no longer valid after a reset. - */ - inline static void reset() { - service.reset(); - } - -private: - static std::shared_ptr service; -}; - - -template -std::shared_ptr ServiceLocator::service{}; - - -} - - -#endif // ENTT_LOCATOR_LOCATOR_HPP diff --git a/external/entt/process/process.hpp b/external/entt/process/process.hpp deleted file mode 100644 index 2077b0434..000000000 --- a/external/entt/process/process.hpp +++ /dev/null @@ -1,339 +0,0 @@ -#ifndef ENTT_PROCESS_PROCESS_HPP -#define ENTT_PROCESS_PROCESS_HPP - - -#include -#include -#include -#include "../config/config.h" - - -namespace entt { - - -/** - * @brief Base class for processes. - * - * This class stays true to the CRTP idiom. Derived classes must specify what's - * the intended type for elapsed times.
- * A process should expose publicly the following member functions whether - * required: - * - * * @code{.cpp} - * void update(Delta, void *); - * @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 init(void *); - * @endcode - * - * It's invoked at the first tick, immediately before an update. The `void *` - * parameter is an opaque pointer to user data (if any) forwarded directly to - * the process during an update. - * - * * @code{.cpp} - * void succeeded(); - * @endcode - * - * It's invoked in case of success, immediately after an update and during the - * same tick. - * - * * @code{.cpp} - * void failed(); - * @endcode - * - * It's invoked in case of errors, immediately after an update and during the - * same tick. - * - * * @code{.cpp} - * void aborted(); - * @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` protected member functions and even pause or unpause the - * process itself. - * - * @sa Scheduler - * - * @tparam Derived Actual type of process that extends the class template. - * @tparam Delta Type to use to provide elapsed time. - */ -template -class Process { - enum class State: unsigned int { - UNINITIALIZED = 0, - RUNNING, - PAUSED, - SUCCEEDED, - FAILED, - ABORTED, - FINISHED - }; - - template - using tag = std::integral_constant; - - template - auto tick(int, tag, void *data) - -> decltype(std::declval().init(data)) { - static_cast(this)->init(data); - } - - template - auto tick(int, tag, Delta delta, void *data) - -> decltype(std::declval().update(delta, data)) { - static_cast(this)->update(delta, data); - } - - template - auto tick(int, tag) - -> decltype(std::declval().succeeded()) { - static_cast(this)->succeeded(); - } - - template - auto tick(int, tag) - -> decltype(std::declval().failed()) { - static_cast(this)->failed(); - } - - template - auto tick(int, tag) - -> decltype(std::declval().aborted()) { - static_cast(this)->aborted(); - } - - template - void tick(char, tag, Args &&...) const ENTT_NOEXCEPT {} - -protected: - /** - * @brief Terminates a process with success if it's still alive. - * - * The function is idempotent and it does nothing if the process isn't - * alive. - */ - void succeed() ENTT_NOEXCEPT { - if(alive()) { - current = State::SUCCEEDED; - } - } - - /** - * @brief Terminates a process with errors if it's still alive. - * - * The function is idempotent and it does nothing if the process isn't - * alive. - */ - void fail() ENTT_NOEXCEPT { - if(alive()) { - current = State::FAILED; - } - } - - /** - * @brief Stops a process if it's in a running state. - * - * The function is idempotent and it does nothing if the process isn't - * running. - */ - void pause() ENTT_NOEXCEPT { - if(current == State::RUNNING) { - current = State::PAUSED; - } - } - - /** - * @brief Restarts a process if it's paused. - * - * The function is idempotent and it does nothing if the process isn't - * paused. - */ - void unpause() ENTT_NOEXCEPT { - if(current == State::PAUSED) { - current = State::RUNNING; - } - } - -public: - /*! @brief Type used to provide elapsed time. */ - using delta_type = Delta; - - /*! @brief Default destructor. */ - virtual ~Process() ENTT_NOEXCEPT { - static_assert(std::is_base_of::value, "!"); - } - - /** - * @brief Aborts a process if it's still alive. - * - * The function is idempotent and it does nothing if the process isn't - * alive. - * - * @param immediately Requests an immediate operation. - */ - void abort(const bool immediately = false) ENTT_NOEXCEPT { - if(alive()) { - current = State::ABORTED; - - if(immediately) { - tick(0); - } - } - } - - /** - * @brief Returns true if a process is either running or paused. - * @return True if the process is still alive, false otherwise. - */ - bool alive() const ENTT_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. - */ - bool dead() const ENTT_NOEXCEPT { - return current == State::FINISHED; - } - - /** - * @brief Returns true if a process is currently paused. - * @return True if the process is paused, false otherwise. - */ - bool paused() const ENTT_NOEXCEPT { - return current == State::PAUSED; - } - - /** - * @brief Returns true if a process terminated with errors. - * @return True if the process terminated with errors, false otherwise. - */ - bool rejected() const ENTT_NOEXCEPT { - return stopped; - } - - /** - * @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::UNINITIALIZED: - tick(0, tag{}, data); - current = State::RUNNING; - // no break on purpose, tasks are executed immediately - case State::RUNNING: - tick(0, tag{}, delta, data); - default: - // suppress warnings - break; - } - - // if it's dead, it must be notified and removed immediately - switch(current) { - case State::SUCCEEDED: - tick(0, tag{}); - current = State::FINISHED; - break; - case State::FAILED: - tick(0, tag{}); - current = State::FINISHED; - stopped = true; - break; - case State::ABORTED: - tick(0, tag{}); - current = State::FINISHED; - stopped = true; - break; - default: - // suppress warnings - break; - } - } - -private: - State current{State::UNINITIALIZED}; - bool stopped{false}; -}; - - -/** - * @brief Adaptor for lambdas and functors to turn them into processes. - * - * Lambdas and functors can't be used directly with a scheduler for they are not - * properly defined processes with managed life cycles.
- * This class helps in filling the gap and turning lambdas and functors into - * full featured processes usable by a scheduler. - * - * The signature of the function call operator should be equivalent to the - * following: - * - * @code{.cpp} - * void(Delta delta, void *data, auto succeed, auto fail); - * @endcode - * - * Where: - * - * * `delta` is the elapsed time. - * * `data` is an opaque pointer to user data if any, `nullptr` otherwise. - * * `succeed` is a function to call when a process terminates with success. - * * `fail` is a function to call when a process terminates with errors. - * - * The signature of the function call operator of both `succeed` and `fail` - * is equivalent to the following: - * - * @code{.cpp} - * void(); - * @endcode - * - * Usually users shouldn't worry about creating adaptors. A scheduler will - * create them internally each and avery time a lambda or a functor is used as - * a process. - * - * @sa Process - * @sa Scheduler - * - * @tparam Func Actual type of process. - * @tparam Delta Type to use to provide elapsed time. - */ -template -struct ProcessAdaptor: Process, Delta>, private Func { - /** - * @brief Constructs a process adaptor from a lambda or a functor. - * @tparam Args Types of arguments to use to initialize the actual process. - * @param args Parameters to use to initialize the actual process. - */ - template - ProcessAdaptor(Args &&... args) - : Func{std::forward(args)...} - {} - - /** - * @brief Updates a process and its internal state if required. - * @param delta Elapsed time. - * @param data Optional data. - */ - void update(const Delta delta, void *data) { - Func::operator()(delta, data, [this]() { this->succeed(); }, [this]() { this->fail(); }); - } -}; - - -} - - -#endif // ENTT_PROCESS_PROCESS_HPP diff --git a/external/entt/process/scheduler.hpp b/external/entt/process/scheduler.hpp deleted file mode 100644 index c7729bbe9..000000000 --- a/external/entt/process/scheduler.hpp +++ /dev/null @@ -1,311 +0,0 @@ -#ifndef ENTT_PROCESS_SCHEDULER_HPP -#define ENTT_PROCESS_SCHEDULER_HPP - - -#include -#include -#include -#include -#include -#include "../config/config.h" -#include "process.hpp" - - -namespace entt { - - -/** - * @brief Cooperative scheduler for processes. - * - * A cooperative scheduler runs processes and helps managing their life cycles. - * - * Each process is invoked once per tick. If a process terminates, it's - * removed automatically from the scheduler and it's never invoked again.
- * A process can also have a child. In this case, the process is replaced with - * its child when it terminates if it returns with success. In case of errors, - * both the process and its child are discarded. - * - * Example of use (pseudocode): - * - * @code{.cpp} - * scheduler.attach([](auto delta, void *, auto succeed, auto fail) { - * // code - * }).then(arguments...); - * @endcode - * - * In order to invoke all scheduled processes, call the `update` member function - * passing it the elapsed time to forward to the tasks. - * - * @sa Process - * - * @tparam Delta Type to use to provide elapsed time. - */ -template -class Scheduler final { - struct ProcessHandler final { - using instance_type = std::unique_ptr; - using update_fn_type = bool(ProcessHandler &, Delta, void *); - using abort_fn_type = void(ProcessHandler &, bool); - using next_type = std::unique_ptr; - - instance_type instance; - update_fn_type *update; - abort_fn_type *abort; - next_type next; - }; - - struct Then final { - Then(ProcessHandler *handler) - : handler{handler} - {} - - template - decltype(auto) then(Args &&... args) && { - static_assert(std::is_base_of, Proc>::value, "!"); - handler = Scheduler::then(handler, std::forward(args)...); - return std::move(*this); - } - - template - decltype(auto) then(Func &&func) && { - using Proc = ProcessAdaptor, Delta>; - return std::move(*this).template then(std::forward(func)); - } - - private: - ProcessHandler *handler; - }; - - template - static bool update(ProcessHandler &handler, const Delta delta, void *data) { - auto *process = static_cast(handler.instance.get()); - process->tick(delta, data); - - auto dead = process->dead(); - - if(dead) { - if(handler.next && !process->rejected()) { - handler = std::move(*handler.next); - dead = handler.update(handler, delta, data); - } else { - handler.instance.reset(); - } - } - - return dead; - } - - template - static void abort(ProcessHandler &handler, const bool immediately) { - static_cast(handler.instance.get())->abort(immediately); - } - - template - static void deleter(void *proc) { - delete static_cast(proc); - } - - template - static auto then(ProcessHandler *handler, Args &&... args) { - if(handler) { - auto proc = typename ProcessHandler::instance_type{new Proc{std::forward(args)...}, &Scheduler::deleter}; - handler->next.reset(new ProcessHandler{std::move(proc), &Scheduler::update, &Scheduler::abort, nullptr}); - handler = handler->next.get(); - } - - return handler; - } - -public: - /*! @brief Unsigned integer type. */ - using size_type = typename std::vector::size_type; - - /*! @brief Default constructor. */ - Scheduler() ENTT_NOEXCEPT = default; - - /*! @brief Copying a scheduler isn't allowed. */ - Scheduler(const Scheduler &) = delete; - /*! @brief Default move constructor. */ - Scheduler(Scheduler &&) = default; - - /*! @brief Copying a scheduler isn't allowed. @return This scheduler. */ - Scheduler & operator=(const Scheduler &) = delete; - /*! @brief Default move assignment operator. @return This scheduler. */ - Scheduler & operator=(Scheduler &&) = default; - - /** - * @brief Number of processes currently scheduled. - * @return Number of processes currently scheduled. - */ - size_type size() const ENTT_NOEXCEPT { - return handlers.size(); - } - - /** - * @brief Returns true if at least a process is currently scheduled. - * @return True if there are scheduled processes, false otherwise. - */ - bool empty() const ENTT_NOEXCEPT { - return handlers.empty(); - } - - /** - * @brief Discards all scheduled processes. - * - * Processes aren't aborted. They are discarded along with their children - * and never executed again. - */ - void clear() { - handlers.clear(); - } - - /** - * @brief Schedules a process for the next tick. - * - * Returned value is an opaque object that can be used to attach a child to - * the given process. The child is automatically scheduled when the process - * terminates and only if the process returns with success. - * - * Example of use (pseudocode): - * - * @code{.cpp} - * // schedules a task in the form of a process class - * scheduler.attach(arguments...) - * // appends a child in the form of a lambda function - * .then([](auto delta, void *, auto succeed, auto fail) { - * // code - * }) - * // appends a child in the form of another process class - * .then(); - * @endcode - * - * @tparam Proc Type of process to schedule. - * @tparam Args Types of arguments to use to initialize the process. - * @param args Parameters to use to initialize the process. - * @return An opaque object to use to concatenate processes. - */ - template - auto attach(Args &&... args) { - static_assert(std::is_base_of, Proc>::value, "!"); - - auto proc = typename ProcessHandler::instance_type{new Proc{std::forward(args)...}, &Scheduler::deleter}; - ProcessHandler handler{std::move(proc), &Scheduler::update, &Scheduler::abort, nullptr}; - handlers.push_back(std::move(handler)); - - return Then{&handlers.back()}; - } - - /** - * @brief Schedules a process for the next tick. - * - * A process can be either a lambda or a functor. The scheduler wraps both - * of them in a process adaptor internally.
- * The signature of the function call operator should be equivalent to the - * following: - * - * @code{.cpp} - * void(Delta delta, auto succeed, auto fail); - * @endcode - * - * Where: - * - * * `delta` is the elapsed time. - * * `succeed` is a function to call when a process terminates with success. - * * `fail` is a function to call when a process terminates with errors. - * - * The signature of the function call operator of both `succeed` and `fail` - * is equivalent to the following: - * - * @code{.cpp} - * void(); - * @endcode - * - * Returned value is an opaque object that can be used to attach a child to - * the given process. The child is automatically scheduled when the process - * terminates and only if the process returns with success. - * - * Example of use (pseudocode): - * - * @code{.cpp} - * // schedules a task in the form of a lambda function - * scheduler.attach([](auto delta, void *, auto succeed, auto fail) { - * // code - * }) - * // appends a child in the form of another lambda function - * .then([](auto delta, void *, auto succeed, auto fail) { - * // code - * }) - * // appends a child in the form of a process class - * .then(arguments...); - * @endcode - * - * @sa ProcessAdaptor - * - * @tparam Func Type of process to schedule. - * @param func Either a lambda or a functor to use as a process. - * @return An opaque object to use to concatenate processes. - */ - template - auto attach(Func &&func) { - using Proc = ProcessAdaptor, Delta>; - return attach(std::forward(func)); - } - - /** - * @brief Updates all scheduled processes. - * - * All scheduled processes are executed in no specific order.
- * If a process terminates with success, it's replaced with its child, if - * any. Otherwise, if a process terminates with an error, it's removed along - * with its child. - * - * @param delta Elapsed time. - * @param data Optional data. - */ - void update(const Delta delta, void *data = nullptr) { - bool clean = false; - - for(auto pos = handlers.size(); pos; --pos) { - auto &handler = handlers[pos-1]; - const bool dead = handler.update(handler, delta, data); - clean = clean || dead; - } - - if(clean) { - handlers.erase(std::remove_if(handlers.begin(), handlers.end(), [](auto &handler) { - return !handler.instance; - }), handlers.end()); - } - } - - /** - * @brief Aborts all scheduled processes. - * - * Unless an immediate operation is requested, the abort is scheduled for - * the next tick. Processes won't be executed anymore in any case.
- * Once a process is fully aborted and thus finished, it's discarded along - * with its child, if any. - * - * @param immediately Requests an immediate operation. - */ - void abort(const bool immediately = false) { - decltype(handlers) exec; - exec.swap(handlers); - - std::for_each(exec.begin(), exec.end(), [immediately](auto &handler) { - handler.abort(handler, immediately); - }); - - std::move(handlers.begin(), handlers.end(), std::back_inserter(exec)); - handlers.swap(exec); - } - -private: - std::vector handlers{}; -}; - - -} - - -#endif // ENTT_PROCESS_SCHEDULER_HPP diff --git a/external/entt/resource/cache.hpp b/external/entt/resource/cache.hpp deleted file mode 100644 index 032d26998..000000000 --- a/external/entt/resource/cache.hpp +++ /dev/null @@ -1,201 +0,0 @@ -#ifndef ENTT_RESOURCE_CACHE_HPP -#define ENTT_RESOURCE_CACHE_HPP - - -#include -#include -#include -#include -#include "../config/config.h" -#include "../core/hashed_string.hpp" -#include "handle.hpp" -#include "loader.hpp" - - -namespace entt { - - -/** - * @brief Simple cache for resources of a given type. - * - * Minimal implementation of a cache for resources of a given type. It doesn't - * offer much functionalities but it's suitable for small or medium sized - * applications and can be freely inherited to add targeted functionalities for - * large sized applications. - * - * @tparam Resource Type of resources managed by a cache. - */ -template -class ResourceCache { - using container_type = std::unordered_map>; - -public: - /*! @brief Unsigned integer type. */ - using size_type = typename container_type::size_type; - /*! @brief Type of resources managed by a cache. */ - using resource_type = HashedString; - - /*! @brief Default constructor. */ - ResourceCache() = default; - - /*! @brief Copying a cache isn't allowed. */ - ResourceCache(const ResourceCache &) ENTT_NOEXCEPT = delete; - /*! @brief Default move constructor. */ - ResourceCache(ResourceCache &&) ENTT_NOEXCEPT = default; - - /*! @brief Copying a cache isn't allowed. @return This cache. */ - ResourceCache & operator=(const ResourceCache &) ENTT_NOEXCEPT = delete; - /*! @brief Default move assignment operator. @return This cache. */ - ResourceCache & operator=(ResourceCache &&) ENTT_NOEXCEPT = default; - - /** - * @brief Number of resources managed by a cache. - * @return Number of resources currently stored. - */ - size_type size() const ENTT_NOEXCEPT { - return resources.size(); - } - - /** - * @brief Returns true if a cache contains no resources, false otherwise. - * @return True if the cache contains no resources, false otherwise. - */ - bool empty() const ENTT_NOEXCEPT { - return resources.empty(); - } - - /** - * @brief Clears a cache and discards all its resources. - * - * Handles are not invalidated and the memory used by a resource isn't - * freed as long as at least a handle keeps the resource itself alive. - */ - void clear() ENTT_NOEXCEPT { - resources.clear(); - } - - /** - * @brief Loads the resource that corresponds to a given identifier. - * - * In case an identifier isn't already present in the cache, it loads its - * resource and stores it aside for future uses. Arguments are forwarded - * directly to the loader in order to construct properly the requested - * resource. - * - * @note - * If the identifier is already present in the cache, this function does - * nothing and the arguments are simply discarded. - * - * @tparam Loader Type of loader to use to load the resource if required. - * @tparam Args Types of arguments to use to load the resource if required. - * @param id Unique resource identifier. - * @param args Arguments to use to load the resource if required. - * @return True if the resource is ready to use, false otherwise. - */ - template - bool load(const resource_type id, Args &&... args) { - static_assert(std::is_base_of, Loader>::value, "!"); - - bool loaded = true; - - if(resources.find(id) == resources.cend()) { - std::shared_ptr resource = Loader{}.get(std::forward(args)...); - loaded = (static_cast(resource) ? (resources[id] = std::move(resource), loaded) : false); - } - - return loaded; - } - - /** - * @brief Reloads a resource or loads it for the first time if not present. - * - * Equivalent to the following snippet (pseudocode): - * - * @code{.cpp} - * cache.discard(id); - * cache.load(id, args...); - * @endcode - * - * Arguments are forwarded directly to the loader in order to construct - * properly the requested resource. - * - * @tparam Loader Type of loader to use to load the resource. - * @tparam Args Types of arguments to use to load the resource. - * @param id Unique resource identifier. - * @param args Arguments to use to load the resource. - * @return True if the resource is ready to use, false otherwise. - */ - template - bool reload(const resource_type id, Args &&... args) { - return (discard(id), load(id, std::forward(args)...)); - } - - /** - * @brief Creates a temporary handle for a resource. - * - * Arguments are forwarded directly to the loader in order to construct - * properly the requested resource. The handle isn't stored aside and the - * cache isn't in charge of the lifetime of the resource itself. - * - * @tparam Loader Type of loader to use to load the resource. - * @tparam Args Types of arguments to use to load the resource. - * @param args Arguments to use to load the resource. - * @return A handle for the given resource. - */ - template - ResourceHandle temp(Args &&... args) const { - return { Loader{}.get(std::forward(args)...) }; - } - - /** - * @brief Creates a handle for a given resource identifier. - * - * A resource handle can be in a either valid or invalid state. In other - * terms, a resource handle is properly initialized with a resource if the - * cache contains the resource itself. Otherwise the returned handle is - * uninitialized and accessing it results in undefined behavior. - * - * @sa ResourceHandle - * - * @param id Unique resource identifier. - * @return A handle for the given resource. - */ - ResourceHandle handle(const resource_type id) const { - auto it = resources.find(id); - return { it == resources.end() ? nullptr : it->second }; - } - - /** - * @brief Checks if a cache contains a given identifier. - * @param id Unique resource identifier. - * @return True if the cache contains the resource, false otherwise. - */ - bool contains(const resource_type id) const ENTT_NOEXCEPT { - return (resources.find(id) != resources.cend()); - } - - /** - * @brief Discards the resource that corresponds to a given identifier. - * - * Handles are not invalidated and the memory used by the resource isn't - * freed as long as at least a handle keeps the resource itself alive. - * - * @param id Unique resource identifier. - */ - void discard(const resource_type id) ENTT_NOEXCEPT { - auto it = resources.find(id); - - if(it != resources.end()) { - resources.erase(it); - } - } - -private: - container_type resources; -}; - - -} - - -#endif // ENTT_RESOURCE_CACHE_HPP diff --git a/external/entt/resource/handle.hpp b/external/entt/resource/handle.hpp deleted file mode 100644 index ef54f30ae..000000000 --- a/external/entt/resource/handle.hpp +++ /dev/null @@ -1,116 +0,0 @@ -#ifndef ENTT_RESOURCE_HANDLE_HPP -#define ENTT_RESOURCE_HANDLE_HPP - - -#include -#include -#include -#include "../config/config.h" - - -namespace entt { - - -template -class ResourceCache; - - -/** - * @brief Shared resource handle. - * - * A shared resource handle is a small class that wraps a resource and keeps it - * alive even if it's deleted from the cache. It can be either copied or - * moved. A handle shares a reference to the same resource with all the other - * handles constructed for the same identifier.
- * As a rule of thumb, resources should never be copied nor moved. Handles are - * the way to go to keep references to them. - * - * @tparam Resource Type of resource managed by a handle. - */ -template -class ResourceHandle final { - /*! @brief Resource handles are friends of their caches. */ - friend class ResourceCache; - - ResourceHandle(std::shared_ptr res) ENTT_NOEXCEPT - : resource{std::move(res)} - {} - -public: - /*! @brief Default copy constructor. */ - ResourceHandle(const ResourceHandle &) ENTT_NOEXCEPT = default; - /*! @brief Default move constructor. */ - ResourceHandle(ResourceHandle &&) ENTT_NOEXCEPT = default; - - /*! @brief Default copy assignment operator. @return This handle. */ - ResourceHandle & operator=(const ResourceHandle &) ENTT_NOEXCEPT = default; - /*! @brief Default move assignment operator. @return This handle. */ - ResourceHandle & operator=(ResourceHandle &&) ENTT_NOEXCEPT = default; - - /** - * @brief Gets a reference to the managed resource. - * - * @warning - * The behavior is undefined if the handle doesn't contain a resource.
- * An assertion will abort the execution at runtime in debug mode if the - * handle is empty. - * - * @return A reference to the managed resource. - */ - const Resource & get() const ENTT_NOEXCEPT { - assert(static_cast(resource)); - return *resource; - } - - /** - * @brief Casts a handle and gets a reference to the managed resource. - * - * @warning - * The behavior is undefined if the handle doesn't contain a resource.
- * An assertion will abort the execution at runtime in debug mode if the - * handle is empty. - */ - inline operator const Resource &() const ENTT_NOEXCEPT { return get(); } - - /** - * @brief Dereferences a handle to obtain the managed resource. - * - * @warning - * The behavior is undefined if the handle doesn't contain a resource.
- * An assertion will abort the execution at runtime in debug mode if the - * handle is empty. - * - * @return A reference to the managed resource. - */ - inline const Resource & operator *() const ENTT_NOEXCEPT { return get(); } - - /** - * @brief Gets a pointer to the managed resource from a handle. - * - * @warning - * The behavior is undefined if the handle doesn't contain a resource.
- * An assertion will abort the execution at runtime in debug mode if the - * handle is empty. - * - * @return A pointer to the managed resource or `nullptr` if the handle - * contains no resource at all. - */ - inline const Resource * operator ->() const ENTT_NOEXCEPT { - assert(static_cast(resource)); - return resource.get(); - } - - /** - * @brief Returns true if the handle contains a resource, false otherwise. - */ - explicit operator bool() const { return static_cast(resource); } - -private: - std::shared_ptr resource; -}; - - -} - - -#endif // ENTT_RESOURCE_HANDLE_HPP diff --git a/external/entt/resource/loader.hpp b/external/entt/resource/loader.hpp deleted file mode 100644 index cd2ed2ef3..000000000 --- a/external/entt/resource/loader.hpp +++ /dev/null @@ -1,62 +0,0 @@ -#ifndef ENTT_RESOURCE_LOADER_HPP -#define ENTT_RESOURCE_LOADER_HPP - - -#include - - -namespace entt { - - -template -class ResourceCache; - - -/** - * @brief Base class for resource loaders. - * - * Resource loaders must inherit from this class and stay true to the CRTP - * idiom. Moreover, a resource loader must expose a public, const member - * function named `load` that accepts a variable number of arguments and returns - * a shared pointer to the resource just created.
- * As an example: - * - * @code{.cpp} - * struct MyResource {}; - * - * struct MyLoader: entt::ResourceLoader { - * std::shared_ptr load(int) const { - * // use the integer value somehow - * return std::make_shared(); - * } - * }; - * @endcode - * - * In general, resource loaders should not have a state or retain data of any - * type. They should let the cache manage their resources instead. - * - * @note - * Base class and CRTP idiom aren't strictly required with the current - * implementation. One could argue that a cache can easily work with loaders of - * any type. However, future changes won't be breaking ones by forcing the use - * of a base class today and that's why the model is already in its place. - * - * @tparam Loader Type of the derived class. - * @tparam Resource Type of resource for which to use the loader. - */ -template -class ResourceLoader { - /*! @brief Resource loaders are friends of their caches. */ - friend class ResourceCache; - - template - std::shared_ptr get(Args &&... args) const { - return static_cast(this)->load(std::forward(args)...); - } -}; - - -} - - -#endif // ENTT_RESOURCE_LOADER_HPP diff --git a/external/entt/signal/delegate.hpp b/external/entt/signal/delegate.hpp deleted file mode 100644 index 7fdd75c0f..000000000 --- a/external/entt/signal/delegate.hpp +++ /dev/null @@ -1,166 +0,0 @@ -#ifndef ENTT_SIGNAL_DELEGATE_HPP -#define ENTT_SIGNAL_DELEGATE_HPP - - -#include -#include "../config/config.h" - - -namespace entt { - - -/** - * @brief Basic delegate implementation. - * - * Primary template isn't defined on purpose. All the specializations give a - * compile-time error unless the template parameter is a function type. - */ -template -class Delegate; - - -/** - * @brief Utility class to send around functions and member functions. - * - * Unmanaged delegate for function pointers and member functions. Users of this - * class are in charge of disconnecting instances before deleting them. - * - * A delegate can be used as general purpose invoker with no memory overhead for - * free functions and member functions provided along with an instance on which - * to invoke them. - * - * @tparam Ret Return type of a function type. - * @tparam Args Types of arguments of a function type. - */ -template -class Delegate final { - using proto_fn_type = Ret(void *, Args...); - using stub_type = std::pair; - - template - static Ret proto(void *, Args... args) { - return (Function)(args...); - } - - template - static Ret proto(void *instance, Args... args) { - return (static_cast(instance)->*Member)(args...); - } - - template - static Ret proto(void *instance, Args... args) { - return (static_cast(instance)->*Member)(args...); - } - -public: - /*! @brief Default constructor. */ - Delegate() ENTT_NOEXCEPT - : stub{} - {} - - /** - * @brief Checks whether a delegate actually stores a listener. - * @return True if the delegate is empty, false otherwise. - */ - bool empty() const ENTT_NOEXCEPT { - // no need to test also stub.first - return !stub.second; - } - - /** - * @brief Binds a free function to a delegate. - * @tparam Function A valid free function pointer. - */ - template - void connect() ENTT_NOEXCEPT { - stub = std::make_pair(nullptr, &proto); - } - - /** - * @brief Connects a member function for a given instance to a delegate. - * - * The delegate isn't responsible for the connected object. Users must - * guarantee that the lifetime of the instance overcomes the one of the - * delegate. - * - * @tparam Class Type of class to which the member function belongs. - * @tparam Member Member function to connect to the delegate. - * @param instance A valid instance of type pointer to `Class`. - */ - template - void connect(Class *instance) ENTT_NOEXCEPT { - stub = std::make_pair(instance, &proto); - } - - /** - * @brief Connects a member function for a given instance to a delegate. - * - * The delegate isn't responsible for the connected object. Users must - * guarantee that the lifetime of the instance overcomes the one of the - * delegate. - * - * @tparam Class Type of class to which the member function belongs. - * @tparam Member Member function to connect to the delegate. - * @param instance A valid instance of type pointer to `Class`. - */ - template - void connect(Class *instance) ENTT_NOEXCEPT { - stub = std::make_pair(instance, &proto); - } - - /** - * @brief Resets a delegate. - * - * After a reset, a delegate can be safely invoked with no effect. - */ - void reset() ENTT_NOEXCEPT { - stub.second = nullptr; - } - - /** - * @brief Triggers a delegate. - * @param args Arguments to use to invoke the underlying function. - * @return The value returned by the underlying function. - */ - Ret operator()(Args... args) const { - return stub.second(stub.first, args...); - } - - /** - * @brief Checks if the contents of the two delegates are different. - * - * Two delegates are identical if they contain the same listener. - * - * @param other Delegate with which to compare. - * @return True if the two delegates are identical, false otherwise. - */ - bool operator==(const Delegate &other) const ENTT_NOEXCEPT { - return stub.first == other.stub.first && stub.second == other.stub.second; - } - -private: - stub_type stub; -}; - - -/** - * @brief Checks if the contents of the two delegates are different. - * - * Two delegates are identical if they contain the same listener. - * - * @tparam Ret Return type of a function type. - * @tparam Args Types of arguments of a function type. - * @param lhs A valid delegate object. - * @param rhs A valid delegate object. - * @return True if the two delegates are different, false otherwise. - */ -template -bool operator!=(const Delegate &lhs, const Delegate &rhs) ENTT_NOEXCEPT { - return !(lhs == rhs); -} - - -} - - -#endif // ENTT_SIGNAL_DELEGATE_HPP diff --git a/external/entt/signal/dispatcher.hpp b/external/entt/signal/dispatcher.hpp deleted file mode 100644 index 8743ebd7a..000000000 --- a/external/entt/signal/dispatcher.hpp +++ /dev/null @@ -1,188 +0,0 @@ -#ifndef ENTT_SIGNAL_DISPATCHER_HPP -#define ENTT_SIGNAL_DISPATCHER_HPP - - -#include -#include -#include -#include -#include -#include -#include "../config/config.h" -#include "../core/family.hpp" -#include "sigh.hpp" - - -namespace entt { - - -/** - * @brief Basic dispatcher implementation. - * - * A dispatcher can be used either to trigger an immediate event or to enqueue - * events to be published all together once per tick.
- * Listeners are provided in the form of member functions. For each event of - * type `Event`, listeners must have the following function type: - * @code{.cpp} - * void(const Event &) - * @endcode - * - * Member functions named `receive` are automatically detected and registered or - * unregistered by the dispatcher. The type of the instances is `Class *` (a - * naked pointer). It means that users must guarantee that the lifetimes of the - * instances overcome the one of the dispatcher itself to avoid crashes. - */ -class Dispatcher final { - using event_family = Family; - - template - using instance_type = typename SigH::template instance_type; - - struct BaseSignalWrapper { - virtual ~BaseSignalWrapper() = default; - virtual void publish() = 0; - }; - - template - struct SignalWrapper final: BaseSignalWrapper { - using sink_type = typename SigH::sink_type; - - void publish() override { - const auto &curr = current++; - current %= std::extent::value; - std::for_each(events[curr].cbegin(), events[curr].cend(), [this](const auto &event) { signal.publish(event); }); - events[curr].clear(); - } - - inline sink_type sink() ENTT_NOEXCEPT { - return signal.sink(); - } - - template - inline void trigger(Args &&... args) { - signal.publish({ std::forward(args)... }); - } - - template - inline void enqueue(Args &&... args) { - events[current].push_back({ std::forward(args)... }); - } - - private: - SigH signal{}; - std::vector events[2]; - int current{}; - }; - - template - SignalWrapper & wrapper() { - const auto type = event_family::type(); - - if(!(type < wrappers.size())) { - wrappers.resize(type + 1); - } - - if(!wrappers[type]) { - wrappers[type] = std::make_unique>(); - } - - return static_cast &>(*wrappers[type]); - } - -public: - /*! @brief Type of sink for the given event. */ - template - using sink_type = typename SignalWrapper::sink_type; - - /** - * @brief Returns a sink object for the given event. - * - * A sink is an opaque object used to connect listeners to events. - * - * The function type for a listener is: - * @code{.cpp} - * void(const Event &) - * @endcode - * - * The order of invocation of the listeners isn't guaranteed. - * - * @sa SigH::Sink - * - * @tparam Event Type of event of which to get the sink. - * @return A temporary sink object. - */ - template - inline sink_type sink() ENTT_NOEXCEPT { - return wrapper().sink(); - } - - /** - * @brief Triggers an immediate event of the given type. - * - * All the listeners registered for the given type are immediately notified. - * The event is discarded after the execution. - * - * @tparam Event Type of event to trigger. - * @tparam Args Types of arguments to use to construct the event. - * @param args Arguments to use to construct the event. - */ - template - inline void trigger(Args &&... args) { - wrapper().trigger(std::forward(args)...); - } - - /** - * @brief Enqueues an event of the given type. - * - * An event of the given type is queued. No listener is invoked. Use the - * `update` member function to notify listeners when ready. - * - * @tparam Event Type of event to trigger. - * @tparam Args Types of arguments to use to construct the event. - * @param args Arguments to use to construct the event. - */ - template - inline void enqueue(Args &&... args) { - wrapper().enqueue(std::forward(args)...); - } - - /** - * @brief Delivers all the pending events of the given type. - * - * This method is blocking and it doesn't return until all the events are - * delivered to the registered listeners. It's responsibility of the users - * to reduce at a minimum the time spent in the bodies of the listeners. - * - * @tparam Event Type of events to send. - */ - template - inline void update() { - wrapper().publish(); - } - - /** - * @brief Delivers all the pending events. - * - * This method is blocking and it doesn't return until all the events are - * delivered to the registered listeners. It's responsibility of the users - * to reduce at a minimum the time spent in the bodies of the listeners. - */ - inline void update() const { - for(auto pos = wrappers.size(); pos; --pos) { - auto &wrapper = wrappers[pos-1]; - - if(wrapper) { - wrapper->publish(); - } - } - } - -private: - std::vector> wrappers; -}; - - -} - - -#endif // ENTT_SIGNAL_DISPATCHER_HPP diff --git a/external/entt/signal/emitter.hpp b/external/entt/signal/emitter.hpp deleted file mode 100644 index 39ef3d1b5..000000000 --- a/external/entt/signal/emitter.hpp +++ /dev/null @@ -1,336 +0,0 @@ -#ifndef ENTT_SIGNAL_EMITTER_HPP -#define ENTT_SIGNAL_EMITTER_HPP - - -#include -#include -#include -#include -#include -#include -#include -#include -#include "../config/config.h" -#include "../core/family.hpp" - - -namespace entt { - - -/** - * @brief General purpose event emitter. - * - * The emitter class template follows the CRTP idiom. To create a custom emitter - * type, derived classes must inherit directly from the base class as: - * - * ```cpp - * struct MyEmitter: Emitter { - * // ... - * } - * ``` - * - * Handlers for the type of events are created internally on the fly. It's not - * required to specify in advance the full list of accepted types.
- * Moreover, whenever an event is published, an emitter provides the listeners - * with a reference to itself along with a const reference to the event. - * Therefore listeners have an handy way to work with it without incurring in - * the need of capturing a reference to the emitter. - * - * @tparam Derived Actual type of emitter that extends the class template. - */ -template -class Emitter { - using handler_family = Family; - - struct BaseHandler { - virtual ~BaseHandler() = default; - virtual bool empty() const ENTT_NOEXCEPT = 0; - virtual void clear() ENTT_NOEXCEPT = 0; - }; - - template - struct Handler final: BaseHandler { - using listener_type = std::function; - using element_type = std::pair; - using container_type = std::list; - using connection_type = typename container_type::iterator; - - bool empty() const ENTT_NOEXCEPT override { - auto pred = [](auto &&element) { return element.first; }; - - return std::all_of(onceL.cbegin(), onceL.cend(), pred) && - std::all_of(onL.cbegin(), onL.cend(), pred); - } - - void clear() ENTT_NOEXCEPT override { - if(publishing) { - auto func = [](auto &&element) { element.first = true; }; - std::for_each(onceL.begin(), onceL.end(), func); - std::for_each(onL.begin(), onL.end(), func); - } else { - onceL.clear(); - onL.clear(); - } - } - - inline connection_type once(listener_type listener) { - return onceL.emplace(onceL.cend(), false, std::move(listener)); - } - - inline connection_type on(listener_type listener) { - return onL.emplace(onL.cend(), false, std::move(listener)); - } - - void erase(connection_type conn) ENTT_NOEXCEPT { - conn->first = true; - - if(!publishing) { - auto pred = [](auto &&element) { return element.first; }; - onceL.remove_if(pred); - onL.remove_if(pred); - } - } - - void publish(const Event &event, Derived &ref) { - container_type currentL; - onceL.swap(currentL); - - auto func = [&event, &ref](auto &&element) { - return element.first ? void() : element.second(event, ref); - }; - - publishing = true; - - std::for_each(onL.rbegin(), onL.rend(), func); - std::for_each(currentL.rbegin(), currentL.rend(), func); - - publishing = false; - - onL.remove_if([](auto &&element) { return element.first; }); - } - - private: - bool publishing{false}; - container_type onceL{}; - container_type onL{}; - }; - - template - Handler & handler() ENTT_NOEXCEPT { - const std::size_t family = handler_family::type(); - - if(!(family < handlers.size())) { - handlers.resize(family+1); - } - - if(!handlers[family]) { - handlers[family] = std::make_unique>(); - } - - return static_cast &>(*handlers[family]); - } - -public: - /** @brief Type of listeners accepted for the given event. */ - template - using Listener = typename Handler::listener_type; - - /** - * @brief Generic connection type for events. - * - * Type of the connection object returned by the event emitter whenever a - * listener for the given type is registered.
- * It can be used to break connections still in use. - * - * @tparam Event Type of event for which the connection is created. - */ - template - struct Connection final: private Handler::connection_type { - /** @brief Event emitters are friend classes of connections. */ - friend class Emitter; - - /*! @brief Default constructor. */ - Connection() ENTT_NOEXCEPT = default; - - /** - * @brief Creates a connection that wraps its underlying instance. - * @param conn A connection object to wrap. - */ - Connection(typename Handler::connection_type conn) - : Handler::connection_type{std::move(conn)} - {} - - /*! @brief Default copy constructor. */ - Connection(const Connection &) = default; - /*! @brief Default move constructor. */ - Connection(Connection &&) = default; - - /** - * @brief Default copy assignment operator. - * @return This connection. - */ - Connection & operator=(const Connection &) = default; - - /** - * @brief Default move assignment operator. - * @return This connection. - */ - Connection & operator=(Connection &&) = default; - }; - - /*! @brief Default constructor. */ - Emitter() ENTT_NOEXCEPT = default; - - /*! @brief Default destructor. */ - virtual ~Emitter() ENTT_NOEXCEPT { - static_assert(std::is_base_of, Derived>::value, "!"); - } - - /*! @brief Copying an emitter isn't allowed. */ - Emitter(const Emitter &) = delete; - /*! @brief Default move constructor. */ - Emitter(Emitter &&) = default; - - /*! @brief Copying an emitter isn't allowed. @return This emitter. */ - Emitter & operator=(const Emitter &) = delete; - /*! @brief Default move assignment operator. @return This emitter. */ - Emitter & operator=(Emitter &&) = default; - - /** - * @brief Emits the given event. - * - * All the listeners registered for the specific event type are invoked with - * the given event. The event type must either have a proper constructor for - * the arguments provided or be an aggregate type. - * - * @tparam Event Type of event to publish. - * @tparam Args Types of arguments to use to construct the event. - * @param args Parameters to use to initialize the event. - */ - template - void publish(Args &&... args) { - handler().publish({ std::forward(args)... }, *static_cast(this)); - } - - /** - * @brief Registers a long-lived listener with the event emitter. - * - * This method can be used to register a listener designed to be invoked - * more than once for the given event type.
- * The connection returned by the method can be freely discarded. It's meant - * to be used later to disconnect the listener if required. - * - * The listener is as a callable object that can be moved and the type of - * which is `void(const Event &, Derived &)`. - * - * @note - * Whenever an event is emitted, the emitter provides the listener with a - * reference to the derived class. Listeners don't have to capture those - * instances for later uses. - * - * @tparam Event Type of event to which to connect the listener. - * @param listener The listener to register. - * @return Connection object that can be used to disconnect the listener. - */ - template - Connection on(Listener listener) { - return handler().on(std::move(listener)); - } - - /** - * @brief Registers a short-lived listener with the event emitter. - * - * This method can be used to register a listener designed to be invoked - * only once for the given event type.
- * The connection returned by the method can be freely discarded. It's meant - * to be used later to disconnect the listener if required. - * - * The listener is as a callable object that can be moved and the type of - * which is `void(const Event &, Derived &)`. - * - * @note - * Whenever an event is emitted, the emitter provides the listener with a - * reference to the derived class. Listeners don't have to capture those - * instances for later uses. - * - * @tparam Event Type of event to which to connect the listener. - * @param listener The listener to register. - * @return Connection object that can be used to disconnect the listener. - */ - template - Connection once(Listener listener) { - return handler().once(std::move(listener)); - } - - /** - * @brief Disconnects a listener from the event emitter. - * - * Do not use twice the same connection to disconnect a listener, it results - * in undefined behavior. Once used, discard the connection object. - * - * @tparam Event Type of event of the connection. - * @param conn A valid connection. - */ - template - void erase(Connection conn) ENTT_NOEXCEPT { - handler().erase(std::move(conn)); - } - - /** - * @brief Disconnects all the listeners for the given event type. - * - * All the connections previously returned for the given event are - * invalidated. Using them results in undefined behavior. - * - * @tparam Event Type of event to reset. - */ - template - void clear() ENTT_NOEXCEPT { - handler().clear(); - } - - /** - * @brief Disconnects all the listeners. - * - * All the connections previously returned are invalidated. Using them - * results in undefined behavior. - */ - void clear() ENTT_NOEXCEPT { - std::for_each(handlers.begin(), handlers.end(), [](auto &&handler) { - return handler ? handler->clear() : void(); - }); - } - - /** - * @brief Checks if there are listeners registered for the specific event. - * @tparam Event Type of event to test. - * @return True if there are no listeners registered, false otherwise. - */ - template - bool empty() const ENTT_NOEXCEPT { - const std::size_t family = handler_family::type(); - - return (!(family < handlers.size()) || - !handlers[family] || - static_cast &>(*handlers[family]).empty()); - } - - /** - * @brief Checks if there are listeners registered with the event emitter. - * @return True if there are no listeners registered, false otherwise. - */ - bool empty() const ENTT_NOEXCEPT { - return std::all_of(handlers.cbegin(), handlers.cend(), [](auto &&handler) { - return !handler || handler->empty(); - }); - } - -private: - std::vector> handlers{}; -}; - - -} - - -#endif // ENTT_SIGNAL_EMITTER_HPP diff --git a/external/entt/signal/sigh.hpp b/external/entt/signal/sigh.hpp deleted file mode 100644 index d6f795fd7..000000000 --- a/external/entt/signal/sigh.hpp +++ /dev/null @@ -1,426 +0,0 @@ -#ifndef ENTT_SIGNAL_SIGH_HPP -#define ENTT_SIGNAL_SIGH_HPP - - -#include -#include -#include -#include "../config/config.h" - - -namespace entt { - - -/** - * @cond TURN_OFF_DOXYGEN - * Internal details not to be documented. - */ - - -namespace internal { - - -template -struct sigh_traits; - - -template -struct sigh_traits { - using proto_fn_type = Ret(void *, Args...); - using call_type = std::pair; -}; - - -template -struct Invoker; - - -template -struct Invoker { - using proto_fn_type = typename sigh_traits::proto_fn_type; - - virtual ~Invoker() = default; - - bool invoke(Collector &collector, proto_fn_type *proto, void *instance, Args... args) const { - return collector(proto(instance, args...)); - } -}; - - -template -struct Invoker { - using proto_fn_type = typename sigh_traits::proto_fn_type; - - virtual ~Invoker() = default; - - bool invoke(Collector &, proto_fn_type *proto, void *instance, Args... args) const { - return (proto(instance, args...), true); - } -}; - - -template -struct NullCollector final { - using result_type = Ret; - bool operator()(result_type) const ENTT_NOEXCEPT { return true; } -}; - - -template<> -struct NullCollector final { - using result_type = void; - bool operator()() const ENTT_NOEXCEPT { return true; } -}; - - -template -struct DefaultCollector; - - -template -struct DefaultCollector final { - using collector_type = NullCollector; -}; - - -template -using DefaultCollectorType = typename DefaultCollector::collector_type; - - -} - - -/** - * Internal details not to be documented. - * @endcond TURN_OFF_DOXYGEN - */ - - -/** - * @brief Sink implementation. - * - * Primary template isn't defined on purpose. All the specializations give a - * compile-time error unless the template parameter is a function type. - * - * @tparam Function A valid function type. - */ -template -class Sink; - - -/** - * @brief Unmanaged signal handler declaration. - * - * Primary template isn't defined on purpose. All the specializations give a - * compile-time error unless the template parameter is a function type. - * - * @tparam Function A valid function type. - * @tparam Collector Type of collector to use, if any. - */ -template> -class SigH; - - -/** - * @brief Sink implementation. - * - * A sink is an opaque object used to connect listeners to signals.
- * The function type for a listener is the one of the signal to which it - * belongs. - * - * The clear separation between a signal and a sink permits to store the - * former as private data member without exposing the publish functionality - * to the users of a class. - * - * @tparam Ret Return type of a function type. - * @tparam Args Types of arguments of a function type. - */ -template -class Sink final { - /*! @brief A signal is allowed to create sinks. */ - template - friend class SigH; - - using call_type = typename internal::sigh_traits::call_type; - - template - static Ret proto(void *, Args... args) { - return (Function)(args...); - } - - template - static Ret proto(void *instance, Args... args) { - return (static_cast(instance)->*Member)(args...); - } - - template - static Ret proto(void *instance, Args... args) { - return (static_cast(instance)->*Member)(args...); - } - - Sink(std::vector *calls) ENTT_NOEXCEPT - : calls{calls} - {} - -public: - /** - * @brief Connects a free function to a signal. - * - * The signal handler performs checks to avoid multiple connections for - * free functions. - * - * @tparam Function A valid free function pointer. - */ - template - void connect() { - disconnect(); - calls->emplace_back(nullptr, &proto); - } - - /** - * @brief Connects a member function for a given instance to a signal. - * - * The signal isn't responsible for the connected object. Users must - * guarantee that the lifetime of the instance overcomes the one of the - * signal. On the other side, the signal handler performs checks to - * avoid multiple connections for the same member function of a given - * instance. - * - * @tparam Class Type of class to which the member function belongs. - * @tparam Member Member function to connect to the signal. - * @param instance A valid instance of type pointer to `Class`. - */ - template - void connect(Class *instance) { - disconnect(instance); - calls->emplace_back(instance, &proto); - } - - /** - * @brief Connects a member function for a given instance to a signal. - * - * The signal isn't responsible for the connected object. Users must - * guarantee that the lifetime of the instance overcomes the one of the - * signal. On the other side, the signal handler performs checks to - * avoid multiple connections for the same member function of a given - * instance. - * - * @tparam Class Type of class to which the member function belongs. - * @tparam Member Member function to connect to the signal. - * @param instance A valid instance of type pointer to `Class`. - */ - template - void connect(Class *instance) { - disconnect(instance); - calls->emplace_back(instance, &proto); - } - - /** - * @brief Disconnects a free function from a signal. - * @tparam Function A valid free function pointer. - */ - template - void disconnect() { - call_type target{nullptr, &proto}; - calls->erase(std::remove(calls->begin(), calls->end(), std::move(target)), calls->end()); - } - - /** - * @brief Disconnects the given member function from a signal. - * @tparam Class Type of class to which the member function belongs. - * @tparam Member Member function to connect to the signal. - * @param instance A valid instance of type pointer to `Class`. - */ - template - void disconnect(Class *instance) { - call_type target{instance, &proto}; - calls->erase(std::remove(calls->begin(), calls->end(), std::move(target)), calls->end()); - } - - /** - * @brief Disconnects the given member function from a signal. - * @tparam Class Type of class to which the member function belongs. - * @tparam Member Member function to connect to the signal. - * @param instance A valid instance of type pointer to `Class`. - */ - template - void disconnect(Class *instance) { - call_type target{instance, &proto}; - calls->erase(std::remove(calls->begin(), calls->end(), std::move(target)), calls->end()); - } - - /** - * @brief Removes all existing connections for the given instance. - * @tparam Class Type of class to which the member function belongs. - * @param instance A valid instance of type pointer to `Class`. - */ - template - void disconnect(Class *instance) { - auto func = [instance](const call_type &call) { return call.first == instance; }; - calls->erase(std::remove_if(calls->begin(), calls->end(), std::move(func)), calls->end()); - } - - /** - * @brief Disconnects all the listeners from a signal. - */ - void disconnect() { - calls->clear(); - } - -private: - std::vector *calls; -}; - - -/** - * @brief Unmanaged signal handler definition. - * - * Unmanaged signal handler. It works directly with naked pointers to classes - * and pointers to member functions as well as pointers to free functions. Users - * of this class are in charge of disconnecting instances before deleting them. - * - * This class serves mainly two purposes: - * - * * Creating signals used later to notify a bunch of listeners. - * * Collecting results from a set of functions like in a voting system. - * - * The default collector does nothing. To properly collect data, define and use - * a class that has a call operator the signature of which is `bool(Param)` and: - * - * * `Param` is a type to which `Ret` can be converted. - * * The return type is true if the handler must stop collecting data, false - * otherwise. - * - * @tparam Ret Return type of a function type. - * @tparam Args Types of arguments of a function type. - * @tparam Collector Type of collector to use, if any. - */ -template -class SigH final: private internal::Invoker { - using call_type = typename internal::sigh_traits::call_type; - -public: - /*! @brief Unsigned integer type. */ - using size_type = typename std::vector::size_type; - /*! @brief Collector type. */ - using collector_type = Collector; - /*! @brief Sink type. */ - using sink_type = Sink; - - /** - * @brief Instance type when it comes to connecting member functions. - * @tparam Class Type of class to which the member function belongs. - */ - template - using instance_type = Class *; - - /** - * @brief Number of listeners connected to the signal. - * @return Number of listeners currently connected. - */ - size_type size() const ENTT_NOEXCEPT { - return calls.size(); - } - - /** - * @brief Returns false if at least a listener is connected to the signal. - * @return True if the signal has no listeners connected, false otherwise. - */ - bool empty() const ENTT_NOEXCEPT { - return calls.empty(); - } - - /** - * @brief Returns a sink object for the given signal. - * - * A sink is an opaque object used to connect listeners to signals.
- * The function type for a listener is the one of the signal to which it - * belongs. The order of invocation of the listeners isn't guaranteed. - * - * @return A temporary sink object. - */ - sink_type sink() ENTT_NOEXCEPT { - return { &calls }; - } - - /** - * @brief Triggers a signal. - * - * All the listeners are notified. Order isn't guaranteed. - * - * @param args Arguments to use to invoke listeners. - */ - void publish(Args... args) const { - for(auto pos = calls.size(); pos; --pos) { - auto &call = calls[pos-1]; - call.second(call.first, args...); - } - } - - /** - * @brief Collects return values from the listeners. - * @param args Arguments to use to invoke listeners. - * @return An instance of the collector filled with collected data. - */ - collector_type collect(Args... args) const { - collector_type collector; - - for(auto &&call: calls) { - if(!this->invoke(collector, call.second, call.first, args...)) { - break; - } - } - - return collector; - } - - /** - * @brief Swaps listeners between the two signals. - * @param lhs A valid signal object. - * @param rhs A valid signal object. - */ - friend void swap(SigH &lhs, SigH &rhs) { - using std::swap; - swap(lhs.calls, rhs.calls); - } - - /** - * @brief Checks if the contents of the two signals are identical. - * - * Two signals are identical if they have the same size and the same - * listeners registered exactly in the same order. - * - * @param other Signal with which to compare. - * @return True if the two signals are identical, false otherwise. - */ - bool operator==(const SigH &other) const ENTT_NOEXCEPT { - return std::equal(calls.cbegin(), calls.cend(), other.calls.cbegin(), other.calls.cend()); - } - -private: - std::vector calls; -}; - - -/** - * @brief Checks if the contents of the two signals are different. - * - * Two signals are identical if they have the same size and the same - * listeners registered exactly in the same order. - * - * @tparam Ret Return type of a function type. - * @tparam Args Types of arguments of a function type. - * @param lhs A valid signal object. - * @param rhs A valid signal object. - * @return True if the two signals are different, false otherwise. - */ -template -bool operator!=(const SigH &lhs, const SigH &rhs) ENTT_NOEXCEPT { - return !(lhs == rhs); -} - - -} - - -#endif // ENTT_SIGNAL_SIGH_HPP diff --git a/source/client/CMakeLists.txt b/source/client/CMakeLists.txt index 474e73b44..17eb259a1 100644 --- a/source/client/CMakeLists.txt +++ b/source/client/CMakeLists.txt @@ -7,7 +7,9 @@ set(PROJECT_NAME ${CMAKE_PROJECT_NAME}) # Get source files #------------------------------------------------------------------------------ file(GLOB_RECURSE SOURCE_FILES *.cpp) -file(GLOB_RECURSE HEADER_FILES *.hpp ../server/*.hpp ../common/*.hpp ../../external/*.hpp) +file(GLOB_RECURSE HEADER_FILES *.hpp ../server/*.hpp ../common/*.hpp) + +include_directories(../../external ../../external/entt/single_include) foreach(HEADER_FILE ${HEADER_FILES}) get_filename_component(HEADER_DIRECTORY ${HEADER_FILE} DIRECTORY) diff --git a/source/client/scene/RenderingController.cpp b/source/client/scene/RenderingController.cpp index 696bf119f..b86c9e5ef 100644 --- a/source/client/scene/RenderingController.cpp +++ b/source/client/scene/RenderingController.cpp @@ -38,9 +38,7 @@ void RenderingController::draw(entt::registry ®istry, gk::RenderTarget &targe registry.view().each([&](auto entity, auto &drawableDef) { const InventoryCubeDef &cubeDef = drawableDef.getInventoryCubeDef(); - DrawableComponent &drawable = (!registry.has()) - ? registry.assign(entity) - : registry.get(entity); + DrawableComponent &drawable = registry.get_or_assign(entity); InventoryCube &cube = drawable.setDrawable(cubeDef.size, true); cube.setOrigin(cubeDef.origin); diff --git a/source/common/CMakeLists.txt b/source/common/CMakeLists.txt index 35235c0f6..bfadc9203 100644 --- a/source/common/CMakeLists.txt +++ b/source/common/CMakeLists.txt @@ -7,7 +7,9 @@ set(PROJECT_NAME ${CMAKE_PROJECT_NAME}_common) # Get source files #------------------------------------------------------------------------------ file(GLOB_RECURSE SOURCE_FILES *.cpp) -file(GLOB_RECURSE HEADER_FILES *.hpp ../../external/*.hpp) +file(GLOB_RECURSE HEADER_FILES *.hpp) + +include_directories(../../external ../../external/entt/single_include) foreach(HEADER_FILE ${HEADER_FILES}) get_filename_component(HEADER_DIRECTORY ${HEADER_FILE} DIRECTORY) @@ -18,6 +20,7 @@ endforeach(HEADER_FILE) # Add library #------------------------------------------------------------------------------ add_library(${PROJECT_NAME} STATIC ${SOURCE_FILES}) +add_dependencies(${PROJECT_NAME} EnTT) #------------------------------------------------------------------------------ # Compiler flags diff --git a/source/common/scene/SceneSerializer.cpp b/source/common/scene/SceneSerializer.cpp index bf1d90129..75888f9b1 100644 --- a/source/common/scene/SceneSerializer.cpp +++ b/source/common/scene/SceneSerializer.cpp @@ -31,36 +31,36 @@ #include "SceneSerializer.hpp" void SceneSerializer::serialize(sf::Packet &packet, const Scene &scene) const { - m_outputArchive.setPacket(packet); + // m_outputArchive.setPacket(packet); - scene.registry().snapshot().component< - AnimationComponent, - gk::DoubleBox, - ItemStack, - gk::Transformable, - DrawableDef - >(m_outputArchive); + // scene.registry().snapshot().component< + // AnimationComponent, + // gk::DoubleBox, + // ItemStack, + // gk::Transformable, + // DrawableDef + // >(m_outputArchive); } void SceneSerializer::deserialize(sf::Packet &packet, Scene &scene) { - m_inputArchive.setPacket(packet); + // m_inputArchive.setPacket(packet); - scene.registry().restore().component< - AnimationComponent, - gk::DoubleBox, - ItemStack, - gk::Transformable, - DrawableDef - >(m_inputArchive); + // scene.registry().restore().component< + // AnimationComponent, + // gk::DoubleBox, + // ItemStack, + // gk::Transformable, + // DrawableDef + // >(m_inputArchive); } -void SceneSerializer::OutputArchive::operator()(Entity entity) { - // gkDebug() << entity; - (*m_packet) << entity; -} - -void SceneSerializer::InputArchive::operator()(Entity &entity) { - (*m_packet) >> entity; - // gkDebug() << entity; -} +// void SceneSerializer::OutputArchive::operator()(Entity entity) { +// // gkDebug() << entity; +// // (*m_packet) << entity; +// } +// +// void SceneSerializer::InputArchive::operator()(Entity &entity) { +// // (*m_packet) >> entity; +// // gkDebug() << entity; +// } diff --git a/source/common/scene/SceneSerializer.hpp b/source/common/scene/SceneSerializer.hpp index 2243186f7..419f10a85 100644 --- a/source/common/scene/SceneSerializer.hpp +++ b/source/common/scene/SceneSerializer.hpp @@ -43,43 +43,43 @@ class SceneSerializer { void deserialize(sf::Packet &packet, Scene &scene); private: - class OutputArchive { - public: - void operator()(Entity entity); - - template - void operator()(Entity entity, const T &value) { - // gkDebug() << entity << (void *)&value << typeid(T).name(); - (*m_packet) << entity << value; - // FIXME: It should be possible to check the type here and to create - // a defintion struct to serialize for some of them - // instead of sending the component - } - - void setPacket(sf::Packet &packet) { m_packet = &packet; } - - private: - sf::Packet *m_packet = nullptr; - }; - - class InputArchive { - public: - void operator()(Entity &entity); - - template - void operator()(Entity &entity, T &value) { - (*m_packet) >> entity >> value; - // gkDebug() << entity << (void *)&value << typeid(T).name(); - } - - void setPacket(sf::Packet &packet) { m_packet = &packet; } - - private: - sf::Packet *m_packet = nullptr; - }; - - mutable OutputArchive m_outputArchive; - mutable InputArchive m_inputArchive; + // class OutputArchive { + // public: + // void operator()(Entity entity); + // + // template + // void operator()(Entity entity, const T &value) { + // // gkDebug() << entity << (void *)&value << typeid(T).name(); + // // (*m_packet) << entity << value; + // // FIXME: It should be possible to check the type here and to create + // // a defintion struct to serialize for some of them + // // instead of sending the component + // } + // + // void setPacket(sf::Packet &packet) { m_packet = &packet; } + // + // private: + // sf::Packet *m_packet = nullptr; + // }; + // + // class InputArchive { + // public: + // void operator()(Entity &entity); + // + // template + // void operator()(Entity &entity, T &value) { + // // (*m_packet) >> entity >> value; + // // gkDebug() << entity << (void *)&value << typeid(T).name(); + // } + // + // void setPacket(sf::Packet &packet) { m_packet = &packet; } + // + // private: + // sf::Packet *m_packet = nullptr; + // }; + // + // mutable OutputArchive m_outputArchive; + // mutable InputArchive m_inputArchive; }; #endif // SCENESERIALIZER_HPP_ diff --git a/source/server/CMakeLists.txt b/source/server/CMakeLists.txt index ab136739f..1914331bf 100644 --- a/source/server/CMakeLists.txt +++ b/source/server/CMakeLists.txt @@ -6,8 +6,10 @@ set(PROJECT_NAME ${PROJECT_NAME}_server) #------------------------------------------------------------------------------ # Get source files #------------------------------------------------------------------------------ -file(GLOB_RECURSE SOURCE_FILES */*.cpp ../../external/*.cpp) -file(GLOB_RECURSE HEADER_FILES *.hpp ../common/*.hpp ../../external/*.hpp) +file(GLOB_RECURSE SOURCE_FILES */*.cpp ../../external/FastNoise.cpp) +file(GLOB_RECURSE HEADER_FILES *.hpp ../common/*.hpp) + +include_directories(../../external ../../external/entt/single_include) foreach(HEADER_FILE ${HEADER_FILES}) get_filename_component(HEADER_DIRECTORY ${HEADER_FILE} DIRECTORY)