diff --git a/include/Cubed/gameplay/client_world.hpp b/include/Cubed/gameplay/client_world.hpp index 7af32c1..dee5d9b 100644 --- a/include/Cubed/gameplay/client_world.hpp +++ b/include/Cubed/gameplay/client_world.hpp @@ -15,7 +15,6 @@ #include #include -#include #include #include #include @@ -102,7 +101,6 @@ public: void send_chat_message(ChatMessage& message); void receive_voice_message(VoiceMsg& msg); bool enable_voice_chat() const; - const entt::registry& get_registry(); int get_per_tick_time() const override; template void register_ticktimer(std::string_view id, TickType threshold, Fn&& f) { @@ -111,17 +109,6 @@ public: std::forward_as_tuple(threshold, std::forward(f))); } - template - entt::entity create_entity(Components&&... components) { - auto e = m_registry.create(); - - (m_registry.emplace>( - e, std::forward(components)), - ...); - - return e; - } - private: struct VoiceMessage { std::string data; @@ -151,10 +138,7 @@ private: static constexpr int WORLD_EXIT_TIMEOUT = 200; static constexpr int MAX_UPLOAD_CHUNK_SUM = 16; - entt::registry m_registry; - ClientPlayer m_player; - std::unordered_map m_player_entities; ChunkHashMap m_chunks; AudioEngine& m_audio; Config& m_config; diff --git a/include/Cubed/gameplay/move_system.hpp b/include/Cubed/gameplay/move_system.hpp deleted file mode 100644 index a5fee1c..0000000 --- a/include/Cubed/gameplay/move_system.hpp +++ /dev/null @@ -1,20 +0,0 @@ -#pragma once -#include "Cubed/gameplay/entity.hpp" -#include "Cubed/gameplay/world.hpp" - -#include -namespace Cubed { - -class MoveSystem { -public: - static void update(World& world, entt::registry& registry); - -private: - static void move_x(World& world, Transform& transform, Velocity& v, - const EntityInfo& info); - static void move_y(World& world, Transform& transform, Velocity& v, - const EntityInfo& info); - static void move_z(World& world, Transform& transform, Velocity& v, - const EntityInfo& info); -}; -} // namespace Cubed \ No newline at end of file diff --git a/include/entt/.clang-format b/include/entt/.clang-format deleted file mode 100644 index 9d15924..0000000 --- a/include/entt/.clang-format +++ /dev/null @@ -1,2 +0,0 @@ -DisableFormat: true -SortIncludes: false diff --git a/include/entt/config/config.h b/include/entt/config/config.h deleted file mode 100644 index a200d29..0000000 --- a/include/entt/config/config.h +++ /dev/null @@ -1,134 +0,0 @@ -#ifndef ENTT_CONFIG_CONFIG_H -#define ENTT_CONFIG_CONFIG_H - -#if __has_include() -# include -#endif - -#include -#include "version.h" - -// NOLINTBEGIN(cppcoreguidelines-macro-usage) - -#ifdef ENTT_USE_STL -# define ENTT_FORCE_STL -#endif - -#if defined(__cpp_exceptions) && !defined(ENTT_NO_EXCEPTION) -# define ENTT_THROW throw -# define ENTT_TRY try -# define ENTT_CATCH catch(...) -#else -# define ENTT_THROW -# define ENTT_TRY if(true) -# define ENTT_CATCH if(false) -#endif - -#if defined(__cpp_consteval) -# define ENTT_CONSTEVAL consteval -#else -# define ENTT_CONSTEVAL constexpr -#endif - -#ifdef ENTT_USE_ATOMIC -# include "../stl/atomic.hpp" -# define ENTT_MAYBE_ATOMIC(Type) stl::atomic -#else -# define ENTT_MAYBE_ATOMIC(Type) Type -#endif - -#ifndef ENTT_ID_TYPE -# include "../stl/cstdint.hpp" -# define ENTT_ID_TYPE stl::uint32_t -#else -# include "../stl/cstdint.hpp" // provides coverage for types in the std namespace -#endif - -#ifndef ENTT_SPARSE_PAGE -# define ENTT_SPARSE_PAGE 4096 -#endif - -#ifndef ENTT_PACKED_PAGE -# define ENTT_PACKED_PAGE 1024 -#endif - -#ifdef ENTT_DISABLE_ASSERT -# undef ENTT_ASSERT -# define ENTT_ASSERT(condition, msg) (void(0)) -#elif !defined ENTT_ASSERT -# include -# define ENTT_ASSERT(condition, msg) assert(((condition) && (msg))) -#endif - -#ifdef ENTT_DISABLE_ASSERT -# undef ENTT_ASSERT_CONSTEXPR -# define ENTT_ASSERT_CONSTEXPR(condition, msg) (void(0)) -#elif !defined ENTT_ASSERT_CONSTEXPR -# define ENTT_ASSERT_CONSTEXPR(condition, msg) ENTT_ASSERT(condition, msg) -#endif - -#define ENTT_FAIL(msg) ENTT_ASSERT(false, msg); - -#ifdef ENTT_NO_ETO -# define ENTT_ETO_TYPE(Type) void -#else -# define ENTT_ETO_TYPE(Type) Type -#endif - -#ifdef ENTT_NO_MIXIN -# define ENTT_STORAGE(Mixin, ...) __VA_ARGS__ -#else -# define ENTT_STORAGE(Mixin, ...) Mixin<__VA_ARGS__> -#endif - -#ifdef ENTT_STANDARD_CPP -# define ENTT_NONSTD false -#else -# define ENTT_NONSTD true -# if defined __clang__ || defined __GNUC__ -# define ENTT_PRETTY_FUNCTION __PRETTY_FUNCTION__ -# define ENTT_PRETTY_FUNCTION_PREFIX '=' -# define ENTT_PRETTY_FUNCTION_SUFFIX ']' -# elif defined _MSC_VER -# define ENTT_PRETTY_FUNCTION __FUNCSIG__ -# define ENTT_PRETTY_FUNCTION_PREFIX '<' -# define ENTT_PRETTY_FUNCTION_SUFFIX '>' -# endif -#endif - -#ifndef ENTT_EXPORT -# if defined _WIN32 || defined __CYGWIN__ || defined _MSC_VER -# define ENTT_EXPORT __declspec(dllexport) -# define ENTT_IMPORT __declspec(dllimport) -# define ENTT_HIDDEN -# elif defined __GNUC__ && __GNUC__ >= 4 -# define ENTT_EXPORT __attribute__((visibility("default"))) -# define ENTT_IMPORT __attribute__((visibility("default"))) -# define ENTT_HIDDEN __attribute__((visibility("hidden"))) -# else /* Unsupported compiler */ -# define ENTT_EXPORT -# define ENTT_IMPORT -# define ENTT_HIDDEN -# endif -#endif - -#ifndef ENTT_API -# if defined ENTT_API_EXPORT -# define ENTT_API ENTT_EXPORT -# elif defined ENTT_API_IMPORT -# define ENTT_API ENTT_IMPORT -# else /* No API */ -# define ENTT_API -# endif -#endif - -#if defined _MSC_VER -# pragma detect_mismatch("entt.version", ENTT_VERSION) -# pragma detect_mismatch("entt.noexcept", ENTT_XSTR(ENTT_TRY)) -# pragma detect_mismatch("entt.id", ENTT_XSTR(ENTT_ID_TYPE)) -# pragma detect_mismatch("entt.nonstd", ENTT_XSTR(ENTT_NONSTD)) -#endif - -// NOLINTEND(cppcoreguidelines-macro-usage) - -#endif diff --git a/include/entt/config/macro.h b/include/entt/config/macro.h deleted file mode 100644 index b7b2323..0000000 --- a/include/entt/config/macro.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef ENTT_CONFIG_MACRO_H -#define ENTT_CONFIG_MACRO_H - -// NOLINTBEGIN(cppcoreguidelines-macro-usage) - -#define ENTT_STR(arg) #arg -#define ENTT_XSTR(arg) ENTT_STR(arg) - -// NOLINTEND(cppcoreguidelines-macro-usage) - -#endif diff --git a/include/entt/config/version.h b/include/entt/config/version.h deleted file mode 100644 index d014997..0000000 --- a/include/entt/config/version.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef ENTT_CONFIG_VERSION_H -#define ENTT_CONFIG_VERSION_H - -#include "macro.h" - -// NOLINTBEGIN(cppcoreguidelines-macro-*,modernize-macro-*) - -#define ENTT_VERSION_MAJOR 4 -#define ENTT_VERSION_MINOR 0 -#define ENTT_VERSION_PATCH 0 - -#define ENTT_VERSION \ - ENTT_XSTR(ENTT_VERSION_MAJOR) \ - "." ENTT_XSTR(ENTT_VERSION_MINOR) "." ENTT_XSTR(ENTT_VERSION_PATCH) - -// NOLINTEND(cppcoreguidelines-macro-*,modernize-macro-*) - -#endif diff --git a/include/entt/container/dense_map.hpp b/include/entt/container/dense_map.hpp deleted file mode 100644 index e4f5ee5..0000000 --- a/include/entt/container/dense_map.hpp +++ /dev/null @@ -1,1026 +0,0 @@ -#ifndef ENTT_CONTAINER_DENSE_MAP_HPP -#define ENTT_CONTAINER_DENSE_MAP_HPP - -#include -#include "../config/config.h" -#include "../core/bit.hpp" -#include "../core/compressed_pair.hpp" -#include "../core/iterator.hpp" -#include "../core/memory.hpp" -#include "../core/type_traits.hpp" -#include "../stl/bit.hpp" -#include "../stl/cmath.hpp" -#include "../stl/concepts.hpp" -#include "../stl/cstddef.hpp" -#include "../stl/functional.hpp" -#include "../stl/iterator.hpp" -#include "../stl/limits.hpp" -#include "../stl/memory.hpp" -#include "../stl/tuple.hpp" -#include "../stl/type_traits.hpp" -#include "../stl/utility.hpp" -#include "../stl/vector.hpp" -#include "fwd.hpp" - -namespace entt { - -/*! @cond ENTT_INTERNAL */ -namespace internal { - -static constexpr stl::size_t dense_map_placeholder_position = (stl::numeric_limits::max)(); - -template -struct dense_map_node final { - using value_type = stl::pair; - - template - dense_map_node(const stl::size_t pos, Args &&...args) - : next{pos}, - element{stl::forward(args)...} {} - - template - dense_map_node(stl::allocator_arg_t, const auto &allocator, const stl::size_t pos, Args &&...args) - : next{pos}, - element{entt::make_obj_using_allocator(allocator, stl::forward(args)...)} {} - - dense_map_node(stl::allocator_arg_t, const auto &allocator, const dense_map_node &other) - : next{other.next}, - element{entt::make_obj_using_allocator(allocator, other.element)} {} - - dense_map_node(stl::allocator_arg_t, const auto &allocator, dense_map_node &&other) - : next{other.next}, - element{entt::make_obj_using_allocator(allocator, stl::move(other.element))} {} - - stl::size_t next; - value_type element; -}; - -template -class dense_map_iterator final { - template - friend class dense_map_iterator; - - static_assert(stl::is_pointer_v, "Not a pointer type"); - using first_type = decltype(stl::as_const(stl::declval()->element.first)); - using second_type = decltype((stl::declval()->element.second)); - -public: - using value_type = stl::pair; - using pointer = input_iterator_pointer; - using reference = value_type; - using difference_type = stl::ptrdiff_t; - using iterator_category = stl::input_iterator_tag; - using iterator_concept = stl::random_access_iterator_tag; - - constexpr dense_map_iterator() noexcept - : it{} {} - - constexpr dense_map_iterator(const It iter) noexcept - : it{iter} {} - - template - requires (!stl::same_as && stl::constructible_from) - constexpr dense_map_iterator(const dense_map_iterator &other) noexcept - : it{other.it} {} - - constexpr dense_map_iterator &operator++() noexcept { - return ++it, *this; - } - - constexpr dense_map_iterator operator++(int) noexcept { - const dense_map_iterator orig = *this; - return ++(*this), orig; - } - - constexpr dense_map_iterator &operator--() noexcept { - return --it, *this; - } - - constexpr dense_map_iterator operator--(int) noexcept { - const dense_map_iterator orig = *this; - return operator--(), orig; - } - - constexpr dense_map_iterator &operator+=(const difference_type value) noexcept { - it += value; - return *this; - } - - constexpr dense_map_iterator operator+(const difference_type value) const noexcept { - dense_map_iterator copy = *this; - return (copy += value); - } - - constexpr dense_map_iterator &operator-=(const difference_type value) noexcept { - return (*this += -value); - } - - constexpr dense_map_iterator operator-(const difference_type value) const noexcept { - return (*this + -value); - } - - [[nodiscard]] constexpr reference operator[](const difference_type value) const noexcept { - return {it[value].element.first, it[value].element.second}; - } - - [[nodiscard]] constexpr pointer operator->() const noexcept { - return operator*(); - } - - [[nodiscard]] constexpr reference operator*() const noexcept { - return operator[](0); - } - - template - [[nodiscard]] constexpr stl::ptrdiff_t operator-(const dense_map_iterator &other) const noexcept { - return it - other.it; - } - - template - [[nodiscard]] constexpr bool operator==(const dense_map_iterator &other) const noexcept { - return it == other.it; - } - - template - [[nodiscard]] constexpr auto operator<=>(const dense_map_iterator &other) const noexcept { - return it <=> other.it; - } - -private: - It it; -}; - -template -class dense_map_local_iterator final { - template - friend class dense_map_local_iterator; - - static_assert(stl::is_pointer_v, "Not a pointer type"); - using first_type = decltype(stl::as_const(stl::declval()->element.first)); - using second_type = decltype((stl::declval()->element.second)); - -public: - using value_type = stl::pair; - using pointer = input_iterator_pointer; - using reference = value_type; - using difference_type = stl::ptrdiff_t; - using iterator_category = stl::input_iterator_tag; - using iterator_concept = stl::forward_iterator_tag; - - constexpr dense_map_local_iterator() noexcept = default; - - constexpr dense_map_local_iterator(It iter, const stl::size_t pos) noexcept - : it{iter}, - offset{pos} {} - - template - requires (!stl::same_as && stl::constructible_from) - constexpr dense_map_local_iterator(const dense_map_local_iterator &other) noexcept - : it{other.it}, - offset{other.offset} {} - - constexpr dense_map_local_iterator &operator++() noexcept { - return (offset = it[static_cast(offset)].next), *this; - } - - constexpr dense_map_local_iterator operator++(int) noexcept { - const dense_map_local_iterator orig = *this; - return ++(*this), orig; - } - - [[nodiscard]] constexpr pointer operator->() const noexcept { - return operator*(); - } - - [[nodiscard]] constexpr reference operator*() const noexcept { - const auto idx = static_cast(offset); - return {it[idx].element.first, it[idx].element.second}; - } - - template - [[nodiscard]] constexpr bool operator==(const dense_map_local_iterator &other) const noexcept { - return offset == other.offset; - } - - [[nodiscard]] constexpr stl::size_t index() const noexcept { - return offset; - } - -private: - It it{}; - stl::size_t offset{dense_map_placeholder_position}; -}; - -} // namespace internal -/*! @endcond */ - -/** - * @brief Associative container for key-value pairs with unique keys. - * - * Internally, elements are organized into buckets. Which bucket an element is - * placed into depends entirely on the hash of its key. Keys with the same hash - * code appear in the same bucket. - * - * @tparam Key Key type of the associative container. - * @tparam Type Mapped type of the associative container. - * @tparam Hash Type of function to use to hash the keys. - * @tparam KeyEqual Type of function to use to compare the keys for equality. - * @tparam Allocator Type of allocator used to manage memory and elements. - */ -template -class dense_map { - static constexpr float default_threshold = 0.875f; - static constexpr stl::size_t minimum_capacity = 8u; - static constexpr stl::size_t placeholder_position = internal::dense_map_placeholder_position; - - using node_type = internal::dense_map_node; - using alloc_traits = stl::allocator_traits; - static_assert(stl::is_same_v>, "Invalid value type"); - using sparse_container_type = stl::vector>; - using packed_container_type = stl::vector>; - - [[nodiscard]] stl::size_t key_to_bucket(const auto &key) const noexcept { - // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay) - return fast_mod(static_cast(sparse.second()(key)), bucket_count()); - } - - [[nodiscard]] auto constrained_find(const auto &key, const stl::size_t bucket) { - for(auto offset = sparse.first()[bucket]; offset != placeholder_position; offset = packed.first()[offset].next) { - if(packed.second()(packed.first()[offset].element.first, key)) { - return begin() + static_cast(offset); - } - } - - return end(); - } - - [[nodiscard]] auto constrained_find(const auto &key, const stl::size_t bucket) const { - for(auto offset = sparse.first()[bucket]; offset != placeholder_position; offset = packed.first()[offset].next) { - if(packed.second()(packed.first()[offset].element.first, key)) { - return cbegin() + static_cast(offset); - } - } - - return cend(); - } - - template - [[nodiscard]] auto insert_or_do_nothing(Other &&key, Args &&...args) { - const auto index = key_to_bucket(key); - - if(auto it = constrained_find(key, index); it != end()) { - return stl::make_pair(it, false); - } - - packed.first().emplace_back(sparse.first()[index], stl::piecewise_construct, stl::forward_as_tuple(stl::forward(key)), stl::forward_as_tuple(stl::forward(args)...)); - sparse.first()[index] = packed.first().size() - 1u; - rehash_if_required(); - - return stl::make_pair(--end(), true); - } - - template - [[nodiscard]] auto insert_or_overwrite(Other &&key, Arg &&value) { - const auto index = key_to_bucket(key); - - if(auto it = constrained_find(key, index); it != end()) { - it->second = stl::forward(value); - return stl::make_pair(it, false); - } - - packed.first().emplace_back(sparse.first()[index], stl::forward(key), stl::forward(value)); - sparse.first()[index] = packed.first().size() - 1u; - rehash_if_required(); - - return stl::make_pair(--end(), true); - } - - void move_and_pop(const stl::size_t pos) { - if(const auto last = size() - 1u; pos != last) { - size_type *curr = &sparse.first()[key_to_bucket(packed.first().back().element.first)]; - packed.first()[pos] = stl::move(packed.first().back()); - for(; *curr != last; curr = &packed.first()[*curr].next) {} - *curr = pos; - } - - packed.first().pop_back(); - } - - void rehash_if_required() { - if(const auto bc = bucket_count(); size() > static_cast(static_cast(bc) * max_load_factor())) { - rehash(bc * 2u); - } - } - -public: - /*! @brief Allocator type. */ - using allocator_type = Allocator; - /*! @brief Key type of the container. */ - using key_type = Key; - /*! @brief Mapped type of the container. */ - using mapped_type = Type; - /*! @brief Key-value type of the container. */ - using value_type = stl::pair; - /*! @brief Unsigned integer type. */ - using size_type = stl::size_t; - /*! @brief Signed integer type. */ - using difference_type = stl::ptrdiff_t; - /*! @brief Type of function to use to hash the keys. */ - using hasher = Hash; - /*! @brief Type of function to use to compare the keys for equality. */ - using key_equal = KeyEqual; - /*! @brief Input iterator type. */ - using iterator = internal::dense_map_iterator; - /*! @brief Constant input iterator type. */ - using const_iterator = internal::dense_map_iterator; - /*! @brief Input iterator type. */ - using local_iterator = internal::dense_map_local_iterator; - /*! @brief Constant input iterator type. */ - using const_local_iterator = internal::dense_map_local_iterator; - - /*! @brief Default constructor. */ - dense_map() - : dense_map{minimum_capacity} {} - - /** - * @brief Constructs an empty container with a given allocator. - * @param allocator The allocator to use. - */ - explicit dense_map(const allocator_type &allocator) - : dense_map{minimum_capacity, hasher{}, key_equal{}, allocator} {} - - /** - * @brief Constructs an empty container with a given allocator and user - * supplied minimal number of buckets. - * @param cnt Minimal number of buckets. - * @param allocator The allocator to use. - */ - dense_map(const size_type cnt, const allocator_type &allocator) - : dense_map{cnt, hasher{}, key_equal{}, allocator} {} - - /** - * @brief Constructs an empty container with a given allocator, hash - * function and user supplied minimal number of buckets. - * @param cnt Minimal number of buckets. - * @param hash Hash function to use. - * @param allocator The allocator to use. - */ - dense_map(const size_type cnt, const hasher &hash, const allocator_type &allocator) - : dense_map{cnt, hash, key_equal{}, allocator} {} - - /** - * @brief Constructs an empty container with a given allocator, hash - * function, compare function and user supplied minimal number of buckets. - * @param cnt Minimal number of buckets. - * @param hash Hash function to use. - * @param equal Compare function to use. - * @param allocator The allocator to use. - */ - explicit dense_map(const size_type cnt, const hasher &hash = hasher{}, const key_equal &equal = key_equal{}, const allocator_type &allocator = allocator_type{}) - : sparse{allocator, hash}, - packed{allocator, equal} { - rehash(cnt); - } - - /*! @brief Default copy constructor. */ - dense_map(const dense_map &) = default; - - /** - * @brief Allocator-extended copy constructor. - * @param other The instance to copy from. - * @param allocator The allocator to use. - */ - dense_map(const dense_map &other, const allocator_type &allocator) - : sparse{stl::piecewise_construct, stl::forward_as_tuple(other.sparse.first(), allocator), stl::forward_as_tuple(other.sparse.second())}, - packed{stl::piecewise_construct, stl::forward_as_tuple(other.packed.first(), allocator), stl::forward_as_tuple(other.packed.second())}, - threshold{other.threshold} {} - - /*! @brief Default move constructor. */ - dense_map(dense_map &&) noexcept = default; - - /** - * @brief Allocator-extended move constructor. - * @param other The instance to move from. - * @param allocator The allocator to use. - */ - dense_map(dense_map &&other, const allocator_type &allocator) - : sparse{stl::piecewise_construct, stl::forward_as_tuple(stl::move(other.sparse.first()), allocator), stl::forward_as_tuple(stl::move(other.sparse.second()))}, - packed{stl::piecewise_construct, stl::forward_as_tuple(stl::move(other.packed.first()), allocator), stl::forward_as_tuple(stl::move(other.packed.second()))}, - threshold{other.threshold} {} - - /*! @brief Default destructor. */ - ~dense_map() = default; - - /** - * @brief Default copy assignment operator. - * @return This container. - */ - dense_map &operator=(const dense_map &) = default; - - /** - * @brief Default move assignment operator. - * @return This container. - */ - dense_map &operator=(dense_map &&) noexcept = default; - - /** - * @brief Exchanges the contents with those of a given container. - * @param other Container to exchange the content with. - */ - void swap(dense_map &other) noexcept { - using stl::swap; - swap(sparse, other.sparse); - swap(packed, other.packed); - swap(threshold, other.threshold); - } - - /** - * @brief Returns the associated allocator. - * @return The associated allocator. - */ - [[nodiscard]] constexpr allocator_type get_allocator() const noexcept { - return sparse.first().get_allocator(); - } - - /** - * @brief Returns an iterator to the beginning. - * - * If the array is empty, the returned iterator will be equal to `end()`. - * - * @return An iterator to the first instance of the internal array. - */ - [[nodiscard]] const_iterator cbegin() const noexcept { - return packed.first().data(); - } - - /*! @copydoc cbegin */ - [[nodiscard]] const_iterator begin() const noexcept { - return cbegin(); - } - - /*! @copydoc begin */ - [[nodiscard]] iterator begin() noexcept { - return packed.first().data(); - } - - /** - * @brief Returns an iterator to the end. - * @return An iterator to the element following the last instance of the - * internal array. - */ - [[nodiscard]] const_iterator cend() const noexcept { - return packed.first().data() + packed.first().size(); - } - - /*! @copydoc cend */ - [[nodiscard]] const_iterator end() const noexcept { - return cend(); - } - - /*! @copydoc end */ - [[nodiscard]] iterator end() noexcept { - return packed.first().data() + packed.first().size(); - } - - /** - * @brief Checks whether a container is empty. - * @return True if the container is empty, false otherwise. - */ - [[nodiscard]] bool empty() const noexcept { - return packed.first().empty(); - } - - /** - * @brief Returns the number of elements in a container. - * @return Number of elements in a container. - */ - [[nodiscard]] size_type size() const noexcept { - return packed.first().size(); - } - - /** - * @brief Returns the maximum possible number of elements. - * @return Maximum possible number of elements. - */ - [[nodiscard]] size_type max_size() const noexcept { - return packed.first().max_size(); - } - - /*! @brief Clears the container. */ - void clear() noexcept { - sparse.first().clear(); - packed.first().clear(); - rehash(0u); - } - - /** - * @brief Inserts an element into the container, if the key does not exist. - * @param value A key-value pair eventually convertible to the value type. - * @return A pair consisting of an iterator to the inserted element (or to - * the element that prevented the insertion) and a bool denoting whether the - * insertion took place. - */ - stl::pair insert(const value_type &value) { - return insert_or_do_nothing(value.first, value.second); - } - - /*! @copydoc insert */ - stl::pair insert(value_type &&value) { - return insert_or_do_nothing(stl::move(value.first), stl::move(value.second)); - } - - /** - * @copydoc insert - * @tparam Arg Type of the key-value pair to insert into the container. - */ - template - requires stl::constructible_from - stl::pair insert(Arg &&value) { - return insert_or_do_nothing(stl::forward(value).first, stl::forward(value).second); - } - - /** - * @brief Inserts elements into the container, if their keys do not exist. - * @param first An iterator to the first element of the range of elements. - * @param last An iterator past the last element of the range of elements. - */ - void insert(stl::input_iterator auto first, stl::input_iterator auto last) { - for(; first != last; ++first) { - insert(*first); - } - } - - /** - * @brief Inserts an element into the container or assigns to the current - * element if the key already exists. - * @tparam Arg Type of the value to insert or assign. - * @param key A key used both to look up and to insert if not found. - * @param value A value to insert or assign. - * @return A pair consisting of an iterator to the element and a bool - * denoting whether the insertion took place. - */ - template - stl::pair insert_or_assign(const key_type &key, Arg &&value) { - return insert_or_overwrite(key, stl::forward(value)); - } - - /*! @copydoc insert_or_assign */ - template - stl::pair insert_or_assign(key_type &&key, Arg &&value) { - return insert_or_overwrite(stl::move(key), stl::forward(value)); - } - - /** - * @brief Constructs an element in-place, if the key does not exist. - * - * The element is also constructed when the container already has the key, - * in which case the newly constructed object is destroyed immediately. - * - * @tparam Args Types of arguments to forward to the constructor of the - * element. - * @param args Arguments to forward to the constructor of the element. - * @return A pair consisting of an iterator to the inserted element (or to - * the element that prevented the insertion) and a bool denoting whether the - * insertion took place. - */ - template - stl::pair emplace([[maybe_unused]] Args &&...args) { - if constexpr(sizeof...(Args) == 0u) { - return insert_or_do_nothing(key_type{}); - } else if constexpr(sizeof...(Args) == 1u) { - return insert_or_do_nothing(stl::forward(args).first..., stl::forward(args).second...); - } else if constexpr(sizeof...(Args) == 2u) { - return insert_or_do_nothing(stl::forward(args)...); - } else { - auto &node = packed.first().emplace_back(packed.first().size(), stl::forward(args)...); - const auto index = key_to_bucket(node.element.first); - - if(auto it = constrained_find(node.element.first, index); it != end()) { - packed.first().pop_back(); - return stl::make_pair(it, false); - } - - stl::swap(node.next, sparse.first()[index]); - rehash_if_required(); - - return stl::make_pair(--end(), true); - } - } - - /** - * @brief Inserts in-place if the key does not exist, does nothing if the - * key exists. - * @tparam Args Types of arguments to forward to the constructor of the - * element. - * @param key A key used both to look up and to insert if not found. - * @param args Arguments to forward to the constructor of the element. - * @return A pair consisting of an iterator to the inserted element (or to - * the element that prevented the insertion) and a bool denoting whether the - * insertion took place. - */ - template - stl::pair try_emplace(const key_type &key, Args &&...args) { - return insert_or_do_nothing(key, stl::forward(args)...); - } - - /*! @copydoc try_emplace */ - template - stl::pair try_emplace(key_type &&key, Args &&...args) { - return insert_or_do_nothing(stl::move(key), stl::forward(args)...); - } - - /** - * @brief Removes an element from a given position. - * @param pos An iterator to the element to remove. - * @return An iterator following the removed element. - */ - iterator erase(const_iterator pos) { - const auto diff = pos - cbegin(); - erase(pos->first); - return begin() + diff; - } - - /** - * @brief Removes the given elements from a container. - * @param first An iterator to the first element of the range of elements. - * @param last An iterator past the last element of the range of elements. - * @return An iterator following the last removed element. - */ - iterator erase(const_iterator first, const_iterator last) { - const auto dist = first - cbegin(); - - for(auto from = last - cbegin(); from != dist; --from) { - erase(packed.first()[static_cast(from) - 1u].element.first); - } - - return (begin() + dist); - } - - /** - * @brief Removes the element associated with a given key. - * @param key A key value of an element to remove. - * @return Number of elements removed (either 0 or 1). - */ - size_type erase(const key_type &key) { - for(size_type *curr = &sparse.first()[key_to_bucket(key)]; *curr != placeholder_position; curr = &packed.first()[*curr].next) { - if(packed.second()(packed.first()[*curr].element.first, key)) { - const auto index = *curr; - *curr = packed.first()[*curr].next; - move_and_pop(index); - return 1u; - } - } - - return 0u; - } - - /** - * @brief Accesses a given element with bounds checking. - * @param key A key of an element to find. - * @return A reference to the mapped value of the requested element. - */ - [[nodiscard]] mapped_type &at(const key_type &key) { - auto it = find(key); - ENTT_ASSERT(it != end(), "Invalid key"); - return it->second; - } - - /*! @copydoc at */ - [[nodiscard]] const mapped_type &at(const key_type &key) const { - auto it = find(key); - ENTT_ASSERT(it != cend(), "Invalid key"); - return it->second; - } - - /** - * @brief Accesses a given element with bounds checking. - * @param key A key of an element to find. - * @return A reference to the mapped value of the requested element. - */ - [[nodiscard]] mapped_type const &at(const auto &key) const - requires is_transparent_v && is_transparent_v { - auto it = find(key); - ENTT_ASSERT(it != cend(), "Invalid key"); - return it->second; - } - - /*! @copydoc at */ - [[nodiscard]] mapped_type &at(const auto &key) - requires is_transparent_v && is_transparent_v { - auto it = find(key); - ENTT_ASSERT(it != end(), "Invalid key"); - return it->second; - } - - /** - * @brief Accesses or inserts a given element. - * @param key A key of an element to find or insert. - * @return A reference to the mapped value of the requested element. - */ - [[nodiscard]] mapped_type &operator[](const key_type &key) { - return insert_or_do_nothing(key).first->second; - } - - /** - * @brief Accesses or inserts a given element. - * @param key A key of an element to find or insert. - * @return A reference to the mapped value of the requested element. - */ - [[nodiscard]] mapped_type &operator[](key_type &&key) { - return insert_or_do_nothing(stl::move(key)).first->second; - } - - /** - * @brief Returns the number of elements matching a key (either 1 or 0). - * @param key Key value of an element to search for. - * @return Number of elements matching the key (either 1 or 0). - */ - [[nodiscard]] size_type count(const key_type &key) const { - return find(key) != end(); - } - - /** - * @brief Returns the number of elements matching a key (either 1 or 0). - * @param key Key value of an element to search for. - * @return Number of elements matching the key (either 1 or 0). - */ - [[nodiscard]] size_type count(const auto &key) const - requires is_transparent_v && is_transparent_v { - return find(key) != end(); - } - - /** - * @brief Finds an element with a given key. - * @param key Key value of an element to search for. - * @return An iterator to an element with the given key. If no such element - * is found, a past-the-end iterator is returned. - */ - [[nodiscard]] iterator find(const key_type &key) { - return constrained_find(key, key_to_bucket(key)); - } - - /*! @copydoc find */ - [[nodiscard]] const_iterator find(const key_type &key) const { - return constrained_find(key, key_to_bucket(key)); - } - - /** - * @brief Finds an element with a key that compares _equivalent_ to a given - * key. - * @param key Key value of an element to search for. - * @return An iterator to an element with the given key. If no such element - * is found, a past-the-end iterator is returned. - */ - [[nodiscard]] iterator find(const auto &key) - requires is_transparent_v && is_transparent_v { - return constrained_find(key, key_to_bucket(key)); - } - - /*! @copydoc find */ - [[nodiscard]] const_iterator find(const auto &key) const - requires is_transparent_v && is_transparent_v { - return constrained_find(key, key_to_bucket(key)); - } - - /** - * @brief Returns a range containing all elements with a given key. - * @param key Key value of an element to search for. - * @return A pair of iterators pointing to the first element and past the - * last element of the range. - */ - [[nodiscard]] stl::pair equal_range(const key_type &key) { - const auto it = find(key); - return {it, it + !(it == end())}; - } - - /*! @copydoc equal_range */ - [[nodiscard]] stl::pair equal_range(const key_type &key) const { - const auto it = find(key); - return {it, it + !(it == cend())}; - } - - /** - * @brief Returns a range containing all elements that compare _equivalent_ - * to a given key. - * @param key Key value of an element to search for. - * @return A pair of iterators pointing to the first element and past the - * last element of the range. - */ - [[nodiscard]] stl::pair equal_range(const auto &key) - requires is_transparent_v && is_transparent_v { - const auto it = find(key); - return {it, it + !(it == end())}; - } - - /*! @copydoc equal_range */ - [[nodiscard]] stl::pair equal_range(const auto &key) const - requires is_transparent_v && is_transparent_v { - const auto it = find(key); - return {it, it + !(it == cend())}; - } - - /** - * @brief Checks if the container contains an element with a given key. - * @param key Key value of an element to search for. - * @return True if there is such an element, false otherwise. - */ - [[nodiscard]] bool contains(const key_type &key) const { - return (find(key) != cend()); - } - - /** - * @brief Checks if the container contains an element with a key that - * compares _equivalent_ to a given value. - * @param key Key value of an element to search for. - * @return True if there is such an element, false otherwise. - */ - [[nodiscard]] bool contains(const auto &key) const - requires is_transparent_v && is_transparent_v { - return (find(key) != cend()); - } - - /** - * @brief Returns an iterator to the beginning of a given bucket. - * @param index An index of a bucket to access. - * @return An iterator to the beginning of the given bucket. - */ - [[nodiscard]] const_local_iterator cbegin(const size_type index) const { - return {packed.first().data(), sparse.first()[index]}; - } - - /** - * @brief Returns an iterator to the beginning of a given bucket. - * @param index An index of a bucket to access. - * @return An iterator to the beginning of the given bucket. - */ - [[nodiscard]] const_local_iterator begin(const size_type index) const { - return cbegin(index); - } - - /** - * @brief Returns an iterator to the beginning of a given bucket. - * @param index An index of a bucket to access. - * @return An iterator to the beginning of the given bucket. - */ - [[nodiscard]] local_iterator begin(const size_type index) { - return {packed.first().data(), sparse.first()[index]}; - } - - /** - * @brief Returns an iterator to the end of a given bucket. - * @param index An index of a bucket to access. - * @return An iterator to the end of the given bucket. - */ - [[nodiscard]] const_local_iterator cend([[maybe_unused]] const size_type index) const { - return {}; - } - - /** - * @brief Returns an iterator to the end of a given bucket. - * @param index An index of a bucket to access. - * @return An iterator to the end of the given bucket. - */ - [[nodiscard]] const_local_iterator end(const size_type index) const { - return cend(index); - } - - /** - * @brief Returns an iterator to the end of a given bucket. - * @param index An index of a bucket to access. - * @return An iterator to the end of the given bucket. - */ - [[nodiscard]] local_iterator end([[maybe_unused]] const size_type index) { - return {}; - } - - /** - * @brief Returns the number of buckets. - * @return The number of buckets. - */ - [[nodiscard]] size_type bucket_count() const { - return sparse.first().size(); - } - - /** - * @brief Returns the maximum number of buckets. - * @return The maximum number of buckets. - */ - [[nodiscard]] size_type max_bucket_count() const { - return sparse.first().max_size(); - } - - /** - * @brief Returns the number of elements in a given bucket. - * @param index The index of the bucket to examine. - * @return The number of elements in the given bucket. - */ - [[nodiscard]] size_type bucket_size(const size_type index) const { - return static_cast(stl::distance(begin(index), end(index))); - } - - /** - * @brief Returns the bucket for a given key. - * @param key The value of the key to examine. - * @return The bucket for the given key. - */ - [[nodiscard]] size_type bucket(const key_type &key) const { - return key_to_bucket(key); - } - - /** - * @brief Returns the average number of elements per bucket. - * @return The average number of elements per bucket. - */ - [[nodiscard]] float load_factor() const { - return static_cast(size()) / static_cast(bucket_count()); - } - - /** - * @brief Returns the maximum average number of elements per bucket. - * @return The maximum average number of elements per bucket. - */ - [[nodiscard]] float max_load_factor() const { - return threshold; - } - - /** - * @brief Sets the desired maximum average number of elements per bucket. - * @param value A desired maximum average number of elements per bucket. - */ - void max_load_factor(const float value) { - ENTT_ASSERT(value > 0.f, "Invalid load factor"); - threshold = value; - rehash(0u); - } - - /** - * @brief Reserves at least the specified number of buckets and regenerates - * the hash table. - * @param cnt New number of buckets. - */ - void rehash(const size_type cnt) { - auto value = cnt > minimum_capacity ? cnt : minimum_capacity; - const auto cap = static_cast(static_cast(size()) / max_load_factor()); - value = value > cap ? value : cap; - - if(const auto sz = stl::bit_ceil(value); sz != bucket_count()) { - sparse.first().resize(sz); - - for(auto &&elem: sparse.first()) { - elem = placeholder_position; - } - - for(size_type pos{}, last = size(); pos < last; ++pos) { - const auto index = key_to_bucket(packed.first()[pos].element.first); - packed.first()[pos].next = stl::exchange(sparse.first()[index], pos); - } - } - } - - /** - * @brief Reserves space for at least the specified number of elements and - * regenerates the hash table. - * @param cnt New number of elements. - */ - void reserve(const size_type cnt) { - packed.first().reserve(cnt); - rehash(static_cast(stl::ceil(static_cast(cnt) / max_load_factor()))); - } - - /** - * @brief Returns the function used to hash the keys. - * @return The function used to hash the keys. - */ - [[nodiscard]] hasher hash_function() const { - return sparse.second(); - } - - /** - * @brief Returns the function used to compare keys for equality. - * @return The function used to compare keys for equality. - */ - [[nodiscard]] key_equal key_eq() const { - return packed.second(); - } - -private: - compressed_pair sparse; - compressed_pair packed; - float threshold{default_threshold}; -}; - -} // namespace entt - -/*! @cond ENTT_INTERNAL */ -#include - -namespace std { - -template -struct uses_allocator, Allocator> - : entt::stl::true_type {}; - -} // namespace std -/*! @endcond */ - -#endif diff --git a/include/entt/container/dense_set.hpp b/include/entt/container/dense_set.hpp deleted file mode 100644 index df71b72..0000000 --- a/include/entt/container/dense_set.hpp +++ /dev/null @@ -1,890 +0,0 @@ -#ifndef ENTT_CONTAINER_DENSE_SET_HPP -#define ENTT_CONTAINER_DENSE_SET_HPP - -#include -#include "../config/config.h" -#include "../core/bit.hpp" -#include "../core/compressed_pair.hpp" -#include "../core/type_traits.hpp" -#include "../stl/bit.hpp" -#include "../stl/cmath.hpp" -#include "../stl/concepts.hpp" -#include "../stl/cstddef.hpp" -#include "../stl/functional.hpp" -#include "../stl/iterator.hpp" -#include "../stl/limits.hpp" -#include "../stl/memory.hpp" -#include "../stl/tuple.hpp" -#include "../stl/type_traits.hpp" -#include "../stl/utility.hpp" -#include "../stl/vector.hpp" -#include "fwd.hpp" - -namespace entt { - -/*! @cond ENTT_INTERNAL */ -namespace internal { - -static constexpr stl::size_t dense_set_placeholder_position = (stl::numeric_limits::max)(); - -template -class dense_set_iterator final { - template - friend class dense_set_iterator; - - static_assert(stl::is_pointer_v, "Not a pointer type"); - -public: - using value_type = stl::remove_const_t>::second_type; - using pointer = const value_type *; - using reference = const value_type &; - using difference_type = stl::ptrdiff_t; - using iterator_category = stl::random_access_iterator_tag; - - constexpr dense_set_iterator() noexcept - : it{} {} - - constexpr dense_set_iterator(const It iter) noexcept - : it{iter} {} - - template - requires (!stl::same_as && stl::constructible_from) - constexpr dense_set_iterator(const dense_set_iterator &other) noexcept - : it{other.it} {} - - constexpr dense_set_iterator &operator++() noexcept { - return ++it, *this; - } - - constexpr dense_set_iterator operator++(int) noexcept { - const dense_set_iterator orig = *this; - return ++(*this), orig; - } - - constexpr dense_set_iterator &operator--() noexcept { - return --it, *this; - } - - constexpr dense_set_iterator operator--(int) noexcept { - const dense_set_iterator orig = *this; - return operator--(), orig; - } - - constexpr dense_set_iterator &operator+=(const difference_type value) noexcept { - it += value; - return *this; - } - - constexpr dense_set_iterator operator+(const difference_type value) const noexcept { - dense_set_iterator copy = *this; - return (copy += value); - } - - constexpr dense_set_iterator &operator-=(const difference_type value) noexcept { - return (*this += -value); - } - - constexpr dense_set_iterator operator-(const difference_type value) const noexcept { - return (*this + -value); - } - - [[nodiscard]] constexpr reference operator[](const difference_type value) const noexcept { - return it[value].second; - } - - [[nodiscard]] constexpr pointer operator->() const noexcept { - return stl::addressof(operator[](0)); - } - - [[nodiscard]] constexpr reference operator*() const noexcept { - return operator[](0); - } - - template - [[nodiscard]] constexpr stl::ptrdiff_t operator-(const dense_set_iterator &other) const noexcept { - return it - other.it; - } - - template - [[nodiscard]] constexpr bool operator==(const dense_set_iterator &other) const noexcept { - return it == other.it; - } - - template - [[nodiscard]] constexpr auto operator<=>(const dense_set_iterator &other) const noexcept { - return it <=> other.it; - } - -private: - It it; -}; - -template -class dense_set_local_iterator final { - template - friend class dense_set_local_iterator; - - static_assert(stl::is_pointer_v, "Not a pointer type"); - -public: - using value_type = stl::remove_const_t>::second_type; - using pointer = const value_type *; - using reference = const value_type &; - using difference_type = stl::ptrdiff_t; - using iterator_category = stl::forward_iterator_tag; - - constexpr dense_set_local_iterator() noexcept = default; - - constexpr dense_set_local_iterator(It iter, const stl::size_t pos) noexcept - : it{iter}, - offset{pos} {} - - template - requires (!stl::same_as && stl::constructible_from) - constexpr dense_set_local_iterator(const dense_set_local_iterator &other) noexcept - : it{other.it}, - offset{other.offset} {} - - constexpr dense_set_local_iterator &operator++() noexcept { - return offset = it[static_cast(offset)].first, *this; - } - - constexpr dense_set_local_iterator operator++(int) noexcept { - const dense_set_local_iterator orig = *this; - return ++(*this), orig; - } - - [[nodiscard]] constexpr pointer operator->() const noexcept { - return stl::addressof(it[static_cast(offset)].second); - } - - [[nodiscard]] constexpr reference operator*() const noexcept { - return *operator->(); - } - - template - [[nodiscard]] constexpr bool operator==(const dense_set_local_iterator &other) const noexcept { - return offset == other.offset; - } - - [[nodiscard]] constexpr stl::size_t index() const noexcept { - return offset; - } - -private: - It it{}; - stl::size_t offset{dense_set_placeholder_position}; -}; - -} // namespace internal -/*! @endcond */ - -/** - * @brief Associative container for unique objects of a given type. - * - * Internally, elements are organized into buckets. Which bucket an element is - * placed into depends entirely on its hash. Elements with the same hash code - * appear in the same bucket. - * - * @tparam Type Value type of the associative container. - * @tparam Hash Type of function to use to hash the values. - * @tparam KeyEqual Type of function to use to compare the values for equality. - * @tparam Allocator Type of allocator used to manage memory and elements. - */ -template -class dense_set { - static constexpr float default_threshold = 0.875f; - static constexpr stl::size_t minimum_capacity = 8u; - static constexpr stl::size_t placeholder_position = internal::dense_set_placeholder_position; - - using node_type = stl::pair; - using alloc_traits = stl::allocator_traits; - static_assert(stl::is_same_v, "Invalid value type"); - using sparse_container_type = stl::vector>; - using packed_container_type = stl::vector>; - - [[nodiscard]] stl::size_t value_to_bucket(const auto &value) const noexcept { - return fast_mod(static_cast(sparse.second()(value)), bucket_count()); - } - - [[nodiscard]] auto constrained_find(const auto &value, const stl::size_t bucket) { - for(auto offset = sparse.first()[bucket]; offset != placeholder_position; offset = packed.first()[offset].first) { - if(packed.second()(packed.first()[offset].second, value)) { - return begin() + static_cast(offset); - } - } - - return end(); - } - - [[nodiscard]] auto constrained_find(const auto &value, const stl::size_t bucket) const { - for(auto offset = sparse.first()[bucket]; offset != placeholder_position; offset = packed.first()[offset].first) { - if(packed.second()(packed.first()[offset].second, value)) { - return cbegin() + static_cast(offset); - } - } - - return cend(); - } - - template - [[nodiscard]] auto insert_or_do_nothing(Other &&value) { - const auto index = value_to_bucket(value); - - if(auto it = constrained_find(value, index); it != end()) { - return stl::make_pair(it, false); - } - - packed.first().emplace_back(sparse.first()[index], stl::forward(value)); - sparse.first()[index] = packed.first().size() - 1u; - rehash_if_required(); - - return stl::make_pair(--end(), true); - } - - void move_and_pop(const stl::size_t pos) { - if(const auto last = size() - 1u; pos != last) { - size_type *curr = &sparse.first()[value_to_bucket(packed.first().back().second)]; - packed.first()[pos] = stl::move(packed.first().back()); - for(; *curr != last; curr = &packed.first()[*curr].first) {} - *curr = pos; - } - - packed.first().pop_back(); - } - - void rehash_if_required() { - if(const auto bc = bucket_count(); size() > static_cast(static_cast(bc) * max_load_factor())) { - rehash(bc * 2u); - } - } - -public: - /*! @brief Allocator type. */ - using allocator_type = Allocator; - /*! @brief Key type of the container. */ - using key_type = Type; - /*! @brief Value type of the container. */ - using value_type = Type; - /*! @brief Unsigned integer type. */ - using size_type = stl::size_t; - /*! @brief Signed integer type. */ - using difference_type = stl::ptrdiff_t; - /*! @brief Type of function to use to hash the elements. */ - using hasher = Hash; - /*! @brief Type of function to use to compare the elements for equality. */ - using key_equal = KeyEqual; - /*! @brief Random access iterator type. */ - using iterator = internal::dense_set_iterator; - /*! @brief Constant random access iterator type. */ - using const_iterator = internal::dense_set_iterator; - /*! @brief Reverse iterator type. */ - using reverse_iterator = stl::reverse_iterator; - /*! @brief Constant reverse iterator type. */ - using const_reverse_iterator = stl::reverse_iterator; - /*! @brief Forward iterator type. */ - using local_iterator = internal::dense_set_local_iterator; - /*! @brief Constant forward iterator type. */ - using const_local_iterator = internal::dense_set_local_iterator; - - /*! @brief Default constructor. */ - dense_set() - : dense_set{minimum_capacity} {} - - /** - * @brief Constructs an empty container with a given allocator. - * @param allocator The allocator to use. - */ - explicit dense_set(const allocator_type &allocator) - : dense_set{minimum_capacity, hasher{}, key_equal{}, allocator} {} - - /** - * @brief Constructs an empty container with a given allocator and user - * supplied minimal number of buckets. - * @param cnt Minimal number of buckets. - * @param allocator The allocator to use. - */ - dense_set(const size_type cnt, const allocator_type &allocator) - : dense_set{cnt, hasher{}, key_equal{}, allocator} {} - - /** - * @brief Constructs an empty container with a given allocator, hash - * function and user supplied minimal number of buckets. - * @param cnt Minimal number of buckets. - * @param hash Hash function to use. - * @param allocator The allocator to use. - */ - dense_set(const size_type cnt, const hasher &hash, const allocator_type &allocator) - : dense_set{cnt, hash, key_equal{}, allocator} {} - - /** - * @brief Constructs an empty container with a given allocator, hash - * function, compare function and user supplied minimal number of buckets. - * @param cnt Minimal number of buckets. - * @param hash Hash function to use. - * @param equal Compare function to use. - * @param allocator The allocator to use. - */ - explicit dense_set(const size_type cnt, const hasher &hash = hasher{}, const key_equal &equal = key_equal{}, const allocator_type &allocator = allocator_type{}) - : sparse{allocator, hash}, - packed{allocator, equal} { - rehash(cnt); - } - - /*! @brief Default copy constructor. */ - dense_set(const dense_set &) = default; - - /** - * @brief Allocator-extended copy constructor. - * @param other The instance to copy from. - * @param allocator The allocator to use. - */ - dense_set(const dense_set &other, const allocator_type &allocator) - : sparse{stl::piecewise_construct, stl::forward_as_tuple(other.sparse.first(), allocator), stl::forward_as_tuple(other.sparse.second())}, - packed{stl::piecewise_construct, stl::forward_as_tuple(other.packed.first(), allocator), stl::forward_as_tuple(other.packed.second())}, - threshold{other.threshold} {} - - /*! @brief Default move constructor. */ - dense_set(dense_set &&) noexcept = default; - - /** - * @brief Allocator-extended move constructor. - * @param other The instance to move from. - * @param allocator The allocator to use. - */ - dense_set(dense_set &&other, const allocator_type &allocator) - : sparse{stl::piecewise_construct, stl::forward_as_tuple(stl::move(other.sparse.first()), allocator), stl::forward_as_tuple(stl::move(other.sparse.second()))}, - packed{stl::piecewise_construct, stl::forward_as_tuple(stl::move(other.packed.first()), allocator), stl::forward_as_tuple(stl::move(other.packed.second()))}, - threshold{other.threshold} {} - - /*! @brief Default destructor. */ - ~dense_set() = default; - - /** - * @brief Default copy assignment operator. - * @return This container. - */ - dense_set &operator=(const dense_set &) = default; - - /** - * @brief Default move assignment operator. - * @return This container. - */ - dense_set &operator=(dense_set &&) noexcept = default; - - /** - * @brief Exchanges the contents with those of a given container. - * @param other Container to exchange the content with. - */ - void swap(dense_set &other) noexcept { - using stl::swap; - swap(sparse, other.sparse); - swap(packed, other.packed); - swap(threshold, other.threshold); - } - - /** - * @brief Returns the associated allocator. - * @return The associated allocator. - */ - [[nodiscard]] constexpr allocator_type get_allocator() const noexcept { - return sparse.first().get_allocator(); - } - - /** - * @brief Returns an iterator to the beginning. - * - * If the array is empty, the returned iterator will be equal to `end()`. - * - * @return An iterator to the first instance of the internal array. - */ - [[nodiscard]] const_iterator cbegin() const noexcept { - return packed.first().data(); - } - - /*! @copydoc cbegin */ - [[nodiscard]] const_iterator begin() const noexcept { - return cbegin(); - } - - /*! @copydoc begin */ - [[nodiscard]] iterator begin() noexcept { - return packed.first().data(); - } - - /** - * @brief Returns an iterator to the end. - * @return An iterator to the element following the last instance of the - * internal array. - */ - [[nodiscard]] const_iterator cend() const noexcept { - return packed.first().data() + packed.first().size(); - } - - /*! @copydoc cend */ - [[nodiscard]] const_iterator end() const noexcept { - return cend(); - } - - /*! @copydoc end */ - [[nodiscard]] iterator end() noexcept { - return packed.first().data() + packed.first().size(); - } - - /** - * @brief Returns a reverse iterator to the beginning. - * - * If the array is empty, the returned iterator will be equal to `rend()`. - * - * @return An iterator to the first instance of the reversed internal array. - */ - [[nodiscard]] const_reverse_iterator crbegin() const noexcept { - return stl::make_reverse_iterator(cend()); - } - - /*! @copydoc crbegin */ - [[nodiscard]] const_reverse_iterator rbegin() const noexcept { - return crbegin(); - } - - /*! @copydoc rbegin */ - [[nodiscard]] reverse_iterator rbegin() noexcept { - return stl::make_reverse_iterator(end()); - } - - /** - * @brief Returns a reverse iterator to the end. - * @return An iterator to the element following the last instance of the - * reversed internal array. - */ - [[nodiscard]] const_reverse_iterator crend() const noexcept { - return stl::make_reverse_iterator(cbegin()); - } - - /*! @copydoc crend */ - [[nodiscard]] const_reverse_iterator rend() const noexcept { - return crend(); - } - - /*! @copydoc rend */ - [[nodiscard]] reverse_iterator rend() noexcept { - return stl::make_reverse_iterator(begin()); - } - - /** - * @brief Checks whether a container is empty. - * @return True if the container is empty, false otherwise. - */ - [[nodiscard]] bool empty() const noexcept { - return packed.first().empty(); - } - - /** - * @brief Returns the number of elements in a container. - * @return Number of elements in a container. - */ - [[nodiscard]] size_type size() const noexcept { - return packed.first().size(); - } - - /** - * @brief Returns the maximum possible number of elements. - * @return Maximum possible number of elements. - */ - [[nodiscard]] size_type max_size() const noexcept { - return packed.first().max_size(); - } - - /*! @brief Clears the container. */ - void clear() noexcept { - sparse.first().clear(); - packed.first().clear(); - rehash(0u); - } - - /** - * @brief Inserts an element into the container, if it does not exist. - * @param value An element to insert into the container. - * @return A pair consisting of an iterator to the inserted element (or to - * the element that prevented the insertion) and a bool denoting whether the - * insertion took place. - */ - stl::pair insert(const value_type &value) { - return insert_or_do_nothing(value); - } - - /*! @copydoc insert */ - stl::pair insert(value_type &&value) { - return insert_or_do_nothing(stl::move(value)); - } - - /** - * @brief Inserts elements into the container, if they do not exist. - * @param first An iterator to the first element of the range of elements. - * @param last An iterator past the last element of the range of elements. - */ - void insert(stl::input_iterator auto first, stl::input_iterator auto last) { - for(; first != last; ++first) { - insert(*first); - } - } - - /** - * @brief Constructs an element in-place, if it does not exist. - * - * The element is also constructed when the container already has the key, - * in which case the newly constructed object is destroyed immediately. - * - * @tparam Args Types of arguments to forward to the constructor of the - * element. - * @param args Arguments to forward to the constructor of the element. - * @return A pair consisting of an iterator to the inserted element (or to - * the element that prevented the insertion) and a bool denoting whether the - * insertion took place. - */ - template - stl::pair emplace(Args &&...args) { - if constexpr(((sizeof...(Args) == 1u) && ... && stl::is_same_v, value_type>)) { - return insert_or_do_nothing(stl::forward(args)...); - } else { - auto &node = packed.first().emplace_back(stl::piecewise_construct, stl::make_tuple(packed.first().size()), stl::forward_as_tuple(stl::forward(args)...)); - const auto index = value_to_bucket(node.second); - - if(auto it = constrained_find(node.second, index); it != end()) { - packed.first().pop_back(); - return stl::make_pair(it, false); - } - - stl::swap(node.first, sparse.first()[index]); - rehash_if_required(); - - return stl::make_pair(--end(), true); - } - } - - /** - * @brief Removes an element from a given position. - * @param pos An iterator to the element to remove. - * @return An iterator following the removed element. - */ - iterator erase(const_iterator pos) { - const auto diff = pos - cbegin(); - erase(*pos); - return begin() + diff; - } - - /** - * @brief Removes the given elements from a container. - * @param first An iterator to the first element of the range of elements. - * @param last An iterator past the last element of the range of elements. - * @return An iterator following the last removed element. - */ - iterator erase(const_iterator first, const_iterator last) { - const auto dist = first - cbegin(); - - for(auto from = last - cbegin(); from != dist; --from) { - erase(packed.first()[static_cast(from) - 1u].second); - } - - return (begin() + dist); - } - - /** - * @brief Removes the element associated with a given value. - * @param value Value of an element to remove. - * @return Number of elements removed (either 0 or 1). - */ - size_type erase(const value_type &value) { - for(size_type *curr = &sparse.first()[value_to_bucket(value)]; *curr != placeholder_position; curr = &packed.first()[*curr].first) { - if(packed.second()(packed.first()[*curr].second, value)) { - const auto index = *curr; - *curr = packed.first()[*curr].first; - move_and_pop(index); - return 1u; - } - } - - return 0u; - } - - /** - * @brief Returns the number of elements matching a value (either 1 or 0). - * @param key Key value of an element to search for. - * @return Number of elements matching the key (either 1 or 0). - */ - [[nodiscard]] size_type count(const value_type &key) const { - return find(key) != end(); - } - - /** - * @brief Returns the number of elements matching a key (either 1 or 0). - * @param key Key value of an element to search for. - * @return Number of elements matching the key (either 1 or 0). - */ - [[nodiscard]] size_type count(const auto &key) const - requires is_transparent_v && is_transparent_v { - return find(key) != end(); - } - - /** - * @brief Finds an element with a given value. - * @param value Value of an element to search for. - * @return An iterator to an element with the given value. If no such - * element is found, a past-the-end iterator is returned. - */ - [[nodiscard]] iterator find(const value_type &value) { - return constrained_find(value, value_to_bucket(value)); - } - - /*! @copydoc find */ - [[nodiscard]] const_iterator find(const value_type &value) const { - return constrained_find(value, value_to_bucket(value)); - } - - /** - * @brief Finds an element that compares _equivalent_ to a given value. - * @param value Value of an element to search for. - * @return An iterator to an element with the given value. If no such - * element is found, a past-the-end iterator is returned. - */ - [[nodiscard]] iterator find(const auto &value) - requires is_transparent_v && is_transparent_v { - return constrained_find(value, value_to_bucket(value)); - } - - /*! @copydoc find */ - [[nodiscard]] const_iterator find(const auto &value) const - requires is_transparent_v && is_transparent_v { - return constrained_find(value, value_to_bucket(value)); - } - - /** - * @brief Returns a range containing all elements with a given value. - * @param value Value of an element to search for. - * @return A pair of iterators pointing to the first element and past the - * last element of the range. - */ - [[nodiscard]] stl::pair equal_range(const value_type &value) { - const auto it = find(value); - return {it, it + !(it == end())}; - } - - /*! @copydoc equal_range */ - [[nodiscard]] stl::pair equal_range(const value_type &value) const { - const auto it = find(value); - return {it, it + !(it == cend())}; - } - - /** - * @brief Returns a range containing all elements that compare _equivalent_ - * to a given value. - * @param value Value of an element to search for. - * @return A pair of iterators pointing to the first element and past the - * last element of the range. - */ - [[nodiscard]] stl::pair equal_range(const auto &value) - requires is_transparent_v && is_transparent_v { - const auto it = find(value); - return {it, it + !(it == end())}; - } - - /*! @copydoc equal_range */ - [[nodiscard]] stl::pair equal_range(const auto &value) const - requires is_transparent_v && is_transparent_v { - const auto it = find(value); - return {it, it + !(it == cend())}; - } - - /** - * @brief Checks if the container contains an element with a given value. - * @param value Value of an element to search for. - * @return True if there is such an element, false otherwise. - */ - [[nodiscard]] bool contains(const value_type &value) const { - return (find(value) != cend()); - } - - /** - * @brief Checks if the container contains an element that compares - * _equivalent_ to a given value. - * @param value Value of an element to search for. - * @return True if there is such an element, false otherwise. - */ - [[nodiscard]] bool contains(const auto &value) const - requires is_transparent_v && is_transparent_v { - return (find(value) != cend()); - } - - /** - * @brief Returns an iterator to the beginning of a given bucket. - * @param index An index of a bucket to access. - * @return An iterator to the beginning of the given bucket. - */ - [[nodiscard]] const_local_iterator cbegin(const size_type index) const { - return {packed.first().data(), sparse.first()[index]}; - } - - /** - * @brief Returns an iterator to the beginning of a given bucket. - * @param index An index of a bucket to access. - * @return An iterator to the beginning of the given bucket. - */ - [[nodiscard]] const_local_iterator begin(const size_type index) const { - return cbegin(index); - } - - /** - * @brief Returns an iterator to the beginning of a given bucket. - * @param index An index of a bucket to access. - * @return An iterator to the beginning of the given bucket. - */ - [[nodiscard]] local_iterator begin(const size_type index) { - return {packed.first().data(), sparse.first()[index]}; - } - - /** - * @brief Returns an iterator to the end of a given bucket. - * @param index An index of a bucket to access. - * @return An iterator to the end of the given bucket. - */ - [[nodiscard]] const_local_iterator cend([[maybe_unused]] const size_type index) const { - return {}; - } - - /** - * @brief Returns an iterator to the end of a given bucket. - * @param index An index of a bucket to access. - * @return An iterator to the end of the given bucket. - */ - [[nodiscard]] const_local_iterator end(const size_type index) const { - return cend(index); - } - - /** - * @brief Returns an iterator to the end of a given bucket. - * @param index An index of a bucket to access. - * @return An iterator to the end of the given bucket. - */ - [[nodiscard]] local_iterator end([[maybe_unused]] const size_type index) { - return {}; - } - - /** - * @brief Returns the number of buckets. - * @return The number of buckets. - */ - [[nodiscard]] size_type bucket_count() const { - return sparse.first().size(); - } - - /** - * @brief Returns the maximum number of buckets. - * @return The maximum number of buckets. - */ - [[nodiscard]] size_type max_bucket_count() const { - return sparse.first().max_size(); - } - - /** - * @brief Returns the number of elements in a given bucket. - * @param index The index of the bucket to examine. - * @return The number of elements in the given bucket. - */ - [[nodiscard]] size_type bucket_size(const size_type index) const { - return static_cast(stl::distance(begin(index), end(index))); - } - - /** - * @brief Returns the bucket for a given element. - * @param value The value of the element to examine. - * @return The bucket for the given element. - */ - [[nodiscard]] size_type bucket(const value_type &value) const { - return value_to_bucket(value); - } - - /** - * @brief Returns the average number of elements per bucket. - * @return The average number of elements per bucket. - */ - [[nodiscard]] float load_factor() const { - return static_cast(size()) / static_cast(bucket_count()); - } - - /** - * @brief Returns the maximum average number of elements per bucket. - * @return The maximum average number of elements per bucket. - */ - [[nodiscard]] float max_load_factor() const { - return threshold; - } - - /** - * @brief Sets the desired maximum average number of elements per bucket. - * @param value A desired maximum average number of elements per bucket. - */ - void max_load_factor(const float value) { - ENTT_ASSERT(value > 0.f, "Invalid load factor"); - threshold = value; - rehash(0u); - } - - /** - * @brief Reserves at least the specified number of buckets and regenerates - * the hash table. - * @param cnt New number of buckets. - */ - void rehash(const size_type cnt) { - auto value = cnt > minimum_capacity ? cnt : minimum_capacity; - const auto cap = static_cast(static_cast(size()) / max_load_factor()); - value = value > cap ? value : cap; - - if(const auto sz = stl::bit_ceil(value); sz != bucket_count()) { - sparse.first().resize(sz); - - for(auto &&elem: sparse.first()) { - elem = placeholder_position; - } - - for(size_type pos{}, last = size(); pos < last; ++pos) { - const auto index = value_to_bucket(packed.first()[pos].second); - packed.first()[pos].first = stl::exchange(sparse.first()[index], pos); - } - } - } - - /** - * @brief Reserves space for at least the specified number of elements and - * regenerates the hash table. - * @param cnt New number of elements. - */ - void reserve(const size_type cnt) { - packed.first().reserve(cnt); - rehash(static_cast(stl::ceil(static_cast(cnt) / max_load_factor()))); - } - - /** - * @brief Returns the function used to hash the elements. - * @return The function used to hash the elements. - */ - [[nodiscard]] hasher hash_function() const { - return sparse.second(); - } - - /** - * @brief Returns the function used to compare elements for equality. - * @return The function used to compare elements for equality. - */ - [[nodiscard]] key_equal key_eq() const { - return packed.second(); - } - -private: - compressed_pair sparse; - compressed_pair packed; - float threshold{default_threshold}; -}; - -} // namespace entt - -#endif diff --git a/include/entt/container/fwd.hpp b/include/entt/container/fwd.hpp deleted file mode 100644 index 72f0906..0000000 --- a/include/entt/container/fwd.hpp +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef ENTT_CONTAINER_FWD_HPP -#define ENTT_CONTAINER_FWD_HPP - -#include "../stl/functional.hpp" -#include "../stl/memory.hpp" -#include "../stl/utility.hpp" -#include "../stl/vector.hpp" - -namespace entt { - -template< - typename Key, - typename Type, - typename = stl::hash, - typename = stl::equal_to<>, - typename = stl::allocator>> -class dense_map; - -template< - typename Type, - typename = stl::hash, - typename = stl::equal_to<>, - typename = stl::allocator> -class dense_set; - -template -class basic_table; - -/** - * @brief Alias declaration for the most common use case. - * @tparam Type Element types. - */ -template -using table = basic_table...>; - -} // namespace entt - -#endif diff --git a/include/entt/container/table.hpp b/include/entt/container/table.hpp deleted file mode 100644 index 86e278d..0000000 --- a/include/entt/container/table.hpp +++ /dev/null @@ -1,434 +0,0 @@ -#ifndef ENTT_CONTAINER_TABLE_HPP -#define ENTT_CONTAINER_TABLE_HPP - -#include "../config/config.h" -#include "../core/iterator.hpp" -#include "../stl/concepts.hpp" -#include "../stl/cstddef.hpp" -#include "../stl/iterator.hpp" -#include "../stl/tuple.hpp" -#include "../stl/utility.hpp" -#include "fwd.hpp" - -namespace entt { - -/*! @cond ENTT_INTERNAL */ -namespace internal { - -template -class table_iterator { - template - friend class table_iterator; - -public: - using value_type = decltype(stl::forward_as_tuple(*stl::declval()...)); - using pointer = input_iterator_pointer; - using reference = value_type; - using difference_type = stl::ptrdiff_t; - using iterator_category = stl::input_iterator_tag; - using iterator_concept = stl::random_access_iterator_tag; - - constexpr table_iterator() noexcept - : it{} {} - - constexpr table_iterator(It... from) noexcept - : it{from...} {} - - template - requires (stl::constructible_from && ...) - constexpr table_iterator(const table_iterator &other) noexcept - : table_iterator{stl::get(other.it)...} {} - - constexpr table_iterator &operator++() noexcept { - return (++stl::get(it), ...), *this; - } - - constexpr table_iterator operator++(int) noexcept { - const table_iterator orig = *this; - return ++(*this), orig; - } - - constexpr table_iterator &operator--() noexcept { - return (--stl::get(it), ...), *this; - } - - constexpr table_iterator operator--(int) noexcept { - const table_iterator orig = *this; - return operator--(), orig; - } - - constexpr table_iterator &operator+=(const difference_type value) noexcept { - return ((stl::get(it) += value), ...), *this; - } - - constexpr table_iterator operator+(const difference_type value) const noexcept { - table_iterator copy = *this; - return (copy += value); - } - - constexpr table_iterator &operator-=(const difference_type value) noexcept { - return (*this += -value); - } - - constexpr table_iterator operator-(const difference_type value) const noexcept { - return (*this + -value); - } - - [[nodiscard]] constexpr reference operator[](const difference_type value) const noexcept { - return stl::forward_as_tuple(stl::get(it)[value]...); - } - - [[nodiscard]] constexpr pointer operator->() const noexcept { - return {operator[](0)}; - } - - [[nodiscard]] constexpr reference operator*() const noexcept { - return operator[](0); - } - - template - [[nodiscard]] constexpr stl::ptrdiff_t operator-(const table_iterator &other) const noexcept { - return stl::get<0>(it) - stl::get<0>(other.it); - } - - template - [[nodiscard]] constexpr bool operator==(const table_iterator &other) const noexcept { - return stl::get<0>(it) == stl::get<0>(other.it); - } - - template - [[nodiscard]] constexpr auto operator<=>(const table_iterator &other) const noexcept { - return stl::get<0>(it) <=> stl::get<0>(other.it); - } - -private: - stl::tuple it; -}; - -} // namespace internal -/*! @endcond */ - -/** - * @brief Basic table implementation. - * - * Internal data structures arrange elements to maximize performance. There are - * no guarantees that objects are returned in the insertion order when iterate - * a table. Do not make assumption on the order in any case. - * - * @tparam Container Sequence container row types. - */ -template -class basic_table { - using container_type = stl::tuple; - -public: - /*! @brief Unsigned integer type. */ - using size_type = stl::size_t; - /*! @brief Signed integer type. */ - using difference_type = stl::ptrdiff_t; - /*! @brief Input iterator type. */ - using iterator = internal::table_iterator; - /*! @brief Constant input iterator type. */ - using const_iterator = internal::table_iterator; - /*! @brief Reverse iterator type. */ - using reverse_iterator = internal::table_iterator; - /*! @brief Constant reverse iterator type. */ - using const_reverse_iterator = internal::table_iterator; - - /*! @brief Default constructor. */ - basic_table() - : payload{} { - } - - /** - * @brief Copy constructs the underlying containers. - * @param container The containers to copy from. - */ - explicit basic_table(const Container &...container) noexcept - : payload{container...} { - ENTT_ASSERT((((stl::get(payload).size() * sizeof...(Container)) == (stl::get(payload).size() + ...)) && ...), "Unexpected container size"); - } - - /** - * @brief Move constructs the underlying containers. - * @param container The containers to move from. - */ - explicit basic_table(Container &&...container) noexcept - : payload{stl::move(container)...} { - ENTT_ASSERT((((stl::get(payload).size() * sizeof...(Container)) == (stl::get(payload).size() + ...)) && ...), "Unexpected container size"); - } - - /*! @brief Default copy constructor, deleted on purpose. */ - basic_table(const basic_table &) = delete; - - /** - * @brief Move constructor. - * @param other The instance to move from. - */ - basic_table(basic_table &&other) noexcept - : payload{stl::move(other.payload)} {} - - /** - * @brief Constructs the underlying containers using a given allocator. - * @param allocator A valid allocator. - */ - explicit basic_table(const auto &allocator) - : payload{Container{allocator}...} {} - - /** - * @brief Copy constructs the underlying containers using a given allocator. - * @tparam Allocator Type of allocator. - * @param container The containers to copy from. - * @param allocator A valid allocator. - */ - template - basic_table(const Container &...container, const Allocator &allocator) noexcept - : payload{Container{container, allocator}...} { - ENTT_ASSERT((((stl::get(payload).size() * sizeof...(Container)) == (stl::get(payload).size() + ...)) && ...), "Unexpected container size"); - } - - /** - * @brief Move constructs the underlying containers using a given allocator. - * @tparam Allocator Type of allocator. - * @param container The containers to move from. - * @param allocator A valid allocator. - */ - template - basic_table(Container &&...container, const Allocator &allocator) noexcept - : payload{Container{stl::move(container), allocator}...} { - ENTT_ASSERT((((stl::get(payload).size() * sizeof...(Container)) == (stl::get(payload).size() + ...)) && ...), "Unexpected container size"); - } - - /** - * @brief Allocator-extended move constructor. - * @tparam Allocator Type of allocator. - * @param other The instance to move from. - * @param allocator The allocator to use. - */ - template - basic_table(basic_table &&other, const Allocator &allocator) - : payload{Container{stl::move(stl::get(other.payload)), allocator}...} {} - - /*! @brief Default destructor. */ - ~basic_table() = default; - - /** - * @brief Default copy assignment operator, deleted on purpose. - * @return This container. - */ - basic_table &operator=(const basic_table &) = delete; - - /** - * @brief Move assignment operator. - * @param other The instance to move from. - * @return This container. - */ - basic_table &operator=(basic_table &&other) noexcept { - swap(other); - return *this; - } - - /** - * @brief Exchanges the contents with those of a given table. - * @param other Table to exchange the content with. - */ - void swap(basic_table &other) noexcept { - using stl::swap; - swap(payload, other.payload); - } - - /** - * @brief Increases the capacity of a table. - * - * 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) { - (stl::get(payload).reserve(cap), ...); - } - - /** - * @brief Returns the number of rows that a table has currently allocated - * space for. - * @return Capacity of the table. - */ - [[nodiscard]] size_type capacity() const noexcept { - return stl::get<0>(payload).capacity(); - } - - /*! @brief Requests the removal of unused capacity. */ - void shrink_to_fit() { - (stl::get(payload).shrink_to_fit(), ...); - } - - /** - * @brief Returns the number of rows in a table. - * @return Number of rows. - */ - [[nodiscard]] size_type size() const noexcept { - return stl::get<0>(payload).size(); - } - - /** - * @brief Checks whether a table is empty. - * @return True if the table is empty, false otherwise. - */ - [[nodiscard]] bool empty() const noexcept { - return stl::get<0>(payload).empty(); - } - - /** - * @brief Returns an iterator to the beginning. - * - * If the table is empty, the returned iterator will be equal to `end()`. - * - * @return An iterator to the first row of the table. - */ - [[nodiscard]] const_iterator cbegin() const noexcept { - return {stl::get(payload).cbegin()...}; - } - - /*! @copydoc cbegin */ - [[nodiscard]] const_iterator begin() const noexcept { - return cbegin(); - } - - /*! @copydoc begin */ - [[nodiscard]] iterator begin() noexcept { - return {stl::get(payload).begin()...}; - } - - /** - * @brief Returns an iterator to the end. - * @return An iterator to the element following the last row of the table. - */ - [[nodiscard]] const_iterator cend() const noexcept { - return {stl::get(payload).cend()...}; - } - - /*! @copydoc cend */ - [[nodiscard]] const_iterator end() const noexcept { - return cend(); - } - - /*! @copydoc end */ - [[nodiscard]] iterator end() noexcept { - return {stl::get(payload).end()...}; - } - - /** - * @brief Returns a reverse iterator to the beginning. - * - * If the table is empty, the returned iterator will be equal to `rend()`. - * - * @return An iterator to the first row of the reversed table. - */ - [[nodiscard]] const_reverse_iterator crbegin() const noexcept { - return {stl::get(payload).crbegin()...}; - } - - /*! @copydoc crbegin */ - [[nodiscard]] const_reverse_iterator rbegin() const noexcept { - return crbegin(); - } - - /*! @copydoc rbegin */ - [[nodiscard]] reverse_iterator rbegin() noexcept { - return {stl::get(payload).rbegin()...}; - } - - /** - * @brief Returns a reverse iterator to the end. - * @return An iterator to the element following the last row of the reversed - * table. - */ - [[nodiscard]] const_reverse_iterator crend() const noexcept { - return {stl::get(payload).crend()...}; - } - - /*! @copydoc crend */ - [[nodiscard]] const_reverse_iterator rend() const noexcept { - return crend(); - } - - /*! @copydoc rend */ - [[nodiscard]] reverse_iterator rend() noexcept { - return {stl::get(payload).rend()...}; - } - - /** - * @brief Appends a row to the end of a table. - * @tparam Args Types of arguments to use to construct the row data. - * @param args Parameters to use to construct the row data. - * @return A reference to the newly created row data. - */ - template - stl::tuple emplace(Args &&...args) { - if constexpr(sizeof...(Args) == 0u) { - return stl::forward_as_tuple(stl::get(payload).emplace_back()...); - } else { - return stl::forward_as_tuple(stl::get(payload).emplace_back(stl::forward(args))...); - } - } - - /** - * @brief Removes a row from a table. - * @param pos An iterator to the row to remove. - * @return An iterator following the removed row. - */ - iterator erase(const_iterator pos) { - const auto diff = pos - begin(); - return {stl::get(payload).erase(stl::get(payload).begin() + diff)...}; - } - - /** - * @brief Removes a row from a table. - * @param pos Index of the row to remove. - */ - void erase(const size_type pos) { - ENTT_ASSERT(pos < size(), "Index out of bounds"); - erase(begin() + static_cast(pos)); - } - - /** - * @brief Returns the row data at specified location. - * @param pos The row for which to return the data. - * @return The row data at specified location. - */ - [[nodiscard]] stl::tuple operator[](const size_type pos) const { - ENTT_ASSERT(pos < size(), "Index out of bounds"); - return stl::forward_as_tuple(stl::get(payload)[pos]...); - } - - /*! @copydoc operator[] */ - [[nodiscard]] stl::tuple operator[](const size_type pos) { - ENTT_ASSERT(pos < size(), "Index out of bounds"); - return stl::forward_as_tuple(stl::get(payload)[pos]...); - } - - /*! @brief Clears a table. */ - void clear() { - (stl::get(payload).clear(), ...); - } - -private: - container_type payload; -}; - -} // namespace entt - -/*! @cond ENTT_INTERNAL */ -#include - -namespace std { - -template -struct uses_allocator, Allocator> - : entt::stl::bool_constant<(entt::stl::uses_allocator_v && ...)> {}; - -} // namespace std -/*! @endcond */ - -#endif diff --git a/include/entt/core/algorithm.hpp b/include/entt/core/algorithm.hpp deleted file mode 100644 index 758f0cd..0000000 --- a/include/entt/core/algorithm.hpp +++ /dev/null @@ -1,143 +0,0 @@ -#ifndef ENTT_CORE_ALGORITHM_HPP -#define ENTT_CORE_ALGORITHM_HPP - -#include "../stl/algorithm.hpp" -#include "../stl/concepts.hpp" -#include "../stl/cstddef.hpp" -#include "../stl/functional.hpp" -#include "../stl/iterator.hpp" -#include "../stl/utility.hpp" -#include "../stl/vector.hpp" - -namespace entt { - -/** - * @brief Function object to wrap `stl::sort` in a class type. - * - * Unfortunately, `stl::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 `stl::sort` in a - * function object. - */ -struct std_sort { - /** - * @brief Sorts the elements in a range. - * - * Sorts the elements in a range using the given binary comparison function. - * - * @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()(stl::random_access_iterator auto first, stl::random_access_iterator auto last, Compare compare = Compare{}, Args &&...args) const { - stl::sort(stl::forward(args)..., stl::move(first), stl::move(last), stl::move(compare)); - } -}; - -/*! @brief Function object for performing insertion sort. */ -struct insertion_sort { - /** - * @brief Sorts the elements in a range. - * - * Sorts the elements in a range using the given binary comparison function. - * - * @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()(stl::random_access_iterator auto first, stl::random_access_iterator auto last, Compare compare = Compare{}) const { - if(first < last) { - for(auto it = first + 1; it < last; ++it) { - auto value = stl::move(*it); - auto pre = it; - - // NOLINTBEGIN(cppcoreguidelines-pro-bounds-pointer-arithmetic) - for(; pre > first && compare(value, *(pre - 1)); --pre) { - *pre = stl::move(*(pre - 1)); - } - // NOLINTEND(cppcoreguidelines-pro-bounds-pointer-arithmetic) - - *pre = stl::move(value); - } - } - } -}; - -/** - * @brief Function object for performing LSD radix sort. - * @tparam Bit Number of bits processed per pass. - * @tparam N Maximum number of bits to sort. - */ -template -requires ((N % Bit) == 0) // The maximum number of bits to sort must be a multiple of the number of bits processed per pass -struct radix_sort { - /** - * @brief Sorts the elements in a range. - * - * Sorts the elements in a range using the given _getter_ to access the - * actual data to be sorted. - * - * This implementation is inspired by the online book - * [Physically Based Rendering](http://www.pbr-book.org/3ed-2018/Primitives_and_Intersection_Acceleration/Bounding_Volume_Hierarchies.html#RadixSort). - * - * @tparam It Type of random access iterator. - * @tparam Getter Type of _getter_ 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 getter A valid _getter_ function object. - */ - template - void operator()(It first, It last, Getter getter = Getter{}) const { - if(first < last) { - constexpr auto passes = N / Bit; - - using value_type = stl::iterator_traits::value_type; - using difference_type = stl::iterator_traits::difference_type; - stl::vector aux(static_cast(stl::distance(first, last))); - - auto part = [getter = stl::move(getter)](auto from, auto to, auto out, auto start) { - constexpr auto mask = (1 << Bit) - 1; - constexpr auto buckets = 1 << Bit; - - // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays, modernize-avoid-c-arrays, misc-const-correctness) - stl::size_t count[buckets]{}; - - for(auto it = from; it != to; ++it) { - ++count[(getter(*it) >> start) & mask]; - } - - // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays, modernize-avoid-c-arrays) - stl::size_t index[buckets]{}; - - for(stl::size_t pos{}, end = buckets - 1u; pos < end; ++pos) { - index[pos + 1u] = index[pos] + count[pos]; - } - - for(auto it = from; it != to; ++it) { - const auto pos = index[(getter(*it) >> start) & mask]++; - out[static_cast(pos)] = stl::move(*it); - } - }; - - for(stl::size_t pass = 0; pass < (passes & ~1u); pass += 2) { - part(first, last, aux.begin(), pass * Bit); - part(aux.begin(), aux.end(), first, (pass + 1) * Bit); - } - - if constexpr(passes & 1) { - part(first, last, aux.begin(), (passes - 1) * Bit); - stl::move(aux.begin(), aux.end(), first); - } - } - } -}; - -} // namespace entt - -#endif diff --git a/include/entt/core/any.hpp b/include/entt/core/any.hpp deleted file mode 100644 index 74e27d6..0000000 --- a/include/entt/core/any.hpp +++ /dev/null @@ -1,623 +0,0 @@ -#ifndef ENTT_CORE_ANY_HPP -#define ENTT_CORE_ANY_HPP - -#include "../config/config.h" -#include "../core/concepts.hpp" -#include "../stl/concepts.hpp" -#include "../stl/cstddef.hpp" -#include "../stl/cstdint.hpp" -#include "../stl/memory.hpp" -#include "../stl/type_traits.hpp" -#include "../stl/utility.hpp" -#include "fwd.hpp" -#include "type_info.hpp" -#include "type_traits.hpp" -#include "utility.hpp" - -namespace entt { - -/*! @cond ENTT_INTERNAL */ -namespace internal { - -enum class any_request : stl::uint8_t { - info, - transfer, - assign, - compare, - copy, - move -}; - -template -struct basic_any_storage { - static constexpr bool has_buffer = true; - union { - const void *instance{}; - // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays, modernize-avoid-c-arrays) - alignas(Align) stl::byte buffer[Len]; - }; -}; - -template -struct basic_any_storage<0u, Align> { - static constexpr bool has_buffer = false; - const void *instance{}; -}; - -template -// NOLINTNEXTLINE(bugprone-sizeof-expression) -struct in_situ: stl::bool_constant<(Len != 0u) && alignof(Type) <= Align && sizeof(Type) <= Len && stl::is_nothrow_move_constructible_v> {}; - -template -struct in_situ: stl::false_type {}; - -} // namespace internal -/*! @endcond */ - -/** - * @brief A SBO friendly, type-safe container for single values of any type. - * @tparam Len Size of the buffer reserved for the small buffer optimization. - * @tparam Align Optional alignment requirement. - */ -template -class basic_any: private internal::basic_any_storage { - using request = internal::any_request; - using base_type = internal::basic_any_storage; - using vtable_type = const void *(const request, const basic_any &, const void *); - using deleter_type = void(const basic_any &); - - template - static constexpr bool in_situ_v = internal::in_situ::value; - - template - static const void *basic_vtable(const request req, const basic_any &value, const void *other) { - switch(const auto *elem = static_cast(value.data()); req) { - using enum internal::any_request; - case info: - return &type_id(); - case transfer: - if constexpr(stl::is_move_assignable_v) { - // NOLINTNEXTLINE(bugprone-casting-through-void) - *const_cast(elem) = stl::move(*static_cast(const_cast(other))); - return other; - } - [[fallthrough]]; - case assign: - if constexpr(stl::is_copy_assignable_v) { - *const_cast(elem) = *static_cast(other); - return other; - } - break; - case compare: - if constexpr(!stl::is_function_v && !stl::is_array_v && is_equality_comparable_v) { - return (*elem == *static_cast(other)) ? other : nullptr; - } else { - return (elem == other) ? other : nullptr; - } - case copy: - if constexpr(stl::is_copy_constructible_v) { - // NOLINTNEXTLINE(bugprone-casting-through-void) - static_cast(const_cast(other))->initialize(*elem); - } - break; - case move: - ENTT_ASSERT(value.mode == any_policy::embedded, "Unexpected policy"); - if constexpr(in_situ_v) { - // NOLINTNEXTLINE(bugprone-casting-through-void, bugprone-multi-level-implicit-pointer-conversion) - return ::new(&static_cast(const_cast(other))->buffer) Type{stl::move(*const_cast(elem))}; - } - } - - return nullptr; - } - - template - static void basic_deleter(const basic_any &value) { - ENTT_ASSERT((value.mode == any_policy::dynamic) || ((value.mode == any_policy::embedded) && !stl::is_trivially_destructible_v), "Unexpected policy"); - - const auto *elem = static_cast(value.data()); - - if constexpr(in_situ_v) { - (value.mode == any_policy::embedded) ? elem->~Type() : (delete elem); - } else if constexpr(stl::is_array_v) { - delete[] elem; - } else { - delete elem; - } - } - - template - void initialize([[maybe_unused]] Args &&...args) { - using plain_type = stl::remove_cvref_t; - - vtable = basic_vtable; - underlying_type = type_hash::value(); - - if constexpr(stl::is_void_v) { - deleter = nullptr; - mode = any_policy::empty; - this->instance = nullptr; - } else if constexpr(stl::is_lvalue_reference_v) { - deleter = nullptr; - mode = stl::is_const_v> ? any_policy::cref : any_policy::ref; - static_assert((stl::is_lvalue_reference_v && ...) && (sizeof...(Args) == 1u), "Invalid arguments"); - // NOLINTNEXTLINE(bugprone-multi-level-implicit-pointer-conversion) - this->instance = (stl::addressof(args), ...); - } else if constexpr(in_situ_v) { - if constexpr(stl::is_trivially_destructible_v) { - deleter = nullptr; - } else { - deleter = &basic_deleter; - } - - mode = any_policy::embedded; - - if constexpr(stl::is_aggregate_v && (sizeof...(Args) != 0u || !stl::is_default_constructible_v)) { - ::new(&this->buffer) plain_type{stl::forward(args)...}; - } else { - // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay) - ::new(&this->buffer) plain_type(stl::forward(args)...); - } - } else { - deleter = &basic_deleter; - mode = any_policy::dynamic; - - if constexpr(stl::is_aggregate_v && (sizeof...(Args) != 0u || !stl::is_default_constructible_v)) { - this->instance = new plain_type{stl::forward(args)...}; - } else if constexpr(stl::is_array_v) { - static_assert(sizeof...(Args) == 0u, "Invalid arguments"); - this->instance = new plain_type[stl::extent_v](); - } else { - this->instance = new plain_type(stl::forward(args)...); - } - } - } - - void invoke_deleter_if_exists() { - if(deleter != nullptr) { - deleter(*this); - } - } - -public: - /*! @brief Size of the internal buffer. */ - static constexpr auto length = Len; - /*! @brief Alignment requirement. */ - static constexpr auto alignment = Align; - - /*! @brief Default constructor. */ - constexpr basic_any() noexcept - : basic_any{stl::in_place_type} {} - - /** - * @brief Constructs a wrapper by directly initializing the new object. - * @tparam Type Type of object to use to initialize the wrapper. - * @tparam Args Types of arguments to use to construct the new instance. - * @param args Parameters to use to construct the instance. - */ - template - explicit basic_any(stl::in_place_type_t, Args &&...args) - : base_type{} { - initialize(stl::forward(args)...); - } - - /** - * @brief Constructs a wrapper taking ownership of the passed object. - * @tparam Type Type of object to use to initialize the wrapper. - * @param value A pointer to an object to take ownership of. - */ - template - requires (!stl::is_const_v && !stl::is_void_v) - explicit basic_any(stl::in_place_t, Type *value) - : base_type{} { - if(value == nullptr) { - initialize(); - } else { - initialize(*value); - deleter = &basic_deleter; - mode = any_policy::dynamic; - } - } - - /** - * @brief Constructs a wrapper from a given value. - * @tparam Type Type of object to use to initialize the wrapper. - * @param value An instance of an object to use to initialize the wrapper. - */ - template - requires (!stl::same_as, basic_any>) - basic_any(Type &&value) - : basic_any{stl::in_place_type>, stl::forward(value)} {} - - /** - * @brief Copy constructor. - * @param other The instance to copy from. - */ - basic_any(const basic_any &other) - : basic_any{} { - other.vtable(request::copy, other, this); - } - - /** - * @brief Move constructor. - * @param other The instance to move from. - */ - basic_any(basic_any &&other) noexcept - : base_type{}, - vtable{other.vtable}, - deleter{other.deleter}, - underlying_type{other.underlying_type}, - mode{other.mode} { - if(other.mode == any_policy::embedded) { - other.vtable(request::move, other, this); - } else if(other.mode != any_policy::empty) { - this->instance = stl::exchange(other.instance, nullptr); - } - } - - /*! @brief Frees the internal buffer, whatever it means. */ - ~basic_any() { - invoke_deleter_if_exists(); - } - - /** - * @brief Copy assignment operator. - * @param other The instance to copy from. - * @return This any object. - */ - basic_any &operator=(const basic_any &other) { - if(this != &other) { - invoke_deleter_if_exists(); - - if(other) { - other.vtable(request::copy, other, this); - } else { - initialize(); - } - } - - return *this; - } - - /** - * @brief Move assignment operator. - * @param other The instance to move from. - * @return This any object. - */ - basic_any &operator=(basic_any &&other) noexcept { - if(this != &other) { - invoke_deleter_if_exists(); - - if(other.mode == any_policy::embedded) { - other.vtable(request::move, other, this); - } else if(other.mode != any_policy::empty) { - this->instance = stl::exchange(other.instance, nullptr); - } - - vtable = other.vtable; - deleter = other.deleter; - underlying_type = other.underlying_type; - mode = other.mode; - } - - return *this; - } - - /** - * @brief Value assignment operator. - * @tparam Type Type of object to use to initialize the wrapper. - * @param value An instance of an object to use to initialize the wrapper. - * @return This any object. - */ - template - requires (!stl::same_as, basic_any>) - basic_any &operator=(Type &&value) { - emplace>(stl::forward(value)); - return *this; - } - - /** - * @brief Returns false if a wrapper is empty, true otherwise. - * @return False if the wrapper is empty, true otherwise. - */ - [[nodiscard]] bool has_value() const noexcept { - return (mode != any_policy::empty); - } - - /** - * @brief Returns false if the wrapper does not contain the expected type, - * true otherwise. - * @param req Expected type. - * @return False if the wrapper does not contain the expected type, true - * otherwise. - */ - [[nodiscard]] bool has_value(const type_info &req) const noexcept { - return (underlying_type == req.hash()); - } - - /** - * @brief Returns false if the wrapper does not contain the expected type, - * true otherwise. - * @tparam Type Expected type. - * @return False if the wrapper does not contain the expected type, true - * otherwise. - */ - template - [[nodiscard]] bool has_value() const noexcept { - return (underlying_type == type_hash::value()); - } - - /** - * @brief Returns the object type info if any, `type_id()` otherwise. - * @return The object type info if any, `type_id()` otherwise. - */ - [[nodiscard]] const type_info &info() const noexcept { - return *static_cast(vtable(request::info, *this, nullptr)); - } - - /** - * @brief Returns an opaque pointer to the contained instance. - * @return An opaque pointer the contained instance, if any. - */ - [[nodiscard]] const void *data() const noexcept { - if constexpr(base_type::has_buffer) { - return (mode == any_policy::embedded) ? &this->buffer : this->instance; - } else { - return this->instance; - } - } - - /** - * @brief Returns an opaque pointer to the contained instance. - * @param req Expected type. - * @return An opaque pointer the contained instance, if any. - */ - [[nodiscard]] const void *data(const type_info &req) const noexcept { - return has_value(req) ? data() : nullptr; - } - - /** - * @brief Returns an opaque pointer to the contained instance. - * @tparam Type Expected type. - * @return An opaque pointer the contained instance, if any. - */ - template - [[nodiscard]] const Type *data() const noexcept { - return has_value>() ? static_cast(data()) : nullptr; - } - - /** - * @brief Returns an opaque pointer to the contained instance. - * @return An opaque pointer the contained instance, if any. - */ - [[nodiscard]] void *data() noexcept { - return (mode == any_policy::cref) ? nullptr : const_cast(stl::as_const(*this).data()); - } - - /** - * @brief Returns an opaque pointer to the contained instance. - * @param req Expected type. - * @return An opaque pointer the contained instance, if any. - */ - [[nodiscard]] void *data(const type_info &req) noexcept { - return (mode == any_policy::cref) ? nullptr : const_cast(stl::as_const(*this).data(req)); - } - - /** - * @brief Returns an opaque pointer to the contained instance. - * @tparam Type Expected type. - * @return An opaque pointer the contained instance, if any. - */ - template - [[nodiscard]] Type *data() noexcept { - if constexpr(stl::is_const_v) { - return stl::as_const(*this).template data>(); - } else { - return (mode == any_policy::cref) ? nullptr : const_cast(stl::as_const(*this).template data>()); - } - } - - /** - * @brief Replaces the contained object by creating a new instance directly. - * @tparam Type Type of object to use to initialize the wrapper. - * @tparam Args Types of arguments to use to construct the new instance. - * @param args Parameters to use to construct the instance. - */ - template - void emplace(Args &&...args) { - invoke_deleter_if_exists(); - initialize(stl::forward(args)...); - } - - /** - * @brief Assigns a value to the contained object without replacing it. - * @param other The value to assign to the contained object. - * @return True in case of success, false otherwise. - */ - bool assign(const basic_any &other) { - if(other && (mode != any_policy::cref) && (underlying_type == other.underlying_type)) { - return (vtable(request::assign, *this, other.data()) != nullptr); - } - - return false; - } - - /*! @copydoc assign */ - // NOLINTNEXTLINE(cppcoreguidelines-rvalue-reference-param-not-moved) - bool assign(basic_any &&other) { - if(other && (mode != any_policy::cref) && (underlying_type == other.underlying_type)) { - return (other.mode == any_policy::cref) ? (vtable(request::assign, *this, stl::as_const(other).data()) != nullptr) : (vtable(request::transfer, *this, other.data()) != nullptr); - } - - return false; - } - - /*! @brief Destroys contained object */ - void reset() { - invoke_deleter_if_exists(); - initialize(); - } - - /** - * @brief Returns false if a wrapper is empty, true otherwise. - * @return False if the wrapper is empty, true otherwise. - */ - [[nodiscard]] explicit operator bool() const noexcept { - return has_value(); - } - - /** - * @brief Checks if two wrappers differ in their content. - * @param other Wrapper with which to compare. - * @return False if the two objects differ in their content, true otherwise. - */ - [[nodiscard]] bool operator==(const basic_any &other) const noexcept { - if(other && (underlying_type == other.underlying_type)) { - return (vtable(request::compare, *this, other.data()) != nullptr); - } - - return (!*this && !other); - } - - /** - * @brief Aliasing constructor. - * @return A wrapper that shares a reference to an unmanaged object. - */ - [[nodiscard]] basic_any as_ref() noexcept { - basic_any other = stl::as_const(*this).as_ref(); - - switch(mode) { - using enum any_policy; - case cref: - case empty: - other.mode = mode; - break; - default: - other.mode = any_policy::ref; - break; - } - - return other; - } - - /*! @copydoc as_ref */ - [[nodiscard]] basic_any as_ref() const noexcept { - basic_any other{}; - other.instance = data(); - other.vtable = vtable; - other.underlying_type = underlying_type; - other.mode = any_policy::cref; - return other; - } - - /** - * @brief Returns true if a wrapper owns its object, false otherwise. - * @return True if the wrapper owns its object, false otherwise. - */ - [[nodiscard]] bool owner() const noexcept { - return (mode == any_policy::dynamic || mode == any_policy::embedded); - } - - /** - * @brief Returns the current mode of an any object. - * @return The current mode of the any object. - */ - [[nodiscard]] any_policy policy() const noexcept { - return mode; - } - -private: - vtable_type *vtable{}; - deleter_type *deleter{}; - id_type underlying_type{}; - any_policy mode{}; -}; - -/** - * @brief Performs type-safe access to the contained object. - * @tparam Type Type to which conversion is required. - * @tparam Len Size of the buffer reserved for the small buffer optimization. - * @tparam Align Alignment requirement. - * @param data Target any object. - * @return The element converted to the requested type. - */ -template -[[nodiscard]] stl::remove_const_t any_cast(const basic_any &data) noexcept { - const auto *const instance = any_cast>(&data); - ENTT_ASSERT(instance, "Invalid instance"); - return static_cast(*instance); -} - -/*! @copydoc any_cast */ -template -[[nodiscard]] stl::remove_const_t any_cast(basic_any &data) noexcept { - // forces const on non-reference types to make them work also with wrappers for const references - auto *const instance = any_cast>(&data); - ENTT_ASSERT(instance, "Invalid instance"); - return static_cast(*instance); -} - -/*! @copydoc any_cast */ -template -// NOLINTNEXTLINE(cppcoreguidelines-rvalue-reference-param-not-moved) -[[nodiscard]] stl::remove_const_t any_cast(basic_any &&data) noexcept { - if constexpr(stl::is_copy_constructible_v>) { - if(auto *const instance = any_cast>(&data); instance) { - return static_cast(stl::move(*instance)); - } - - return any_cast(data); - } else { - auto *const instance = any_cast>(&data); - ENTT_ASSERT(instance, "Invalid instance"); - return static_cast(stl::move(*instance)); - } -} - -/*! @copydoc any_cast */ -template -[[nodiscard]] const Type *any_cast(const basic_any *data) noexcept { - return data->template data>(); -} - -/*! @copydoc any_cast */ -template -[[nodiscard]] Type *any_cast(basic_any *data) noexcept { - if constexpr(stl::is_const_v) { - // last attempt to make wrappers for const references return their values - return any_cast(&stl::as_const(*data)); - } else { - return data->template data(); - } -} - -/** - * @brief Constructs a wrapper from a given type, passing it all arguments. - * @tparam Type Type of object to use to initialize the wrapper. - * @tparam Len Size of the buffer reserved for the small buffer optimization. - * @tparam Align Optional alignment requirement. - * @tparam Args Types of arguments to use to construct the new instance. - * @param args Parameters to use to construct the instance. - * @return A properly initialized wrapper for an object of the given type. - */ -template::length, stl::size_t Align = basic_any::alignment, typename... Args> -[[nodiscard]] basic_any make_any(Args &&...args) { - return basic_any{stl::in_place_type, stl::forward(args)...}; -} - -/** - * @brief Forwards its argument and avoids copies for lvalue references. - * @tparam Len Size of the buffer reserved for the small buffer optimization. - * @tparam Align Optional alignment requirement. - * @tparam Type Type of argument to use to construct the new instance. - * @param value Parameter to use to construct the instance. - * @return A properly initialized and not necessarily owning wrapper. - */ -template::length, stl::size_t Align = basic_any::alignment, typename Type> -[[nodiscard]] basic_any forward_as_any(Type &&value) { - return basic_any{stl::in_place_type, stl::forward(value)}; -} - -} // namespace entt - -#endif diff --git a/include/entt/core/bit.hpp b/include/entt/core/bit.hpp deleted file mode 100644 index d0698f2..0000000 --- a/include/entt/core/bit.hpp +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef ENTT_CORE_BIT_HPP -#define ENTT_CORE_BIT_HPP - -#include "../config/config.h" -#include "../stl/bit.hpp" -#include "../stl/concepts.hpp" -#include "../stl/cstddef.hpp" - -namespace entt { - -/** - * @brief Fast module utility function (powers of two only). - * @tparam Type Unsigned integer type. - * @param value A value of unsigned integer type. - * @param mod _Modulus_, it must be a power of two. - * @return The common remainder. - */ -template -[[nodiscard]] constexpr Type fast_mod(const Type value, const stl::size_t mod) noexcept { - ENTT_ASSERT_CONSTEXPR(stl::has_single_bit(mod), "Value must be a power of two"); - return static_cast(value & (mod - 1u)); -} - -} // namespace entt - -#endif diff --git a/include/entt/core/compressed_pair.hpp b/include/entt/core/compressed_pair.hpp deleted file mode 100644 index 9f45225..0000000 --- a/include/entt/core/compressed_pair.hpp +++ /dev/null @@ -1,266 +0,0 @@ -#ifndef ENTT_CORE_COMPRESSED_PAIR_HPP -#define ENTT_CORE_COMPRESSED_PAIR_HPP - -#include "../stl/concepts.hpp" -#include "../stl/cstddef.hpp" -#include "../stl/tuple.hpp" -#include "../stl/type_traits.hpp" -#include "../stl/utility.hpp" -#include "fwd.hpp" -#include "type_traits.hpp" - -namespace entt { - -/*! @cond ENTT_INTERNAL */ -namespace internal { - -template -struct compressed_pair_element { - using reference = Type &; - using const_reference = const Type &; - - // NOLINTNEXTLINE(modernize-use-equals-default) - constexpr compressed_pair_element() noexcept(stl::is_nothrow_default_constructible_v) - requires stl::default_initializable {} - - template - constexpr compressed_pair_element(Arg &&arg) noexcept(stl::is_nothrow_constructible_v) - requires (!stl::same_as, compressed_pair_element>) - : value{stl::forward(arg)} {} - - template - constexpr compressed_pair_element(stl::tuple args, stl::index_sequence) noexcept(stl::is_nothrow_constructible_v) - : value{stl::forward(stl::get(args))...} {} - - [[nodiscard]] constexpr reference get() noexcept { - return value; - } - - [[nodiscard]] constexpr const_reference get() const noexcept { - return value; - } - -private: - Type value{}; -}; - -template -requires is_ebco_eligible_v -struct compressed_pair_element: Type { - using reference = Type &; - using const_reference = const Type &; - using base_type = Type; - - constexpr compressed_pair_element() noexcept(stl::is_nothrow_default_constructible_v) - requires stl::default_initializable - : base_type{} {} - - template - constexpr compressed_pair_element(Arg &&arg) noexcept(stl::is_nothrow_constructible_v) - requires (!stl::same_as, compressed_pair_element>) - : base_type{stl::forward(arg)} {} - - template - constexpr compressed_pair_element(stl::tuple args, stl::index_sequence) noexcept(stl::is_nothrow_constructible_v) - : base_type{stl::forward(stl::get(args))...} {} - - [[nodiscard]] constexpr reference get() noexcept { - return *this; - } - - [[nodiscard]] constexpr const_reference get() const noexcept { - return *this; - } -}; - -} // namespace internal -/*! @endcond */ - -/** - * @brief A compressed pair. - * - * A pair that exploits the _Empty Base Class Optimization_ (or _EBCO_) to - * reduce its final size to a minimum. - * - * @tparam First The type of the first element that the pair stores. - * @tparam Second The type of the second element that the pair stores. - */ -template -class compressed_pair final - : internal::compressed_pair_element, - internal::compressed_pair_element { - using first_base = internal::compressed_pair_element; - using second_base = internal::compressed_pair_element; - -public: - /*! @brief The type of the first element that the pair stores. */ - using first_type = First; - /*! @brief The type of the second element that the pair stores. */ - using second_type = Second; - - /** - * @brief Default constructor, conditionally enabled. - * - * This constructor is only available when the types that the pair stores - * are both at least default constructible. - */ - constexpr compressed_pair() noexcept(stl::is_nothrow_default_constructible_v && stl::is_nothrow_default_constructible_v) - requires stl::default_initializable && stl::default_initializable - : first_base{}, - second_base{} {} - - /** - * @brief Copy constructor. - * @param other The instance to copy from. - */ - constexpr compressed_pair(const compressed_pair &other) = default; - - /** - * @brief Move constructor. - * @param other The instance to move from. - */ - constexpr compressed_pair(compressed_pair &&other) noexcept = default; - - /** - * @brief Constructs a pair from its values. - * @tparam Arg Type of value to use to initialize the first element. - * @tparam Other Type of value to use to initialize the second element. - * @param arg Value to use to initialize the first element. - * @param other Value to use to initialize the second element. - */ - template - constexpr compressed_pair(Arg &&arg, Other &&other) noexcept(stl::is_nothrow_constructible_v && stl::is_nothrow_constructible_v) - : first_base{stl::forward(arg)}, - second_base{stl::forward(other)} {} - - /** - * @brief Constructs a pair by forwarding the arguments to its parts. - * @tparam Args Types of arguments to use to initialize the first element. - * @tparam Other Types of arguments to use to initialize the second element. - * @param args Arguments to use to initialize the first element. - * @param other Arguments to use to initialize the second element. - */ - template - constexpr compressed_pair(stl::piecewise_construct_t, stl::tuple args, stl::tuple other) noexcept(stl::is_nothrow_constructible_v && stl::is_nothrow_constructible_v) - : first_base{stl::move(args), stl::index_sequence_for{}}, - second_base{stl::move(other), stl::index_sequence_for{}} {} - - /*! @brief Default destructor. */ - ~compressed_pair() = default; - - /** - * @brief Copy assignment operator. - * @param other The instance to copy from. - * @return This compressed pair object. - */ - constexpr compressed_pair &operator=(const compressed_pair &other) = default; - - /** - * @brief Move assignment operator. - * @param other The instance to move from. - * @return This compressed pair object. - */ - constexpr compressed_pair &operator=(compressed_pair &&other) noexcept = default; - - /** - * @brief Returns the first element that a pair stores. - * @return The first element that a pair stores. - */ - [[nodiscard]] constexpr first_type &first() noexcept { - return static_cast(*this).get(); - } - - /*! @copydoc first */ - [[nodiscard]] constexpr const first_type &first() const noexcept { - return static_cast(*this).get(); - } - - /** - * @brief Returns the second element that a pair stores. - * @return The second element that a pair stores. - */ - [[nodiscard]] constexpr second_type &second() noexcept { - return static_cast(*this).get(); - } - - /*! @copydoc second */ - [[nodiscard]] constexpr const second_type &second() const noexcept { - return static_cast(*this).get(); - } - - /** - * @brief Swaps two compressed pair objects. - * @param other The compressed pair to swap with. - */ - constexpr void swap(compressed_pair &other) noexcept { - using stl::swap; - swap(first(), other.first()); - swap(second(), other.second()); - } - - /** - * @brief Extracts an element from the compressed pair. - * @tparam Index An integer value that is either 0 or 1. - * @return Returns a reference to the first element if `Index` is 0 and a - * reference to the second element if `Index` is 1. - */ - template - requires (Index <= 1u) - [[nodiscard]] constexpr decltype(auto) get() noexcept { - if constexpr(Index == 0u) { - return first(); - } else { - return second(); - } - } - - /*! @copydoc get */ - template - requires (Index <= 1u) - [[nodiscard]] constexpr decltype(auto) get() const noexcept { - if constexpr(Index == 0u) { - return first(); - } else { - return second(); - } - } -}; - -/** - * @brief Deduction guide. - * @tparam Type Type of value to use to initialize the first element. - * @tparam Other Type of value to use to initialize the second element. - */ -template -compressed_pair(Type &&, Other &&) -> compressed_pair, stl::decay_t>; - -/** - * @brief Swaps two compressed pair objects. - * @tparam First The type of the first element that the pairs store. - * @tparam Second The type of the second element that the pairs store. - * @param lhs A valid compressed pair object. - * @param rhs A valid compressed pair object. - */ -template -constexpr void swap(compressed_pair &lhs, compressed_pair &rhs) noexcept { - lhs.swap(rhs); -} - -} // namespace entt - -/*! @cond ENTT_INTERNAL */ -#include - -namespace std { - -template -struct tuple_size>: integral_constant {}; - -template -requires (Index <= 1u) -struct tuple_element>: conditional {}; - -} // namespace std -/*! @endcond */ - -#endif diff --git a/include/entt/core/concepts.hpp b/include/entt/core/concepts.hpp deleted file mode 100644 index a8bb989..0000000 --- a/include/entt/core/concepts.hpp +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef ENTT_CORE_CONCEPTS_HPP -#define ENTT_CORE_CONCEPTS_HPP - -#include "../stl/type_traits.hpp" - -namespace entt { - -/** - * @brief Specifies that a type is not a cv-qualified reference. - * @tparam Type Type to check. - */ -template -concept cvref_unqualified = stl::is_same_v, Type>; - -} // namespace entt - -#endif diff --git a/include/entt/core/enum.hpp b/include/entt/core/enum.hpp deleted file mode 100644 index ed1b093..0000000 --- a/include/entt/core/enum.hpp +++ /dev/null @@ -1,102 +0,0 @@ -#ifndef ENTT_CORE_ENUM_HPP -#define ENTT_CORE_ENUM_HPP - -#include "../stl/concepts.hpp" -#include "../stl/type_traits.hpp" - -namespace entt { - -/** - * @brief Enable bitmask support for enum classes. - * @tparam Type The enum type for which to enable bitmask support. - */ -template -struct enum_as_bitmask: stl::false_type {}; - -/*! @copydoc enum_as_bitmask */ -template -requires requires { - requires stl::is_enum_v; - { Type::_entt_enum_as_bitmask } -> stl::same_as; -} -struct enum_as_bitmask: stl::true_type {}; - -/** - * @brief Helper variable template. - * @tparam Type The enum class type for which to enable bitmask support. - */ -template -inline constexpr bool enum_as_bitmask_v = enum_as_bitmask::value; - -/** - * @brief Specifies that an enum class supports bitmask operations. - * @tparam Type Enum class type. - */ -template -// check again that it is an enum to deal with incorrect specializations -concept enum_bitmask = stl::is_enum_v && enum_as_bitmask_v; - -} // namespace entt - -/** - * @brief Operator available for enums for which bitmask support is enabled. - * @tparam Type Enum class type. - * @param lhs The first value to use. - * @param rhs The second value to use. - * @return The result of invoking the operator on the underlying types of the - * two values provided. - */ -template -[[nodiscard]] constexpr Type operator|(const Type lhs, const Type rhs) noexcept { - return static_cast(static_cast>(lhs) | static_cast>(rhs)); -} - -/*! @copydoc operator| */ -template -[[nodiscard]] constexpr Type operator&(const Type lhs, const Type rhs) noexcept { - return static_cast(static_cast>(lhs) & static_cast>(rhs)); -} - -/*! @copydoc operator| */ -template -[[nodiscard]] constexpr Type operator^(const Type lhs, const Type rhs) noexcept { - return static_cast(static_cast>(lhs) ^ static_cast>(rhs)); -} - -/** - * @brief Operator available for enums for which bitmask support is enabled. - * @tparam Type Enum class type. - * @param value The value to use. - * @return The result of invoking the operator on the underlying types of the - * value provided. - */ -template -[[nodiscard]] constexpr Type operator~(const Type value) noexcept { - return static_cast(~static_cast>(value)); -} - -/*! @copydoc operator~ */ -template -[[nodiscard]] constexpr bool operator!(const Type value) noexcept { - return !static_cast>(value); -} - -/*! @copydoc operator| */ -template -constexpr Type &operator|=(Type &lhs, const Type rhs) noexcept { - return (lhs = (lhs | rhs)); -} - -/*! @copydoc operator| */ -template -constexpr Type &operator&=(Type &lhs, const Type rhs) noexcept { - return (lhs = (lhs & rhs)); -} - -/*! @copydoc operator| */ -template -constexpr Type &operator^=(Type &lhs, const Type rhs) noexcept { - return (lhs = (lhs ^ rhs)); -} - -#endif diff --git a/include/entt/core/family.hpp b/include/entt/core/family.hpp deleted file mode 100644 index 953c12d..0000000 --- a/include/entt/core/family.hpp +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef ENTT_CORE_FAMILY_HPP -#define ENTT_CORE_FAMILY_HPP - -#include "../config/config.h" -#include "fwd.hpp" - -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 auto identifier() noexcept { - static ENTT_MAYBE_ATOMIC(id_type) value{}; - return value++; - } - -public: - /*! @brief Unsigned integer type. */ - using value_type = id_type; - - /*! @brief Statically generated unique identifier for the given type. */ - template - // at the time I'm writing, clang crashes during compilation if auto is used instead of value_type - inline static const value_type value = identifier(); -}; - -} // namespace entt - -#endif diff --git a/include/entt/core/fwd.hpp b/include/entt/core/fwd.hpp deleted file mode 100644 index c454e8e..0000000 --- a/include/entt/core/fwd.hpp +++ /dev/null @@ -1,51 +0,0 @@ -#ifndef ENTT_CORE_FWD_HPP -#define ENTT_CORE_FWD_HPP - -#include "../config/config.h" -#include "../stl/cstddef.hpp" -#include "../stl/cstdint.hpp" - -namespace entt { - -/*! @brief Possible modes of an any object. */ -enum class any_policy : stl::uint8_t { - /*! @brief Default mode, no element available. */ - empty, - /*! @brief Owning mode, dynamically allocated element. */ - dynamic, - /*! @brief Owning mode, embedded element. */ - embedded, - /*! @brief Aliasing mode, non-const reference. */ - ref, - /*! @brief Const aliasing mode, const reference. */ - cref -}; - -// NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays, modernize-avoid-c-arrays) -template -class basic_any; - -/*! @brief Alias declaration for type identifiers. */ -using id_type = ENTT_ID_TYPE; - -/*! @brief Alias declaration for the most common use case. */ -using any = basic_any<>; - -template -class compressed_pair; - -template -class basic_hashed_string; - -/*! @brief Aliases for common character types. */ -using hashed_string = basic_hashed_string; - -/*! @brief Aliases for common character types. */ -using hashed_wstring = basic_hashed_string; - -// NOLINTNEXTLINE(bugprone-forward-declaration-namespace) -struct type_info; - -} // namespace entt - -#endif diff --git a/include/entt/core/hashed_string.hpp b/include/entt/core/hashed_string.hpp deleted file mode 100644 index f3398af..0000000 --- a/include/entt/core/hashed_string.hpp +++ /dev/null @@ -1,260 +0,0 @@ -#ifndef ENTT_CORE_HASHED_STRING_HPP -#define ENTT_CORE_HASHED_STRING_HPP - -#include "../stl/cstddef.hpp" -#include "../stl/cstdint.hpp" -#include "fwd.hpp" - -namespace entt { - -/*! @cond ENTT_INTERNAL */ -namespace internal { - -template -struct fnv_1a_params; - -template<> -struct fnv_1a_params { - static constexpr auto offset = 2166136261; - static constexpr auto prime = 16777619; -}; - -template<> -struct fnv_1a_params { - static constexpr auto offset = 14695981039346656037ull; - static constexpr auto prime = 1099511628211ull; -}; - -template -struct basic_hashed_string { - using value_type = Char; - using size_type = stl::size_t; - using hash_type = id_type; - - const value_type *repr{}; - hash_type hash{fnv_1a_params<>::offset}; - size_type length{}; -}; - -} // namespace internal -/*! @endcond */ - -/** - * @brief Zero overhead unique identifier. - * - * A hashed string is a compile-time tool that allows users to use - * human-readable identifiers 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. - * - * @warning - * This class doesn't take ownership of user-supplied strings nor does it make a - * copy of them. - * - * @tparam Char Character type. - */ -template -class basic_hashed_string: internal::basic_hashed_string { - using base_type = internal::basic_hashed_string; - using params = internal::fnv_1a_params<>; - - struct const_wrapper { - // non-explicit constructor on purpose - constexpr const_wrapper(const base_type::value_type *str) noexcept - : repr{str} {} - - const base_type::value_type *repr; - }; - -public: - /*! @brief Character type. */ - using value_type = base_type::value_type; - /*! @brief Unsigned integer type. */ - using size_type = base_type::size_type; - /*! @brief Unsigned integer type. */ - using hash_type = base_type::hash_type; - - /** - * @brief Returns directly the numeric representation of a string view. - * @param str Human-readable identifier. - * @param len Length of the string to hash. - * @return The numeric representation of the string. - */ - [[nodiscard]] static constexpr hash_type value(const value_type *str, const size_type len) noexcept { - return basic_hashed_string{str, len}; - } - - /** - * @brief Returns directly the numeric representation of a string. - * @tparam N Number of characters of the identifier. - * @param str Human-readable identifier. - * @return The numeric representation of the string. - */ - template - // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays, modernize-avoid-c-arrays) - [[nodiscard]] static ENTT_CONSTEVAL hash_type value(const value_type (&str)[N]) noexcept { - return basic_hashed_string{str}; - } - - /** - * @brief Returns directly the numeric representation of a string. - * @param wrapper Helps achieving the purpose by relying on overloading. - * @return The numeric representation of the string. - */ - [[nodiscard]] static constexpr hash_type value(const_wrapper wrapper) noexcept { - return basic_hashed_string{wrapper}; - } - - /*! @brief Constructs an empty hashed string. */ - constexpr basic_hashed_string() noexcept - : basic_hashed_string{nullptr, 0u} {} - - /** - * @brief Constructs a hashed string from a string view. - * @param str Human-readable identifier. - * @param len Length of the string to hash. - */ - constexpr basic_hashed_string(const value_type *str, const size_type len) noexcept - // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay) - : base_type{str} { - // NOLINTBEGIN(cppcoreguidelines-pro-bounds-pointer-arithmetic) - for(; base_type::length < len; ++base_type::length) { - base_type::hash = (base_type::hash ^ static_cast(str[base_type::length])) * params::prime; - } - // NOLINTEND(cppcoreguidelines-pro-bounds-pointer-arithmetic) - } - - /** - * @brief Constructs a hashed string from an array of const characters. - * @tparam N Number of characters of the identifier. - * @param str Human-readable identifier. - */ - template - // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays, modernize-avoid-c-arrays) - ENTT_CONSTEVAL basic_hashed_string(const value_type (&str)[N]) noexcept - // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-array-to-pointer-decay) - : base_type{str} { - for(; str[base_type::length]; ++base_type::length) { - base_type::hash = (base_type::hash ^ static_cast(str[base_type::length])) * params::prime; - } - } - - /** - * @brief Explicit constructor on purpose to avoid constructing a hashed - * string directly from a `const value_type *`. - * - * @warning - * The lifetime of the string is not extended nor is it copied. - * - * @param wrapper Helps achieving the purpose by relying on overloading. - */ - explicit constexpr basic_hashed_string(const_wrapper wrapper) noexcept - : base_type{wrapper.repr} { - // NOLINTBEGIN(cppcoreguidelines-pro-bounds-pointer-arithmetic) - for(; wrapper.repr[base_type::length]; ++base_type::length) { - base_type::hash = (base_type::hash ^ static_cast(wrapper.repr[base_type::length])) * params::prime; - } - // NOLINTEND(cppcoreguidelines-pro-bounds-pointer-arithmetic) - } - - /** - * @brief Returns the size of a hashed string. - * @return The size of the hashed string. - */ - [[nodiscard]] constexpr size_type size() const noexcept { - return base_type::length; - } - - /** - * @brief Returns the human-readable representation of a hashed string. - * @return The string used to initialize the hashed string. - */ - [[nodiscard]] constexpr const value_type *data() const noexcept { - return base_type::repr; - } - - /** - * @brief Returns the numeric representation of a hashed string. - * @return The numeric representation of the hashed string. - */ - [[nodiscard]] constexpr hash_type value() const noexcept { - return base_type::hash; - } - - /*! @copydoc data */ - [[nodiscard]] explicit constexpr operator const value_type *() const noexcept { - return data(); - } - - /** - * @brief Returns the numeric representation of a hashed string. - * @return The numeric representation of the hashed string. - */ - [[nodiscard]] constexpr operator hash_type() const noexcept { - return value(); - } - - /** - * @brief Compares two hashed strings. - * @param other A valid hashed string. - * @return True if the two hashed strings are identical, false otherwise. - */ - [[nodiscard]] constexpr bool operator==(const basic_hashed_string &other) const noexcept { - return value() == other.value(); - } - - /** - * @brief Lexicographically compares two hashed strings. - * @param other A valid hashed string. - * @return The relative order between the two hashed strings. - */ - [[nodiscard]] constexpr auto operator<=>(const basic_hashed_string &other) const noexcept { - return value() <=> other.value(); - } -}; - -/** - * @brief Deduction guide. - * @tparam Char Character type. - * @param str Human-readable identifier. - * @param len Length of the string to hash. - */ -template -basic_hashed_string(const Char *str, stl::size_t len) -> basic_hashed_string; - -/** - * @brief Deduction guide. - * @tparam Char Character type. - * @tparam N Number of characters of the identifier. - * @param str Human-readable identifier. - */ -template -// NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays, modernize-avoid-c-arrays) -basic_hashed_string(const Char (&str)[N]) -> basic_hashed_string; - -inline namespace literals { - -/** - * @brief User defined literal for hashed strings. - * @param str The literal without its suffix. - * @return A properly initialized hashed string. - */ -[[nodiscard]] ENTT_CONSTEVAL hashed_string operator""_hs(const char *str, stl::size_t) noexcept { - return hashed_string{str}; -} - -/** - * @brief User defined literal for hashed wstrings. - * @param str The literal without its suffix. - * @return A properly initialized hashed wstring. - */ -[[nodiscard]] ENTT_CONSTEVAL hashed_wstring operator""_hws(const wchar_t *str, stl::size_t) noexcept { - return hashed_wstring{str}; -} - -} // namespace literals - -} // namespace entt - -#endif diff --git a/include/entt/core/ident.hpp b/include/entt/core/ident.hpp deleted file mode 100644 index 3413393..0000000 --- a/include/entt/core/ident.hpp +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef ENTT_CORE_IDENT_HPP -#define ENTT_CORE_IDENT_HPP - -#include "../stl/cstddef.hpp" -#include "../stl/type_traits.hpp" -#include "../stl/utility.hpp" -#include "fwd.hpp" -#include "type_traits.hpp" - -namespace entt { - -/** - * @brief Type integral identifiers. - * @tparam Type List of types for which to generate identifiers. - */ -template -class ident { - template - [[nodiscard]] static ENTT_CONSTEVAL id_type get(stl::index_sequence) noexcept { - return (0 + ... + (stl::is_same_v...>>> ? id_type{Index} : id_type{})); - } - -public: - /*! @brief Unsigned integer type. */ - using value_type = id_type; - - /*! @brief Statically generated unique identifier for the given type. */ - template - requires (stl::is_same_v, Type> || ...) - static constexpr value_type value = get>(stl::index_sequence_for{}); -}; - -} // namespace entt - -#endif diff --git a/include/entt/core/iterator.hpp b/include/entt/core/iterator.hpp deleted file mode 100644 index f389e23..0000000 --- a/include/entt/core/iterator.hpp +++ /dev/null @@ -1,181 +0,0 @@ -#ifndef ENTT_CORE_ITERATOR_HPP -#define ENTT_CORE_ITERATOR_HPP - -#include "../stl/concepts.hpp" -#include "../stl/cstddef.hpp" -#include "../stl/iterator.hpp" -#include "../stl/memory.hpp" -#include "../stl/type_traits.hpp" -#include "../stl/utility.hpp" - -namespace entt { - -/** - * @brief Helper type to use as pointer with input iterators. - * @tparam Type of wrapped value. - */ -template -struct input_iterator_pointer final { - /*! @brief Value type. */ - using value_type = Type; - /*! @brief Pointer type. */ - using pointer = Type *; - /*! @brief Reference type. */ - using reference = Type &; - - /** - * @brief Constructs a proxy object by move. - * @param val Value to use to initialize the proxy object. - */ - constexpr input_iterator_pointer(value_type &&val) noexcept(stl::is_nothrow_move_constructible_v) - : value{stl::move(val)} {} - - /** - * @brief Access operator for accessing wrapped values. - * @return A pointer to the wrapped value. - */ - [[nodiscard]] constexpr pointer operator->() noexcept { - return stl::addressof(value); - } - - /** - * @brief Dereference operator for accessing wrapped values. - * @return A reference to the wrapped value. - */ - [[nodiscard]] constexpr reference operator*() noexcept { - return value; - } - -private: - Type value; -}; - -/** - * @brief Plain iota iterator (waiting for C++20). - * @tparam Type Value type. - */ -template -struct iota_iterator final { - /*! @brief Value type, likely an integral one. */ - using value_type = Type; - /*! @brief Invalid pointer type. */ - using pointer = void; - /*! @brief Non-reference type, same as value type. */ - using reference = value_type; - /*! @brief Difference type. */ - using difference_type = stl::ptrdiff_t; - /*! @brief Iterator category. */ - using iterator_category = stl::input_iterator_tag; - - /*! @brief Default constructor. */ - constexpr iota_iterator() noexcept - : current{} {} - - /** - * @brief Constructs an iota iterator from a given value. - * @param init The initial value assigned to the iota iterator. - */ - constexpr iota_iterator(const value_type init) noexcept - : current{init} {} - - /** - * @brief Pre-increment operator. - * @return This iota iterator. - */ - constexpr iota_iterator &operator++() noexcept { - return ++current, *this; - } - - /** - * @brief Post-increment operator. - * @return This iota iterator. - */ - constexpr iota_iterator operator++(int) noexcept { - const iota_iterator orig = *this; - return ++(*this), orig; - } - - /** - * @brief Dereference operator. - * @return The underlying value. - */ - [[nodiscard]] constexpr reference operator*() const noexcept { - return current; - } - - /** - * @brief Comparison operator. - * @param other A properly initialized iota iterator. - * @return True if the two iterators are identical, false otherwise. - */ - [[nodiscard]] constexpr bool operator==(const iota_iterator &other) const noexcept { - return current == other.current; - } - -private: - value_type current; -}; - -/** - * @brief Utility class to create an iterable object from a pair of iterators. - * @tparam It Type of iterator. - * @tparam Sentinel Type of sentinel. - */ -template Sentinel = It> -struct iterable_adaptor final { - /*! @brief Value type. */ - using value_type = stl::iterator_traits::value_type; - /*! @brief Iterator type. */ - using iterator = It; - /*! @brief Sentinel type. */ - using sentinel = Sentinel; - - /*! @brief Default constructor. */ - constexpr iterable_adaptor() noexcept(stl::is_nothrow_default_constructible_v && stl::is_nothrow_default_constructible_v) - : first{}, - last{} {} - - /** - * @brief Creates an iterable object from a pair of iterators. - * @param from Begin iterator. - * @param to End iterator. - */ - constexpr iterable_adaptor(iterator from, sentinel to) noexcept(stl::is_nothrow_move_constructible_v && stl::is_nothrow_move_constructible_v) - : first{stl::move(from)}, - last{stl::move(to)} {} - - /** - * @brief Returns an iterator to the beginning. - * @return An iterator to the first element of the range. - */ - [[nodiscard]] constexpr iterator begin() const noexcept { - return first; - } - - /** - * @brief Returns an iterator to the end. - * @return An iterator to the element following the last element of the - * range. - */ - [[nodiscard]] constexpr sentinel end() const noexcept { - return last; - } - - /*! @copydoc begin */ - [[nodiscard]] constexpr iterator cbegin() const noexcept { - return begin(); - } - - /*! @copydoc end */ - [[nodiscard]] constexpr sentinel cend() const noexcept { - return end(); - } - -private: - It first; - Sentinel last; -}; - -} // namespace entt - -#endif diff --git a/include/entt/core/memory.hpp b/include/entt/core/memory.hpp deleted file mode 100644 index 4ec18aa..0000000 --- a/include/entt/core/memory.hpp +++ /dev/null @@ -1,225 +0,0 @@ -#ifndef ENTT_CORE_MEMORY_HPP -#define ENTT_CORE_MEMORY_HPP - -#include "../config/config.h" -#include "../stl/cstddef.hpp" -#include "../stl/memory.hpp" -#include "../stl/tuple.hpp" -#include "../stl/type_traits.hpp" -#include "../stl/utility.hpp" - -namespace entt { - -/** - * @brief Utility function to design allocation-aware containers. - * @tparam Allocator Type of allocator. - * @param lhs A valid allocator. - * @param rhs Another valid allocator. - */ -template -constexpr void propagate_on_container_copy_assignment([[maybe_unused]] Allocator &lhs, [[maybe_unused]] Allocator &rhs) noexcept { - if constexpr(stl::allocator_traits::propagate_on_container_copy_assignment::value) { - lhs = rhs; - } -} - -/** - * @brief Utility function to design allocation-aware containers. - * @tparam Allocator Type of allocator. - * @param lhs A valid allocator. - * @param rhs Another valid allocator. - */ -template -constexpr void propagate_on_container_move_assignment([[maybe_unused]] Allocator &lhs, [[maybe_unused]] Allocator &rhs) noexcept { - if constexpr(stl::allocator_traits::propagate_on_container_move_assignment::value) { - lhs = stl::move(rhs); - } -} - -/** - * @brief Utility function to design allocation-aware containers. - * @tparam Allocator Type of allocator. - * @param lhs A valid allocator. - * @param rhs Another valid allocator. - */ -template -constexpr void propagate_on_container_swap([[maybe_unused]] Allocator &lhs, [[maybe_unused]] Allocator &rhs) noexcept { - if constexpr(stl::allocator_traits::propagate_on_container_swap::value) { - using stl::swap; - swap(lhs, rhs); - } else { - ENTT_ASSERT_CONSTEXPR(lhs == rhs, "Cannot swap the containers"); - } -} - -/** - * @brief Deleter for allocator-aware unique pointers (waiting for C++20). - * @tparam Allocator Type of allocator used to manage memory and elements. - */ -template -struct allocation_deleter: private Allocator { - /*! @brief Allocator type. */ - using allocator_type = Allocator; - /*! @brief Pointer type. */ - using pointer = stl::allocator_traits::pointer; - - /** - * @brief Inherited constructors. - * @param alloc The allocator to use. - */ - constexpr allocation_deleter(const allocator_type &alloc) noexcept(stl::is_nothrow_copy_constructible_v) - : Allocator{alloc} {} - - /** - * @brief Destroys the pointed object and deallocates its memory. - * @param ptr A valid pointer to an object of the given type. - */ - constexpr void operator()(pointer ptr) noexcept(stl::is_nothrow_destructible_v) { - using alloc_traits = stl::allocator_traits; - alloc_traits::destroy(*this, stl::to_address(ptr)); - alloc_traits::deallocate(*this, ptr, 1u); - } -}; - -/** - * @brief Allows `stl::unique_ptr` to use allocators (waiting for C++20). - * @tparam Type Type of object to allocate for and to construct. - * @tparam Allocator Type of allocator used to manage memory and elements. - * @tparam Args Types of arguments to use to construct the object. - * @param allocator The allocator to use. - * @param args Parameters to use to construct the object. - * @return A properly initialized unique pointer with a custom deleter. - */ -template -constexpr auto allocate_unique(Allocator &allocator, Args &&...args) { - static_assert(!stl::is_array_v, "Array types are not supported"); - - using alloc_traits = stl::allocator_traits::template rebind_traits; - using allocator_type = alloc_traits::allocator_type; - - allocator_type alloc{allocator}; - auto ptr = alloc_traits::allocate(alloc, 1u); - - ENTT_TRY { - alloc_traits::construct(alloc, stl::to_address(ptr), stl::forward(args)...); - } - ENTT_CATCH { - alloc_traits::deallocate(alloc, ptr, 1u); - ENTT_THROW; - } - - return stl::unique_ptr>{ptr, alloc}; -} - -/*! @cond ENTT_INTERNAL */ -namespace internal { - -template -struct uses_allocator_construction { - template - static constexpr auto args([[maybe_unused]] const Allocator &allocator, Params &&...params) noexcept { - if constexpr(!stl::uses_allocator_v && stl::is_constructible_v) { - return stl::forward_as_tuple(stl::forward(params)...); - } else { - static_assert(stl::uses_allocator_v, "Ill-formed request"); - - if constexpr(stl::is_constructible_v) { - return stl::tuple{stl::allocator_arg, allocator, stl::forward(params)...}; - } else { - static_assert(stl::is_constructible_v, "Ill-formed request"); - return stl::forward_as_tuple(stl::forward(params)..., allocator); - } - } - } -}; - -template -struct uses_allocator_construction> { - using type = stl::pair; - - template - static constexpr auto args(const auto &allocator, stl::piecewise_construct_t, First &&first, Second &&second) noexcept { - return stl::make_tuple( - stl::piecewise_construct, - stl::apply([&allocator](auto &&...curr) { return uses_allocator_construction::args(allocator, stl::forward(curr)...); }, stl::forward(first)), - stl::apply([&allocator](auto &&...curr) { return uses_allocator_construction::args(allocator, stl::forward(curr)...); }, stl::forward(second))); - } - - static constexpr auto args(const auto &allocator) noexcept { - return uses_allocator_construction::args(allocator, stl::piecewise_construct, stl::tuple<>{}, stl::tuple<>{}); - } - - template - static constexpr auto args(const auto &allocator, First &&first, Second &&second) noexcept { - return uses_allocator_construction::args(allocator, stl::piecewise_construct, stl::forward_as_tuple(stl::forward(first)), stl::forward_as_tuple(stl::forward(second))); - } - - template - static constexpr auto args(const auto &allocator, const stl::pair &value) noexcept { - return uses_allocator_construction::args(allocator, stl::piecewise_construct, stl::forward_as_tuple(value.first), stl::forward_as_tuple(value.second)); - } - - template - static constexpr auto args(const auto &allocator, stl::pair &&value) noexcept { - return uses_allocator_construction::args(allocator, stl::piecewise_construct, stl::forward_as_tuple(stl::move(value.first)), stl::forward_as_tuple(stl::move(value.second))); - } -}; - -} // namespace internal -/*! @endcond */ - -/** - * @brief Uses-allocator construction utility (waiting for C++20). - * - * Primarily intended for internal use. Prepares the argument list needed to - * create an object of a given type by means of uses-allocator construction. - * - * @tparam Type Type to return arguments for. - * @tparam Args Types of arguments to use to construct the object. - * @param allocator The allocator to use. - * @param args Parameters to use to construct the object. - * @return The arguments needed to create an object of the given type. - */ -template -constexpr auto uses_allocator_construction_args(const auto &allocator, Args &&...args) noexcept { - return internal::uses_allocator_construction::args(allocator, stl::forward(args)...); -} - -/** - * @brief Uses-allocator construction utility (waiting for C++20). - * - * Primarily intended for internal use. Creates an object of a given type by - * means of uses-allocator construction. - * - * @tparam Type Type of object to create. - * @tparam Args Types of arguments to use to construct the object. - * @param allocator The allocator to use. - * @param args Parameters to use to construct the object. - * @return A newly created object of the given type. - */ -template -constexpr Type make_obj_using_allocator(const auto &allocator, Args &&...args) { - return stl::make_from_tuple(internal::uses_allocator_construction::args(allocator, stl::forward(args)...)); -} - -/** - * @brief Uses-allocator construction utility (waiting for C++20). - * - * Primarily intended for internal use. Creates an object of a given type by - * means of uses-allocator construction at an uninitialized memory location. - * - * @tparam Type Type of object to create. - * @tparam Args Types of arguments to use to construct the object. - * @param value Memory location in which to place the object. - * @param allocator The allocator to use. - * @param args Parameters to use to construct the object. - * @return A pointer to the newly created object of the given type. - */ -template -constexpr Type *uninitialized_construct_using_allocator(Type *value, const auto &allocator, Args &&...args) { - return stl::apply([value](auto &&...curr) { return ::new(value) Type(stl::forward(curr)...); }, internal::uses_allocator_construction::args(allocator, stl::forward(args)...)); -} - -} // namespace entt - -#endif diff --git a/include/entt/core/monostate.hpp b/include/entt/core/monostate.hpp deleted file mode 100644 index 4116bda..0000000 --- a/include/entt/core/monostate.hpp +++ /dev/null @@ -1,60 +0,0 @@ -#ifndef ENTT_CORE_MONOSTATE_HPP -#define ENTT_CORE_MONOSTATE_HPP - -#include "../config/config.h" -#include "fwd.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. - * @return This monostate object. - */ - template - monostate &operator=(Type val) noexcept { - value = val; - return *this; - } - - /** - * @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 noexcept { - return value; - } - -private: - template - // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) - inline static ENTT_MAYBE_ATOMIC(Type) value{}; -}; - -/** - * @brief Helper variable template. - * @tparam Value Value used to differentiate between different variables. - */ -template -// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) -inline monostate monostate_v{}; - -} // namespace entt - -#endif diff --git a/include/entt/core/ranges.hpp b/include/entt/core/ranges.hpp deleted file mode 100644 index 255d7d7..0000000 --- a/include/entt/core/ranges.hpp +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef ENTT_CORE_RANGES_HPP -#define ENTT_CORE_RANGES_HPP - -#include - -#if defined(__cpp_lib_ranges) -# include -# include "iterator.hpp" - -namespace std::ranges { - -template -inline constexpr bool enable_borrowed_range>{true}; - -template -inline constexpr bool enable_view>{true}; - -} // namespace std::ranges - -#endif - -#endif diff --git a/include/entt/core/tuple.hpp b/include/entt/core/tuple.hpp deleted file mode 100644 index fa55ad0..0000000 --- a/include/entt/core/tuple.hpp +++ /dev/null @@ -1,90 +0,0 @@ -#ifndef ENTT_CORE_TUPLE_HPP -#define ENTT_CORE_TUPLE_HPP - -#include "../stl/tuple.hpp" -#include "../stl/type_traits.hpp" -#include "../stl/utility.hpp" - -namespace entt { - -/** - * @brief Provides the member constant `value` equal to true if a given type is - * a tuple, false otherwise. - * @tparam Type The type to test. - */ -template -struct is_tuple: stl::false_type {}; - -/** - * @copybrief is_tuple - * @tparam Args Tuple template arguments. - */ -template -struct is_tuple>: stl::true_type {}; - -/** - * @brief Helper variable template. - * @tparam Type The type to test. - */ -template -inline constexpr bool is_tuple_v = is_tuple::value; - -/** - * @brief Utility function to unwrap tuples of a single element. - * @tparam Type Tuple type of any sizes. - * @param value A tuple object of the given type. - * @return The tuple itself if it contains more than one element, the first - * element otherwise. - */ -template -constexpr decltype(auto) unwrap_tuple(Type &&value) noexcept { - if constexpr(stl::tuple_size_v> == 1u) { - return stl::get<0>(stl::forward(value)); - } else { - return stl::forward(value); - } -} - -/** - * @brief Utility class to forward-and-apply tuple objects. - * @tparam Func Type of underlying invocable object. - */ -template -struct forward_apply: private Func { - /** - * @brief Constructs a forward-and-apply object. - * @tparam Args Types of arguments to use to construct the new instance. - * @param args Parameters to use to construct the instance. - */ - template - constexpr forward_apply(Args &&...args) noexcept(stl::is_nothrow_constructible_v) - : Func{stl::forward(args)...} {} - - /** - * @brief Forwards and applies the arguments with the underlying function. - * @tparam Type Tuple-like type to forward to the underlying function. - * @param args Parameters to forward to the underlying function. - * @return Return value of the underlying function, if any. - */ - template - constexpr decltype(auto) operator()(Type &&args) noexcept(noexcept(stl::apply(stl::declval(), args))) { - return stl::apply(static_cast(*this), stl::forward(args)); - } - - /*! @copydoc operator()() */ - template - constexpr decltype(auto) operator()(Type &&args) const noexcept(noexcept(stl::apply(stl::declval(), args))) { - return stl::apply(static_cast(*this), stl::forward(args)); - } -}; - -/** - * @brief Deduction guide. - * @tparam Func Type of underlying invocable object. - */ -template -forward_apply(Func) -> forward_apply>; - -} // namespace entt - -#endif diff --git a/include/entt/core/type_info.hpp b/include/entt/core/type_info.hpp deleted file mode 100644 index 1c251ab..0000000 --- a/include/entt/core/type_info.hpp +++ /dev/null @@ -1,232 +0,0 @@ -#ifndef ENTT_CORE_TYPE_INFO_HPP -#define ENTT_CORE_TYPE_INFO_HPP - -#include -#include "../config/config.h" -#include "../stl/string_view.hpp" -#include "../stl/type_traits.hpp" -#include "../stl/utility.hpp" -#include "fwd.hpp" -#include "hashed_string.hpp" - -namespace entt { - -/*! @cond ENTT_INTERNAL */ -namespace internal { - -struct ENTT_API type_index final { - [[nodiscard]] static id_type next() noexcept { - static ENTT_MAYBE_ATOMIC(id_type) value{}; - return value++; - } -}; - -template -[[nodiscard]] constexpr const char *pretty_function() noexcept { -#if defined ENTT_PRETTY_FUNCTION - return static_cast(ENTT_PRETTY_FUNCTION); -#else - return ""; -#endif -} - -template -[[nodiscard]] constexpr auto stripped_type_name() noexcept { -#if defined ENTT_PRETTY_FUNCTION - const stl::string_view full_name{pretty_function()}; - auto first = full_name.find_first_not_of(' ', full_name.find_first_of(ENTT_PRETTY_FUNCTION_PREFIX) + 1); - auto value = full_name.substr(first, full_name.find_last_of(ENTT_PRETTY_FUNCTION_SUFFIX) - first); - return value; -#else - return stl::string_view{}; -#endif -} - -template().find_first_of('.')> -[[nodiscard]] ENTT_CONSTEVAL stl::string_view type_name(int) noexcept { - constexpr auto value = stripped_type_name(); - return value; -} - -template -[[nodiscard]] stl::string_view type_name(char) noexcept { - static const auto value = stripped_type_name(); - return value; -} - -template().find_first_of('.')> -[[nodiscard]] ENTT_CONSTEVAL id_type type_hash(int) noexcept { - constexpr auto stripped = stripped_type_name(); - constexpr auto value = hashed_string::value(stripped.data(), stripped.size()); - return value; -} - -template -[[nodiscard]] id_type type_hash(char) noexcept { - static const auto value = [](const auto stripped) { - return hashed_string::value(stripped.data(), stripped.size()); - }(stripped_type_name()); - return value; -} - -} // namespace internal -/*! @endcond */ - -/** - * @brief Type sequential identifier. - * @tparam Type Type for which to generate a sequential identifier. - */ -template -struct ENTT_API type_index final { - /** - * @brief Returns the sequential identifier of a given type. - * @return The sequential identifier of a given type. - */ - [[nodiscard]] static id_type value() noexcept { - static const id_type value = internal::type_index::next(); - return value; - } - - /*! @copydoc value */ - [[nodiscard]] constexpr operator id_type() const noexcept { - return value(); - } -}; - -/** - * @brief Type hash. - * @tparam Type Type for which to generate a hash value. - */ -template -struct type_hash final { - /** - * @brief Returns the numeric representation of a given type. - * @return The numeric representation of the given type. - */ -#if defined ENTT_PRETTY_FUNCTION - [[nodiscard]] static constexpr id_type value() noexcept { - return internal::type_hash(0); -#else - [[nodiscard]] static constexpr id_type value() noexcept { - return type_index::value(); -#endif - } - - /*! @copydoc value */ - [[nodiscard]] constexpr operator id_type() const noexcept { - return value(); - } -}; - -/** - * @brief Type name. - * @tparam Type Type for which to generate a name. - */ -template -struct type_name final { - /** - * @brief Returns the name of a given type. - * @return The name of the given type. - */ - [[nodiscard]] static constexpr stl::string_view value() noexcept { - return internal::type_name(0); - } - - /*! @copydoc value */ - [[nodiscard]] constexpr operator stl::string_view() const noexcept { - return value(); - } -}; - -/*! @brief Implementation specific information about a type. */ -struct type_info final { - /** - * @brief Constructs a type info object for a given type. - * @tparam Type Type for which to construct a type info object. - */ - template - // NOLINTBEGIN(modernize-use-transparent-functors) - constexpr type_info(stl::in_place_type_t) noexcept - : seq{type_index>::value()}, - identifier{type_hash>::value()}, - alias{type_name>::value()} {} - // NOLINTEND(modernize-use-transparent-functors) - - /** - * @brief Type index. - * @return Type index. - */ - [[nodiscard]] constexpr id_type index() const noexcept { - return seq; - } - - /** - * @brief Type hash. - * @return Type hash. - */ - [[nodiscard]] constexpr id_type hash() const noexcept { - return identifier; - } - - /** - * @brief Type name. - * @return Type name. - */ - [[nodiscard]] constexpr stl::string_view name() const noexcept { - return alias; - } - - /** - * @brief Compares two type info objects. - * @param other A type info object. - * @return True if the two type info objects are identical, false otherwise. - */ - [[nodiscard]] constexpr bool operator==(const type_info &other) const noexcept { - return identifier == other.identifier; - } - - /** - * @brief Lexicographically compares two type info objects. - * @param other A type info object. - * @return The relative order between the two type info objects. - */ - [[nodiscard]] constexpr auto operator<=>(const type_info &other) const noexcept { - return seq <=> other.seq; - } - -private: - id_type seq; - id_type identifier; - stl::string_view alias; -}; - -/** - * @brief Returns the type info object associated to a given type. - * - * The returned element refers to an object with static storage duration.
- * The type doesn't need to be a complete type. If the type is a reference, the - * result refers to the referenced type. In all cases, top-level cv-qualifiers - * are ignored. - * - * @tparam Type Type for which to generate a type info object. - * @return A reference to a properly initialized type info object. - */ -template -[[nodiscard]] const type_info &type_id() noexcept { - if constexpr(stl::is_same_v>) { - static const type_info instance{stl::in_place_type}; - return instance; - } else { - return type_id>(); - } -} - -/*! @copydoc type_id */ -template -[[nodiscard]] const type_info &type_id(const Type &) noexcept { - return type_id>(); -} - -} // namespace entt - -#endif diff --git a/include/entt/core/type_traits.hpp b/include/entt/core/type_traits.hpp deleted file mode 100644 index 2c63a61..0000000 --- a/include/entt/core/type_traits.hpp +++ /dev/null @@ -1,909 +0,0 @@ -#ifndef ENTT_CORE_TYPE_TRAITS_HPP -#define ENTT_CORE_TYPE_TRAITS_HPP - -#include "../config/config.h" -#include "../stl/concepts.hpp" -#include "../stl/cstddef.hpp" -#include "../stl/iterator.hpp" -#include "../stl/tuple.hpp" -#include "../stl/type_traits.hpp" -#include "../stl/utility.hpp" -#include "fwd.hpp" - -namespace entt { - -/** - * @brief Utility class to disambiguate overloaded functions. - * @tparam N Number of choices available. - */ -template -struct choice_t - // unfortunately, doxygen cannot parse such a construct - : /*! @cond ENTT_INTERNAL */ choice_t /*! @endcond */ -{}; - -/*! @copybrief choice_t */ -template<> -struct choice_t<0> {}; - -/** - * @brief Variable template for the choice trick. - * @tparam N Number of choices available. - */ -template -inline constexpr choice_t choice{}; - -/** - * @brief A type-only `sizeof` wrapper that returns 0 where `sizeof` complains. - * @tparam Type The type of which to return the size. - */ -template -struct size_of: stl::integral_constant {}; - -/*! @copydoc size_of */ -template -requires requires { sizeof(Type); } -struct size_of - // NOLINTNEXTLINE(bugprone-sizeof-expression) - : stl::integral_constant {}; - -/** - * @brief Helper variable template. - * @tparam Type The type of which to return the size. - */ -template -inline constexpr stl::size_t size_of_v = size_of::value; - -/** - * @brief Using declaration to be used to _repeat_ the same type a number of - * times equal to the size of a given parameter pack. - * @tparam Type A type to repeat. - */ -template -using unpack_as_type = Type; - -/** - * @brief Helper variable template to be used to _repeat_ the same value a - * number of times equal to the size of a given parameter pack. - * @tparam Value A value to repeat. - */ -template -inline constexpr auto unpack_as_value = Value; - -/** - * @brief Wraps a static constant. - * @tparam Value A static constant. - */ -template -using integral_constant = stl::integral_constant; - -/** - * @brief Alias template to facilitate the creation of named values. - * @tparam Value A constant value at least convertible to `id_type`. - */ -template -using tag = integral_constant; - -/** - * @brief A class to use to push around lists of types, nothing more. - * @tparam Type Types provided by the type list. - */ -template -struct type_list { - /*! @brief Type list type. */ - using type = type_list; - /*! @brief Compile-time number of elements in the type list. */ - static constexpr auto size = sizeof...(Type); -}; - -/*! @brief Primary template isn't defined on purpose. */ -template -struct type_list_element; - -/** - * @brief Provides compile-time indexed access to the types of a type list. - * @tparam Index Index of the type to return. - * @tparam First First type provided by the type list. - * @tparam Other Other types provided by the type list. - */ -template -struct type_list_element> - : type_list_element> {}; - -/** - * @brief Provides compile-time indexed access to the types of a type list. - * @tparam First First type provided by the type list. - * @tparam Other Other types provided by the type list. - */ -template -struct type_list_element<0u, type_list> { - /*! @brief Searched type. */ - using type = First; -}; - -/** - * @brief Helper type. - * @tparam Index Index of the type to return. - * @tparam List Type list to search into. - */ -template -using type_list_element_t = type_list_element::type; - -/*! @brief Primary template isn't defined on purpose. */ -template -struct type_list_index; - -/** - * @brief Provides compile-time type access to the types of a type list. - * @tparam Type Type to look for and for which to return the index. - * @tparam First First type provided by the type list. - * @tparam Other Other types provided by the type list. - */ -template -struct type_list_index> { - /*! @brief Unsigned integer type. */ - using value_type = stl::size_t; - /*! @brief Compile-time position of the given type in the sublist. */ - static constexpr value_type value = 1u + type_list_index>::value; -}; - -/** - * @brief Provides compile-time type access to the types of a type list. - * @tparam Type Type to look for and for which to return the index. - * @tparam Other Other types provided by the type list. - */ -template -requires (type_list_index>::value == sizeof...(Other)) -struct type_list_index> { - /*! @brief Unsigned integer type. */ - using value_type = stl::size_t; - /*! @brief Compile-time position of the given type in the sublist. */ - static constexpr value_type value = 0u; -}; - -/** - * @brief Provides compile-time type access to the types of a type list. - * @tparam Type Type to look for and for which to return the index. - */ -template -struct type_list_index> { - /*! @brief Unsigned integer type. */ - using value_type = stl::size_t; - /*! @brief Compile-time position of the given type in the sublist. */ - static constexpr value_type value = 0u; -}; - -/** - * @brief Helper variable template. - * @tparam List Type list. - * @tparam Type Type to look for and for which to return the index. - */ -template -inline constexpr stl::size_t type_list_index_v = type_list_index::value; - -/** - * @brief Concatenates multiple type lists. - * @tparam Type Types provided by the first type list. - * @tparam Other Types provided by the second type list. - * @return A type list composed by the types of both the type lists. - */ -template -ENTT_CONSTEVAL type_list operator+(type_list, type_list) { - return {}; -} - -/*! @brief Primary template isn't defined on purpose. */ -template -struct type_list_cat; - -/*! @brief Concatenates multiple type lists. */ -template<> -struct type_list_cat<> { - /*! @brief A type list composed by the types of all the type lists. */ - using type = type_list<>; -}; - -/** - * @brief Concatenates multiple type lists. - * @tparam Type Types provided by the first type list. - * @tparam Other Types provided by the second type list. - * @tparam List Other type lists, if any. - */ -template -struct type_list_cat, type_list, List...> { - /*! @brief A type list composed by the types of all the type lists. */ - using type = type_list_cat, List...>::type; -}; - -/** - * @brief Concatenates multiple type lists. - * @tparam Type Types provided by the type list. - */ -template -struct type_list_cat> { - /*! @brief A type list composed by the types of all the type lists. */ - using type = type_list; -}; - -/** - * @brief Helper type. - * @tparam List Type lists to concatenate. - */ -template -using type_list_cat_t = type_list_cat::type; - -/*! @cond ENTT_INTERNAL */ -namespace internal { - -template -struct type_list_unique; - -template -struct type_list_unique, Type...> - : stl::conditional_t<(stl::is_same_v || ...), type_list_unique, Type...>, type_list_unique, Type..., First>> {}; - -template -struct type_list_unique, Type...> { - using type = type_list; -}; - -} // namespace internal -/*! @endcond */ - -/** - * @brief Removes duplicates types from a type list. - * @tparam List Type list. - */ -template -struct type_list_unique { - /*! @brief A type list without duplicate types. */ - using type = internal::type_list_unique::type; -}; - -/** - * @brief Helper type. - * @tparam List Type list. - */ -template -using type_list_unique_t = type_list_unique::type; - -/** - * @brief Provides the member constant `value` equal to true if a type list - * contains a given type, false otherwise. - * @tparam List Type list. - * @tparam Type Type to look for. - */ -template -struct type_list_contains; - -/** - * @copybrief type_list_contains - * @tparam Type Types provided by the type list. - * @tparam Other Type to look for. - */ -template -struct type_list_contains, Other> - : stl::bool_constant<(stl::is_same_v || ...)> {}; - -/** - * @brief Helper variable template. - * @tparam List Type list. - * @tparam Type Type to look for. - */ -template -inline constexpr bool type_list_contains_v = type_list_contains::value; - -/*! @brief Primary template isn't defined on purpose. */ -template -struct type_list_diff; - -/** - * @brief Computes the difference between two type lists. - * @tparam Type Types provided by the first type list. - * @tparam Other Types provided by the second type list. - */ -template -struct type_list_diff, type_list> { - /*! @brief A type list that is the difference between the two type lists. */ - using type = type_list_cat_t, Type>, type_list<>, type_list>...>; -}; - -/** - * @brief Helper type. - * @tparam List Type lists between which to compute the difference. - */ -template -using type_list_diff_t = type_list_diff::type; - -/*! @brief Primary template isn't defined on purpose. */ -template class> -struct type_list_transform; - -/** - * @brief Applies a given _function_ to a type list and generates a new list. - * @tparam Type Types provided by the type list. - * @tparam Op Unary operation as template class with a type member named `type`. - */ -template class Op> -struct type_list_transform, Op> { - /*! @brief Resulting type list after applying the transform function. */ - // NOLINTNEXTLINE(modernize-type-traits) - using type = type_list::type...>; -}; - -/** - * @brief Helper type. - * @tparam List Type list. - * @tparam Op Unary operation as template class with a type member named `type`. - */ -template class Op> -using type_list_transform_t = type_list_transform::type; - -/** - * @brief A class to use to push around lists of constant values, nothing more. - * @tparam Value Values provided by the value list. - */ -template -struct value_list { - /*! @brief Value list type. */ - using type = value_list; - /*! @brief Compile-time number of elements in the value list. */ - static constexpr auto size = sizeof...(Value); -}; - -/*! @brief Primary template isn't defined on purpose. */ -template -struct value_list_element; - -/** - * @brief Provides compile-time indexed access to the values of a value list. - * @tparam Index Index of the value to return. - * @tparam Value First value provided by the value list. - * @tparam Other Other values provided by the value list. - */ -template -struct value_list_element> - : value_list_element> {}; - -/** - * @brief Provides compile-time indexed access to the types of a type list. - * @tparam Value First value provided by the value list. - * @tparam Other Other values provided by the value list. - */ -template -struct value_list_element<0u, value_list> { - /*! @brief Searched type. */ - using type = decltype(Value); - /*! @brief Searched value. */ - static constexpr auto value = Value; -}; - -/** - * @brief Helper type. - * @tparam Index Index of the type to return. - * @tparam List Value list to search into. - */ -template -using value_list_element_t = value_list_element::type; - -/** - * @brief Helper type. - * @tparam Index Index of the value to return. - * @tparam List Value list to search into. - */ -template -inline constexpr auto value_list_element_v = value_list_element::value; - -/*! @brief Primary template isn't defined on purpose. */ -template -struct value_list_index; - -/** - * @brief Provides compile-time type access to the values of a value list. - * @tparam Value Value to look for and for which to return the index. - * @tparam First First value provided by the value list. - * @tparam Other Other values provided by the value list. - */ -template -struct value_list_index> { - /*! @brief Unsigned integer type. */ - using value_type = stl::size_t; - /*! @brief Compile-time position of the given value in the sublist. */ - static constexpr value_type value = 1u + value_list_index>::value; -}; - -/** - * @brief Provides compile-time type access to the values of a value list. - * @tparam Value Value to look for and for which to return the index. - * @tparam Other Other values provided by the value list. - */ -template -requires (value_list_index>::value == sizeof...(Other)) -struct value_list_index> { - /*! @brief Unsigned integer type. */ - using value_type = stl::size_t; - /*! @brief Compile-time position of the given value in the sublist. */ - static constexpr value_type value = 0u; -}; - -/** - * @brief Provides compile-time type access to the values of a value list. - * @tparam Value Value to look for and for which to return the index. - */ -template -struct value_list_index> { - /*! @brief Unsigned integer type. */ - using value_type = stl::size_t; - /*! @brief Compile-time position of the given type in the sublist. */ - static constexpr value_type value = 0u; -}; - -/** - * @brief Helper variable template. - * @tparam List Value list. - * @tparam Value Value to look for and for which to return the index. - */ -template -inline constexpr stl::size_t value_list_index_v = value_list_index::value; - -/** - * @brief Concatenates multiple value lists. - * @tparam Value Values provided by the first value list. - * @tparam Other Values provided by the second value list. - * @return A value list composed by the values of both the value lists. - */ -template -ENTT_CONSTEVAL value_list operator+(value_list, value_list) { - return {}; -} - -/*! @brief Primary template isn't defined on purpose. */ -template -struct value_list_cat; - -/*! @brief Concatenates multiple value lists. */ -template<> -struct value_list_cat<> { - /*! @brief A value list composed by the values of all the value lists. */ - using type = value_list<>; -}; - -/** - * @brief Concatenates multiple value lists. - * @tparam Value Values provided by the first value list. - * @tparam Other Values provided by the second value list. - * @tparam List Other value lists, if any. - */ -template -struct value_list_cat, value_list, List...> { - /*! @brief A value list composed by the values of all the value lists. */ - using type = value_list_cat, List...>::type; -}; - -/** - * @brief Concatenates multiple value lists. - * @tparam Value Values provided by the value list. - */ -template -struct value_list_cat> { - /*! @brief A value list composed by the values of all the value lists. */ - using type = value_list; -}; - -/** - * @brief Helper type. - * @tparam List Value lists to concatenate. - */ -template -using value_list_cat_t = value_list_cat::type; - -/*! @brief Primary template isn't defined on purpose. */ -template -struct value_list_unique; - -/** - * @brief Removes duplicates values from a value list. - * @tparam Value One of the values provided by the given value list. - * @tparam Other The other values provided by the given value list. - */ -template -struct value_list_unique> { - /*! @brief A value list without duplicate types. */ - using type = stl::conditional_t< - ((Value == Other) || ...), - typename value_list_unique>::type, - value_list_cat_t, typename value_list_unique>::type>>; -}; - -/*! @brief Removes duplicates values from a value list. */ -template<> -struct value_list_unique> { - /*! @brief A value list without duplicate types. */ - using type = value_list<>; -}; - -/** - * @brief Helper type. - * @tparam Type A value list. - */ -template -using value_list_unique_t = value_list_unique::type; - -/** - * @brief Provides the member constant `value` equal to true if a value list - * contains a given value, false otherwise. - * @tparam List Value list. - * @tparam Value Value to look for. - */ -template -struct value_list_contains; - -/** - * @copybrief value_list_contains - * @tparam Value Values provided by the value list. - * @tparam Other Value to look for. - */ -template -struct value_list_contains, Other> - : stl::bool_constant<((Value == Other) || ...)> {}; - -/** - * @brief Helper variable template. - * @tparam List Value list. - * @tparam Value Value to look for. - */ -template -inline constexpr bool value_list_contains_v = value_list_contains::value; - -/*! @brief Primary template isn't defined on purpose. */ -template -struct value_list_diff; - -/** - * @brief Computes the difference between two value lists. - * @tparam Value Values provided by the first value list. - * @tparam Other Values provided by the second value list. - */ -template -struct value_list_diff, value_list> { - /*! @brief A value list that is the difference between the two lists. */ - using type = value_list_cat_t, Value>, value_list<>, value_list>...>; -}; - -/** - * @brief Helper type. - * @tparam List Value lists between which to compute the difference. - */ -template -using value_list_diff_t = value_list_diff::type; - -/*! @brief Same as stl::is_invocable, but with tuples. */ -template -struct is_applicable: stl::false_type {}; - -/** - * @copybrief is_applicable - * @tparam Func A valid function type. - * @tparam Tuple Tuple-like type. - * @tparam Args The list of arguments to use to probe the function type. - */ -template class Tuple, typename... Args> -struct is_applicable>: stl::is_invocable {}; - -/** - * @copybrief is_applicable - * @tparam Func A valid function type. - * @tparam Tuple Tuple-like type. - * @tparam Args The list of arguments to use to probe the function type. - */ -template class Tuple, typename... Args> -struct is_applicable>: stl::is_invocable {}; - -/** - * @brief Helper variable template. - * @tparam Func A valid function type. - * @tparam Args The list of arguments to use to probe the function type. - */ -template -inline constexpr bool is_applicable_v = is_applicable::value; - -/*! @brief Same as stl::is_invocable_r, but with tuples for arguments. */ -template -struct is_applicable_r: stl::false_type {}; - -/** - * @copybrief is_applicable_r - * @tparam Ret The type to which the return type of the function should be - * convertible. - * @tparam Func A valid function type. - * @tparam Args The list of arguments to use to probe the function type. - */ -template -struct is_applicable_r>: stl::is_invocable_r {}; - -/** - * @brief Helper variable template. - * @tparam Ret The type to which the return type of the function should be - * convertible. - * @tparam Func A valid function type. - * @tparam Args The list of arguments to use to probe the function type. - */ -template -inline constexpr bool is_applicable_r_v = is_applicable_r::value; - -/** - * @brief Provides the member constant `value` equal to true if a given type is - * complete, false otherwise. - * @tparam Type The type to test. - */ -template -struct is_complete: stl::false_type {}; - -/*! @copydoc is_complete */ -template -requires requires { sizeof(Type); } -struct is_complete: stl::true_type {}; - -/** - * @brief Helper variable template. - * @tparam Type The type to test. - */ -template -inline constexpr bool is_complete_v = is_complete::value; - -/** - * @brief Provides the member constant `value` equal to true if a given type is - * an iterator, false otherwise. - * @tparam Type The type to test. - */ -template -struct is_iterator: stl::false_type {}; - -/*! @cond ENTT_INTERNAL */ -namespace internal { - -template -struct has_iterator_category: stl::false_type {}; - -template -requires requires { typename stl::iterator_traits::iterator_category; } -struct has_iterator_category: stl::true_type {}; - -} // namespace internal -/*! @endcond */ - -/*! @copydoc is_iterator */ -template -requires (!stl::is_void_v>>) -struct is_iterator: internal::has_iterator_category {}; - -/** - * @brief Helper variable template. - * @tparam Type The type to test. - */ -template -inline constexpr bool is_iterator_v = is_iterator::value; - -/** - * @brief Provides the member constant `value` equal to true if a given type is - * both an empty and non-final class, false otherwise. - * @tparam Type The type to test - */ -template -struct is_ebco_eligible: stl::bool_constant && !stl::is_final_v> {}; - -/** - * @brief Helper variable template. - * @tparam Type The type to test. - */ -template -inline constexpr bool is_ebco_eligible_v = is_ebco_eligible::value; - -/** - * @brief Provides the member constant `value` equal to true if - * `Type::is_transparent` is valid and denotes a type, false otherwise. - * @tparam Type The type to test. - */ -template -struct is_transparent: stl::false_type {}; - -/*! @copydoc is_transparent */ -template -requires requires { typename Type::is_transparent; } -struct is_transparent: stl::true_type {}; - -/** - * @brief Helper variable template. - * @tparam Type The type to test. - */ -template -inline constexpr bool is_transparent_v = is_transparent::value; - -/*! @cond ENTT_INTERNAL */ -namespace internal { - -template -struct has_tuple_size_value: stl::false_type {}; - -template -requires is_complete_v> -struct has_tuple_size_value: stl::true_type {}; - -template -struct has_value_type: stl::false_type {}; - -template -requires requires { typename Type::value_type; } -struct has_value_type: stl::true_type {}; - -template -[[nodiscard]] ENTT_CONSTEVAL bool dispatch_is_equality_comparable(); - -template -[[nodiscard]] ENTT_CONSTEVAL bool unpack_maybe_equality_comparable(stl::index_sequence) { - return (dispatch_is_equality_comparable>() && ...); -} - -template -[[nodiscard]] ENTT_CONSTEVAL bool maybe_equality_comparable(char) { - return false; -} - -template -[[nodiscard]] ENTT_CONSTEVAL auto maybe_equality_comparable(int) -> decltype(stl::declval() == stl::declval()) { - return true; -} - -template -[[nodiscard]] ENTT_CONSTEVAL bool dispatch_is_equality_comparable() { - // NOLINTBEGIN(modernize-use-transparent-functors) - if constexpr(stl::is_array_v) { - return false; - } else if constexpr(is_complete_v>>) { - if constexpr(has_tuple_size_value::value) { - return maybe_equality_comparable(0) && unpack_maybe_equality_comparable(stl::make_index_sequence::value>{}); - } else { - return maybe_equality_comparable(0); - } - } else if constexpr(has_value_type::value) { - if constexpr(is_iterator_v || stl::is_same_v || dispatch_is_equality_comparable()) { - return maybe_equality_comparable(0); - } else { - return false; - } - } else { - return maybe_equality_comparable(0); - } - // NOLINTEND(modernize-use-transparent-functors) -} - -} // namespace internal -/*! @endcond */ - -/** - * @brief Provides the member constant `value` equal to true if a given type is - * equality comparable, false otherwise. - * @tparam Type The type to test. - */ -template -struct is_equality_comparable: stl::bool_constant()> {}; - -/*! @copydoc is_equality_comparable */ -template -struct is_equality_comparable: is_equality_comparable {}; - -/** - * @brief Helper variable template. - * @tparam Type The type to test. - */ -template -inline constexpr bool is_equality_comparable_v = is_equality_comparable::value; - -/** - * @brief Transcribes the constness of a type to another type. - * @tparam To The type to which to transcribe the constness. - * @tparam From The type from which to transcribe the constness. - */ -template -struct constness_as { - /*! @brief The type resulting from the transcription of the constness. */ - using type = stl::remove_const_t; -}; - -/*! @copydoc constness_as */ -template -struct constness_as { - /*! @brief The type resulting from the transcription of the constness. */ - using type = const To; -}; - -/** - * @brief Alias template to facilitate the transcription of the constness. - * @tparam To The type to which to transcribe the constness. - * @tparam From The type from which to transcribe the constness. - */ -template -using constness_as_t = constness_as::type; - -/*! @brief Primary template isn't defined on purpose. */ -template -class member_class; - -/** - * @brief Extracts the class of a non-static member object or function. - * @tparam Member A pointer to a non-static member object or function. - */ -template -requires stl::is_member_pointer_v -class member_class { - template - static Class *clazz(Ret (Class::*)(Args...)); - - template - static Class *clazz(Ret (Class::*)(Args...) const); - - template - static Class *clazz(Type Class::*); - -public: - /*! @brief The class of the given non-static member object or function. */ - using type = stl::remove_pointer_t()))>; -}; - -/** - * @brief Helper type. - * @tparam Member A pointer to a non-static member object or function. - */ -template -using member_class_t = member_class::type; - -/** - * @brief Extracts the n-th argument of a _callable_ type. - * @tparam Index The index of the argument to extract. - * @tparam Candidate A valid _callable_ type. - */ -template -class nth_argument { - template - static ENTT_CONSTEVAL type_list pick_up(Ret (*)(Args...)); - - template - static ENTT_CONSTEVAL type_list pick_up(Ret (Class ::*)(Args...)); - - template - static ENTT_CONSTEVAL type_list pick_up(Ret (Class ::*)(Args...) const); - - template - static ENTT_CONSTEVAL type_list pick_up(Type Class ::*); - - template - static ENTT_CONSTEVAL decltype(pick_up(&Type::operator())) pick_up(Type &&); - -public: - /*! @brief N-th argument of the _callable_ type. */ - using type = type_list_element_t()))>; -}; - -/** - * @brief Helper type. - * @tparam Index The index of the argument to extract. - * @tparam Candidate A valid function, member function or data member type. - */ -template -using nth_argument_t = nth_argument::type; - -} // namespace entt - -template -struct entt::stl::tuple_size>: entt::stl::integral_constant::size> {}; - -template -struct entt::stl::tuple_element>: entt::type_list_element> {}; - -template -struct entt::stl::tuple_size>: entt::stl::integral_constant::size> {}; - -template -struct entt::stl::tuple_element>: entt::value_list_element> {}; - -#endif diff --git a/include/entt/core/utility.hpp b/include/entt/core/utility.hpp deleted file mode 100644 index b7e50c4..0000000 --- a/include/entt/core/utility.hpp +++ /dev/null @@ -1,84 +0,0 @@ -#ifndef ENTT_CORE_UTILITY_HPP -#define ENTT_CORE_UTILITY_HPP - -#include "../stl/type_traits.hpp" -#include "../stl/utility.hpp" - -namespace entt { - -/** - * @brief Constant utility to disambiguate overloaded members of a class. - * @tparam Type Type of the desired overload. - * @tparam Class Type of class to which the member belongs. - * @param member A valid pointer to a member. - * @return Pointer to the member. - */ -template -[[nodiscard]] constexpr auto overload(Type Class::*member) noexcept { - return member; -} - -/** - * @brief Constant utility to disambiguate overloaded functions. - * @tparam Func Function type of the desired overload. - * @param func A valid pointer to a function. - * @return Pointer to the function. - */ -template -[[nodiscard]] constexpr auto overload(Func *func) noexcept { - return func; -} - -/** - * @brief Helper type for visitors. - * @tparam Func Types of function objects. - */ -template -struct overloaded: Func... { - using Func::operator()...; -}; - -/** - * @brief Deduction guide. - * @tparam Func Types of function objects. - */ -template -overloaded(Func...) -> overloaded; - -/** - * @brief Basic implementation of a y-combinator. - * @tparam Func Type of a potentially recursive function. - */ -template -struct y_combinator { - /** - * @brief Constructs a y-combinator from a given function. - * @param recursive A potentially recursive function. - */ - constexpr y_combinator(Func recursive) noexcept(stl::is_nothrow_move_constructible_v) - : func{stl::move(recursive)} {} - - /** - * @brief Invokes a y-combinator and therefore its underlying function. - * @tparam Args Types of arguments to use to invoke the underlying function. - * @param args Parameters to use to invoke the underlying function. - * @return Return value of the underlying function, if any. - */ - template - constexpr decltype(auto) operator()(Args &&...args) const noexcept(stl::is_nothrow_invocable_v) { - return func(*this, stl::forward(args)...); - } - - /*! @copydoc operator()() */ - template - constexpr decltype(auto) operator()(Args &&...args) noexcept(stl::is_nothrow_invocable_v) { - return func(*this, stl::forward(args)...); - } - -private: - Func func; -}; - -} // namespace entt - -#endif diff --git a/include/entt/entity/component.hpp b/include/entt/entity/component.hpp deleted file mode 100644 index 6730fc3..0000000 --- a/include/entt/entity/component.hpp +++ /dev/null @@ -1,59 +0,0 @@ -#ifndef ENTT_ENTITY_COMPONENT_HPP -#define ENTT_ENTITY_COMPONENT_HPP - -#include "../config/config.h" -#include "../core/concepts.hpp" -#include "../stl/concepts.hpp" -#include "../stl/cstddef.hpp" -#include "../stl/type_traits.hpp" -#include "fwd.hpp" - -namespace entt { - -/*! @cond ENTT_INTERNAL */ -namespace internal { - -template -struct in_place_delete: stl::bool_constant && stl::is_move_assignable_v)> {}; - -template<> -struct in_place_delete: stl::false_type {}; - -template -requires Type::in_place_delete -struct in_place_delete: stl::true_type {}; - -template -struct page_size: stl::integral_constant * ENTT_PACKED_PAGE> {}; - -template<> -struct page_size: stl::integral_constant {}; - -template -requires stl::is_convertible_v -struct page_size: stl::integral_constant {}; - -} // namespace internal -/*! @endcond */ - -/** - * @brief Common way to access various properties of components. - * @tparam Type Element type. - * @tparam Entity A valid entity type. - */ -template -struct component_traits { - /*! @brief Element type. */ - using element_type = Type; - /*! @brief Underlying entity identifier. */ - using entity_type = Entity; - - /*! @brief Pointer stability, default is `false`. */ - static constexpr bool in_place_delete = internal::in_place_delete::value; - /*! @brief Page size, default is `ENTT_PACKED_PAGE` for non-empty types. */ - static constexpr stl::size_t page_size = internal::page_size::value; -}; - -} // namespace entt - -#endif diff --git a/include/entt/entity/entity.hpp b/include/entt/entity/entity.hpp deleted file mode 100644 index 111574a..0000000 --- a/include/entt/entity/entity.hpp +++ /dev/null @@ -1,312 +0,0 @@ -#ifndef ENTT_ENTITY_ENTITY_HPP -#define ENTT_ENTITY_ENTITY_HPP - -#include "../config/config.h" -#include "../core/bit.hpp" -#include "../stl/bit.hpp" -#include "../stl/concepts.hpp" -#include "../stl/cstddef.hpp" -#include "../stl/cstdint.hpp" -#include "../stl/type_traits.hpp" -#include "fwd.hpp" - -namespace entt { - -/*! @cond ENTT_INTERNAL */ -namespace internal { - -template -struct entt_traits; - -template -requires requires { - requires stl::is_enum_v; - typename internal::entt_traits>::value_type; -} -struct entt_traits: entt_traits> { - using value_type = Type; -}; - -template -requires requires { typename Type::entity_type; } -struct entt_traits - : entt_traits { - using value_type = Type; -}; - -template<> -struct entt_traits { - using value_type = stl::uint32_t; - - using entity_type = stl::uint32_t; - using version_type = stl::uint16_t; - - static constexpr entity_type entity_mask = 0xFFFFF; - static constexpr entity_type version_mask = 0xFFF; -}; - -template<> -struct entt_traits { - using value_type = stl::uint64_t; - - using entity_type = stl::uint64_t; - using version_type = stl::uint32_t; - - static constexpr entity_type entity_mask = 0xFFFFFFFF; - static constexpr entity_type version_mask = 0xFFFFFFFF; -}; - -} // namespace internal -/*! @endcond */ - -/** - * @brief Specifies that a type is an entity-like type. - * @tparam Type Type to check. - */ -template -concept entity_like = requires { - typename internal::entt_traits::value_type; -}; - -/** - * @brief Common basic entity traits implementation. - * @tparam Traits Actual entity traits to use. - */ -template -class basic_entt_traits { - static constexpr auto length = stl::popcount(Traits::entity_mask); - -public: - /*! @brief Value type. */ - using value_type = Traits::value_type; - /*! @brief Underlying entity type. */ - using entity_type = Traits::entity_type; - /*! @brief Underlying version type. */ - using version_type = Traits::version_type; - - /*! @brief Entity mask size. */ - static constexpr entity_type entity_mask = Traits::entity_mask; - /*! @brief Version mask size */ - static constexpr entity_type version_mask = Traits::version_mask; - - /** - * @brief Converts an entity to its underlying type. - * @param value The value to convert. - * @return The integral representation of the given value. - */ - [[nodiscard]] static constexpr entity_type to_integral(const value_type value) noexcept { - return static_cast(value); - } - - /** - * @brief Returns the entity part once converted to the underlying type. - * @param value The value to convert. - * @return The integral representation of the entity part. - */ - [[nodiscard]] static constexpr entity_type to_entity(const value_type value) noexcept { - static_assert(Traits::entity_mask && ((Traits::entity_mask & (Traits::entity_mask + 1)) == 0), "Invalid entity mask"); - return (to_integral(value) & entity_mask); - } - - /** - * @brief Returns the version part once converted to the underlying type. - * @param value The value to convert. - * @return The integral representation of the version part. - */ - [[nodiscard]] static constexpr version_type to_version(const value_type value) noexcept { - if constexpr(Traits::version_mask == 0u) { - return version_type{}; - } else { - static_assert((Traits::version_mask & (Traits::version_mask + 1)) == 0, "Invalid version mask"); - return (static_cast(to_integral(value) >> length) & version_mask); - } - } - - /** - * @brief Returns the successor of a given identifier. - * @param value The identifier of which to return the successor. - * @return The successor of the given identifier. - */ - [[nodiscard]] static constexpr value_type next(const value_type value) noexcept { - const auto vers = to_version(value) + 1; - return construct(to_integral(value), static_cast(vers + (vers == version_mask))); - } - - /** - * @brief Constructs an identifier from its parts. - * - * If the version part is not provided, a tombstone is returned.
- * If the entity part is not provided, a null identifier is returned. - * - * @param entity The entity part of the identifier. - * @param version The version part of the identifier. - * @return A properly constructed identifier. - */ - [[nodiscard]] static constexpr value_type construct(const entity_type entity, const version_type version) noexcept { - if constexpr(Traits::version_mask == 0u) { - return value_type{entity & entity_mask}; - } else { - return value_type{(entity & entity_mask) | (static_cast(version & version_mask) << length)}; - } - } - - /** - * @brief Combines two identifiers in a single one. - * - * The returned identifier is a copy of the first element except for its - * version, which is taken from the second element. - * - * @param lhs The identifier from which to take the entity part. - * @param rhs The identifier from which to take the version part. - * @return A properly constructed identifier. - */ - [[nodiscard]] static constexpr value_type combine(const entity_type lhs, const entity_type rhs) noexcept { - if constexpr(Traits::version_mask == 0u) { - return value_type{lhs & entity_mask}; - } else { - return value_type{(lhs & entity_mask) | (rhs & (version_mask << length))}; - } - } -}; - -/** - * @brief Entity traits. - * @tparam Type Type of identifier. - */ -template -struct entt_traits: basic_entt_traits> { - /*! @brief Base type. */ - using base_type = basic_entt_traits>; - /*! @brief Page size, default is `ENTT_SPARSE_PAGE`. */ - static constexpr stl::size_t page_size = ENTT_SPARSE_PAGE; -}; - -/** - * @brief Converts an entity to its underlying type. - * @tparam Entity The value type. - * @param value The value to convert. - * @return The integral representation of the given value. - */ -template -[[nodiscard]] constexpr entt_traits::entity_type to_integral(const Entity value) noexcept { - return entt_traits::to_integral(value); -} - -/** - * @brief Returns the entity part once converted to the underlying type. - * @tparam Entity The value type. - * @param value The value to convert. - * @return The integral representation of the entity part. - */ -template -[[nodiscard]] constexpr entt_traits::entity_type to_entity(const Entity value) noexcept { - return entt_traits::to_entity(value); -} - -/** - * @brief Returns the version part once converted to the underlying type. - * @tparam Entity The value type. - * @param value The value to convert. - * @return The integral representation of the version part. - */ -template -[[nodiscard]] constexpr entt_traits::version_type to_version(const Entity value) noexcept { - return entt_traits::to_version(value); -} - -/*! @brief Null object for all identifiers. */ -struct null_t { - /** - * @brief Converts the null object to identifiers of any type. - * @tparam Entity Type of identifier. - * @return The null representation for the given type. - */ - template - [[nodiscard]] constexpr operator Entity() const noexcept { - using traits_type = entt_traits; - return traits_type::construct(traits_type::entity_mask, traits_type::version_mask); - } - - /** - * @brief Compares two null objects. - * @param other A null object. - * @return True in all cases. - */ - [[nodiscard]] constexpr bool operator==([[maybe_unused]] const null_t other) const noexcept { - return true; - } - - /** - * @brief Compares a null object and an identifier of any type. - * @tparam Entity Type of identifier. - * @param entity Identifier with which to compare. - * @return False if the two elements differ, true otherwise. - */ - template - [[nodiscard]] constexpr bool operator==(const Entity entity) const noexcept { - using traits_type = entt_traits; - return traits_type::to_entity(entity) == traits_type::to_entity(*this); - } -}; - -/*! @brief Tombstone object for all identifiers. */ -struct tombstone_t { - /** - * @brief Converts the tombstone object to identifiers of any type. - * @tparam Entity Type of identifier. - * @return The tombstone representation for the given type. - */ - template - [[nodiscard]] constexpr operator Entity() const noexcept { - using traits_type = entt_traits; - return traits_type::construct(traits_type::entity_mask, traits_type::version_mask); - } - - /** - * @brief Compares two tombstone objects. - * @param other A tombstone object. - * @return True in all cases. - */ - [[nodiscard]] constexpr bool operator==([[maybe_unused]] const tombstone_t other) const noexcept { - return true; - } - - /** - * @brief Compares a tombstone object and an identifier of any type. - * @tparam Entity Type of identifier. - * @param entity Identifier with which to compare. - * @return False if the two elements differ, true otherwise. - */ - template - [[nodiscard]] constexpr bool operator==(const Entity entity) const noexcept { - using traits_type = entt_traits; - - if constexpr(traits_type::version_mask == 0u) { - return false; - } else { - return (traits_type::to_version(entity) == traits_type::to_version(*this)); - } - } -}; - -/** - * @brief Compile-time constant for null entities. - * - * There exist implicit conversions from this variable to identifiers of any - * allowed type. Similarly, there exist comparison operators between the null - * entity and any other identifier. - */ -inline constexpr null_t null{}; - -/** - * @brief Compile-time constant for tombstone entities. - * - * There exist implicit conversions from this variable to identifiers of any - * allowed type. Similarly, there exist comparison operators between the - * tombstone entity and any other identifier. - */ -inline constexpr tombstone_t tombstone{}; - -} // namespace entt - -#endif diff --git a/include/entt/entity/fwd.hpp b/include/entt/entity/fwd.hpp deleted file mode 100644 index f1d1a89..0000000 --- a/include/entt/entity/fwd.hpp +++ /dev/null @@ -1,291 +0,0 @@ -#ifndef ENTT_ENTITY_FWD_HPP -#define ENTT_ENTITY_FWD_HPP - -#include "../config/config.h" -#include "../core/concepts.hpp" -#include "../core/fwd.hpp" -#include "../core/type_traits.hpp" -#include "../stl/cstdint.hpp" -#include "../stl/memory.hpp" -#include "../stl/type_traits.hpp" - -namespace entt { - -/*! @brief Default entity identifier. */ -enum class entity : id_type {}; - -/*! @brief Storage deletion policy. */ -enum class deletion_policy : stl::uint8_t { - /*! @brief Swap-and-pop deletion policy. */ - swap_and_pop = 0u, - /*! @brief In-place deletion policy. */ - in_place = 1u, - /*! @brief Swap-only deletion policy. */ - swap_only = 2u, - /*! @brief Unspecified deletion policy. */ - unspecified = swap_and_pop -}; - -template -struct component_traits; - -template> -class basic_sparse_set; - -template> -class basic_storage; - -template -class basic_sigh_mixin; - -template -class basic_reactive_mixin; - -template> -class basic_registry; - -template -class basic_view; - -template> -class basic_runtime_view; - -template -class basic_group; - -template -class basic_organizer; - -template -class basic_handle; - -template -class basic_snapshot; - -template -class basic_snapshot_loader; - -template -class basic_continuous_loader; - -/*! @brief Alias declaration for the most common use case. */ -using sparse_set = basic_sparse_set<>; - -/** - * @brief Alias declaration for the most common use case. - * @tparam Type Element type. - */ -template -using storage = basic_storage; - -/** - * @brief Alias declaration for the most common use case. - * @tparam Type Underlying storage type. - */ -template -using sigh_mixin = basic_sigh_mixin>; - -/** - * @brief Alias declaration for the most common use case. - * @tparam Type Underlying storage type. - */ -template -using reactive_mixin = basic_reactive_mixin>; - -/*! @brief Alias declaration for the most common use case. */ -using registry = basic_registry<>; - -/*! @brief Alias declaration for the most common use case. */ -using organizer = basic_organizer; - -/*! @brief Alias declaration for the most common use case. */ -using handle = basic_handle; - -/*! @brief Alias declaration for the most common use case. */ -using const_handle = basic_handle; - -/** - * @brief Alias declaration for the most common use case. - * @tparam Args Other template parameters. - */ -template -using handle_view = basic_handle; - -/** - * @brief Alias declaration for the most common use case. - * @tparam Args Other template parameters. - */ -template -using const_handle_view = basic_handle; - -/*! @brief Alias declaration for the most common use case. */ -using snapshot = basic_snapshot; - -/*! @brief Alias declaration for the most common use case. */ -using snapshot_loader = basic_snapshot_loader; - -/*! @brief Alias declaration for the most common use case. */ -using continuous_loader = basic_continuous_loader; - -/*! @brief Alias declaration for the most common use case. */ -using runtime_view = basic_runtime_view; - -/*! @brief Alias declaration for the most common use case. */ -using const_runtime_view = basic_runtime_view; - -/** - * @brief Alias for exclusion lists. - * @tparam Type List of types. - */ -template -struct exclude_t final: type_list { - /*! @brief Default constructor. */ - explicit ENTT_CONSTEVAL exclude_t() = default; -}; - -/** - * @brief Variable template for exclusion lists. - * @tparam Type List of types. - */ -template -inline constexpr exclude_t exclude{}; - -/** - * @brief Alias for lists of observed elements. - * @tparam Type List of types. - */ -template -struct get_t final: type_list { - /*! @brief Default constructor. */ - explicit ENTT_CONSTEVAL get_t() = default; -}; - -/** - * @brief Variable template for lists of observed elements. - * @tparam Type List of types. - */ -template -inline constexpr get_t get{}; - -/** - * @brief Alias for lists of owned elements. - * @tparam Type List of types. - */ -template -struct owned_t final: type_list { - /*! @brief Default constructor. */ - explicit ENTT_CONSTEVAL owned_t() = default; -}; - -/** - * @brief Variable template for lists of owned elements. - * @tparam Type List of types. - */ -template -inline constexpr owned_t owned{}; - -/** - * @brief Applies a given _function_ to a get list and generate a new list. - * @tparam Type Types provided by the get list. - * @tparam Op Unary operation as template class with a type member named `type`. - */ -template class Op> -struct type_list_transform, Op> { - /*! @brief Resulting get list after applying the transform function. */ - using type = get_t::type...>; -}; - -/** - * @brief Applies a given _function_ to an exclude list and generate a new list. - * @tparam Type Types provided by the exclude list. - * @tparam Op Unary operation as template class with a type member named `type`. - */ -template class Op> -struct type_list_transform, Op> { - /*! @brief Resulting exclude list after applying the transform function. */ - using type = exclude_t::type...>; -}; - -/** - * @brief Applies a given _function_ to an owned list and generate a new list. - * @tparam Type Types provided by the owned list. - * @tparam Op Unary operation as template class with a type member named `type`. - */ -template class Op> -struct type_list_transform, Op> { - /*! @brief Resulting owned list after applying the transform function. */ - using type = owned_t::type...>; -}; - -/** - * @brief Provides a common way to define storage types. - * @tparam Type Storage value type. - * @tparam Entity A valid entity type. - * @tparam Allocator Type of allocator used to manage memory and elements. - */ -template> -struct storage_type { - /*! @brief Type-to-storage conversion result. */ - using type = ENTT_STORAGE(sigh_mixin, basic_storage); -}; - -/*! @brief Empty value type for reactive storage types. */ -struct reactive final {}; - -/** - * @ brief Partial specialization for reactive storage types. - * @tparam Entity A valid entity type. - * @tparam Allocator Type of allocator used to manage memory and elements. - */ -template -struct storage_type { - /*! @brief Type-to-storage conversion result. */ - using type = ENTT_STORAGE(reactive_mixin, basic_storage); -}; - -/** - * @brief Helper type. - * @tparam Args Arguments to forward. - */ -template -using storage_type_t = storage_type::type; - -/** - * Type-to-storage conversion utility that preserves constness. - * @tparam Type Storage value type, eventually const. - * @tparam Entity A valid entity type. - * @tparam Allocator Type of allocator used to manage memory and elements. - */ -template>> -struct storage_for { - /*! @brief Type-to-storage conversion result. */ - using type = constness_as_t, Entity, Allocator>, Type>; -}; - -/** - * @brief Helper type. - * @tparam Args Arguments to forward. - */ -template -using storage_for_t = storage_for::type; - -/** - * @brief Alias declaration for the most common use case. - * @tparam Get Types of storage iterated by the view. - * @tparam Exclude Types of storage used to filter the view. - */ -template> -using view = basic_view, type_list_transform_t>; - -/** - * @brief Alias declaration for the most common use case. - * @tparam Owned Types of storage _owned_ by the group. - * @tparam Get Types of storage _observed_ by the group. - * @tparam Exclude Types of storage used to filter the group. - */ -template, typename Exclude = exclude_t<>> -using group = basic_group, type_list_transform_t, type_list_transform_t>; - -} // namespace entt - -#endif diff --git a/include/entt/entity/group.hpp b/include/entt/entity/group.hpp deleted file mode 100644 index dcb1714..0000000 --- a/include/entt/entity/group.hpp +++ /dev/null @@ -1,1052 +0,0 @@ -#ifndef ENTT_ENTITY_GROUP_HPP -#define ENTT_ENTITY_GROUP_HPP - -#include "../config/config.h" -#include "../core/algorithm.hpp" -#include "../core/fwd.hpp" -#include "../core/iterator.hpp" -#include "../core/type_info.hpp" -#include "../core/type_traits.hpp" -#include "../stl/array.hpp" -#include "../stl/concepts.hpp" -#include "../stl/cstddef.hpp" -#include "../stl/iterator.hpp" -#include "../stl/tuple.hpp" -#include "../stl/type_traits.hpp" -#include "../stl/utility.hpp" -#include "entity.hpp" -#include "fwd.hpp" - -namespace entt { - -/*! @cond ENTT_INTERNAL */ -namespace internal { - -template -class extended_group_iterator; - -template -class extended_group_iterator, get_t> { - template - [[nodiscard]] auto index_to_element([[maybe_unused]] Type &cpool) const { - if constexpr(stl::is_void_v) { - return stl::make_tuple(); - } else { - return stl::forward_as_tuple(cpool.rbegin()[it.index()]); - } - } - -public: - using iterator_type = It; - using value_type = decltype(stl::tuple_cat(stl::make_tuple(*stl::declval()), stl::declval().get_as_tuple({})..., stl::declval().get_as_tuple({})...)); - using pointer = input_iterator_pointer; - using reference = value_type; - using difference_type = stl::ptrdiff_t; - using iterator_category = stl::input_iterator_tag; - using iterator_concept = stl::forward_iterator_tag; - - constexpr extended_group_iterator() - : it{}, - pools{} {} - - extended_group_iterator(iterator_type from, stl::tuple cpools) - : it{from}, - pools{stl::move(cpools)} {} - - extended_group_iterator &operator++() noexcept { - return ++it, *this; - } - - extended_group_iterator operator++(int) noexcept { - const extended_group_iterator orig = *this; - return ++(*this), orig; - } - - [[nodiscard]] reference operator*() const noexcept { - return stl::tuple_cat(stl::make_tuple(*it), index_to_element(*stl::get(pools))..., stl::get(pools)->get_as_tuple(*it)...); - } - - [[nodiscard]] pointer operator->() const noexcept { - return operator*(); - } - - [[nodiscard]] constexpr iterator_type base() const noexcept { - return it; - } - - template - [[nodiscard]] constexpr bool operator==(const extended_group_iterator &other) const noexcept { - return it == other.it; - } - -private: - It it; - stl::tuple pools; -}; - -struct group_descriptor { - using size_type = stl::size_t; - virtual ~group_descriptor() = default; - [[nodiscard]] virtual bool owned(const id_type) const noexcept { - return false; - } -}; - -template -class group_handler final: public group_descriptor { - using entity_type = Type::entity_type; - - void swap_elements(const stl::size_t pos, const entity_type entt) { - for(size_type next{}; next < Owned; ++next) { - pools[next]->swap_elements((*pools[next])[pos], entt); - } - } - - void push_on_construct(const entity_type entt) { - if(stl::apply([entt, pos = len](auto *cpool, auto *...other) { return cpool->contains(entt) && !(cpool->index(entt) < pos) && (other->contains(entt) && ...); }, pools) - && stl::apply([entt](auto *...cpool) { return (!cpool->contains(entt) && ...); }, filter)) { - swap_elements(len++, entt); - } - } - - void push_on_destroy(const entity_type entt) { - if(stl::apply([entt, pos = len](auto *cpool, auto *...other) { return cpool->contains(entt) && !(cpool->index(entt) < pos) && (other->contains(entt) && ...); }, pools) - && stl::apply([entt](auto *...cpool) { return (0u + ... + cpool->contains(entt)) == 1u; }, filter)) { - swap_elements(len++, entt); - } - } - - void remove_if(const entity_type entt) { - if(pools[0u]->contains(entt) && (pools[0u]->index(entt) < len)) { - swap_elements(--len, entt); - } - } - - void common_setup() { - // we cannot iterate backwards because we want to leave behind valid entities in case of owned types - for(auto first = pools[0u]->rbegin(), last = first + static_cast(pools[0u]->size()); first != last; ++first) { - push_on_construct(*first); - } - } - -public: - using common_type = Type; - using size_type = Type::size_type; - - template - group_handler(stl::tuple ogpool, stl::tuple epool) - : pools{stl::apply([](auto &&...cpool) { return stl::array{&cpool...}; }, ogpool)}, - filter{stl::apply([](auto &&...cpool) { return stl::array{&cpool...}; }, epool)} { - stl::apply([this](auto &...cpool) { ((cpool.on_construct().template connect<&group_handler::push_on_construct>(*this), cpool.on_destroy().template connect<&group_handler::remove_if>(*this)), ...); }, ogpool); - stl::apply([this](auto &...cpool) { ((cpool.on_construct().template connect<&group_handler::remove_if>(*this), cpool.on_destroy().template connect<&group_handler::push_on_destroy>(*this)), ...); }, epool); - common_setup(); - } - - [[nodiscard]] bool owned(const id_type hash) const noexcept override { - for(size_type pos{}; pos < Owned; ++pos) { - if(pools[pos]->info().hash() == hash) { - return true; - } - } - - return false; - } - - [[nodiscard]] size_type length() const noexcept { - return len; - } - - template - [[nodiscard]] common_type *storage() const noexcept { - if constexpr(Index < (Owned + Get)) { - return pools[Index]; - } else { - return filter[Index - (Owned + Get)]; - } - } - -private: - stl::array pools; - stl::array filter; - stl::size_t len{}; -}; - -template -class group_handler final: public group_descriptor { - using entity_type = Type::entity_type; - - void push_on_construct(const entity_type entt) { - if(!elem.contains(entt) - && stl::apply([entt](auto *...cpool) { return (cpool->contains(entt) && ...); }, pools) - && stl::apply([entt](auto *...cpool) { return (!cpool->contains(entt) && ...); }, filter)) { - elem.push(entt); - } - } - - void push_on_destroy(const entity_type entt) { - if(!elem.contains(entt) - && stl::apply([entt](auto *...cpool) { return (cpool->contains(entt) && ...); }, pools) - && stl::apply([entt](auto *...cpool) { return (0u + ... + cpool->contains(entt)) == 1u; }, filter)) { - elem.push(entt); - } - } - - void remove_if(const entity_type entt) { - elem.remove(entt); - } - - void common_setup() { - for(const auto entity: *pools[0u]) { - push_on_construct(entity); - } - } - -public: - using common_type = Type; - - template - group_handler(const Allocator &allocator, stl::tuple gpool, stl::tuple epool) - : pools{stl::apply([](auto &&...cpool) { return stl::array{&cpool...}; }, gpool)}, - filter{stl::apply([](auto &&...cpool) { return stl::array{&cpool...}; }, epool)}, - elem{allocator} { - stl::apply([this](auto &...cpool) { ((cpool.on_construct().template connect<&group_handler::push_on_construct>(*this), cpool.on_destroy().template connect<&group_handler::remove_if>(*this)), ...); }, gpool); - stl::apply([this](auto &...cpool) { ((cpool.on_construct().template connect<&group_handler::remove_if>(*this), cpool.on_destroy().template connect<&group_handler::push_on_destroy>(*this)), ...); }, epool); - common_setup(); - } - - [[nodiscard]] common_type &handle() noexcept { - return elem; - } - - [[nodiscard]] const common_type &handle() const noexcept { - return elem; - } - - template - [[nodiscard]] common_type *storage() const noexcept { - if constexpr(Index < Get) { - return pools[Index]; - } else { - return filter[Index - Get]; - } - } - -private: - stl::array pools; - stl::array filter; - common_type elem; -}; - -} // namespace internal -/*! @endcond */ - -/** - * @brief Group. - * - * Primary template isn't defined on purpose. All the specializations give a - * compile-time error, but for a few reasonable cases. - */ -template -class basic_group; - -/** - * @brief Non-owning group. - * - * A non-owning group returns all entities and only the entities that are at - * least in the given storage. Moreover, it's guaranteed that the entity list is - * tightly packed in memory for fast iterations. - * - * @b Important - * - * Iterators aren't invalidated if: - * - * * New elements are added to the storage. - * * The entity currently pointed is modified (for example, elements are added - * or removed from it). - * * The entity currently pointed is destroyed. - * - * In all other cases, modifying the pools iterated by the group in any way - * invalidates all the iterators. - * - * @tparam Get Types of storage _observed_ by the group. - * @tparam Exclude Types of storage used to filter the group. - */ -template -class basic_group, get_t, exclude_t> { - using base_type = stl::common_type_t; - using underlying_type = base_type::entity_type; - - template - static constexpr stl::size_t index_of = type_list_index_v, type_list>; - - template - [[nodiscard]] auto pools_for(stl::index_sequence) const noexcept { - using return_type = stl::tuple; - return descriptor ? return_type{static_cast(descriptor->template storage())...} : return_type{}; - } - -public: - /*! @brief Underlying entity identifier. */ - using entity_type = underlying_type; - /*! @brief Unsigned integer type. */ - using size_type = stl::size_t; - /*! @brief Signed integer type. */ - using difference_type = stl::ptrdiff_t; - /*! @brief Common type among all storage types. */ - using common_type = base_type; - /*! @brief Random access iterator type. */ - using iterator = common_type::iterator; - /*! @brief Reverse iterator type. */ - using reverse_iterator = common_type::reverse_iterator; - /*! @brief Iterable group type. */ - using iterable = iterable_adaptor, get_t>>; - /*! @brief Group handler type. */ - using handler = internal::group_handler; - - /** - * @brief Group opaque identifier. - * @return Group opaque identifier. - */ - static id_type group_id() noexcept { - return type_hash, get_t...>, exclude_t...>>>::value(); - } - - /*! @brief Default constructor to use to create empty, invalid groups. */ - basic_group() noexcept - : descriptor{} {} - - /** - * @brief Constructs a group from a set of storage classes. - * @param ref A reference to a group handler. - */ - basic_group(handler &ref) noexcept - : descriptor{&ref} {} - - /** - * @brief Returns the leading storage of a group. - * @return The leading storage of the group. - */ - [[nodiscard]] const common_type &handle() const noexcept { - return descriptor->handle(); - } - - /** - * @brief Returns the storage for a given element type, if any. - * @tparam Type Type of element of which to return the storage. - * @return The storage for the given element type. - */ - template - [[nodiscard]] auto *storage() const noexcept { - return storage>(); - } - - /** - * @brief Returns the storage for a given index, if any. - * @tparam Index Index of the storage to return. - * @return The storage for the given index. - */ - template - [[nodiscard]] auto *storage() const noexcept { - using type = type_list_element_t>; - return *this ? static_cast(descriptor->template storage()) : nullptr; - } - - /** - * @brief Returns the number of entities that are part of the group. - * @return Number of entities that are part of the group. - */ - [[nodiscard]] size_type size() const noexcept { - return *this ? handle().size() : size_type{}; - } - - /** - * @brief Returns the number of elements that a group has currently - * allocated space for. - * @return Capacity of the group. - */ - [[nodiscard]] size_type capacity() const noexcept { - return *this ? handle().capacity() : size_type{}; - } - - /*! @brief Requests the removal of unused capacity. */ - void shrink_to_fit() { - if(*this) { - descriptor->handle().shrink_to_fit(); - } - } - - /** - * @brief Checks whether a group is empty. - * @return True if the group is empty, false otherwise. - */ - [[nodiscard]] bool empty() const noexcept { - return !*this || handle().empty(); - } - - /** - * @brief Returns an iterator to the first entity of the group. - * - * If the group is empty, the returned iterator will be equal to `end()`. - * - * @return An iterator to the first entity of the group. - */ - [[nodiscard]] iterator begin() const noexcept { - return *this ? handle().begin() : iterator{}; - } - - /** - * @brief Returns an iterator that is past the last entity of the group. - * @return An iterator to the entity following the last entity of the - * group. - */ - [[nodiscard]] iterator end() const noexcept { - return *this ? handle().end() : iterator{}; - } - - /** - * @brief Returns an iterator to the first entity of the reversed group. - * - * If the group is empty, the returned iterator will be equal to `rend()`. - * - * @return An iterator to the first entity of the reversed group. - */ - [[nodiscard]] reverse_iterator rbegin() const noexcept { - return *this ? handle().rbegin() : reverse_iterator{}; - } - - /** - * @brief Returns an iterator that is past the last entity of the reversed - * group. - * @return An iterator to the entity following the last entity of the - * reversed group. - */ - [[nodiscard]] reverse_iterator rend() const noexcept { - return *this ? handle().rend() : reverse_iterator{}; - } - - /** - * @brief Returns the first entity of the group, if any. - * @return The first entity of the group if one exists, the null entity - * otherwise. - */ - [[nodiscard]] entity_type front() const noexcept { - const auto it = begin(); - return it != end() ? *it : null; - } - - /** - * @brief Returns the last entity of the group, if any. - * @return The last entity of the group if one exists, the null entity - * otherwise. - */ - [[nodiscard]] entity_type back() const noexcept { - const auto it = rbegin(); - return it != rend() ? *it : null; - } - - /** - * @brief Finds an entity. - * @param entt A valid identifier. - * @return An iterator to the given entity if it's found, past the end - * iterator otherwise. - */ - [[nodiscard]] iterator find(const entity_type entt) const noexcept { - return *this ? handle().find(entt) : iterator{}; - } - - /** - * @brief Returns the identifier that occupies the given position. - * @param pos Position of the element to return. - * @return The identifier that occupies the given position. - */ - [[nodiscard]] entity_type operator[](const size_type pos) const { - return begin()[static_cast(pos)]; - } - - /** - * @brief Checks if a group is properly initialized. - * @return True if the group is properly initialized, false otherwise. - */ - [[nodiscard]] explicit operator bool() const noexcept { - return descriptor != nullptr; - } - - /** - * @brief Checks if a group contains an entity. - * @param entt A valid identifier. - * @return True if the group contains the given entity, false otherwise. - */ - [[nodiscard]] bool contains(const entity_type entt) const noexcept { - return *this && handle().contains(entt); - } - - /** - * @brief Returns the elements assigned to the given entity. - * @tparam Type Type of the element to get. - * @tparam Other Other types of elements to get. - * @param entt A valid identifier. - * @return The elements assigned to the entity. - */ - template - [[nodiscard]] decltype(auto) get(const entity_type entt) const { - return get, index_of...>(entt); - } - - /** - * @brief Returns the elements assigned to the given entity. - * @tparam Index Indexes of the elements to get. - * @param entt A valid identifier. - * @return The elements assigned to the entity. - */ - template - [[nodiscard]] decltype(auto) get(const entity_type entt) const { - const auto cpools = pools_for(stl::index_sequence_for{}); - - if constexpr(sizeof...(Index) == 0) { - return stl::apply([entt](auto *...curr) { return stl::tuple_cat(curr->get_as_tuple(entt)...); }, cpools); - } else if constexpr(sizeof...(Index) == 1) { - return (stl::get(cpools)->get(entt), ...); - } else { - return stl::tuple_cat(stl::get(cpools)->get_as_tuple(entt)...); - } - } - - /** - * @brief Iterates entities and elements 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 non-empty elements. The - * _constness_ of the elements is as requested.
- * The signature of the function must be equivalent to one of the following - * forms: - * - * @code{.cpp} - * void(const entity_type, Type &...); - * void(Type &...); - * @endcode - * - * @note - * Empty types aren't explicitly instantiated and therefore they are never - * returned during iterations. - * - * @tparam Func Type of the function object to invoke. - * @param func A valid function object. - */ - template - void each(Func func) const { - for(const auto entt: *this) { - if constexpr(is_applicable_v{}, stl::declval().get({})))>) { - stl::apply(func, stl::tuple_cat(stl::make_tuple(entt), get(entt))); - } else { - stl::apply(func, get(entt)); - } - } - } - - /** - * @brief Returns an iterable object to use to _visit_ a group. - * - * The iterable object returns tuples that contain the current entity and a - * set of references to its non-empty elements. The _constness_ of the - * elements is as requested. - * - * @note - * Empty types aren't explicitly instantiated and therefore they are never - * returned during iterations. - * - * @return An iterable object to use to _visit_ the group. - */ - [[nodiscard]] iterable each() const noexcept { - const auto cpools = pools_for(stl::index_sequence_for{}); - return iterable{{begin(), cpools}, {end(), cpools}}; - } - - /** - * @brief Sort a group according to the given comparison function. - * - * 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 one of the following: - * - * @code{.cpp} - * bool(stl::tuple, stl::tuple); - * bool(const Type &..., const Type &...); - * bool(const Entity, const Entity); - * @endcode - * - * Where `Type` are such that they are iterated by the group.
- * Moreover, the comparison function object shall induce a - * _strict weak ordering_ on the values. - * - * The sort function object 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. - * - * @tparam Type Optional type of element to compare. - * @tparam Other Other optional types of elements to compare. - * @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 algo A valid sort function object. - * @param args Arguments to forward to the sort function object, if any. - */ - template - void sort(Compare compare, Sort algo = Sort{}, Args &&...args) { - sort, index_of...>(stl::move(compare), stl::move(algo), stl::forward(args)...); - } - - /** - * @brief Sort a group according to the given comparison function. - * - * @sa sort - * - * @tparam Index Optional indexes of elements to compare. - * @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 algo A valid sort function object. - * @param args Arguments to forward to the sort function object, if any. - */ - template - void sort(Compare compare, Sort algo = Sort{}, Args &&...args) { - if(*this) { - if constexpr(sizeof...(Index) == 0) { - static_assert(stl::is_invocable_v, "Invalid comparison function"); - descriptor->handle().sort(stl::move(compare), stl::move(algo), stl::forward(args)...); - } else { - auto comp = [&compare, cpools = pools_for(stl::index_sequence_for{})](const entity_type lhs, const entity_type rhs) { - if constexpr(sizeof...(Index) == 1) { - return compare((stl::get(cpools)->get(lhs), ...), (stl::get(cpools)->get(rhs), ...)); - } else { - return compare(stl::forward_as_tuple(stl::get(cpools)->get(lhs)...), stl::forward_as_tuple(stl::get(cpools)->get(rhs)...)); - } - }; - - descriptor->handle().sort(stl::move(comp), stl::move(algo), stl::forward(args)...); - } - } - } - - /** - * @brief Sort entities according to their order in a range. - * - * The shared pool of entities and thus its order is affected by the changes - * to each and every pool that it tracks. - * - * @param first An iterator to the first element of the range of entities. - * @param last An iterator past the last element of the range of entities. - */ - void sort_as(stl::input_iterator auto first, stl::input_iterator auto last) const { - if(*this) { - descriptor->handle().sort_as(first, last); - } - } - -private: - handler *descriptor; -}; - -/** - * @brief Owning group. - * - * Owning groups returns all entities and only the entities that are at - * least in the given storage. Moreover: - * - * * It's guaranteed that the entity list is tightly packed in memory for fast - * iterations. - * * It's guaranteed that all elements in the owned storage are tightly packed - * in memory for even faster iterations and to allow direct access. - * * They stay true to the order of the owned storage and all instances have the - * same order in memory. - * - * The more types of storage are owned, the faster it is to iterate a group. - * - * @b Important - * - * Iterators aren't invalidated if: - * - * * New elements are added to the storage. - * * The entity currently pointed is modified (for example, elements are added - * or removed from it). - * * The entity currently pointed is destroyed. - * - * In all other cases, modifying the pools iterated by the group in any way - * invalidates all the iterators. - * - * @tparam Owned Types of storage _owned_ by the group. - * @tparam Get Types of storage _observed_ by the group. - * @tparam Exclude Types of storage used to filter the group. - */ -template -class basic_group, get_t, exclude_t> { - static_assert(((Owned::storage_policy != deletion_policy::in_place) && ...), "Groups do not support in-place delete"); - - using base_type = stl::common_type_t; - using underlying_type = base_type::entity_type; - - template - static constexpr stl::size_t index_of = type_list_index_v, type_list>; - - template - [[nodiscard]] auto pools_for(stl::index_sequence, stl::index_sequence) const noexcept { - using return_type = stl::tuple; - return descriptor ? return_type{static_cast(descriptor->template storage())..., static_cast(descriptor->template storage())...} : return_type{}; - } - -public: - /*! @brief Underlying entity identifier. */ - using entity_type = underlying_type; - /*! @brief Unsigned integer type. */ - using size_type = stl::size_t; - /*! @brief Signed integer type. */ - using difference_type = stl::ptrdiff_t; - /*! @brief Common type among all storage types. */ - using common_type = base_type; - /*! @brief Random access iterator type. */ - using iterator = common_type::iterator; - /*! @brief Reverse iterator type. */ - using reverse_iterator = common_type::reverse_iterator; - /*! @brief Iterable group type. */ - using iterable = iterable_adaptor, get_t>>; - /*! @brief Group handler type. */ - using handler = internal::group_handler; - - /** - * @brief Group opaque identifier. - * @return Group opaque identifier. - */ - static id_type group_id() noexcept { - return type_hash...>, get_t...>, exclude_t...>>>::value(); - } - - /*! @brief Default constructor to use to create empty, invalid groups. */ - basic_group() noexcept - : descriptor{} {} - - /** - * @brief Constructs a group from a set of storage classes. - * @param ref A reference to a group handler. - */ - basic_group(handler &ref) noexcept - : descriptor{&ref} {} - - /** - * @brief Returns the leading storage of a group. - * @return The leading storage of the group. - */ - [[nodiscard]] const common_type &handle() const noexcept { - return *storage<0>(); - } - - /** - * @brief Returns the storage for a given element type, if any. - * @tparam Type Type of element of which to return the storage. - * @return The storage for the given element type. - */ - template - [[nodiscard]] auto *storage() const noexcept { - return storage>(); - } - - /** - * @brief Returns the storage for a given index, if any. - * @tparam Index Index of the storage to return. - * @return The storage for the given index. - */ - template - [[nodiscard]] auto *storage() const noexcept { - using type = type_list_element_t>; - return *this ? static_cast(descriptor->template storage()) : nullptr; - } - - /** - * @brief Returns the number of entities that that are part of the group. - * @return Number of entities that that are part of the group. - */ - [[nodiscard]] size_type size() const noexcept { - return *this ? descriptor->length() : size_type{}; - } - - /** - * @brief Checks whether a group is empty. - * @return True if the group is empty, false otherwise. - */ - [[nodiscard]] bool empty() const noexcept { - return !*this || !descriptor->length(); - } - - /** - * @brief Returns an iterator to the first entity of the group. - * - * If the group is empty, the returned iterator will be equal to `end()`. - * - * @return An iterator to the first entity of the group. - */ - [[nodiscard]] iterator begin() const noexcept { - return *this ? (handle().end() - static_cast(descriptor->length())) : iterator{}; - } - - /** - * @brief Returns an iterator that is past the last entity of the group. - * @return An iterator to the entity following the last entity of the - * group. - */ - [[nodiscard]] iterator end() const noexcept { - return *this ? handle().end() : iterator{}; - } - - /** - * @brief Returns an iterator to the first entity of the reversed group. - * - * If the group is empty, the returned iterator will be equal to `rend()`. - * - * @return An iterator to the first entity of the reversed group. - */ - [[nodiscard]] reverse_iterator rbegin() const noexcept { - return *this ? handle().rbegin() : reverse_iterator{}; - } - - /** - * @brief Returns an iterator that is past the last entity of the reversed - * group. - * @return An iterator to the entity following the last entity of the - * reversed group. - */ - [[nodiscard]] reverse_iterator rend() const noexcept { - return *this ? (handle().rbegin() + static_cast(descriptor->length())) : reverse_iterator{}; - } - - /** - * @brief Returns the first entity of the group, if any. - * @return The first entity of the group if one exists, the null entity - * otherwise. - */ - [[nodiscard]] entity_type front() const noexcept { - const auto it = begin(); - return it != end() ? *it : null; - } - - /** - * @brief Returns the last entity of the group, if any. - * @return The last entity of the group if one exists, the null entity - * otherwise. - */ - [[nodiscard]] entity_type back() const noexcept { - const auto it = rbegin(); - return it != rend() ? *it : null; - } - - /** - * @brief Finds an entity. - * @param entt A valid identifier. - * @return An iterator to the given entity if it's found, past the end - * iterator otherwise. - */ - [[nodiscard]] iterator find(const entity_type entt) const noexcept { - const auto it = *this ? handle().find(entt) : iterator{}; - return it >= begin() ? it : iterator{}; - } - - /** - * @brief Returns the identifier that occupies the given position. - * @param pos Position of the element to return. - * @return The identifier that occupies the given position. - */ - [[nodiscard]] entity_type operator[](const size_type pos) const { - return begin()[static_cast(pos)]; - } - - /** - * @brief Checks if a group is properly initialized. - * @return True if the group is properly initialized, false otherwise. - */ - [[nodiscard]] explicit operator bool() const noexcept { - return descriptor != nullptr; - } - - /** - * @brief Checks if a group contains an entity. - * @param entt A valid identifier. - * @return True if the group contains the given entity, false otherwise. - */ - [[nodiscard]] bool contains(const entity_type entt) const noexcept { - return *this && handle().contains(entt) && (handle().index(entt) < (descriptor->length())); - } - - /** - * @brief Returns the elements assigned to the given entity. - * @tparam Type Type of the element to get. - * @tparam Other Other types of elements to get. - * @param entt A valid identifier. - * @return The elements assigned to the entity. - */ - template - [[nodiscard]] decltype(auto) get(const entity_type entt) const { - return get, index_of...>(entt); - } - - /** - * @brief Returns the elements assigned to the given entity. - * @tparam Index Indexes of the elements to get. - * @param entt A valid identifier. - * @return The elements assigned to the entity. - */ - template - [[nodiscard]] decltype(auto) get(const entity_type entt) const { - const auto cpools = pools_for(stl::index_sequence_for{}, stl::index_sequence_for{}); - - if constexpr(sizeof...(Index) == 0) { - return stl::apply([entt](auto *...curr) { return stl::tuple_cat(curr->get_as_tuple(entt)...); }, cpools); - } else if constexpr(sizeof...(Index) == 1) { - return (stl::get(cpools)->get(entt), ...); - } else { - return stl::tuple_cat(stl::get(cpools)->get_as_tuple(entt)...); - } - } - - /** - * @brief Iterates entities and elements 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 non-empty elements. The - * _constness_ of the elements is as requested.
- * The signature of the function must be equivalent to one of the following - * forms: - * - * @code{.cpp} - * void(const entity_type, Type &...); - * void(Type &...); - * @endcode - * - * @note - * Empty types aren't explicitly instantiated and therefore they are never - * returned during iterations. - * - * @tparam Func Type of the function object to invoke. - * @param func A valid function object. - */ - template - void each(Func func) const { - for(auto args: each()) { - if constexpr(is_applicable_v{}, stl::declval().get({})))>) { - stl::apply(func, args); - } else { - stl::apply([&func](auto, auto &&...less) { func(stl::forward(less)...); }, args); - } - } - } - - /** - * @brief Returns an iterable object to use to _visit_ a group. - * - * The iterable object returns tuples that contain the current entity and a - * set of references to its non-empty elements. The _constness_ of the - * elements is as requested. - * - * @note - * Empty types aren't explicitly instantiated and therefore they are never - * returned during iterations. - * - * @return An iterable object to use to _visit_ the group. - */ - [[nodiscard]] iterable each() const noexcept { - const auto cpools = pools_for(stl::index_sequence_for{}, stl::index_sequence_for{}); - return iterable{{begin(), cpools}, {end(), cpools}}; - } - - /** - * @brief Sort a group according to the given comparison function. - * - * 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 one of the following: - * - * @code{.cpp} - * bool(stl::tuple, stl::tuple); - * bool(const Type &, const Type &); - * bool(const Entity, const Entity); - * @endcode - * - * Where `Type` are either owned types or not but still such that they are - * iterated by the group.
- * Moreover, the comparison function object shall induce a - * _strict weak ordering_ on the values. - * - * The sort function object 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. - * - * @tparam Type Optional type of element to compare. - * @tparam Other Other optional types of elements to compare. - * @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 algo A valid sort function object. - * @param args Arguments to forward to the sort function object, if any. - */ - template - void sort(Compare compare, Sort algo = Sort{}, Args &&...args) const { - sort, index_of...>(stl::move(compare), stl::move(algo), stl::forward(args)...); - } - - /** - * @brief Sort a group according to the given comparison function. - * - * @sa sort - * - * @tparam Index Optional indexes of elements to compare. - * @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 algo A valid sort function object. - * @param args Arguments to forward to the sort function object, if any. - */ - template - void sort(Compare compare, Sort algo = Sort{}, Args &&...args) const { - const auto cpools = pools_for(stl::index_sequence_for{}, stl::index_sequence_for{}); - - if constexpr(sizeof...(Index) == 0) { - static_assert(stl::is_invocable_v, "Invalid comparison function"); - storage<0>()->sort_n(descriptor->length(), stl::move(compare), stl::move(algo), stl::forward(args)...); - } else { - auto comp = [&compare, &cpools](const entity_type lhs, const entity_type rhs) { - if constexpr(sizeof...(Index) == 1) { - return compare((stl::get(cpools)->get(lhs), ...), (stl::get(cpools)->get(rhs), ...)); - } else { - return compare(stl::forward_as_tuple(stl::get(cpools)->get(lhs)...), stl::forward_as_tuple(stl::get(cpools)->get(rhs)...)); - } - }; - - storage<0>()->sort_n(descriptor->length(), stl::move(comp), stl::move(algo), stl::forward(args)...); - } - - auto cb = [this](auto *head, auto *...other) { - for(auto next = descriptor->length(); next; --next) { - const auto pos = next - 1; - [[maybe_unused]] const auto entt = head->data()[pos]; - (other->swap_elements(other->data()[pos], entt), ...); - } - }; - - stl::apply(cb, cpools); - } - -private: - handler *descriptor; -}; - -} // namespace entt - -#endif diff --git a/include/entt/entity/handle.hpp b/include/entt/entity/handle.hpp deleted file mode 100644 index a14016f..0000000 --- a/include/entt/entity/handle.hpp +++ /dev/null @@ -1,368 +0,0 @@ -#ifndef ENTT_ENTITY_HANDLE_HPP -#define ENTT_ENTITY_HANDLE_HPP - -#include "../config/config.h" -#include "../core/iterator.hpp" -#include "../core/type_traits.hpp" -#include "../stl/iterator.hpp" -#include "../stl/tuple.hpp" -#include "../stl/type_traits.hpp" -#include "../stl/utility.hpp" -#include "entity.hpp" -#include "fwd.hpp" - -namespace entt { - -/*! @cond ENTT_INTERNAL */ -namespace internal { - -template -class handle_storage_iterator final { - template - friend class handle_storage_iterator; - - using underlying_type = stl::remove_reference_t; - using entity_type = underlying_type::entity_type; - -public: - using value_type = stl::iterator_traits::value_type; - using pointer = input_iterator_pointer; - using reference = value_type; - using difference_type = stl::ptrdiff_t; - using iterator_category = stl::input_iterator_tag; - using iterator_concept = stl::forward_iterator_tag; - - constexpr handle_storage_iterator() noexcept - : entt{null}, - it{}, - last{} {} - - constexpr handle_storage_iterator(entity_type value, It from, It to) noexcept - : entt{value}, - it{from}, - last{to} { - while(it != last && !it->second.contains(entt)) { - ++it; - } - } - - constexpr handle_storage_iterator &operator++() noexcept { - for(++it; it != last && !it->second.contains(entt); ++it) {} - return *this; - } - - constexpr handle_storage_iterator operator++(int) noexcept { - const handle_storage_iterator orig = *this; - return ++(*this), orig; - } - - [[nodiscard]] constexpr reference operator*() const noexcept { - return *it; - } - - [[nodiscard]] constexpr pointer operator->() const noexcept { - return operator*(); - } - - template - [[nodiscard]] constexpr bool operator==(const handle_storage_iterator &other) const noexcept { - return it == other.it; - } - -private: - entity_type entt; - It it; - It last; -}; - -} // namespace internal -/*! @endcond */ - -/** - * @brief Non-owning handle to an entity. - * - * Tiny wrapper around a registry and an entity. - * - * @tparam Registry Basic registry type. - * @tparam Scope Types to which to restrict the scope of a handle. - */ -template -class basic_handle { - using traits_type = entt_traits; - - [[nodiscard]] auto &owner_or_assert() const noexcept { - ENTT_ASSERT(owner != nullptr, "Invalid pointer to registry"); - return static_cast(*owner); - } - -public: - /*! @brief Type of registry accepted by the handle. */ - using registry_type = Registry; - /*! @brief Underlying entity identifier. */ - using entity_type = traits_type::value_type; - /*! @brief Underlying version type. */ - using version_type = traits_type::version_type; - /*! @brief Unsigned integer type. */ - using size_type = stl::size_t; - /*! @brief Iterable handle type. */ - using iterable = iterable_adaptor().storage())::iterator>>; - - /*! @brief Constructs an invalid handle. */ - basic_handle() noexcept - : owner{}, - entt{null} {} - - /** - * @brief Constructs a handle from a given registry and entity. - * @param ref An instance of the registry class. - * @param value A valid identifier. - */ - basic_handle(registry_type &ref, entity_type value) noexcept - : owner{&ref}, - entt{value} {} - - /** - * @brief Returns an iterable object to use to _visit_ a handle. - * - * The iterable object returns a pair that contains the name and a reference - * to the current storage.
- * Returned storage are those that contain the entity associated with the - * handle. - * - * @return An iterable object to use to _visit_ the handle. - */ - [[nodiscard]] iterable storage() const noexcept { - auto underlying = owner_or_assert().storage(); - return iterable{{entt, underlying.begin(), underlying.end()}, {entt, underlying.end(), underlying.end()}}; - } - - /*! @copydoc valid */ - [[nodiscard]] explicit operator bool() const noexcept { - return owner && owner->valid(entt); - } - - /** - * @brief Checks if a handle refers to a valid registry and entity. - * @return True if the handle refers to a valid registry and entity, false - * otherwise. - */ - [[nodiscard]] bool valid() const { - return static_cast(*this); - } - - /** - * @brief Returns a pointer to the underlying registry, if any. - * @return A pointer to the underlying registry, if any. - */ - [[nodiscard]] registry_type *registry() const noexcept { - return owner; - } - - /** - * @brief Returns the entity associated with a handle. - * @return The entity associated with the handle. - */ - [[nodiscard]] entity_type entity() const noexcept { - return entt; - } - - /*! @copydoc entity */ - [[nodiscard]] operator entity_type() const noexcept { - return entity(); - } - - /*! @brief Destroys the entity associated with a handle. */ - void destroy() { - owner_or_assert().destroy(stl::exchange(entt, null)); - } - - /** - * @brief Destroys the entity associated with a handle. - * @param version A desired version upon destruction. - */ - void destroy(const version_type version) { - owner_or_assert().destroy(stl::exchange(entt, null), version); - } - - /** - * @brief Assigns the given element to a handle. - * @tparam Type Type of element to create. - * @tparam Args Types of arguments to use to construct the element. - * @param args Parameters to use to initialize the element. - * @return A reference to the newly created element. - */ - template - // NOLINTNEXTLINE(modernize-use-nodiscard) - decltype(auto) emplace(Args &&...args) const { - static_assert(((sizeof...(Scope) == 0) || ... || stl::is_same_v), "Invalid type"); - return owner_or_assert().template emplace(entt, stl::forward(args)...); - } - - /** - * @brief Assigns or replaces the given element for a handle. - * @tparam Type Type of element to assign or replace. - * @tparam Args Types of arguments to use to construct the element. - * @param args Parameters to use to initialize the element. - * @return A reference to the newly created element. - */ - template - decltype(auto) emplace_or_replace(Args &&...args) const { - static_assert(((sizeof...(Scope) == 0) || ... || stl::is_same_v), "Invalid type"); - return owner_or_assert().template emplace_or_replace(entt, stl::forward(args)...); - } - - /** - * @brief Patches the given element for a handle. - * @tparam Type Type of element to patch. - * @tparam Func Types of the function objects to invoke. - * @param func Valid function objects. - * @return A reference to the patched element. - */ - template - decltype(auto) patch(Func &&...func) const { - static_assert(((sizeof...(Scope) == 0) || ... || stl::is_same_v), "Invalid type"); - return owner_or_assert().template patch(entt, stl::forward(func)...); - } - - /** - * @brief Replaces the given element for a handle. - * @tparam Type Type of element to replace. - * @tparam Args Types of arguments to use to construct the element. - * @param args Parameters to use to initialize the element. - * @return A reference to the element being replaced. - */ - template - decltype(auto) replace(Args &&...args) const { - static_assert(((sizeof...(Scope) == 0) || ... || stl::is_same_v), "Invalid type"); - return owner_or_assert().template replace(entt, stl::forward(args)...); - } - - /** - * @brief Removes the given elements from a handle. - * @tparam Type Types of elements to remove. - * @return The number of elements actually removed. - */ - template - // NOLINTNEXTLINE(modernize-use-nodiscard) - size_type remove() const { - static_assert(sizeof...(Scope) == 0 || (type_list_contains_v, Type> && ...), "Invalid type"); - return owner_or_assert().template remove(entt); - } - - /** - * @brief Erases the given elements from a handle. - * @tparam Type Types of elements to erase. - */ - template - void erase() const { - static_assert(sizeof...(Scope) == 0 || (type_list_contains_v, Type> && ...), "Invalid type"); - owner_or_assert().template erase(entt); - } - - /** - * @brief Checks if a handle has all the given elements. - * @tparam Type Elements for which to perform the check. - * @return True if the handle has all the elements, false otherwise. - */ - template - [[nodiscard]] decltype(auto) all_of() const { - return owner_or_assert().template all_of(entt); - } - - /** - * @brief Checks if a handle has at least one of the given elements. - * @tparam Type Elements for which to perform the check. - * @return True if the handle has at least one of the given elements, - * false otherwise. - */ - template - [[nodiscard]] decltype(auto) any_of() const { - return owner_or_assert().template any_of(entt); - } - - /** - * @brief Returns references to the given elements for a handle. - * @tparam Type Types of elements to get. - * @return References to the elements owned by the handle. - */ - template - [[nodiscard]] decltype(auto) get() const { - static_assert(sizeof...(Scope) == 0 || (type_list_contains_v, Type> && ...), "Invalid type"); - return owner_or_assert().template get(entt); - } - - /** - * @brief Returns a reference to the given element for a handle. - * @tparam Type Type of element to get. - * @tparam Args Types of arguments to use to construct the element. - * @param args Parameters to use to initialize the element. - * @return Reference to the element owned by the handle. - */ - template - [[nodiscard]] decltype(auto) get_or_emplace(Args &&...args) const { - static_assert(((sizeof...(Scope) == 0) || ... || stl::is_same_v), "Invalid type"); - return owner_or_assert().template get_or_emplace(entt, stl::forward(args)...); - } - - /** - * @brief Returns pointers to the given elements for a handle. - * @tparam Type Types of elements to get. - * @return Pointers to the elements owned by the handle. - */ - template - [[nodiscard]] auto try_get() const { - static_assert(sizeof...(Scope) == 0 || (type_list_contains_v, Type> && ...), "Invalid type"); - return owner_or_assert().template try_get(entt); - } - - /** - * @brief Checks if a handle has elements assigned. - * @return True if the handle has no elements assigned, false otherwise. - */ - [[nodiscard]] bool orphan() const { - return owner_or_assert().orphan(entt); - } - - /** - * @brief Compares two handles. - * @tparam Other Scope of the other handle. - * @param other A valid handle. - * @return True if both handles refer to the same registry and the same - * entity, false otherwise. - */ - template - [[nodiscard]] bool operator==(const basic_handle &other) const noexcept { - return owner == other.registry() && entt == other.entity(); - } - - /** - * @brief Compares a handle with the null object. - * @param other A null object yet to be converted. - * @return False if the two elements differ, true otherwise. - */ - [[nodiscard]] constexpr bool operator==(const null_t other) const noexcept { - return (entt == other); - } - - /** - * @brief Returns a const handle from a non-const one. - * @tparam Other A valid entity type. - * @tparam Args Scope of the handle to construct. - * @return A const handle referring to the same registry and the same - * entity. - */ - template - operator basic_handle() const noexcept { - static_assert(stl::is_same_v || stl::is_same_v, Registry>, "Invalid conversion between different handles"); - static_assert((sizeof...(Scope) == 0 || ((sizeof...(Args) != 0 && sizeof...(Args) <= sizeof...(Scope)) && ... && (type_list_contains_v, Args>))), "Invalid conversion between different handles"); - return owner ? basic_handle{*owner, entt} : basic_handle{}; - } - -private: - registry_type *owner; - entity_type entt; -}; - -} // namespace entt - -#endif diff --git a/include/entt/entity/helper.hpp b/include/entt/entity/helper.hpp deleted file mode 100644 index 3a89c2f..0000000 --- a/include/entt/entity/helper.hpp +++ /dev/null @@ -1,256 +0,0 @@ -#ifndef ENTT_ENTITY_HELPER_HPP -#define ENTT_ENTITY_HELPER_HPP - -#include "../core/fwd.hpp" -#include "../core/type_traits.hpp" -#include "../stl/memory.hpp" -#include "../stl/type_traits.hpp" -#include "../stl/utility.hpp" -#include "component.hpp" -#include "fwd.hpp" -#include "group.hpp" -#include "storage.hpp" -#include "view.hpp" - -namespace entt { - -/** - * @brief Converts a registry to a view. - * @tparam Registry Basic registry type. - */ -template -class as_view { - template - [[nodiscard]] auto dispatch(get_t, exclude_t) const { - return reg->template view...>(exclude_t...>{}); - } - -public: - /*! @brief Type of registry to convert. */ - using registry_type = Registry; - /*! @brief Underlying entity identifier. */ - using entity_type = registry_type::entity_type; - - /** - * @brief Constructs a converter for a given registry. - * @param source A valid reference to a registry. - */ - as_view(registry_type &source) noexcept - : reg{&source} {} - - /** - * @brief Conversion function from a registry to a view. - * @tparam Get Type of storage used to construct the view. - * @tparam Exclude Types of storage used to filter the view. - * @return A newly created view. - */ - template - operator basic_view() const { - return dispatch(Get{}, Exclude{}); - } - -private: - registry_type *reg; -}; - -/** - * @brief Converts a registry to a group. - * @tparam Registry Basic registry type. - */ -template -class as_group { - template - [[nodiscard]] auto dispatch(owned_t, get_t, exclude_t) const { - if constexpr(stl::is_const_v) { - return reg->template group_if_exists(get_t{}, exclude_t{}); - } else { - return reg->template group...>(get_t...>{}, exclude_t...>{}); - } - } - -public: - /*! @brief Type of registry to convert. */ - using registry_type = Registry; - /*! @brief Underlying entity identifier. */ - using entity_type = registry_type::entity_type; - - /** - * @brief Constructs a converter for a given registry. - * @param source A valid reference to a registry. - */ - as_group(registry_type &source) noexcept - : reg{&source} {} - - /** - * @brief Conversion function from a registry to a group. - * @tparam Owned Types of _owned_ by the group. - * @tparam Get Types of storage _observed_ by the group. - * @tparam Exclude Types of storage used to filter the group. - * @return A newly created group. - */ - template - operator basic_group() const { - return dispatch(Owned{}, Get{}, Exclude{}); - } - -private: - registry_type *reg; -}; - -/** - * @brief Helper to create a listener that directly invokes a member function. - * @tparam Member Member function to invoke on an element of the given type. - * @tparam Registry Basic registry type. - * @param reg A registry that contains the given entity and its elements. - * @param entt Entity from which to get the element. - */ -template>> -void invoke(Registry ®, const typename Registry::entity_type entt) { - static_assert(stl::is_member_function_pointer_v, "Invalid pointer to non-static member function"); - (reg.template get>(entt).*Member)(reg, entt); -} - -/** - * @brief Returns the entity associated with a given element. - * - * @warning - * Currently, this function only works correctly with the default storage as it - * makes assumptions about how the elements are laid out. - * - * @tparam Args Storage type template parameters. - * @param storage A storage that contains the given element. - * @param instance A valid element instance. - * @return The entity associated with the given element. - */ -template -basic_storage::entity_type to_entity(const basic_storage &storage, const typename basic_storage::value_type &instance) { - using traits_type = component_traits::value_type, typename basic_storage::entity_type>; - static_assert(traits_type::page_size != 0u, "Unexpected page size"); - const auto *page = storage.raw(); - - // NOLINTBEGIN(cppcoreguidelines-pro-bounds-pointer-arithmetic) - for(stl::size_t pos{}, count = storage.size(); pos < count; pos += traits_type::page_size, ++page) { - if(const auto dist = (stl::addressof(instance) - *page); dist >= 0 && dist < static_cast(traits_type::page_size)) { - return *(static_cast::base_type &>(storage).rbegin() + static_cast(pos) + dist); - } - } - // NOLINTEND(cppcoreguidelines-pro-bounds-pointer-arithmetic) - - return null; -} - -/*! @brief Primary template isn't defined on purpose. */ -template -struct sigh_helper; - -/** - * @brief Signal connection helper for registries. - * @tparam Registry Basic registry type. - */ -template -struct sigh_helper { - /*! @brief Registry type. */ - using registry_type = Registry; - - /** - * @brief Constructs a helper for a given registry. - * @param ref A valid reference to a registry. - */ - sigh_helper(registry_type &ref) - : bucket{&ref} {} - - /** - * @brief Binds a properly initialized helper to a given signal type. - * @tparam Type Type of signal to bind the helper to. - * @param id Optional name for the underlying storage to use. - * @return A helper for a given registry and signal type. - */ - template - auto with(const id_type id = type_hash::value()) noexcept { - return sigh_helper{*bucket, id}; - } - - /** - * @brief Returns a reference to the underlying registry. - * @return A reference to the underlying registry. - */ - [[nodiscard]] registry_type ®istry() noexcept { - return *bucket; - } - -private: - registry_type *bucket; -}; - -/** - * @brief Signal connection helper for registries. - * @tparam Registry Basic registry type. - * @tparam Type Type of signal to connect listeners to. - */ -template -struct sigh_helper final: sigh_helper { - /*! @brief Registry type. */ - using registry_type = Registry; - - /** - * @brief Constructs a helper for a given registry. - * @param ref A valid reference to a registry. - * @param id Optional name for the underlying storage to use. - */ - sigh_helper(registry_type &ref, const id_type id = type_hash::value()) - : sigh_helper{ref}, - name{id} {} - - /** - * @brief Forwards the call to `on_construct` on the underlying storage. - * @tparam Candidate Function or member to connect. - * @tparam Args Type of class or type of payload, if any. - * @param args A valid object that fits the purpose, if any. - * @return This helper. - */ - template - auto on_construct(Args &&...args) { - this->registry().template on_construct(name).template connect(stl::forward(args)...); - return *this; - } - - /** - * @brief Forwards the call to `on_update` on the underlying storage. - * @tparam Candidate Function or member to connect. - * @tparam Args Type of class or type of payload, if any. - * @param args A valid object that fits the purpose, if any. - * @return This helper. - */ - template - auto on_update(Args &&...args) { - this->registry().template on_update(name).template connect(stl::forward(args)...); - return *this; - } - - /** - * @brief Forwards the call to `on_destroy` on the underlying storage. - * @tparam Candidate Function or member to connect. - * @tparam Args Type of class or type of payload, if any. - * @param args A valid object that fits the purpose, if any. - * @return This helper. - */ - template - auto on_destroy(Args &&...args) { - this->registry().template on_destroy(name).template connect(stl::forward(args)...); - return *this; - } - -private: - id_type name; -}; - -/** - * @brief Deduction guide. - * @tparam Registry Basic registry type. - */ -template -sigh_helper(Registry &) -> sigh_helper; - -} // namespace entt - -#endif diff --git a/include/entt/entity/mixin.hpp b/include/entt/entity/mixin.hpp deleted file mode 100644 index d5a15b9..0000000 --- a/include/entt/entity/mixin.hpp +++ /dev/null @@ -1,593 +0,0 @@ -#ifndef ENTT_ENTITY_MIXIN_HPP -#define ENTT_ENTITY_MIXIN_HPP - -#include "../config/config.h" -#include "../core/any.hpp" -#include "../core/type_info.hpp" -#include "../signal/sigh.hpp" -#include "../stl/concepts.hpp" -#include "../stl/iterator.hpp" -#include "../stl/type_traits.hpp" -#include "../stl/utility.hpp" -#include "../stl/vector.hpp" -#include "entity.hpp" -#include "fwd.hpp" - -namespace entt { - -/*! @cond ENTT_INTERNAL */ -namespace internal { - -template -struct has_on_construct final: stl::false_type {}; - -template -requires stl::invocable -struct has_on_construct: stl::true_type {}; - -template -struct has_on_update final: stl::false_type {}; - -template -requires stl::invocable -struct has_on_update: stl::true_type {}; - -template -struct has_on_destroy final: stl::false_type {}; - -template -requires stl::invocable -struct has_on_destroy: stl::true_type {}; - -} // namespace internal -/*! @endcond */ - -/** - * @brief Mixin type used to add signal support to storage types. - * - * The function type of a listener is equivalent to: - * - * @code{.cpp} - * void(basic_registry &, entity_type); - * @endcode - * - * This applies to all signals made available. - * - * @tparam Type Underlying storage type. - * @tparam Registry Basic registry type. - */ -template -class basic_sigh_mixin final: public Type { - using underlying_type = Type; - using owner_type = Registry; - - using basic_registry_type = basic_registry; - using sigh_type = sigh; - using underlying_iterator = underlying_type::base_type::basic_iterator; - - static_assert(stl::is_base_of_v, "Invalid registry type"); - - [[nodiscard]] auto &owner_or_assert() const noexcept { - ENTT_ASSERT(owner != nullptr, "Invalid pointer to registry"); - return static_cast(*owner); - } - -private: - void pop(underlying_iterator first, underlying_iterator last) final { - if(auto ® = owner_or_assert(); destruction.empty()) { - underlying_type::pop(first, last); - } else { - for(; first != last; ++first) { - const auto entt = *first; - destruction.publish(reg, entt); - const auto it = underlying_type::find(entt); - underlying_type::pop(it, it + 1u); - } - } - } - - void pop_all() final { - if(auto ® = owner_or_assert(); !destruction.empty()) { - if constexpr(stl::is_same_v) { - for(typename underlying_type::size_type pos{}, last = underlying_type::free_list(); pos < last; ++pos) { - destruction.publish(reg, underlying_type::base_type::operator[](pos)); - } - } else { - for(auto entt: static_cast(*this)) { - if constexpr(underlying_type::storage_policy == deletion_policy::in_place) { - if(entt != tombstone) { - destruction.publish(reg, entt); - } - } else { - destruction.publish(reg, entt); - } - } - } - } - - underlying_type::pop_all(); - } - - underlying_iterator try_emplace(const underlying_type::entity_type entt, const bool force_back, const void *value) final { - const auto it = underlying_type::try_emplace(entt, force_back, value); - - if(auto ® = owner_or_assert(); it != underlying_type::base_type::end()) { - construction.publish(reg, *it); - } - - return it; - } - - void bind_any(any value) noexcept final { - owner = any_cast(&value); - - if constexpr(!stl::is_same_v) { - if(owner == nullptr) { - owner = any_cast(&value); - } - } - - underlying_type::bind_any(stl::move(value)); - } - -public: - /*! @brief Allocator type. */ - using allocator_type = underlying_type::allocator_type; - /*! @brief Underlying entity identifier. */ - using entity_type = underlying_type::entity_type; - /*! @brief Expected registry type. */ - using registry_type = owner_type; - - /*! @brief Default constructor. */ - basic_sigh_mixin() - : basic_sigh_mixin{allocator_type{}} {} - - /** - * @brief Constructs an empty storage with a given allocator. - * @param allocator The allocator to use. - */ - explicit basic_sigh_mixin(const allocator_type &allocator) - : underlying_type{allocator}, - owner{}, - construction{allocator}, - destruction{allocator}, - update{allocator} { - if constexpr(internal::has_on_construct::value) { - sink{construction}.template connect<&underlying_type::element_type::on_construct>(); - } - - if constexpr(internal::has_on_update::value) { - sink{update}.template connect<&underlying_type::element_type::on_update>(); - } - - if constexpr(internal::has_on_destroy::value) { - sink{destruction}.template connect<&underlying_type::element_type::on_destroy>(); - } - } - - /*! @brief Default copy constructor, deleted on purpose. */ - basic_sigh_mixin(const basic_sigh_mixin &) = delete; - - /** - * @brief Move constructor. - * @param other The instance to move from. - */ - basic_sigh_mixin(basic_sigh_mixin &&other) noexcept - : underlying_type{static_cast(other)}, - owner{other.owner}, - construction{stl::move(other.construction)}, - destruction{stl::move(other.destruction)}, - update{stl::move(other.update)} {} - - /** - * @brief Allocator-extended move constructor. - * @param other The instance to move from. - * @param allocator The allocator to use. - */ - basic_sigh_mixin(basic_sigh_mixin &&other, const allocator_type &allocator) - : underlying_type{static_cast(other), allocator}, - owner{other.owner}, - construction{stl::move(other.construction), allocator}, - destruction{stl::move(other.destruction), allocator}, - update{stl::move(other.update), allocator} {} - - /*! @brief Default destructor. */ - ~basic_sigh_mixin() override = default; - - /** - * @brief Default copy assignment operator, deleted on purpose. - * @return This mixin. - */ - basic_sigh_mixin &operator=(const basic_sigh_mixin &) = delete; - - /** - * @brief Move assignment operator. - * @param other The instance to move from. - * @return This mixin. - */ - basic_sigh_mixin &operator=(basic_sigh_mixin &&other) noexcept { - swap(other); - return *this; - } - - /** - * @brief Exchanges the contents with those of a given storage. - * @param other Storage to exchange the content with. - */ - void swap(basic_sigh_mixin &other) noexcept { - using stl::swap; - swap(owner, other.owner); - swap(construction, other.construction); - swap(destruction, other.destruction); - swap(update, other.update); - underlying_type::swap(other); - } - - /** - * @brief Returns a sink object. - * - * The sink returned by this function can be used to receive notifications - * whenever a new instance is created and assigned to an entity.
- * Listeners are invoked after the object has been assigned to the entity. - * - * @sa sink - * - * @return A temporary sink object. - */ - [[nodiscard]] auto on_construct() noexcept { - return sink{construction}; - } - - /** - * @brief Returns a sink object. - * - * The sink returned by this function can be used to receive notifications - * whenever an instance is explicitly updated.
- * Listeners are invoked after the object has been updated. - * - * @sa sink - * - * @return A temporary sink object. - */ - [[nodiscard]] auto on_update() noexcept { - return sink{update}; - } - - /** - * @brief Returns a sink object. - * - * The sink returned by this function can be used to receive notifications - * whenever an instance is removed from an entity and thus destroyed.
- * Listeners are invoked before the object has been removed from the entity. - * - * @sa sink - * - * @return A temporary sink object. - */ - [[nodiscard]] auto on_destroy() noexcept { - return sink{destruction}; - } - - /** - * @brief Checks if a mixin refers to a valid registry. - * @return True if the mixin refers to a valid registry, false otherwise. - */ - [[nodiscard]] explicit operator bool() const noexcept { - return (owner != nullptr); - } - - /** - * @brief Returns a pointer to the underlying registry, if any. - * @return A pointer to the underlying registry, if any. - */ - [[nodiscard]] const registry_type ®istry() const noexcept { - return owner_or_assert(); - } - - /*! @copydoc registry */ - [[nodiscard]] registry_type ®istry() noexcept { - return owner_or_assert(); - } - - /** - * @brief Creates a new identifier or recycles a destroyed one. - * @return A valid identifier. - */ - auto generate() { - const auto entt = underlying_type::generate(); - construction.publish(owner_or_assert(), entt); - return entt; - } - - /** - * @brief Creates a new identifier or recycles a destroyed one. - * @param hint Required identifier. - * @return A valid identifier. - */ - entity_type generate(const entity_type hint) { - const auto entt = underlying_type::generate(hint); - construction.publish(owner_or_assert(), entt); - return entt; - } - - /** - * @brief Assigns each element in a range an identifier. - * @tparam It Type of output iterator. - * @param first An iterator to the first element of the range to generate. - * @param last An iterator past the last element of the range to generate. - */ - template It> - void generate(It first, It last) { - underlying_type::generate(first, last); - - if(auto ® = owner_or_assert(); !construction.empty()) { - for(; first != last; ++first) { - construction.publish(reg, *first); - } - } - } - - /** - * @brief Assigns an entity to a storage and constructs its object. - * @tparam Args Types of arguments to forward to the underlying storage. - * @param entt A valid identifier. - * @param args Parameters to forward to the underlying storage. - * @return A reference to the newly created object. - */ - template - decltype(auto) emplace(const entity_type entt, Args &&...args) { - underlying_type::emplace(entt, stl::forward(args)...); - construction.publish(owner_or_assert(), entt); - return this->get(entt); - } - - /** - * @brief Updates the instance assigned to a given entity in-place. - * @tparam Func Types of the function objects to invoke. - * @param entt A valid identifier. - * @param func Valid function objects. - * @return A reference to the patched instance. - */ - template - decltype(auto) patch(const entity_type entt, Func &&...func) { - underlying_type::patch(entt, stl::forward(func)...); - update.publish(owner_or_assert(), entt); - return this->get(entt); - } - - /** - * @brief Assigns one or more entities to a storage and constructs their - * objects from a given instance. - * @tparam Args Types of arguments to forward to the underlying storage. - * @param first An iterator to the first element of the range of entities. - * @param last An iterator past the last element of the range of entities. - * @param args Parameters to use to forward to the underlying storage. - */ - template - void insert(stl::input_iterator auto first, stl::input_iterator auto last, Args &&...args) { - auto from = underlying_type::size(); - underlying_type::insert(first, last, stl::forward(args)...); - - if(auto ® = owner_or_assert(); !construction.empty()) { - // fine as long as insert passes force_back true to try_emplace - for(const auto to = underlying_type::size(); from != to; ++from) { - construction.publish(reg, underlying_type::operator[](from)); - } - } - } - -private: - basic_registry_type *owner; - sigh_type construction; - sigh_type destruction; - sigh_type update; -}; - -/** - * @brief Mixin type used to add _reactive_ support to storage types. - * @tparam Type Underlying storage type. - * @tparam Registry Basic registry type. - */ -template -class basic_reactive_mixin final: public Type { - using underlying_type = Type; - using owner_type = Registry; - - using alloc_traits = stl::allocator_traits; - using basic_registry_type = basic_registry; - using container_type = stl::vector>; - - static_assert(stl::is_base_of_v, "Invalid registry type"); - - [[nodiscard]] auto &owner_or_assert() const noexcept { - ENTT_ASSERT(owner != nullptr, "Invalid pointer to registry"); - return static_cast(*owner); - } - - void emplace_element(const Registry &, underlying_type::entity_type entity) { - if(!underlying_type::contains(entity)) { - underlying_type::emplace(entity); - } - } - -private: - void bind_any(any value) noexcept final { - owner = any_cast(&value); - - if constexpr(!stl::is_same_v) { - if(owner == nullptr) { - owner = any_cast(&value); - } - } - - underlying_type::bind_any(stl::move(value)); - } - -public: - /*! @brief Allocator type. */ - using allocator_type = underlying_type::allocator_type; - /*! @brief Underlying entity identifier. */ - using entity_type = underlying_type::entity_type; - /*! @brief Expected registry type. */ - using registry_type = owner_type; - - /*! @brief Default constructor. */ - basic_reactive_mixin() - : basic_reactive_mixin{allocator_type{}} {} - - /** - * @brief Constructs an empty storage with a given allocator. - * @param allocator The allocator to use. - */ - explicit basic_reactive_mixin(const allocator_type &allocator) - : underlying_type{allocator}, - owner{}, - conn{allocator} { - } - - /*! @brief Default copy constructor, deleted on purpose. */ - basic_reactive_mixin(const basic_reactive_mixin &) = delete; - - /** - * @brief Move constructor. - * @param other The instance to move from. - */ - basic_reactive_mixin(basic_reactive_mixin &&other) noexcept - : underlying_type{static_cast(other)}, - owner{other.owner}, - conn{stl::move(other.conn)} { - } - - /** - * @brief Allocator-extended move constructor. - * @param other The instance to move from. - * @param allocator The allocator to use. - */ - basic_reactive_mixin(basic_reactive_mixin &&other, const allocator_type &allocator) - : underlying_type{static_cast(other), allocator}, - owner{other.owner}, - conn{stl::move(other.conn), allocator} { - } - - /*! @brief Default destructor. */ - ~basic_reactive_mixin() override = default; - - /** - * @brief Default copy assignment operator, deleted on purpose. - * @return This mixin. - */ - basic_reactive_mixin &operator=(const basic_reactive_mixin &) = delete; - - /** - * @brief Move assignment operator. - * @param other The instance to move from. - * @return This mixin. - */ - basic_reactive_mixin &operator=(basic_reactive_mixin &&other) noexcept { - underlying_type::swap(other); - return *this; - } - - /** - * @brief Makes storage _react_ to creation of objects of the given type. - * @tparam Clazz Type of element to _react_ to. - * @tparam Candidate Function to use to _react_ to the event. - * @param id Optional name used to map the storage within the registry. - * @return This mixin. - */ - template - basic_reactive_mixin &on_construct(const id_type id = type_hash::value()) { - auto curr = owner_or_assert().template storage(id).on_construct().template connect(*this); - conn.push_back(stl::move(curr)); - return *this; - } - - /** - * @brief Makes storage _react_ to update of objects of the given type. - * @tparam Clazz Type of element to _react_ to. - * @tparam Candidate Function to use to _react_ to the event. - * @param id Optional name used to map the storage within the registry. - * @return This mixin. - */ - template - basic_reactive_mixin &on_update(const id_type id = type_hash::value()) { - auto curr = owner_or_assert().template storage(id).on_update().template connect(*this); - conn.push_back(stl::move(curr)); - return *this; - } - - /** - * @brief Makes storage _react_ to destruction of objects of the given type. - * @tparam Clazz Type of element to _react_ to. - * @tparam Candidate Function to use to _react_ to the event. - * @param id Optional name used to map the storage within the registry. - * @return This mixin. - */ - template - basic_reactive_mixin &on_destroy(const id_type id = type_hash::value()) { - auto curr = owner_or_assert().template storage(id).on_destroy().template connect(*this); - conn.push_back(stl::move(curr)); - return *this; - } - - /** - * @brief Checks if a mixin refers to a valid registry. - * @return True if the mixin refers to a valid registry, false otherwise. - */ - [[nodiscard]] explicit operator bool() const noexcept { - return (owner != nullptr); - } - - /** - * @brief Returns a pointer to the underlying registry, if any. - * @return A pointer to the underlying registry, if any. - */ - [[nodiscard]] const registry_type ®istry() const noexcept { - return owner_or_assert(); - } - - /*! @copydoc registry */ - [[nodiscard]] registry_type ®istry() noexcept { - return owner_or_assert(); - } - - /** - * @brief Returns a view that is filtered by the underlying storage. - * @tparam Get Types of elements used to construct the view. - * @tparam Exclude Types of elements used to filter the view. - * @return A newly created view. - */ - template - [[nodiscard]] basic_view...>, exclude_t...>> - view(exclude_t = exclude_t{}) const { - const owner_type &parent = owner_or_assert(); - basic_view...>, exclude_t...>> elem{}; - [&elem](const auto *...curr) { ((curr ? elem.storage(*curr) : void()), ...); }(parent.template storage>()..., parent.template storage>()..., this); - return elem; - } - - /*! @copydoc view */ - template - [[nodiscard]] basic_view...>, exclude_t...>> - view(exclude_t = exclude_t{}) { - stl::conditional_t<((stl::is_const_v && ...) && (stl::is_const_v && ...)), const owner_type, owner_type> &parent = owner_or_assert(); - return {*this, parent.template storage>()..., parent.template storage>()...}; - } - - /*! @brief Releases all connections to the underlying registry, if any. */ - void reset() { - for(auto &&curr: conn) { - curr.release(); - } - - conn.clear(); - } - -private: - basic_registry_type *owner; - container_type conn; -}; - -} // namespace entt - -#endif diff --git a/include/entt/entity/organizer.hpp b/include/entt/entity/organizer.hpp deleted file mode 100644 index 711d4b4..0000000 --- a/include/entt/entity/organizer.hpp +++ /dev/null @@ -1,437 +0,0 @@ -#ifndef ENTT_ENTITY_ORGANIZER_HPP -#define ENTT_ENTITY_ORGANIZER_HPP - -#include "../core/type_info.hpp" -#include "../core/type_traits.hpp" -#include "../core/utility.hpp" -#include "../graph/adjacency_matrix.hpp" -#include "../graph/flow.hpp" -#include "../stl/cstddef.hpp" -#include "../stl/type_traits.hpp" -#include "../stl/utility.hpp" -#include "../stl/vector.hpp" -#include "fwd.hpp" -#include "helper.hpp" - -namespace entt { - -/*! @cond ENTT_INTERNAL */ -namespace internal { - -template -struct is_view: stl::false_type {}; - -template -struct is_view>: stl::true_type {}; - -template -inline constexpr bool is_view_v = is_view::value; - -template -struct is_group: stl::false_type {}; - -template -struct is_group>: stl::true_type {}; - -template -inline constexpr bool is_group_v = is_group::value; - -template -struct unpack_type { - using ro = stl::conditional_t< - type_list_contains_v || (stl::is_const_v && !type_list_contains_v>), - type_list>, - type_list<>>; - - using rw = stl::conditional_t< - type_list_contains_v> || (!stl::is_const_v && !type_list_contains_v), - type_list, - type_list<>>; -}; - -template -struct unpack_type, type_list> { - using ro = type_list<>; - using rw = type_list<>; -}; - -template -struct unpack_type, type_list> - : unpack_type, type_list> {}; - -template -struct unpack_type, exclude_t>, type_list> { - using ro = type_list_cat_t, typename unpack_type, type_list>::ro...>; - using rw = type_list_cat_t, type_list>::rw...>; -}; - -template -struct unpack_type, exclude_t>, type_list> - : unpack_type, exclude_t>, type_list> {}; - -template -struct unpack_type, get_t, exclude_t>, type_list> { - using ro = type_list_cat_t, typename unpack_type, type_list>::ro..., typename unpack_type, type_list>::ro...>; - using rw = type_list_cat_t, type_list>::rw..., typename unpack_type, type_list>::rw...>; -}; - -template -struct unpack_type, get_t, exclude_t>, type_list> - : unpack_type, get_t, exclude_t>, type_list> {}; - -template -struct resource_traits; - -template -struct resource_traits, type_list> { - using args = type_list...>; - using ro = type_list_cat_t>::ro..., typename unpack_type>::ro...>; - using rw = type_list_cat_t>::rw..., typename unpack_type>::rw...>; - static constexpr auto sync_point = (stl::is_same_v || ...); -}; - -template -resource_traits...>, type_list> free_function_to_resource_traits(Ret (*)(Args...)); - -template -resource_traits...>, type_list> constrained_function_to_resource_traits(Ret (*)(Type &, Args...)); - -template -resource_traits...>, type_list> constrained_function_to_resource_traits(Ret (Class::*)(Args...)); - -template -resource_traits...>, type_list> constrained_function_to_resource_traits(Ret (Class::*)(Args...) const); - -} // namespace internal -/*! @endcond */ - -/** - * @brief Utility class for creating a static task graph. - * - * This class offers minimal support (but sufficient in many cases) for creating - * an execution graph from functions and their requirements on resources.
- * Note that the resulting tasks aren't executed in any case. This isn't the - * goal of the tool. Instead, they are returned to the user in the form of a - * graph that allows for safe execution. - * - * @tparam Registry Basic registry type. - */ -template -class basic_organizer final { - using callback_type = void(const void *, Registry &); - using prepare_type = void(Registry &); - using dependency_type = stl::size_t(const bool, const type_info **, const stl::size_t); - - struct vertex_data final { - stl::size_t ro_count{}; - stl::size_t rw_count{}; - const char *name{}; - const void *payload{}; - callback_type *callback{}; - dependency_type *dependency{}; - prepare_type *prepare{}; - const type_info *info{}; - }; - - template - [[nodiscard]] static decltype(auto) extract(Registry ®) { - if constexpr(stl::is_same_v) { - return reg; - } else if constexpr(internal::is_view_v) { - return static_cast(as_view{reg}); - } else if constexpr(internal::is_group_v) { - return static_cast(as_group{reg}); - } else { - return reg.ctx().template emplace>(); - } - } - - template - [[nodiscard]] static auto to_args(Registry ®, type_list) { - return stl::tuple(reg))...>(extract(reg)...); - } - - template - [[nodiscard]] static stl::size_t fill_dependencies(type_list, [[maybe_unused]] const type_info **buffer, [[maybe_unused]] const stl::size_t count) { - if constexpr(sizeof...(Type) == 0u) { - return {}; - } else { - // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays, modernize-avoid-c-arrays) - const type_info *info[]{&type_id()...}; - const auto length = count < sizeof...(Type) ? count : sizeof...(Type); - - for(stl::size_t pos{}; pos < length; ++pos) { - // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) - buffer[pos] = info[pos]; - } - - return length; - } - } - - template - void track_dependencies(stl::size_t index, const bool sync_point, type_list, type_list) { - builder.bind(static_cast(index)); - builder.set(type_hash::value(), sync_point || (sizeof...(RO) + sizeof...(RW) == 0u)); - (builder.ro(type_hash::value()), ...); - (builder.rw(type_hash::value()), ...); - } - -public: - /*! Basic registry type. */ - using registry_type = Registry; - /*! @brief Underlying entity identifier. */ - using entity_type = registry_type::entity_type; - /*! @brief Unsigned integer type. */ - using size_type = stl::size_t; - /*! @brief Raw task function type. */ - using function_type = callback_type; - - /*! @brief Vertex type of a task graph defined as an adjacency list. */ - struct vertex { - /** - * @brief Constructs a vertex of the task graph. - * @param data The data associated with the vertex. - * @param from List of in-edges of the vertex. - * @param to List of out-edges of the vertex. - */ - vertex(vertex_data data, stl::vector from, stl::vector to) - : node{stl::move(data)}, - in{stl::move(from)}, - out{stl::move(to)} {} - - /** - * @brief Fills a buffer with the type info objects for the writable - * resources of a vertex. - * @param buffer A buffer pre-allocated by the user. - * @param length The length of the user-supplied buffer. - * @return The number of type info objects written to the buffer. - */ - [[nodiscard]] size_type ro_dependency(const type_info **buffer, const stl::size_t length) const noexcept { - return node.dependency(false, buffer, length); - } - - /** - * @brief Fills a buffer with the type info objects for the read-only - * resources of a vertex. - * @param buffer A buffer pre-allocated by the user. - * @param length The length of the user-supplied buffer. - * @return The number of type info objects written to the buffer. - */ - [[nodiscard]] size_type rw_dependency(const type_info **buffer, const stl::size_t length) const noexcept { - return node.dependency(true, buffer, length); - } - - /** - * @brief Returns the number of read-only resources of a vertex. - * @return The number of read-only resources of the vertex. - */ - [[nodiscard]] size_type ro_count() const noexcept { - return node.ro_count; - } - - /** - * @brief Returns the number of writable resources of a vertex. - * @return The number of writable resources of the vertex. - */ - [[nodiscard]] size_type rw_count() const noexcept { - return node.rw_count; - } - - /** - * @brief Checks if a vertex is also a top-level one. - * @return True if the vertex is a top-level one, false otherwise. - */ - [[nodiscard]] bool top_level() const noexcept { - return in.empty(); - } - - /** - * @brief Returns a type info object associated with a vertex. - * @return A properly initialized type info object. - */ - [[nodiscard]] const type_info &info() const noexcept { - return *node.info; - } - - /** - * @brief Returns a user defined name associated with a vertex, if any. - * @return The user defined name associated with the vertex, if any. - */ - [[nodiscard]] const char *name() const noexcept { - return node.name; - } - - /** - * @brief Returns the function associated with a vertex. - * @return The function associated with the vertex. - */ - [[nodiscard]] function_type *callback() const noexcept { - return node.callback; - } - - /** - * @brief Returns the payload associated with a vertex, if any. - * @return The payload associated with the vertex, if any. - */ - [[nodiscard]] const void *data() const noexcept { - return node.payload; - } - - /** - * @brief Returns the list of in-edges of a vertex. - * @return The list of in-edges of a vertex. - */ - [[nodiscard]] const stl::vector &in_edges() const noexcept { - return in; - } - - /** - * @brief Returns the list of out-edges of a vertex. - * @return The list of out-edges of a vertex. - */ - [[nodiscard]] const stl::vector &out_edges() const noexcept { - return out; - } - - /** - * @brief Prepares a registry and assures that all required resources - * are properly instantiated before using them. - * @param reg A valid registry. - */ - void prepare(registry_type ®) const { - node.prepare ? node.prepare(reg) : void(); - } - - private: - vertex_data node; - stl::vector in; - stl::vector out; - }; - - /** - * @brief Adds a free function to the task list. - * @tparam Candidate Function to add to the task list. - * @tparam Req Additional requirements and/or override resource access mode. - * @param name Optional name to associate with the task. - */ - template - void emplace(const char *name = nullptr) { - using resource_type = decltype(internal::free_function_to_resource_traits(Candidate)); - - callback_type *callback = +[](const void *, registry_type ®) { - stl::apply(Candidate, to_args(reg, typename resource_type::args{})); - }; - - vertex_data vdata{ - resource_type::ro::size, - resource_type::rw::size, - name, - nullptr, - callback, - +[](const bool rw, const type_info **buffer, const stl::size_t length) { return rw ? fill_dependencies(typename resource_type::rw{}, buffer, length) : fill_dependencies(typename resource_type::ro{}, buffer, length); }, - +[](registry_type ®) { void(to_args(reg, typename resource_type::args{})); }, - &type_id>()}; - - track_dependencies(vertices.size(), resource_type::sync_point, typename resource_type::ro{}, typename resource_type::rw{}); - vertices.push_back(stl::move(vdata)); - } - - /** - * @brief Adds a free function with payload or a member function with an - * instance to the task list. - * @tparam Candidate Function or member to add to the task list. - * @tparam Req Additional requirements and/or override resource access mode. - * @tparam Type Type of class or type of payload. - * @param value_or_instance A valid object that fits the purpose. - * @param name Optional name to associate with the task. - */ - template - void emplace(Type &value_or_instance, const char *name = nullptr) { - using resource_type = decltype(internal::constrained_function_to_resource_traits(Candidate)); - - callback_type *callback = +[](const void *payload, registry_type ®) { - Type *curr = static_cast(const_cast *>(payload)); - stl::apply(Candidate, stl::tuple_cat(stl::forward_as_tuple(*curr), to_args(reg, typename resource_type::args{}))); - }; - - vertex_data vdata{ - resource_type::ro::size, - resource_type::rw::size, - name, - &value_or_instance, - callback, - +[](const bool rw, const type_info **buffer, const stl::size_t length) { return rw ? fill_dependencies(typename resource_type::rw{}, buffer, length) : fill_dependencies(typename resource_type::ro{}, buffer, length); }, - +[](registry_type ®) { void(to_args(reg, typename resource_type::args{})); }, - &type_id>()}; - - track_dependencies(vertices.size(), resource_type::sync_point, typename resource_type::ro{}, typename resource_type::rw{}); - vertices.push_back(stl::move(vdata)); - } - - /** - * @brief Adds an user defined function with optional payload to the task - * list. - * @tparam Req Additional requirements and/or override resource access mode. - * @param func Function to add to the task list. - * @param payload User defined arbitrary data. - * @param name Optional name to associate with the task. - */ - template - void emplace(function_type *func, const void *payload = nullptr, const char *name = nullptr) { - using resource_type = internal::resource_traits, type_list>; - track_dependencies(vertices.size(), true, typename resource_type::ro{}, typename resource_type::rw{}); - - vertex_data vdata{ - resource_type::ro::size, - resource_type::rw::size, - name, - payload, - func, - +[](const bool rw, const type_info **buffer, const stl::size_t length) { return rw ? fill_dependencies(typename resource_type::rw{}, buffer, length) : fill_dependencies(typename resource_type::ro{}, buffer, length); }, - nullptr, - &type_id()}; - - vertices.push_back(stl::move(vdata)); - } - - /** - * @brief Generates a task graph for the current content. - * @return The adjacency list of the task graph. - */ - [[nodiscard]] stl::vector graph() const { - stl::vector adjacency_list{}; - adjacency_list.reserve(vertices.size()); - - for(auto adjacency_matrix = builder.graph(); auto curr: adjacency_matrix.vertices()) { - stl::vector in{}; - stl::vector out{}; - - for(auto &&edge: adjacency_matrix.in_edges(curr)) { - in.push_back(edge.first); - } - - for(auto &&edge: adjacency_matrix.out_edges(curr)) { - out.push_back(edge.second); - } - - adjacency_list.emplace_back(vertices[curr], stl::move(in), stl::move(out)); - } - - return adjacency_list; - } - - /*! @brief Erases all elements from a container. */ - void clear() { - builder.clear(); - vertices.clear(); - } - -private: - stl::vector vertices; - flow builder; -}; - -} // namespace entt - -#endif diff --git a/include/entt/entity/ranges.hpp b/include/entt/entity/ranges.hpp deleted file mode 100644 index 284e5f5..0000000 --- a/include/entt/entity/ranges.hpp +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef ENTT_ENTITY_RANGES_HPP -#define ENTT_ENTITY_RANGES_HPP - -#include - -#if defined(__cpp_lib_ranges) -# include -# include "fwd.hpp" - -namespace std::ranges { - -template -inline constexpr bool enable_borrowed_range>{true}; - -template -inline constexpr bool enable_borrowed_range>{true}; - -template -inline constexpr bool enable_view>{true}; - -template -inline constexpr bool enable_view>{true}; - -} // namespace std::ranges - -#endif - -#endif diff --git a/include/entt/entity/registry.hpp b/include/entt/entity/registry.hpp deleted file mode 100644 index 4123b5c..0000000 --- a/include/entt/entity/registry.hpp +++ /dev/null @@ -1,1181 +0,0 @@ -#ifndef ENTT_ENTITY_REGISTRY_HPP -#define ENTT_ENTITY_REGISTRY_HPP - -#include -#include "../config/config.h" -#include "../container/dense_map.hpp" -#include "../core/algorithm.hpp" -#include "../core/any.hpp" -#include "../core/concepts.hpp" -#include "../core/fwd.hpp" -#include "../core/iterator.hpp" -#include "../core/memory.hpp" -#include "../core/type_info.hpp" -#include "../core/type_traits.hpp" -#include "../stl/algorithm.hpp" -#include "../stl/array.hpp" -#include "../stl/concepts.hpp" -#include "../stl/cstddef.hpp" -#include "../stl/functional.hpp" -#include "../stl/iterator.hpp" -#include "../stl/memory.hpp" -#include "../stl/tuple.hpp" -#include "../stl/type_traits.hpp" -#include "../stl/utility.hpp" -#include "entity.hpp" -#include "fwd.hpp" -#include "group.hpp" -#include "mixin.hpp" -#include "sparse_set.hpp" -#include "storage.hpp" -#include "view.hpp" - -namespace entt { - -/*! @cond ENTT_INTERNAL */ -namespace internal { - -template -class registry_storage_iterator final { - template - friend class registry_storage_iterator; - - using mapped_type = stl::remove_reference_t()->second)>; - -public: - using value_type = stl::pair &>; - using pointer = input_iterator_pointer; - using reference = value_type; - using difference_type = stl::ptrdiff_t; - using iterator_category = stl::input_iterator_tag; - using iterator_concept = stl::random_access_iterator_tag; - - constexpr registry_storage_iterator() noexcept - : it{} {} - - constexpr registry_storage_iterator(It iter) noexcept - : it{iter} {} - - template - requires (!stl::same_as && stl::constructible_from) - constexpr registry_storage_iterator(const registry_storage_iterator &other) noexcept - : registry_storage_iterator{other.it} {} - - constexpr registry_storage_iterator &operator++() noexcept { - return ++it, *this; - } - - constexpr registry_storage_iterator operator++(int) noexcept { - const registry_storage_iterator orig = *this; - return ++(*this), orig; - } - - constexpr registry_storage_iterator &operator--() noexcept { - return --it, *this; - } - - constexpr registry_storage_iterator operator--(int) noexcept { - const registry_storage_iterator orig = *this; - return operator--(), orig; - } - - constexpr registry_storage_iterator &operator+=(const difference_type value) noexcept { - it += value; - return *this; - } - - constexpr registry_storage_iterator operator+(const difference_type value) const noexcept { - registry_storage_iterator copy = *this; - return (copy += value); - } - - constexpr registry_storage_iterator &operator-=(const difference_type value) noexcept { - return (*this += -value); - } - - constexpr registry_storage_iterator operator-(const difference_type value) const noexcept { - return (*this + -value); - } - - [[nodiscard]] constexpr reference operator[](const difference_type value) const noexcept { - return {it[value].first, *it[value].second}; - } - - [[nodiscard]] constexpr reference operator*() const noexcept { - return operator[](0); - } - - [[nodiscard]] constexpr pointer operator->() const noexcept { - return operator*(); - } - - template - [[nodiscard]] constexpr stl::ptrdiff_t operator-(const registry_storage_iterator &other) const noexcept { - return it - other.it; - } - - template - [[nodiscard]] constexpr bool operator==(const registry_storage_iterator &other) const noexcept { - return it == other.it; - } - - template - [[nodiscard]] constexpr auto operator<=>(const registry_storage_iterator &other) const noexcept { - return it <=> other.it; - } - -private: - It it; -}; - -template -class registry_context { - using alloc_traits = stl::allocator_traits; - using allocator_type = alloc_traits::template rebind_alloc>>; - -public: - explicit registry_context(const allocator_type &allocator) - : ctx{allocator} {} - - void clear() noexcept { - ctx.clear(); - } - - template - Type &emplace_as(const id_type id, Args &&...args) { - return any_cast(ctx.try_emplace(id, stl::in_place_type, stl::forward(args)...).first->second); - } - - template - Type &emplace(Args &&...args) { - return emplace_as(type_id().hash(), stl::forward(args)...); - } - - template - Type &insert_or_assign(const id_type id, Type &&value) { - return any_cast &>(ctx.insert_or_assign(id, stl::forward(value)).first->second); - } - - template - Type &insert_or_assign(Type &&value) { - return insert_or_assign(type_id().hash(), stl::forward(value)); - } - - template - bool erase(const id_type id = type_id().hash()) { - const auto it = ctx.find(id); - return it != ctx.end() && it->second.info() == type_id() ? (ctx.erase(it), true) : false; - } - - template - [[nodiscard]] const Type &get(const id_type id = type_id().hash()) const { - return any_cast(ctx.at(id)); - } - - template - [[nodiscard]] Type &get(const id_type id = type_id().hash()) { - return any_cast(ctx.at(id)); - } - - template - [[nodiscard]] const Type *find(const id_type id = type_id().hash()) const { - const auto it = ctx.find(id); - return it != ctx.cend() ? any_cast(&it->second) : nullptr; - } - - template - [[nodiscard]] Type *find(const id_type id = type_id().hash()) { - const auto it = ctx.find(id); - return it != ctx.end() ? any_cast(&it->second) : nullptr; - } - - template - [[nodiscard]] bool contains(const id_type id = type_id().hash()) const { - const auto it = ctx.find(id); - return it != ctx.cend() && it->second.info() == type_id(); - } - -private: - dense_map, stl::identity, stl::equal_to<>, allocator_type> ctx; -}; - -} // namespace internal -/*! @endcond */ - -/** - * @brief Fast and reliable entity-component system. - * @tparam Entity A valid entity type. - * @tparam Allocator Type of allocator used to manage memory and elements. - */ -template -class basic_registry { - using base_type = basic_sparse_set; - using alloc_traits = stl::allocator_traits; - static_assert(stl::is_same_v, "Invalid value type"); - // stl::shared_ptr because of its type erased allocator which is useful here - using pool_container_type = dense_map, stl::identity, stl::equal_to<>, typename alloc_traits::template rebind_alloc>>>; - using group_container_type = dense_map, stl::identity, stl::equal_to<>, typename alloc_traits::template rebind_alloc>>>; - using traits_type = entt_traits; - - template - [[nodiscard]] auto &assure([[maybe_unused]] const id_type id = type_hash::value()) { - if constexpr(stl::is_same_v) { - ENTT_ASSERT(id == type_hash::value(), "User entity storage not allowed"); - return entities; - } else { - using storage_type = storage_for_type; - - if(auto it = pools.find(id); it != pools.cend()) { - ENTT_ASSERT(it->second->info() == type_id(), "Unexpected type"); - return static_cast(*it->second); - } - - typename pool_container_type::mapped_type cpool = stl::allocate_shared(get_allocator(), get_allocator()); - pools.emplace(id, cpool); - cpool->bind(*this); - - return static_cast(*cpool); - } - } - - template - [[nodiscard]] const auto *assure([[maybe_unused]] const id_type id = type_hash::value()) const { - if constexpr(stl::is_same_v) { - ENTT_ASSERT(id == type_hash::value(), "User entity storage not allowed"); - return &entities; - } else { - if(const auto it = pools.find(id); it != pools.cend()) { - ENTT_ASSERT(it->second->info() == type_id(), "Unexpected type"); - return static_cast *>(it->second.get()); - } - - return static_cast *>(nullptr); - } - } - - void rebind() { - entities.bind(*this); - - for(auto &&curr: pools) { - curr.second->bind(*this); - } - } - -public: - /*! @brief Allocator type. */ - using allocator_type = Allocator; - /*! @brief Underlying entity identifier. */ - using entity_type = traits_type::value_type; - /*! @brief Underlying version type. */ - using version_type = traits_type::version_type; - /*! @brief Unsigned integer type. */ - using size_type = stl::size_t; - /*! @brief Common type among all storage types. */ - using common_type = base_type; - /*! @brief Context type. */ - using context = internal::registry_context; - /*! @brief Iterable registry type. */ - using iterable = iterable_adaptor>; - /*! @brief Constant iterable registry type. */ - using const_iterable = iterable_adaptor>; - - /** - * @copybrief storage_for - * @tparam Type Storage value type, eventually const. - */ - template - using storage_for_type = storage_for>>::type; - - /*! @brief Default constructor. */ - basic_registry() - : basic_registry{allocator_type{}} {} - - /** - * @brief Constructs an empty registry with a given allocator. - * @param allocator The allocator to use. - */ - explicit basic_registry(const allocator_type &allocator) - : basic_registry{0u, allocator} {} - - /** - * @brief Allocates enough memory upon construction to store `count` pools. - * @param count The number of pools to allocate memory for. - * @param allocator The allocator to use. - */ - basic_registry(const size_type count, const allocator_type &allocator = allocator_type{}) - : vars{allocator}, - pools{allocator}, - groups{allocator}, - entities{allocator} { - pools.reserve(count); - rebind(); - } - - /*! @brief Default copy constructor, deleted on purpose. */ - basic_registry(const basic_registry &) = delete; - - /** - * @brief Move constructor. - * @param other The instance to move from. - */ - basic_registry(basic_registry &&other) noexcept - : vars{stl::move(other.vars)}, - pools{stl::move(other.pools)}, - groups{stl::move(other.groups)}, - entities{stl::move(other.entities)} { - rebind(); - } - - /*! @brief Default destructor. */ - ~basic_registry() = default; - - /** - * @brief Default copy assignment operator, deleted on purpose. - * @return This mixin. - */ - basic_registry &operator=(const basic_registry &) = delete; - - /** - * @brief Move assignment operator. - * @param other The instance to move from. - * @return This registry. - */ - basic_registry &operator=(basic_registry &&other) noexcept { - swap(other); - return *this; - } - - /** - * @brief Exchanges the contents with those of a given registry. - * @param other Registry to exchange the content with. - */ - void swap(basic_registry &other) noexcept { - using stl::swap; - - swap(vars, other.vars); - swap(pools, other.pools); - swap(groups, other.groups); - swap(entities, other.entities); - - rebind(); - other.rebind(); - } - - /** - * @brief Returns the associated allocator. - * @return The associated allocator. - */ - [[nodiscard]] constexpr allocator_type get_allocator() const noexcept { - return entities.get_allocator(); - } - - /** - * @brief Returns an iterable object to use to _visit_ a registry. - * - * The iterable object returns a pair that contains the name and a reference - * to the current storage. - * - * @return An iterable object to use to _visit_ the registry. - */ - [[nodiscard]] iterable storage() noexcept { - return iterable{pools.begin(), pools.end()}; - } - - /*! @copydoc storage */ - [[nodiscard]] const_iterable storage() const noexcept { - return const_iterable{pools.cbegin(), pools.cend()}; - } - - /** - * @brief Finds the storage associated with a given name, if any. - * @param id Name used to map the storage within the registry. - * @return A pointer to the storage if it exists, a null pointer otherwise. - */ - [[nodiscard]] common_type *storage(const id_type id) { - return const_cast(stl::as_const(*this).storage(id)); - } - - /** - * @brief Finds the storage associated with a given name, if any. - * @param id Name used to map the storage within the registry. - * @return A pointer to the storage if it exists, a null pointer otherwise. - */ - [[nodiscard]] const common_type *storage(const id_type id) const { - const auto it = pools.find(id); - return it == pools.cend() ? nullptr : it->second.get(); - } - - /** - * @brief Returns the storage for a given element type. - * @tparam Type Type of element of which to return the storage. - * @param id Optional name used to map the storage within the registry. - * @return The storage for the given element type. - */ - template - storage_for_type &storage(const id_type id = type_hash::value()) { - return assure>(id); - } - - /** - * @brief Returns the storage for a given element type, if any. - * @tparam Type Type of element of which to return the storage. - * @param id Optional name used to map the storage within the registry. - * @return The storage for the given element type. - */ - template - [[nodiscard]] const storage_for_type *storage(const id_type id = type_hash::value()) const { - return assure>(id); - } - - /** - * @brief Discards the storage associated with a given name, if any. - * @param id Name used to map the storage within the registry. - * @return True in case of success, false otherwise. - */ - bool reset(const id_type id) { - ENTT_ASSERT(id != type_hash::value(), "Cannot reset entity storage"); - return !(pools.erase(id) == 0u); - } - - /** - * @brief Checks if an identifier refers to a valid entity. - * @param entt An identifier, either valid or not. - * @return True if the identifier is valid, false otherwise. - */ - [[nodiscard]] bool valid(const entity_type entt) const { - return static_cast(entities.find(entt).index()) < entities.free_list(); - } - - /** - * @brief Returns the actual version for an identifier. - * @param entt A valid identifier. - * @return The version for the given identifier if valid, the tombstone - * version otherwise. - */ - [[nodiscard]] version_type current(const entity_type entt) const { - return entities.current(entt); - } - - /** - * @brief Creates a new entity or recycles a destroyed one. - * @return A valid identifier. - */ - [[nodiscard]] entity_type create() { - return entities.generate(); - } - - /** - * @copybrief create - * - * If the requested entity isn't in use, the suggested identifier is used. - * Otherwise, a new identifier is generated. - * - * @param hint Required identifier. - * @return A valid identifier. - */ - [[nodiscard]] entity_type create(const entity_type hint) { - return entities.generate(hint); - } - - /** - * @brief Assigns each element in a range an identifier. - * - * @sa create - * - * @tparam It Type of output iterator. - * @param first An iterator to the first element of the range to generate. - * @param last An iterator past the last element of the range to generate. - */ - template It> - void create(It first, It last) { - entities.generate(stl::move(first), stl::move(last)); - } - - /** - * @brief Destroys an entity and releases its identifier. - * - * @warning - * Adding or removing elements to an entity that is being destroyed can - * result in undefined behavior. - * - * @param entt A valid identifier. - * @return The version of the recycled entity. - */ - version_type destroy(const entity_type entt) { - for(size_type pos = pools.size(); pos != 0u; --pos) { - pools.begin()[static_cast(pos - 1u)].second->remove(entt); - } - - entities.erase(entt); - return entities.current(entt); - } - - /** - * @brief Destroys an entity and releases its identifier. - * - * The suggested version or the valid version closest to the suggested one - * is used instead of the implicitly generated version. - * - * @sa destroy - * - * @param entt A valid identifier. - * @param version A desired version upon destruction. - * @return The version actually assigned to the entity. - */ - version_type destroy(const entity_type entt, const version_type version) { - destroy(entt); - const auto elem = traits_type::construct(traits_type::to_entity(entt), version); - return entities.bump((elem == tombstone) ? traits_type::next(elem) : elem); - } - - /** - * @brief Destroys all entities in a range and releases their identifiers. - * - * @sa destroy - * - * @param first An iterator to the first element of the range of entities. - * @param last An iterator past the last element of the range of entities. - */ - void destroy(stl::input_iterator auto first, stl::input_iterator auto last) { - const auto to = entities.sort_as(first, last); - const auto from = entities.cend() - static_cast(entities.free_list()); - - for(auto &&curr: pools) { - curr.second->remove(from, to); - } - - entities.erase(from, to); - } - - /** - * @brief Assigns the given element to an entity. - * - * The element must have a proper constructor or be of aggregate type. - * - * @warning - * Attempting to assign an element to an entity that already owns it results - * in undefined behavior. - * - * @tparam Type Type of element to create. - * @tparam Args Types of arguments to use to construct the element. - * @param entt A valid identifier. - * @param args Parameters to use to initialize the element. - * @return A reference to the newly created element. - */ - template - decltype(auto) emplace(const entity_type entt, Args &&...args) { - ENTT_ASSERT(valid(entt), "Invalid entity"); - return assure().emplace(entt, stl::forward(args)...); - } - - /** - * @brief Assigns each entity in a range the given element. - * - * @sa emplace - * - * @tparam Type Type of element to create. - * @param first An iterator to the first element of the range of entities. - * @param last An iterator past the last element of the range of entities. - * @param value An instance of the element to assign. - */ - template - void insert(stl::input_iterator auto first, stl::input_iterator auto last, const Type &value = {}) { - ENTT_ASSERT(stl::all_of(first, last, [this](const auto entt) { return valid(entt); }), "Invalid entity"); - assure().insert(stl::move(first), stl::move(last), value); - } - - /** - * @brief Assigns each entity in a range the given elements. - * - * @sa emplace - * - * @tparam Type Type of element to create. - * @tparam EIt Type of input iterator. - * @tparam CIt Type of input iterator. - * @param first An iterator to the first element of the range of entities. - * @param last An iterator past the last element of the range of entities. - * @param from An iterator to the first element of the range of elements. - */ - template - requires stl::same_as::value_type, Type> - void insert(EIt first, EIt last, CIt from) { - ENTT_ASSERT(stl::all_of(first, last, [this](const auto entt) { return valid(entt); }), "Invalid entity"); - assure().insert(first, last, from); - } - - /** - * @brief Assigns or replaces the given element for an entity. - * - * @sa emplace - * @sa replace - * - * @tparam Type Type of element to assign or replace. - * @tparam Args Types of arguments to use to construct the element. - * @param entt A valid identifier. - * @param args Parameters to use to initialize the element. - * @return A reference to the newly created element. - */ - template - decltype(auto) emplace_or_replace(const entity_type entt, Args &&...args) { - auto &cpool = assure(); - ENTT_ASSERT(valid(entt), "Invalid entity"); - return cpool.contains(entt) ? cpool.patch(entt, [&args...](auto &...curr) { ((curr = Type{stl::forward(args)...}), ...); }) : cpool.emplace(entt, stl::forward(args)...); - } - - /** - * @brief Patches the given element for an entity. - * - * The signature of the function should be equivalent to the following: - * - * @code{.cpp} - * void(Type &); - * @endcode - * - * @warning - * Attempting to patch an element of an entity that doesn't own it results - * in undefined behavior. - * - * @tparam Type Type of element to patch. - * @tparam Func Types of the function objects to invoke. - * @param entt A valid identifier. - * @param func Valid function objects. - * @return A reference to the patched element. - */ - template - decltype(auto) patch(const entity_type entt, Func &&...func) { - return assure().patch(entt, stl::forward(func)...); - } - - /** - * @brief Replaces the given element for an entity. - * - * The element must have a proper constructor or be of aggregate type. - * - * @warning - * Attempting to replace an element of an entity that doesn't own it results - * in undefined behavior. - * - * @tparam Type Type of element to replace. - * @tparam Args Types of arguments to use to construct the element. - * @param entt A valid identifier. - * @param args Parameters to use to initialize the element. - * @return A reference to the element being replaced. - */ - template - decltype(auto) replace(const entity_type entt, Args &&...args) { - return patch(entt, [&args...](auto &...curr) { ((curr = Type{stl::forward(args)...}), ...); }); - } - - /** - * @brief Removes the given elements from an entity. - * @tparam Type Type of element to remove. - * @tparam Other Other types of elements to remove. - * @param entt A valid identifier. - * @return The number of elements actually removed. - */ - template - size_type remove(const entity_type entt) { - return (assure().remove(entt) + ... + assure().remove(entt)); - } - - /** - * @brief Removes the given elements from all the entities in a range. - * - * @sa remove - * - * @tparam Type Type of element to remove. - * @tparam Other Other types of elements to remove. - * @tparam It Type of input iterator. - * @param first An iterator to the first element of the range of entities. - * @param last An iterator past the last element of the range of entities. - * @return The number of elements actually removed. - */ - template - size_type remove(It first, It last) { - size_type count{}; - - if constexpr(stl::is_same_v) { - stl::array cpools{static_cast(&assure()), static_cast(&assure())...}; - - for(auto from = cpools.begin(), to = cpools.end(); from != to; ++from) { - if constexpr(sizeof...(Other) != 0u) { - if((*from)->data() == first.data()) { - stl::swap((*from), cpools.back()); - } - } - - count += (*from)->remove(first, last); - } - - } else { - for(auto cpools = stl::forward_as_tuple(assure(), assure()...); first != last; ++first) { - count += stl::apply([entt = *first](auto &...curr) { return (curr.remove(entt) + ... + 0u); }, cpools); - } - } - - return count; - } - - /** - * @brief Erases the given elements from an entity. - * - * @warning - * Attempting to erase an element from an entity that doesn't own it results - * in undefined behavior. - * - * @tparam Type Types of elements to erase. - * @tparam Other Other types of elements to erase. - * @param entt A valid identifier. - */ - template - void erase(const entity_type entt) { - (assure().erase(entt), (assure().erase(entt), ...)); - } - - /** - * @brief Erases the given elements from all the entities in a range. - * - * @sa erase - * - * @tparam Type Types of elements to erase. - * @tparam Other Other types of elements to erase. - * @tparam It Type of input iterator. - * @param first An iterator to the first element of the range of entities. - * @param last An iterator past the last element of the range of entities. - */ - template - void erase(It first, It last) { - if constexpr(stl::is_same_v) { - stl::array cpools{static_cast(&assure()), static_cast(&assure())...}; - - for(auto from = cpools.begin(), to = cpools.end(); from != to; ++from) { - if constexpr(sizeof...(Other) != 0u) { - if((*from)->data() == first.data()) { - stl::swap(*from, cpools.back()); - } - } - - (*from)->erase(first, last); - } - } else { - for(auto cpools = stl::forward_as_tuple(assure(), assure()...); first != last; ++first) { - stl::apply([entt = *first](auto &...curr) { (curr.erase(entt), ...); }, cpools); - } - } - } - - /** - * @brief Erases elements satisfying specific criteria from an entity. - * - * The function type is equivalent to: - * - * @code{.cpp} - * void(const id_type, typename basic_registry::common_type &); - * @endcode - * - * Only storage where the entity exists are passed to the function. - * - * @tparam Func Type of the function object to invoke. - * @param entt A valid identifier. - * @param func A valid function object. - */ - template - void erase_if(const entity_type entt, Func func) { - for(auto [id, cpool]: storage()) { - if(cpool.contains(entt) && func(id, stl::as_const(cpool))) { - cpool.erase(entt); - } - } - } - - /** - * @brief Removes all tombstones from a registry or only the pools for the - * given elements. - * @tparam Type Types of elements for which to clear all tombstones. - */ - template - void compact() { - if constexpr(sizeof...(Type) == 0u) { - for(auto &&curr: pools) { - curr.second->compact(); - } - } else { - (assure().compact(), ...); - } - } - - /** - * @brief Check if an entity is part of all the given storage. - * @tparam Type Type of storage to check for. - * @param entt A valid identifier. - * @return True if the entity is part of all the storage, false otherwise. - */ - template - [[nodiscard]] bool all_of([[maybe_unused]] const entity_type entt) const { - if constexpr(sizeof...(Type) == 1u) { - auto *cpool = assure...>(); - return cpool && cpool->contains(entt); - } else { - return (all_of(entt) && ...); - } - } - - /** - * @brief Check if an entity is part of at least one given storage. - * @tparam Type Type of storage to check for. - * @param entt A valid identifier. - * @return True if the entity is part of at least one storage, false - * otherwise. - */ - template - [[nodiscard]] bool any_of([[maybe_unused]] const entity_type entt) const { - return (all_of(entt) || ...); - } - - /** - * @brief Returns references to the given elements for an entity. - * - * @warning - * Attempting to get an element from an entity that doesn't own it results - * in undefined behavior. - * - * @tparam Type Types of elements to get. - * @param entt A valid identifier. - * @return References to the elements owned by the entity. - */ - template - [[nodiscard]] decltype(auto) get([[maybe_unused]] const entity_type entt) const { - if constexpr(sizeof...(Type) == 1u) { - return (assure>()->get(entt), ...); - } else { - return stl::forward_as_tuple(get(entt)...); - } - } - - /*! @copydoc get */ - template - [[nodiscard]] decltype(auto) get([[maybe_unused]] const entity_type entt) { - if constexpr(sizeof...(Type) == 1u) { - return (static_cast &>(assure>()).get(entt), ...); - } else { - return stl::forward_as_tuple(get(entt)...); - } - } - - /** - * @brief Returns a reference to the given element for an entity. - * - * In case the entity doesn't own the element, the parameters provided are - * used to construct it. - * - * @sa get - * @sa emplace - * - * @tparam Type Type of element to get. - * @tparam Args Types of arguments to use to construct the element. - * @param entt A valid identifier. - * @param args Parameters to use to initialize the element. - * @return Reference to the element owned by the entity. - */ - template - [[nodiscard]] decltype(auto) get_or_emplace(const entity_type entt, Args &&...args) { - auto &cpool = assure(); - ENTT_ASSERT(valid(entt), "Invalid entity"); - return cpool.contains(entt) ? cpool.get(entt) : cpool.emplace(entt, stl::forward(args)...); - } - - /** - * @brief Returns pointers to the given elements for an entity. - * - * @note - * The registry retains ownership of the pointed-to elements. - * - * @tparam Type Types of elements to get. - * @param entt A valid identifier. - * @return Pointers to the elements owned by the entity. - */ - template - [[nodiscard]] auto try_get([[maybe_unused]] const entity_type entt) const { - if constexpr(sizeof...(Type) == 1u) { - const auto *cpool = assure...>(); - return (cpool && cpool->contains(entt)) ? stl::addressof(cpool->get(entt)) : nullptr; - } else { - return stl::make_tuple(try_get(entt)...); - } - } - - /*! @copydoc try_get */ - template - [[nodiscard]] auto try_get([[maybe_unused]] const entity_type entt) { - if constexpr(sizeof...(Type) == 1u) { - return (const_cast(stl::as_const(*this).template try_get(entt)), ...); - } else { - return stl::make_tuple(try_get(entt)...); - } - } - - /** - * @brief Clears a whole registry or the pools for the given elements. - * @tparam Type Types of elements to remove from their entities. - */ - template - void clear() { - if constexpr(sizeof...(Type) == 0u) { - for(size_type pos = pools.size(); pos; --pos) { - pools.begin()[static_cast(pos - 1u)].second->clear(); - } - - const auto elem = entities.each(); - entities.erase(elem.begin().base(), elem.end().base()); - } else { - (assure().clear(), ...); - } - } - - /** - * @brief Checks if an entity has elements assigned. - * @param entt A valid identifier. - * @return True if the entity has no elements assigned, false otherwise. - */ - [[nodiscard]] bool orphan(const entity_type entt) const { - return stl::none_of(pools.cbegin(), pools.cend(), [entt](auto &&curr) { return curr.second->contains(entt); }); - } - - /** - * @brief Returns a sink object for the given element. - * - * Use this function to receive notifications whenever a new instance of the - * given element is created and assigned to an entity.
- * The function type for a listener is equivalent to: - * - * @code{.cpp} - * void(basic_registry &, Entity); - * @endcode - * - * Listeners are invoked **after** assigning the element to the entity. - * - * @sa sink - * - * @tparam Type Type of element of which to get the sink. - * @param id Optional name used to map the storage within the registry. - * @return A temporary sink object. - */ - template - [[nodiscard]] auto on_construct(const id_type id = type_hash::value()) { - return assure(id).on_construct(); - } - - /** - * @brief Returns a sink object for the given element. - * - * Use this function to receive notifications whenever an instance of the - * given element is explicitly updated.
- * The function type for a listener is equivalent to: - * - * @code{.cpp} - * void(basic_registry &, Entity); - * @endcode - * - * Listeners are invoked **after** updating the element. - * - * @sa sink - * - * @tparam Type Type of element of which to get the sink. - * @param id Optional name used to map the storage within the registry. - * @return A temporary sink object. - */ - template - [[nodiscard]] auto on_update(const id_type id = type_hash::value()) { - return assure(id).on_update(); - } - - /** - * @brief Returns a sink object for the given element. - * - * Use this function to receive notifications whenever an instance of the - * given element is removed from an entity and thus destroyed.
- * The function type for a listener is equivalent to: - * - * @code{.cpp} - * void(basic_registry &, Entity); - * @endcode - * - * Listeners are invoked **before** removing the element from the entity. - * - * @sa sink - * - * @tparam Type Type of element of which to get the sink. - * @param id Optional name used to map the storage within the registry. - * @return A temporary sink object. - */ - template - [[nodiscard]] auto on_destroy(const id_type id = type_hash::value()) { - return assure(id).on_destroy(); - } - - /** - * @brief Returns a view for the given elements. - * @tparam Type Type of element used to construct the view. - * @tparam Other Other types of elements used to construct the view. - * @tparam Exclude Types of elements used to filter the view. - * @return A newly created view. - */ - template - [[nodiscard]] basic_view, storage_for_type...>, exclude_t...>> - view(exclude_t = exclude_t{}) const { - basic_view, storage_for_type...>, exclude_t...>> elem{}; - [&elem](const auto *...curr) { ((curr ? elem.storage(*curr) : void()), ...); }(assure>()..., assure>()..., assure>()); - return elem; - } - - /*! @copydoc view */ - template - [[nodiscard]] basic_view, storage_for_type...>, exclude_t...>> - view(exclude_t = exclude_t{}) { - return {assure>(), assure>()..., assure>()...}; - } - - /** - * @brief Returns a group for the given elements. - * @tparam Owned Types of storage _owned_ by the group. - * @tparam Get Types of storage _observed_ by the group, if any. - * @tparam Exclude Types of storage used to filter the group, if any. - * @return A newly created group. - */ - template - basic_group...>, get_t...>, exclude_t...>> - group(get_t = get_t{}, exclude_t = exclude_t{}) { - using group_type = basic_group...>, get_t...>, exclude_t...>>; - using handler_type = group_type::handler; - - if(auto it = groups.find(group_type::group_id()); it != groups.cend()) { - return {*stl::static_pointer_cast(it->second)}; - } - - stl::shared_ptr handler{}; - - if constexpr(sizeof...(Owned) == 0u) { - handler = stl::allocate_shared(get_allocator(), get_allocator(), stl::forward_as_tuple(assure>()...), stl::forward_as_tuple(assure>()...)); - } else { - handler = stl::allocate_shared(get_allocator(), stl::forward_as_tuple(assure>()..., assure>()...), stl::forward_as_tuple(assure>()...)); - ENTT_ASSERT(stl::all_of(groups.cbegin(), groups.cend(), [](const auto &data) { return !(data.second->owned(type_id().hash()) || ...); }), "Conflicting groups"); - } - - groups.emplace(group_type::group_id(), handler); - return {*handler}; - } - - /*! @copydoc group */ - template - [[nodiscard]] basic_group...>, get_t...>, exclude_t...>> - group_if_exists(get_t = get_t{}, exclude_t = exclude_t{}) const { - using group_type = basic_group...>, get_t...>, exclude_t...>>; - using handler_type = group_type::handler; - - if(auto it = groups.find(group_type::group_id()); it != groups.cend()) { - return {*stl::static_pointer_cast(it->second)}; - } - - return {}; - } - - /** - * @brief Checks whether the given elements belong to any group. - * @tparam Type Types of elements in which one is interested. - * @return True if the pools of the given elements are _free_, false - * otherwise. - */ - template - [[nodiscard]] bool owned() const { - return stl::any_of(groups.cbegin(), groups.cend(), [](auto &&data) { return (data.second->owned(type_id().hash()) || ...); }); - } - - /** - * @brief Sorts the elements of a given element. - * - * The comparison function object returns `true` if the first element is - * _less_ than the second one, `false` otherwise. Its signature is also - * equivalent to one of the following: - * - * @code{.cpp} - * bool(const Entity, const Entity); - * bool(const Type &, const Type &); - * @endcode - * - * Moreover, it shall induce a _strict weak ordering_ on the values.
- * The sort function object offers an `operator()` that accepts: - * - * * 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 object to use to compare the elements. - * - * The comparison function object hasn't necessarily the type of the one - * passed along with the other parameters to this member function. - * - * @warning - * Pools of elements owned by a group cannot be sorted. - * - * @tparam Type Type of elements 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 algo A valid sort function object. - * @param args Arguments to forward to the sort function object, if any. - */ - template - void sort(Compare compare, Sort algo = Sort{}, Args &&...args) { - ENTT_ASSERT(!owned(), "Cannot sort owned storage"); - auto &cpool = assure(); - - if constexpr(stl::is_invocable_v) { - auto comp = [&cpool, compare = stl::move(compare)](const auto lhs, const auto rhs) { return compare(stl::as_const(cpool.get(lhs)), stl::as_const(cpool.get(rhs))); }; - cpool.sort(stl::move(comp), stl::move(algo), stl::forward(args)...); - } else { - cpool.sort(stl::move(compare), stl::move(algo), stl::forward(args)...); - } - } - - /** - * @brief Sorts two pools of elements in the same way. - * - * Entities and elements in `To` which are part of both storage are sorted - * internally with the order they have in `From`. The others follow in no - * particular order. - * - * @warning - * Pools of elements owned by a group cannot be sorted. - * - * @tparam To Type of elements to sort. - * @tparam From Type of elements to use to sort. - */ - template - void sort() { - ENTT_ASSERT(!owned(), "Cannot sort owned storage"); - const base_type &cpool = assure(); - assure().sort_as(cpool.begin(), cpool.end()); - } - - /** - * @brief Returns the context object, that is, a general purpose container. - * @return The context object, that is, a general purpose container. - */ - [[nodiscard]] context &ctx() noexcept { - return vars; - } - - /*! @copydoc ctx */ - [[nodiscard]] const context &ctx() const noexcept { - return vars; - } - -private: - context vars; - pool_container_type pools; - group_container_type groups; - storage_for_type entities; -}; - -} // namespace entt - -#endif diff --git a/include/entt/entity/runtime_view.hpp b/include/entt/entity/runtime_view.hpp deleted file mode 100644 index 1c69c8d..0000000 --- a/include/entt/entity/runtime_view.hpp +++ /dev/null @@ -1,322 +0,0 @@ -#ifndef ENTT_ENTITY_RUNTIME_VIEW_HPP -#define ENTT_ENTITY_RUNTIME_VIEW_HPP - -#include "../stl/algorithm.hpp" -#include "../stl/cstddef.hpp" -#include "../stl/iterator.hpp" -#include "../stl/utility.hpp" -#include "../stl/vector.hpp" -#include "entity.hpp" -#include "fwd.hpp" - -namespace entt { - -/*! @cond ENTT_INTERNAL */ -namespace internal { - -template -class runtime_view_iterator final { - using iterator_type = Set::iterator; - using iterator_traits = stl::iterator_traits; - - [[nodiscard]] bool valid() const { - return (!tombstone_check || *it != tombstone) - && stl::all_of(++pools->begin(), pools->end(), [entt = *it](const auto *curr) { return curr->contains(entt); }) - && stl::none_of(filter->cbegin(), filter->cend(), [entt = *it](const auto *curr) { return curr && curr->contains(entt); }); - } - -public: - using value_type = iterator_traits::value_type; - using pointer = iterator_traits::pointer; - using reference = iterator_traits::reference; - using difference_type = iterator_traits::difference_type; - using iterator_category = stl::bidirectional_iterator_tag; - - constexpr runtime_view_iterator() noexcept - : pools{}, - filter{}, - it{}, - tombstone_check{} {} - - runtime_view_iterator(const stl::vector &cpools, iterator_type curr, const stl::vector &ignore) noexcept - : pools{&cpools}, - filter{&ignore}, - it{curr}, - tombstone_check{pools->size() == 1u && (*pools)[0u]->policy() == deletion_policy::in_place} { - if(it != (*pools)[0]->end() && !valid()) { - ++(*this); - } - } - - runtime_view_iterator &operator++() { - ++it; - for(const auto last = (*pools)[0]->end(); it != last && !valid(); ++it) {} - return *this; - } - - runtime_view_iterator operator++(int) { - const runtime_view_iterator orig = *this; - return ++(*this), orig; - } - - runtime_view_iterator &operator--() { - --it; - for(const auto first = (*pools)[0]->begin(); it != first && !valid(); --it) {} - return *this; - } - - runtime_view_iterator operator--(int) { - const runtime_view_iterator orig = *this; - return operator--(), orig; - } - - [[nodiscard]] pointer operator->() const noexcept { - return it.operator->(); - } - - [[nodiscard]] reference operator*() const noexcept { - return *operator->(); - } - - [[nodiscard]] constexpr bool operator==(const runtime_view_iterator &other) const noexcept { - return it == other.it; - } - -private: - const stl::vector *pools; - const stl::vector *filter; - iterator_type it; - bool tombstone_check; -}; - -} // namespace internal -/*! @endcond */ - -/** - * @brief Generic runtime view. - * - * Runtime views iterate over those entities that are at least in the given - * storage. During initialization, a runtime view looks at the number of - * entities available for each element and uses the smallest set in order to get - * a performance boost when iterating. - * - * @b Important - * - * Iterators aren't invalidated if: - * - * * New elements are added to the storage. - * * The entity currently pointed is modified (for example, elements are added - * or removed from it). - * * The entity currently pointed is destroyed. - * - * In all other cases, modifying the storage iterated by the view in any way - * invalidates all the iterators. - * - * @tparam Type Common base type. - * @tparam Allocator Type of allocator used to manage memory and elements. - */ -template -class basic_runtime_view { - using alloc_traits = stl::allocator_traits; - static_assert(stl::is_same_v, "Invalid value type"); - using container_type = stl::vector; - - [[nodiscard]] auto offset() const noexcept { - ENTT_ASSERT(!pools.empty(), "Invalid view"); - const auto &leading = *pools.front(); - return (leading.policy() == deletion_policy::swap_only) ? leading.free_list() : leading.size(); - } - -public: - /*! @brief Allocator type. */ - using allocator_type = Allocator; - /*! @brief Underlying entity identifier. */ - using entity_type = Type::entity_type; - /*! @brief Unsigned integer type. */ - using size_type = stl::size_t; - /*! @brief Signed integer type. */ - using difference_type = stl::ptrdiff_t; - /*! @brief Common type among all storage types. */ - using common_type = Type; - /*! @brief Bidirectional iterator type. */ - using iterator = internal::runtime_view_iterator; - - /*! @brief Default constructor to use to create empty, invalid views. */ - basic_runtime_view() noexcept - : basic_runtime_view{allocator_type{}} {} - - /** - * @brief Constructs an empty, invalid view with a given allocator. - * @param allocator The allocator to use. - */ - explicit basic_runtime_view(const allocator_type &allocator) - : pools{allocator}, - filter{allocator} {} - - /*! @brief Default copy constructor. */ - basic_runtime_view(const basic_runtime_view &) = default; - - /** - * @brief Allocator-extended copy constructor. - * @param other The instance to copy from. - * @param allocator The allocator to use. - */ - basic_runtime_view(const basic_runtime_view &other, const allocator_type &allocator) - : pools{other.pools, allocator}, - filter{other.filter, allocator} {} - - /*! @brief Default move constructor. */ - basic_runtime_view(basic_runtime_view &&) noexcept = default; - - /** - * @brief Allocator-extended move constructor. - * @param other The instance to move from. - * @param allocator The allocator to use. - */ - basic_runtime_view(basic_runtime_view &&other, const allocator_type &allocator) - : pools{stl::move(other.pools), allocator}, - filter{stl::move(other.filter), allocator} {} - - /*! @brief Default destructor. */ - ~basic_runtime_view() = default; - - /** - * @brief Default copy assignment operator. - * @return This runtime view. - */ - basic_runtime_view &operator=(const basic_runtime_view &) = default; - - /** - * @brief Default move assignment operator. - * @return This runtime view. - */ - basic_runtime_view &operator=(basic_runtime_view &&) noexcept = default; - - /** - * @brief Exchanges the contents with those of a given view. - * @param other View to exchange the content with. - */ - void swap(basic_runtime_view &other) noexcept { - using stl::swap; - swap(pools, other.pools); - swap(filter, other.filter); - } - - /** - * @brief Returns the associated allocator. - * @return The associated allocator. - */ - [[nodiscard]] constexpr allocator_type get_allocator() const noexcept { - return pools.get_allocator(); - } - - /*! @brief Clears the view. */ - void clear() { - pools.clear(); - filter.clear(); - } - - /** - * @brief Appends an opaque storage object to a runtime view. - * @param base An opaque reference to a storage object. - * @return This runtime view. - */ - basic_runtime_view &iterate(common_type &base) { - if(pools.empty() || !(base.size() < pools.front()->size())) { - pools.push_back(&base); - } else { - pools.push_back(stl::exchange(pools.front(), &base)); - } - - return *this; - } - - /** - * @brief Adds an opaque storage object as a filter of a runtime view. - * @param base An opaque reference to a storage object. - * @return This runtime view. - */ - basic_runtime_view &exclude(common_type &base) { - filter.push_back(&base); - return *this; - } - - /** - * @brief Estimates the number of entities iterated by the view. - * @return Estimated number of entities iterated by the view. - */ - [[nodiscard]] size_type size_hint() const { - return pools.empty() ? size_type{} : offset(); - } - - /** - * @brief Returns an iterator to the first entity that has the given - * elements. - * - * If the view is empty, the returned iterator will be equal to `end()`. - * - * @return An iterator to the first entity that has the given elements. - */ - [[nodiscard]] iterator begin() const { - return pools.empty() ? iterator{} : iterator{pools, pools.front()->end() - static_cast(offset()), filter}; - } - - /** - * @brief Returns an iterator that is past the last entity that has the - * given elements. - * @return An iterator to the entity following the last entity that has the - * given elements. - */ - [[nodiscard]] iterator end() const { - return pools.empty() ? iterator{} : iterator{pools, pools.front()->end(), filter}; - } - - /** - * @brief Checks whether a view is initialized or not. - * @return True if the view is initialized, false otherwise. - */ - [[nodiscard]] explicit operator bool() const noexcept { - return !(pools.empty() && filter.empty()); - } - - /** - * @brief Checks if a view contains an entity. - * @param entt A valid identifier. - * @return True if the view contains the given entity, false otherwise. - */ - [[nodiscard]] bool contains(const entity_type entt) const { - return !pools.empty() - && stl::all_of(pools.cbegin(), pools.cend(), [entt](const auto *curr) { return curr->contains(entt); }) - && stl::none_of(filter.cbegin(), filter.cend(), [entt](const auto *curr) { return curr && curr->contains(entt); }) - && pools.front()->index(entt) < offset(); - } - - /** - * @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.
- * 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 { - for(const auto entity: *this) { - func(entity); - } - } - -private: - container_type pools; - container_type filter; -}; - -} // namespace entt - -#endif diff --git a/include/entt/entity/snapshot.hpp b/include/entt/entity/snapshot.hpp deleted file mode 100644 index fd14b26..0000000 --- a/include/entt/entity/snapshot.hpp +++ /dev/null @@ -1,509 +0,0 @@ -#ifndef ENTT_ENTITY_SNAPSHOT_HPP -#define ENTT_ENTITY_SNAPSHOT_HPP - -#include "../config/config.h" -#include "../container/dense_map.hpp" -#include "../core/type_traits.hpp" -#include "../stl/concepts.hpp" -#include "../stl/cstddef.hpp" -#include "../stl/iterator.hpp" -#include "../stl/tuple.hpp" -#include "../stl/type_traits.hpp" -#include "../stl/utility.hpp" -#include "entity.hpp" -#include "fwd.hpp" -#include "view.hpp" - -namespace entt { - -/*! @cond ENTT_INTERNAL */ -namespace internal { - -template -void orphans(Registry ®istry) { - for(auto &storage = registry.template storage(); auto entt: storage) { - if(registry.orphan(entt)) { - storage.erase(entt); - } - } -} - -} // namespace internal -/*! @endcond */ - -/** - * @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 elements of interest.
- * This type can be used in both cases if provided with a correctly configured - * output archive. - * - * @tparam Registry Basic registry type. - */ -template -class basic_snapshot { - static_assert(!stl::is_const_v, "Non-const registry type required"); - using traits_type = entt_traits; - -public: - /*! Basic registry type. */ - using registry_type = Registry; - /*! @brief Underlying entity identifier. */ - using entity_type = registry_type::entity_type; - - /** - * @brief Constructs an instance that is bound to a given registry. - * @param source A valid reference to a registry. - */ - basic_snapshot(const registry_type &source) noexcept - : reg{&source} {} - - /*! @brief Default copy constructor, deleted on purpose. */ - basic_snapshot(const basic_snapshot &) = delete; - - /*! @brief Default move constructor. */ - basic_snapshot(basic_snapshot &&) noexcept = default; - - /*! @brief Default destructor. */ - ~basic_snapshot() = default; - - /** - * @brief Default copy assignment operator, deleted on purpose. - * @return This snapshot. - */ - basic_snapshot &operator=(const basic_snapshot &) = delete; - - /** - * @brief Default move assignment operator. - * @return This snapshot. - */ - basic_snapshot &operator=(basic_snapshot &&) noexcept = default; - - /** - * @brief Serializes all elements of a type with associated identifiers. - * @tparam Type Type of elements to serialize. - * @tparam Archive Type of output archive. - * @param archive A valid reference to an output archive. - * @param id Optional name used to map the storage within the registry. - * @return An object of this type to continue creating the snapshot. - */ - template - const basic_snapshot &get(Archive &archive, const id_type id = type_hash::value()) const { - if(const auto *storage = reg->template storage(id); storage) { - const typename registry_type::common_type &base = *storage; - - archive(static_cast(storage->size())); - - if constexpr(stl::is_same_v) { - archive(static_cast(storage->free_list())); - - for(auto first = base.rbegin(), last = base.rend(); first != last; ++first) { - archive(*first); - } - } else if constexpr(registry_type::template storage_for_type::storage_policy == deletion_policy::in_place) { - for(auto it = base.rbegin(), last = base.rend(); it != last; ++it) { - if(const auto entt = *it; entt == tombstone) { - archive(static_cast(null)); - } else { - archive(entt); - stl::apply([&archive](auto &&...args) { (archive(stl::forward(args)), ...); }, storage->get_as_tuple(entt)); - } - } - } else { - for(auto elem: storage->reach()) { - stl::apply([&archive](auto &&...args) { (archive(stl::forward(args)), ...); }, elem); - } - } - } else { - archive(typename traits_type::entity_type{}); - } - - return *this; - } - - /** - * @brief Serializes all elements of a type with associated identifiers for - * the entities in a range. - * @tparam Type Type of elements to serialize. - * @tparam Archive Type of output archive. - * @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. - * @param id Optional name used to map the storage within the registry. - * @return An object of this type to continue creating the snapshot. - */ - template - const basic_snapshot &get(Archive &archive, stl::input_iterator auto first, stl::input_iterator auto last, const id_type id = type_hash::value()) const { - static_assert(!stl::is_same_v, "Entity types not supported"); - - if(const auto *storage = reg->template storage(id); storage && !storage->empty()) { - archive(static_cast(stl::distance(first, last))); - - for(; first != last; ++first) { - if(const auto entt = *first; storage->contains(entt)) { - archive(entt); - stl::apply([&archive](auto &&...args) { (archive(stl::forward(args)), ...); }, storage->get_as_tuple(entt)); - } else { - archive(static_cast(null)); - } - } - } else { - archive(typename traits_type::entity_type{}); - } - - return *this; - } - -private: - const registry_type *reg; -}; - -/** - * @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 Registry Basic registry type. - */ -template -class basic_snapshot_loader { - static_assert(!stl::is_const_v, "Non-const registry type required"); - using traits_type = entt_traits; - -public: - /*! Basic registry type. */ - using registry_type = Registry; - /*! @brief Underlying entity identifier. */ - using entity_type = registry_type::entity_type; - - /** - * @brief Constructs an instance that is bound to a given registry. - * @param source A valid reference to a registry. - */ - basic_snapshot_loader(registry_type &source) noexcept - : reg{&source} { - // restoring a snapshot as a whole requires a clean registry - ENTT_ASSERT(reg->template storage().free_list() == 0u, "Registry must be empty"); - } - - /*! @brief Default copy constructor, deleted on purpose. */ - basic_snapshot_loader(const basic_snapshot_loader &) = delete; - - /*! @brief Default move constructor. */ - basic_snapshot_loader(basic_snapshot_loader &&) noexcept = default; - - /*! @brief Default destructor. */ - ~basic_snapshot_loader() = default; - - /** - * @brief Default copy assignment operator, deleted on purpose. - * @return This loader. - */ - basic_snapshot_loader &operator=(const basic_snapshot_loader &) = delete; - - /** - * @brief Default move assignment operator. - * @return This loader. - */ - basic_snapshot_loader &operator=(basic_snapshot_loader &&) noexcept = default; - - /** - * @brief Restores all elements of a type with associated identifiers. - * @tparam Type Type of elements to restore. - * @tparam Archive Type of input archive. - * @param archive A valid reference to an input archive. - * @param id Optional name used to map the storage within the registry. - * @return A valid loader to continue restoring data. - */ - template - basic_snapshot_loader &get(Archive &archive, const id_type id = type_hash::value()) { - auto &storage = reg->template storage(id); - typename traits_type::entity_type length{}; - - archive(length); - - if constexpr(stl::is_same_v) { - typename traits_type::entity_type count{}; - entity_type placeholder{}; - - storage.reserve(length); - archive(count); - - for(entity_type entity = null; length; --length) { - archive(entity); - storage.generate(entity); - placeholder = (entity > placeholder) ? entity : placeholder; - } - - storage.start_from(traits_type::next(placeholder)); - storage.free_list(count); - } else { - auto &other = reg->template storage(); - entity_type entt{null}; - - while(length--) { - if(archive(entt); entt != null) { - const auto entity = other.contains(entt) ? entt : other.generate(entt); - ENTT_ASSERT(entity == entt, "Entity not available for use"); - - if constexpr(stl::tuple_size_v == 0u) { - storage.emplace(entity); - } else { - Type elem{}; - archive(elem); - storage.emplace(entity, stl::move(elem)); - } - } - } - } - - return *this; - } - - /** - * @brief Destroys those entities that have no elements. - * - * In case all the entities were serialized but only part of the elements - * was saved, it could happen that some of the entities have no elements - * once restored.
- * This function helps to identify and destroy those entities. - * - * @return A valid loader to continue restoring data. - */ - basic_snapshot_loader &orphans() { - internal::orphans(*reg); - return *this; - } - -private: - registry_type *reg; -}; - -/** - * @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 accommodate 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 application with - * the requirement of transferring somehow parts of the representation side to - * side. - * - * @tparam Registry Basic registry type. - */ -template -class basic_continuous_loader { - static_assert(!stl::is_const_v, "Non-const registry type required"); - using traits_type = entt_traits; - - void restore(Registry::entity_type entt) { - if(const auto entity = to_entity(entt); remloc.contains(entity) && remloc[entity].first == entt) { - if(!reg->valid(remloc[entity].second)) { - remloc[entity].second = reg->create(); - } - } else { - remloc.insert_or_assign(entity, stl::make_pair(entt, reg->create())); - } - } - - template - auto update(int, Container &container) -> decltype(typename Container::mapped_type{}, void()) { - // map like container - Container other; - - for(auto &&pair: container) { - using first_type = stl::remove_const_t::first_type>; - using second_type = stl::decay_t::second_type; - - if constexpr(stl::is_same_v && stl::is_same_v) { - other.emplace(map(pair.first), map(pair.second)); - } else if constexpr(stl::is_same_v) { - other.emplace(map(pair.first), stl::move(pair.second)); - } else { - static_assert(stl::is_same_v, "Neither the key nor the value are of entity type"); - other.emplace(stl::move(pair.first), map(pair.second)); - } - } - - using stl::swap; - swap(container, other); - } - - template - auto update(char, Container &container) -> decltype(typename Container::value_type{}, void()) { - // vector like container - static_assert(stl::is_same_v, "Invalid value type"); - - for(auto &&entt: container) { - entt = map(entt); - } - } - - template - void update([[maybe_unused]] Component &instance, [[maybe_unused]] Member Other::*member) { - if constexpr(!stl::is_same_v) { - return; - } else if constexpr(stl::is_same_v) { - instance.*member = map(instance.*member); - } else { - // maybe a container? let's try... - update(0, instance.*member); - } - } - -public: - /*! Basic registry type. */ - using registry_type = Registry; - /*! @brief Underlying entity identifier. */ - using entity_type = registry_type::entity_type; - - /** - * @brief Constructs an instance that is bound to a given registry. - * @param source A valid reference to a registry. - */ - basic_continuous_loader(registry_type &source) noexcept - : remloc{source.get_allocator()}, - reg{&source} {} - - /*! @brief Default copy constructor, deleted on purpose. */ - basic_continuous_loader(const basic_continuous_loader &) = delete; - - /*! @brief Default move constructor. */ - basic_continuous_loader(basic_continuous_loader &&) noexcept = default; - - /*! @brief Default destructor. */ - ~basic_continuous_loader() = default; - - /** - * @brief Default copy assignment operator, deleted on purpose. - * @return This loader. - */ - basic_continuous_loader &operator=(const basic_continuous_loader &) = delete; - - /** - * @brief Default move assignment operator. - * @return This loader. - */ - basic_continuous_loader &operator=(basic_continuous_loader &&) noexcept = default; - - /** - * @brief Restores all elements of a type with associated identifiers. - * - * It creates local counterparts for remote elements as needed.
- * Members are either data members of type entity_type or containers of - * entities. In both cases, a loader visits them and replaces entities with - * their local counterpart. - * - * @tparam Type Type of elements to restore. - * @tparam Archive Type of input archive. - * @param archive A valid reference to an input archive. - * @param id Optional name used to map the storage within the registry. - * @return A valid loader to continue restoring data. - */ - template - basic_continuous_loader &get(Archive &archive, const id_type id = type_hash::value()) { - auto &storage = reg->template storage(id); - typename traits_type::entity_type length{}; - entity_type entt{null}; - - archive(length); - - if constexpr(stl::is_same_v) { - typename traits_type::entity_type in_use{}; - - storage.reserve(length); - archive(in_use); - - for(stl::size_t pos{}; pos < in_use; ++pos) { - archive(entt); - restore(entt); - } - - for(stl::size_t pos = in_use; pos < length; ++pos) { - archive(entt); - - if(const auto entity = to_entity(entt); remloc.contains(entity)) { - if(reg->valid(remloc[entity].second)) { - reg->destroy(remloc[entity].second); - } - - remloc.erase(entity); - } - } - } else { - for(auto &&ref: remloc) { - storage.remove(ref.second.second); - } - - while(length--) { - if(archive(entt); entt != null) { - restore(entt); - - if constexpr(stl::tuple_size_v == 0u) { - storage.emplace(map(entt)); - } else { - Type elem{}; - archive(elem); - storage.emplace(map(entt), stl::move(elem)); - } - } - } - } - - return *this; - } - - /** - * @brief Destroys those entities that have no elements. - * - * In case all the entities were serialized but only part of the elements - * was saved, it could happen that some of the entities have no elements - * once restored.
- * This function helps to identify and destroy those entities. - * - * @return A non-const reference to this loader. - */ - basic_continuous_loader &orphans() { - internal::orphans(*reg); - return *this; - } - - /** - * @brief Tests if a loader knows about a given entity. - * @param entt A valid identifier. - * @return True if `entity` is managed by the loader, false otherwise. - */ - [[nodiscard]] bool contains(entity_type entt) const noexcept { - const auto it = remloc.find(to_entity(entt)); - return it != remloc.cend() && it->second.first == entt; - } - - /** - * @brief Returns the identifier to which an entity refers. - * @param entt A valid identifier. - * @return The local identifier if any, the null entity otherwise. - */ - [[nodiscard]] entity_type map(entity_type entt) const noexcept { - if(const auto it = remloc.find(to_entity(entt)); it != remloc.cend() && it->second.first == entt) { - return it->second.second; - } - - return null; - } - -private: - dense_map> remloc; - registry_type *reg; -}; - -} // namespace entt - -#endif diff --git a/include/entt/entity/sparse_set.hpp b/include/entt/entity/sparse_set.hpp deleted file mode 100644 index 39540e3..0000000 --- a/include/entt/entity/sparse_set.hpp +++ /dev/null @@ -1,1076 +0,0 @@ -#ifndef ENTT_ENTITY_SPARSE_SET_HPP -#define ENTT_ENTITY_SPARSE_SET_HPP - -#include -#include "../config/config.h" -#include "../core/algorithm.hpp" -#include "../core/any.hpp" -#include "../core/bit.hpp" -#include "../core/type_info.hpp" -#include "../stl/concepts.hpp" -#include "../stl/cstddef.hpp" -#include "../stl/iterator.hpp" -#include "../stl/memory.hpp" -#include "../stl/type_traits.hpp" -#include "../stl/utility.hpp" -#include "../stl/vector.hpp" -#include "entity.hpp" -#include "fwd.hpp" - -namespace entt { - -/*! @cond ENTT_INTERNAL */ -namespace internal { - -template -struct sparse_set_iterator final { - using value_type = Container::value_type; - using pointer = Container::const_pointer; - using reference = Container::const_reference; - using difference_type = Container::difference_type; - using iterator_category = stl::random_access_iterator_tag; - - constexpr sparse_set_iterator() noexcept - : packed{}, - offset{} {} - - constexpr sparse_set_iterator(const Container &ref, const difference_type idx) noexcept - : packed{&ref}, - offset{idx} {} - - constexpr sparse_set_iterator &operator++() noexcept { - return --offset, *this; - } - - constexpr sparse_set_iterator operator++(int) noexcept { - const sparse_set_iterator orig = *this; - return ++(*this), orig; - } - - constexpr sparse_set_iterator &operator--() noexcept { - return ++offset, *this; - } - - constexpr sparse_set_iterator operator--(int) noexcept { - const sparse_set_iterator orig = *this; - return operator--(), orig; - } - - constexpr sparse_set_iterator &operator+=(const difference_type value) noexcept { - offset -= value; - return *this; - } - - constexpr sparse_set_iterator operator+(const difference_type value) const noexcept { - sparse_set_iterator copy = *this; - return (copy += value); - } - - constexpr sparse_set_iterator &operator-=(const difference_type value) noexcept { - return (*this += -value); - } - - constexpr sparse_set_iterator operator-(const difference_type value) const noexcept { - return (*this + -value); - } - - [[nodiscard]] constexpr reference operator[](const difference_type value) const noexcept { - return (*packed)[static_cast(index() - value)]; - } - - [[nodiscard]] constexpr pointer operator->() const noexcept { - return stl::addressof(operator[](0)); - } - - [[nodiscard]] constexpr reference operator*() const noexcept { - return operator[](0); - } - - [[nodiscard]] constexpr stl::ptrdiff_t operator-(const sparse_set_iterator &other) const noexcept { - // intentionally reversed due to backward iteration - return other.offset - offset; - } - - [[nodiscard]] constexpr bool operator==(const sparse_set_iterator &other) const noexcept { - return offset == other.offset; - } - - [[nodiscard]] constexpr auto operator<=>(const sparse_set_iterator &other) const noexcept { - // intentionally reversed due to backward iteration - return other.offset <=> offset; - } - - [[nodiscard]] constexpr pointer data() const noexcept { - return packed ? packed->data() : nullptr; - } - - [[nodiscard]] constexpr difference_type index() const noexcept { - return offset - 1; - } - -private: - const Container *packed; - difference_type offset; -}; - -} // namespace internal -/*! @endcond */ - -/** - * @brief 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 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 - * Internal data structures arrange elements to maximize performance. 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. - * - * @tparam Entity A valid entity type. - * @tparam Allocator Type of allocator used to manage memory and elements. - */ -template -class basic_sparse_set { - using alloc_traits = stl::allocator_traits; - static_assert(stl::is_same_v, "Invalid value type"); - using sparse_container_type = stl::vector>; - using packed_container_type = stl::vector; - using traits_type = entt_traits; - - static constexpr auto max_size = static_cast(traits_type::to_entity(null)); - - // it could be auto but gcc complains and emits a warning due to a false positive - [[nodiscard]] stl::size_t policy_to_head() const noexcept { - return static_cast(max_size * static_cast>(mode != deletion_policy::swap_only)); - } - - [[nodiscard]] auto entity_to_pos(const Entity entt) const noexcept { - return static_cast(traits_type::to_entity(entt)); - } - - [[nodiscard]] auto pos_to_page(const stl::size_t pos) const noexcept { - return static_cast(pos / traits_type::page_size); - } - - [[nodiscard]] auto sparse_ptr(const Entity entt) const { - const auto pos = entity_to_pos(entt); - const auto page = pos_to_page(pos); - return (page < sparse.size() && sparse[page]) ? (sparse[page] + fast_mod(pos, traits_type::page_size)) : nullptr; - } - - [[nodiscard]] auto &sparse_ref(const Entity entt) const { - ENTT_ASSERT(sparse_ptr(entt), "Invalid element"); - const auto pos = entity_to_pos(entt); - return sparse[pos_to_page(pos)][fast_mod(pos, traits_type::page_size)]; - } - - [[nodiscard]] auto to_iterator(const Entity entt) const { - return --(end() - static_cast(index(entt))); - } - - [[nodiscard]] auto &assure_at_least(const Entity entt) { - const auto pos = entity_to_pos(entt); - const auto page = pos_to_page(pos); - - if(!(page < sparse.size())) { - sparse.resize(page + 1u, nullptr); - } - - if(!sparse[page]) { - constexpr entity_type init = null; - auto page_allocator{packed.get_allocator()}; - sparse[page] = alloc_traits::allocate(page_allocator, traits_type::page_size); - stl::uninitialized_fill(sparse[page], sparse[page] + traits_type::page_size, init); - } - - return sparse[page][fast_mod(pos, traits_type::page_size)]; - } - - void release_sparse_pages() { - for(auto page_allocator{packed.get_allocator()}; auto &&page: sparse) { - if(page != nullptr) { - stl::destroy(page, page + traits_type::page_size); - alloc_traits::deallocate(page_allocator, page, traits_type::page_size); - page = nullptr; - } - } - } - - void swap_at(const stl::size_t lhs, const stl::size_t rhs) { - auto &from = packed[lhs]; - auto &to = packed[rhs]; - - sparse_ref(from) = traits_type::combine(static_cast(rhs), traits_type::to_integral(from)); - sparse_ref(to) = traits_type::combine(static_cast(lhs), traits_type::to_integral(to)); - - stl::swap(from, to); - } - -private: - [[nodiscard]] virtual const void *get_at(const stl::size_t) const { - return nullptr; - } - - virtual void swap_or_move([[maybe_unused]] const stl::size_t lhs, [[maybe_unused]] const stl::size_t rhs) { - ENTT_ASSERT((mode != deletion_policy::swap_only) || ((lhs < head) == (rhs < head)), "Cross swapping is not supported"); - } - -protected: - /*! @brief Random access iterator type. */ - using basic_iterator = internal::sparse_set_iterator; - - /** - * @brief Erases an entity from a sparse set. - * @param entt A valid identifier for the element to pop. - */ - void swap_only(const Entity entt) { - ENTT_ASSERT(mode == deletion_policy::swap_only, "Deletion policy mismatch"); - const auto pos = index(entt); - bump(traits_type::next(entt)); - swap_at(pos, head -= (pos < head)); - } - - /** - * @brief Erases an entity from a sparse set. - * @param entt A valid identifier for the element to pop. - */ - void swap_and_pop(const Entity entt) { - ENTT_ASSERT(mode == deletion_policy::swap_and_pop, "Deletion policy mismatch"); - auto &self = sparse_ref(entt); - const auto pos = traits_type::to_entity(self); - sparse_ref(packed.back()) = traits_type::combine(pos, traits_type::to_integral(packed.back())); - packed[static_cast(pos)] = packed.back(); - // unnecessary but it helps to detect nasty bugs - // NOLINTNEXTLINE(bugprone-assert-side-effect) - ENTT_ASSERT((packed.back() = null, true), ""); - // lazy self-assignment guard - self = null; - packed.pop_back(); - } - - /** - * @brief Erases an entity from a sparse set. - * @param entt A valid identifier for the element to pop. - */ - void in_place_pop(const Entity entt) { - ENTT_ASSERT(mode == deletion_policy::in_place, "Deletion policy mismatch"); - const auto pos = entity_to_pos(stl::exchange(sparse_ref(entt), null)); - packed[pos] = traits_type::combine(static_cast(stl::exchange(head, pos)), tombstone); - } - - /** - * @brief Erases entities from a sparse set. - * @param first An iterator to the first element of the range of entities. - * @param last An iterator past the last element of the range of entities. - */ - virtual void pop(basic_iterator first, basic_iterator last) { - switch(mode) { - case deletion_policy::swap_and_pop: - for(; first != last; ++first) { - swap_and_pop(*first); - } - break; - case deletion_policy::in_place: - for(; first != last; ++first) { - in_place_pop(*first); - } - break; - case deletion_policy::swap_only: - for(; first != last; ++first) { - swap_only(*first); - } - break; - } - } - - /*! @brief Erases all entities of a sparse set. */ - virtual void pop_all() { - if(!packed.empty()) { - // suboptimal with few entities, but exploits cache way more with many - for(auto &&elem: sparse) { - if(elem) { - for(size_type pos{}; pos < traits_type::page_size; ++pos) { - elem[pos] = null; - } - } - } - } - - head = policy_to_head(); - packed.clear(); - } - - /** - * @brief Assigns an entity to a sparse set. - * @param entt A valid identifier. - * @param force_back Force back insertion. - * @return Iterator pointing to the emplaced element. - */ - virtual basic_iterator try_emplace(const Entity entt, const bool force_back, const void * = nullptr) { - ENTT_ASSERT(entt != null && entt != tombstone, "Invalid element"); - auto &elem = assure_at_least(entt); - auto pos = size(); - - switch(mode) { - case deletion_policy::in_place: - if(head != max_size && !force_back) { - pos = head; - ENTT_ASSERT(elem == null, "Slot not available"); - elem = traits_type::combine(static_cast(head), traits_type::to_integral(entt)); - head = entity_to_pos(stl::exchange(packed[pos], entt)); - break; - } - [[fallthrough]]; - case deletion_policy::swap_and_pop: - packed.push_back(entt); - ENTT_ASSERT(elem == null, "Slot not available"); - elem = traits_type::combine(static_cast(packed.size() - 1u), traits_type::to_integral(entt)); - break; - case deletion_policy::swap_only: - if(elem == null) { - packed.push_back(entt); - elem = traits_type::combine(static_cast(packed.size() - 1u), traits_type::to_integral(entt)); - } else { - ENTT_ASSERT(!(entity_to_pos(elem) < head), "Slot not available"); - bump(entt); - } - - pos = head++; - swap_at(entity_to_pos(elem), pos); - break; - } - - return iterator{packed, static_cast(++pos)}; - } - - /*! @brief Forwards variables to derived classes, if any. */ - // NOLINTNEXTLINE(performance-unnecessary-value-param) - virtual void bind_any(any) noexcept {} - -public: - /*! @brief Allocator type. */ - using allocator_type = Allocator; - /*! @brief Underlying entity identifier. */ - using entity_type = traits_type::value_type; - /*! @brief Underlying version type. */ - using version_type = traits_type::version_type; - /*! @brief Unsigned integer type. */ - using size_type = stl::size_t; - /*! @brief Signed integer type. */ - using difference_type = stl::ptrdiff_t; - /*! @brief Pointer type to contained entities. */ - using pointer = packed_container_type::const_pointer; - /*! @brief Random access iterator type. */ - using iterator = basic_iterator; - /*! @brief Constant random access iterator type. */ - using const_iterator = iterator; - /*! @brief Reverse iterator type. */ - using reverse_iterator = stl::reverse_iterator; - /*! @brief Constant reverse iterator type. */ - using const_reverse_iterator = stl::reverse_iterator; - - /*! @brief Default constructor. */ - basic_sparse_set() - : basic_sparse_set{type_id()} {} - - /** - * @brief Constructs an empty container with a given allocator. - * @param allocator The allocator to use. - */ - explicit basic_sparse_set(const allocator_type &allocator) - : basic_sparse_set{deletion_policy::swap_and_pop, allocator} {} - - /** - * @brief Constructs an empty container with the given policy and allocator. - * @param pol Type of deletion policy. - * @param allocator The allocator to use (possibly default-constructed). - */ - explicit basic_sparse_set(deletion_policy pol, const allocator_type &allocator = {}) - : basic_sparse_set{type_id(), pol, allocator} {} - - /** - * @brief Constructs an empty container with the given value type, policy - * and allocator. - * @param elem Returned value type, if any. - * @param pol Type of deletion policy. - * @param allocator The allocator to use (possibly default-constructed). - */ - explicit basic_sparse_set(const type_info &elem, deletion_policy pol = deletion_policy::swap_and_pop, const allocator_type &allocator = {}) - : sparse{allocator}, - packed{allocator}, - descriptor{&elem}, - mode{pol}, - head{policy_to_head()} { - ENTT_ASSERT(traits_type::version_mask || mode != deletion_policy::in_place, "Policy does not support zero-sized versions"); - } - - /*! @brief Default copy constructor, deleted on purpose. */ - basic_sparse_set(const basic_sparse_set &) = delete; - - /** - * @brief Move constructor. - * @param other The instance to move from. - */ - basic_sparse_set(basic_sparse_set &&other) noexcept - : sparse{stl::move(other.sparse)}, - packed{stl::move(other.packed)}, - descriptor{other.descriptor}, - mode{other.mode}, - head{stl::exchange(other.head, policy_to_head())} {} - - /** - * @brief Allocator-extended move constructor. - * @param other The instance to move from. - * @param allocator The allocator to use. - */ - basic_sparse_set(basic_sparse_set &&other, const allocator_type &allocator) - : sparse{stl::move(other.sparse), allocator}, - packed{stl::move(other.packed), allocator}, - descriptor{other.descriptor}, - mode{other.mode}, - head{stl::exchange(other.head, policy_to_head())} { - ENTT_ASSERT(alloc_traits::is_always_equal::value || get_allocator() == other.get_allocator(), "Copying a sparse set is not allowed"); - } - - /*! @brief Default destructor. */ - virtual ~basic_sparse_set() { - release_sparse_pages(); - } - - /** - * @brief Default copy assignment operator, deleted on purpose. - * @return This sparse set. - */ - basic_sparse_set &operator=(const basic_sparse_set &) = delete; - - /** - * @brief Move assignment operator. - * @param other The instance to move from. - * @return This sparse set. - */ - basic_sparse_set &operator=(basic_sparse_set &&other) noexcept { - ENTT_ASSERT(alloc_traits::is_always_equal::value || get_allocator() == other.get_allocator(), "Copying a sparse set is not allowed"); - swap(other); - return *this; - } - - /** - * @brief Exchanges the contents with those of a given sparse set. - * @param other Sparse set to exchange the content with. - */ - void swap(basic_sparse_set &other) noexcept { - using stl::swap; - swap(sparse, other.sparse); - swap(packed, other.packed); - swap(descriptor, other.descriptor); - swap(mode, other.mode); - swap(head, other.head); - } - - /** - * @brief Returns the associated allocator. - * @return The associated allocator. - */ - [[nodiscard]] constexpr allocator_type get_allocator() const noexcept { - return packed.get_allocator(); - } - - /** - * @brief Returns the deletion policy of a sparse set. - * @return The deletion policy of the sparse set. - */ - [[nodiscard]] deletion_policy policy() const noexcept { - return mode; - } - - /** - * @brief Returns data on the free list whose meaning depends on the mode. - * @return Free list information that is mode dependent. - */ - [[nodiscard]] size_type free_list() const noexcept { - return head; - } - - /** - * @brief Sets data on the free list whose meaning depends on the mode. - * @param value Free list information that is mode dependent. - */ - void free_list(const size_type value) noexcept { - ENTT_ASSERT((mode == deletion_policy::swap_only) && !(value > packed.size()), "Invalid value"); - head = value; - } - - /** - * @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. - */ - virtual void reserve(const size_type cap) { - packed.reserve(cap); - } - - /** - * @brief Returns the number of elements that a sparse set has currently - * allocated space for. - * @return Capacity of the sparse set. - */ - [[nodiscard]] virtual size_type capacity() const noexcept { - return packed.capacity(); - } - - /*! @brief Requests the removal of unused capacity. */ - virtual void shrink_to_fit() { - sparse_container_type other{sparse.get_allocator()}; - const auto len = sparse.size(); - other.reserve(len); - - for(size_type cnt{}; auto &&elem: stl::as_const(packed)) { - if(elem != tombstone) { - if(const auto page = pos_to_page(entity_to_pos(elem)); sparse[page] != nullptr) { - if(const auto sz = page + 1u; sz > other.size()) { - other.resize(sz, nullptr); - } - - other[page] = stl::exchange(sparse[page], nullptr); - - if(++cnt == len) { - // early exit due to lack of pages - break; - } - } - } - } - - release_sparse_pages(); - sparse.swap(other); - - sparse.shrink_to_fit(); - packed.shrink_to_fit(); - } - - /** - * @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 all pages have been allocated, nor that the - * internal packed array is be the same size. - * - * @return Extent of the sparse set. - */ - [[nodiscard]] size_type extent() const noexcept { - return sparse.size() * traits_type::page_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. - */ - [[nodiscard]] size_type size() const noexcept { - return packed.size(); - } - - /** - * @brief Checks whether a sparse set is empty. - * @return True if the sparse set is empty, false otherwise. - */ - [[nodiscard]] bool empty() const noexcept { - return packed.empty(); - } - - /** - * @brief Checks whether a sparse set is fully packed. - * @return True if the sparse set is fully packed, false otherwise. - */ - [[nodiscard]] bool contiguous() const noexcept { - return (mode != deletion_policy::in_place) || (head == max_size); - } - - /** - * @brief Direct access to the internal packed array. - * @return A pointer to the internal packed array. - */ - [[nodiscard]] pointer data() const noexcept { - return packed.data(); - } - - /** - * @brief Returns an iterator to the beginning. - * - * If the sparse set is empty, the returned iterator will be equal to - * `end()`. - * - * @return An iterator to the first entity of the sparse set. - */ - [[nodiscard]] iterator begin() const noexcept { - const auto pos = static_cast(packed.size()); - return iterator{packed, pos}; - } - - /*! @copydoc begin */ - [[nodiscard]] const_iterator cbegin() const noexcept { - return begin(); - } - - /** - * @brief Returns an iterator to the end. - * @return An iterator to the element following the last entity of a sparse - * set. - */ - [[nodiscard]] iterator end() const noexcept { - return iterator{packed, {}}; - } - - /*! @copydoc end */ - [[nodiscard]] const_iterator cend() const noexcept { - return end(); - } - - /** - * @brief Returns a reverse iterator to the beginning. - * - * If the sparse set is empty, the returned iterator will be equal to - * `rend()`. - * - * @return An iterator to the first entity of the reversed internal packed - * array. - */ - [[nodiscard]] reverse_iterator rbegin() const noexcept { - return stl::make_reverse_iterator(end()); - } - - /*! @copydoc rbegin */ - [[nodiscard]] const_reverse_iterator crbegin() const noexcept { - return rbegin(); - } - - /** - * @brief Returns a reverse iterator to the end. - * @return An iterator to the element following the last entity of the - * reversed sparse set. - */ - [[nodiscard]] reverse_iterator rend() const noexcept { - return stl::make_reverse_iterator(begin()); - } - - /*! @copydoc rend */ - [[nodiscard]] const_reverse_iterator crend() const noexcept { - return rend(); - } - - /** - * @brief Finds an entity. - * @param entt A valid identifier. - * @return An iterator to the given entity if it's found, past the end - * iterator otherwise. - */ - [[nodiscard]] const_iterator find(const entity_type entt) const noexcept { - return contains(entt) ? to_iterator(entt) : end(); - } - - /** - * @brief Checks if a sparse set contains an entity. - * @param entt A valid identifier. - * @return True if the sparse set contains the entity, false otherwise. - */ - [[nodiscard]] bool contains(const entity_type entt) const noexcept { - const auto *elem = sparse_ptr(entt); - constexpr auto cap = traits_type::entity_mask; - constexpr auto mask = traits_type::to_integral(null) & ~cap; - // testing versions permits to avoid accessing the packed array - return elem && (((mask & traits_type::to_integral(entt)) ^ traits_type::to_integral(*elem)) < cap); - } - - /** - * @brief Returns the contained version for an identifier. - * @param entt A valid identifier. - * @return The version for the given identifier if present, the tombstone - * version otherwise. - */ - [[nodiscard]] version_type current(const entity_type entt) const noexcept { - const auto *elem = sparse_ptr(entt); - constexpr auto fallback = traits_type::to_version(tombstone); - return elem ? traits_type::to_version(*elem) : fallback; - } - - /** - * @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. - * - * @param entt A valid identifier. - * @return The position of the entity in the sparse set. - */ - [[nodiscard]] size_type index(const entity_type entt) const noexcept { - ENTT_ASSERT(contains(entt), "Set does not contain entity"); - return entity_to_pos(sparse_ref(entt)); - } - - /** - * @brief Returns the entity at specified location. - * @param pos The position for which to return the entity. - * @return The entity at specified location. - */ - [[nodiscard]] entity_type operator[](const size_type pos) const noexcept { - ENTT_ASSERT(pos < packed.size(), "Index out of bounds"); - return packed[pos]; - } - - /** - * @brief Returns the element assigned to an entity, if any. - * - * @warning - * Attempting to use an entity that doesn't belong to the sparse set results - * in undefined behavior. - * - * @param entt A valid identifier. - * @return An opaque pointer to the element assigned to the entity, if any. - */ - [[nodiscard]] const void *value(const entity_type entt) const noexcept { - return get_at(index(entt)); - } - - /*! @copydoc value */ - [[nodiscard]] void *value(const entity_type entt) noexcept { - return const_cast(stl::as_const(*this).value(entt)); - } - - /** - * @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. - * - * @param entt A valid identifier. - * @param elem Optional opaque element to forward to mixins, if any. - * @return Iterator pointing to the emplaced element in case of success, the - * `end()` iterator otherwise. - */ - iterator push(const entity_type entt, const void *elem = nullptr) { - return try_emplace(entt, false, elem); - } - - /** - * @brief Assigns one or more entities to a sparse set. - * - * @warning - * Attempting to assign an entity that already belongs to the sparse set - * results in undefined behavior. - * - * @param first An iterator to the first element of the range of entities. - * @param last An iterator past the last element of the range of entities. - * @return Iterator pointing to the first element inserted in case of - * success, the `end()` iterator otherwise. - */ - iterator push(stl::input_iterator auto first, stl::input_iterator auto last) { - auto curr = end(); - - for(; first != last; ++first) { - curr = try_emplace(*first, true); - } - - return curr; - } - - /** - * @brief Bump the version number of an entity. - * - * @warning - * Attempting to bump the version of an entity that doesn't belong to the - * sparse set results in undefined behavior. - * - * @param entt A valid identifier. - * @return The version of the given identifier. - */ - version_type bump(const entity_type entt) { - auto &elem = sparse_ref(entt); - ENTT_ASSERT(entt != null && elem != tombstone, "Cannot set the required version"); - elem = traits_type::combine(traits_type::to_integral(elem), traits_type::to_integral(entt)); - packed[entity_to_pos(elem)] = entt; - return traits_type::to_version(entt); - } - - /** - * @brief Erases an entity from a sparse set. - * - * @warning - * Attempting to erase an entity that doesn't belong to the sparse set - * results in undefined behavior. - * - * @param entt A valid identifier. - */ - void erase(const entity_type entt) { - const auto it = to_iterator(entt); - pop(it, it + 1u); - } - - /** - * @brief Erases entities from a set. - * - * @sa erase - * - * @tparam It Type of input iterator. - * @param first An iterator to the first element of the range of entities. - * @param last An iterator past the last element of the range of entities. - */ - template - void erase(It first, It last) { - if constexpr(stl::is_same_v) { - pop(first, last); - } else { - for(; first != last; ++first) { - erase(*first); - } - } - } - - /** - * @brief Removes an entity from a sparse set if it exists. - * @param entt A valid identifier. - * @return True if the entity is actually removed, false otherwise. - */ - bool remove(const entity_type entt) { - return contains(entt) && (erase(entt), true); - } - - /** - * @brief Removes entities from a sparse set if they exist. - * @tparam It Type of input iterator. - * @param first An iterator to the first element of the range of entities. - * @param last An iterator past the last element of the range of entities. - * @return The number of entities actually removed. - */ - template - size_type remove(It first, It last) { - size_type count{}; - - if constexpr(stl::is_same_v) { - while(first != last) { - while(first != last && !contains(*first)) { - ++first; - } - - const auto it = first; - - while(first != last && contains(*first)) { - ++first; - } - - count += static_cast(stl::distance(it, first)); - erase(it, first); - } - } else { - for(; first != last; ++first) { - count += remove(*first); - } - } - - return count; - } - - /*! @brief Removes all tombstones from a sparse set. */ - void compact() { - if(mode == deletion_policy::in_place) { - size_type from = packed.size(); - size_type pos = stl::exchange(head, max_size); - - for(; from && packed[from - 1u] == tombstone; --from) {} - - while(pos != max_size) { - if(const auto to = stl::exchange(pos, entity_to_pos(packed[pos])); to < from) { - --from; - swap_or_move(from, to); - - packed[to] = packed[from]; - const auto elem = static_cast(to); - sparse_ref(packed[to]) = traits_type::combine(elem, traits_type::to_integral(packed[to])); - - for(; from && packed[from - 1u] == tombstone; --from) {} - } - } - - packed.erase(packed.begin() + static_cast(from), packed.end()); - } - } - - /** - * @brief Swaps two entities in a sparse set. - * - * 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. - * - * @param lhs A valid identifier. - * @param rhs A valid identifier. - */ - void swap_elements(const entity_type lhs, const entity_type rhs) { - const auto from = index(lhs); - const auto to = index(rhs); - - // basic no-leak guarantee if swapping throws - swap_or_move(from, to); - swap_at(from, to); - } - - /** - * @brief Sort the first count elements according to the given comparison - * function. - * - * 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 Entity, const Entity); - * @endcode - * - * Moreover, the comparison function object shall induce a - * _strict weak ordering_ on the values. - * - * The sort function object 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. - * - * @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 length Number of elements to sort. - * @param compare A valid comparison function object. - * @param algo A valid sort function object. - * @param args Arguments to forward to the sort function object, if any. - */ - template - void sort_n(const size_type length, Compare compare, Sort algo = Sort{}, Args &&...args) { - ENTT_ASSERT((mode != deletion_policy::in_place) || (head == max_size), "Sorting with tombstones not allowed"); - ENTT_ASSERT(!(length > packed.size()), "Length exceeds the number of elements"); - - algo(packed.rend() - static_cast(length), packed.rend(), stl::move(compare), stl::forward(args)...); - - for(size_type pos{}; pos < length; ++pos) { - auto curr = pos; - auto next = index(packed[curr]); - - while(curr != next) { - const auto idx = index(packed[next]); - const auto entt = packed[curr]; - - swap_or_move(next, idx); - const auto elem = static_cast(curr); - sparse_ref(entt) = traits_type::combine(elem, traits_type::to_integral(packed[curr])); - curr = stl::exchange(next, idx); - } - } - } - - /** - * @brief Sort all elements according to the given comparison function. - * - * @sa sort_n - * - * @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 algo A valid sort function object. - * @param args Arguments to forward to the sort function object, if any. - */ - template - void sort(Compare compare, Sort algo = Sort{}, Args &&...args) { - const size_type len = (mode == deletion_policy::swap_only) ? head : packed.size(); - sort_n(len, stl::move(compare), stl::move(algo), stl::forward(args)...); - } - - /** - * @brief Sort entities according to their order in a range. - * - * Entities that are part of both the sparse set and the range are ordered - * internally according to the order they have in the range.
- * All other entities goes to the end of the sparse set and there are no - * guarantees on their order. - * - * @tparam It Type of input iterator. - * @param first An iterator to the first element of the range of entities. - * @param last An iterator past the last element of the range of entities. - * @return An iterator past the last of the elements actually shared. - */ - template - iterator sort_as(It first, It last) { - ENTT_ASSERT((mode != deletion_policy::in_place) || (head == max_size), "Sorting with tombstones not allowed"); - const size_type len = (mode == deletion_policy::swap_only) ? head : packed.size(); - auto it = end() - static_cast(len); - - for(const auto other = end(); (it != other) && (first != last); ++first) { - if(const auto curr = *first; contains(curr)) { - if(const auto entt = *it; entt != curr) { - // basic no-leak guarantee (with invalid state) if swapping throws - swap_elements(entt, curr); - } - - ++it; - } - } - - return it; - } - - /*! @brief Clears a sparse set. */ - void clear() { - pop_all(); - // sanity check to avoid subtle issues due to storage classes - ENTT_ASSERT((compact(), size()) == 0u, "Non-empty set"); - head = policy_to_head(); - packed.clear(); - } - - /** - * @brief Returns a type info object for the value type, if any. - * @return A type info object for the value type, if any. - */ - [[nodiscard]] const type_info &info() const noexcept { - return *descriptor; - } - - /** - * @brief Forwards variables to derived classes, if any. - * @tparam Type Type of the element to forward. - * @param value The element to forward. - */ - template - void bind(Type &&value) noexcept { - bind_any(forward_as_any(stl::forward(value))); - } - -private: - sparse_container_type sparse; - packed_container_type packed; - const type_info *descriptor; - deletion_policy mode; - size_type head; -}; - -} // namespace entt - -#endif diff --git a/include/entt/entity/storage.hpp b/include/entt/entity/storage.hpp deleted file mode 100644 index d12bf7d..0000000 --- a/include/entt/entity/storage.hpp +++ /dev/null @@ -1,1222 +0,0 @@ -#ifndef ENTT_ENTITY_STORAGE_HPP -#define ENTT_ENTITY_STORAGE_HPP - -#include -#include "../config/config.h" -#include "../core/bit.hpp" -#include "../core/iterator.hpp" -#include "../core/memory.hpp" -#include "../core/type_info.hpp" -#include "../stl/concepts.hpp" -#include "../stl/cstddef.hpp" -#include "../stl/iterator.hpp" -#include "../stl/memory.hpp" -#include "../stl/tuple.hpp" -#include "../stl/type_traits.hpp" -#include "../stl/utility.hpp" -#include "../stl/vector.hpp" -#include "component.hpp" -#include "entity.hpp" -#include "fwd.hpp" -#include "sparse_set.hpp" - -namespace entt { - -/*! @cond ENTT_INTERNAL */ -namespace internal { - -template -class storage_iterator final { - template - friend class storage_iterator; - - using container_type = stl::remove_const_t; - using alloc_traits = stl::allocator_traits; - - using iterator_traits = stl::iterator_traits, - typename alloc_traits::template rebind_traits::element_type>::const_pointer, - typename alloc_traits::template rebind_traits::element_type>::pointer>>; - -public: - using value_type = iterator_traits::value_type; - using pointer = iterator_traits::pointer; - using reference = iterator_traits::reference; - using difference_type = iterator_traits::difference_type; - using iterator_category = stl::random_access_iterator_tag; - - constexpr storage_iterator() noexcept = default; - - constexpr storage_iterator(Container *ref, const difference_type idx) noexcept - : payload{ref}, - offset{idx} {} - - template> Other> - requires stl::is_const_v - constexpr storage_iterator(const storage_iterator &other) noexcept - : storage_iterator{other.payload, other.offset} {} - - constexpr storage_iterator &operator++() noexcept { - return --offset, *this; - } - - constexpr storage_iterator operator++(int) noexcept { - const storage_iterator orig = *this; - return ++(*this), orig; - } - - constexpr storage_iterator &operator--() noexcept { - return ++offset, *this; - } - - constexpr storage_iterator operator--(int) noexcept { - const storage_iterator orig = *this; - return operator--(), orig; - } - - constexpr storage_iterator &operator+=(const difference_type value) noexcept { - offset -= value; - return *this; - } - - constexpr storage_iterator operator+(const difference_type value) const noexcept { - storage_iterator copy = *this; - return (copy += value); - } - - constexpr storage_iterator &operator-=(const difference_type value) noexcept { - return (*this += -value); - } - - constexpr storage_iterator operator-(const difference_type value) const noexcept { - return (*this + -value); - } - - [[nodiscard]] constexpr reference operator[](const difference_type value) const noexcept { - const auto pos = static_cast(index() - value); - return (*payload)[pos / Page][fast_mod(static_cast(pos), Page)]; - } - - [[nodiscard]] constexpr pointer operator->() const noexcept { - return stl::addressof(operator[](0)); - } - - [[nodiscard]] constexpr reference operator*() const noexcept { - return operator[](0); - } - - template - [[nodiscard]] constexpr stl::ptrdiff_t operator-(const storage_iterator &other) const noexcept { - // intentionally reversed due to backward iteration - return other.offset - offset; - } - - template - [[nodiscard]] constexpr bool operator==(const storage_iterator &other) const noexcept { - return offset == other.offset; - } - - template - [[nodiscard]] constexpr auto operator<=>(const storage_iterator &other) const noexcept { - // intentionally reversed due to backward iteration - return other.offset <=> offset; - } - - [[nodiscard]] constexpr difference_type index() const noexcept { - return offset - 1; - } - -private: - Container *payload; - difference_type offset; -}; - -template -class extended_storage_iterator final { - template - friend class extended_storage_iterator; - -public: - using iterator_type = It; - using value_type = decltype(stl::tuple_cat(stl::make_tuple(*stl::declval()), stl::forward_as_tuple(*stl::declval()...))); - using pointer = input_iterator_pointer; - using reference = value_type; - using difference_type = stl::ptrdiff_t; - using iterator_category = stl::input_iterator_tag; - using iterator_concept = stl::forward_iterator_tag; - - constexpr extended_storage_iterator() - : it{} {} - - constexpr extended_storage_iterator(iterator_type base, Other... other) - : it{base, other...} {} - - template - requires (!stl::same_as && ...) && (stl::constructible_from && ...) - constexpr extended_storage_iterator(const extended_storage_iterator &other) - : it{other.it} {} - - constexpr extended_storage_iterator &operator++() noexcept { - return ++stl::get(it), (++stl::get(it), ...), *this; - } - - constexpr extended_storage_iterator operator++(int) noexcept { - const extended_storage_iterator orig = *this; - return ++(*this), orig; - } - - [[nodiscard]] constexpr pointer operator->() const noexcept { - return operator*(); - } - - [[nodiscard]] constexpr reference operator*() const noexcept { - return {*stl::get(it), *stl::get(it)...}; - } - - [[nodiscard]] constexpr iterator_type base() const noexcept { - return stl::get(it); - } - - template - [[nodiscard]] constexpr bool operator==(const extended_storage_iterator &other) const noexcept { - return stl::get<0>(it) == stl::get<0>(other.it); - } - -private: - stl::tuple it; -}; - -} // namespace internal -/*! @endcond */ - -/** - * @brief Storage implementation. - * - * Internal data structures arrange elements to maximize performance. There are - * no guarantees that objects are returned in the insertion order when iterate - * a storage. Do not make assumption on the order in any case. - * - * @warning - * Empty types aren't explicitly instantiated. Therefore, many of the functions - * normally available for non-empty types will not be available for empty ones. - * - * @tparam Type Element type. - * @tparam Entity A valid entity type. - * @tparam Allocator Type of allocator used to manage memory and elements. - */ -template -class basic_storage: public basic_sparse_set::template rebind_alloc> { - using alloc_traits = stl::allocator_traits; - static_assert(stl::is_same_v, "Invalid value type"); - using container_type = stl::vector>; - using underlying_type = basic_sparse_set>; - using underlying_iterator = underlying_type::basic_iterator; - using traits_type = component_traits; - - [[nodiscard]] auto &element_at(const stl::size_t pos) const { - return payload[pos / traits_type::page_size][fast_mod(pos, traits_type::page_size)]; - } - - auto assure_at_least(const stl::size_t pos) { - const auto idx = pos / traits_type::page_size; - - if(!(idx < payload.size())) { - auto curr = payload.size(); - allocator_type allocator{get_allocator()}; - payload.resize(idx + 1u, nullptr); - - ENTT_TRY { - for(const auto last = payload.size(); curr < last; ++curr) { - payload[curr] = alloc_traits::allocate(allocator, traits_type::page_size); - } - } - ENTT_CATCH { - payload.resize(curr); - ENTT_THROW; - } - } - - return payload[idx] + fast_mod(pos, traits_type::page_size); - } - - template - auto emplace_element(const Entity entt, const bool force_back, Args &&...args) { - const auto it = base_type::try_emplace(entt, force_back); - - ENTT_TRY { - auto *elem = stl::to_address(assure_at_least(static_cast(it.index()))); - entt::uninitialized_construct_using_allocator(elem, get_allocator(), stl::forward(args)...); - } - ENTT_CATCH { - base_type::pop(it, it + 1u); - ENTT_THROW; - } - - return it; - } - - void shrink_to_size(const stl::size_t sz) { - const auto from = (sz + traits_type::page_size - 1u) / traits_type::page_size; - allocator_type allocator{get_allocator()}; - - if constexpr(!stl::is_trivially_destructible_v) { - for(auto pos = sz, length = base_type::size(); pos < length; ++pos) { - if constexpr(traits_type::in_place_delete) { - if(base_type::data()[pos] != tombstone) { - alloc_traits::destroy(allocator, stl::addressof(element_at(pos))); - } - } else { - alloc_traits::destroy(allocator, stl::addressof(element_at(pos))); - } - } - } - - for(auto pos = from, last = payload.size(); pos < last; ++pos) { - alloc_traits::deallocate(allocator, payload[pos], traits_type::page_size); - } - - payload.resize(from); - payload.shrink_to_fit(); - } - - void swap_at(const stl::size_t lhs, const stl::size_t rhs) { - using stl::swap; - swap(element_at(lhs), element_at(rhs)); - } - - void move_to(const stl::size_t lhs, const stl::size_t rhs) { - auto &elem = element_at(lhs); - allocator_type allocator{get_allocator()}; - entt::uninitialized_construct_using_allocator(stl::to_address(assure_at_least(rhs)), allocator, stl::move(elem)); - alloc_traits::destroy(allocator, stl::addressof(elem)); - } - -private: - [[nodiscard]] const void *get_at(const stl::size_t pos) const final { - return stl::addressof(element_at(pos)); - } - - void swap_or_move([[maybe_unused]] const stl::size_t from, [[maybe_unused]] const stl::size_t to) override { - static constexpr bool is_pinned_type = !(stl::is_move_constructible_v && stl::is_move_assignable_v); - // use a runtime value to avoid compile-time suppression that drives the code coverage tool crazy - ENTT_ASSERT((from + 1u) && !is_pinned_type, "Pinned type"); - - if constexpr(!is_pinned_type) { - if constexpr(traits_type::in_place_delete) { - (base_type::operator[](to) == tombstone) ? move_to(from, to) : swap_at(from, to); - } else { - swap_at(from, to); - } - } - } - -protected: - /** - * @brief Erases entities from a storage. - * @param first An iterator to the first element of the range of entities. - * @param last An iterator past the last element of the range of entities. - */ - void pop(underlying_iterator first, underlying_iterator last) override { - for(allocator_type allocator{get_allocator()}; first != last; ++first) { - // cannot use first.index() because it would break with cross iterators - auto &elem = element_at(base_type::index(*first)); - - if constexpr(traits_type::in_place_delete) { - base_type::in_place_pop(*first); - alloc_traits::destroy(allocator, stl::addressof(elem)); - } else if constexpr(stl::is_trivially_destructible_v) { - elem = stl::move(element_at(base_type::size() - 1u)); - base_type::swap_and_pop(*first); - } else { - auto &other = element_at(base_type::size() - 1u); - // destroying on exit allows reentrant destructors - [[maybe_unused]] auto unused = stl::exchange(elem, stl::move(other)); - alloc_traits::destroy(allocator, stl::addressof(other)); - base_type::swap_and_pop(*first); - } - } - } - - /*! @brief Erases all entities of a storage. */ - void pop_all() override { - if constexpr(stl::is_trivially_destructible_v) { - base_type::pop_all(); - } else { - allocator_type allocator{get_allocator()}; - - for(auto first = base_type::begin(); !(first.index() < 0); ++first) { - if constexpr(traits_type::in_place_delete) { - if(*first != tombstone) { - base_type::in_place_pop(*first); - alloc_traits::destroy(allocator, stl::addressof(element_at(static_cast(first.index())))); - } - } else { - base_type::swap_and_pop(*first); - alloc_traits::destroy(allocator, stl::addressof(element_at(static_cast(first.index())))); - } - } - } - } - - /** - * @brief Assigns an entity to a storage. - * @param entt A valid identifier. - * @param value Optional opaque value. - * @param force_back Force back insertion. - * @return Iterator pointing to the emplaced element. - */ - underlying_iterator try_emplace([[maybe_unused]] const Entity entt, [[maybe_unused]] const bool force_back, const void *value) override { - if(value != nullptr) { - if constexpr(stl::is_copy_constructible_v) { - return emplace_element(entt, force_back, *static_cast(value)); - } else { - return base_type::end(); - } - } else { - if constexpr(stl::is_default_constructible_v) { - return emplace_element(entt, force_back); - } else { - return base_type::end(); - } - } - } - -public: - /*! @brief Allocator type. */ - using allocator_type = Allocator; - /*! @brief Base type. */ - using base_type = underlying_type; - /*! @brief Element type. */ - using element_type = Type; - /*! @brief Type of the objects assigned to entities. */ - using value_type = element_type; - /*! @brief Underlying entity identifier. */ - using entity_type = Entity; - /*! @brief Unsigned integer type. */ - using size_type = stl::size_t; - /*! @brief Signed integer type. */ - using difference_type = stl::ptrdiff_t; - /*! @brief Pointer type to contained elements. */ - using pointer = container_type::pointer; - /*! @brief Constant pointer type to contained elements. */ - using const_pointer = alloc_traits::template rebind_traits::const_pointer; - /*! @brief Random access iterator type. */ - using iterator = internal::storage_iterator; - /*! @brief Constant random access iterator type. */ - using const_iterator = internal::storage_iterator; - /*! @brief Reverse iterator type. */ - using reverse_iterator = stl::reverse_iterator; - /*! @brief Constant reverse iterator type. */ - using const_reverse_iterator = stl::reverse_iterator; - /*! @brief Extended iterable storage proxy. */ - using iterable = iterable_adaptor>; - /*! @brief Constant extended iterable storage proxy. */ - using const_iterable = iterable_adaptor>; - /*! @brief Extended reverse iterable storage proxy. */ - using reverse_iterable = iterable_adaptor>; - /*! @brief Constant extended reverse iterable storage proxy. */ - using const_reverse_iterable = iterable_adaptor>; - /*! @brief Storage deletion policy. */ - static constexpr deletion_policy storage_policy{traits_type::in_place_delete}; - - /*! @brief Default constructor. */ - basic_storage() - : basic_storage{allocator_type{}} {} - - /** - * @brief Constructs an empty storage with a given allocator. - * @param allocator The allocator to use. - */ - explicit basic_storage(const allocator_type &allocator) - : base_type{type_id(), storage_policy, allocator}, - payload{allocator} {} - - /*! @brief Default copy constructor, deleted on purpose. */ - basic_storage(const basic_storage &) = delete; - - /** - * @brief Move constructor. - * @param other The instance to move from. - */ - basic_storage(basic_storage &&other) noexcept - : base_type{static_cast(other)}, - payload{stl::move(other.payload)} {} - - /** - * @brief Allocator-extended move constructor. - * @param other The instance to move from. - * @param allocator The allocator to use. - */ - basic_storage(basic_storage &&other, const allocator_type &allocator) - : base_type{static_cast(other), allocator}, - payload{stl::move(other.payload), allocator} { - ENTT_ASSERT(alloc_traits::is_always_equal::value || get_allocator() == other.get_allocator(), "Copying a storage is not allowed"); - } - - /*! @brief Default destructor. */ - // NOLINTNEXTLINE(bugprone-exception-escape) - ~basic_storage() override { - shrink_to_size(0u); - } - - /** - * @brief Default copy assignment operator, deleted on purpose. - * @return This storage. - */ - basic_storage &operator=(const basic_storage &) = delete; - - /** - * @brief Move assignment operator. - * @param other The instance to move from. - * @return This storage. - */ - basic_storage &operator=(basic_storage &&other) noexcept { - ENTT_ASSERT(alloc_traits::is_always_equal::value || get_allocator() == other.get_allocator(), "Copying a storage is not allowed"); - swap(other); - return *this; - } - - /** - * @brief Exchanges the contents with those of a given storage. - * @param other Storage to exchange the content with. - */ - void swap(basic_storage &other) noexcept { - using stl::swap; - swap(payload, other.payload); - base_type::swap(other); - } - - /** - * @brief Returns the associated allocator. - * @return The associated allocator. - */ - [[nodiscard]] constexpr allocator_type get_allocator() const noexcept { - return payload.get_allocator(); - } - - /** - * @brief Increases the capacity of a storage. - * - * 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) override { - if(cap != 0u) { - base_type::reserve(cap); - assure_at_least(cap - 1u); - } - } - - /** - * @brief Returns the number of elements that a storage has currently - * allocated space for. - * @return Capacity of the storage. - */ - [[nodiscard]] size_type capacity() const noexcept override { - return payload.size() * traits_type::page_size; - } - - /*! @brief Requests the removal of unused capacity. */ - void shrink_to_fit() override { - base_type::shrink_to_fit(); - shrink_to_size(base_type::size()); - } - - /** - * @brief Direct access to the array of objects. - * @return A pointer to the array of objects. - */ - [[nodiscard]] const_pointer raw() const noexcept { - return payload.data(); - } - - /*! @copydoc raw */ - [[nodiscard]] pointer raw() noexcept { - return payload.data(); - } - - /** - * @brief Returns an iterator to the beginning. - * - * If the storage is empty, the returned iterator will be equal to `end()`. - * - * @return An iterator to the first instance of the internal array. - */ - [[nodiscard]] const_iterator cbegin() const noexcept { - const auto pos = static_cast(base_type::size()); - return const_iterator{&payload, pos}; - } - - /*! @copydoc cbegin */ - [[nodiscard]] const_iterator begin() const noexcept { - return cbegin(); - } - - /*! @copydoc begin */ - [[nodiscard]] iterator begin() noexcept { - const auto pos = static_cast(base_type::size()); - return iterator{&payload, pos}; - } - - /** - * @brief Returns an iterator to the end. - * @return An iterator to the element following the last instance of the - * internal array. - */ - [[nodiscard]] const_iterator cend() const noexcept { - return const_iterator{&payload, {}}; - } - - /*! @copydoc cend */ - [[nodiscard]] const_iterator end() const noexcept { - return cend(); - } - - /*! @copydoc end */ - [[nodiscard]] iterator end() noexcept { - return iterator{&payload, {}}; - } - - /** - * @brief Returns a reverse iterator to the beginning. - * - * If the storage is empty, the returned iterator will be equal to `rend()`. - * - * @return An iterator to the first instance of the reversed internal array. - */ - [[nodiscard]] const_reverse_iterator crbegin() const noexcept { - return stl::make_reverse_iterator(cend()); - } - - /*! @copydoc crbegin */ - [[nodiscard]] const_reverse_iterator rbegin() const noexcept { - return crbegin(); - } - - /*! @copydoc rbegin */ - [[nodiscard]] reverse_iterator rbegin() noexcept { - return stl::make_reverse_iterator(end()); - } - - /** - * @brief Returns a reverse iterator to the end. - * @return An iterator to the element following the last instance of the - * reversed internal array. - */ - [[nodiscard]] const_reverse_iterator crend() const noexcept { - return stl::make_reverse_iterator(cbegin()); - } - - /*! @copydoc crend */ - [[nodiscard]] const_reverse_iterator rend() const noexcept { - return crend(); - } - - /*! @copydoc rend */ - [[nodiscard]] reverse_iterator rend() noexcept { - return stl::make_reverse_iterator(begin()); - } - - /** - * @brief Returns the object assigned to an entity. - * - * @warning - * Attempting to use an entity that doesn't belong to the storage results in - * undefined behavior. - * - * @param entt A valid identifier. - * @return The object assigned to the entity. - */ - [[nodiscard]] const value_type &get(const entity_type entt) const noexcept { - return element_at(base_type::index(entt)); - } - - /*! @copydoc get */ - [[nodiscard]] value_type &get(const entity_type entt) noexcept { - return const_cast(stl::as_const(*this).get(entt)); - } - - /** - * @brief Returns the object assigned to an entity as a tuple. - * @param entt A valid identifier. - * @return The object assigned to the entity as a tuple. - */ - [[nodiscard]] stl::tuple get_as_tuple(const entity_type entt) const noexcept { - return stl::forward_as_tuple(get(entt)); - } - - /*! @copydoc get_as_tuple */ - [[nodiscard]] stl::tuple get_as_tuple(const entity_type entt) noexcept { - return stl::forward_as_tuple(get(entt)); - } - - /** - * @brief Assigns an entity to a storage and constructs its object. - * - * @warning - * Attempting to use an entity that already belongs to the storage results - * in undefined behavior. - * - * @tparam Args Types of arguments to use to construct the object. - * @param entt A valid identifier. - * @param args Parameters to use to construct an object for the entity. - * @return A reference to the newly created object. - */ - template - value_type &emplace(const entity_type entt, Args &&...args) { - if constexpr(stl::is_aggregate_v && (sizeof...(Args) != 0u || !stl::is_default_constructible_v)) { - const auto it = emplace_element(entt, false, Type{stl::forward(args)...}); - return element_at(static_cast(it.index())); - } else { - const auto it = emplace_element(entt, false, stl::forward(args)...); - return element_at(static_cast(it.index())); - } - } - - /** - * @brief Updates the instance assigned to a given entity in-place. - * @tparam Func Types of the function objects to invoke. - * @param entt A valid identifier. - * @param func Valid function objects. - * @return A reference to the updated instance. - */ - template - value_type &patch(const entity_type entt, Func &&...func) { - const auto idx = base_type::index(entt); - auto &elem = element_at(idx); - (stl::forward(func)(elem), ...); - return elem; - } - - /** - * @brief Assigns one or more entities to a storage and constructs their - * objects from a given instance. - * - * @warning - * Attempting to assign an entity that already belongs to the storage - * results in undefined behavior. - * - * @param first An iterator to the first element of the range of entities. - * @param last An iterator past the last element of the range of entities. - * @param value An instance of the object to construct. - * @return Iterator pointing to the first element inserted, if any. - */ - iterator insert(stl::input_iterator auto first, stl::input_iterator auto last, const value_type &value = {}) { - for(; first != last; ++first) { - emplace_element(*first, true, value); - } - - return begin(); - } - - /** - * @brief Assigns one or more entities to a storage and constructs their - * objects from a given range. - * - * @sa construct - * - * @tparam It Type of input iterator. - * @param first An iterator to the first element of the range of entities. - * @param last An iterator past the last element of the range of entities. - * @param from An iterator to the first element of the range of objects. - * @return Iterator pointing to the first element inserted, if any. - */ - template - requires stl::same_as::value_type, value_type> - iterator insert(stl::input_iterator auto first, stl::input_iterator auto last, It from) { - for(; first != last; ++first, ++from) { - emplace_element(*first, true, *from); - } - - return begin(); - } - - /** - * @brief Returns an iterable object to use to _visit_ a storage. - * - * The iterable object returns a tuple that contains the current entity and - * a reference to its element. - * - * @return An iterable object to use to _visit_ the storage. - */ - [[nodiscard]] iterable each() noexcept { - return iterable{{base_type::begin(), begin()}, {base_type::end(), end()}}; - } - - /*! @copydoc each */ - [[nodiscard]] const_iterable each() const noexcept { - return const_iterable{{base_type::cbegin(), cbegin()}, {base_type::cend(), cend()}}; - } - - /** - * @brief Returns a reverse iterable object to use to _visit_ a storage. - * - * @sa each - * - * @return A reverse iterable object to use to _visit_ the storage. - */ - [[nodiscard]] reverse_iterable reach() noexcept { - return reverse_iterable{{base_type::rbegin(), rbegin()}, {base_type::rend(), rend()}}; - } - - /*! @copydoc reach */ - [[nodiscard]] const_reverse_iterable reach() const noexcept { - return const_reverse_iterable{{base_type::crbegin(), crbegin()}, {base_type::crend(), crend()}}; - } - -private: - container_type payload; -}; - -/*! @copydoc basic_storage */ -template -requires (component_traits::page_size == 0u) -class basic_storage - : public basic_sparse_set::template rebind_alloc> { - using alloc_traits = stl::allocator_traits; - static_assert(stl::is_same_v, "Invalid value type"); - using traits_type = component_traits; - -public: - /*! @brief Allocator type. */ - using allocator_type = Allocator; - /*! @brief Base type. */ - using base_type = basic_sparse_set>; - /*! @brief Element type. */ - using element_type = Type; - /*! @brief Type of the objects assigned to entities. */ - using value_type = void; - /*! @brief Underlying entity identifier. */ - using entity_type = Entity; - /*! @brief Unsigned integer type. */ - using size_type = stl::size_t; - /*! @brief Signed integer type. */ - using difference_type = stl::ptrdiff_t; - /*! @brief Extended iterable storage proxy. */ - using iterable = iterable_adaptor>; - /*! @brief Constant extended iterable storage proxy. */ - using const_iterable = iterable_adaptor>; - /*! @brief Extended reverse iterable storage proxy. */ - using reverse_iterable = iterable_adaptor>; - /*! @brief Constant extended reverse iterable storage proxy. */ - using const_reverse_iterable = iterable_adaptor>; - /*! @brief Storage deletion policy. */ - static constexpr deletion_policy storage_policy{traits_type::in_place_delete}; - - /*! @brief Default constructor. */ - basic_storage() - : basic_storage{allocator_type{}} {} - - /** - * @brief Constructs an empty container with a given allocator. - * @param allocator The allocator to use. - */ - explicit basic_storage(const allocator_type &allocator) - : base_type{type_id(), storage_policy, allocator} {} - - /*! @brief Default copy constructor, deleted on purpose. */ - basic_storage(const basic_storage &) = delete; - - /** - * @brief Move constructor. - * @param other The instance to move from. - */ - basic_storage(basic_storage &&other) noexcept = default; - - /** - * @brief Allocator-extended move constructor. - * @param other The instance to move from. - * @param allocator The allocator to use. - */ - basic_storage(basic_storage &&other, const allocator_type &allocator) - : base_type{stl::move(other), allocator} {} - - /*! @brief Default destructor. */ - ~basic_storage() override = default; - - /** - * @brief Default copy assignment operator, deleted on purpose. - * @return This storage. - */ - basic_storage &operator=(const basic_storage &) = delete; - - /** - * @brief Move assignment operator. - * @param other The instance to move from. - * @return This storage. - */ - basic_storage &operator=(basic_storage &&other) noexcept = default; - - /** - * @brief Returns the associated allocator. - * @return The associated allocator. - */ - [[nodiscard]] constexpr allocator_type get_allocator() const noexcept { - return allocator_type{base_type::get_allocator()}; - } - - /** - * @brief Returns the object assigned to an entity, that is `void`. - * - * @warning - * Attempting to use an entity that doesn't belong to the storage results in - * undefined behavior. - * - * @param entt A valid identifier. - */ - void get([[maybe_unused]] const entity_type entt) const noexcept { - ENTT_ASSERT(base_type::contains(entt), "Invalid entity"); - } - - /** - * @brief Returns an empty tuple. - * @param entt A valid identifier. - * @return Returns an empty tuple. - */ - [[nodiscard]] stl::tuple<> get_as_tuple([[maybe_unused]] const entity_type entt) const noexcept { - ENTT_ASSERT(base_type::contains(entt), "Invalid entity"); - return stl::tuple{}; - } - - /** - * @brief Assigns an entity to a storage and constructs its object. - * - * @warning - * Attempting to use an entity that already belongs to the storage results - * in undefined behavior. - * - * @param entt A valid identifier. - */ - void emplace(const entity_type entt, const auto &...) { - base_type::try_emplace(entt, false); - } - - /** - * @brief Updates the instance assigned to a given entity in-place. - * @tparam Func Types of the function objects to invoke. - * @param entt A valid identifier. - * @param func Valid function objects. - */ - template - void patch([[maybe_unused]] const entity_type entt, Func &&...func) { - ENTT_ASSERT(base_type::contains(entt), "Invalid entity"); - (stl::forward(func)(), ...); - } - - /** - * @brief Assigns entities to a storage. - * @param first An iterator to the first element of the range of entities. - * @param last An iterator past the last element of the range of entities. - */ - void insert(stl::input_iterator auto first, stl::input_iterator auto last, const auto &...) { - for(; first != last; ++first) { - base_type::try_emplace(*first, true); - } - } - - /** - * @brief Returns an iterable object to use to _visit_ a storage. - * - * The iterable object returns a tuple that contains the current entity. - * - * @return An iterable object to use to _visit_ the storage. - */ - [[nodiscard]] iterable each() noexcept { - return iterable{base_type::begin(), base_type::end()}; - } - - /*! @copydoc each */ - [[nodiscard]] const_iterable each() const noexcept { - return const_iterable{base_type::cbegin(), base_type::cend()}; - } - - /** - * @brief Returns a reverse iterable object to use to _visit_ a storage. - * - * @sa each - * - * @return A reverse iterable object to use to _visit_ the storage. - */ - [[nodiscard]] reverse_iterable reach() noexcept { - return reverse_iterable{{base_type::rbegin()}, {base_type::rend()}}; - } - - /*! @copydoc reach */ - [[nodiscard]] const_reverse_iterable reach() const noexcept { - return const_reverse_iterable{{base_type::crbegin()}, {base_type::crend()}}; - } -}; - -/** - * @brief Swap-only entity storage specialization. - * @tparam Entity A valid entity type. - * @tparam Allocator Type of allocator used to manage memory and elements. - */ -template -class basic_storage - : public basic_sparse_set { - using alloc_traits = stl::allocator_traits; - static_assert(stl::is_same_v, "Invalid value type"); - using underlying_iterator = basic_sparse_set::basic_iterator; - using traits_type = entt_traits; - - auto from_placeholder() noexcept { - const auto entt = traits_type::combine(static_cast(placeholder), {}); - ENTT_ASSERT(entt != null, "No more entities available"); - placeholder += static_cast(entt != null); - return entt; - } - - auto next() noexcept { - entity_type entt = from_placeholder(); - - while(base_type::current(entt) != traits_type::to_version(tombstone) && entt != null) { - entt = from_placeholder(); - } - - return entt; - } - -protected: - /*! @brief Erases all entities of a storage. */ - void pop_all() override { - base_type::pop_all(); - placeholder = {}; - } - - /** - * @brief Assigns an entity to a storage. - * @param hint A valid identifier. - * @return Iterator pointing to the emplaced element. - */ - underlying_iterator try_emplace(const Entity hint, const bool, const void *) override { - return base_type::find(generate(hint)); - } - -public: - /*! @brief Allocator type. */ - using allocator_type = Allocator; - /*! @brief Base type. */ - using base_type = basic_sparse_set; - /*! @brief Element type. */ - using element_type = Entity; - /*! @brief Type of the objects assigned to entities. */ - using value_type = void; - /*! @brief Underlying entity identifier. */ - using entity_type = Entity; - /*! @brief Unsigned integer type. */ - using size_type = stl::size_t; - /*! @brief Signed integer type. */ - using difference_type = stl::ptrdiff_t; - /*! @brief Extended iterable storage proxy. */ - using iterable = iterable_adaptor>; - /*! @brief Constant extended iterable storage proxy. */ - using const_iterable = iterable_adaptor>; - /*! @brief Extended reverse iterable storage proxy. */ - using reverse_iterable = iterable_adaptor>; - /*! @brief Constant extended reverse iterable storage proxy. */ - using const_reverse_iterable = iterable_adaptor>; - /*! @brief Storage deletion policy. */ - static constexpr deletion_policy storage_policy = deletion_policy::swap_only; - - /*! @brief Default constructor. */ - basic_storage() - : basic_storage{allocator_type{}} { - } - - /** - * @brief Constructs an empty container with a given allocator. - * @param allocator The allocator to use. - */ - explicit basic_storage(const allocator_type &allocator) - : base_type{type_id(), storage_policy, allocator} {} - - /*! @brief Default copy constructor, deleted on purpose. */ - basic_storage(const basic_storage &) = delete; - - /** - * @brief Move constructor. - * @param other The instance to move from. - */ - // NOLINTNEXTLINE(cppcoreguidelines-rvalue-reference-param-not-moved) - basic_storage(basic_storage &&other) noexcept - : base_type{static_cast(other)}, - placeholder{other.placeholder} {} - - /** - * @brief Allocator-extended move constructor. - * @param other The instance to move from. - * @param allocator The allocator to use. - */ - // NOLINTNEXTLINE(cppcoreguidelines-rvalue-reference-param-not-moved) - basic_storage(basic_storage &&other, const allocator_type &allocator) - : base_type{static_cast(other), allocator}, - placeholder{other.placeholder} {} - - /*! @brief Default destructor. */ - ~basic_storage() override = default; - - /** - * @brief Default copy assignment operator, deleted on purpose. - * @return This storage. - */ - basic_storage &operator=(const basic_storage &) = delete; - - /** - * @brief Move assignment operator. - * @param other The instance to move from. - * @return This storage. - */ - basic_storage &operator=(basic_storage &&other) noexcept { - placeholder = other.placeholder; - base_type::operator=(stl::move(other)); - return *this; - } - - /** - * @brief Exchanges the contents with those of a given storage. - * @param other Storage to exchange the content with. - */ - void swap(basic_storage &other) noexcept { - using stl::swap; - swap(placeholder, other.placeholder); - base_type::swap(other); - } - - /** - * @brief Returns the object assigned to an entity, that is `void`. - * - * @warning - * Attempting to use an entity that doesn't belong to the storage results in - * undefined behavior. - * - * @param entt A valid identifier. - */ - void get([[maybe_unused]] const entity_type entt) const noexcept { - ENTT_ASSERT(base_type::index(entt) < base_type::free_list(), "The requested entity is not a live one"); - } - - /** - * @brief Returns an empty tuple. - * @param entt A valid identifier. - * @return Returns an empty tuple. - */ - [[nodiscard]] stl::tuple<> get_as_tuple([[maybe_unused]] const entity_type entt) const noexcept { - ENTT_ASSERT(base_type::index(entt) < base_type::free_list(), "The requested entity is not a live one"); - return stl::tuple{}; - } - - /** - * @brief Creates a new identifier or recycles a destroyed one. - * @return A valid identifier. - */ - entity_type generate() { - const auto len = base_type::free_list(); - const auto entt = (len == base_type::size()) ? next() : base_type::data()[len]; - return *base_type::try_emplace(entt, true); - } - - /** - * @brief Creates a new identifier or recycles a destroyed one. - * - * If the requested identifier isn't in use, the suggested one is used. - * Otherwise, a new identifier is returned. - * - * @param hint Required identifier. - * @return A valid identifier. - */ - entity_type generate(const entity_type hint) { - if(hint != null && hint != tombstone) { - if(const auto curr = traits_type::construct(traits_type::to_entity(hint), base_type::current(hint)); curr == tombstone || !(base_type::index(curr) < base_type::free_list())) { - return *base_type::try_emplace(hint, true); - } - } - - return generate(); - } - - /** - * @brief Assigns each element in a range an identifier. - * @tparam It Type of output iterator. - * @param first An iterator to the first element of the range to generate. - * @param last An iterator past the last element of the range to generate. - */ - template It> - void generate(It first, It last) { - for(const auto sz = base_type::size(); first != last && base_type::free_list() != sz; ++first) { - *first = *base_type::try_emplace(base_type::data()[base_type::free_list()], true); - } - - for(; first != last; ++first) { - *first = *base_type::try_emplace(next(), true); - } - } - - /** - * @brief Updates a given identifier. - * @tparam Func Types of the function objects to invoke. - * @param entt A valid identifier. - * @param func Valid function objects. - */ - template - void patch([[maybe_unused]] const entity_type entt, Func &&...func) { - ENTT_ASSERT(base_type::index(entt) < base_type::free_list(), "The requested entity is not a live one"); - (stl::forward(func)(), ...); - } - - /** - * @brief Returns an iterable object to use to _visit_ a storage. - * - * The iterable object returns a tuple that contains the current entity. - * - * @return An iterable object to use to _visit_ the storage. - */ - [[nodiscard]] iterable each() noexcept { - return stl::as_const(*this).each(); - } - - /*! @copydoc each */ - [[nodiscard]] const_iterable each() const noexcept { - const auto it = base_type::cend(); - const auto offset = static_cast(base_type::free_list()); - return const_iterable{it - offset, it}; - } - - /** - * @brief Returns a reverse iterable object to use to _visit_ a storage. - * - * @sa each - * - * @return A reverse iterable object to use to _visit_ the storage. - */ - [[nodiscard]] reverse_iterable reach() noexcept { - return stl::as_const(*this).reach(); - } - - /*! @copydoc reach */ - [[nodiscard]] const_reverse_iterable reach() const noexcept { - const auto it = base_type::crbegin(); - const auto offset = static_cast(base_type::free_list()); - return const_reverse_iterable{it, it + offset}; - } - - /** - * @brief Sets the starting identifier for generation. - * - * The version is ignored, regardless of the value. - * - * @param hint A valid identifier. - */ - void start_from(const entity_type hint) { - placeholder = static_cast(traits_type::to_entity(hint)); - } - -private: - size_type placeholder{}; -}; - -} // namespace entt - -#endif diff --git a/include/entt/entity/view.hpp b/include/entt/entity/view.hpp deleted file mode 100644 index feb54c4..0000000 --- a/include/entt/entity/view.hpp +++ /dev/null @@ -1,1142 +0,0 @@ -#ifndef ENTT_ENTITY_VIEW_HPP -#define ENTT_ENTITY_VIEW_HPP - -#include "../config/config.h" -#include "../core/concepts.hpp" -#include "../core/iterator.hpp" -#include "../core/type_traits.hpp" -#include "../stl/array.hpp" -#include "../stl/concepts.hpp" -#include "../stl/cstddef.hpp" -#include "../stl/iterator.hpp" -#include "../stl/tuple.hpp" -#include "../stl/type_traits.hpp" -#include "../stl/utility.hpp" -#include "entity.hpp" -#include "fwd.hpp" - -namespace entt { - -/*! @cond ENTT_INTERNAL */ -namespace internal { - -template -// NOLINTNEXTLINE(misc-redundant-expression) -static constexpr bool tombstone_check_v = ((sizeof...(Type) == 1u) && ... && (Type::storage_policy == deletion_policy::in_place)); - -template -const Type *view_placeholder() { - static const Type placeholder{}; - return &placeholder; -} - -[[nodiscard]] bool all_of(auto first, const auto last, const auto entt) noexcept { - for(; (first != last) && (*first)->contains(entt); ++first) {} - return first == last; -} - -[[nodiscard]] bool none_of(auto first, const auto last, const auto entt) noexcept { - for(; (first != last) && !(*first)->contains(entt); ++first) {} - return first == last; -} - -template -[[nodiscard]] bool fully_initialized(It first, const It last, const stl::remove_pointer_t::value_type> *placeholder) noexcept { - for(; (first != last) && *first != placeholder; ++first) {} - return first == last; -} - -template -[[nodiscard]] Result view_pack(const View &view, const Other &other, stl::index_sequence, stl::index_sequence, stl::index_sequence, stl::index_sequence) { - Result elem{}; - // friend-initialization, avoid multiple calls to refresh - elem.pools = {view.template storage()..., other.template storage()...}; - [[maybe_unused]] const auto filter_or_placeholder = [placeholder = elem.placeholder](auto *value) { return (value == nullptr) ? placeholder : value; }; - elem.filter = {filter_or_placeholder(view.template storage())..., filter_or_placeholder(other.template storage())...}; - elem.refresh(); - return elem; -} - -template -class view_iterator final { - template - friend struct extended_view_iterator; - - using iterator_type = Type::const_iterator; - using iterator_traits = stl::iterator_traits; - - [[nodiscard]] bool valid(const iterator_traits::value_type entt) const noexcept { - return (!Checked || (entt != tombstone)) - && ((Get == 1u) || (internal::all_of(pools.begin(), pools.begin() + index, entt) && internal::all_of(pools.begin() + index + 1, pools.end(), entt))) - && ((Exclude == 0u) || internal::none_of(filter.begin(), filter.end(), entt)); - } - - void seek_next() { - for(constexpr iterator_type sentinel{}; it != sentinel && !valid(*it); ++it) {} - } - -public: - using value_type = iterator_traits::value_type; - using pointer = iterator_traits::pointer; - using reference = iterator_traits::reference; - using difference_type = iterator_traits::difference_type; - using iterator_category = stl::forward_iterator_tag; - - constexpr view_iterator() noexcept - : it{}, - pools{}, - filter{}, - index{} {} - - view_iterator(iterator_type first, stl::array value, stl::array excl, const stl::size_t idx) noexcept - : it{first}, - pools{value}, - filter{excl}, - index{static_cast(idx)} { - ENTT_ASSERT((Get != 1u) || (Exclude != 0u) || pools[0u]->policy() == deletion_policy::in_place, "Non in-place storage view iterator"); - seek_next(); - } - - view_iterator &operator++() noexcept { - ++it; - seek_next(); - return *this; - } - - view_iterator operator++(int) noexcept { - const view_iterator orig = *this; - return ++(*this), orig; - } - - [[nodiscard]] pointer operator->() const noexcept { - return &*it; - } - - [[nodiscard]] reference operator*() const noexcept { - return *operator->(); - } - - template - [[nodiscard]] constexpr bool operator==(const view_iterator &other) const noexcept { - return it == other.it; - } - -private: - iterator_type it; - stl::array pools; - stl::array filter; - difference_type index; -}; - -template -struct extended_view_iterator final { - using iterator_type = It; - using value_type = decltype(stl::tuple_cat(stl::make_tuple(*stl::declval()), stl::declval().get_as_tuple({})...)); - using pointer = input_iterator_pointer; - using reference = value_type; - using difference_type = stl::ptrdiff_t; - using iterator_category = stl::input_iterator_tag; - using iterator_concept = stl::forward_iterator_tag; - - constexpr extended_view_iterator() - : it{} {} - - extended_view_iterator(iterator_type from) - : it{from} {} - - extended_view_iterator &operator++() noexcept { - return ++it, *this; - } - - extended_view_iterator operator++(int) noexcept { - const extended_view_iterator orig = *this; - return ++(*this), orig; - } - - [[nodiscard]] reference operator*() const noexcept { - return [this](stl::index_sequence) { - return stl::tuple_cat(stl::make_tuple(*it), static_cast(const_cast *>(stl::get(it.pools)))->get_as_tuple(*it)...); - }(stl::index_sequence_for{}); - } - - [[nodiscard]] pointer operator->() const noexcept { - return operator*(); - } - - [[nodiscard]] constexpr iterator_type base() const noexcept { - return it; - } - - template - [[nodiscard]] constexpr bool operator==(const extended_view_iterator &other) const noexcept { - return it == other.it; - } - -private: - It it; -}; - -} // namespace internal -/*! @endcond */ - -/** - * @brief View implementation. - * - * Primary template isn't defined on purpose. All the specializations give a - * compile-time error, but for a few reasonable cases. - * - * @b Important - * - * View iterators aren't invalidated if: - * - * * New elements are added to the storage iterated by the view. - * * The entity currently returned is modified (for example, elements are added - * or removed from it). - * * The entity currently returned is destroyed. - * - * In all other cases, modifying the storage iterated by a view in any way can - * invalidate all iterators. - */ -template -class basic_view; - -/** - * @brief Basic storage view implementation. - * @warning For internal use only, backward compatibility not guaranteed. - * @tparam Type Common type among all storage types. - * @tparam Checked True to enable the tombstone check, false otherwise. - * @tparam Get Number of storage iterated by the view. - * @tparam Exclude Number of storage used to filter the view. - */ -template -class basic_common_view { - template - friend Return internal::view_pack(const View &, const Other &, stl::index_sequence, stl::index_sequence, stl::index_sequence, stl::index_sequence); - - [[nodiscard]] auto offset() const noexcept { - ENTT_ASSERT(index != Get, "Invalid view"); - return (pools[index]->policy() == deletion_policy::swap_only) ? pools[index]->free_list() : pools[index]->size(); - } - - void unchecked_refresh() noexcept { - index = 0u; - - if constexpr(Get > 1u) { - for(size_type pos{1u}; pos < Get; ++pos) { - if(pools[pos]->size() < pools[index]->size()) { - index = pos; - } - } - } - } - -protected: - /*! @cond ENTT_INTERNAL */ - basic_common_view() noexcept { - for(size_type pos{}, last = filter.size(); pos < last; ++pos) { - filter[pos] = placeholder; - } - } - - basic_common_view(stl::array value, stl::array excl) noexcept - : pools{value}, - filter{excl}, - index{Get} { - unchecked_refresh(); - } - - [[nodiscard]] const Type *pool_at(const stl::size_t pos) const noexcept { - return pools[pos]; - } - - void pool_at(const stl::size_t pos, const Type *elem) noexcept { - ENTT_ASSERT(elem != nullptr, "Unexpected element"); - pools[pos] = elem; - refresh(); - } - - [[nodiscard]] const Type *filter_at(const stl::size_t pos) const noexcept { - return (filter[pos] == placeholder) ? nullptr : filter[pos]; - } - - void filter_at(const stl::size_t pos, const Type *elem) noexcept { - ENTT_ASSERT(elem != nullptr, "Unexpected element"); - filter[pos] = elem; - } - - [[nodiscard]] bool none_of(const Type::entity_type entt) const noexcept { - return internal::none_of(filter.begin(), filter.end(), entt); - } - - void use(const stl::size_t pos) noexcept { - index = (index != Get) ? pos : Get; - } - /*! @endcond */ - -public: - /*! @brief Common type among all storage types. */ - using common_type = Type; - /*! @brief Underlying entity identifier. */ - using entity_type = Type::entity_type; - /*! @brief Unsigned integer type. */ - using size_type = stl::size_t; - /*! @brief Signed integer type. */ - using difference_type = stl::ptrdiff_t; - /*! @brief Forward iterator type. */ - using iterator = internal::view_iterator; - - /*! @brief Updates the internal leading view if required. */ - void refresh() noexcept { - size_type pos = static_cast(index != Get) * Get; - for(; pos < Get && pools[pos] != nullptr; ++pos) {} - - if(pos == Get) { - unchecked_refresh(); - } - } - - /** - * @brief Returns the leading storage of a view, if any. - * @return The leading storage of the view. - */ - [[nodiscard]] const common_type *handle() const noexcept { - return (index != Get) ? pools[index] : nullptr; - } - - /** - * @brief Estimates the number of entities iterated by the view. - * @return Estimated number of entities iterated by the view. - */ - [[nodiscard]] size_type size_hint() const noexcept { - return (index != Get) ? offset() : size_type{}; - } - - /** - * @brief Returns an iterator to the first entity of the view. - * - * If the view is empty, the returned iterator will be equal to `end()`. - * - * @return An iterator to the first entity of the view. - */ - [[nodiscard]] iterator begin() const noexcept { - return (index != Get) ? iterator{pools[index]->end() - static_cast(offset()), pools, filter, index} : iterator{}; - } - - /** - * @brief Returns an iterator that is past the last entity of the view. - * @return An iterator to the entity following the last entity of the view. - */ - [[nodiscard]] iterator end() const noexcept { - return (index != Get) ? iterator{pools[index]->end(), pools, filter, index} : iterator{}; - } - - /** - * @brief Returns the first entity of the view, if any. - * @return The first entity of the view if one exists, the null entity - * otherwise. - */ - [[nodiscard]] entity_type front() const noexcept { - const auto it = begin(); - return it != end() ? *it : null; - } - - /** - * @brief Returns the last entity of the view, if any. - * @return The last entity of the view if one exists, the null entity - * otherwise. - */ - [[nodiscard]] entity_type back() const noexcept { - if(index != Get) { - auto it = pools[index]->rbegin(); - const auto last = it + static_cast(offset()); - for(const auto idx = static_cast(index); it != last && !(internal::all_of(pools.begin(), pools.begin() + idx, *it) && internal::all_of(pools.begin() + idx + 1, pools.end(), *it) && internal::none_of(filter.begin(), filter.end(), *it)); ++it) {} - return it == last ? null : *it; - } - - return null; - } - - /** - * @brief Finds an entity. - * @param entt A valid identifier. - * @return An iterator to the given entity if it's found, past the end - * iterator otherwise. - */ - [[nodiscard]] iterator find(const entity_type entt) const noexcept { - return contains(entt) ? iterator{pools[index]->find(entt), pools, filter, index} : end(); - } - - /** - * @brief Checks if a view is fully initialized. - * @return True if the view is fully initialized, false otherwise. - */ - [[nodiscard]] explicit operator bool() const noexcept { - return (index != Get) && internal::fully_initialized(filter.begin(), filter.end(), placeholder); - } - - /** - * @brief Checks if a view contains an entity. - * @param entt A valid identifier. - * @return True if the view contains the given entity, false otherwise. - */ - [[nodiscard]] bool contains(const entity_type entt) const noexcept { - return (index != Get) - && internal::all_of(pools.begin(), pools.end(), entt) - && internal::none_of(filter.begin(), filter.end(), entt) - && pools[index]->index(entt) < offset(); - } - -private: - stl::array pools{}; - stl::array filter{}; - const common_type *placeholder{internal::view_placeholder()}; - size_type index{Get}; -}; - -/** - * @brief General purpose view. - * - * This view visits all entities that are at least in the given storage. During - * initialization, it also looks at the number of elements available for each - * storage and uses the smallest set in order to get a performance boost. - * - * @sa basic_view - * - * @tparam Get Types of storage iterated by the view. - * @tparam Exclude Types of storage used to filter the view. - */ -template -requires (sizeof...(Get) != 0u) -class basic_view, exclude_t> - : public basic_common_view, internal::tombstone_check_v, sizeof...(Get), sizeof...(Exclude)> { - using base_type = basic_common_view, internal::tombstone_check_v, sizeof...(Get), sizeof...(Exclude)>; - - template - using element_at = type_list_element_t>; - - template - static constexpr stl::size_t index_of = type_list_index_v, type_list>; - - template - [[nodiscard]] auto dispatch_get(const stl::tuple &curr) const { - if constexpr(Curr == Other) { - return stl::forward_as_tuple(stl::get(curr)...); - } else { - return storage()->get_as_tuple(stl::get<0>(curr)); - } - } - - template - void each(Func func, stl::index_sequence) const { - for(const auto curr: storage()->each()) { - if(const auto entt = stl::get<0>(curr); (!internal::tombstone_check_v || (entt != tombstone)) && ((Curr == Index || base_type::pool_at(Index)->contains(entt)) && ...) && base_type::none_of(entt)) { - if constexpr(is_applicable_v{}, stl::declval().get({})))>) { - stl::apply(func, stl::tuple_cat(stl::make_tuple(entt), dispatch_get(curr)...)); - } else { - stl::apply(func, stl::tuple_cat(dispatch_get(curr)...)); - } - } - } - } - - template - void storage_if(Type *elem) noexcept { - if(elem != nullptr) { - storage>(*elem); - } - } - -public: - /*! @brief Common type among all storage types. */ - using common_type = base_type::common_type; - /*! @brief Underlying entity identifier. */ - using entity_type = base_type::entity_type; - /*! @brief Unsigned integer type. */ - using size_type = base_type::size_type; - /*! @brief Signed integer type. */ - using difference_type = stl::ptrdiff_t; - /*! @brief Forward iterator type. */ - using iterator = base_type::iterator; - /*! @brief Iterable view type. */ - using iterable = iterable_adaptor>; - - /*! @brief Default constructor to use to create empty, invalid views. */ - basic_view() noexcept - : base_type{} {} - - /** - * @brief Constructs a view from a set of storage classes. - * @param value The storage for the types to iterate. - * @param excl The storage for the types used to filter the view. - */ - basic_view(Get &...value, Exclude &...excl) noexcept - : base_type{{&value...}, {&excl...}} { - } - - /** - * @brief Constructs a view from a set of storage classes. - * @param value The storage for the types to iterate. - * @param excl The storage for the types used to filter the view. - */ - basic_view(stl::tuple value, stl::tuple excl = {}) noexcept - : basic_view{stl::make_from_tuple(stl::tuple_cat(value, excl))} {} - - /** - * @brief Constructs a view from a convertible counterpart. - * @tparam Args Storage types managed by the other view. - * @param other A view to convert from. - */ - template - requires (!stl::same_as>) - basic_view(const basic_view &other) noexcept - : basic_view{} { - (storage_if(other.template storage()), ...); - (storage_if(other.template storage()), ...); - } - - /** - * @brief Forces a view to use a given element to drive iterations - * @tparam Type Type of element to use to drive iterations. - */ - template - void use() noexcept { - use>(); - } - - /** - * @brief Forces a view to use a given element to drive iterations - * @tparam Index Index of the element to use to drive iterations. - */ - template - void use() noexcept { - base_type::use(Index); - } - - /** - * @brief Returns the storage for a given element type, if any. - * @tparam Type Type of element of which to return the storage. - * @return The storage for the given element type. - */ - template - [[nodiscard]] auto *storage() const noexcept { - return storage>(); - } - - /** - * @brief Returns the storage for a given index, if any. - * @tparam Index Index of the storage to return. - * @return The storage for the given index. - */ - template - [[nodiscard]] auto *storage() const noexcept { - if constexpr(Index < sizeof...(Get)) { - return static_cast *>(const_cast> *>(base_type::pool_at(Index))); - } else { - return static_cast *>(const_cast> *>(base_type::filter_at(Index - sizeof...(Get)))); - } - } - - /** - * @brief Assigns a storage to a view. - * @tparam Type Type of storage to assign to the view. - * @param elem A storage to assign to the view. - */ - template - void storage(Type &elem) noexcept { - storage>(elem); - } - - /** - * @brief Assigns a storage to a view. - * @tparam Index Index of the storage to assign to the view. - * @tparam Type Type of storage to assign to the view. - * @param elem A storage to assign to the view. - */ - template - void storage(Type &elem) noexcept { - static_assert(stl::is_convertible_v &>, "Unexpected type"); - - if constexpr(Index < sizeof...(Get)) { - base_type::pool_at(Index, &elem); - } else { - base_type::filter_at(Index - sizeof...(Get), &elem); - } - } - - /** - * @brief Returns the elements assigned to the given entity. - * @param entt A valid identifier. - * @return The elements assigned to the given entity. - */ - [[nodiscard]] decltype(auto) operator[](const entity_type entt) const { - return get(entt); - } - - /** - * @brief Returns the elements assigned to the given entity. - * @tparam Type Type of the element to get. - * @tparam Other Other types of elements to get. - * @param entt A valid identifier. - * @return The elements assigned to the entity. - */ - template - [[nodiscard]] decltype(auto) get(const entity_type entt) const { - return get, index_of...>(entt); - } - - /** - * @brief Returns the elements assigned to the given entity. - * @tparam Index Indexes of the elements to get. - * @param entt A valid identifier. - * @return The elements assigned to the entity. - */ - template - [[nodiscard]] decltype(auto) get(const entity_type entt) const { - if constexpr(sizeof...(Index) == 0) { - return [this, entt](stl::index_sequence) { - return stl::tuple_cat(this->storage()->get_as_tuple(entt)...); - }(stl::index_sequence_for{}); - } else if constexpr(sizeof...(Index) == 1) { - return (storage()->get(entt), ...); - } else { - return stl::tuple_cat(storage()->get_as_tuple(entt)...); - } - } - - /** - * @brief Iterates entities and elements and applies the given function - * object to them. - * - * The signature of the function must be equivalent to one of the following - * (non-empty types only, constness as requested): - * - * @code{.cpp} - * void(const entity_type, Type &...); - * void(Type &...); - * @endcode - * - * @tparam Func Type of the function object to invoke. - * @param func A valid function object. - */ - template - void each(Func func) const { - [this, &func](stl::index_sequence seq) { - if(const auto *view = base_type::handle(); view != nullptr) { - ((view == base_type::pool_at(Index) ? each(stl::move(func), seq) : void()), ...); - } - }(stl::index_sequence_for{}); - } - - /** - * @brief Returns an iterable object to use to _visit_ a view. - * - * The iterable object returns a tuple that contains the current entity and - * a set of references to its non-empty elements. The _constness_ of the - * elements is as requested. - * - * @return An iterable object to use to _visit_ the view. - */ - [[nodiscard]] iterable each() const noexcept { - return iterable{base_type::begin(), base_type::end()}; - } - - /** - * @brief Combines a view and a storage in _more specific_ view. - * @tparam OGet Type of storage to combine the view with. - * @param other The storage for the type to combine the view with. - * @return A more specific view. - */ - template OGet> - [[nodiscard]] basic_view, exclude_t> operator|(OGet &other) const noexcept { - return *this | basic_view, exclude_t<>>{other}; - } - - /** - * @brief Combines two views in a _more specific_ one. - * @tparam OGet Element list of the view to combine with. - * @tparam OExclude Filter list of the view to combine with. - * @param other The view to combine with. - * @return A more specific view. - */ - template... OGet, stl::derived_from... OExclude> - [[nodiscard]] auto operator|(const basic_view, exclude_t> &other) const noexcept { - return internal::view_pack, exclude_t>>( - *this, other, stl::index_sequence_for{}, stl::index_sequence_for{}, stl::index_sequence_for{}, stl::index_sequence_for{}); - } -}; - -/** - * @brief Basic storage view implementation. - * @warning For internal use only, backward compatibility not guaranteed. - * @tparam Type Common type among all storage types. - * @tparam Policy Storage policy. - */ -template -class basic_storage_view { -protected: - /*! @cond ENTT_INTERNAL */ - basic_storage_view() noexcept = default; - - basic_storage_view(const Type *value) noexcept - : leading{value} { - ENTT_ASSERT(leading->policy() == Policy, "Unexpected storage policy"); - } - /*! @endcond */ - -public: - /*! @brief Common type among all storage types. */ - using common_type = Type; - /*! @brief Underlying entity identifier. */ - using entity_type = common_type::entity_type; - /*! @brief Unsigned integer type. */ - using size_type = stl::size_t; - /*! @brief Signed integer type. */ - using difference_type = stl::ptrdiff_t; - /*! @brief Random access iterator type. */ - using iterator = stl::conditional_t, typename common_type::iterator>; - /*! @brief Reverse iterator type. */ - using reverse_iterator = stl::conditional_t; - - /** - * @brief Returns the leading storage of a view, if any. - * @return The leading storage of the view. - */ - [[nodiscard]] const common_type *handle() const noexcept { - return leading; - } - - /** - * @brief Returns the number of entities that have the given element. - * @return Number of entities that have the given element. - */ - [[nodiscard]] size_type size() const noexcept - requires (Policy != deletion_policy::in_place) { - if constexpr(Policy == deletion_policy::swap_and_pop) { - return leading ? leading->size() : size_type{}; - } else { - static_assert(Policy == deletion_policy::swap_only, "Unexpected storage policy"); - return leading ? leading->free_list() : size_type{}; - } - } - - /** - * @brief Estimates the number of entities iterated by the view. - * @return Estimated number of entities iterated by the view. - */ - [[nodiscard]] size_type size_hint() const noexcept - requires (Policy == deletion_policy::in_place) { - return leading ? leading->size() : size_type{}; - } - - /** - * @brief Checks whether a view is empty. - * @return True if the view is empty, false otherwise. - */ - [[nodiscard]] bool empty() const noexcept - requires (Policy != deletion_policy::in_place) { - if constexpr(Policy == deletion_policy::swap_and_pop) { - return !leading || leading->empty(); - } else { - static_assert(Policy == deletion_policy::swap_only, "Unexpected storage policy"); - return !leading || (leading->free_list() == 0u); - } - } - - /** - * @brief Returns an iterator to the first entity of the view. - * - * If the view is empty, the returned iterator will be equal to `end()`. - * - * @return An iterator to the first entity of the view. - */ - [[nodiscard]] iterator begin() const noexcept { - if constexpr(Policy == deletion_policy::swap_and_pop) { - return leading ? leading->begin() : iterator{}; - } else if constexpr(Policy == deletion_policy::swap_only) { - return leading ? (leading->end() - static_cast(leading->free_list())) : iterator{}; - } else { - static_assert(Policy == deletion_policy::in_place, "Unexpected storage policy"); - return leading ? iterator{leading->begin(), {leading}, {}, 0u} : iterator{}; - } - } - - /** - * @brief Returns an iterator that is past the last entity of the view. - * @return An iterator to the entity following the last entity of the view. - */ - [[nodiscard]] iterator end() const noexcept { - if constexpr(Policy == deletion_policy::swap_and_pop || Policy == deletion_policy::swap_only) { - return leading ? leading->end() : iterator{}; - } else { - static_assert(Policy == deletion_policy::in_place, "Unexpected storage policy"); - return leading ? iterator{leading->end(), {leading}, {}, 0u} : iterator{}; - } - } - - /** - * @brief Returns an iterator to the first entity of the reversed view. - * - * If the view is empty, the returned iterator will be equal to `rend()`. - * - * @return An iterator to the first entity of the reversed view. - */ - [[nodiscard]] reverse_iterator rbegin() const noexcept - requires (Policy != deletion_policy::in_place) { - return leading ? leading->rbegin() : reverse_iterator{}; - } - - /** - * @brief Returns an iterator that is past the last entity of the reversed - * view. - * @return An iterator to the entity following the last entity of the - * reversed view. - */ - [[nodiscard]] reverse_iterator rend() const noexcept - requires (Policy != deletion_policy::in_place) { - if constexpr(Policy == deletion_policy::swap_and_pop) { - return leading ? leading->rend() : reverse_iterator{}; - } else { - static_assert(Policy == deletion_policy::swap_only, "Unexpected storage policy"); - return leading ? (leading->rbegin() + static_cast(leading->free_list())) : reverse_iterator{}; - } - } - - /** - * @brief Returns the first entity of the view, if any. - * @return The first entity of the view if one exists, the null entity - * otherwise. - */ - [[nodiscard]] entity_type front() const noexcept { - if constexpr(Policy == deletion_policy::swap_and_pop) { - return empty() ? null : *leading->begin(); - } else if constexpr(Policy == deletion_policy::swap_only) { - return empty() ? null : *(leading->end() - static_cast(leading->free_list())); - } else { - static_assert(Policy == deletion_policy::in_place, "Unexpected storage policy"); - const auto it = begin(); - return (it == end()) ? null : *it; - } - } - - /** - * @brief Returns the last entity of the view, if any. - * @return The last entity of the view if one exists, the null entity - * otherwise. - */ - [[nodiscard]] entity_type back() const noexcept { - if constexpr(Policy == deletion_policy::swap_and_pop || Policy == deletion_policy::swap_only) { - return empty() ? null : *leading->rbegin(); - } else { - static_assert(Policy == deletion_policy::in_place, "Unexpected storage policy"); - - if(leading) { - auto it = leading->rbegin(); - const auto last = leading->rend(); - for(; (it != last) && (*it == tombstone); ++it) {} - return it == last ? null : *it; - } - - return null; - } - } - - /** - * @brief Finds an entity. - * @param entt A valid identifier. - * @return An iterator to the given entity if it's found, past the end - * iterator otherwise. - */ - [[nodiscard]] iterator find(const entity_type entt) const noexcept { - if constexpr(Policy == deletion_policy::swap_and_pop) { - return leading ? leading->find(entt) : iterator{}; - } else if constexpr(Policy == deletion_policy::swap_only) { - const auto it = leading ? leading->find(entt) : iterator{}; - return leading && (static_cast(it.index()) < leading->free_list()) ? it : iterator{}; - } else { - return leading ? iterator{leading->find(entt), {leading}, {}, 0u} : iterator{}; - } - } - - /** - * @brief Checks if a view is fully initialized. - * @return True if the view is fully initialized, false otherwise. - */ - [[nodiscard]] explicit operator bool() const noexcept { - return (leading != nullptr); - } - - /** - * @brief Checks if a view contains an entity. - * @param entt A valid identifier. - * @return True if the view contains the given entity, false otherwise. - */ - [[nodiscard]] bool contains(const entity_type entt) const noexcept { - if constexpr(Policy == deletion_policy::swap_and_pop || Policy == deletion_policy::in_place) { - return leading && leading->contains(entt); - } else { - static_assert(Policy == deletion_policy::swap_only, "Unexpected storage policy"); - return leading && leading->contains(entt) && (leading->index(entt) < leading->free_list()); - } - } - -private: - const common_type *leading{}; -}; - -/** - * @brief Storage view specialization. - * - * This specialization offers a boost in terms of performance. It can access the - * underlying data structure directly and avoid superfluous checks. - * - * @sa basic_view - * - * @tparam Get Type of storage iterated by the view. - */ -template -class basic_view, exclude_t<>> - : public basic_storage_view { - using base_type = basic_storage_view; - - void storage_if(Get *value) noexcept { - if(value != nullptr) { - storage(*value); - } - } - -public: - /*! @brief Common type among all storage types. */ - using common_type = base_type::common_type; - /*! @brief Underlying entity identifier. */ - using entity_type = base_type::entity_type; - /*! @brief Unsigned integer type. */ - using size_type = base_type::size_type; - /*! @brief Signed integer type. */ - using difference_type = stl::ptrdiff_t; - /*! @brief Random access iterator type. */ - using iterator = base_type::iterator; - /*! @brief Reverse iterator type. */ - using reverse_iterator = base_type::reverse_iterator; - /*! @brief Iterable view type. */ - using iterable = stl::conditional_t>, decltype(stl::declval().each())>; - - /*! @brief Default constructor to use to create empty, invalid views. */ - basic_view() noexcept - : base_type{} {} - - /** - * @brief Constructs a view from a storage class. - * @param value The storage for the type to iterate. - */ - basic_view(Get &value) noexcept - : base_type{&value} { - } - - /** - * @brief Constructs a view from a storage class. - * @param value The storage for the type to iterate. - */ - basic_view(stl::tuple value, stl::tuple<> = {}) noexcept - : basic_view{stl::get<0>(value)} {} - - /** - * @brief Constructs a view from a convertible counterpart. - * @tparam Args Storage types managed by the other view. - * @param other A view to convert from. - */ - template - requires (!stl::same_as>) - basic_view(const basic_view &other) noexcept - : base_type{} { - storage_if(other.template storage()); - } - - /** - * @brief Returns the storage for a given element type, if any. - * @tparam Type Type of element of which to return the storage. - * @return The storage for the given element type. - */ - template - [[nodiscard]] auto *storage() const noexcept { - static_assert(stl::is_same_v, typename Get::element_type>, "Invalid element type"); - return storage<0>(); - } - - /** - * @brief Returns the storage for a given index, if any. - * @tparam Index Index of the storage to return. - * @return The storage for the given index. - */ - template - [[nodiscard]] auto *storage() const noexcept { - static_assert(Index == 0u, "Index out of bounds"); - return static_cast(const_cast *>(base_type::handle())); - } - - /** - * @brief Assigns a storage to a view. - * @param elem A storage to assign to the view. - */ - void storage(Get &elem) noexcept { - storage<0>(elem); - } - - /** - * @brief Assigns a storage to a view. - * @tparam Index Index of the storage to assign to the view. - * @param elem A storage to assign to the view. - */ - template - void storage(Get &elem) noexcept { - static_assert(Index == 0u, "Index out of bounds"); - *this = basic_view{elem}; - } - - /** - * @brief Returns a pointer to the underlying storage. - * @return A pointer to the underlying storage. - */ - [[nodiscard]] Get *operator->() const noexcept { - return storage(); - } - - /** - * @brief Returns the element assigned to the given entity. - * @param entt A valid identifier. - * @return The element assigned to the given entity. - */ - [[nodiscard]] decltype(auto) operator[](const entity_type entt) const { - return storage()->get(entt); - } - - /** - * @brief Returns the element assigned to the given entity. - * @tparam Elem Type of the element to get. - * @param entt A valid identifier. - * @return The element assigned to the entity. - */ - template - [[nodiscard]] decltype(auto) get(const entity_type entt) const { - static_assert(stl::is_same_v, typename Get::element_type>, "Invalid element type"); - return get<0>(entt); - } - - /** - * @brief Returns the element assigned to the given entity. - * @tparam Index Index of the element to get. - * @param entt A valid identifier. - * @return The element assigned to the entity. - */ - template - [[nodiscard]] decltype(auto) get(const entity_type entt) const { - if constexpr(sizeof...(Index) == 0) { - return storage()->get_as_tuple(entt); - } else { - return storage()->get(entt); - } - } - - /** - * @brief Iterates entities and elements and applies the given function - * object to them. - * - * The signature of the function must be equivalent to one of the following - * (non-empty types only, constness as requested): - * - * @code{.cpp} - * void(const entity_type, Type &); - * void(Type &); - * @endcode - * - * @tparam Func Type of the function object to invoke. - * @param func A valid function object. - */ - template - void each(Func func) const { - if constexpr(is_applicable_v{}, stl::declval().get({})))>) { - for(const auto pack: each()) { - stl::apply(func, pack); - } - } else if constexpr(Get::storage_policy == deletion_policy::swap_and_pop || Get::storage_policy == deletion_policy::swap_only) { - if constexpr(stl::is_void_v) { - for(size_type pos = base_type::size(); pos; --pos) { - func(); - } - } else { - if(const auto len = static_cast(base_type::size()); len != 0) { - for(auto last = storage()->end(), first = last - len; first != last; ++first) { - func(*first); - } - } - } - } else { - static_assert(Get::storage_policy == deletion_policy::in_place, "Unexpected storage policy"); - - for(const auto pack: each()) { - stl::apply([&func](const auto, auto &&...elem) { func(stl::forward(elem)...); }, pack); - } - } - } - - /** - * @brief Returns an iterable object to use to _visit_ a view. - * - * The iterable object returns a tuple that contains the current entity and - * a reference to its element if it's a non-empty one. The _constness_ of - * the element is as requested. - * - * @return An iterable object to use to _visit_ the view. - */ - [[nodiscard]] iterable each() const noexcept { - if constexpr(Get::storage_policy == deletion_policy::swap_and_pop || Get::storage_policy == deletion_policy::swap_only) { - return base_type::handle() ? storage()->each() : iterable{}; - } else { - static_assert(Get::storage_policy == deletion_policy::in_place, "Unexpected storage policy"); - return iterable{base_type::begin(), base_type::end()}; - } - } - - /** - * @brief Combines a view and a storage in _more specific_ view. - * @tparam OGet Type of storage to combine the view with. - * @param other The storage for the type to combine the view with. - * @return A more specific view. - */ - template OGet> - [[nodiscard]] basic_view, exclude_t<>> operator|(OGet &other) const noexcept { - return *this | basic_view, exclude_t<>>{other}; - } - - /** - * @brief Combines two views in a _more specific_ one. - * @tparam OGet Element list of the view to combine with. - * @tparam OExclude Filter list of the view to combine with. - * @param other The view to combine with. - * @return A more specific view. - */ - template... OGet, stl::derived_from... OExclude> - [[nodiscard]] auto operator|(const basic_view, exclude_t> &other) const noexcept { - return internal::view_pack, exclude_t>>( - *this, other, stl::index_sequence_for{}, stl::index_sequence_for<>{}, stl::index_sequence_for{}, stl::index_sequence_for{}); - } -}; - -/** - * @brief Deduction guide. - * @tparam Type Type of storage classes used to create the view. - * @param storage The storage for the types to iterate. - */ -template -basic_view(Type &...storage) -> basic_view, exclude_t<>>; - -/** - * @brief Deduction guide. - * @tparam Get Types of elements iterated by the view. - * @tparam Exclude Types of elements used to filter the view. - */ -template -basic_view(stl::tuple, stl::tuple = {}) -> basic_view, exclude_t>; - -} // namespace entt - -#endif diff --git a/include/entt/entt.hpp b/include/entt/entt.hpp deleted file mode 100644 index 09bd14f..0000000 --- a/include/entt/entt.hpp +++ /dev/null @@ -1,93 +0,0 @@ -/*! @brief `EnTT` default namespace. */ -namespace entt {} - -/*! @brief Custom `EnTT` namespace for the standard template library. */ -namespace entt::stl {} - -// IWYU pragma: begin_exports -#include "config/config.h" -#include "config/macro.h" -#include "config/version.h" -#include "container/dense_map.hpp" -#include "container/dense_set.hpp" -#include "container/table.hpp" -#include "core/algorithm.hpp" -#include "core/any.hpp" -#include "core/bit.hpp" -#include "core/compressed_pair.hpp" -#include "core/concepts.hpp" -#include "core/enum.hpp" -#include "core/family.hpp" -#include "core/hashed_string.hpp" -#include "core/ident.hpp" -#include "core/iterator.hpp" -#include "core/memory.hpp" -#include "core/monostate.hpp" -#include "core/ranges.hpp" -#include "core/tuple.hpp" -#include "core/type_info.hpp" -#include "core/type_traits.hpp" -#include "core/utility.hpp" -#include "entity/component.hpp" -#include "entity/entity.hpp" -#include "entity/group.hpp" -#include "entity/handle.hpp" -#include "entity/helper.hpp" -#include "entity/mixin.hpp" -#include "entity/organizer.hpp" -#include "entity/ranges.hpp" -#include "entity/registry.hpp" -#include "entity/runtime_view.hpp" -#include "entity/snapshot.hpp" -#include "entity/sparse_set.hpp" -#include "entity/storage.hpp" -#include "entity/view.hpp" -#include "graph/adjacency_matrix.hpp" -#include "graph/dot.hpp" -#include "graph/flow.hpp" -#include "locator/locator.hpp" -#include "meta/adl_pointer.hpp" -#include "meta/container.hpp" -#include "meta/context.hpp" -#include "meta/factory.hpp" -#include "meta/meta.hpp" -#include "meta/node.hpp" -#include "meta/pointer.hpp" -#include "meta/policy.hpp" -#include "meta/range.hpp" -#include "meta/resolve.hpp" -#include "meta/template.hpp" -#include "meta/type_traits.hpp" -#include "meta/utility.hpp" -#include "poly/poly.hpp" -#include "process/process.hpp" -#include "process/scheduler.hpp" -#include "resource/cache.hpp" -#include "resource/loader.hpp" -#include "resource/resource.hpp" -#include "signal/delegate.hpp" -#include "signal/dispatcher.hpp" -#include "signal/emitter.hpp" -#include "signal/sigh.hpp" -#include "stl/algorithm.hpp" -#include "stl/array.hpp" -#include "stl/atomic.hpp" -#include "stl/bit.hpp" -#include "stl/cmath.hpp" -#include "stl/concepts.hpp" -#include "stl/cstddef.hpp" -#include "stl/cstdint.hpp" -#include "stl/functional.hpp" -#include "stl/ios.hpp" -#include "stl/iterator.hpp" -#include "stl/limits.hpp" -#include "stl/memory.hpp" -#include "stl/ostream.hpp" -#include "stl/sstream.hpp" -#include "stl/string.hpp" -#include "stl/string_view.hpp" -#include "stl/tuple.hpp" -#include "stl/type_traits.hpp" -#include "stl/utility.hpp" -#include "stl/vector.hpp" -// IWYU pragma: end_exports diff --git a/include/entt/fwd.hpp b/include/entt/fwd.hpp deleted file mode 100644 index 4b6e60c..0000000 --- a/include/entt/fwd.hpp +++ /dev/null @@ -1,11 +0,0 @@ -// IWYU pragma: begin_exports -#include "container/fwd.hpp" -#include "core/fwd.hpp" -#include "entity/fwd.hpp" -#include "graph/fwd.hpp" -#include "meta/fwd.hpp" -#include "poly/fwd.hpp" -#include "process/fwd.hpp" -#include "resource/fwd.hpp" -#include "signal/fwd.hpp" -// IWYU pragma: end_exports diff --git a/include/entt/graph/adjacency_matrix.hpp b/include/entt/graph/adjacency_matrix.hpp deleted file mode 100644 index ba83561..0000000 --- a/include/entt/graph/adjacency_matrix.hpp +++ /dev/null @@ -1,332 +0,0 @@ -#ifndef ENTT_GRAPH_ADJACENCY_MATRIX_HPP -#define ENTT_GRAPH_ADJACENCY_MATRIX_HPP - -#include "../config/config.h" -#include "../core/iterator.hpp" -#include "../stl/concepts.hpp" -#include "../stl/cstddef.hpp" -#include "../stl/iterator.hpp" -#include "../stl/memory.hpp" -#include "../stl/type_traits.hpp" -#include "../stl/utility.hpp" -#include "../stl/vector.hpp" -#include "fwd.hpp" - -namespace entt { - -/*! @cond ENTT_INTERNAL */ -namespace internal { - -template -class edge_iterator { - using size_type = stl::size_t; - - void find_next() noexcept { - for(; pos != last && !it[static_cast(pos)]; pos += offset) {} - } - -public: - using value_type = stl::pair; - using pointer = input_iterator_pointer; - using reference = value_type; - using difference_type = stl::ptrdiff_t; - using iterator_category = stl::input_iterator_tag; - using iterator_concept = stl::forward_iterator_tag; - - constexpr edge_iterator() noexcept = default; - - // NOLINTNEXTLINE(bugprone-easily-swappable-parameters) - constexpr edge_iterator(It base, const size_type vertices, const size_type from, const size_type to, const size_type step) noexcept - : it{stl::move(base)}, - vert{vertices}, - pos{from}, - last{to}, - offset{step} { - find_next(); - } - - constexpr edge_iterator &operator++() noexcept { - pos += offset; - find_next(); - return *this; - } - - constexpr edge_iterator operator++(int) noexcept { - const edge_iterator orig = *this; - return ++(*this), orig; - } - - [[nodiscard]] constexpr reference operator*() const noexcept { - return *operator->(); - } - - [[nodiscard]] constexpr pointer operator->() const noexcept { - return stl::make_pair(pos / vert, pos % vert); - } - - [[nodiscard]] constexpr bool operator==(const edge_iterator &other) const noexcept { - return pos == other.pos; - } - -private: - It it{}; - size_type vert{}; - size_type pos{}; - size_type last{}; - size_type offset{}; -}; - -} // namespace internal -/*! @endcond */ - -/** - * @brief Basic implementation of a directed adjacency matrix. - * @tparam Category Either a directed or undirected category tag. - * @tparam Allocator Type of allocator used to manage memory and elements. - */ -template Category, typename Allocator> -class adjacency_matrix { - using alloc_traits = stl::allocator_traits; - static_assert(stl::is_same_v, "Invalid value type"); - using container_type = stl::vector>; - -public: - /*! @brief Allocator type. */ - using allocator_type = Allocator; - /*! @brief Unsigned integer type. */ - using size_type = stl::size_t; - /*! @brief Vertex type. */ - using vertex_type = size_type; - /*! @brief Edge type. */ - using edge_type = stl::pair; - /*! @brief Vertex iterator type. */ - using vertex_iterator = iota_iterator; - /*! @brief Edge iterator type. */ - using edge_iterator = internal::edge_iterator; - /*! @brief Out-edge iterator type. */ - using out_edge_iterator = edge_iterator; - /*! @brief In-edge iterator type. */ - using in_edge_iterator = edge_iterator; - /*! @brief Graph category tag. */ - using graph_category = Category; - - /*! @brief Default constructor. */ - adjacency_matrix() noexcept(noexcept(allocator_type{})) - : adjacency_matrix{0u} { - } - - /** - * @brief Constructs an empty container with a given allocator. - * @param allocator The allocator to use. - */ - explicit adjacency_matrix(const allocator_type &allocator) noexcept - : adjacency_matrix{0u, allocator} {} - - /** - * @brief Constructs an empty container with a given allocator and user - * supplied number of vertices. - * @param vertices Number of vertices. - * @param allocator The allocator to use. - */ - adjacency_matrix(const size_type vertices, const allocator_type &allocator = allocator_type{}) - : matrix{vertices * vertices, allocator}, - vert{vertices} {} - - /*! @brief Default copy constructor. */ - adjacency_matrix(const adjacency_matrix &) = default; - - /** - * @brief Allocator-extended copy constructor. - * @param other The instance to copy from. - * @param allocator The allocator to use. - */ - adjacency_matrix(const adjacency_matrix &other, const allocator_type &allocator) - : matrix{other.matrix, allocator}, - vert{other.vert} {} - - /*! @brief Default move constructor. */ - adjacency_matrix(adjacency_matrix &&) noexcept = default; - - /** - * @brief Allocator-extended move constructor. - * @param other The instance to move from. - * @param allocator The allocator to use. - */ - adjacency_matrix(adjacency_matrix &&other, const allocator_type &allocator) - : matrix{stl::move(other.matrix), allocator}, - vert{other.vert} {} - - /*! @brief Default destructor. */ - ~adjacency_matrix() = default; - - /** - * @brief Default copy assignment operator. - * @return This container. - */ - adjacency_matrix &operator=(const adjacency_matrix &) = default; - - /** - * @brief Default move assignment operator. - * @return This container. - */ - adjacency_matrix &operator=(adjacency_matrix &&) noexcept = default; - - /** - * @brief Exchanges the contents with those of a given adjacency matrix. - * @param other Adjacency matrix to exchange the content with. - */ - void swap(adjacency_matrix &other) noexcept { - using stl::swap; - swap(matrix, other.matrix); - swap(vert, other.vert); - } - - /** - * @brief Returns the associated allocator. - * @return The associated allocator. - */ - [[nodiscard]] constexpr allocator_type get_allocator() const noexcept { - return matrix.get_allocator(); - } - - /*! @brief Clears the adjacency matrix. */ - void clear() noexcept { - matrix.clear(); - vert = {}; - } - - /** - * @brief Returns true if an adjacency matrix is empty, false otherwise. - * - * @warning - * Potentially expensive, try to avoid it on hot paths. - * - * @return True if the adjacency matrix is empty, false otherwise. - */ - [[nodiscard]] bool empty() const noexcept { - const auto iterable = edges(); - return (iterable.begin() == iterable.end()); - } - - /** - * @brief Returns the number of vertices. - * @return The number of vertices. - */ - [[nodiscard]] size_type size() const noexcept { - return vert; - } - - /** - * @brief Returns an iterable object to visit all vertices of a matrix. - * @return An iterable object to visit all vertices of a matrix. - */ - [[nodiscard]] iterable_adaptor vertices() const noexcept { - return {0u, vert}; - } - - /** - * @brief Returns an iterable object to visit all edges of a matrix. - * @return An iterable object to visit all edges of a matrix. - */ - [[nodiscard]] iterable_adaptor edges() const noexcept { - const auto it = matrix.cbegin(); - const auto sz = matrix.size(); - return {{it, vert, 0u, sz, 1u}, {it, vert, sz, sz, 1u}}; - } - - /** - * @brief Returns an iterable object to visit all out-edges of a vertex. - * @param vertex The vertex of which to return all out-edges. - * @return An iterable object to visit all out-edges of a vertex. - */ - [[nodiscard]] iterable_adaptor out_edges(const vertex_type vertex) const noexcept { - const auto it = matrix.cbegin(); - const auto from = vertex * vert; - const auto to = from + vert; - return {{it, vert, from, to, 1u}, {it, vert, to, to, 1u}}; - } - - /** - * @brief Returns an iterable object to visit all in-edges of a vertex. - * @param vertex The vertex of which to return all in-edges. - * @return An iterable object to visit all in-edges of a vertex. - */ - [[nodiscard]] iterable_adaptor in_edges(const vertex_type vertex) const noexcept { - const auto it = matrix.cbegin(); - const auto from = vertex; - const auto to = vert * vert + from; - return {{it, vert, from, to, vert}, {it, vert, to, to, vert}}; - } - - /** - * @brief Resizes an adjacency matrix. - * @param vertices The new number of vertices. - */ - void resize(const size_type vertices) { - adjacency_matrix other{vertices, get_allocator()}; - - for(auto [lhs, rhs]: edges()) { - other.insert(lhs, rhs); - } - - other.swap(*this); - } - - /** - * @brief Inserts an edge into the adjacency matrix, if it does not exist. - * @param lhs The left hand vertex of the edge. - * @param rhs The right hand vertex of the edge. - * @return A pair consisting of an iterator to the inserted element (or to - * the element that prevented the insertion) and a bool denoting whether the - * insertion took place. - */ - stl::pair insert(const vertex_type lhs, const vertex_type rhs) { - const auto pos = lhs * vert + rhs; - - if constexpr(stl::is_same_v) { - const auto rev = rhs * vert + lhs; - ENTT_ASSERT(matrix[pos] == matrix[rev], "Something went really wrong"); - matrix[rev] = 1u; - } - - const auto inserted = !stl::exchange(matrix[pos], 1u); - return {edge_iterator{matrix.cbegin(), vert, pos, matrix.size(), 1u}, inserted}; - } - - /** - * @brief Removes the edge associated with a pair of given vertices. - * @param lhs The left hand vertex of the edge. - * @param rhs The right hand vertex of the edge. - * @return Number of elements removed (either 0 or 1). - */ - size_type erase(const vertex_type lhs, const vertex_type rhs) { - const auto pos = lhs * vert + rhs; - - if constexpr(stl::is_same_v) { - const auto rev = rhs * vert + lhs; - ENTT_ASSERT(matrix[pos] == matrix[rev], "Something went really wrong"); - matrix[rev] = 0u; - } - - return stl::exchange(matrix[pos], 0u); - } - - /** - * @brief Checks if an adjacency matrix contains a given edge. - * @param lhs The left hand vertex of the edge. - * @param rhs The right hand vertex of the edge. - * @return True if there is such an edge, false otherwise. - */ - [[nodiscard]] bool contains(const vertex_type lhs, const vertex_type rhs) const { - const auto pos = lhs * vert + rhs; - return pos < matrix.size() && matrix[pos]; - } - -private: - container_type matrix; - size_type vert; -}; - -} // namespace entt - -#endif diff --git a/include/entt/graph/dot.hpp b/include/entt/graph/dot.hpp deleted file mode 100644 index e8d237a..0000000 --- a/include/entt/graph/dot.hpp +++ /dev/null @@ -1,56 +0,0 @@ -#ifndef ENTT_GRAPH_DOT_HPP -#define ENTT_GRAPH_DOT_HPP - -#include "../stl/concepts.hpp" -#include "../stl/ostream.hpp" -#include "fwd.hpp" - -namespace entt { - -/** - * @brief Outputs a graph in dot format. - * @tparam Graph Graph type, valid as long as it exposes edges and vertices. - * @param out A standard output stream. - * @param graph The graph to output. - * @param writer Vertex decorator object. - */ -template -requires stl::derived_from -void dot(stl::ostream &out, const Graph &graph, stl::invocable auto writer) { - if constexpr(stl::same_as) { - out << "graph{"; - } else { - out << "digraph{"; - } - - for(auto &&vertex: graph.vertices()) { - out << vertex << "["; - writer(out, vertex); - out << "];"; - } - - for(auto [lhs, rhs]: graph.edges()) { - if constexpr(stl::same_as) { - out << lhs << "--" << rhs << ";"; - } else { - out << lhs << "->" << rhs << ";"; - } - } - - out << "}"; -} - -/** - * @brief Outputs a graph in dot format. - * @tparam Graph Graph type, valid as long as it exposes edges and vertices. - * @param out A standard output stream. - * @param graph The graph to output. - */ -template -void dot(stl::ostream &out, const Graph &graph) { - return dot(out, graph, [](auto &&...) {}); -} - -} // namespace entt - -#endif diff --git a/include/entt/graph/flow.hpp b/include/entt/graph/flow.hpp deleted file mode 100644 index df4372f..0000000 --- a/include/entt/graph/flow.hpp +++ /dev/null @@ -1,345 +0,0 @@ -#ifndef ENTT_GRAPH_FLOW_HPP -#define ENTT_GRAPH_FLOW_HPP - -#include "../config/config.h" -#include "../container/dense_map.hpp" -#include "../container/dense_set.hpp" -#include "../core/compressed_pair.hpp" -#include "../core/fwd.hpp" -#include "../core/iterator.hpp" -#include "../stl/algorithm.hpp" -#include "../stl/concepts.hpp" -#include "../stl/cstddef.hpp" -#include "../stl/functional.hpp" -#include "../stl/iterator.hpp" -#include "../stl/memory.hpp" -#include "../stl/type_traits.hpp" -#include "../stl/utility.hpp" -#include "../stl/vector.hpp" -#include "adjacency_matrix.hpp" -#include "fwd.hpp" - -namespace entt { - -/** - * @brief Utility class for creating task graphs. - * @tparam Allocator Type of allocator used to manage memory and elements. - */ -template -class basic_flow { - using alloc_traits = stl::allocator_traits; - static_assert(stl::is_same_v, "Invalid value type"); - using task_container_type = dense_set, typename alloc_traits::template rebind_alloc>; - using ro_rw_container_type = stl::vector, typename alloc_traits::template rebind_alloc>>; - using deps_container_type = dense_map, typename alloc_traits::template rebind_alloc>>; - using adjacency_matrix_type = adjacency_matrix>; - - void emplace(const id_type res, const bool is_rw) { - ENTT_ASSERT(index.first() < vertices.size(), "Invalid node"); - - if(!deps.contains(res) && sync_on != vertices.size()) { - deps[res].emplace_back(sync_on, true); - } - - deps[res].emplace_back(index.first(), is_rw); - } - - void setup_graph(adjacency_matrix_type &matrix) const { - for(const auto &elem: deps) { - const auto last = elem.second.cend(); - auto it = elem.second.cbegin(); - - while(it != last) { - if(it->second) { - // rw item - if(auto curr = it++; it != last) { - if(it->second) { - matrix.insert(curr->first, it->first); - } else if(const auto next = stl::find_if(it, last, [](const auto &value) { return value.second; }); next != last) { - for(; it != next; ++it) { - matrix.insert(curr->first, it->first); - matrix.insert(it->first, next->first); - } - } else { - for(; it != next; ++it) { - matrix.insert(curr->first, it->first); - } - } - } - } else { - // ro item (first iteration only) - if(const auto next = stl::find_if(it, last, [](const auto &value) { return value.second; }); next != last) { - for(; it != next; ++it) { - matrix.insert(it->first, next->first); - } - } else { - it = last; - } - } - } - } - } - - void transitive_closure(adjacency_matrix_type &matrix) const { - const auto length = matrix.size(); - - for(stl::size_t vk{}; vk < length; ++vk) { - for(stl::size_t vi{}; vi < length; ++vi) { - for(stl::size_t vj{}; vj < length; ++vj) { - if(matrix.contains(vi, vk) && matrix.contains(vk, vj)) { - matrix.insert(vi, vj); - } - } - } - } - } - - void transitive_reduction(adjacency_matrix_type &matrix) const { - const auto length = matrix.size(); - - for(stl::size_t vert{}; vert < length; ++vert) { - matrix.erase(vert, vert); - } - - for(stl::size_t vj{}; vj < length; ++vj) { - for(stl::size_t vi{}; vi < length; ++vi) { - if(matrix.contains(vi, vj)) { - for(stl::size_t vk{}; vk < length; ++vk) { - if(matrix.contains(vj, vk)) { - matrix.erase(vi, vk); - } - } - } - } - } - } - -public: - /*! @brief Allocator type. */ - using allocator_type = Allocator; - /*! @brief Unsigned integer type. */ - using size_type = stl::size_t; - /*! @brief Iterable task list. */ - using iterable = iterable_adaptor; - /*! @brief Adjacency matrix type. */ - using graph_type = adjacency_matrix_type; - - /*! @brief Default constructor. */ - basic_flow() - : basic_flow{allocator_type{}} {} - - /** - * @brief Constructs a flow builder with a given allocator. - * @param allocator The allocator to use. - */ - explicit basic_flow(const allocator_type &allocator) - : index{0u, allocator}, - vertices{allocator}, - deps{allocator} {} - - /*! @brief Default copy constructor. */ - basic_flow(const basic_flow &) = default; - - /** - * @brief Allocator-extended copy constructor. - * @param other The instance to copy from. - * @param allocator The allocator to use. - */ - basic_flow(const basic_flow &other, const allocator_type &allocator) - : index{other.index.first(), allocator}, - vertices{other.vertices, allocator}, - deps{other.deps, allocator}, - sync_on{other.sync_on} {} - - /*! @brief Default move constructor. */ - basic_flow(basic_flow &&) noexcept = default; - - /** - * @brief Allocator-extended move constructor. - * @param other The instance to move from. - * @param allocator The allocator to use. - */ - basic_flow(basic_flow &&other, const allocator_type &allocator) - : index{other.index.first(), allocator}, - vertices{stl::move(other.vertices), allocator}, - deps{stl::move(other.deps), allocator}, - sync_on{other.sync_on} {} - - /*! @brief Default destructor. */ - ~basic_flow() = default; - - /** - * @brief Default copy assignment operator. - * @return This flow builder. - */ - basic_flow &operator=(const basic_flow &) = default; - - /** - * @brief Default move assignment operator. - * @return This flow builder. - */ - basic_flow &operator=(basic_flow &&) noexcept = default; - - /** - * @brief Exchanges the contents with those of a given flow builder. - * @param other Flow builder to exchange the content with. - */ - void swap(basic_flow &other) noexcept { - using stl::swap; - swap(index, other.index); - swap(vertices, other.vertices); - swap(deps, other.deps); - swap(sync_on, other.sync_on); - } - - /** - * @brief Returns the associated allocator. - * @return The associated allocator. - */ - [[nodiscard]] constexpr allocator_type get_allocator() const noexcept { - return allocator_type{index.second()}; - } - - /** - * @brief Returns the identifier at specified location. - * @param pos Position of the identifier to return. - * @return The requested identifier. - */ - [[nodiscard]] id_type operator[](const size_type pos) const { - return vertices.cbegin()[static_cast(pos)]; - } - - /*! @brief Clears the flow builder. */ - void clear() noexcept { - index.first() = {}; - vertices.clear(); - deps.clear(); - sync_on = {}; - } - - /** - * @brief Returns true if a flow builder contains no tasks, false otherwise. - * @return True if the flow builder contains no tasks, false otherwise. - */ - [[nodiscard]] bool empty() const noexcept { - return vertices.empty(); - } - - /** - * @brief Returns the number of tasks. - * @return The number of tasks. - */ - [[nodiscard]] size_type size() const noexcept { - return vertices.size(); - } - - /** - * @brief Binds a task to a flow builder. - * @param value Task identifier. - * @return This flow builder. - */ - basic_flow &bind(const id_type value) { - sync_on += (sync_on == vertices.size()); - const auto it = vertices.emplace(value).first; - index.first() = size_type(it - vertices.begin()); - return *this; - } - - /** - * @brief Turns the current task into a sync point. - * @return This flow builder. - */ - basic_flow &sync() { - ENTT_ASSERT(index.first() < vertices.size(), "Invalid node"); - sync_on = index.first(); - - for(const auto &elem: deps) { - elem.second.emplace_back(sync_on, true); - } - - return *this; - } - - /** - * @brief Assigns a resource to the current task with a given access mode. - * @param res Resource identifier. - * @param is_rw Access mode. - * @return This flow builder. - */ - basic_flow &set(const id_type res, bool is_rw = false) { - emplace(res, is_rw); - return *this; - } - - /** - * @brief Assigns a read-only resource to the current task. - * @param res Resource identifier. - * @return This flow builder. - */ - basic_flow &ro(const id_type res) { - emplace(res, false); - return *this; - } - - /** - * @brief Assigns a range of read-only resources to the current task. - * @param first An iterator to the first element of the range of elements. - * @param last An iterator past the last element of the range of elements. - * @return This flow builder. - */ - basic_flow &ro(stl::input_iterator auto first, stl::input_iterator auto last) { - for(; first != last; ++first) { - emplace(*first, false); - } - - return *this; - } - - /** - * @brief Assigns a writable resource to the current task. - * @param res Resource identifier. - * @return This flow builder. - */ - basic_flow &rw(const id_type res) { - emplace(res, true); - return *this; - } - - /** - * @brief Assigns a range of writable resources to the current task. - * @param first An iterator to the first element of the range of elements. - * @param last An iterator past the last element of the range of elements. - * @return This flow builder. - */ - basic_flow &rw(stl::input_iterator auto first, stl::input_iterator auto last) { - for(; first != last; ++first) { - emplace(*first, true); - } - - return *this; - } - - /** - * @brief Generates a task graph for the current content. - * @return The adjacency matrix of the task graph. - */ - [[nodiscard]] graph_type graph() const { - graph_type matrix{vertices.size(), get_allocator()}; - - setup_graph(matrix); - transitive_closure(matrix); - transitive_reduction(matrix); - - return matrix; - } - -private: - compressed_pair index; - task_container_type vertices; - deps_container_type deps; - size_type sync_on{}; -}; - -} // namespace entt - -#endif diff --git a/include/entt/graph/fwd.hpp b/include/entt/graph/fwd.hpp deleted file mode 100644 index c1fd58e..0000000 --- a/include/entt/graph/fwd.hpp +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef ENTT_GRAPH_FWD_HPP -#define ENTT_GRAPH_FWD_HPP - -#include "../core/fwd.hpp" -#include "../stl/concepts.hpp" -#include "../stl/cstddef.hpp" -#include "../stl/memory.hpp" - -namespace entt { - -/*! @brief Undirected graph category tag. */ -struct directed_tag {}; - -/*! @brief Directed graph category tag. */ -struct undirected_tag: directed_tag {}; - -template, typename = stl::allocator> -class adjacency_matrix; - -template> -class basic_flow; - -/*! @brief Alias declaration for the most common use case. */ -using flow = basic_flow<>; - -} // namespace entt - -#endif diff --git a/include/entt/locator/locator.hpp b/include/entt/locator/locator.hpp deleted file mode 100644 index 0d6fecf..0000000 --- a/include/entt/locator/locator.hpp +++ /dev/null @@ -1,161 +0,0 @@ -#ifndef ENTT_LOCATOR_LOCATOR_HPP -#define ENTT_LOCATOR_LOCATOR_HPP - -#include "../config/config.h" -#include "../stl/concepts.hpp" -#include "../stl/memory.hpp" -#include "../stl/utility.hpp" - -namespace entt { - -/** - * @brief Service locator, nothing more. - * - * A service locator is 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 tiny class - * tries to fill the gap and to get rid of the burden of defining a different - * specific locator for each application. - * - * @note - * Users shouldn't retain references to a service. The recommended way is to - * retrieve the service implementation currently set each and every time the - * need for it arises. The risk is to incur in unexpected behaviors otherwise. - * - * @tparam Service Service type. - */ -template -class locator final { - class service_handle { - friend class locator; - stl::shared_ptr value{}; - }; - -public: - /*! @brief Service type. */ - using type = Service; - /*! @brief Service node type. */ - using node_type = service_handle; - - /*! @brief Default constructor, deleted on purpose. */ - locator() = delete; - - /*! @brief Default copy constructor, deleted on purpose. */ - locator(const locator &) = delete; - - /*! @brief Default destructor, deleted on purpose. */ - ~locator() = delete; - - /** - * @brief Default copy assignment operator, deleted on purpose. - * @return This locator. - */ - locator &operator=(const locator &) = delete; - - /** - * @brief Checks whether a service locator contains a value. - * @return True if the service locator contains a value, false otherwise. - */ - [[nodiscard]] static bool has_value() noexcept { - return (service != nullptr); - } - - /** - * @brief Returns a reference to a valid service, if any. - * - * @warning - * Invoking this function can result in undefined behavior if the service - * hasn't been set yet. - * - * @return A reference to the service currently set, if any. - */ - [[nodiscard]] static Service &value() noexcept { - ENTT_ASSERT(has_value(), "Service not available"); - return *service; - } - - /** - * @brief Returns a service if available or sets it from a fallback type. - * - * Arguments are used only if a service doesn't already exist. In all other - * cases, they are discarded. - * - * @tparam Args Types of arguments to use to construct the fallback service. - * @tparam Type Fallback service type. - * @param args Parameters to use to construct the fallback service. - * @return A reference to a valid service. - */ - template Type = Service, typename... Args> - requires stl::constructible_from - [[nodiscard]] static Service &value_or(Args &&...args) { - return service ? *service : emplace(stl::forward(args)...); - } - - /** - * @brief Sets or replaces a service. - * @tparam Type Service type. - * @tparam Args Types of arguments to use to construct the service. - * @param args Parameters to use to construct the service. - * @return A reference to a valid service. - */ - template Type = Service, typename... Args> - requires stl::constructible_from - static Service &emplace(Args &&...args) { - service = stl::make_shared(stl::forward(args)...); - return *service; - } - - /** - * @brief Sets or replaces a service using a given allocator. - * @tparam Type Service type. - * @tparam Args Types of arguments to use to construct the service. - * @param alloc The allocator to use. - * @param args Parameters to use to construct the service. - * @return A reference to a valid service. - */ - template Type = Service, typename... Args> - requires stl::constructible_from - static Service &emplace(stl::allocator_arg_t, auto alloc, Args &&...args) { - service = stl::allocate_shared(alloc, stl::forward(args)...); - return *service; - } - - /** - * @brief Returns a handle to the underlying service. - * @return A handle to the underlying service. - */ - static node_type handle() noexcept { - node_type node{}; - node.value = service; - return node; - } - - /** - * @brief Resets or replaces a service. - * @param other Optional handle with which to replace the service. - */ - static void reset(const node_type &other = {}) noexcept { - service = other.value; - } - - /** - * @brief Resets or replaces a service. - * @tparam Type Service type. - * @tparam Deleter Deleter type. - * @param elem A pointer to a service to manage. - * @param deleter A deleter to use to destroy the service. - */ - template Type, typename Deleter = stl::default_delete> - static void reset(Type *elem, Deleter deleter = {}) { - service = stl::shared_ptr{elem, stl::move(deleter)}; - } - -private: - // stl::shared_ptr because of its type erased allocator which is useful here - // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) - inline static stl::shared_ptr service{}; -}; - -} // namespace entt - -#endif diff --git a/include/entt/meta/adl_pointer.hpp b/include/entt/meta/adl_pointer.hpp deleted file mode 100644 index 5bb768a..0000000 --- a/include/entt/meta/adl_pointer.hpp +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef ENTT_META_ADL_POINTER_HPP -#define ENTT_META_ADL_POINTER_HPP - -namespace entt { - -/** - * @brief ADL based lookup function for dereferencing meta pointer-like types. - * @tparam Type Element type. - * @param value A pointer-like object. - * @return The value returned from the dereferenced pointer. - */ -template -decltype(auto) dereference_meta_pointer_like(const Type &value) { - return *value; -} - -/** - * @brief Fake ADL based lookup function for meta pointer-like types. - * @tparam Type Element type. - */ -template -struct adl_meta_pointer_like { - /** - * @brief Uses the default ADL based lookup method to resolve the call. - * @param value A pointer-like object. - * @return The value returned from the dereferenced pointer. - */ - static decltype(auto) dereference(const Type &value) { - return dereference_meta_pointer_like(value); - } -}; - -} // namespace entt - -#endif diff --git a/include/entt/meta/container.hpp b/include/entt/meta/container.hpp deleted file mode 100644 index 9c131be..0000000 --- a/include/entt/meta/container.hpp +++ /dev/null @@ -1,298 +0,0 @@ -// IWYU pragma: always_keep - -#ifndef ENTT_META_CONTAINER_HPP -#define ENTT_META_CONTAINER_HPP - -#include "../core/concepts.hpp" -#include "../core/type_traits.hpp" -#include "../stl/concepts.hpp" -#include "../stl/cstddef.hpp" -#include "../stl/iterator.hpp" -#include "../stl/type_traits.hpp" -#include "../stl/utility.hpp" -#include "context.hpp" -#include "fwd.hpp" -#include "meta.hpp" -#include "type_traits.hpp" - -namespace entt { - -/*! @cond ENTT_INTERNAL */ -namespace internal { - -template -struct sequence_container_extent: integral_constant {}; - -template -requires is_complete_v> -struct sequence_container_extent: integral_constant> {}; - -template -inline constexpr stl::size_t sequence_container_extent_v = sequence_container_extent::value; - -template -concept meta_sequence_container_like = requires(Type elem) { - typename Type::value_type; - typename Type::iterator; - requires entt::stl::forward_iterator; - { elem.begin() } -> stl::same_as; - { elem.end() } -> stl::same_as; - requires !requires { typename Type::key_type; }; - requires !requires { elem.substr(); }; -}; - -template -concept meta_associative_container_like = requires(Type value) { - typename Type::key_type; - typename Type::value_type; - typename Type::iterator; - requires entt::stl::forward_iterator; - { value.begin() } -> stl::same_as; - { value.end() } -> stl::same_as; - value.find(stl::declval()); -}; - -} // namespace internal -/*! @endcond */ - -/** - * @brief General purpose implementation of meta sequence container traits. - * @tparam Type Type of underlying sequence container. - */ -template -struct basic_meta_sequence_container_traits { - /*! @brief Unsigned integer type. */ - using size_type = meta_sequence_container::size_type; - /*! @brief Meta iterator type. */ - using iterator = meta_sequence_container::iterator; - - /*! @brief Number of elements, or `meta_dynamic_extent` if dynamic. */ - static constexpr stl::size_t extent = internal::sequence_container_extent_v; - - /** - * @brief Returns the number of elements in a container. - * @param container Opaque pointer to a container of the given type. - * @return Number of elements. - */ - [[nodiscard]] static size_type size(const void *container) { - return static_cast(container)->size(); - } - - /** - * @brief Clears a container. - * @param container Opaque pointer to a container of the given type. - * @return True in case of success, false otherwise. - */ - [[nodiscard]] static bool clear([[maybe_unused]] void *container) { - if constexpr(requires(Type elem) { elem.clear(); }) { - static_cast(container)->clear(); - return true; - } else { - return false; - } - } - - /** - * @brief Increases the capacity of a container. - * @param container Opaque pointer to a container of the given type. - * @param sz Desired capacity. - * @return True in case of success, false otherwise. - */ - [[nodiscard]] static bool reserve([[maybe_unused]] void *container, [[maybe_unused]] const size_type sz) { - if constexpr(requires(Type elem) { elem.reserve(sz); }) { - static_cast(container)->reserve(sz); - return true; - } else { - return false; - } - } - - /** - * @brief Resizes a container. - * @param container Opaque pointer to a container of the given type. - * @param sz The new number of elements. - * @return True in case of success, false otherwise. - */ - [[nodiscard]] static bool resize([[maybe_unused]] void *container, [[maybe_unused]] const size_type sz) { - if constexpr(stl::is_default_constructible_v && requires(Type elem) { elem.resize(sz); }) { - static_cast(container)->resize(sz); - return true; - } else { - return false; - } - } - - /** - * @brief Returns a possibly const iterator to the beginning or the end. - * @param area The context to pass to the newly created iterator. - * @param container Opaque pointer to a container of the given type. - * @param as_const Const opaque pointer fallback. - * @param end False to get a pointer that is past the last element. - * @return An iterator to the first or past the last element of the - * container. - */ - static iterator iter(const meta_ctx &area, void *container, const void *as_const, const bool end) { - return (container == nullptr) - ? iterator{area, end ? static_cast(as_const)->cend() : static_cast(as_const)->cbegin()} - : iterator{area, end ? static_cast(container)->end() : static_cast(container)->begin()}; - } - - /** - * @brief Assigns one element to a container and constructs its object from - * a given opaque instance. - * @param area The context to pass to the newly created iterator. - * @param container Opaque pointer to a container of the given type. - * @param value Optional opaque instance of the object to construct (as - * value type). - * @param cref Optional opaque instance of the object to construct (as - * decayed const reference type). - * @param it Iterator before which the element will be inserted. - * @return A possibly invalid iterator to the inserted element. - */ - [[nodiscard]] static iterator insert([[maybe_unused]] const meta_ctx &area, [[maybe_unused]] void *container, [[maybe_unused]] const void *value, [[maybe_unused]] const void *cref, [[maybe_unused]] const iterator &it) { - if constexpr(requires(Type elem, typename Type::const_iterator iter, Type::value_type instance) { elem.insert(iter, instance); }) { - auto *const non_const = any_cast(&it.base()); - return {area, static_cast(container)->insert( - non_const ? *non_const : any_cast(it.base()), - (value != nullptr) ? *static_cast(value) : *static_cast *>(cref))}; - } else { - return iterator{}; - } - } - - /** - * @brief Erases an element from a container. - * @param area The context to pass to the newly created iterator. - * @param container Opaque pointer to a container of the given type. - * @param it An opaque iterator to the element to erase. - * @return A possibly invalid iterator following the last removed element. - */ - [[nodiscard]] static iterator erase([[maybe_unused]] const meta_ctx &area, [[maybe_unused]] void *container, [[maybe_unused]] const iterator &it) { - if constexpr(requires(Type elem, typename Type::const_iterator iter) { elem.erase(iter); }) { - auto *const non_const = any_cast(&it.base()); - return {area, static_cast(container)->erase(non_const ? *non_const : any_cast(it.base()))}; - } else { - return iterator{}; - } - } -}; - -/** - * @brief General purpose implementation of meta associative container traits. - * @tparam Type Type of underlying associative container. - */ -template -struct basic_meta_associative_container_traits { - /*! @brief Unsigned integer type. */ - using size_type = meta_associative_container::size_type; - /*! @brief Meta iterator type. */ - using iterator = meta_associative_container::iterator; - - /*! @brief True in case of key-only containers, false otherwise. */ - static constexpr bool key_only = !requires { typename Type::mapped_type; }; - - /** - * @brief Returns the number of elements in a container. - * @param container Opaque pointer to a container of the given type. - * @return Number of elements. - */ - [[nodiscard]] static size_type size(const void *container) { - return static_cast(container)->size(); - } - - /** - * @brief Clears a container. - * @param container Opaque pointer to a container of the given type. - * @return True in case of success, false otherwise. - */ - [[nodiscard]] static bool clear(void *container) { - static_cast(container)->clear(); - return true; - } - - /** - * @brief Increases the capacity of a container. - * @param container Opaque pointer to a container of the given type. - * @param sz Desired capacity. - * @return True in case of success, false otherwise. - */ - [[nodiscard]] static bool reserve([[maybe_unused]] void *container, [[maybe_unused]] const size_type sz) { - if constexpr(requires(Type elem) { elem.reserve(sz); }) { - static_cast(container)->reserve(sz); - return true; - } else { - return false; - } - } - - /** - * @brief Returns a possibly const iterator to the beginning or the end. - * @param area The context to pass to the newly created iterator. - * @param container Opaque pointer to a container of the given type. - * @param as_const Const opaque pointer fallback. - * @param end False to get a pointer that is past the last element. - * @return An iterator to the first or past the last element of the - * container. - */ - static iterator iter(const meta_ctx &area, void *container, const void *as_const, const bool end) { - return (container == nullptr) - ? iterator{area, stl::bool_constant{}, end ? static_cast(as_const)->cend() : static_cast(as_const)->cbegin()} - : iterator{area, stl::bool_constant{}, end ? static_cast(container)->end() : static_cast(container)->begin()}; - } - - /** - * @brief Inserts an element into a container, if the key does not exist. - * @param container Opaque pointer to a container of the given type. - * @param key An opaque key value of an element to insert. - * @param value Optional opaque value to insert (key-value containers). - * @return True if the insertion took place, false otherwise. - */ - [[nodiscard]] static bool insert(void *container, const void *key, [[maybe_unused]] const void *value) { - if constexpr(key_only) { - return static_cast(container)->insert(*static_cast(key)).second; - } else { - return static_cast(container)->emplace(*static_cast(key), *static_cast(value)).second; - } - } - - /** - * @brief Removes an element from a container. - * @param container Opaque pointer to a container of the given type. - * @param key An opaque key value of an element to remove. - * @return Number of elements removed (either 0 or 1). - */ - [[nodiscard]] static size_type erase(void *container, const void *key) { - return static_cast(container)->erase(*static_cast(key)); - } - - /** - * @brief Finds an element with a given key. - * @param area The context to pass to the newly created iterator. - * @param container Opaque pointer to a container of the given type. - * @param as_const Const opaque pointer fallback. - * @param key Opaque key value of an element to search for. - * @return An iterator to the element with the given key, if any. - */ - static iterator find(const meta_ctx &area, void *container, const void *as_const, const void *key) { - return (container != nullptr) ? iterator{area, stl::bool_constant{}, static_cast(container)->find(*static_cast(key))} - : iterator{area, stl::bool_constant{}, static_cast(as_const)->find(*static_cast(key))}; - } -}; - -/** - * @brief Traits meta sequence container like types. - * @tparam Type Container type to inspect. - */ -template -struct meta_sequence_container_traits: basic_meta_sequence_container_traits {}; - -/** - * @brief Traits for meta associative container like types. - * @tparam Type Container type to inspect. - */ -template -struct meta_associative_container_traits: basic_meta_associative_container_traits {}; - -} // namespace entt - -#endif diff --git a/include/entt/meta/context.hpp b/include/entt/meta/context.hpp deleted file mode 100644 index 4d3e34e..0000000 --- a/include/entt/meta/context.hpp +++ /dev/null @@ -1,47 +0,0 @@ -#ifndef ENTT_META_CTX_HPP -#define ENTT_META_CTX_HPP - -#include "../container/dense_map.hpp" -#include "../core/fwd.hpp" -#include "../stl/functional.hpp" -#include "../stl/memory.hpp" -#include "fwd.hpp" - -namespace entt { - -/*! @cond ENTT_INTERNAL */ -namespace internal { - -struct meta_type_node; - -struct meta_context { - using bucket_type = dense_map, stl::identity>; - - bucket_type bucket; - - [[nodiscard]] inline static meta_context &from(meta_ctx &); - [[nodiscard]] inline static const meta_context &from(const meta_ctx &); -}; - -} // namespace internal -/*! @endcond */ - -/*! @brief Opaque meta context type. */ -struct meta_ctx: private internal::meta_context { - // attorney idiom like model to access the base class - friend struct internal::meta_context; -}; - -/*! @cond ENTT_INTERNAL */ -[[nodiscard]] inline internal::meta_context &internal::meta_context::from(meta_ctx &ctx) { - return ctx; -} - -[[nodiscard]] inline const internal::meta_context &internal::meta_context::from(const meta_ctx &ctx) { - return ctx; -} -/*! @endcond */ - -} // namespace entt - -#endif diff --git a/include/entt/meta/factory.hpp b/include/entt/meta/factory.hpp deleted file mode 100644 index e91888a..0000000 --- a/include/entt/meta/factory.hpp +++ /dev/null @@ -1,656 +0,0 @@ -#ifndef ENTT_META_FACTORY_HPP -#define ENTT_META_FACTORY_HPP - -#include "../config/config.h" -#include "../core/bit.hpp" -#include "../core/fwd.hpp" -#include "../core/hashed_string.hpp" -#include "../core/type_info.hpp" -#include "../core/type_traits.hpp" -#include "../locator/locator.hpp" -#include "../stl/algorithm.hpp" -#include "../stl/concepts.hpp" -#include "../stl/cstddef.hpp" -#include "../stl/cstdint.hpp" -#include "../stl/functional.hpp" -#include "../stl/memory.hpp" -#include "../stl/type_traits.hpp" -#include "../stl/utility.hpp" -#include "context.hpp" -#include "fwd.hpp" -#include "meta.hpp" -#include "node.hpp" -#include "policy.hpp" -#include "range.hpp" -#include "utility.hpp" - -namespace entt { - -/*! @cond ENTT_INTERNAL */ -namespace internal { - -class basic_meta_factory { - using invoke_type = stl::remove_pointer_t; - - enum class mode { - type, - data, - func - }; - - [[nodiscard]] auto *find_member_or_assert() { - auto *member = find_member(parent->details->data, bucket); - ENTT_ASSERT(member != nullptr, "Cannot find member"); - return member; - } - - [[nodiscard]] auto *find_overload_or_assert() { - ENTT_ASSERT(invoke != nullptr, "Invoke function not available"); - auto *overload = find_overload(find_member(parent->details->func, bucket), invoke); - ENTT_ASSERT(overload != nullptr, "Cannot find overload"); - return overload; - } - - bool unique_alias(const id_type alias) const noexcept { - return (ctx->bucket.find(alias) == ctx->bucket.cend()) && (stl::find_if(ctx->bucket.cbegin(), ctx->bucket.cend(), [alias](const auto &value) { return value.second->alias == alias; }) == ctx->bucket.cend()); - } - -protected: - void type(const id_type alias, const char *name) noexcept { - state = mode::type; - ENTT_ASSERT((parent->alias == alias) || unique_alias(alias), "Duplicate identifier"); - parent->alias = alias; - parent->name = name; - } - - template - void insert_or_assign(Type node) { - state = mode::type; - - if constexpr(stl::is_same_v) { - auto *member = find_member(parent->details->base, node.id); - member ? (*member = node) : parent->details->base.emplace_back(node); - } else if constexpr(stl::is_same_v) { - auto *member = find_member(parent->details->conv, node.id); - member ? (*member = node) : parent->details->conv.emplace_back(node); - } else { - static_assert(stl::is_same_v, "Unexpected type"); - auto *member = find_member(parent->details->ctor, node.id); - member ? (*member = node) : parent->details->ctor.emplace_back(node); - } - } - - void data(meta_data_node node) { - state = mode::data; - bucket = node.id; - - if(auto *member = find_member(parent->details->data, node.id); member == nullptr) { - parent->details->data.emplace_back(stl::move(node)); - } else if(member->set != node.set || member->get != node.get) { - *member = stl::move(node); - } - } - - void func(meta_func_node node) { - state = mode::func; - bucket = node.id; - invoke = node.invoke; - - if(auto *member = find_member(parent->details->func, node.id); member == nullptr) { - parent->details->func.emplace_back(stl::move(node)); - } else if(auto *overload = find_overload(member, node.invoke); overload == nullptr) { - while(member->next != nullptr) { member = member->next.get(); } - member->next = stl::make_unique(stl::move(node)); - } - } - - void traits(const meta_traits value, const bool unset) { - const auto set_or_unset_on = [=](auto &node) { - node.traits = (unset ? (node.traits & ~value) : (node.traits | value)); - }; - - switch(state) { - case mode::type: - set_or_unset_on(*parent); - break; - case mode::data: - set_or_unset_on(*find_member_or_assert()); - break; - case mode::func: - set_or_unset_on(*find_overload_or_assert()); - break; - } - } - - void custom(meta_custom_node node) { - switch(state) { - case mode::type: - parent->custom = stl::move(node); - break; - case mode::data: - find_member_or_assert()->custom = stl::move(node); - break; - case mode::func: - find_overload_or_assert()->custom = stl::move(node); - break; - } - } - -public: - basic_meta_factory(meta_ctx &area, meta_type_node node, const id_type id) - : ctx{&meta_context::from(area)}, - bucket{}, - state{mode::type} { - if(const auto it = ctx->bucket.find(id); it == ctx->bucket.cend()) { - ENTT_ASSERT(unique_alias(id), "Duplicate identifier"); - parent = ctx->bucket.emplace(id, stl::make_unique(stl::move(node))).first->second.get(); - parent->details = stl::make_unique(); - parent->alias = id; - } else { - parent = it->second.get(); - } - } - -private: - meta_context *ctx{}; - invoke_type *invoke{}; - meta_type_node *parent{}; - id_type bucket{}; - mode state{}; -}; - -} // namespace internal -/*! @endcond */ - -/** - * @brief Meta factory to be used for reflection purposes. - * @tparam Type Type for which the factory was created. - */ -template -class meta_factory: private internal::basic_meta_factory { - using base_type = internal::basic_meta_factory; - -public: - /*! @brief Type of object for which this factory builds a meta type. */ - using element_type = Type; - - /*! @brief Default constructor. */ - meta_factory() noexcept - : meta_factory{locator::value_or()} {} - - /** - * @brief Context aware constructor. - * @param area The context into which to construct meta types. - */ - meta_factory(meta_ctx &area) noexcept - : base_type{area, internal::setup_node_for(), type_hash::value()} {} - - /** - * @brief Constructs an unconstrained type assigned to a given identifier. - * @param id A custom unique identifier. - */ - meta_factory(const id_type id) noexcept - : meta_factory{locator::value_or(), id} {} - - /** - * @brief Context aware constructor. - * @param id A custom unique identifier. - * @param area The context into which to construct meta types. - */ - meta_factory(meta_ctx &area, const id_type id) noexcept - : base_type{area, internal::setup_node_for(), id} {} - - /** - * @brief Assigns a custom unique identifier to a meta type. - * @param name A custom unique identifier as a **string literal**. - * @return A meta factory for the given type. - */ - meta_factory type(const char *name) noexcept { - return type(hashed_string::value(name), name); - } - - /** - * @brief Assigns a custom unique identifier to a meta type. - * @param alias A custom unique identifier. - * @param name An optional name for the type as a **string literal**. - * @return A meta factory for the given type. - */ - meta_factory type(const id_type alias, const char *name = nullptr) noexcept { - base_type::type(alias, name); - return *this; - } - - /** - * @brief Assigns a meta base to a meta type. - * - * A reflected base class must be a real base class of the reflected type. - * - * @tparam Base Type of the base class to assign to the meta type. - * @return A meta factory for the parent type. - */ - template - requires stl::derived_from - meta_factory base() noexcept { - if constexpr(!stl::same_as) { - auto *const op = +[](const void *instance) noexcept { return static_cast(static_cast(static_cast(instance))); }; - - base_type::insert_or_assign( - internal::meta_base_node{ - type_id().hash(), - &internal::resolve, - op}); - } - - return *this; - } - - /** - * @brief Assigns a meta conversion function to a meta type. - * - * Conversion functions can be either free functions or member - * functions.
- * In case of free functions, they must accept a const reference to an - * instance of the parent type as an argument. In case of member functions, - * they should have no arguments at all. - * - * @tparam Candidate The actual function to use for the conversion. - * @return A meta factory for the parent type. - */ - template - auto conv() noexcept { - using conv_type = stl::remove_cvref_t>; - auto *const op = +[](const meta_ctx &area, const void *instance) { return forward_as_meta(area, stl::invoke(Candidate, *static_cast(instance))); }; - - base_type::insert_or_assign( - internal::meta_conv_node{ - type_id().hash(), - op}); - - return *this; - } - - /** - * @brief Assigns a meta conversion function to a meta type. - * - * The given type must be such that an instance of the reflected type can be - * converted to it. - * - * @tparam To Type of the conversion function to assign to the meta type. - * @return A meta factory for the parent type. - */ - template - meta_factory conv() noexcept { - using conv_type = stl::remove_cvref_t; - auto *const op = +[](const meta_ctx &area, const void *instance) { return forward_as_meta(area, static_cast(*static_cast(instance))); }; - - base_type::insert_or_assign( - internal::meta_conv_node{ - type_id().hash(), - op}); - - return *this; - } - - /** - * @brief Assigns a meta constructor to a meta type. - * - * Both member functions and free function can be assigned to meta types in - * the role of constructors. All that is required is that they return an - * instance of the underlying type.
- * From a client's point of view, nothing changes if a constructor of a meta - * type is a built-in one or not. - * - * @tparam Candidate The actual function to use as a constructor. - * @tparam Policy Optional policy (no policy set by default). - * @return A meta factory for the parent type. - */ - template - meta_factory ctor() noexcept { - using descriptor = meta_function_helper_t; - static_assert(Policy::template value, "Invalid return type for the given policy"); - static_assert(stl::is_same_v, element_type>, "The function doesn't return an object of the required type"); - - base_type::insert_or_assign( - internal::meta_ctor_node{ - type_id().hash(), - descriptor::args_type::size, - &meta_arg, - &meta_construct}); - - return *this; - } - - /** - * @brief Assigns a meta constructor to a meta type. - * - * A meta constructor is uniquely identified by the types of its arguments - * and is such that there exists an actual constructor of the underlying - * type that can be invoked with parameters whose types are those given. - * - * @tparam Args Types of arguments to use to construct an instance. - * @return A meta factory for the parent type. - */ - template - meta_factory ctor() noexcept { - // default constructor is already implicitly generated, no need for redundancy - if constexpr(sizeof...(Args) != 0u) { - using descriptor = meta_function_helper_t; - - base_type::insert_or_assign( - internal::meta_ctor_node{ - type_id().hash(), - descriptor::args_type::size, - &meta_arg, - &meta_construct}); - } - - return *this; - } - - /** - * @brief Assigns a meta data to a meta type. - * @tparam Data The actual variable to attach to the meta type. - * @tparam Policy Optional policy (no policy set by default). - * @param name A custom unique identifier as a **string literal**. - * @return A meta factory for the given type. - */ - template - meta_factory data(const char *name) noexcept { - return data(hashed_string::value(name), name); - } - - /** - * @brief Assigns a meta data to a meta type. - * - * Both data members and static and global variables, as well as constants - * of any kind, can be assigned to a meta type.
- * From a client's point of view, all the variables associated with the - * reflected object will appear as if they were part of the type itself. - * - * @tparam Data The actual variable to attach to the meta type. - * @tparam Policy Optional policy (no policy set by default). - * @param id Unique identifier. - * @param name An optional name for the meta data as a **string literal**. - * @return A meta factory for the parent type. - */ - template - meta_factory data(const id_type id, const char *name = nullptr) noexcept { - if constexpr(stl::is_member_object_pointer_v) { - using data_type = stl::invoke_result_t; - static_assert(Policy::template value, "Invalid return type for the given policy"); - - base_type::data( - internal::meta_data_node{ - id, - name, - /* this is never static */ - stl::is_const_v> ? internal::meta_traits::is_const : internal::meta_traits::is_none, - 1u, - 0u, - &meta_arg>>, - &meta_arg>, - &internal::resolve>, - &meta_setter, - &meta_getter}); - } else { - using data_type = stl::remove_pointer_t; - - if constexpr(stl::is_pointer_v) { - static_assert(Policy::template value, "Invalid return type for the given policy"); - } else { - static_assert(Policy::template value, "Invalid return type for the given policy"); - } - - base_type::data( - internal::meta_data_node{ - id, - name, - ((!stl::is_pointer_v || stl::is_const_v) ? internal::meta_traits::is_const : internal::meta_traits::is_none) | internal::meta_traits::is_static, - 1u, - 0u, - &meta_arg>>, - &meta_arg>, - &internal::resolve>, - &meta_setter, - &meta_getter}); - } - - return *this; - } - - /** - * @brief Assigns a meta data to a meta type by means of its setter and - * getter. - * @tparam Setter The actual function to use as a setter. - * @tparam Getter The actual function to use as a getter. - * @tparam Policy Optional policy (no policy set by default). - * @param name A custom unique identifier as a **string literal**. - * @return A meta factory for the given type. - */ - template - meta_factory data(const char *name) noexcept { - return data(hashed_string::value(name), name); - } - - /** - * @brief Assigns a meta data to a meta type by means of its setter and - * getter. - * - * Setters and getters can be either free functions, member functions or a - * mix of them.
- * In case of free functions, setters and getters must accept a reference to - * an instance of the parent type as their first argument. A setter has then - * an extra argument of a type convertible to that of the parameter to - * set.
- * In case of member functions, getters have no arguments at all, while - * setters has an argument of a type convertible to that of the parameter to - * set. - * - * @tparam Setter The actual function to use as a setter. - * @tparam Getter The actual function to use as a getter. - * @tparam Policy Optional policy (no policy set by default). - * @param id Unique identifier. - * @param name An optional name for the meta data as a **string literal**. - * @return A meta factory for the parent type. - */ - template - meta_factory data(const id_type id, const char *name = nullptr) noexcept { - using getter = meta_function_helper_t; - static_assert(Policy::template value, "Invalid return type for the given policy"); - - if constexpr(stl::is_same_v) { - base_type::data( - internal::meta_data_node{ - id, - name, - /* this is never static */ - internal::meta_traits::is_const, - 0u, - getter::args_type::size, - &meta_arg>, - &meta_arg, - &internal::resolve>, - &meta_setter, - &meta_getter}); - } else { - using setter = meta_function_helper_t; - - base_type::data( - internal::meta_data_node{ - id, - name, - /* this is never static nor const */ - internal::meta_traits::is_none, - setter::args_type::size, - getter::args_type::size, - &meta_arg, - &meta_arg, - &internal::resolve>, - &meta_setter, - &meta_getter}); - } - - return *this; - } - - /** - * @brief Assigns a meta function to a meta type. - * @tparam Candidate The actual function to attach to the meta function. - * @tparam Policy Optional policy (no policy set by default). - * @param name A custom unique identifier as a **string literal**. - * @return A meta factory for the given type. - */ - template - meta_factory func(const char *name) noexcept { - return func(hashed_string::value(name), name); - } - - /** - * @brief Assigns a meta function to a meta type. - * - * Both member functions and free functions can be assigned to a meta - * type.
- * From a client's point of view, all the functions associated with the - * reflected object will appear as if they were part of the type itself. - * - * @tparam Candidate The actual function to attach to the meta type. - * @tparam Policy Optional policy (no policy set by default). - * @param id Unique identifier. - * @param name An optional name for the function as a **string literal**. - * @return A meta factory for the parent type. - */ - template - meta_factory func(const id_type id, const char *name = nullptr) noexcept { - using descriptor = meta_function_helper_t; - static_assert(Policy::template value, "Invalid return type for the given policy"); - - base_type::func( - internal::meta_func_node{ - id, - name, - (descriptor::is_const ? internal::meta_traits::is_const : internal::meta_traits::is_none) | (descriptor::is_static ? internal::meta_traits::is_static : internal::meta_traits::is_none), - descriptor::args_type::size, - &internal::resolve, void, stl::remove_cvref_t>>, - &meta_arg, - &meta_invoke}); - - return *this; - } - - /** - * @brief Sets traits on the last created meta object. - * - * The assigned value must be an enum and intended as a bitmask. - * - * @tparam Value Type of the traits value. - * @param value Traits value. - * @param unset True to unset the given traits, false otherwise. - * @return A meta factory for the parent type. - */ - template - meta_factory traits(const Value value, const bool unset = false) { - static_assert(stl::is_enum_v, "Invalid enum type"); - base_type::traits(internal::user_to_meta_traits(value), unset); - return *this; - } - - /** - * @brief Sets user defined data that will never be used by the library. - * @tparam Value Type of user defined data to store. - * @tparam Args Types of arguments to use to construct the user data. - * @param args Parameters to use to initialize the user data. - * @return A meta factory for the parent type. - */ - template - meta_factory custom(Args &&...args) { - base_type::custom(internal::meta_custom_node{type_id().hash(), stl::make_shared(stl::forward(args)...)}); - return *this; - } -}; - -/** - * @brief Resets a type and all its parts. - * - * Resets a type and all its data members, member functions and properties, as - * well as its constructors, destructors and conversion functions if any.
- * Base classes aren't reset but the link between the two types is removed. - * - * The type is also removed from the set of searchable types. - * - * @param alias Unique identifier. - * @param ctx The context from which to reset meta types. - */ -inline void meta_reset(meta_ctx &ctx, const id_type alias) noexcept { - auto &bucket = internal::meta_context::from(ctx).bucket; - - // fast path for unsearchable and overloaded types - if(bucket.erase(alias) == 0u) { - if(const auto it = stl::find_if(bucket.cbegin(), bucket.cend(), [alias](const auto &value) { return value.second->alias == alias; }); it != bucket.cend()) { - bucket.erase(it); - } - } -} - -/** - * @brief Resets a type and all its parts. - * - * Resets a type and all its data members, member functions and properties, as - * well as its constructors, destructors and conversion functions if any.
- * Base classes aren't reset but the link between the two types is removed. - * - * The type is also removed from the set of searchable types. - * - * @param alias Unique identifier. - */ -inline void meta_reset(const id_type alias) noexcept { - meta_reset(locator::value_or(), alias); -} - -/** - * @brief Resets a type and all its parts. - * - * @sa meta_reset - * - * @tparam Type Type to reset. - * @param ctx The context from which to reset meta types. - */ -template -void meta_reset(meta_ctx &ctx) noexcept { - internal::meta_context::from(ctx).bucket.erase(type_id().hash()); -} - -/** - * @brief Resets a type and all its parts. - * - * @sa meta_reset - * - * @tparam Type Type to reset. - */ -template -void meta_reset() noexcept { - meta_reset(locator::value_or()); -} - -/** - * @brief Resets all meta types. - * - * @sa meta_reset - * - * @param ctx The context from which to reset meta types. - */ -inline void meta_reset(meta_ctx &ctx) noexcept { - internal::meta_context::from(ctx).bucket.clear(); -} - -/** - * @brief Resets all meta types. - * - * @sa meta_reset - */ -inline void meta_reset() noexcept { - meta_reset(locator::value_or()); -} - -} // namespace entt - -#endif diff --git a/include/entt/meta/fwd.hpp b/include/entt/meta/fwd.hpp deleted file mode 100644 index ac949c7..0000000 --- a/include/entt/meta/fwd.hpp +++ /dev/null @@ -1,43 +0,0 @@ -#ifndef ENTT_META_FWD_HPP -#define ENTT_META_FWD_HPP - -#include "../stl/cstddef.hpp" -#include "../stl/limits.hpp" - -namespace entt { - -struct meta_ctx; - -class meta_sequence_container; - -class meta_associative_container; - -class meta_any; - -class meta_handle; - -struct meta_custom; - -struct meta_data; - -struct meta_func; - -struct meta_base; - -class meta_type; - -template -class meta_factory; - -/*! @brief Used to identicate that a sequence container has not a fixed size. */ -inline constexpr stl::size_t meta_dynamic_extent = (stl::numeric_limits::max)(); - -/*! @brief Disambiguation tag for constructors and the like. */ -struct meta_ctx_arg_t final {}; - -/*! @brief Constant of type meta_context_arg_t used to disambiguate calls. */ -inline constexpr meta_ctx_arg_t meta_ctx_arg{}; - -} // namespace entt - -#endif diff --git a/include/entt/meta/meta.hpp b/include/entt/meta/meta.hpp deleted file mode 100644 index f94026d..0000000 --- a/include/entt/meta/meta.hpp +++ /dev/null @@ -1,1902 +0,0 @@ -#ifndef ENTT_META_META_HPP -#define ENTT_META_META_HPP - -#include "../config/config.h" -#include "../core/any.hpp" -#include "../core/concepts.hpp" -#include "../core/fwd.hpp" -#include "../core/iterator.hpp" -#include "../core/type_info.hpp" -#include "../core/type_traits.hpp" -#include "../core/utility.hpp" -#include "../locator/locator.hpp" -#include "../stl/array.hpp" -#include "../stl/concepts.hpp" -#include "../stl/cstddef.hpp" -#include "../stl/iterator.hpp" -#include "../stl/memory.hpp" -#include "../stl/string_view.hpp" -#include "../stl/type_traits.hpp" -#include "../stl/utility.hpp" -#include "adl_pointer.hpp" -#include "context.hpp" -#include "fwd.hpp" -#include "node.hpp" -#include "range.hpp" -#include "type_traits.hpp" - -namespace entt { - -/*! @cond ENTT_INTERNAL */ -namespace internal { - -template -struct basic_meta_object { - [[nodiscard]] auto &node_or_assert() const noexcept { - ENTT_ASSERT(node != nullptr, "Invalid pointer to node"); - return *node; - } - - const Type *node{}; - const meta_ctx *ctx{&locator::value_or()}; -}; - -} // namespace internal -/*! @endcond */ - -/*! @brief Proxy object for sequence containers. */ -class meta_sequence_container { - class meta_iterator; - -public: - /*! @brief Unsigned integer type. */ - using size_type = stl::size_t; - /*! @brief Meta iterator type. */ - using iterator = meta_iterator; - - /*! @brief Default constructor. */ - meta_sequence_container() = default; - - /** - * @brief Context aware constructor. - * @tparam Type Type of container to wrap. - * @param area The context from which to search for meta types. - * @param instance The container to wrap. - */ - template - meta_sequence_container(const meta_ctx &area, Type &instance) noexcept - : ctx{&area}, - data{&instance}, - value_type_node{&internal::resolve}, - const_reference_node{&internal::resolve>}, - size_fn{meta_sequence_container_traits>::size}, - clear_fn{meta_sequence_container_traits>::clear}, - reserve_fn{meta_sequence_container_traits>::reserve}, - resize_fn{meta_sequence_container_traits>::resize}, - begin_end_fn{meta_sequence_container_traits>::iter}, - insert_fn{meta_sequence_container_traits>::insert}, - erase_fn{meta_sequence_container_traits>::erase}, - const_only{stl::is_const_v} {} - - [[nodiscard]] inline meta_type value_type() const noexcept; - [[nodiscard]] inline size_type size() const noexcept; - inline bool resize(size_type); - inline bool clear(); - inline bool reserve(size_type); - [[nodiscard]] inline iterator begin(); - [[nodiscard]] inline iterator end(); - inline iterator insert(const iterator &, meta_any); - inline iterator erase(const iterator &); - [[nodiscard]] inline meta_any operator[](size_type); - [[nodiscard]] inline explicit operator bool() const noexcept; - -private: - const meta_ctx *ctx{}; - const void *data{}; - const internal::meta_type_node &(*value_type_node)(const internal::meta_context &){}; - const internal::meta_type_node &(*const_reference_node)(const internal::meta_context &){}; - size_type (*size_fn)(const void *){}; - bool (*clear_fn)(void *){}; - bool (*reserve_fn)(void *, const size_type){}; - bool (*resize_fn)(void *, const size_type){}; - iterator (*begin_end_fn)(const meta_ctx &, void *, const void *, const bool){}; - iterator (*insert_fn)(const meta_ctx &, void *, const void *, const void *, const iterator &){}; - iterator (*erase_fn)(const meta_ctx &, void *, const iterator &){}; - bool const_only{}; -}; - -/*! @brief Proxy object for associative containers. */ -class meta_associative_container { - class meta_iterator; - -public: - /*! @brief Unsigned integer type. */ - using size_type = stl::size_t; - /*! @brief Meta iterator type. */ - using iterator = meta_iterator; - - /*! @brief Default constructor. */ - meta_associative_container() = default; - - /** - * @brief Context aware constructor. - * @tparam Type Type of container to wrap. - * @param area The context from which to search for meta types. - * @param instance The container to wrap. - */ - template - meta_associative_container(const meta_ctx &area, Type &instance) noexcept - : ctx{&area}, - data{&instance}, - key_type_node{&internal::resolve}, - value_type_node{&internal::resolve}, - size_fn{&meta_associative_container_traits>::size}, - clear_fn{&meta_associative_container_traits>::clear}, - reserve_fn{&meta_associative_container_traits>::reserve}, - begin_end_fn{&meta_associative_container_traits>::iter}, - insert_fn{&meta_associative_container_traits>::insert}, - erase_fn{&meta_associative_container_traits>::erase}, - find_fn{&meta_associative_container_traits>::find}, - const_only{stl::is_const_v} { - if constexpr(!meta_associative_container_traits>::key_only) { - mapped_type_node = &internal::resolve; - } - } - - [[nodiscard]] inline meta_type key_type() const noexcept; - [[nodiscard]] inline meta_type mapped_type() const noexcept; - [[nodiscard]] inline meta_type value_type() const noexcept; - [[nodiscard]] inline size_type size() const noexcept; - inline bool clear(); - inline bool reserve(size_type); - [[nodiscard]] inline iterator begin(); - [[nodiscard]] inline iterator end(); - inline bool insert(meta_any, meta_any); - inline size_type erase(meta_any); - [[nodiscard]] inline iterator find(meta_any); - [[nodiscard]] inline explicit operator bool() const noexcept; - -private: - const meta_ctx *ctx{}; - const void *data{}; - const internal::meta_type_node &(*key_type_node)(const internal::meta_context &){}; - const internal::meta_type_node &(*mapped_type_node)(const internal::meta_context &){}; - const internal::meta_type_node &(*value_type_node)(const internal::meta_context &){}; - size_type (*size_fn)(const void *){}; - bool (*clear_fn)(void *){}; - bool (*reserve_fn)(void *, const size_type){}; - iterator (*begin_end_fn)(const meta_ctx &, void *, const void *, const bool){}; - bool (*insert_fn)(void *, const void *, const void *){}; - size_type (*erase_fn)(void *, const void *){}; - iterator (*find_fn)(const meta_ctx &, void *, const void *, const void *){}; - bool const_only{}; -}; - -/*! @brief Opaque wrapper for values of any type. */ -class meta_any { - using vtable_type = void(const internal::meta_traits, const meta_any &, void *); - - template - static void basic_vtable(const internal::meta_traits req, const meta_any &value, [[maybe_unused]] void *other) { - if(req == internal::meta_traits::is_none) { - value.node = &internal::resolve(internal::meta_context::from(*value.ctx)); - } - - if constexpr(is_meta_pointer_like_v) { - if(req == internal::meta_traits::is_pointer) { - if constexpr(!stl::is_void_v::element_type>>) { - if constexpr(stl::is_constructible_v) { - if(const auto &pointer_like = any_cast(value.storage); pointer_like) { - static_cast(other)->emplace::dereference(stl::declval()))>(adl_meta_pointer_like::dereference(pointer_like)); - } - } else { - static_cast(other)->emplace::dereference(stl::declval()))>(adl_meta_pointer_like::dereference(any_cast(value.storage))); - } - } - } - } else if constexpr(requires(Type elem) { *elem; }) { - if(req == internal::meta_traits::is_pointer) { - if constexpr(stl::is_class_v) { - if(const auto &elem = any_cast(value.storage); elem) { - return (value.storage.policy() == any_policy::cref) ? static_cast(other)->emplace(*elem) : static_cast(other)->emplace(elem))>(*const_cast(elem)); - } - } else if constexpr(!stl::is_array_v && !stl::is_void_v>>) { - if(auto *pointer = any_cast(value.storage); pointer) { - static_cast(other)->emplace>>, Type, stl::remove_pointer_t &>>(*pointer); - } - } - } - } else if constexpr(is_complete_v> || is_complete_v>) { - if(constexpr auto flag = (is_complete_v> ? internal::meta_traits::is_sequence_container : internal::meta_traits::is_associative_container); req == flag) { - using container_type = stl::conditional_t>, meta_sequence_container, meta_associative_container>; - *static_cast(other) = (value.storage.policy() == any_policy::cref) ? container_type{*value.ctx, any_cast(value.storage)} : container_type{*value.ctx, any_cast(const_cast(value).storage)}; - } - } - } - - [[nodiscard]] const auto &fetch_node() const { - if(node == nullptr) { - ENTT_ASSERT(*this, "Invalid vtable function"); - vtable(internal::meta_traits::is_none, *this, nullptr); - } - - ENTT_ASSERT(node != nullptr, "Invalid pointer to node"); - return *node; - } - - meta_any(const meta_any &other, any elem) - : storage{stl::move(elem)}, - ctx{other.ctx}, - node{other.node}, - vtable{other.vtable} {} - -public: - /*! Default constructor. */ - meta_any() = default; - - /** - * @brief Context aware constructor. - * @param area The context from which to search for meta types. - */ - meta_any(meta_ctx_arg_t, const meta_ctx &area) - : ctx{&area} {} - - /** - * @brief Constructs a wrapper by directly initializing the new object. - * @tparam Type Type of object to use to initialize the wrapper. - * @param args Parameters to use to construct the instance. - */ - template - explicit meta_any(stl::in_place_type_t, auto &&...args) - : meta_any{locator::value_or(), stl::in_place_type, stl::forward(args)...} {} - - /** - * @brief Constructs a wrapper by directly initializing the new object. - * @tparam Type Type of object to use to initialize the wrapper. - * @param area The context from which to search for meta types. - * @param args Parameters to use to construct the instance. - */ - template - explicit meta_any(const meta_ctx &area, stl::in_place_type_t, auto &&...args) - : storage{stl::in_place_type, stl::forward(args)...}, - ctx{&area}, - vtable{&basic_vtable>} {} - - /** - * @brief Constructs a wrapper taking ownership of the passed object. - * @param value A pointer to an object to take ownership of. - */ - explicit meta_any(stl::in_place_t, auto *value) - : meta_any{locator::value_or(), stl::in_place, value} {} - - /** - * @brief Constructs a wrapper taking ownership of the passed object. - * @param area The context from which to search for meta types. - * @param value A pointer to an object to take ownership of. - */ - explicit meta_any(const meta_ctx &area, stl::in_place_t, auto *value) - : storage{stl::in_place, value}, - ctx{&area}, - vtable{storage ? &basic_vtable>> : nullptr} { - } - - /** - * @brief Constructs a wrapper from a given value. - * @param value An instance of an object to use to initialize the wrapper. - */ - meta_any(auto &&value) - requires (!stl::same_as, meta_any>) - : meta_any{locator::value_or(), stl::forward(value)} {} - - /** - * @brief Constructs a wrapper from a given value. - * @param area The context from which to search for meta types. - * @param value An instance of an object to use to initialize the wrapper. - */ - meta_any(const meta_ctx &area, auto &&value) - requires (!stl::same_as, meta_any>) - : meta_any{area, stl::in_place_type>, stl::forward(value)} {} - - /** - * @brief Context aware copy constructor. - * @param area The context from which to search for meta types. - * @param other The instance to copy from. - */ - meta_any(const meta_ctx &area, const meta_any &other) - : storage{other.storage}, - ctx{&area}, - node{(ctx == other.ctx) ? other.node : nullptr}, - vtable{other.vtable} {} - - /** - * @brief Context aware move constructor. - * @param area The context from which to search for meta types. - * @param other The instance to move from. - */ - meta_any(const meta_ctx &area, meta_any &&other) - : storage{stl::move(other.storage)}, - ctx{&area}, - node{(ctx == other.ctx) ? stl::exchange(other.node, nullptr) : nullptr}, - vtable{stl::exchange(other.vtable, nullptr)} {} - - /** - * @brief Copy constructor. - * @param other The instance to copy from. - */ - meta_any(const meta_any &other) - : storage{other.storage}, - ctx{other.ctx}, - node{(other.storage && !storage) ? nullptr : other.node}, - vtable{(other.storage && !storage) ? nullptr : other.vtable} { - } - - /** - * @brief Move constructor. - * @param other The instance to move from. - */ - meta_any(meta_any &&other) noexcept - : storage{stl::move(other.storage)}, - ctx{other.ctx}, - node{stl::exchange(other.node, nullptr)}, - vtable{stl::exchange(other.vtable, nullptr)} {} - - /*! @brief Default destructor. */ - ~meta_any() = default; - - /** - * @brief Copy assignment operator. - * @param other The instance to copy from. - * @return This meta any object. - */ - meta_any &operator=(const meta_any &other) { - if(this != &other) { - ctx = other.ctx; - storage = other.storage; - node = (other.storage && !storage) ? nullptr : other.node; - vtable = (other.storage && !storage) ? nullptr : other.vtable; - } - - return *this; - } - - /** - * @brief Move assignment operator. - * @param other The instance to move from. - * @return This meta any object. - */ - meta_any &operator=(meta_any &&other) noexcept { - storage = stl::move(other.storage); - ctx = other.ctx; - node = stl::exchange(other.node, nullptr); - vtable = stl::exchange(other.vtable, nullptr); - return *this; - } - - /** - * @brief Value assignment operator. - * @param value An instance of an object to use to initialize the wrapper. - * @return This meta any object. - */ - meta_any &operator=(auto &&value) - requires (!stl::same_as, meta_any>) { - emplace>(stl::forward(value)); - return *this; - } - - /** - * @brief Returns the meta type associated with the contained instance. - * @return The meta type associated with the contained instance. - */ - [[nodiscard]] inline meta_type type() const noexcept; - - /** - * @brief Sets a meta type for the contained instance. - * @param alias The meta to use with the contained instance. - */ - inline void type(const meta_type &alias) noexcept; - - /** - * @brief Invokes the underlying function, if possible. - * @param id Unique identifier. - * @param args Parameters to use to invoke the function. - * @return A wrapper containing the returned value, if any. - */ - meta_any invoke(id_type id, auto &&...args) const; - - /*! @copydoc invoke */ - meta_any invoke(id_type id, auto &&...args); - - /** - * @brief Sets the value of a given variable. - * @param id Unique identifier. - * @param args Parameters to use to set the underlying variable. - * @return True in case of success, false otherwise. - */ - bool set(id_type id, auto &&...args); - - /** - * @brief Gets the value of a given variable. - * @param id Unique identifier. - * @param args Parameters to use to set the underlying variable, if any. - * @return A wrapper containing the value of the underlying variable. - */ - [[nodiscard]] meta_any get(id_type id, auto &&...args) const; - - /*! @copydoc get */ - [[nodiscard]] meta_any get(id_type id, auto &&...args); - - /** - * @brief Tries to cast an instance to a given type. - * @tparam Type Type to which to cast the instance. - * @return A (possibly null) pointer to the contained instance. - */ - template - [[nodiscard]] const Type *try_cast() const { - const auto *elem = any_cast(&storage); - return ((elem != nullptr) || !*this) ? elem : static_cast(internal::try_cast(internal::meta_context::from(*ctx), fetch_node(), type_hash>::value(), storage.data())); - } - - /*! @copydoc try_cast */ - template - [[nodiscard]] Type *try_cast() { - return ((storage.policy() == any_policy::cref) && !stl::is_const_v) ? nullptr : const_cast(stl::as_const(*this).try_cast>()); - } - - /** - * @brief Tries to cast an instance to a given type. - * @tparam Type Type to which to cast the instance. - * @return A reference to the contained instance. - */ - template - [[nodiscard]] stl::remove_const_t cast() const { - auto *const instance = try_cast>(); - ENTT_ASSERT(instance, "Invalid instance"); - return static_cast(*instance); - } - - /*! @copydoc cast */ - template - [[nodiscard]] stl::remove_const_t cast() { - // forces const on non-reference types to make them work also with wrappers for const references - auto *const instance = try_cast>(); - ENTT_ASSERT(instance, "Invalid instance"); - return static_cast(*instance); - } - - /** - * @brief Converts an object in such a way that a given cast becomes viable. - * @param type Meta type to which the cast is requested. - * @return A valid meta object if convertible, an invalid one otherwise. - */ - [[nodiscard]] meta_any allow_cast(const meta_type &type) const; - - /** - * @brief Converts an object in such a way that a given cast becomes viable. - * @param type Meta type to which the cast is requested. - * @return True if convertible, false otherwise. - */ - [[nodiscard]] bool allow_cast(const meta_type &type); - - /** - * @brief Converts an object in such a way that a given cast becomes viable. - * @tparam Type Type to which the cast is requested. - * @return A valid meta object if convertible, an invalid one otherwise. - */ - template - [[nodiscard]] meta_any allow_cast() const { - if constexpr(!stl::is_reference_v || stl::is_const_v>) { - if(storage.has_value>()) { - return as_ref(); - } else if(*this) { - if constexpr(stl::is_arithmetic_v> || stl::is_enum_v>) { - if(const auto &from = fetch_node(); from.conversion_helper) { - return meta_any{*ctx, static_cast(from.conversion_helper(nullptr, storage.data()))}; - } - } - - if(const auto &from = fetch_node(); from.details != nullptr) { - if(const auto *elem = internal::find_member(from.details->conv, entt::type_hash>::value()); elem != nullptr) { - return elem->conv(*ctx, storage.data()); - } - - for(auto &&curr: from.details->base) { - if(auto other = curr.type(internal::meta_context::from(*ctx)).from_void(*ctx, nullptr, curr.cast(storage.data())); curr.id == entt::type_hash>::value()) { - return other; - } else if(auto from_base = stl::as_const(other).template allow_cast(); from_base) { - return from_base; - } - } - } - } - } - - return meta_any{meta_ctx_arg, *ctx}; - } - - /** - * @brief Converts an object in such a way that a given cast becomes viable. - * @tparam Type Type to which the cast is requested. - * @return True if convertible, false otherwise. - */ - template - [[nodiscard]] bool allow_cast() { - if constexpr(stl::is_reference_v && !stl::is_const_v>) { - return allow_cast &>() && (storage.policy() != any_policy::cref); - } else { - if(storage.has_value>()) { - return true; - } else if(auto other = stl::as_const(*this).allow_cast>(); other) { - if(other.storage.owner()) { - stl::swap(*this, other); - } - - return true; - } - - return false; - } - } - - /*! @copydoc any::emplace */ - template - void emplace(auto &&...args) { - storage.emplace(stl::forward(args)...); - auto *prev = stl::exchange(vtable, &basic_vtable>); - node = (prev == vtable) ? node : nullptr; - } - - /*! @copydoc any::assign */ - bool assign(const meta_any &other); - - /*! @copydoc any::assign */ - bool assign(meta_any &&other); - - /*! @copydoc any::reset */ - void reset() { - storage.reset(); - node = nullptr; - vtable = nullptr; - } - - /** - * @brief Returns a sequence container proxy. - * @return A sequence container proxy for the underlying object. - */ - [[nodiscard]] meta_sequence_container as_sequence_container() noexcept { - meta_sequence_container proxy{}; - if(*this) { vtable(internal::meta_traits::is_sequence_container, *this, &proxy); } - return proxy; - } - - /*! @copydoc as_sequence_container */ - [[nodiscard]] meta_sequence_container as_sequence_container() const noexcept { - meta_sequence_container proxy{}; - if(*this) { vtable(internal::meta_traits::is_sequence_container, as_ref(), &proxy); } - return proxy; - } - - /** - * @brief Returns an associative container proxy. - * @return An associative container proxy for the underlying object. - */ - [[nodiscard]] meta_associative_container as_associative_container() noexcept { - meta_associative_container proxy{}; - if(*this) { vtable(internal::meta_traits::is_associative_container, *this, &proxy); } - return proxy; - } - - /*! @copydoc as_associative_container */ - [[nodiscard]] meta_associative_container as_associative_container() const noexcept { - meta_associative_container proxy{}; - if(*this) { vtable(internal::meta_traits::is_associative_container, as_ref(), &proxy); } - return proxy; - } - - /** - * @brief Indirection operator for dereferencing opaque objects. - * @return A wrapper that shares a reference to an unmanaged object if the - * wrapped element is dereferenceable, an invalid meta any otherwise. - */ - [[nodiscard]] meta_any operator*() noexcept { - meta_any ret{meta_ctx_arg, *ctx}; - if(*this) { vtable(internal::meta_traits::is_pointer, *this, &ret); } - return ret; - } - - /*! @copydoc operator* */ - [[nodiscard]] meta_any operator*() const noexcept { - meta_any ret{meta_ctx_arg, *ctx}; - if(*this) { vtable(internal::meta_traits::is_pointer, as_ref(), &ret); } - return ret; - } - - /*! @copydoc any::operator bool */ - [[nodiscard]] explicit operator bool() const noexcept { - return !(vtable == nullptr); - } - - /*! @copydoc any::operator== */ - [[nodiscard]] bool operator==(const meta_any &other) const noexcept { - return (ctx == other.ctx) && (!*this == !other) && (storage == other.storage); - } - - /*! @copydoc any::as_ref */ - [[nodiscard]] meta_any as_ref() noexcept { - return meta_any{*this, storage.as_ref()}; - } - - /*! @copydoc any::as_ref */ - [[nodiscard]] meta_any as_ref() const noexcept { - return meta_any{*this, storage.as_ref()}; - } - - /** - * @brief Returns the underlying storage. - * @return The underlyig storage. - */ - [[nodiscard]] const any &base() const noexcept { - return storage; - } - - /** - * @brief Returns the underlying meta context. - * @return The underlying meta context. - */ - [[nodiscard]] const meta_ctx &context() const noexcept { - return *ctx; - } - -private: - any storage{}; - const meta_ctx *ctx{&locator::value_or()}; - mutable const internal::meta_type_node *node{}; - vtable_type *vtable{}; -}; - -/** - * @brief Forwards its argument and avoids copies for lvalue references. - * @param value Parameter to use to construct the instance. - * @param ctx The context from which to search for meta types. - * @return A properly initialized and not necessarily owning wrapper. - */ -[[nodiscard]] meta_any forward_as_meta(const meta_ctx &ctx, auto &&value) { - return meta_any{ctx, stl::in_place_type, stl::forward(value)}; -} - -/** - * @brief Forwards its argument and avoids copies for lvalue references. - * @param value Parameter to use to construct the instance. - * @return A properly initialized and not necessarily owning wrapper. - */ -[[nodiscard]] meta_any forward_as_meta(auto &&value) { - return forward_as_meta(locator::value_or(), stl::forward(value)); -} - -/*! @brief Opaque pointers to instances of any type. */ -class meta_handle { - meta_handle(int, auto &value, auto &&...args) - requires stl::same_as, meta_any> - : any{stl::forward(args)..., value.as_ref()} {} - - meta_handle(char, auto &value, auto &&...args) - : any{stl::forward(args)..., stl::in_place_type, value} {} - -public: - /*! Default constructor. */ - meta_handle() = default; - - /** - * @brief Creates a handle that points to an unmanaged object. - * @param ctx The context from which to search for meta types. - * @param value An instance of an object to use to initialize the handle. - */ - meta_handle(const meta_ctx &ctx, auto &value) - requires (!stl::same_as, meta_handle>) - : meta_handle{0, value, ctx} {} - - /** - * @brief Creates a handle that points to an unmanaged object. - * @param value An instance of an object to use to initialize the handle. - */ - meta_handle(auto &value) - requires (!stl::same_as, meta_handle>) - : meta_handle{0, value} {} - - /** - * @brief Context aware move constructor. - * @param area The context from which to search for meta types. - * @param other The instance to move from. - */ - meta_handle(const meta_ctx &area, meta_handle &&other) - : any{area, stl::move(other.any)} {} - - /*! @brief Default copy constructor, deleted on purpose. */ - meta_handle(const meta_handle &) = delete; - - /*! @brief Default move constructor. */ - meta_handle(meta_handle &&) = default; - - /*! @brief Default destructor. */ - ~meta_handle() = default; - - /** - * @brief Default copy assignment operator, deleted on purpose. - * @return This meta handle. - */ - meta_handle &operator=(const meta_handle &) = delete; - - /** - * @brief Default move assignment operator. - * @return This meta handle. - */ - meta_handle &operator=(meta_handle &&) = default; - - /** - * @brief Returns false if a handle is invalid, true otherwise. - * @return False if the handle is invalid, true otherwise. - */ - [[nodiscard]] explicit operator bool() const noexcept { - return static_cast(any); - } - - /** - * @brief Access operator for accessing the contained opaque object. - * @return A wrapper that shares a reference to an unmanaged object. - */ - [[nodiscard]] meta_any *operator->() { - return &any; - } - -private: - meta_any any{}; -}; - -/*! @brief Opaque wrapper for user defined data of any type. */ -struct meta_custom { - /*! @brief Default constructor. */ - meta_custom() noexcept = default; - - /** - * @brief Basic constructor for meta objects. - * @param curr The underlying node with which to construct the instance. - */ - meta_custom(const internal::meta_custom_node &curr) noexcept - : node{&curr} {} - - /** - * @brief Generic conversion operator. - * @tparam Type Type to which conversion is requested. - */ - template - [[nodiscard]] operator Type *() const noexcept { - return ((node != nullptr) && (type_hash>::value() == node->id)) ? static_cast(node->value.get()) : nullptr; - } - - /** - * @brief Generic conversion operator. - * @tparam Type Type to which conversion is requested. - */ - template - [[nodiscard]] operator Type &() const noexcept { - ENTT_ASSERT(static_cast(*this) != nullptr, "Invalid type"); - return *static_cast(node->value.get()); - } - -private: - const internal::meta_custom_node *node{}; -}; - -/** - * @brief Common opaque wrapper for meta objects. - * @tparam Type Underlying meta node type. - */ -template -struct meta_object: protected internal::basic_meta_object { - /*! @brief Underlying meta node type. */ - using node_type = Type; - /*! @brief Unsigned integer type. */ - using size_type = stl::size_t; - - /*! @brief Default constructor. */ - meta_object() noexcept = default; - - /** - * @brief Context aware constructor for meta objects. - * @param area The context from which to search for meta types. - * @param curr The underlying node with which to construct the instance. - */ - meta_object(const meta_ctx &area, const node_type &curr) noexcept - : internal::basic_meta_object{&curr, &area} { - } - - /** - * @brief Returns true if an object is valid, false otherwise. - * @return True if the object is valid, false otherwise. - */ - [[nodiscard]] explicit operator bool() const noexcept { - return (this->node != nullptr); - } - - /** - * @brief Checks if two objects refer to the same type. - * @param other The object with which to compare. - * @return True if the objects refer to the same type, false otherwise. - */ - [[nodiscard]] bool operator==(const meta_object &other) const noexcept { - return (this->ctx == other.ctx) && (this->node == other.node); - } -}; - -/*! @brief Opaque wrapper for data members. */ -struct meta_data: meta_object { - using meta_object::meta_object; - - /** - * @brief Returns the name assigned to a data member, if any. - * @return The name assigned to the data member, if any. - */ - [[nodiscard]] stl::string_view name() const noexcept { - return (node_or_assert().name == nullptr) ? stl::string_view{} : stl::string_view{node_or_assert().name}; - } - - /** - * @brief Returns the number of arguments of a data member's setter. - * @return The number of arguments accepted by the data member's setter. - */ - [[nodiscard]] size_type set_arity() const noexcept { - return node_or_assert().set_arity; - } - - /** - * @brief Returns the number of arguments of a data member's getter. - * @return The number of arguments accepted by the data member's getter. - */ - [[nodiscard]] size_type get_arity() const noexcept { - return node_or_assert().get_arity; - } - - /** - * @brief Indicates whether a data member is constant or not. - * @return True if the data member is constant, false otherwise. - */ - [[nodiscard]] bool is_const() const noexcept { - return !!(node_or_assert().traits & internal::meta_traits::is_const); - } - - /** - * @brief Indicates whether a data member is static or not. - * @return True if the data member is static, false otherwise. - */ - [[nodiscard]] bool is_static() const noexcept { - return !!(node_or_assert().traits & internal::meta_traits::is_static); - } - - /*! @copydoc meta_any::type */ - [[nodiscard]] inline meta_type type() const noexcept; - - /** - * @brief Sets the value of a given variable. - * @tparam Instance Type of instance to operate on. - * @param instance An instance that fits the underlying type. - * @param args Parameters to use to set the underlying variable. - * @return True in case of success, false otherwise. - */ - template - // NOLINTNEXTLINE(modernize-use-nodiscard) - bool set(Instance &&instance, auto &&...args) const { - return (sizeof...(args) >= set_arity()) && node_or_assert().set(meta_handle{*ctx, stl::forward(instance)}, stl::array{meta_any{*ctx, stl::forward(args)}...}.data()); - } - - /** - * @brief Gets the value of a given variable. - * @tparam Instance Type of instance to operate on. - * @param instance An instance that fits the underlying type. - * @param args Parameters to use to get the underlying variable, if any. - * @return A wrapper containing the value of the underlying variable. - */ - template - [[nodiscard]] meta_any get(Instance &&instance, auto &&...args) const { - return (sizeof...(args) >= get_arity()) ? node_or_assert().get(meta_handle{*ctx, stl::forward(instance)}, stl::array{meta_any{*ctx, stl::forward(args)}...}.data()) : meta_any{meta_ctx_arg, *ctx}; - } - - /** - * @brief Returns the type of the i-th argument of a data member's setter. - * @param index Index of the argument of which to return the type. - * @return The type of the i-th argument of a data member's setter. - */ - [[nodiscard]] inline meta_type set_arg(size_type index) const noexcept; - - /** - * @brief Returns the type of the i-th argument of a data member's getter. - * @param index Index of the argument of which to return the type. - * @return The type of the i-th argument of a data member's getter. - */ - [[nodiscard]] inline meta_type get_arg(size_type index) const noexcept; - - /** - * @brief Returns all meta traits for a given meta object. - * @tparam Type The type to convert the meta traits to. - * @return The registered meta traits, if any. - */ - template - [[nodiscard]] Type traits() const noexcept { - return internal::meta_to_user_traits(node_or_assert().traits); - } - - /** - * @brief Returns user defined data for a given meta object. - * @return User defined arbitrary data. - */ - [[nodiscard]] meta_custom custom() const noexcept { - return {node_or_assert().custom}; - } -}; - -/*! @brief Opaque wrapper for member functions. */ -struct meta_func: meta_object { - using meta_object::meta_object; - - /** - * @brief Returns the name assigned to a member function, if any. - * @return The name assigned to the member function, if any. - */ - [[nodiscard]] stl::string_view name() const noexcept { - return (node_or_assert().name == nullptr) ? stl::string_view{} : stl::string_view{node_or_assert().name}; - } - - /** - * @brief Returns the number of arguments accepted by a member function. - * @return The number of arguments accepted by the member function. - */ - [[nodiscard]] size_type arity() const noexcept { - return node_or_assert().arity; - } - - /** - * @brief Indicates whether a member function is constant or not. - * @return True if the member function is constant, false otherwise. - */ - [[nodiscard]] bool is_const() const noexcept { - return !!(node_or_assert().traits & internal::meta_traits::is_const); - } - - /** - * @brief Indicates whether a member function is static or not. - * @return True if the member function is static, false otherwise. - */ - [[nodiscard]] bool is_static() const noexcept { - return !!(node_or_assert().traits & internal::meta_traits::is_static); - } - - /** - * @brief Returns the return type of a member function. - * @return The return type of the member function. - */ - [[nodiscard]] inline meta_type ret() const noexcept; - - /** - * @brief Returns the type of the i-th argument of a member function. - * @param index Index of the argument of which to return the type. - * @return The type of the i-th argument of a member function. - */ - [[nodiscard]] inline meta_type arg(size_type index) const noexcept; - - /** - * @brief Invokes the underlying function, if possible. - * @tparam Instance Type of instance to operate on. - * @param instance An instance that fits the underlying type. - * @param args Parameters to use to invoke the function. - * @return A wrapper containing the returned value, if any. - */ - template - // NOLINTNEXTLINE(modernize-use-nodiscard) - meta_any invoke(Instance &&instance, auto &&...args) const { - return (sizeof...(args) == arity()) ? node_or_assert().invoke(meta_handle{*ctx, stl::forward(instance)}, stl::array{meta_any{*ctx, stl::forward(args)}...}.data()) : meta_any{meta_ctx_arg, *ctx}; - } - - /*! @copydoc meta_data::traits */ - template - [[nodiscard]] Type traits() const noexcept { - return internal::meta_to_user_traits(node_or_assert().traits); - } - - /*! @copydoc meta_data::custom */ - [[nodiscard]] meta_custom custom() const noexcept { - return {node_or_assert().custom}; - } - - /** - * @brief Returns the next overload of a given function, if any. - * @return The next overload of the given function, if any. - */ - [[nodiscard]] meta_func next() const { - return (node_or_assert().next != nullptr) ? meta_func{*ctx, *node_or_assert().next} : meta_func{}; - } -}; - -/*! @brief Opaque wrapper for base types. */ -struct meta_base: meta_object { - using meta_object::meta_object; - - /*! @copydoc meta_any::type */ - [[nodiscard]] inline meta_type type() const noexcept; -}; - -/*! @brief Opaque wrapper for types. */ -class meta_type { - friend class meta_any; - - [[nodiscard]] const auto &fetch_node() const { - return (node == nullptr) ? internal::resolve(internal::meta_context::from(*ctx)) : *node; - } - - [[nodiscard]] auto lookup(meta_handle *const args, const auto sz, [[maybe_unused]] bool constness, auto next) const { - decltype(next()) candidate = nullptr; - size_type same{}; - bool ambiguous{}; - - for(auto curr = next(); curr; curr = next()) { - if constexpr(stl::is_same_v, internal::meta_func_node>) { - if(constness && !(curr->traits & internal::meta_traits::is_const)) { - continue; - } - } - - if(curr->arity == sz) { - size_type match{}; - size_type pos{}; - - // NOLINTBEGIN(cppcoreguidelines-pro-bounds-pointer-arithmetic) - waiting for C++20 (and stl::span) - for(; pos < sz; ++pos) { - const auto other = curr->arg(*ctx, pos); - const auto type = args[pos]->type(); - - if(const auto &info = other.info(); info == type.info()) { - ++match; - } else if(!(type.fetch_node().conversion_helper && other.fetch_node().conversion_helper) && !(type.fetch_node().details && (internal::find_member(type.fetch_node().details->base, info.hash()) || internal::find_member(type.fetch_node().details->conv, info.hash())))) { - break; - } - } - // NOLINTEND(cppcoreguidelines-pro-bounds-pointer-arithmetic) - - if(pos == sz) { - if(!candidate || match > same) { - candidate = curr; - same = match; - ambiguous = false; - } else if(match == same) { - if constexpr(stl::is_same_v, internal::meta_func_node>) { - if(!!(curr->traits & internal::meta_traits::is_const) != !!(candidate->traits & internal::meta_traits::is_const)) { - candidate = !!(candidate->traits & internal::meta_traits::is_const) ? curr : candidate; - ambiguous = false; - continue; - } - } - - ambiguous = true; - } - } - } - } - - return ambiguous ? nullptr : candidate; - } - -public: - /*! @brief Unsigned integer type. */ - using size_type = internal::meta_type_node::size_type; - - /*! @brief Default constructor. */ - meta_type() noexcept = default; - - /** - * @brief Context aware constructor for meta objects. - * @param area The context from which to search for meta types. - * @param curr The underlying node with which to construct the instance. - */ - meta_type(const meta_ctx &area, const internal::meta_type_node &curr) noexcept - : node{&curr}, - ctx{&area} {} - - /** - * @brief Returns the type info object of the underlying type. - * @return The type info object of the underlying type. - */ - [[nodiscard]] const type_info &info() const noexcept { - return *fetch_node().info; - } - - /** - * @brief Returns the alias assigned to a type. - * @return The alias assigned to the type. - */ - [[nodiscard]] id_type alias() const noexcept { - return fetch_node().alias; - } - - /** - * @brief Returns the name assigned to a type, if any. - * @return The name assigned to the type, if any. - */ - [[nodiscard]] stl::string_view name() const noexcept { - return (fetch_node().name == nullptr) ? stl::string_view{} : stl::string_view{fetch_node().name}; - } - - /** - * @brief Returns the size of the underlying type if known. - * @return The size of the underlying type if known, 0 otherwise. - */ - [[nodiscard]] size_type size_of() const noexcept { - return fetch_node().size_of; - } - - /** - * @brief Checks whether a type refers to an arithmetic type or not. - * @return True if the underlying type is an arithmetic type, false - * otherwise. - */ - [[nodiscard]] bool is_arithmetic() const noexcept { - return !!(fetch_node().traits & internal::meta_traits::is_arithmetic); - } - - /** - * @brief Checks whether a type refers to an integral type or not. - * @return True if the underlying type is an integral type, false otherwise. - */ - [[nodiscard]] bool is_integral() const noexcept { - return !!(fetch_node().traits & internal::meta_traits::is_integral); - } - - /** - * @brief Checks whether a type refers to a signed type or not. - * @return True if the underlying type is a signed type, false otherwise. - */ - [[nodiscard]] bool is_signed() const noexcept { - return !!(fetch_node().traits & internal::meta_traits::is_signed); - } - - /** - * @brief Checks whether a type refers to an array type or not. - * @return True if the underlying type is an array type, false otherwise. - */ - [[nodiscard]] bool is_array() const noexcept { - return !!(fetch_node().traits & internal::meta_traits::is_array); - } - - /** - * @brief Checks whether a type refers to an enum or not. - * @return True if the underlying type is an enum, false otherwise. - */ - [[nodiscard]] bool is_enum() const noexcept { - return !!(fetch_node().traits & internal::meta_traits::is_enum); - } - - /** - * @brief Checks whether a type refers to a class or not. - * @return True if the underlying type is a class, false otherwise. - */ - [[nodiscard]] bool is_class() const noexcept { - return !!(fetch_node().traits & internal::meta_traits::is_class); - } - - /** - * @brief Checks whether a type refers to a pointer or not. - * @return True if the underlying type is a pointer, false otherwise. - */ - [[nodiscard]] bool is_pointer() const noexcept { - return !!(fetch_node().traits & internal::meta_traits::is_pointer); - } - - /** - * @brief Provides the type for which the pointer is defined. - * @return The type for which the pointer is defined or this type if it - * doesn't refer to a pointer type. - */ - [[nodiscard]] meta_type remove_pointer() const noexcept { - return meta_type{*ctx, fetch_node().remove_pointer(internal::meta_context::from(*ctx))}; - } - - /** - * @brief Checks whether a type is a pointer-like type or not. - * @return True if the underlying type is pointer-like, false otherwise. - */ - [[nodiscard]] bool is_pointer_like() const noexcept { - return !!(fetch_node().traits & internal::meta_traits::is_pointer_like); - } - - /** - * @brief Checks whether a type refers to a sequence container or not. - * @return True if the type is a sequence container, false otherwise. - */ - [[nodiscard]] bool is_sequence_container() const noexcept { - return !!(fetch_node().traits & internal::meta_traits::is_sequence_container); - } - - /** - * @brief Checks whether a type refers to an associative container or not. - * @return True if the type is an associative container, false otherwise. - */ - [[nodiscard]] bool is_associative_container() const noexcept { - return !!(fetch_node().traits & internal::meta_traits::is_associative_container); - } - - /** - * @brief Checks whether a type refers to a template specialization or not. - * @return True if the type is a template specialization, false otherwise. - */ - [[nodiscard]] bool is_template_specialization() const noexcept { - return (fetch_node().templ.arity != 0u); - } - - /** - * @brief Returns the number of template arguments. - * @return The number of template arguments. - */ - [[nodiscard]] size_type template_arity() const noexcept { - return fetch_node().templ.arity; - } - - /** - * @brief Returns a tag for the class template of the underlying type. - * @return The tag for the class template of the underlying type. - */ - [[nodiscard]] meta_type template_type() const noexcept { - return (fetch_node().templ.resolve != nullptr) ? meta_type{*ctx, fetch_node().templ.resolve(internal::meta_context::from(*ctx))} : meta_type{}; - } - - /** - * @brief Returns the type of the i-th template argument of a type. - * @param index Index of the template argument of which to return the type. - * @return The type of the i-th template argument of a type. - */ - [[nodiscard]] meta_type template_arg(const size_type index) const noexcept { - return index < template_arity() ? meta_type{*ctx, fetch_node().templ.arg(internal::meta_context::from(*ctx), index)} : meta_type{}; - } - - /** - * @brief Checks if a type supports direct casting to another type. - * @param other The meta type to test for. - * @return True if direct casting is allowed, false otherwise. - */ - [[nodiscard]] bool can_cast(const meta_type &other) const noexcept { - // casting this is UB in all cases but we aren't going to use the resulting pointer, so... - return other && ((*this == other) || (internal::try_cast(internal::meta_context::from(*ctx), fetch_node(), other.fetch_node().info->hash(), this) != nullptr)); - } - - /** - * @brief Checks whether a type supports conversion to another type. - * @param other The meta type to test for. - * @return True if the conversion is allowed, false otherwise. - */ - [[nodiscard]] bool can_convert(const meta_type &other) const noexcept { - if(const auto &to = other.info().hash(); (info().hash() == to) || ((fetch_node().conversion_helper != nullptr) && (other.is_arithmetic() || other.is_enum()))) { - return true; - } else if(const auto &from = fetch_node(); from.details) { - if(const auto *elem = internal::find_member(from.details->conv, to); elem != nullptr) { - return true; - } - - for(auto &&curr: from.details->base) { - if(curr.id == to || meta_type{*ctx, curr.type(internal::meta_context::from(*ctx))}.can_convert(other)) { - return true; - } - } - } - - return false; - } - - /** - * @brief Returns a range to visit registered top-level base meta types. - * @return An iterable range to visit registered top-level base meta types. - */ - [[nodiscard]] meta_range base() const noexcept { - using range_type = meta_range; - return fetch_node().details ? range_type{{*ctx, fetch_node().details->base.cbegin()}, {*ctx, fetch_node().details->base.cend()}} : range_type{}; - } - - /** - * @brief Returns a range to visit registered top-level meta data. - * @return An iterable range to visit registered top-level meta data. - */ - [[nodiscard]] meta_range data() const noexcept { - using range_type = meta_range; - return fetch_node().details ? range_type{{*ctx, fetch_node().details->data.cbegin()}, {*ctx, fetch_node().details->data.cend()}} : range_type{}; - } - - /** - * @brief Lookup utility for meta data (bases are also visited). - * @param id Unique identifier. - * @param recursive True for a search in the base classes, false otherwise. - * @return The registered meta data for the given identifier, if any. - */ - [[nodiscard]] meta_data data(const id_type id, const bool recursive = true) const { - const auto *elem = internal::look_for<&internal::meta_type_descriptor::data>(internal::meta_context::from(*ctx), fetch_node(), id, recursive); - return (elem != nullptr) ? meta_data{*ctx, *elem} : meta_data{}; - } - - /** - * @brief Returns a range to visit registered top-level functions. - * @return An iterable range to visit registered top-level functions. - */ - [[nodiscard]] meta_range func() const noexcept { - using return_type = meta_range; - return fetch_node().details ? return_type{{*ctx, fetch_node().details->func.cbegin()}, {*ctx, fetch_node().details->func.cend()}} : return_type{}; - } - - /** - * @brief Lookup utility for meta functions (bases are also visited). - * @param id Unique identifier. - * @param recursive True for a search in the base classes, false otherwise. - * @return The registered meta function for the given identifier, if any. - */ - [[nodiscard]] meta_func func(const id_type id, const bool recursive = true) const { - const auto *elem = internal::look_for<&internal::meta_type_descriptor::func>(internal::meta_context::from(*ctx), fetch_node(), id, recursive); - return (elem != nullptr) ? meta_func{*ctx, *elem} : meta_func{}; - } - - /** - * @copybrief construct - * @param args Parameters to use to construct the instance. - * @return A wrapper containing the new instance, if any. - */ - [[nodiscard]] meta_any construct(auto &&...args) const { - if(const auto &ref = fetch_node(); ref.details) { - if(const auto *candidate = lookup(stl::array{meta_handle{*ctx, args}...}.data(), sizeof...(args), false, [first = ref.details->ctor.cbegin(), last = ref.details->ctor.cend()]() mutable { return first == last ? nullptr : &*(first++); }); candidate) { - return candidate->invoke(*ctx, stl::array{meta_any{*ctx, stl::forward(args)}...}.data()); - } - } - - if(const auto &ref = fetch_node(); (sizeof...(args) == 0u) && (ref.default_constructor != nullptr)) { - return ref.default_constructor(*ctx); - } - - return meta_any{meta_ctx_arg, *ctx}; - } - - /** - * @brief Wraps an opaque element of the underlying type. - * @param elem A valid pointer to an element of the underlying type. - * @param transfer_ownership True to transfer ownership, false otherwise. - * @return A wrapper that references the given instance. - */ - [[nodiscard]] meta_any from_void(void *elem, bool transfer_ownership = false) const { - return ((elem != nullptr) && (fetch_node().from_void != nullptr)) ? fetch_node().from_void(*ctx, elem, transfer_ownership ? elem : nullptr) : meta_any{meta_ctx_arg, *ctx}; - } - - /** - * @brief Wraps an opaque element of the underlying type. - * @param elem A valid pointer to an element of the underlying type. - * @return A wrapper that references the given instance. - */ - [[nodiscard]] meta_any from_void(const void *elem) const { - return ((elem != nullptr) && (fetch_node().from_void != nullptr)) ? fetch_node().from_void(*ctx, nullptr, elem) : meta_any{meta_ctx_arg, *ctx}; - } - - /** - * @copybrief invoke - * @param id Unique identifier. - * @tparam Instance Type of instance to operate on. - * @param instance An instance that fits the underlying type. - * @param args Parameters to use to invoke the function. - * @return A wrapper containing the returned value, if any. - */ - template - // NOLINTNEXTLINE(modernize-use-nodiscard) - meta_any invoke(const id_type id, Instance &&instance, auto &&...args) const { - meta_handle wrapped{*ctx, stl::forward(instance)}; - - if(const auto &ref = fetch_node(); ref.details) { - if(auto *elem = internal::find_member(ref.details->func, id); elem != nullptr) { - if(const auto *candidate = lookup(stl::array{meta_handle{*ctx, args}...}.data(), sizeof...(args), (wrapped->base().policy() == any_policy::cref), [curr = elem]() mutable { return (curr != nullptr) ? stl::exchange(curr, curr->next.get()) : nullptr; }); candidate) { - return candidate->invoke(stl::move(wrapped), stl::array{meta_any{*ctx, stl::forward(args)}...}.data()); - } - } - } - - for(auto &&curr: base()) { - if(auto elem = curr.second.type().invoke(id, *wrapped.operator->(), stl::forward(args)...); elem) { - return elem; - } - } - - return meta_any{meta_ctx_arg, *ctx}; - } - - /** - * @brief Sets the value of a given variable. - * @tparam Instance Type of instance to operate on. - * @param id Unique identifier. - * @param instance An instance that fits the underlying type. - * @param args Parameters to use to set the underlying variable. - * @return True in case of success, false otherwise. - */ - template - // NOLINTNEXTLINE(modernize-use-nodiscard) - bool set(const id_type id, Instance &&instance, auto &&...args) const { - const auto candidate = data(id); - return candidate && candidate.set(stl::forward(instance), stl::forward(args)...); - } - - /** - * @brief Gets the value of a given variable. - * @tparam Instance Type of instance to operate on. - * @param id Unique identifier. - * @param instance An instance that fits the underlying type. - * @param args Parameters to use to set the underlying variable, if any. - * @return A wrapper containing the value of the underlying variable. - */ - template - [[nodiscard]] meta_any get(const id_type id, Instance &&instance, auto &&...args) const { - const auto candidate = data(id); - return candidate ? candidate.get(stl::forward(instance), stl::forward(args)...) : meta_any{meta_ctx_arg, *ctx}; - } - - /*! @copydoc meta_data::traits */ - template - [[nodiscard]] Type traits() const noexcept { - return internal::meta_to_user_traits(fetch_node().traits); - } - - /*! @copydoc meta_data::custom */ - [[nodiscard]] meta_custom custom() const noexcept { - return fetch_node().custom; - } - - /*! @copydoc meta_data::operator bool */ - [[nodiscard]] explicit operator bool() const noexcept { - return (node != nullptr); - } - - /*! @copydoc meta_data::operator== */ - [[nodiscard]] bool operator==(const meta_type &other) const noexcept { - return (ctx == other.ctx) && (fetch_node().alias == other.fetch_node().alias); - } - -private: - mutable const internal::meta_type_node *node{}; - const meta_ctx *ctx{&locator::value_or()}; -}; - -[[nodiscard]] inline meta_type meta_any::type() const noexcept { - return *this ? meta_type{*ctx, fetch_node()} : meta_type{}; -} - -inline void meta_any::type(const meta_type &alias) noexcept { - ENTT_ASSERT(storage.info() == alias.info(), "Unexpected type"); - node = alias.node; - ctx = alias.ctx; -} - -// NOLINTNEXTLINE(modernize-use-nodiscard) -meta_any meta_any::invoke(const id_type id, auto &&...args) const { - return type().invoke(id, *this, stl::forward(args)...); -} - -meta_any meta_any::invoke(const id_type id, auto &&...args) { - return type().invoke(id, *this, stl::forward(args)...); -} - -bool meta_any::set(const id_type id, auto &&...args) { - return type().set(id, *this, stl::forward(args)...); -} - -[[nodiscard]] inline meta_any meta_any::get(const id_type id, auto &&...args) const { - return type().get(id, *this, stl::forward(args)...); -} - -[[nodiscard]] inline meta_any meta_any::get(const id_type id, auto &&...args) { - return type().get(id, *this, stl::forward(args)...); -} - -[[nodiscard]] inline meta_any meta_any::allow_cast(const meta_type &type) const { - if(storage.has_value(type.info())) { - return as_ref(); - } else if(*this) { - if(const auto &from = fetch_node(); (from.conversion_helper != nullptr) && (type.is_arithmetic() || type.is_enum())) { - auto other = type.construct(); - const auto value = from.conversion_helper(nullptr, storage.data()); - other.fetch_node().conversion_helper(other.storage.data(), &value); - return other; - } - - if(const auto &from = fetch_node(); from.details) { - if(const auto *elem = internal::find_member(from.details->conv, type.info().hash()); elem != nullptr) { - return elem->conv(*ctx, storage.data()); - } - - for(auto &&curr: from.details->base) { - if(auto other = curr.type(internal::meta_context::from(*ctx)).from_void(*ctx, nullptr, curr.cast(storage.data())); curr.id == type.info().hash()) { - return other; - } else if(auto from_base = stl::as_const(other).allow_cast(type); from_base) { - return from_base; - } - } - } - } - - return meta_any{meta_ctx_arg, *ctx}; -} - -[[nodiscard]] inline bool meta_any::allow_cast(const meta_type &type) { - if(storage.has_value(type.info())) { - return true; - } else if(auto other = stl::as_const(*this).allow_cast(type); other) { - if(other.storage.owner()) { - stl::swap(*this, other); - } - - return true; - } - - return false; -} - -inline bool meta_any::assign(const meta_any &other) { - if(!storage.assign(other.storage)) { - auto value = other.allow_cast(type()); - return storage.assign(value.storage); - } - - return true; -} - -inline bool meta_any::assign(meta_any &&other) { - return storage.assign(stl::move(other.storage)) || storage.assign(stl::as_const(other).allow_cast(type()).storage); -} - -[[nodiscard]] inline meta_type meta_data::type() const noexcept { - return meta_type{*ctx, node_or_assert().type(internal::meta_context::from(*ctx))}; -} - -[[nodiscard]] inline meta_type meta_data::set_arg(const size_type index) const noexcept { - return index < set_arity() ? node_or_assert().set_arg(*ctx, index) : meta_type{}; -} - -[[nodiscard]] inline meta_type meta_data::get_arg(const size_type index) const noexcept { - return index < get_arity() ? node_or_assert().get_arg(*ctx, index) : meta_type{}; -} - -[[nodiscard]] inline meta_type meta_func::ret() const noexcept { - return meta_type{*ctx, node_or_assert().ret(internal::meta_context::from(*ctx))}; -} - -[[nodiscard]] inline meta_type meta_func::arg(const size_type index) const noexcept { - return index < arity() ? node_or_assert().arg(*ctx, index) : meta_type{}; -} - -[[nodiscard]] inline meta_type meta_base::type() const noexcept { - return meta_type{*ctx, node_or_assert().type(internal::meta_context::from(*ctx))}; -} - -/*! @cond ENTT_INTERNAL */ -class meta_sequence_container::meta_iterator final { - using vtable_type = void(const void *, const stl::ptrdiff_t, meta_any *); - - template - static void basic_vtable(const void *value, const stl::ptrdiff_t offset, meta_any *other) { - const auto &it = *static_cast(value); - other ? other->emplace(*it) : stl::advance(const_cast(it), offset); - } - -public: - using value_type = meta_any; - using pointer = input_iterator_pointer; - using reference = value_type; - using difference_type = stl::ptrdiff_t; - using iterator_category = stl::input_iterator_tag; - using iterator_concept = stl::bidirectional_iterator_tag; - - meta_iterator() = default; - - meta_iterator(const meta_ctx &area, stl::bidirectional_iterator auto iter) noexcept - : ctx{&area}, - vtable{&basic_vtable}, - handle{iter} {} - - meta_iterator &operator++() noexcept { - return vtable(handle.data(), 1, nullptr), *this; - } - - meta_iterator operator++(int value) noexcept { - meta_iterator orig = *this; - vtable(handle.data(), ++value, nullptr); - return orig; - } - - meta_iterator &operator--() noexcept { - return vtable(handle.data(), -1, nullptr), *this; - } - - meta_iterator operator--(int value) noexcept { - meta_iterator orig = *this; - vtable(handle.data(), --value, nullptr); - return orig; - } - - [[nodiscard]] reference operator*() const { - reference other{meta_ctx_arg, *ctx}; - vtable(handle.data(), 0, &other); - return other; - } - - [[nodiscard]] pointer operator->() const { - return operator*(); - } - - [[nodiscard]] explicit operator bool() const noexcept { - return (vtable != nullptr); - } - - [[nodiscard]] bool operator==(const meta_iterator &other) const noexcept { - return handle == other.handle; - } - - [[nodiscard]] const any &base() const noexcept { - return handle; - } - -private: - const meta_ctx *ctx{}; - vtable_type *vtable{}; - any handle{}; -}; - -class meta_associative_container::meta_iterator final { - using vtable_type = void(const void *, stl::pair *); - - template - static void basic_vtable(const void *value, stl::pair *other) { - if(const auto &it = *static_cast(value); other) { - if constexpr(KeyOnly) { - other->first.emplace(*it); - } else { - other->first.emplacefirst))>(it->first); - other->second.emplacesecond))>(it->second); - } - } else { - ++const_cast(it); - } - } - -public: - using value_type = stl::pair; - using pointer = input_iterator_pointer; - using reference = value_type; - using difference_type = stl::ptrdiff_t; - using iterator_category = stl::input_iterator_tag; - using iterator_concept = stl::forward_iterator_tag; - - meta_iterator() = default; - - template - meta_iterator(const meta_ctx &area, stl::bool_constant, stl::forward_iterator auto iter) noexcept - : ctx{&area}, - vtable{&basic_vtable}, - handle{iter} {} - - meta_iterator &operator++() noexcept { - return vtable(handle.data(), nullptr), *this; - } - - meta_iterator operator++(int) noexcept { - meta_iterator orig = *this; - vtable(handle.data(), nullptr); - return orig; - } - - [[nodiscard]] reference operator*() const { - reference other{{meta_ctx_arg, *ctx}, {meta_ctx_arg, *ctx}}; - vtable(handle.data(), &other); - return other; - } - - [[nodiscard]] pointer operator->() const { - return operator*(); - } - - [[nodiscard]] explicit operator bool() const noexcept { - return (vtable != nullptr); - } - - [[nodiscard]] bool operator==(const meta_iterator &other) const noexcept { - return handle == other.handle; - } - -private: - const meta_ctx *ctx{}; - vtable_type *vtable{}; - any handle{}; -}; - -/*! @endcond */ - -/** - * @brief Returns the meta value type of a container. - * @return The meta value type of the container. - */ -[[nodiscard]] inline meta_type meta_sequence_container::value_type() const noexcept { - return (value_type_node != nullptr) ? meta_type{*ctx, value_type_node(internal::meta_context::from(*ctx))} : meta_type{}; -} - -/** - * @brief Returns the size of a container. - * @return The size of the container. - */ -[[nodiscard]] inline meta_sequence_container::size_type meta_sequence_container::size() const noexcept { - return size_fn(data); -} - -/** - * @brief Resizes a container to contain a given number of elements. - * @param sz The new size of the container. - * @return True in case of success, false otherwise. - */ -inline bool meta_sequence_container::resize(const size_type sz) { - return !const_only && resize_fn(const_cast(data), sz); -} - -/** - * @brief Clears the content of a container. - * @return True in case of success, false otherwise. - */ -inline bool meta_sequence_container::clear() { - return !const_only && clear_fn(const_cast(data)); -} - -/** - * @brief Reserves storage for at least the given number of elements. - * @param sz The new capacity of the container. - * @return True in case of success, false otherwise. - */ -inline bool meta_sequence_container::reserve(const size_type sz) { - return !const_only && reserve_fn(const_cast(data), sz); -} - -/** - * @brief Returns an iterator to the first element of a container. - * @return An iterator to the first element of the container. - */ -[[nodiscard]] inline meta_sequence_container::iterator meta_sequence_container::begin() { - return begin_end_fn(*ctx, const_only ? nullptr : const_cast(data), data, false); -} - -/** - * @brief Returns an iterator that is past the last element of a container. - * @return An iterator that is past the last element of the container. - */ -[[nodiscard]] inline meta_sequence_container::iterator meta_sequence_container::end() { - return begin_end_fn(*ctx, const_only ? nullptr : const_cast(data), data, true); -} - -/** - * @brief Inserts an element at a specified location of a container. - * @param it Iterator before which the element will be inserted. - * @param value Element value to insert. - * @return A possibly invalid iterator to the inserted element. - */ -inline meta_sequence_container::iterator meta_sequence_container::insert(const iterator &it, meta_any value) { - // this abomination is necessary because only on macos value_type and const_reference are different types for stl::vector - if(const auto &vtype = value_type_node(internal::meta_context::from(*ctx)); !const_only && (value.allow_cast({*ctx, vtype}) || value.allow_cast({*ctx, const_reference_node(internal::meta_context::from(*ctx))}))) { - const bool is_value_type = (value.type().info() == *vtype.info); - return insert_fn(*ctx, const_cast(data), is_value_type ? value.base().data() : nullptr, is_value_type ? nullptr : value.base().data(), it); - } - - return iterator{}; -} - -/** - * @brief Removes a given element from a container. - * @param it Iterator to the element to remove. - * @return A possibly invalid iterator following the last removed element. - */ -inline meta_sequence_container::iterator meta_sequence_container::erase(const iterator &it) { - return const_only ? iterator{} : erase_fn(*ctx, const_cast(data), it); -} - -/** - * @brief Returns a reference to the element at a given location of a container. - * @param pos The position of the element to return. - * @return A reference to the requested element properly wrapped. - */ -[[nodiscard]] inline meta_any meta_sequence_container::operator[](const size_type pos) { - auto it = begin(); - it.operator++(static_cast(pos) - 1); - return *it; -} - -/** - * @brief Returns false if a proxy is invalid, true otherwise. - * @return False if the proxy is invalid, true otherwise. - */ -[[nodiscard]] inline meta_sequence_container::operator bool() const noexcept { - return (data != nullptr); -} - -/** - * @brief Returns the meta key type of a container. - * @return The meta key type of the a container. - */ -[[nodiscard]] inline meta_type meta_associative_container::key_type() const noexcept { - return (key_type_node != nullptr) ? meta_type{*ctx, key_type_node(internal::meta_context::from(*ctx))} : meta_type{}; -} - -/** - * @brief Returns the meta mapped type of a container. - * @return The meta mapped type of the a container. - */ -[[nodiscard]] inline meta_type meta_associative_container::mapped_type() const noexcept { - return (mapped_type_node != nullptr) ? meta_type{*ctx, mapped_type_node(internal::meta_context::from(*ctx))} : meta_type{}; -} - -/*! @copydoc meta_sequence_container::value_type */ -[[nodiscard]] inline meta_type meta_associative_container::value_type() const noexcept { - return (value_type_node != nullptr) ? meta_type{*ctx, value_type_node(internal::meta_context::from(*ctx))} : meta_type{}; -} - -/*! @copydoc meta_sequence_container::size */ -[[nodiscard]] inline meta_associative_container::size_type meta_associative_container::size() const noexcept { - return size_fn(data); -} - -/*! @copydoc meta_sequence_container::clear */ -inline bool meta_associative_container::clear() { - return !const_only && clear_fn(const_cast(data)); -} - -/*! @copydoc meta_sequence_container::reserve */ -inline bool meta_associative_container::reserve(const size_type sz) { - return !const_only && reserve_fn(const_cast(data), sz); -} - -/*! @copydoc meta_sequence_container::begin */ -[[nodiscard]] inline meta_associative_container::iterator meta_associative_container::begin() { - return begin_end_fn(*ctx, const_only ? nullptr : const_cast(data), data, false); -} - -/*! @copydoc meta_sequence_container::end */ -[[nodiscard]] inline meta_associative_container::iterator meta_associative_container::end() { - return begin_end_fn(*ctx, const_only ? nullptr : const_cast(data), data, true); -} - -/** - * @brief Inserts a key-only or key/value element into a container. - * @param key The key of the element to insert. - * @param value The value of the element to insert, if needed. - * @return A bool denoting whether the insertion took place. - */ -inline bool meta_associative_container::insert(meta_any key, meta_any value = {}) { - return !const_only && key.allow_cast(meta_type{*ctx, key_type_node(internal::meta_context::from(*ctx))}) - && ((mapped_type_node == nullptr) || value.allow_cast(meta_type{*ctx, mapped_type_node(internal::meta_context::from(*ctx))})) - && insert_fn(const_cast(data), key.base().data(), value.base().data()); -} - -/** - * @brief Removes the specified element from a container. - * @param key The key of the element to remove. - * @return A bool denoting whether the removal took place. - */ -inline meta_associative_container::size_type meta_associative_container::erase(meta_any key) { - return (!const_only && key.allow_cast(meta_type{*ctx, key_type_node(internal::meta_context::from(*ctx))})) ? erase_fn(const_cast(data), key.base().data()) : 0u; -} - -/** - * @brief Returns an iterator to the element with a given key, if any. - * @param key The key of the element to search. - * @return An iterator to the element with the given key, if any. - */ -[[nodiscard]] inline meta_associative_container::iterator meta_associative_container::find(meta_any key) { - return key.allow_cast(meta_type{*ctx, key_type_node(internal::meta_context::from(*ctx))}) ? find_fn(*ctx, const_only ? nullptr : const_cast(data), data, key.base().data()) : iterator{}; -} - -/** - * @brief Returns false if a proxy is invalid, true otherwise. - * @return False if the proxy is invalid, true otherwise. - */ -[[nodiscard]] inline meta_associative_container::operator bool() const noexcept { - return (data != nullptr); -} - -} // namespace entt - -#endif diff --git a/include/entt/meta/node.hpp b/include/entt/meta/node.hpp deleted file mode 100644 index 8b35546..0000000 --- a/include/entt/meta/node.hpp +++ /dev/null @@ -1,287 +0,0 @@ -#ifndef ENTT_META_NODE_HPP -#define ENTT_META_NODE_HPP - -#include "../config/config.h" -#include "../core/bit.hpp" -#include "../core/concepts.hpp" -#include "../core/enum.hpp" -#include "../core/fwd.hpp" -#include "../core/type_info.hpp" -#include "../core/type_traits.hpp" -#include "../core/utility.hpp" -#include "../stl/array.hpp" -#include "../stl/bit.hpp" -#include "../stl/cstddef.hpp" -#include "../stl/cstdint.hpp" -#include "../stl/memory.hpp" -#include "../stl/type_traits.hpp" -#include "../stl/utility.hpp" -#include "../stl/vector.hpp" -#include "context.hpp" -#include "fwd.hpp" -#include "type_traits.hpp" - -namespace entt { - -/*! @cond ENTT_INTERNAL */ -namespace internal { - -enum class meta_traits : stl::uint32_t { - is_none = 0x0000, - is_const = 0x0001, - is_static = 0x0002, - is_arithmetic = 0x0004, - is_integral = 0x0008, - is_signed = 0x0010, - is_array = 0x0020, - is_enum = 0x0040, - is_class = 0x0080, - is_pointer = 0x0100, - is_pointer_like = 0x0200, - is_sequence_container = 0x0400, - is_associative_container = 0x0800, - _user_defined_traits = 0xFFFF, - _entt_enum_as_bitmask = 0xFFFF -}; - -template -requires stl::is_enum_v -[[nodiscard]] auto meta_to_user_traits(const meta_traits traits) noexcept { - constexpr auto shift = stl::popcount(static_cast>(meta_traits::_user_defined_traits)); - return Type{static_cast>(static_cast>(traits) >> shift)}; -} - -template -requires stl::is_enum_v -[[nodiscard]] auto user_to_meta_traits(const Type value) noexcept { - constexpr auto shift = stl::popcount(static_cast>(meta_traits::_user_defined_traits)); - const auto traits = static_cast>(static_cast>(value)); - ENTT_ASSERT(traits < ((~static_cast>(meta_traits::_user_defined_traits)) >> shift), "Invalid traits"); - return meta_traits{traits << shift}; -} - -struct meta_type_node; - -struct meta_custom_node { - id_type id{}; - stl::shared_ptr value{}; -}; - -struct meta_base_node { - id_type id{}; - const meta_type_node &(*type)(const meta_context &) noexcept {}; - const void *(*cast)(const void *) noexcept {}; -}; - -struct meta_conv_node { - id_type id{}; - meta_any (*conv)(const meta_ctx &, const void *){}; -}; - -struct meta_ctor_node { - using size_type = stl::size_t; - - id_type id{}; - size_type arity{0u}; - meta_type (*arg)(const meta_ctx &, const size_type) noexcept {}; - meta_any (*invoke)(const meta_ctx &, meta_any *const){}; -}; - -struct meta_data_node { - using size_type = stl::size_t; - - id_type id{}; - const char *name{}; - meta_traits traits{meta_traits::is_none}; - size_type set_arity{0u}; - size_type get_arity{0u}; - meta_type (*set_arg)(const meta_ctx &, const size_type) noexcept {}; - meta_type (*get_arg)(const meta_ctx &, const size_type) noexcept {}; - const meta_type_node &(*type)(const meta_context &) noexcept {}; - bool (*set)(meta_handle, meta_any *const){}; - meta_any (*get)(meta_handle, meta_any *const){}; - meta_custom_node custom{}; -}; - -struct meta_func_node { - using size_type = stl::size_t; - - id_type id{}; - const char *name{}; - meta_traits traits{meta_traits::is_none}; - size_type arity{0u}; - const meta_type_node &(*ret)(const meta_context &) noexcept {}; - meta_type (*arg)(const meta_ctx &, const size_type) noexcept {}; - meta_any (*invoke)(meta_handle, meta_any *const){}; - stl::unique_ptr next; - meta_custom_node custom{}; -}; - -struct meta_template_node { - using size_type = stl::size_t; - - size_type arity{0u}; - const meta_type_node &(*resolve)(const meta_context &) noexcept {}; - const meta_type_node &(*arg)(const meta_context &, const size_type) noexcept {}; -}; - -struct meta_type_descriptor { - stl::vector ctor{}; - stl::vector base{}; - stl::vector conv{}; - stl::vector data{}; - stl::vector func{}; -}; - -struct meta_type_node { - using size_type = stl::size_t; - - const type_info *info{}; - id_type alias{}; - const char *name{}; - meta_traits traits{meta_traits::is_none}; - size_type size_of{0u}; - const meta_type_node &(*remove_pointer)(const meta_context &) noexcept {}; - meta_any (*default_constructor)(const meta_ctx &){}; - double (*conversion_helper)(void *, const void *){}; - meta_any (*from_void)(const meta_ctx &, void *, const void *){}; - meta_template_node templ{}; - meta_custom_node custom{}; - stl::unique_ptr details{}; -}; - -template -[[nodiscard]] auto *find_member(Type &from, const Value value) { - for(auto &&elem: from) { - if(elem.id == value) { - return &elem; - } - } - - return static_cast(nullptr); -} - -[[nodiscard]] inline auto *find_overload(meta_func_node *curr, stl::remove_pointer_t *const ref) { - while((curr != nullptr) && (curr->invoke != ref)) { curr = curr->next.get(); } - return curr; -} - -template -[[nodiscard]] auto *look_for(const meta_context &context, const meta_type_node &node, const id_type id, bool recursive) { - using value_type = stl::remove_reference_t*Member))>::value_type; - - if(node.details) { - if(auto *member = find_member((node.details.get()->*Member), id); member != nullptr) { - return member; - } - - if(recursive) { - for(auto &&curr: node.details->base) { - if(auto *elem = look_for(context, curr.type(context), id, recursive); elem) { - return elem; - } - } - } - } - - return static_cast(nullptr); -} - -template -const meta_type_node &resolve(const meta_context &) noexcept; - -template -[[nodiscard]] const meta_type_node &meta_arg_node(const meta_context &context, type_list, const stl::size_t index) noexcept { - using resolve_type = const meta_type_node &(*)(const meta_context &) noexcept; - constexpr stl::array list{&resolve>...}; - ENTT_ASSERT(index < sizeof...(Args), "Out of bounds"); - return list[index](context); -} - -[[nodiscard]] inline const void *try_cast(const meta_context &context, const meta_type_node &from, const id_type to, const void *instance) noexcept { - if(from.details) { - for(auto &&curr: from.details->base) { - if(const void *other = curr.cast(instance); curr.id == to) { - return other; - } else if(const void *elem = try_cast(context, curr.type(context), to, other); elem) { - return elem; - } - } - } - - return nullptr; -} - -template -auto setup_node_for() noexcept { - meta_type_node node{ - &type_id(), - type_id().hash(), - nullptr, - (stl::is_arithmetic_v ? meta_traits::is_arithmetic : meta_traits::is_none) - | (stl::is_integral_v ? meta_traits::is_integral : meta_traits::is_none) - | (stl::is_signed_v ? meta_traits::is_signed : meta_traits::is_none) - | (stl::is_array_v ? meta_traits::is_array : meta_traits::is_none) - | (stl::is_enum_v ? meta_traits::is_enum : meta_traits::is_none) - | (stl::is_class_v ? meta_traits::is_class : meta_traits::is_none) - | (stl::is_pointer_v ? meta_traits::is_pointer : meta_traits::is_none) - | (is_meta_pointer_like_v ? meta_traits::is_pointer_like : meta_traits::is_none) - | (is_complete_v> ? meta_traits::is_sequence_container : meta_traits::is_none) - | (is_complete_v> ? meta_traits::is_associative_container : meta_traits::is_none), - size_of_v, - &resolve>>}; - - if constexpr(stl::is_default_constructible_v) { - node.default_constructor = +[](const meta_ctx &ctx) { - return meta_any{ctx, stl::in_place_type}; - }; - } - - if constexpr(stl::is_arithmetic_v) { - node.conversion_helper = +[](void *lhs, const void *rhs) { - return lhs ? static_cast(*static_cast(lhs) = static_cast(*static_cast(rhs))) : static_cast(*static_cast(rhs)); - }; - } else if constexpr(stl::is_enum_v) { - node.conversion_helper = +[](void *lhs, const void *rhs) { - return lhs ? static_cast(*static_cast(lhs) = static_cast(static_cast>(*static_cast(rhs)))) : static_cast(*static_cast(rhs)); - }; - } - - if constexpr(!stl::is_void_v && !stl::is_function_v) { - node.from_void = +[](const meta_ctx &ctx, void *elem, const void *celem) { - if(elem && celem) { // ownership construction request - return meta_any{ctx, stl::in_place, static_cast *>(elem)}; - } - - if(elem) { // non-const reference construction request - return meta_any{ctx, stl::in_place_type &>, *static_cast *>(elem)}; - } - - // const reference construction request - return meta_any{ctx, stl::in_place_type &>, *static_cast *>(celem)}; - }; - } - - if constexpr(is_complete_v>) { - node.templ = meta_template_node{ - meta_template_traits::args_type::size, - &resolve::class_type>, - +[](const meta_context &area, const stl::size_t index) noexcept -> decltype(auto) { return meta_arg_node(area, typename meta_template_traits::args_type{}, index); }}; - } - - return node; -} - -template -[[nodiscard]] const meta_type_node &resolve(const meta_context &context) noexcept { - static const meta_type_node node = setup_node_for(); - const auto it = context.bucket.find(node.info->hash()); - return (it == context.bucket.cend()) ? node : *it->second; -} - -} // namespace internal -/*! @endcond */ - -} // namespace entt - -#endif diff --git a/include/entt/meta/pointer.hpp b/include/entt/meta/pointer.hpp deleted file mode 100644 index e347756..0000000 --- a/include/entt/meta/pointer.hpp +++ /dev/null @@ -1,42 +0,0 @@ -// IWYU pragma: always_keep - -#ifndef ENTT_META_POINTER_HPP -#define ENTT_META_POINTER_HPP - -#include "../stl/memory.hpp" -#include "../stl/type_traits.hpp" -#include "type_traits.hpp" - -namespace entt { - -/** - * @brief Makes `stl::shared_ptr`s of any type pointer-like types for the meta - * system. - * @tparam Type Element type. - */ -template -struct is_meta_pointer_like> - : stl::true_type {}; - -/** - * @brief Makes `stl::unique_ptr`s of any type pointer-like types for the meta - * system. - * @tparam Type Element type. - * @tparam Args Other arguments. - */ -template -struct is_meta_pointer_like> - : stl::true_type {}; - -/** - * @brief Specialization for self-proclaimed meta pointer like types. - * @tparam Type Element type. - */ -template -requires requires { typename Type::is_meta_pointer_like; } -struct is_meta_pointer_like - : stl::true_type {}; - -} // namespace entt - -#endif diff --git a/include/entt/meta/policy.hpp b/include/entt/meta/policy.hpp deleted file mode 100644 index be0e3d9..0000000 --- a/include/entt/meta/policy.hpp +++ /dev/null @@ -1,81 +0,0 @@ -#ifndef ENTT_META_POLICY_HPP -#define ENTT_META_POLICY_HPP - -#include "../stl/type_traits.hpp" - -namespace entt { - -/*! @cond ENTT_INTERNAL */ -namespace internal { - -struct meta_policy {}; - -} // namespace internal -/*! @endcond */ - -/*! @brief Empty class type used to request the _as-is_ policy. */ -struct as_value_t final: private internal::meta_policy { - /*! @cond ENTT_INTERNAL */ - template - static constexpr bool value = true; - /*! @endcond */ -}; - -/*! @brief Empty class type used to request the _as void_ policy. */ -struct as_void_t final: private internal::meta_policy { - /*! @cond ENTT_INTERNAL */ - template - static constexpr bool value = true; - /*! @endcond */ -}; - -/*! @brief Empty class type used to request the _as ref_ policy. */ -struct as_ref_t final: private internal::meta_policy { - /*! @cond ENTT_INTERNAL */ - template - static constexpr bool value = stl::is_reference_v && !stl::is_const_v>; - /*! @endcond */ -}; - -/*! @brief Empty class type used to request the _as cref_ policy. */ -struct as_cref_t final: private internal::meta_policy { - /*! @cond ENTT_INTERNAL */ - template - static constexpr bool value = stl::is_reference_v; - /*! @endcond */ -}; - -/*! @brief Empty class type used to request the _as auto_ policy. */ -struct as_is_t final: private internal::meta_policy { - /*! @cond ENTT_INTERNAL */ - template - static constexpr bool value = true; - /*! @endcond */ -}; - -/** - * @brief Provides the member constant `value` equal to true if a type also is a - * meta policy, false otherwise. - * @tparam Type Type to check. - */ -template -struct is_meta_policy - : stl::bool_constant> {}; - -/** - * @brief Helper variable template. - * @tparam Type Type to check. - */ -template -inline constexpr bool is_meta_policy_v = is_meta_policy::value; - -/** - * @brief Specifies whether a type is a meta policy. - * @tparam Type Type to check. - */ -template -concept meta_policy = is_meta_policy_v; - -} // namespace entt - -#endif diff --git a/include/entt/meta/range.hpp b/include/entt/meta/range.hpp deleted file mode 100644 index 2e47d79..0000000 --- a/include/entt/meta/range.hpp +++ /dev/null @@ -1,119 +0,0 @@ -#ifndef ENTT_META_RANGE_HPP -#define ENTT_META_RANGE_HPP - -#include -#include "../core/fwd.hpp" -#include "../core/iterator.hpp" -#include "../stl/concepts.hpp" -#include "../stl/cstddef.hpp" -#include "../stl/iterator.hpp" -#include "../stl/utility.hpp" -#include "context.hpp" - -namespace entt { - -/*! @cond ENTT_INTERNAL */ -namespace internal { - -struct meta_base_node; - -template -struct meta_range_iterator final { - using value_type = stl::pair; - using pointer = input_iterator_pointer; - using reference = value_type; - using difference_type = stl::ptrdiff_t; - using iterator_category = stl::input_iterator_tag; - using iterator_concept = stl::random_access_iterator_tag; - - constexpr meta_range_iterator() noexcept - : it{}, - ctx{} {} - - constexpr meta_range_iterator(const meta_ctx &area, const It iter) noexcept - : it{iter}, - ctx{&area} {} - - constexpr meta_range_iterator &operator++() noexcept { - return ++it, *this; - } - - constexpr meta_range_iterator operator++(int) noexcept { - const meta_range_iterator orig = *this; - return ++(*this), orig; - } - - constexpr meta_range_iterator &operator--() noexcept { - return --it, *this; - } - - constexpr meta_range_iterator operator--(int) noexcept { - const meta_range_iterator orig = *this; - return operator--(), orig; - } - - constexpr meta_range_iterator &operator+=(const difference_type value) noexcept { - it += value; - return *this; - } - - constexpr meta_range_iterator operator+(const difference_type value) const noexcept { - meta_range_iterator copy = *this; - return (copy += value); - } - - constexpr meta_range_iterator &operator-=(const difference_type value) noexcept { - return (*this += -value); - } - - constexpr meta_range_iterator operator-(const difference_type value) const noexcept { - return (*this + -value); - } - - [[nodiscard]] constexpr reference operator[](const difference_type value) const noexcept { - if constexpr(stl::is_same_v) { - return {it[value].first, Type{*ctx, *it[value].second}}; - } else { - return {it[value].id, Type{*ctx, it[value]}}; - } - } - - [[nodiscard]] constexpr pointer operator->() const noexcept { - return operator*(); - } - - [[nodiscard]] constexpr reference operator*() const noexcept { - return operator[](0); - } - - [[nodiscard]] constexpr stl::ptrdiff_t operator-(const meta_range_iterator &other) const noexcept { - return it - other.it; - } - - [[nodiscard]] constexpr bool operator==(const meta_range_iterator &other) const noexcept { - return it == other.it; - } - - [[nodiscard]] constexpr auto operator<=>(const meta_range_iterator &other) const noexcept { - return it <=> other.it; - } - -private: - It it; - const meta_ctx *ctx; -}; - -} // namespace internal -/*! @endcond */ - -/** - * @brief Iterable range to use to iterate all types of meta objects. - * @tparam Type Type of meta objects returned. - * @tparam It Type of forward iterator. - */ -template -using meta_range = iterable_adaptor>; - -} // namespace entt - -#endif diff --git a/include/entt/meta/resolve.hpp b/include/entt/meta/resolve.hpp deleted file mode 100644 index 7f3eb97..0000000 --- a/include/entt/meta/resolve.hpp +++ /dev/null @@ -1,109 +0,0 @@ -#ifndef ENTT_META_RESOLVE_HPP -#define ENTT_META_RESOLVE_HPP - -#include "../core/type_info.hpp" -#include "../locator/locator.hpp" -#include "../stl/type_traits.hpp" -#include "context.hpp" -#include "meta.hpp" -#include "node.hpp" -#include "range.hpp" - -namespace entt { - -/** - * @brief Returns the meta type associated with a given type. - * @tparam Type Type to use to search for a meta type. - * @param ctx The context from which to search for meta types. - * @return The meta type associated with the given type, if any. - */ -template -[[nodiscard]] meta_type resolve(const meta_ctx &ctx) noexcept { - const auto &context = internal::meta_context::from(ctx); - return {ctx, internal::resolve>(context)}; -} - -/** - * @brief Returns the meta type associated with a given type. - * @tparam Type Type to use to search for a meta type. - * @return The meta type associated with the given type, if any. - */ -template -[[nodiscard]] meta_type resolve() noexcept { - return resolve(locator::value_or()); -} - -/** - * @brief Returns a range to use to visit all meta types. - * @param ctx The context from which to search for meta types. - * @return An iterable range to use to visit all meta types. - */ -[[nodiscard]] inline meta_range resolve(const meta_ctx &ctx) noexcept { - const auto &context = internal::meta_context::from(ctx); - return {{ctx, context.bucket.cbegin()}, {ctx, context.bucket.cend()}}; -} - -/** - * @brief Returns a range to use to visit all meta types. - * @return An iterable range to use to visit all meta types. - */ -[[nodiscard]] inline meta_range resolve() noexcept { - return resolve(locator::value_or()); -} - -/** - * @brief Returns the meta type associated with a given identifier, if any. - * @param ctx The context from which to search for meta types. - * @param alias Unique identifier. - * @return The meta type associated with the given identifier, if any. - */ -[[nodiscard]] inline meta_type resolve(const meta_ctx &ctx, const id_type alias) noexcept { - const auto &context = internal::meta_context::from(ctx); - - // fast lookup for unsearchable and overloaded types - if(const auto it = context.bucket.find(alias); it != context.bucket.end()) { - return meta_type{ctx, *it->second}; - } - - for(auto &&curr: context.bucket) { - if(curr.second->alias == alias) { - return meta_type{ctx, *curr.second}; - } - } - - return meta_type{}; -} - -/** - * @brief Returns the meta type associated with a given identifier, if any. - * @param alias Unique identifier. - * @return The meta type associated with the given identifier, if any. - */ -[[nodiscard]] inline meta_type resolve(const id_type alias) noexcept { - return resolve(locator::value_or(), alias); -} - -/** - * @brief Returns the meta type associated with a given type info object. - * @param ctx The context from which to search for meta types. - * @param info The type info object of the requested type. - * @return The meta type associated with the given type info object, if any. - */ -[[nodiscard]] inline meta_type resolve(const meta_ctx &ctx, const type_info &info) noexcept { - const auto &context = internal::meta_context::from(ctx); - const auto it = context.bucket.find(info.hash()); - return (it == context.bucket.cend()) ? meta_type{} : meta_type{ctx, *it->second}; -} - -/** - * @brief Returns the meta type associated with a given type info object. - * @param info The type info object of the requested type. - * @return The meta type associated with the given type info object, if any. - */ -[[nodiscard]] inline meta_type resolve(const type_info &info) noexcept { - return resolve(locator::value_or(), info); -} - -} // namespace entt - -#endif diff --git a/include/entt/meta/template.hpp b/include/entt/meta/template.hpp deleted file mode 100644 index 5eab2af..0000000 --- a/include/entt/meta/template.hpp +++ /dev/null @@ -1,29 +0,0 @@ -// IWYU pragma: always_keep - -#ifndef ENTT_META_TEMPLATE_HPP -#define ENTT_META_TEMPLATE_HPP - -#include "../core/type_traits.hpp" - -namespace entt { - -/*! @brief Utility class to disambiguate class templates. */ -template class> -struct meta_class_template_tag {}; - -/** - * @brief General purpose traits class for generating meta template information. - * @tparam Clazz Type of class template. - * @tparam Args Types of template arguments. - */ -template class Clazz, typename... Args> -struct meta_template_traits> { - /*! @brief Wrapped class template. */ - using class_type = meta_class_template_tag; - /*! @brief List of template arguments. */ - using args_type = type_list; -}; - -} // namespace entt - -#endif diff --git a/include/entt/meta/type_traits.hpp b/include/entt/meta/type_traits.hpp deleted file mode 100644 index cc271fc..0000000 --- a/include/entt/meta/type_traits.hpp +++ /dev/null @@ -1,54 +0,0 @@ -#ifndef ENTT_META_TYPE_TRAITS_HPP -#define ENTT_META_TYPE_TRAITS_HPP - -#include "../stl/type_traits.hpp" -#include "../stl/utility.hpp" - -namespace entt { - -/** - * @brief Traits class template to be specialized to enable support for meta - * template information. - */ -template -struct meta_template_traits; - -/** - * @brief Traits class template to be specialized to enable support for meta - * sequence containers. - */ -template -struct meta_sequence_container_traits; - -/** - * @brief Traits class template to be specialized to enable support for meta - * associative containers. - */ -template -struct meta_associative_container_traits; - -/** - * @brief Provides the member constant `value` equal to true if a given type is - * a pointer-like type, false otherwise. - */ -template -struct is_meta_pointer_like: stl::false_type {}; - -/** - * @brief Partial specialization to ensure that const pointer-like types are - * also accepted. - * @tparam Type Potentially pointer-like type. - */ -template -struct is_meta_pointer_like: is_meta_pointer_like {}; - -/** - * @brief Helper variable template. - * @tparam Type Potentially pointer-like type. - */ -template -inline constexpr auto is_meta_pointer_like_v = is_meta_pointer_like::value; - -} // namespace entt - -#endif diff --git a/include/entt/meta/utility.hpp b/include/entt/meta/utility.hpp deleted file mode 100644 index ea5b01e..0000000 --- a/include/entt/meta/utility.hpp +++ /dev/null @@ -1,500 +0,0 @@ -#ifndef ENTT_META_UTILITY_HPP -#define ENTT_META_UTILITY_HPP - -#include "../core/type_traits.hpp" -#include "../locator/locator.hpp" -#include "../stl/cstddef.hpp" -#include "../stl/functional.hpp" -#include "../stl/type_traits.hpp" -#include "../stl/utility.hpp" -#include "meta.hpp" -#include "node.hpp" -#include "policy.hpp" - -namespace entt { - -/** - * @brief Meta function descriptor traits. - * @tparam Ret Function return type. - * @tparam Args Function arguments. - * @tparam Static Function staticness. - * @tparam Const Function constness. - */ -template -struct meta_function_descriptor_traits { - /*! @brief Meta function return type. */ - using return_type = Ret; - /*! @brief Meta function arguments. */ - using args_type = Args; - - /*! @brief True if the meta function is static, false otherwise. */ - static constexpr bool is_static = Static; - /*! @brief True if the meta function is const, false otherwise. */ - static constexpr bool is_const = Const; -}; - -/*! @brief Primary template isn't defined on purpose. */ -template -struct meta_function_descriptor; - -/** - * @brief Meta function descriptor. - * @tparam Type Reflected type to which the meta function is associated. - * @tparam Ret Function return type. - * @tparam Class Actual owner of the member function. - * @tparam Args Function arguments. - */ -template -struct meta_function_descriptor - : meta_function_descriptor_traits< - Ret, - stl::conditional_t, type_list, type_list>, - !stl::is_base_of_v, - true> {}; - -/** - * @brief Meta function descriptor. - * @tparam Type Reflected type to which the meta function is associated. - * @tparam Ret Function return type. - * @tparam Class Actual owner of the member function. - * @tparam Args Function arguments. - */ -template -struct meta_function_descriptor - : meta_function_descriptor_traits< - Ret, - stl::conditional_t, type_list, type_list>, - !stl::is_base_of_v, - false> {}; - -/** - * @brief Meta function descriptor. - * @tparam Type Reflected type to which the meta data is associated. - * @tparam Class Actual owner of the data member. - * @tparam Ret Data member type. - */ -template -struct meta_function_descriptor - : meta_function_descriptor_traits< - Ret &, - stl::conditional_t, type_list<>, type_list>, - !stl::is_base_of_v, - false> {}; - -/** - * @brief Meta function descriptor. - * @tparam Type Reflected type to which the meta function is associated. - * @tparam Ret Function return type. - * @tparam MaybeType First function argument. - * @tparam Args Other function arguments. - */ -template -struct meta_function_descriptor - : meta_function_descriptor_traits< - Ret, - stl::conditional_t< - stl::is_same_v, Type> || stl::is_base_of_v, Type>, - type_list, - type_list>, - !(stl::is_same_v, Type> || stl::is_base_of_v, Type>), - stl::is_const_v> && (stl::is_same_v, Type> || stl::is_base_of_v, Type>)> {}; - -/** - * @brief Meta function descriptor. - * @tparam Type Reflected type to which the meta function is associated. - * @tparam Ret Function return type. - */ -template -struct meta_function_descriptor - : meta_function_descriptor_traits< - Ret, - type_list<>, - true, - false> {}; - -/** - * @brief Meta function helper. - * - * Converts a function type to be associated with a reflected type into its meta - * function descriptor. - * - * @tparam Type Reflected type to which the meta function is associated. - * @tparam Candidate The actual function to associate with the reflected type. - */ -template -class meta_function_helper { - template - static meta_function_descriptor get_rid_of_noexcept(Ret (Class::*)(Args...) const); - - template - static meta_function_descriptor get_rid_of_noexcept(Ret (Class::*)(Args...)); - - template - requires stl::is_member_object_pointer_v - static meta_function_descriptor get_rid_of_noexcept(Ret Class::*); - - template - static meta_function_descriptor get_rid_of_noexcept(Ret (*)(Args...)); - - template - static meta_function_descriptor get_rid_of_noexcept(Class); - -public: - /*! @brief The meta function descriptor of the given function. */ - using type = decltype(get_rid_of_noexcept(stl::declval())); -}; - -/** - * @brief Helper type. - * @tparam Type Reflected type to which the meta function is associated. - * @tparam Candidate The actual function to associate with the reflected type. - */ -template -using meta_function_helper_t = meta_function_helper::type; - -/** - * @brief Wraps a value depending on the given policy. - * - * This function always returns a wrapped value in the requested context.
- * Therefore, if the passed value is itself a wrapped object with a different - * context, it undergoes a rebinding to the requested context. - * - * @tparam Policy Optional policy (no policy set by default). - * @tparam Type Type of value to wrap. - * @param ctx The context from which to search for meta types. - * @param value Value to wrap. - * @return A meta any containing the returned value, if any. - */ -template -[[nodiscard]] meta_any meta_dispatch(const meta_ctx &ctx, [[maybe_unused]] Type &&value) { - if constexpr(stl::is_same_v) { - static_assert(stl::is_lvalue_reference_v, "Invalid type"); - return meta_any{ctx, stl::in_place_type &>, stl::as_const(value)}; - } else if constexpr(stl::is_same_v || (stl::is_same_v && stl::is_lvalue_reference_v)) { - return meta_any{ctx, stl::in_place_type, value}; - } else if constexpr(stl::is_same_v) { - return meta_any{ctx, stl::in_place_type}; - } else { - return meta_any{ctx, stl::forward(value)}; - } -} - -/** - * @brief Wraps a value depending on the given policy. - * @tparam Policy Optional policy (no policy set by default). - * @tparam Type Type of value to wrap. - * @param value Value to wrap. - * @return A meta any containing the returned value, if any. - */ -template -[[nodiscard]] meta_any meta_dispatch(Type &&value) { - return meta_dispatch(locator::value_or(), stl::forward(value)); -} - -/*! @cond ENTT_INTERNAL */ -namespace internal { - -template -[[nodiscard]] meta_any meta_invoke_with_args(const meta_ctx &ctx, Candidate &&candidate, Args &&...args) { - if constexpr(stl::is_void_v(candidate), args...))>) { - stl::invoke(stl::forward(candidate), args...); - return meta_any{ctx, stl::in_place_type}; - } else { - return meta_dispatch(ctx, stl::invoke(stl::forward(candidate), args...)); - } -} - -template -[[nodiscard]] meta_any meta_invoke(meta_any &instance, Candidate &&candidate, [[maybe_unused]] meta_any *const args, stl::index_sequence) { - using descriptor = meta_function_helper_t>; - - // NOLINTBEGIN(cppcoreguidelines-pro-bounds-pointer-arithmetic) - waiting for C++20 (and stl::span) - if constexpr(stl::is_invocable_v, const Type &, type_list_element_t...>) { - if(const auto *const clazz = instance.try_cast(); clazz && ((args + Index)->allow_cast>() && ...)) { - return meta_invoke_with_args(instance.context(), stl::forward(candidate), *clazz, (args + Index)->cast>()...); - } - } else if constexpr(stl::is_invocable_v, Type &, type_list_element_t...>) { - if(auto *const clazz = instance.try_cast(); clazz && ((args + Index)->allow_cast>() && ...)) { - return meta_invoke_with_args(instance.context(), stl::forward(candidate), *clazz, (args + Index)->cast>()...); - } - } else { - if(((args + Index)->allow_cast>() && ...)) { - return meta_invoke_with_args(instance.context(), stl::forward(candidate), (args + Index)->cast>()...); - } - } - // NOLINTEND(cppcoreguidelines-pro-bounds-pointer-arithmetic) - - return meta_any{meta_ctx_arg, instance.context()}; -} - -template -[[nodiscard]] meta_any meta_construct(const meta_ctx &ctx, meta_any *const args, stl::index_sequence) { - // NOLINTBEGIN(cppcoreguidelines-pro-bounds-pointer-arithmetic) - waiting for C++20 (and stl::span) - if(((args + Index)->allow_cast() && ...)) { - return meta_any{ctx, stl::in_place_type, (args + Index)->cast()...}; - } - // NOLINTEND(cppcoreguidelines-pro-bounds-pointer-arithmetic) - - return meta_any{meta_ctx_arg, ctx}; -} - -} // namespace internal -/*! @endcond */ - -/** - * @brief Returns the meta type of the i-th element of a list of arguments. - * @tparam Type Type list of the actual types of arguments. - * @param ctx The context from which to search for meta types. - * @param index The index of the element for which to return the meta type. - * @return The meta type of the i-th element of the list of arguments. - */ -template -[[nodiscard]] meta_type meta_arg(const meta_ctx &ctx, const stl::size_t index) noexcept { - const auto &context = internal::meta_context::from(ctx); - return {ctx, internal::meta_arg_node(context, Type{}, index)}; -} - -/** - * @brief Returns the meta type of the i-th element of a list of arguments. - * @tparam Type Type list of the actual types of arguments. - * @param index The index of the element for which to return the meta type. - * @return The meta type of the i-th element of the list of arguments. - */ -template -[[nodiscard]] meta_type meta_arg(const stl::size_t index) noexcept { - return meta_arg(locator::value_or(), index); -} - -/** - * @brief Sets the value of a given variable. - * @tparam Type Reflected type to which the variable is associated. - * @tparam Data The actual variable to set. - * @param instance An opaque instance of the underlying type, if required. - * @param args Parameters to use to set the variable. - * @return True in case of success, false otherwise. - */ -template -[[nodiscard]] bool meta_setter([[maybe_unused]] meta_handle instance, [[maybe_unused]] meta_any *const args) { - if constexpr(stl::is_member_function_pointer_v || stl::is_function_v>>) { - return static_cast(internal::meta_invoke(*instance.operator->(), Data, args, stl::make_index_sequence::args_type::size>{})); - } else if constexpr(stl::is_member_object_pointer_v) { - using data_type = stl::remove_reference_t::return_type>; - - if constexpr(!stl::is_array_v && !stl::is_const_v) { - if(auto *const clazz = instance->try_cast(); clazz && args->allow_cast()) { - stl::invoke(Data, *clazz) = args->cast(); - return true; - } - } - - return false; - } else if constexpr(stl::is_pointer_v) { - using data_type = stl::remove_reference_t; - - if constexpr(!stl::is_array_v && !stl::is_const_v) { - if(args->allow_cast()) { - *Data = args->cast(); - return true; - } - } - - return false; - } else { - return false; - } -} - -/** - * @brief Sets the value of a given variable. - * @tparam Type Reflected type to which the variable is associated. - * @tparam Data The actual variable to set. - * @param instance An opaque instance of the underlying type, if required. - * @param value Parameter to use to set the variable. - * @return True in case of success, false otherwise. - */ -template -[[nodiscard]] bool meta_setter(meta_handle instance, meta_any value) { - return meta_setter(*instance.operator->(), &value); -} - -/** - * @brief Gets the value of a given variable. - * @tparam Type Reflected type to which the variable is associated. - * @tparam Data The actual variable to get. - * @tparam Policy Optional policy (no policy set by default). - * @param instance An opaque instance of the underlying type, if required. - * @param args Parameters to use to set the variable. - * @return A meta any containing the value of the underlying variable. - */ -template -[[nodiscard]] meta_any meta_getter(meta_handle instance, [[maybe_unused]] meta_any *const args) { - if constexpr(stl::is_member_function_pointer_v || stl::is_function_v>>) { - return internal::meta_invoke(*instance.operator->(), Data, args, stl::make_index_sequence::args_type::size>{}); - } else if constexpr(stl::is_member_object_pointer_v) { - if constexpr(!stl::is_array_v>>) { - if(auto *clazz = instance->try_cast(); clazz) { - return meta_dispatch(instance->context(), stl::invoke(Data, *clazz)); - } else if(auto *fallback = instance->try_cast(); fallback) { - return meta_dispatch(instance->context(), stl::invoke(Data, *fallback)); - } - } - - return meta_any{meta_ctx_arg, instance->context()}; - } else if constexpr(stl::is_pointer_v) { - if constexpr(stl::is_array_v>) { - return meta_any{meta_ctx_arg, instance->context()}; - } else { - return meta_dispatch(instance->context(), *Data); - } - } else { - return meta_dispatch(instance->context(), Data); - } -} - -/** - * @brief Gets the value of a given variable. - * @tparam Type Reflected type to which the variable is associated. - * @tparam Data The actual variable to get. - * @tparam Policy Optional policy (no policy set by default). - * @param instance An opaque instance of the underlying type, if required. - * @return A meta any containing the value of the underlying variable. - */ -template -[[nodiscard]] meta_any meta_getter(meta_handle instance) { - return meta_getter(*instance.operator->(), nullptr); -} - -/** - * @brief Tries to _invoke_ an object given a list of erased parameters. - * @tparam Type Reflected type to which the object to _invoke_ is associated. - * @tparam Policy Optional policy (no policy set by default). - * @tparam Candidate The type of the actual object to _invoke_. - * @param instance An opaque instance of the underlying type, if required. - * @param candidate The actual object to _invoke_. - * @param args Parameters to use to _invoke_ the object. - * @return A meta any containing the returned value, if any. - */ -template -[[nodiscard]] meta_any meta_invoke(meta_handle instance, Candidate &&candidate, meta_any *const args) { - return internal::meta_invoke(*instance.operator->(), stl::forward(candidate), args, stl::make_index_sequence>::args_type::size>{}); -} - -/** - * @brief Tries to invoke a function given a list of erased parameters. - * @tparam Type Reflected type to which the function is associated. - * @tparam Candidate The actual function to invoke. - * @tparam Policy Optional policy (no policy set by default). - * @param instance An opaque instance of the underlying type, if required. - * @param args Parameters to use to invoke the function. - * @return A meta any containing the returned value, if any. - */ -template -[[nodiscard]] meta_any meta_invoke(meta_handle instance, meta_any *const args) { - return internal::meta_invoke(*instance.operator->(), Candidate, args, stl::make_index_sequence>::args_type::size>{}); -} - -/** - * @brief Tries to construct an instance given a list of erased parameters. - * - * @warning - * The context provided is used only for the return type.
- * It's up to the caller to bind the arguments to the right context(s). - * - * @tparam Type Actual type of the instance to construct. - * @tparam Args Types of arguments expected. - * @param ctx The context from which to search for meta types. - * @param args Parameters to use to construct the instance. - * @return A meta any containing the new instance, if any. - */ -template -[[nodiscard]] meta_any meta_construct(const meta_ctx &ctx, meta_any *const args) { - return internal::meta_construct(ctx, args, stl::index_sequence_for{}); -} - -/** - * @brief Tries to construct an instance given a list of erased parameters. - * @tparam Type Actual type of the instance to construct. - * @tparam Args Types of arguments expected. - * @param args Parameters to use to construct the instance. - * @return A meta any containing the new instance, if any. - */ -template -[[nodiscard]] meta_any meta_construct(meta_any *const args) { - return meta_construct(locator::value_or(), args); -} - -/** - * @brief Tries to construct an instance given a list of erased parameters. - * - * @warning - * The context provided is used only for the return type.
- * It's up to the caller to bind the arguments to the right context(s). - * - * @tparam Type Reflected type to which the object to _invoke_ is associated. - * @tparam Policy Optional policy (no policy set by default). - * @tparam Candidate The type of the actual object to _invoke_. - * @param ctx The context from which to search for meta types. - * @param candidate The actual object to _invoke_. - * @param args Parameters to use to _invoke_ the object. - * @return A meta any containing the returned value, if any. - */ -template -[[nodiscard]] meta_any meta_construct(const meta_ctx &ctx, Candidate &&candidate, meta_any *const args) { - if constexpr(meta_function_helper_t::is_static || stl::is_class_v>) { - meta_any placeholder{meta_ctx_arg, ctx}; - return internal::meta_invoke(placeholder, stl::forward(candidate), args, stl::make_index_sequence>::args_type::size>{}); - } else { - // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) - waiting for C++20 (and stl::span) - return internal::meta_invoke(*args, stl::forward(candidate), args + 1u, stl::make_index_sequence>::args_type::size>{}); - } -} - -/** - * @brief Tries to construct an instance given a list of erased parameters. - * @tparam Type Reflected type to which the object to _invoke_ is associated. - * @tparam Policy Optional policy (no policy set by default). - * @tparam Candidate The type of the actual object to _invoke_. - * @param candidate The actual object to _invoke_. - * @param args Parameters to use to _invoke_ the object. - * @return A meta any containing the returned value, if any. - */ -template -[[nodiscard]] meta_any meta_construct(Candidate &&candidate, meta_any *const args) { - return meta_construct(locator::value_or(), stl::forward(candidate), args); -} - -/** - * @brief Tries to construct an instance given a list of erased parameters. - * - * @warning - * The context provided is used only for the return type.
- * It's up to the caller to bind the arguments to the right context(s). - * - * @tparam Type Reflected type to which the function is associated. - * @tparam Candidate The actual function to invoke. - * @tparam Policy Optional policy (no policy set by default). - * @param ctx The context from which to search for meta types. - * @param args Parameters to use to invoke the function. - * @return A meta any containing the returned value, if any. - */ -template -[[nodiscard]] meta_any meta_construct(const meta_ctx &ctx, meta_any *const args) { - return meta_construct(ctx, Candidate, args); -} - -/** - * @brief Tries to construct an instance given a list of erased parameters. - * @tparam Type Reflected type to which the function is associated. - * @tparam Candidate The actual function to invoke. - * @tparam Policy Optional policy (no policy set by default). - * @param args Parameters to use to invoke the function. - * @return A meta any containing the returned value, if any. - */ -template -[[nodiscard]] meta_any meta_construct(meta_any *const args) { - return meta_construct(locator::value_or(), args); -} - -} // namespace entt - -#endif diff --git a/include/entt/natvis/config.natvis b/include/entt/natvis/config.natvis deleted file mode 100644 index 6eb47e3..0000000 --- a/include/entt/natvis/config.natvis +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/include/entt/natvis/container.natvis b/include/entt/natvis/container.natvis deleted file mode 100644 index 5bd4ac6..0000000 --- a/include/entt/natvis/container.natvis +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - {{ size={ size() } }} - - packed.first_base::value.capacity() - bucket_count() - (float)size() / (float)bucket_count() - threshold - - size() - packed.first_base::value[$i].element - - - - - - - {{ size={ size() } }} - - packed.first_base::value.capacity() - bucket_count() - (float)size() / (float)bucket_count() - threshold - - size() - packed.first_base::value[$i].second - - - - - { payload } - - payload - - - diff --git a/include/entt/natvis/core.natvis b/include/entt/natvis/core.natvis deleted file mode 100644 index 1e9dd19..0000000 --- a/include/entt/natvis/core.natvis +++ /dev/null @@ -1,32 +0,0 @@ - - - - {{ policy={ mode,en } }} - - - - - - - ({ first() }, { second() }) - - first() - second() - - - - {{ hash={ base_type::hash } }} - {{}} - - base_type::repr,na - base_type::length - - - - {{ name={ alias,na } }} - - identifier - seq - - - diff --git a/include/entt/natvis/entity.natvis b/include/entt/natvis/entity.natvis deleted file mode 100644 index f8fe42c..0000000 --- a/include/entt/natvis/entity.natvis +++ /dev/null @@ -1,181 +0,0 @@ - - - - {{ pools={ pools.size() } }} - - entities - - { pools.size() } - - - - - - - - *pools.packed.first_base::value[pos].element.second,view(simple) - - ++pos - - - - - groups.size() - - { vars.ctx.size() } - - - - - - - - vars.ctx.packed.first_base::value[pos].element.second - - ++pos - - - - - - - - - - - - - - - {{ size={ packed.size() }, type={ descriptor->alias,na } }} - - packed.capacity() - mode,en - head - - { sparse.size() * traits_type::page_size } - - - - - - - - - page = pos / traits_type::page_size - offset = pos & (traits_type::page_size - 1) - - *((traits_type::entity_type *)&sparse[page][offset]) & traits_type::entity_mask - - ++pos - - - - - - { packed.size() } - - - - - - - - packed[pos] - - ++pos - - - - - - - - - - - {{ size={ base_type::packed.size() }, type={ base_type::descriptor->alias,na } }} - - payload.capacity() * traits_type::page_size - traits_type::page_size - placeholder - (base_type*)this,nand - (base_type*)this,view(simple)nand - - - - - - - payload[pos / traits_type::page_size][pos & (traits_type::page_size - 1)] - - ++pos - - - - - - {{ size_hint={ pools[index]->packed.size() } }} - {{ size_hint=0 }} - - pools,na - filter,na - pools[index],na - - - - {{ size={ leading->packed.size() } }} - {{ size=0 }} - - leading,na - - - - { *(base_type*)this } - - *(base_type*)this - - - - {{ size_hint={ pools[0]->packed.size() } }} - {{ size_hint=0 }} - - pools,na - filter,na - - - - - - - {{ entity={ entt } }} - - entt - owner,na - - - - - - - - - - - - pool_at(pos),view(simple)nanr - - ++pos - - - - - - - - <null> - - - <tombstone> - - diff --git a/include/entt/natvis/graph.natvis b/include/entt/natvis/graph.natvis deleted file mode 100644 index d585ae2..0000000 --- a/include/entt/natvis/graph.natvis +++ /dev/null @@ -1,19 +0,0 @@ - - - - {{ size={ vert } }} - - - - - - - - pos % vert - - ++pos - - - - - diff --git a/include/entt/natvis/locator.natvis b/include/entt/natvis/locator.natvis deleted file mode 100644 index 6eb47e3..0000000 --- a/include/entt/natvis/locator.natvis +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/include/entt/natvis/meta.natvis b/include/entt/natvis/meta.natvis deleted file mode 100644 index 739897e..0000000 --- a/include/entt/natvis/meta.natvis +++ /dev/null @@ -1,200 +0,0 @@ - - - - {{ id={ id } }} - {{}} - - id - - - - {{ id={ id } }} - {{}} - - id - - - - {{ id={ id } }} - {{}} - - id - arity - - - - {{ id={ id } }} - {{}} - - id - value - - - - - - - {{ id={ name,na } }} - {{ id={ id } }} - {{}} - - id - name,na - arity - has_trait(entt::internal::meta_traits::is_const) - has_trait(entt::internal::meta_traits::is_static) - custom - - - - - - - {{ id={ name,na } }} - {{ id={ id } }} - {{}} - - id - name,na - arity - has_trait(entt::internal::meta_traits::is_const) - has_trait(entt::internal::meta_traits::is_static) - *next - custom - - - - {{ arity={ arity } }} - {{}} - - arity - - - - - - ctor,view(simple) - base,view(simple) - conv,view(simple) - data,view(simple) - func,view(simple) - - - - - - - {{ type={ name,na } }} - {{ type={ info->alias,na } }} - {{}} - - alias - name,na - size_of - has_trait(entt::internal::meta_traits::is_arithmetic) - has_trait(entt::internal::meta_traits::is_integral) - has_trait(entt::internal::meta_traits::is_signed) - has_trait(entt::internal::meta_traits::is_array) - has_trait(entt::internal::meta_traits::is_enum) - has_trait(entt::internal::meta_traits::is_class) - has_trait(entt::internal::meta_traits::is_pointer) - has_trait(entt::internal::meta_traits::is_pointer_like) - has_trait(entt::internal::meta_traits::is_sequence_container) - has_trait(entt::internal::meta_traits::is_associative_container) - default_constructor != nullptr - conversion_helper != nullptr - from_void != nullptr - templ - custom - *details - - - - { storage } - {{}} - - node,na - ctx,na - - - - { any } - - any - - - - {{ const={ const_only } }} - {{}} - - ctx,na - const_only - data - - - - {{ const={ const_only } }} - {{}} - - ctx,na - const_only - data - - - - { node,na } - {{}} - - node - - - - { node,na } - {{}} - - node - ctx,na - - - - { node,na } - {{}} - - node - ctx,na - - - - { node,na } - {{}} - - node - ctx,na - - - - { node,na } - {{}} - - node - ctx,na - - - - - - - { bucket } - - - - - - - element_at(pos).second - ++pos - - - - - diff --git a/include/entt/natvis/poly.natvis b/include/entt/natvis/poly.natvis deleted file mode 100644 index 8dfd72a..0000000 --- a/include/entt/natvis/poly.natvis +++ /dev/null @@ -1,6 +0,0 @@ - - - - { storage } - - diff --git a/include/entt/natvis/process.natvis b/include/entt/natvis/process.natvis deleted file mode 100644 index 1f959ff..0000000 --- a/include/entt/natvis/process.natvis +++ /dev/null @@ -1,21 +0,0 @@ - - - - {{ state={ current,en } }} - - current,en - *next.first_base::value - - - - - {{ size={ size() } }} - - handlers.first_base::value.capacity() - - size() - *handlers.first_base::value[$i] - - - - diff --git a/include/entt/natvis/resource.natvis b/include/entt/natvis/resource.natvis deleted file mode 100644 index cecd3b9..0000000 --- a/include/entt/natvis/resource.natvis +++ /dev/null @@ -1,26 +0,0 @@ - - - - { value } - - value - - - - - {{ size={ size() } }} - - - - - - - - *pool.first_base::value.packed.first_base::value[pos].element.second - - ++pos - - - - - diff --git a/include/entt/natvis/signal.natvis b/include/entt/natvis/signal.natvis deleted file mode 100644 index b486810..0000000 --- a/include/entt/natvis/signal.natvis +++ /dev/null @@ -1,51 +0,0 @@ - - - - {{ type={ "$T1" } }} - - fn == nullptr - instance - - - - - {{ size={ size() } }} - - - size() - *pools.first_base::value.packed.first_base::value[$i].element.second - - - - - {{ size={ events.size() }, event={ "$T1" } }} - - signal - events,view(simple) - - - - {{ size={ handlers.first_base::value.size() } }} - - - {{ bound={ signal != nullptr } }} - - - { conn } - - - {{ size={ calls.size() }, type={ "$T1" } }} - - - calls.size() - calls[$i] - - - - - {{ type={ "$T1" } }} - - signal,na - - - diff --git a/include/entt/poly/fwd.hpp b/include/entt/poly/fwd.hpp deleted file mode 100644 index 4d513e3..0000000 --- a/include/entt/poly/fwd.hpp +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef ENTT_POLY_FWD_HPP -#define ENTT_POLY_FWD_HPP - -#include "../stl/cstddef.hpp" - -namespace entt { - -// NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays, modernize-avoid-c-arrays) -template -class basic_poly; - -/** - * @brief Alias declaration for the most common use case. - * @tparam Concept Concept descriptor. - */ -template -using poly = basic_poly; - -} // namespace entt - -#endif diff --git a/include/entt/poly/poly.hpp b/include/entt/poly/poly.hpp deleted file mode 100644 index a409c9a..0000000 --- a/include/entt/poly/poly.hpp +++ /dev/null @@ -1,316 +0,0 @@ -#ifndef ENTT_POLY_POLY_HPP -#define ENTT_POLY_POLY_HPP - -#include "../core/any.hpp" -#include "../core/concepts.hpp" -#include "../core/type_info.hpp" -#include "../core/type_traits.hpp" -#include "../stl/concepts.hpp" -#include "../stl/cstddef.hpp" -#include "../stl/functional.hpp" -#include "../stl/tuple.hpp" -#include "../stl/type_traits.hpp" -#include "../stl/utility.hpp" -#include "fwd.hpp" - -namespace entt { - -/*! @brief Inspector class used to infer the type of the virtual table. */ -struct poly_inspector { - /** - * @brief Generic conversion operator (definition only). - * @tparam Type Type to which conversion is requested. - */ - template - operator Type &&() const; - - /** - * @brief Dummy invocation function (definition only). - * @tparam Member Index of the function to invoke. - * @tparam Args Types of arguments to pass to the function. - * @param args The arguments to pass to the function. - * @return A poly inspector convertible to any type. - */ - template - [[nodiscard]] poly_inspector invoke(Args &&...args) const; - - /*! @copydoc invoke */ - template - [[nodiscard]] poly_inspector invoke(Args &&...args); -}; - -/** - * @brief Static virtual table factory. - * @tparam Concept Concept descriptor. - * @tparam Len Size of the storage reserved for the small buffer optimization. - * @tparam Align Alignment requirement. - */ -template -class poly_vtable { - using inspector = Concept::template type; - - template - requires stl::derived_from> - static auto vtable_entry(Ret (*)(Clazz &, Args...)) - -> Ret (*)(constness_as_t, Clazz> &, Args...); - - template - static auto vtable_entry(Ret (*)(Args...)) - -> Ret (*)(const basic_any &, Args...); - - template - requires stl::derived_from - static auto vtable_entry(Ret (Clazz::*)(Args...)) - -> Ret (*)(basic_any &, Args...); - - template - requires stl::derived_from - static auto vtable_entry(Ret (Clazz::*)(Args...) const) - -> Ret (*)(const basic_any &, Args...); - - template - static auto make_vtable(value_list) noexcept - -> decltype(stl::make_tuple(vtable_entry(Candidate)...)); - - template - [[nodiscard]] static ENTT_CONSTEVAL auto make_vtable(type_list) noexcept { - if constexpr(sizeof...(Func) == 0u) { - return decltype(make_vtable(typename Concept::template impl{})){}; - } else if constexpr((stl::is_function_v && ...)) { - return decltype(stl::make_tuple(vtable_entry(stl::declval())...)){}; - } - } - - template - static void fill_vtable_entry(Ret (*&entry)(Any &, Args...)) noexcept { - if constexpr(stl::is_invocable_r_v) { - entry = +[](Any &, Args... args) -> Ret { - return stl::invoke(Candidate, stl::forward(args)...); - }; - } else { - entry = +[](Any &instance, Args... args) -> Ret { - return static_cast(stl::invoke(Candidate, any_cast &>(instance), stl::forward(args)...)); - }; - } - } - - template - [[nodiscard]] static auto fill_vtable(stl::index_sequence) noexcept { - vtable_type impl{}; - (fill_vtable_entry>>(stl::get(impl)), ...); - return impl; - } - - using vtable_type = decltype(make_vtable(Concept{})); - static constexpr bool is_mono = stl::tuple_size_v == 1u; - -public: - /*! @brief Virtual table type. */ - using type = stl::conditional_t, const vtable_type *>; - - /** - * @brief Returns a static virtual table for a specific concept and type. - * @tparam Type The type for which to generate the virtual table. - * @return A static virtual table for the given concept and type. - */ - template - [[nodiscard]] static type instance() noexcept { - static const vtable_type vtable = fill_vtable(stl::make_index_sequence::size>{}); - - if constexpr(is_mono) { - return stl::get<0>(vtable); - } else { - return &vtable; - } - } -}; - -/** - * @brief Poly base class used to inject functionalities into concepts. - * @tparam Poly The outermost poly class. - */ -template -struct poly_base { - /** - * @brief Invokes a function from the static virtual table. - * @tparam Member Index of the function to invoke. - * @tparam Args Types of arguments to pass to the function. - * @param self A reference to the poly object that made the call. - * @param args The arguments to pass to the function. - * @return The return value of the invoked function, if any. - */ - template - [[nodiscard]] decltype(auto) invoke(const poly_base &self, Args &&...args) const { - const auto &poly = static_cast(self); - - if constexpr(stl::is_function_v>) { - return poly.vtable(poly.storage, stl::forward(args)...); - } else { - return stl::get(*poly.vtable)(poly.storage, stl::forward(args)...); - } - } - - /*! @copydoc invoke */ - template - [[nodiscard]] decltype(auto) invoke(poly_base &self, Args &&...args) { - auto &poly = static_cast(self); - - if constexpr(stl::is_function_v>) { - static_assert(Member == 0u, "Unknown member"); - return poly.vtable(poly.storage, stl::forward(args)...); - } else { - return stl::get(*poly.vtable)(poly.storage, stl::forward(args)...); - } - } -}; - -/** - * @brief Shortcut for calling `poly_base::invoke`. - * @tparam Member Index of the function to invoke. - * @tparam Poly A fully defined poly object. - * @tparam Args Types of arguments to pass to the function. - * @param self A reference to the poly object that made the call. - * @param args The arguments to pass to the function. - * @return The return value of the invoked function, if any. - */ -template -decltype(auto) poly_call(Poly &&self, Args &&...args) { - return stl::forward(self).template invoke(self, stl::forward(args)...); -} - -/** - * @brief Static polymorphism made simple and within everyone's reach. - * - * Static polymorphism is a very powerful tool in C++, albeit sometimes - * cumbersome to obtain.
- * This class aims to make it simple and easy to use. - * - * @note - * Both deduced and defined static virtual tables are supported.
- * Moreover, the `poly` class template also works with unmanaged objects. - * - * @tparam Concept Concept descriptor. - * @tparam Len Size of the storage reserved for the small buffer optimization. - * @tparam Align Optional alignment requirement. - */ -template -class basic_poly: private Concept::template type>> { - friend struct poly_base; - -public: - /*! @brief Concept type. */ - using concept_type = Concept::template type>; - /*! @brief Virtual table type. */ - using vtable_type = poly_vtable::type; - - /*! @brief Default constructor. */ - basic_poly() noexcept = default; - - /** - * @brief Constructs a poly by directly initializing the new object. - * @tparam Type Type of object to use to initialize the poly. - * @tparam Args Types of arguments to use to construct the new instance. - * @param args Parameters to use to construct the instance. - */ - template - explicit basic_poly(stl::in_place_type_t, Args &&...args) - : storage{stl::in_place_type, stl::forward(args)...}, - vtable{poly_vtable::template instance>()} {} - - /** - * @brief Constructs a poly from a given value. - * @tparam Type Type of object to use to initialize the poly. - * @param value An instance of an object to use to initialize the poly. - */ - template - requires (!stl::same_as, basic_poly>) - basic_poly(Type &&value) noexcept - : basic_poly{stl::in_place_type>, stl::forward(value)} {} - - /** - * @brief Returns the object type info if any, `type_id()` otherwise. - * @return The object type info if any, `type_id()` otherwise. - */ - [[nodiscard]] const type_info &info() const noexcept { - return storage.info(); - } - - /** - * @brief Returns an opaque pointer to the contained instance. - * @return An opaque pointer the contained instance, if any. - */ - [[nodiscard]] const void *data() const noexcept { - return storage.data(); - } - - /*! @copydoc data */ - [[nodiscard]] void *data() noexcept { - return storage.data(); - } - - /** - * @brief Replaces the contained object by creating a new instance directly. - * @tparam Type Type of object to use to initialize the poly. - * @tparam Args Types of arguments to use to construct the new instance. - * @param args Parameters to use to construct the instance. - */ - template - void emplace(Args &&...args) { - storage.template emplace(stl::forward(args)...); - vtable = poly_vtable::template instance>(); - } - - /*! @brief Destroys contained object */ - void reset() { - storage.reset(); - vtable = {}; - } - - /** - * @brief Returns false if a poly is empty, true otherwise. - * @return False if the poly is empty, true otherwise. - */ - [[nodiscard]] explicit operator bool() const noexcept { - return static_cast(storage); - } - - /** - * @brief Returns a pointer to the underlying concept. - * @return A pointer to the underlying concept. - */ - [[nodiscard]] concept_type *operator->() noexcept { - return this; - } - - /*! @copydoc operator-> */ - [[nodiscard]] const concept_type *operator->() const noexcept { - return this; - } - - /** - * @brief Aliasing constructor. - * @return A poly that shares a reference to an unmanaged object. - */ - [[nodiscard]] basic_poly as_ref() noexcept { - basic_poly ref{}; - ref.storage = storage.as_ref(); - ref.vtable = vtable; - return ref; - } - - /*! @copydoc as_ref */ - [[nodiscard]] basic_poly as_ref() const noexcept { - basic_poly ref{}; - ref.storage = storage.as_ref(); - ref.vtable = vtable; - return ref; - } - -private: - basic_any storage{}; - vtable_type vtable{}; -}; - -} // namespace entt - -#endif diff --git a/include/entt/process/fwd.hpp b/include/entt/process/fwd.hpp deleted file mode 100644 index 77bc495..0000000 --- a/include/entt/process/fwd.hpp +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef ENTT_PROCESS_FWD_HPP -#define ENTT_PROCESS_FWD_HPP - -#include "../stl/cstdint.hpp" -#include "../stl/memory.hpp" - -namespace entt { - -template> -class basic_process; - -/*! @brief Alias declaration for the most common use case. */ -using process = basic_process; - -template> -class basic_scheduler; - -/*! @brief Alias declaration for the most common use case. */ -using scheduler = basic_scheduler; - -} // namespace entt - -#endif diff --git a/include/entt/process/process.hpp b/include/entt/process/process.hpp deleted file mode 100644 index 8e5c950..0000000 --- a/include/entt/process/process.hpp +++ /dev/null @@ -1,316 +0,0 @@ -#ifndef ENTT_PROCESS_PROCESS_HPP -#define ENTT_PROCESS_PROCESS_HPP - -#include "../core/compressed_pair.hpp" -#include "../core/type_traits.hpp" -#include "../stl/cstdint.hpp" -#include "../stl/memory.hpp" -#include "../stl/type_traits.hpp" -#include "../stl/utility.hpp" -#include "fwd.hpp" - -namespace entt { - -/*! @cond ENTT_INTERNAL */ -namespace internal { - -template -struct process_adaptor; - -} // namespace internal -/*! @endcond */ - -/** - * @brief Base class for processes. - * - * Derived classes must specify what's the intended type for elapsed times.
- * A process can implement the following member functions whether required: - * - * * @code{.cpp} - * void update(Delta, void *) override; - * @endcode - * - * It's invoked once per tick until a process is explicitly aborted or it - * terminates either with or without errors. Even though it's not mandatory to - * declare this member function, as a rule of thumb each process should at - * least define it to work properly. The `void *` parameter is an opaque - * pointer to user data (if any) forwarded directly to the process during an - * update. - * - * * @code{.cpp} - * void succeeded() override; - * @endcode - * - * It's invoked in case of success, immediately after an update and during the - * same tick. - * - * * @code{.cpp} - * void failed() override; - * @endcode - * - * It's invoked in case of errors, immediately after an update and during the - * same tick. - * - * * @code{.cpp} - * void aborted() override; - * @endcode - * - * It's invoked only if a process is explicitly aborted. There is no guarantee - * that it executes in the same tick, this depends solely on whether the - * process is aborted immediately or not. - * - * Derived classes can change the internal state of a process by invoking the - * `succeed` and `fail` member functions and even pause or unpause the process - * itself. - * - * @sa scheduler - * - * @tparam Delta Type to use to provide elapsed time. - * @tparam Allocator Type of allocator used to manage memory and elements. - */ -template -class basic_process: public stl::enable_shared_from_this> { - enum class state : stl::uint8_t { - idle = 0, - running, - paused, - succeeded, - failed, - aborted, - finished, - rejected - }; - - virtual void update(const Delta, void *) { - abort(); - } - - virtual void succeeded() {} - virtual void failed() {} - virtual void aborted() {} - -public: - /*! @brief Allocator type. */ - using allocator_type = Allocator; - /*! @brief Type used to provide elapsed time. */ - using delta_type = Delta; - /*! @brief Handle type. */ - using handle_type = stl::shared_ptr; - - /*! @brief Default constructor. */ - basic_process() - : basic_process{allocator_type{}} {} - - /** - * @brief Constructs a scheduler with a given allocator. - * @param allocator The allocator to use. - */ - explicit basic_process(const allocator_type &allocator) - : next{nullptr, allocator}, - current{state::idle} {} - - /*! @brief Default copy constructor, deleted on purpose. */ - basic_process(const basic_process &) = delete; - - /*! @brief Default move constructor, deleted on purpose. */ - basic_process(basic_process &&) = delete; - - /*! @brief Default destructor. */ - virtual ~basic_process() = default; - - /** - * @brief Default copy assignment operator, deleted on purpose. - * @return This process scheduler. - */ - basic_process &operator=(const basic_process &) = delete; - - /** - * @brief Default move assignment operator, deleted on purpose. - * @return This process scheduler. - */ - basic_process &operator=(basic_process &&) = delete; - - /** - * @brief Returns the associated allocator. - * @return The associated allocator. - */ - [[nodiscard]] constexpr allocator_type get_allocator() const noexcept { - return next.second(); - } - - /*! @brief Aborts a process if it's still alive, otherwise does nothing. */ - void abort() { - if(alive()) { - current = state::aborted; - } - } - - /** - * @brief Terminates a process with success if it's still alive, otherwise - * does nothing. - */ - void succeed() noexcept { - if(alive()) { - current = state::succeeded; - } - } - - /** - * @brief Terminates a process with errors if it's still alive, otherwise - * does nothing. - */ - void fail() noexcept { - if(alive()) { - current = state::failed; - } - } - - /*! @brief Stops a process if it's running, otherwise does nothing. */ - void pause() noexcept { - if(alive()) { - current = state::paused; - } - } - - /*! @brief Restarts a process if it's paused, otherwise does nothing. */ - void unpause() noexcept { - if(alive()) { - current = state::running; - } - } - - /** - * @brief Returns true if a process is either running or paused. - * @return True if the process is still alive, false otherwise. - */ - [[nodiscard]] bool alive() const noexcept { - return current == state::running || current == state::paused; - } - - /** - * @brief Returns true if a process is already terminated. - * @return True if the process is terminated, false otherwise. - */ - [[nodiscard]] bool finished() const noexcept { - return current == state::finished; - } - - /** - * @brief Returns true if a process is currently paused. - * @return True if the process is paused, false otherwise. - */ - [[nodiscard]] bool paused() const noexcept { - return current == state::paused; - } - - /** - * @brief Returns true if a process terminated with errors. - * @return True if the process terminated with errors, false otherwise. - */ - [[nodiscard]] bool rejected() const noexcept { - return current == state::rejected; - } - - /** - * @brief Assigns a child process to run in case of success. - * @tparam Type Type of child process to create. - * @tparam Args Types of arguments to use to initialize the child process. - * @param args Parameters to use to initialize the child process. - * @return A reference to the newly created child process. - */ - template - basic_process &then(Args &&...args) { - const auto &allocator = next.second(); - return *(next.first() = stl::allocate_shared(allocator, allocator, stl::forward(args)...)); - } - - /** - * @brief Assigns a child process to run in case of success. - * @tparam Func Type of child process to create. - * @param func Either a lambda or a functor to use as a child process. - * @return A reference to the newly created child process. - */ - template - basic_process &then(Func func) { - const auto &allocator = next.second(); - using process_type = internal::process_adaptor; - return *(next.first() = stl::allocate_shared(allocator, allocator, stl::move(func))); - } - - /** - * @brief Returns the child process without releasing ownership, if any. - * @return The child process attached to the object, if any. - */ - handle_type peek() { - return next.first(); - } - - /** - * @brief Updates a process and its internal state, if required. - * @param delta Elapsed time. - * @param data Optional data. - */ - void tick(const Delta delta, void *data = nullptr) { - switch(current) { - case state::idle: - case state::running: - current = state::running; - update(delta, data); - break; - default: - // suppress warnings - break; - } - - // if it's dead, it must be notified and removed immediately - switch(current) { - case state::succeeded: - succeeded(); - current = state::finished; - break; - case state::failed: - failed(); - current = state::rejected; - break; - case state::aborted: - aborted(); - current = state::rejected; - break; - default: - // suppress warnings - break; - } - } - -private: - compressed_pair next; - state current; -}; - -/*! @cond ENTT_INTERNAL */ -namespace internal { - -template -struct process_adaptor: public basic_process { - using allocator_type = Allocator; - using base_type = basic_process; - using delta_type = base_type::delta_type; - - process_adaptor(const allocator_type &allocator, Func proc) - : base_type{allocator}, - func{stl::move(proc)} {} - - void update(const delta_type delta, void *data) override { - func(*this, delta, data); - } - -private: - Func func; -}; - -} // namespace internal -/*! @endcond */ - -} // namespace entt - -#endif diff --git a/include/entt/process/scheduler.hpp b/include/entt/process/scheduler.hpp deleted file mode 100644 index 554f7c2..0000000 --- a/include/entt/process/scheduler.hpp +++ /dev/null @@ -1,227 +0,0 @@ -#ifndef ENTT_PROCESS_SCHEDULER_HPP -#define ENTT_PROCESS_SCHEDULER_HPP - -#include "../config/config.h" -#include "../core/compressed_pair.hpp" -#include "../stl/cstddef.hpp" -#include "../stl/memory.hpp" -#include "../stl/type_traits.hpp" -#include "../stl/utility.hpp" -#include "../stl/vector.hpp" -#include "fwd.hpp" -#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. - * - * 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. - * @tparam Allocator Type of allocator used to manage memory and elements. - */ -template -class basic_scheduler { - using base_type = basic_process; - using alloc_traits = stl::allocator_traits; - using container_allocator = alloc_traits::template rebind_alloc>; - using container_type = stl::vector, container_allocator>; - -public: - /*! @brief Process type. */ - using type = base_type; - /*! @brief Allocator type. */ - using allocator_type = Allocator; - /*! @brief Unsigned integer type. */ - using size_type = stl::size_t; - /*! @brief Unsigned integer type. */ - using delta_type = Delta; - - /*! @brief Default constructor. */ - basic_scheduler() - : basic_scheduler{allocator_type{}} {} - - /** - * @brief Constructs a scheduler with a given allocator. - * @param allocator The allocator to use. - */ - explicit basic_scheduler(const allocator_type &allocator) - : handlers{allocator, allocator} {} - - /*! @brief Default copy constructor, deleted on purpose. */ - basic_scheduler(const basic_scheduler &) = delete; - - /** - * @brief Move constructor. - * @param other The instance to move from. - */ - basic_scheduler(basic_scheduler &&other) noexcept - : handlers{stl::move(other.handlers)} {} - - /** - * @brief Allocator-extended move constructor. - * @param other The instance to move from. - * @param allocator The allocator to use. - */ - basic_scheduler(basic_scheduler &&other, const allocator_type &allocator) - : handlers{container_type{stl::move(other.handlers.first()), allocator}, allocator} { - ENTT_ASSERT(alloc_traits::is_always_equal::value || get_allocator() == other.get_allocator(), "Copying a scheduler is not allowed"); - } - - /*! @brief Default destructor. */ - ~basic_scheduler() = default; - - /** - * @brief Default copy assignment operator, deleted on purpose. - * @return This process scheduler. - */ - basic_scheduler &operator=(const basic_scheduler &) = delete; - - /** - * @brief Move assignment operator. - * @param other The instance to move from. - * @return This process scheduler. - */ - basic_scheduler &operator=(basic_scheduler &&other) noexcept { - ENTT_ASSERT(alloc_traits::is_always_equal::value || get_allocator() == other.get_allocator(), "Copying a scheduler is not allowed"); - swap(other); - return *this; - } - - /** - * @brief Exchanges the contents with those of a given scheduler. - * @param other Scheduler to exchange the content with. - */ - void swap(basic_scheduler &other) noexcept { - using stl::swap; - swap(handlers, other.handlers); - } - - /** - * @brief Returns the associated allocator. - * @return The associated allocator. - */ - [[nodiscard]] constexpr allocator_type get_allocator() const noexcept { - return handlers.second(); - } - - /** - * @brief Number of processes currently scheduled. - * @return Number of processes currently scheduled. - */ - [[nodiscard]] size_type size() const noexcept { - return handlers.first().size(); - } - - /** - * @brief Returns true if at least a process is currently scheduled. - * @return True if there are scheduled processes, false otherwise. - */ - [[nodiscard]] bool empty() const noexcept { - return handlers.first().empty(); - } - - /** - * @brief Discards all scheduled processes. - * - * Processes aren't aborted. They are discarded along with their children - * and never executed again. - */ - void clear() { - handlers.first().clear(); - } - - /** - * @brief Schedules a process for the next tick. - * @tparam Type Type of process to create. - * @tparam Args Types of arguments to use to initialize the process. - * @param args Parameters to use to initialize the process. - * @return A reference to the newly created process. - */ - template - type &attach(Args &&...args) { - const auto &allocator = handlers.second(); - return *handlers.first().emplace_back(stl::allocate_shared(allocator, allocator, stl::forward(args)...)); - } - - /** - * @brief Schedules a process for the next tick. - * @tparam Func Type of process to create. - * @param func Either a lambda or a functor to use as a process. - * @return A reference to the newly created process. - */ - template - type &attach(Func func) { - const auto &allocator = handlers.second(); - using process_type = internal::process_adaptor; - return *handlers.first().emplace_back(stl::allocate_shared(allocator, allocator, stl::move(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_type delta, void *data = nullptr) { - for(auto next = handlers.first().size(); next; --next) { - const auto pos = next - 1u; - handlers.first()[pos]->tick(delta, data); - // updating might spawn/reallocate, cannot hold refs until here - auto &elem = handlers.first()[pos]; - - if(elem->finished()) { - elem = elem->peek(); - } - - if(!elem || elem->rejected()) { - elem = stl::move(handlers.first().back()); - handlers.first().pop_back(); - } - } - } - - /** - * @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 immediate Requests an immediate operation. - */ - void abort(const bool immediate = false) { - for(auto &&curr: handlers.first()) { - curr->abort(); - - if(immediate) { - curr->tick({}); - } - } - } - -private: - compressed_pair handlers; -}; - -} // namespace entt - -#endif diff --git a/include/entt/resource/cache.hpp b/include/entt/resource/cache.hpp deleted file mode 100644 index 99c10e0..0000000 --- a/include/entt/resource/cache.hpp +++ /dev/null @@ -1,386 +0,0 @@ -#ifndef ENTT_RESOURCE_RESOURCE_CACHE_HPP -#define ENTT_RESOURCE_RESOURCE_CACHE_HPP - -#include -#include "../container/dense_map.hpp" -#include "../core/compressed_pair.hpp" -#include "../core/fwd.hpp" -#include "../core/iterator.hpp" -#include "../stl/concepts.hpp" -#include "../stl/cstddef.hpp" -#include "../stl/functional.hpp" -#include "../stl/iterator.hpp" -#include "../stl/memory.hpp" -#include "../stl/tuple.hpp" -#include "../stl/type_traits.hpp" -#include "../stl/utility.hpp" -#include "fwd.hpp" -#include "loader.hpp" -#include "resource.hpp" - -namespace entt { - -/*! @cond ENTT_INTERNAL */ -namespace internal { - -template -class resource_cache_iterator final { - template - friend class resource_cache_iterator; - -public: - using value_type = stl::pair>; - using pointer = input_iterator_pointer; - using reference = value_type; - using difference_type = stl::ptrdiff_t; - using iterator_category = stl::input_iterator_tag; - using iterator_concept = stl::random_access_iterator_tag; - - constexpr resource_cache_iterator() noexcept = default; - - constexpr resource_cache_iterator(const It iter) noexcept - : it{iter} {} - - template - requires (!stl::same_as && stl::constructible_from) - constexpr resource_cache_iterator(const resource_cache_iterator, Other> &other) noexcept - : it{other.it} {} - - constexpr resource_cache_iterator &operator++() noexcept { - return ++it, *this; - } - - constexpr resource_cache_iterator operator++(int) noexcept { - const resource_cache_iterator orig = *this; - return ++(*this), orig; - } - - constexpr resource_cache_iterator &operator--() noexcept { - return --it, *this; - } - - constexpr resource_cache_iterator operator--(int) noexcept { - const resource_cache_iterator orig = *this; - return operator--(), orig; - } - - constexpr resource_cache_iterator &operator+=(const difference_type value) noexcept { - it += value; - return *this; - } - - constexpr resource_cache_iterator operator+(const difference_type value) const noexcept { - resource_cache_iterator copy = *this; - return (copy += value); - } - - constexpr resource_cache_iterator &operator-=(const difference_type value) noexcept { - return (*this += -value); - } - - constexpr resource_cache_iterator operator-(const difference_type value) const noexcept { - return (*this + -value); - } - - [[nodiscard]] constexpr reference operator[](const difference_type value) const noexcept { - return {it[value].first, resource{it[value].second}}; - } - - [[nodiscard]] constexpr reference operator*() const noexcept { - return operator[](0); - } - - [[nodiscard]] constexpr pointer operator->() const noexcept { - return operator*(); - } - - template - [[nodiscard]] constexpr stl::ptrdiff_t operator-(const resource_cache_iterator &other) const noexcept { - return it - other.it; - } - - template - [[nodiscard]] constexpr bool operator==(const resource_cache_iterator &other) const noexcept { - return it == other.it; - } - - template - [[nodiscard]] constexpr auto operator<=>(const resource_cache_iterator &other) const noexcept { - return it <=> other.it; - } - -private: - It it; -}; - -} // namespace internal -/*! @endcond */ - -/** - * @brief Basic cache for resources of any type. - * @tparam Type Type of resources managed by a cache. - * @tparam Loader Type of loader used to create the resources. - * @tparam Allocator Type of allocator used to manage memory and elements. - */ -template -class resource_cache { - using alloc_traits = stl::allocator_traits; - static_assert(stl::is_same_v, "Invalid value type"); - using container_allocator = alloc_traits::template rebind_alloc>; - using container_type = dense_map, container_allocator>; - -public: - /*! @brief Allocator type. */ - using allocator_type = Allocator; - /*! @brief Resource type. */ - using value_type = Type; - /*! @brief Unsigned integer type. */ - using size_type = stl::size_t; - /*! @brief Loader type. */ - using loader_type = Loader; - /*! @brief Input iterator type. */ - using iterator = internal::resource_cache_iterator; - /*! @brief Constant input iterator type. */ - using const_iterator = internal::resource_cache_iterator; - - /*! @brief Default constructor. */ - resource_cache() - : resource_cache{loader_type{}} {} - - /** - * @brief Constructs an empty cache with a given allocator. - * @param allocator The allocator to use. - */ - explicit resource_cache(const allocator_type &allocator) - : resource_cache{loader_type{}, allocator} {} - - /** - * @brief Constructs an empty cache with a given allocator and loader. - * @param callable The loader to use. - * @param allocator The allocator to use. - */ - explicit resource_cache(const loader_type &callable, const allocator_type &allocator = allocator_type{}) - : pool{container_type{allocator}, callable} {} - - /*! @brief Default copy constructor. */ - resource_cache(const resource_cache &) = default; - - /** - * @brief Allocator-extended copy constructor. - * @param other The instance to copy from. - * @param allocator The allocator to use. - */ - resource_cache(const resource_cache &other, const allocator_type &allocator) - : pool{stl::piecewise_construct, stl::forward_as_tuple(other.pool.first(), allocator), stl::forward_as_tuple(other.pool.second())} {} - - /*! @brief Default move constructor. */ - resource_cache(resource_cache &&) noexcept = default; - - /** - * @brief Allocator-extended move constructor. - * @param other The instance to move from. - * @param allocator The allocator to use. - */ - resource_cache(resource_cache &&other, const allocator_type &allocator) - : pool{stl::piecewise_construct, stl::forward_as_tuple(stl::move(other.pool.first()), allocator), stl::forward_as_tuple(stl::move(other.pool.second()))} {} - - /*! @brief Default destructor. */ - ~resource_cache() = default; - - /** - * @brief Default copy assignment operator. - * @return This cache. - */ - resource_cache &operator=(const resource_cache &) = default; - - /** - * @brief Default move assignment operator. - * @return This cache. - */ - resource_cache &operator=(resource_cache &&) noexcept = default; - - /** - * @brief Returns the associated allocator. - * @return The associated allocator. - */ - [[nodiscard]] constexpr allocator_type get_allocator() const noexcept { - return pool.first().get_allocator(); - } - - /** - * @brief Returns an iterator to the beginning. - * - * If the cache is empty, the returned iterator will be equal to `end()`. - * - * @return An iterator to the first instance of the internal cache. - */ - [[nodiscard]] const_iterator cbegin() const noexcept { - return pool.first().begin(); - } - - /*! @copydoc cbegin */ - [[nodiscard]] const_iterator begin() const noexcept { - return cbegin(); - } - - /*! @copydoc begin */ - [[nodiscard]] iterator begin() noexcept { - return pool.first().begin(); - } - - /** - * @brief Returns an iterator to the end. - * @return An iterator to the element following the last instance of the - * internal cache. - */ - [[nodiscard]] const_iterator cend() const noexcept { - return pool.first().end(); - } - - /*! @copydoc cend */ - [[nodiscard]] const_iterator end() const noexcept { - return cend(); - } - - /*! @copydoc end */ - [[nodiscard]] iterator end() noexcept { - return pool.first().end(); - } - - /** - * @brief Returns true if a cache contains no resources, false otherwise. - * @return True if the cache contains no resources, false otherwise. - */ - [[nodiscard]] bool empty() const noexcept { - return pool.first().empty(); - } - - /** - * @brief Number of resources managed by a cache. - * @return Number of resources currently stored. - */ - [[nodiscard]] size_type size() const noexcept { - return pool.first().size(); - } - - /*! @brief Clears a cache. */ - void clear() noexcept { - pool.first().clear(); - } - - /** - * @brief Loads a resource, if its identifier does not exist. - * - * Arguments are forwarded directly to the loader and _consumed_ only if the - * resource doesn't already exist. - * - * @warning - * If the resource isn't loaded correctly, the returned handle could be - * invalid and any use of it will result in undefined behavior. - * - * @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 A pair consisting of an iterator to the inserted element (or to - * the element that prevented the insertion) and a bool denoting whether the - * insertion took place. - */ - template - stl::pair load(const id_type id, Args &&...args) { - if(auto it = pool.first().find(id); it != pool.first().end()) { - return {it, false}; - } - - return pool.first().emplace(id, pool.second()(stl::forward(args)...)); - } - - /** - * @brief Force loads a resource, even if its identifier already exists. - * @copydetails load - */ - template - stl::pair force_load(const id_type id, Args &&...args) { - return {pool.first().insert_or_assign(id, pool.second()(stl::forward(args)...)).first, true}; - } - - /** - * @brief Returns a handle for a given resource identifier. - * - * @warning - * There is no guarantee that the returned handle is valid.
- * If it is not, any use will result in undefined behavior. - * - * @param id Unique resource identifier. - * @return A handle for the given resource. - */ - [[nodiscard]] resource operator[](const id_type id) const { - if(auto it = pool.first().find(id); it != pool.first().cend()) { - return resource{it->second}; - } - - return {}; - } - - /*! @copydoc operator[] */ - [[nodiscard]] resource operator[](const id_type id) { - if(auto it = pool.first().find(id); it != pool.first().end()) { - return resource{it->second}; - } - - return {}; - } - - /** - * @brief Checks if a cache contains a given identifier. - * @param id Unique resource identifier. - * @return True if the cache contains the resource, false otherwise. - */ - [[nodiscard]] bool contains(const id_type id) const { - return pool.first().contains(id); - } - - /** - * @brief Removes an element from a given position. - * @param pos An iterator to the element to remove. - * @return An iterator following the removed element. - */ - iterator erase(const_iterator pos) { - const auto it = pool.first().begin(); - return pool.first().erase(it + (pos - const_iterator{it})); - } - - /** - * @brief Removes the given elements from a cache. - * @param first An iterator to the first element of the range of elements. - * @param last An iterator past the last element of the range of elements. - * @return An iterator following the last removed element. - */ - iterator erase(const_iterator first, const_iterator last) { - const auto it = pool.first().begin(); - return pool.first().erase(it + (first - const_iterator{it}), it + (last - const_iterator{it})); - } - - /** - * @brief Removes the given elements from a cache. - * @param id Unique resource identifier. - * @return Number of resources erased (either 0 or 1). - */ - size_type erase(const id_type id) { - return pool.first().erase(id); - } - - /** - * @brief Returns the loader used to create resources. - * @return The loader used to create resources. - */ - [[nodiscard]] loader_type loader() const { - return pool.second(); - } - -private: - compressed_pair pool; -}; - -} // namespace entt - -#endif diff --git a/include/entt/resource/fwd.hpp b/include/entt/resource/fwd.hpp deleted file mode 100644 index bb9c542..0000000 --- a/include/entt/resource/fwd.hpp +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef ENTT_RESOURCE_FWD_HPP -#define ENTT_RESOURCE_FWD_HPP - -#include "../stl/memory.hpp" - -namespace entt { - -template -struct resource_loader; - -template, typename = stl::allocator> -class resource_cache; - -template -class resource; - -} // namespace entt - -#endif diff --git a/include/entt/resource/loader.hpp b/include/entt/resource/loader.hpp deleted file mode 100644 index 2df95d0..0000000 --- a/include/entt/resource/loader.hpp +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef ENTT_RESOURCE_LOADER_HPP -#define ENTT_RESOURCE_LOADER_HPP - -#include "../stl/memory.hpp" -#include "../stl/utility.hpp" -#include "fwd.hpp" - -namespace entt { - -/** - * @brief Transparent loader for shared resources. - * @tparam Type Type of resources created by the loader. - */ -template -struct resource_loader { - /*! @brief Result type. */ - using result_type = stl::shared_ptr; - - /** - * @brief Constructs a shared pointer to a resource from its arguments. - * @tparam Args Types of arguments to use to construct the resource. - * @param args Parameters to use to construct the resource. - * @return A shared pointer to a resource of the given type. - */ - template - result_type operator()(Args &&...args) const { - return stl::make_shared(stl::forward(args)...); - } -}; - -} // namespace entt - -#endif diff --git a/include/entt/resource/resource.hpp b/include/entt/resource/resource.hpp deleted file mode 100644 index 670569d..0000000 --- a/include/entt/resource/resource.hpp +++ /dev/null @@ -1,212 +0,0 @@ -#ifndef ENTT_RESOURCE_RESOURCE_HPP -#define ENTT_RESOURCE_RESOURCE_HPP - -#include -#include "../stl/concepts.hpp" -#include "../stl/memory.hpp" -#include "../stl/utility.hpp" -#include "fwd.hpp" - -namespace entt { - -/** - * @brief Basic resource handle. - * - * A handle wraps a resource and extends its lifetime. It also shares the same - * resource with all other handles constructed from the same element.
- * As a rule of thumb, resources should never be copied nor moved. Handles are - * the way to go to push references around. - * - * @tparam Type Type of resource managed by a handle. - */ -template -class resource { - template - friend class resource; - -public: - /*! @brief Resource type. */ - using element_type = Type; - /*! @brief Handle type. */ - using handle_type = stl::shared_ptr; - - /*! @brief Default constructor. */ - resource() noexcept - : value{} {} - - /** - * @brief Creates a new resource handle. - * @param res A handle to a resource. - */ - explicit resource(handle_type res) noexcept - : value{stl::move(res)} {} - - /*! @brief Default copy constructor. */ - resource(const resource &) noexcept = default; - - /*! @brief Default move constructor. */ - resource(resource &&) noexcept = default; - - /** - * @brief Aliasing constructor. - * @tparam Other Type of resource managed by the received handle. - * @param other The handle with which to share ownership information. - * @param res Unrelated and unmanaged resources. - */ - template - resource(const resource &other, element_type &res) noexcept - : value{other.value, stl::addressof(res)} {} - - /** - * @brief Copy constructs a handle which shares ownership of the resource. - * @tparam Other Type of resource managed by the received handle. - * @param other The handle to copy from. - */ - template - requires (!stl::same_as && stl::constructible_from) - resource(const resource &other) noexcept - : value{other.value} {} - - /** - * @brief Move constructs a handle which takes ownership of the resource. - * @tparam Other Type of resource managed by the received handle. - * @param other The handle to move from. - */ - template - requires (!stl::same_as && stl::constructible_from) - resource(resource &&other) noexcept - : value{stl::move(other.value)} {} - - /*! @brief Default destructor. */ - ~resource() = default; - - /** - * @brief Default copy assignment operator. - * @return This resource handle. - */ - resource &operator=(const resource &) noexcept = default; - - /** - * @brief Default move assignment operator. - * @return This resource handle. - */ - resource &operator=(resource &&) noexcept = default; - - /** - * @brief Copy assignment operator from foreign handle. - * @tparam Other Type of resource managed by the received handle. - * @param other The handle to copy from. - * @return This resource handle. - */ - template - requires (!stl::same_as && stl::constructible_from) - resource &operator=(const resource &other) noexcept { - value = other.value; - return *this; - } - - /** - * @brief Move assignment operator from foreign handle. - * @tparam Other Type of resource managed by the received handle. - * @param other The handle to move from. - * @return This resource handle. - */ - template - requires (!stl::same_as && stl::constructible_from) - resource &operator=(resource &&other) noexcept { - value = stl::move(other.value); - return *this; - } - - /** - * @brief Exchanges the content with that of a given resource. - * @param other Resource to exchange the content with. - */ - void swap(resource &other) noexcept { - using stl::swap; - swap(value, other.value); - } - - /** - * @brief Returns a reference to the managed resource. - * - * @warning - * The behavior is undefined if the handle doesn't contain a resource. - * - * @return A reference to the managed resource. - */ - [[nodiscard]] element_type &operator*() const noexcept { - return *value; - } - - /*! @copydoc operator* */ - [[nodiscard]] operator element_type &() const noexcept { - return *value; - } - - /** - * @brief Returns a pointer to the managed resource. - * @return A pointer to the managed resource. - */ - [[nodiscard]] element_type *operator->() const noexcept { - return value.get(); - } - - /** - * @brief Returns true if a handle contains a resource, false otherwise. - * @return True if the handle contains a resource, false otherwise. - */ - [[nodiscard]] explicit operator bool() const noexcept { - return static_cast(value); - } - - /** - * @brief Compares two handles. - * @tparam Other Type of resource managed by the other handle. - * @param other A valid handle. - * @return True if both handles refer to the same resource, false otherwise. - */ - template - [[nodiscard]] bool operator==(const resource &other) const noexcept { - return (value == other.value); - } - - /** - * @brief Lexicographically compares two handles. - * @tparam Other Type of resource managed by the other handle. - * @param other A valid handle. - * @return The relative order between the two handles. - */ - template - [[nodiscard]] auto operator<=>(const resource &other) const noexcept { - return (value <=> other.value); - } - - /*! @brief Releases the ownership of the managed resource. */ - void reset() { - value.reset(); - } - - /** - * @brief Replaces the managed resource. - * @param other A handle to a resource. - */ - void reset(handle_type other) { - value = stl::move(other); - } - - /** - * @brief Returns the underlying resource handle. - * @return The underlying resource handle. - */ - [[nodiscard]] handle_type handle() const noexcept { - return value; - } - -private: - handle_type value; -}; - -} // namespace entt - -#endif diff --git a/include/entt/signal/delegate.hpp b/include/entt/signal/delegate.hpp deleted file mode 100644 index 0ecedcd..0000000 --- a/include/entt/signal/delegate.hpp +++ /dev/null @@ -1,314 +0,0 @@ -#ifndef ENTT_SIGNAL_DELEGATE_HPP -#define ENTT_SIGNAL_DELEGATE_HPP - -#include "../config/config.h" -#include "../core/type_traits.hpp" -#include "../stl/cstddef.hpp" -#include "../stl/functional.hpp" -#include "../stl/tuple.hpp" -#include "../stl/type_traits.hpp" -#include "../stl/utility.hpp" -#include "fwd.hpp" - -namespace entt { - -/*! @cond ENTT_INTERNAL */ -namespace internal { - -template -auto function_pointer(Ret (*)(Args...)) -> Ret (*)(Args...); - -template -auto function_pointer(Ret (*)(Type, Args...), Other &&) -> Ret (*)(Args...); - -template -auto function_pointer(Ret (Class::*)(Args...), Other &&...) -> Ret (*)(Args...); - -template -auto function_pointer(Ret (Class::*)(Args...) const, Other &&...) -> Ret (*)(Args...); - -template -requires stl::is_member_object_pointer_v -auto function_pointer(Type Class::*, Other &&...) -> Type (*)(); - -template -using function_pointer_t = decltype(function_pointer(stl::declval()...)); - -template -[[nodiscard]] ENTT_CONSTEVAL auto index_sequence_for(Ret (*)(Args...)) { - return stl::index_sequence_for{}; -} - -} // namespace internal -/*! @endcond */ - -/** - * @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 use to send around functions and members. - * - * Unmanaged delegate for function pointers and members. Users of this class are - * in charge of disconnecting instances before deleting them. - * - * A delegate can be used as a general purpose invoker without memory overhead - * for free functions possibly with payloads and bound or unbound members. - * - * @tparam Ret Return type of a function type. - * @tparam Args Types of arguments of a function type. - */ -template -class delegate { - using return_type = stl::remove_const_t; - using delegate_type = return_type(const void *, Args...); - - template - [[nodiscard]] auto wrap(stl::index_sequence) noexcept { - return [](const void *, Args... args) -> return_type { - [[maybe_unused]] const auto arguments = stl::forward_as_tuple(stl::forward(args)...); - [[maybe_unused]] constexpr auto offset = !stl::is_invocable_r_v>...> * (sizeof...(Args) - sizeof...(Index)); - return static_cast(stl::invoke(Candidate, stl::forward>>(stl::get(arguments))...)); - }; - } - - template - [[nodiscard]] auto wrap(Type &, stl::index_sequence) noexcept { - return [](const void *payload, Args... args) -> return_type { - Type *curr = static_cast(const_cast *>(payload)); - [[maybe_unused]] const auto arguments = stl::forward_as_tuple(stl::forward(args)...); - [[maybe_unused]] constexpr auto offset = !stl::is_invocable_r_v>...> * (sizeof...(Args) - sizeof...(Index)); - return static_cast(stl::invoke(Candidate, *curr, stl::forward>>(stl::get(arguments))...)); - }; - } - - template - [[nodiscard]] auto wrap(Type *, stl::index_sequence) noexcept { - return [](const void *payload, Args... args) -> return_type { - Type *curr = static_cast(const_cast *>(payload)); - [[maybe_unused]] const auto arguments = stl::forward_as_tuple(stl::forward(args)...); - [[maybe_unused]] constexpr auto offset = !stl::is_invocable_r_v>...> * (sizeof...(Args) - sizeof...(Index)); - return static_cast(stl::invoke(Candidate, curr, stl::forward>>(stl::get(arguments))...)); - }; - } - -public: - /*! @brief Function type of the contained target. */ - using function_type = Ret(const void *, Args...); - /*! @brief Function type of the delegate. */ - using type = Ret(Args...); - /*! @brief Return type of the delegate. */ - using result_type = Ret; - - /*! @brief Default constructor. */ - delegate() noexcept = default; - - /** - * @brief Constructs a delegate with a given object or payload, if any. - * @tparam Candidate Function or member to connect to the delegate. - * @tparam Type Type of class or type of payload, if any. - * @param value_or_instance Optional valid object that fits the purpose. - */ - template - delegate(connect_arg_t, Type &&...value_or_instance) noexcept { - connect(stl::forward(value_or_instance)...); - } - - /** - * @brief Constructs a delegate and connects an user defined function with - * optional payload. - * @param function Function to connect to the delegate. - * @param payload User defined arbitrary data. - */ - delegate(function_type *function, const void *payload = nullptr) noexcept { - connect(function, payload); - } - - /** - * @brief Connects a free function or an unbound member to a delegate. - * @tparam Candidate Function or member to connect to the delegate. - */ - template - void connect() noexcept { - instance = nullptr; - - if constexpr(stl::is_invocable_r_v) { - fn = [](const void *, Args... args) -> return_type { - return Ret(stl::invoke(Candidate, stl::forward(args)...)); - }; - } else if constexpr(stl::is_member_pointer_v) { - fn = wrap(internal::index_sequence_for>>(internal::function_pointer_t{})); - } else { - fn = wrap(internal::index_sequence_for(internal::function_pointer_t{})); - } - } - - /** - * @brief Connects a free function with payload or a bound member to a - * delegate. - * - * The delegate isn't responsible for the connected object or the payload. - * Users must always guarantee that the lifetime of the instance overcomes - * the one of the delegate.
- * When used to connect a free function with payload, its signature must be - * such that the instance is the first argument before the ones used to - * define the delegate itself. - * - * @tparam Candidate Function or member to connect to the delegate. - * @tparam Type Type of class or type of payload. - * @param value_or_instance A valid reference that fits the purpose. - */ - template - void connect(Type &value_or_instance) noexcept { - instance = &value_or_instance; - - if constexpr(stl::is_invocable_r_v) { - fn = [](const void *payload, Args... args) -> return_type { - Type *curr = static_cast(const_cast *>(payload)); - return Ret(stl::invoke(Candidate, *curr, stl::forward(args)...)); - }; - } else { - fn = wrap(value_or_instance, internal::index_sequence_for(internal::function_pointer_t{})); - } - } - - /** - * @brief Connects a free function with payload or a bound member to a - * delegate. - * - * @sa connect(Type &) - * - * @tparam Candidate Function or member to connect to the delegate. - * @tparam Type Type of class or type of payload. - * @param value_or_instance A valid pointer that fits the purpose. - */ - template - void connect(Type *value_or_instance) noexcept { - instance = value_or_instance; - - if constexpr(stl::is_invocable_r_v) { - fn = [](const void *payload, Args... args) -> return_type { - Type *curr = static_cast(const_cast *>(payload)); - return Ret(stl::invoke(Candidate, curr, stl::forward(args)...)); - }; - } else { - fn = wrap(value_or_instance, internal::index_sequence_for(internal::function_pointer_t{})); - } - } - - /** - * @brief Connects an user defined function with optional payload to a - * delegate. - * - * The delegate isn't responsible for the connected object or the payload. - * Users must always guarantee that the lifetime of an instance overcomes - * the one of the delegate.
- * The payload is returned as the first argument to the target function in - * all cases. - * - * @param function Function to connect to the delegate. - * @param payload User defined arbitrary data. - */ - void connect(function_type *function, const void *payload = nullptr) noexcept { - ENTT_ASSERT(function != nullptr, "Uninitialized function pointer"); - instance = payload; - fn = function; - } - - /** - * @brief Resets a delegate. - * - * After a reset, a delegate cannot be invoked anymore. - */ - void reset() noexcept { - instance = nullptr; - fn = nullptr; - } - - /** - * @brief Returns a pointer to the stored callable function target, if any. - * @return An opaque pointer to the stored callable function target. - */ - [[nodiscard]] function_type *target() const noexcept { - return fn; - } - - /** - * @brief Returns the instance or the payload linked to a delegate, if any. - * @return An opaque pointer to the underlying data. - */ - [[nodiscard]] const void *data() const noexcept { - return instance; - } - - /** - * @brief Triggers a delegate. - * - * The delegate invokes the underlying function and returns the result. - * - * @warning - * Attempting to trigger an invalid delegate results in undefined - * behavior. - * - * @param args Arguments to use to invoke the underlying function. - * @return The value returned by the underlying function. - */ - Ret operator()(Args... args) const { - ENTT_ASSERT(static_cast(*this), "Uninitialized delegate"); - return fn(instance, stl::forward(args)...); - } - - /** - * @brief Checks whether a delegate actually stores a listener. - * @return False if the delegate is empty, true otherwise. - */ - [[nodiscard]] explicit operator bool() const noexcept { - // no need to also test instance - return !(fn == nullptr); - } - - /** - * @brief Compares the contents of two delegates. - * @param other Delegate with which to compare. - * @return False if the two contents differ, true otherwise. - */ - [[nodiscard]] bool operator==(const delegate &other) const noexcept { - return fn == other.fn && instance == other.instance; - } - -private: - const void *instance{}; - delegate_type *fn{}; -}; - -/** - * @brief Deduction guide. - * @tparam Candidate Function or member to connect to the delegate. - */ -template -delegate(connect_arg_t) -> delegate>>; - -/** - * @brief Deduction guide. - * @tparam Candidate Function or member to connect to the delegate. - * @tparam Type Type of class or type of payload. - */ -template -delegate(connect_arg_t, Type &&) -> delegate>>; - -/** - * @brief Deduction guide. - * @tparam Ret Return type of a function type. - * @tparam Args Types of arguments of a function type. - */ -template -delegate(Ret (*)(const void *, Args...), const void * = nullptr) -> delegate; - -} // namespace entt - -#endif diff --git a/include/entt/signal/dispatcher.hpp b/include/entt/signal/dispatcher.hpp deleted file mode 100644 index 3a3ccee..0000000 --- a/include/entt/signal/dispatcher.hpp +++ /dev/null @@ -1,391 +0,0 @@ -#ifndef ENTT_SIGNAL_DISPATCHER_HPP -#define ENTT_SIGNAL_DISPATCHER_HPP - -#include "../container/dense_map.hpp" -#include "../core/compressed_pair.hpp" -#include "../core/concepts.hpp" -#include "../core/fwd.hpp" -#include "../core/type_info.hpp" -#include "../stl/cstddef.hpp" -#include "../stl/functional.hpp" -#include "../stl/memory.hpp" -#include "../stl/type_traits.hpp" -#include "../stl/utility.hpp" -#include "../stl/vector.hpp" -#include "fwd.hpp" -#include "sigh.hpp" - -namespace entt { - -/*! @cond ENTT_INTERNAL */ -namespace internal { - -struct basic_dispatcher_handler { - virtual ~basic_dispatcher_handler() = default; - virtual void publish() = 0; - virtual void disconnect(void *) = 0; - virtual void clear() noexcept = 0; - [[nodiscard]] virtual stl::size_t size() const noexcept = 0; -}; - -template -class dispatcher_handler final: public basic_dispatcher_handler { - using alloc_traits = stl::allocator_traits; - using signal_type = sigh; - using container_type = stl::vector>; - -public: - using allocator_type = Allocator; - - dispatcher_handler(const allocator_type &allocator) - : signal{allocator}, - events{allocator} {} - - void publish() override { - container_type other{}; - other.swap(events); - - for(auto &&elem: other) { - signal.publish(elem); - } - } - - void disconnect(void *instance) override { - bucket().disconnect(instance); - } - - void clear() noexcept override { - events.clear(); - } - - [[nodiscard]] auto bucket() noexcept { - return typename signal_type::sink_type{signal}; - } - - void trigger(Type &event) { - signal.publish(event); - } - - template - void enqueue(Args &&...args) { - if constexpr(stl::is_aggregate_v && (sizeof...(Args) != 0u || !stl::is_default_constructible_v)) { - events.push_back(Type{stl::forward(args)...}); - } else { - events.emplace_back(stl::forward(args)...); - } - } - - [[nodiscard]] stl::size_t size() const noexcept override { - return events.size(); - } - -private: - signal_type signal; - container_type events; -}; - -} // namespace internal -/*! @endcond */ - -/** - * @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 `Type`, listeners are such that they can be invoked with an argument of - * type `Type &`, no matter what the return type is. - * - * The dispatcher creates instances of the `sigh` class internally. Refer to the - * documentation of the latter for more details. - * - * @tparam Allocator Type of allocator used to manage memory and elements. - */ -template -class basic_dispatcher { - template - using handler_type = internal::dispatcher_handler; - - using key_type = id_type; - // stl::shared_ptr because of its type erased allocator which is useful here - using mapped_type = stl::shared_ptr; - - using alloc_traits = stl::allocator_traits; - using container_allocator = alloc_traits::template rebind_alloc>; - using container_type = dense_map, container_allocator>; - - template - [[nodiscard]] handler_type &assure(const id_type id) { - auto &&ptr = pools.first()[id]; - - if(!ptr) { - const auto &allocator = get_allocator(); - ptr = stl::allocate_shared>(allocator, allocator); - } - - return static_cast &>(*ptr); - } - - template - [[nodiscard]] const handler_type *assure(const id_type id) const { - if(auto it = pools.first().find(id); it != pools.first().cend()) { - return static_cast *>(it->second.get()); - } - - return nullptr; - } - -public: - /*! @brief Allocator type. */ - using allocator_type = Allocator; - /*! @brief Unsigned integer type. */ - using size_type = stl::size_t; - - /*! @brief Default constructor. */ - basic_dispatcher() - : basic_dispatcher{allocator_type{}} {} - - /** - * @brief Constructs a dispatcher with a given allocator. - * @param allocator The allocator to use. - */ - explicit basic_dispatcher(const allocator_type &allocator) - : pools{allocator, allocator} {} - - /*! @brief Default copy constructor, deleted on purpose. */ - basic_dispatcher(const basic_dispatcher &) = delete; - - /** - * @brief Move constructor. - * @param other The instance to move from. - */ - basic_dispatcher(basic_dispatcher &&other) noexcept - : pools{stl::move(other.pools)} {} - - /** - * @brief Allocator-extended move constructor. - * @param other The instance to move from. - * @param allocator The allocator to use. - */ - basic_dispatcher(basic_dispatcher &&other, const allocator_type &allocator) - : pools{container_type{stl::move(other.pools.first()), allocator}, allocator} { - ENTT_ASSERT(alloc_traits::is_always_equal::value || get_allocator() == other.get_allocator(), "Copying a dispatcher is not allowed"); - } - - /*! @brief Default destructor. */ - ~basic_dispatcher() = default; - - /** - * @brief Default copy assignment operator, deleted on purpose. - * @return This dispatcher. - */ - basic_dispatcher &operator=(const basic_dispatcher &) = delete; - - /** - * @brief Move assignment operator. - * @param other The instance to move from. - * @return This dispatcher. - */ - basic_dispatcher &operator=(basic_dispatcher &&other) noexcept { - ENTT_ASSERT(alloc_traits::is_always_equal::value || get_allocator() == other.get_allocator(), "Copying a dispatcher is not allowed"); - swap(other); - return *this; - } - - /** - * @brief Exchanges the contents with those of a given dispatcher. - * @param other Dispatcher to exchange the content with. - */ - void swap(basic_dispatcher &other) noexcept { - using stl::swap; - swap(pools, other.pools); - } - - /** - * @brief Returns the associated allocator. - * @return The associated allocator. - */ - [[nodiscard]] constexpr allocator_type get_allocator() const noexcept { - return pools.second(); - } - - /** - * @brief Returns the number of pending events for a given type. - * @tparam Type Type of event for which to return the count. - * @param id Name used to map the event queue within the dispatcher. - * @return The number of pending events for the given type. - */ - template - [[nodiscard]] size_type size(const id_type id = type_hash::value()) const noexcept { - const auto *cpool = assure>(id); - return cpool ? cpool->size() : 0u; - } - - /** - * @brief Returns the total number of pending events. - * @return The total number of pending events. - */ - [[nodiscard]] size_type size() const noexcept { - size_type count{}; - - for(auto &&cpool: pools.first()) { - count += cpool.second->size(); - } - - return count; - } - - /** - * @brief Returns a sink object for the given event and queue. - * - * A sink is an opaque object used to connect listeners to events. - * - * The function type for a listener is _compatible_ with: - * - * @code{.cpp} - * void(Type &); - * @endcode - * - * The order of invocation of the listeners isn't guaranteed. - * - * @sa sink - * - * @tparam Type Type of event of which to get the sink. - * @param id Name used to map the event queue within the dispatcher. - * @return A temporary sink object. - */ - template - [[nodiscard]] auto sink(const id_type id = type_hash::value()) { - return assure(id).bucket(); - } - - /** - * @brief Triggers an immediate event of a given type. - * @tparam Type Type of event to trigger. - * @param value An instance of the given type of event. - */ - template - void trigger(Type value) { - trigger(type_hash>::value(), value); - } - - /** - * @brief Triggers an immediate event on a queue of a given type. - * @tparam Type Type of event to trigger. - * @param value An instance of the given type of event. - * @param id Name used to map the event queue within the dispatcher. - */ - template - void trigger(const id_type id, Type value) { - assure>(id).trigger(value); - } - - /** - * @brief Enqueues an event of the given type. - * @tparam Type Type of event to enqueue. - * @tparam Args Types of arguments to use to construct the event. - * @param args Arguments to use to construct the event. - */ - template - void enqueue(Args &&...args) { - enqueue_hint(type_hash::value(), stl::forward(args)...); - } - - /** - * @brief Enqueues an event of the given type. - * @tparam Type Type of event to enqueue. - * @param value An instance of the given type of event. - */ - template - void enqueue(Type &&value) { - enqueue_hint(type_hash>::value(), stl::forward(value)); - } - - /** - * @brief Enqueues an event of the given type. - * @tparam Type Type of event to enqueue. - * @tparam Args Types of arguments to use to construct the event. - * @param id Name used to map the event queue within the dispatcher. - * @param args Arguments to use to construct the event. - */ - template - void enqueue_hint(const id_type id, Args &&...args) { - assure(id).enqueue(stl::forward(args)...); - } - - /** - * @brief Enqueues an event of the given type. - * @tparam Type Type of event to enqueue. - * @param id Name used to map the event queue within the dispatcher. - * @param value An instance of the given type of event. - */ - template - void enqueue_hint(const id_type id, Type &&value) { - assure>(id).enqueue(stl::forward(value)); - } - - /** - * @brief Utility function to disconnect everything related to a given value - * or instance from a dispatcher. - * @tparam Type Type of class or type of payload. - * @param value_or_instance A valid object that fits the purpose. - */ - template - void disconnect(Type &value_or_instance) { - disconnect(&value_or_instance); - } - - /** - * @brief Utility function to disconnect everything related to a given value - * or instance from a dispatcher. - * @tparam Type Type of class or type of payload. - * @param value_or_instance A valid object that fits the purpose. - */ - template - void disconnect(Type *value_or_instance) { - for(auto &&cpool: pools.first()) { - cpool.second->disconnect(value_or_instance); - } - } - - /** - * @brief Discards all the events stored so far in a given queue. - * @tparam Type Type of event to discard. - * @param id Name used to map the event queue within the dispatcher. - */ - template - void clear(const id_type id = type_hash::value()) { - assure(id).clear(); - } - - /*! @brief Discards all the events queued so far. */ - void clear() noexcept { - for(auto &&cpool: pools.first()) { - cpool.second->clear(); - } - } - - /** - * @brief Delivers all the pending events of a given queue. - * @tparam Type Type of event to send. - * @param id Name used to map the event queue within the dispatcher. - */ - template - void update(const id_type id = type_hash::value()) { - assure(id).publish(); - } - - /*! @brief Delivers all the pending events. */ - void update() const { - for(auto &&cpool: pools.first()) { - cpool.second->publish(); - } - } - -private: - compressed_pair pools; -}; - -} // namespace entt - -#endif diff --git a/include/entt/signal/emitter.hpp b/include/entt/signal/emitter.hpp deleted file mode 100644 index 1ef4951..0000000 --- a/include/entt/signal/emitter.hpp +++ /dev/null @@ -1,181 +0,0 @@ -#ifndef ENTT_SIGNAL_EMITTER_HPP -#define ENTT_SIGNAL_EMITTER_HPP - -#include "../container/dense_map.hpp" -#include "../core/compressed_pair.hpp" -#include "../core/fwd.hpp" -#include "../core/type_info.hpp" -#include "../stl/functional.hpp" -#include "../stl/type_traits.hpp" -#include "../stl/utility.hpp" -#include "fwd.hpp" - -namespace entt { - -/** - * @brief General purpose event emitter. - * - * To create an emitter type, derived classes must inherit from the base as: - * - * @code{.cpp} - * struct my_emitter: emitter { - * // ... - * } - * @endcode - * - * Handlers for the different events are created internally on the fly. It's not - * required to specify in advance the full list of accepted events.
- * Moreover, whenever an event is published, an emitter also passes a reference - * to itself to its listeners. - * - * @tparam Derived Emitter type. - * @tparam Allocator Type of allocator used to manage memory and elements. - */ -template -class emitter { - using key_type = id_type; - using mapped_type = stl::function; - - using alloc_traits = stl::allocator_traits; - using container_allocator = alloc_traits::template rebind_alloc>; - using container_type = dense_map, container_allocator>; - -public: - /*! @brief Allocator type. */ - using allocator_type = Allocator; - /*! @brief Unsigned integer type. */ - using size_type = stl::size_t; - - /*! @brief Default constructor. */ - emitter() - : emitter{allocator_type{}} {} - - /** - * @brief Constructs an emitter with a given allocator. - * @param allocator The allocator to use. - */ - explicit emitter(const allocator_type &allocator) - : handlers{allocator, allocator} {} - - /*! @brief Default copy constructor, deleted on purpose. */ - emitter(const emitter &) = delete; - - /** - * @brief Move constructor. - * @param other The instance to move from. - */ - emitter(emitter &&other) noexcept - : handlers{stl::move(other.handlers)} {} - - /** - * @brief Allocator-extended move constructor. - * @param other The instance to move from. - * @param allocator The allocator to use. - */ - emitter(emitter &&other, const allocator_type &allocator) - : handlers{container_type{stl::move(other.handlers.first()), allocator}, allocator} { - ENTT_ASSERT(alloc_traits::is_always_equal::value || handlers.second() == other.handlers.second(), "Copying an emitter is not allowed"); - } - - /*! @brief Default destructor. */ - virtual ~emitter() { - static_assert(stl::is_base_of_v, Derived>, "Invalid emitter type"); - } - - /** - * @brief Default copy assignment operator, deleted on purpose. - * @return This emitter. - */ - emitter &operator=(const emitter &) = delete; - - /** - * @brief Move assignment operator. - * @param other The instance to move from. - * @return This emitter. - */ - emitter &operator=(emitter &&other) noexcept { - ENTT_ASSERT(alloc_traits::is_always_equal::value || handlers.second() == other.handlers.second(), "Copying an emitter is not allowed"); - swap(other); - return *this; - } - - /** - * @brief Exchanges the contents with those of a given emitter. - * @param other Emitter to exchange the content with. - */ - void swap(emitter &other) noexcept { - using stl::swap; - swap(handlers, other.handlers); - } - - /** - * @brief Returns the associated allocator. - * @return The associated allocator. - */ - [[nodiscard]] constexpr allocator_type get_allocator() const noexcept { - return handlers.second(); - } - - /** - * @brief Publishes a given event. - * @tparam Type Type of event to trigger. - * @param value An instance of the given type of event. - */ - template - void publish(Type value) { - if(const auto id = type_id().hash(); handlers.first().contains(id)) { - handlers.first()[id](&value); - } - } - - /** - * @brief Registers a listener with the event emitter. - * @tparam Type Type of event to which to connect the listener. - * @param func The listener to register. - */ - template - void on(stl::function func) { - handlers.first().insert_or_assign(type_id().hash(), [func = stl::move(func), this](void *value) { - func(*static_cast(value), static_cast(*this)); - }); - } - - /** - * @brief Disconnects a listener from the event emitter. - * @tparam Type Type of event of the listener. - */ - template - void erase() { - handlers.first().erase(type_hash>::value()); - } - - /*! @brief Disconnects all the listeners. */ - void clear() noexcept { - handlers.first().clear(); - } - - /** - * @brief Checks if there are listeners registered for the specific event. - * @tparam Type Type of event to test. - * @return True if there are no listeners registered, false otherwise. - */ - template - [[nodiscard]] bool contains() const { - return handlers.first().contains(type_hash>::value()); - } - - /** - * @brief Checks if there are listeners registered with the event emitter. - * @return True if there are no listeners registered, false otherwise. - */ - [[nodiscard]] bool empty() const noexcept { - return handlers.first().empty(); - } - -private: - compressed_pair handlers; -}; - -} // namespace entt - -#endif diff --git a/include/entt/signal/fwd.hpp b/include/entt/signal/fwd.hpp deleted file mode 100644 index 4543622..0000000 --- a/include/entt/signal/fwd.hpp +++ /dev/null @@ -1,46 +0,0 @@ -#ifndef ENTT_SIGNAL_FWD_HPP -#define ENTT_SIGNAL_FWD_HPP - -#include "../stl/memory.hpp" - -namespace entt { - -template -class delegate; - -template> -class basic_dispatcher; - -template> -class emitter; - -class connection; - -struct scoped_connection; - -template -class sink; - -template> -class sigh; - -/*! @brief Alias declaration for the most common use case. */ -using dispatcher = basic_dispatcher<>; - -/*! @brief Disambiguation tag for constructors and the like. */ -template -struct connect_arg_t { - /*! @brief Default constructor. */ - explicit connect_arg_t() = default; -}; - -/** - * @brief Constant of type connect_arg_t used to disambiguate calls. - * @tparam Candidate Element to connect (likely a free or member function). - */ -template -inline constexpr connect_arg_t connect_arg{}; - -} // namespace entt - -#endif diff --git a/include/entt/signal/sigh.hpp b/include/entt/signal/sigh.hpp deleted file mode 100644 index fb05a36..0000000 --- a/include/entt/signal/sigh.hpp +++ /dev/null @@ -1,573 +0,0 @@ -#ifndef ENTT_SIGNAL_SIGH_HPP -#define ENTT_SIGNAL_SIGH_HPP - -#include "../stl/cstddef.hpp" -#include "../stl/memory.hpp" -#include "../stl/type_traits.hpp" -#include "../stl/utility.hpp" -#include "../stl/vector.hpp" -#include "delegate.hpp" -#include "fwd.hpp" - -namespace entt { - -/** - * @brief Sink class. - * - * Primary template isn't defined on purpose. All the specializations give a - * compile-time error unless the template parameter is a function type. - * - * @tparam Type A valid signal handler type. - */ -template -class sink; - -/** - * @brief Unmanaged signal handler. - * - * Primary template isn't defined on purpose. All the specializations give a - * compile-time error unless the template parameter is a function type. - * - * @tparam Type A valid function type. - * @tparam Allocator Type of allocator used to manage memory and elements. - */ -template -class sigh; - -/** - * @brief Unmanaged signal handler. - * - * It works directly with references 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 to use later to notify a bunch of listeners. - * * Collecting results from a set of functions like in a voting system. - * - * @tparam Ret Return type of a function type. - * @tparam Args Types of arguments of a function type. - * @tparam Allocator Type of allocator used to manage memory and elements. - */ -template -class sigh { - friend class sink>; - - using alloc_traits = stl::allocator_traits; - using delegate_type = delegate; - using container_type = stl::vector>; - -public: - /*! @brief Allocator type. */ - using allocator_type = Allocator; - /*! @brief Unsigned integer type. */ - using size_type = stl::size_t; - /*! @brief Sink type. */ - using sink_type = sink>; - - /*! @brief Default constructor. */ - sigh() noexcept(noexcept(allocator_type{})) - : sigh{allocator_type{}} {} - - /** - * @brief Constructs a signal handler with a given allocator. - * @param allocator The allocator to use. - */ - explicit sigh(const allocator_type &allocator) noexcept - : calls{allocator} {} - - /** - * @brief Copy constructor. - * @param other The instance to copy from. - */ - sigh(const sigh &other) - : calls{other.calls} {} - - /** - * @brief Allocator-extended copy constructor. - * @param other The instance to copy from. - * @param allocator The allocator to use. - */ - sigh(const sigh &other, const allocator_type &allocator) - : calls{other.calls, allocator} {} - - /** - * @brief Move constructor. - * @param other The instance to move from. - */ - sigh(sigh &&other) noexcept - : calls{stl::move(other.calls)} {} - - /** - * @brief Allocator-extended move constructor. - * @param other The instance to move from. - * @param allocator The allocator to use. - */ - sigh(sigh &&other, const allocator_type &allocator) - : calls{stl::move(other.calls), allocator} {} - - /*! @brief Default destructor. */ - ~sigh() = default; - - /** - * @brief Copy assignment operator. - * @param other The instance to copy from. - * @return This signal handler. - */ - sigh &operator=(const sigh &other) { - calls = other.calls; - return *this; - } - - /** - * @brief Move assignment operator. - * @param other The instance to move from. - * @return This signal handler. - */ - sigh &operator=(sigh &&other) noexcept { - swap(other); - return *this; - } - - /** - * @brief Exchanges the contents with those of a given signal handler. - * @param other Signal handler to exchange the content with. - */ - void swap(sigh &other) noexcept { - using stl::swap; - swap(calls, other.calls); - } - - /** - * @brief Returns the associated allocator. - * @return The associated allocator. - */ - [[nodiscard]] constexpr allocator_type get_allocator() const noexcept { - return calls.get_allocator(); - } - - /** - * @brief Number of listeners connected to the signal. - * @return Number of listeners currently connected. - */ - [[nodiscard]] size_type size() const 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. - */ - [[nodiscard]] bool empty() const noexcept { - return calls.empty(); - } - - /** - * @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) { - calls[pos - 1u](args...); - } - } - - /** - * @brief Collects return values from the listeners. - * - * The collector must expose a call operator with the following properties: - * - * * The return type is either `void` or such that it's convertible to - * `bool`. In the second case, a true value will stop the iteration. - * * The list of parameters is empty if `Ret` is `void`, otherwise it - * contains a single element such that `Ret` is convertible to it. - * - * @tparam Func Type of collector to use, if any. - * @param func A valid function object. - * @param args Arguments to use to invoke listeners. - */ - template - void collect(Func func, Args... args) const { - for(auto pos = calls.size(); pos; --pos) { - if constexpr(stl::is_void_v || !stl::is_invocable_v) { - calls[pos - 1u](args...); - - if constexpr(stl::is_invocable_r_v) { - if(func()) { - break; - } - } else { - func(); - } - } else if constexpr(stl::is_invocable_r_v) { - if(func(calls[pos - 1u](args...))) { - break; - } - } else { - func(calls[pos - 1u](args...)); - } - } - } - -private: - container_type calls; -}; - -/** - * @brief Connection class. - * - * Opaque object the aim of which is to allow users to release an already - * established connection without having to keep a reference to the signal or - * the sink that generated it. - */ -class connection { - template - friend class sink; - - connection(delegate fn, void *ref) - : disconnect{fn}, signal{ref} {} - -public: - /*! @brief Default constructor. */ - connection() - : signal{} {} - - /** - * @brief Checks whether a connection is properly initialized. - * @return True if the connection is properly initialized, false otherwise. - */ - [[nodiscard]] explicit operator bool() const noexcept { - return static_cast(disconnect); - } - - /*! @brief Breaks the connection. */ - void release() { - if(disconnect) { - disconnect(signal); - disconnect.reset(); - } - } - -private: - delegate disconnect; - void *signal; -}; - -/** - * @brief Scoped connection class. - * - * Opaque object the aim of which is to allow users to release an already - * established connection without having to keep a reference to the signal or - * the sink that generated it.
- * A scoped connection automatically breaks the link between the two objects - * when it goes out of scope. - */ -struct scoped_connection { - /*! @brief Default constructor. */ - scoped_connection() = default; - - /** - * @brief Constructs a scoped connection from a basic connection. - * @param other A valid connection object. - */ - scoped_connection(const connection &other) - : conn{other} {} - - /*! @brief Default copy constructor, deleted on purpose. */ - scoped_connection(const scoped_connection &) = delete; - - /** - * @brief Move constructor. - * @param other The scoped connection to move from. - */ - scoped_connection(scoped_connection &&other) noexcept - : conn{stl::exchange(other.conn, {})} {} - - /*! @brief Automatically breaks the link on destruction. */ - ~scoped_connection() { - conn.release(); - } - - /** - * @brief Default copy assignment operator, deleted on purpose. - * @return This scoped connection. - */ - scoped_connection &operator=(const scoped_connection &) = delete; - - /** - * @brief Move assignment operator. - * @param other The scoped connection to move from. - * @return This scoped connection. - */ - scoped_connection &operator=(scoped_connection &&other) noexcept { - conn = stl::exchange(other.conn, {}); - return *this; - } - - /** - * @brief Acquires a connection. - * @param other The connection object to acquire. - * @return This scoped connection. - */ - scoped_connection &operator=(connection other) { - conn = other; - return *this; - } - - /** - * @brief Checks whether a scoped connection is properly initialized. - * @return True if the connection is properly initialized, false otherwise. - */ - [[nodiscard]] explicit operator bool() const noexcept { - return static_cast(conn); - } - - /*! @brief Breaks the connection. */ - void release() { - conn.release(); - } - -private: - connection conn; -}; - -/** - * @brief Sink class. - * - * A sink is used to connect listeners to signals and to disconnect them.
- * 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 the class. - * - * @warning - * Lifetime of a sink must not overcome that of the signal to which it refers. - * In any other case, attempting to use a sink results in undefined behavior. - * - * @tparam Ret Return type of a function type. - * @tparam Args Types of arguments of a function type. - * @tparam Allocator Type of allocator used to manage memory and elements. - */ -template -class sink> { - using signal_type = sigh; - using delegate_type = signal_type::delegate_type; - using difference_type = signal_type::container_type::difference_type; - - template - static void release(Type value_or_instance, void *signal) { - sink{*static_cast(signal)}.disconnect(value_or_instance); - } - - template - static void release(void *signal) { - sink{*static_cast(signal)}.disconnect(); - } - - template - void disconnect_if(Func callback) { - auto &ref = signal_or_assert(); - - for(auto pos = ref.calls.size(); pos; --pos) { - if(auto &elem = ref.calls[pos - 1u]; callback(elem)) { - elem = stl::move(ref.calls.back()); - ref.calls.pop_back(); - } - } - } - - [[nodiscard]] auto &signal_or_assert() const noexcept { - ENTT_ASSERT(signal != nullptr, "Invalid pointer to signal"); - return *signal; - } - -public: - /*! @brief Constructs an invalid sink. */ - sink() noexcept - : signal{} {} - - /** - * @brief Constructs a sink that is allowed to modify a given signal. - * @param ref A valid reference to a signal object. - */ - sink(sigh &ref) noexcept - : signal{&ref} {} - - /** - * @brief Returns false if at least a listener is connected to the sink. - * @return True if the sink has no listeners connected, false otherwise. - */ - [[nodiscard]] bool empty() const noexcept { - return signal_or_assert().calls.empty(); - } - - /** - * @brief Connects a free function or an unbound member to a signal. - * @tparam Candidate Function or member to connect to the signal. - * @return A properly initialized connection object. - */ - template - connection connect() { - disconnect(); - - delegate_type call{}; - call.template connect(); - signal_or_assert().calls.push_back(stl::move(call)); - - delegate conn{}; - conn.template connect<&release>(); - return {conn, signal}; - } - - /** - * @brief Connects a free function with payload or a bound member to a - * signal. - * - * The signal isn't responsible for the connected object or the payload. - * Users must always guarantee that the lifetime of the instance overcomes - * the one of the signal.
- * When used to connect a free function with payload, its signature must be - * such that the instance is the first argument before the ones used to - * define the signal itself. - * - * @tparam Candidate Function or member to connect to the signal. - * @tparam Type Type of class or type of payload. - * @param value_or_instance A valid reference that fits the purpose. - * @return A properly initialized connection object. - */ - template - connection connect(Type &value_or_instance) { - disconnect(value_or_instance); - - delegate_type call{}; - call.template connect(value_or_instance); - signal_or_assert().calls.push_back(stl::move(call)); - - delegate conn{}; - conn.template connect<&release>(value_or_instance); - return {conn, signal}; - } - - /** - * @brief Connects a free function with payload or a bound member to a - * signal. - * - * @sa connect(Type &) - * - * @tparam Candidate Function or member to connect to the signal. - * @tparam Type Type of class or type of payload. - * @param value_or_instance A valid pointer that fits the purpose. - * @return A properly initialized connection object. - */ - template - connection connect(Type *value_or_instance) { - disconnect(value_or_instance); - - delegate_type call{}; - call.template connect(value_or_instance); - signal_or_assert().calls.push_back(stl::move(call)); - - delegate conn{}; - conn.template connect<&release>(value_or_instance); - return {conn, signal}; - } - - /** - * @brief Disconnects a free function or an unbound member from a signal. - * @tparam Candidate Function or member to disconnect from the signal. - */ - template - void disconnect() { - delegate_type call{}; - call.template connect(); - disconnect_if([&call](const auto &elem) { return elem == call; }); - } - - /** - * @brief Disconnects a free function with payload or a bound member from a - * signal. - * - * The signal isn't responsible for the connected object or the payload. - * Users must always guarantee that the lifetime of the instance overcomes - * the one of the signal.
- * When used to connect a free function with payload, its signature must be - * such that the instance is the first argument before the ones used to - * define the signal itself. - * - * @tparam Candidate Function or member to disconnect from the signal. - * @tparam Type Type of class or type of payload, if any. - * @param value_or_instance A valid reference that fits the purpose. - */ - template - void disconnect(Type &value_or_instance) { - delegate_type call{}; - call.template connect(value_or_instance); - disconnect_if([&call](const auto &elem) { return elem == call; }); - } - - /** - * @brief Disconnects a free function with payload or a bound member from a - * signal. - * - * @sa disconnect(Type &) - * - * @tparam Candidate Function or member to disconnect from the signal. - * @tparam Type Type of class or type of payload, if any. - * @param value_or_instance A valid pointer that fits the purpose. - */ - template - void disconnect(Type *value_or_instance) { - delegate_type call{}; - call.template connect(value_or_instance); - disconnect_if([&call](const auto &elem) { return elem == call; }); - } - - /** - * @brief Disconnects free functions with payload or bound members from a - * signal. - * @param value_or_instance A valid object that fits the purpose. - */ - void disconnect(const void *value_or_instance) { - ENTT_ASSERT(value_or_instance != nullptr, "Invalid value or instance"); - disconnect_if([value_or_instance](const auto &elem) { return elem.data() == value_or_instance; }); - } - - /*! @brief Disconnects all the listeners from a signal. */ - void disconnect() { - signal_or_assert().calls.clear(); - } - - /** - * @brief Returns true if a sink is correctly initialized, false otherwise. - * @return True if a sink is correctly initialized, false otherwise. - */ - [[nodiscard]] explicit operator bool() const noexcept { - return signal != nullptr; - } - -private: - signal_type *signal; -}; - -/** - * @brief Deduction guide. - * - * It allows to deduce the signal handler type of a sink directly from the - * signal it refers to. - * - * @tparam Ret Return type of a function type. - * @tparam Args Types of arguments of a function type. - * @tparam Allocator Type of allocator used to manage memory and elements. - */ -template -sink(sigh &) -> sink>; - -} // namespace entt - -#endif diff --git a/include/entt/stl/algorithm.hpp b/include/entt/stl/algorithm.hpp deleted file mode 100644 index 8fc29d9..0000000 --- a/include/entt/stl/algorithm.hpp +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef ENTT_STL_ALGORITHM_HPP -#define ENTT_STL_ALGORITHM_HPP - -/*! @cond ENTT_INTERNAL */ -#if __has_include() -# include -#else -# include - -namespace entt::stl { - -using std::all_of; -using std::any_of; -using std::find_if; -using std::none_of; -using std::sort; - -} // namespace entt::stl -#endif -/*! @endcond */ - -#endif diff --git a/include/entt/stl/array.hpp b/include/entt/stl/array.hpp deleted file mode 100644 index 27137da..0000000 --- a/include/entt/stl/array.hpp +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef ENTT_STL_ARRAY_HPP -#define ENTT_STL_ARRAY_HPP - -/*! @cond ENTT_INTERNAL */ -#if __has_include() -# include -#else -# include - -namespace entt::stl { - -using std::array; -using std::get; - -} // namespace entt::stl -#endif -/*! @endcond */ - -#endif diff --git a/include/entt/stl/atomic.hpp b/include/entt/stl/atomic.hpp deleted file mode 100644 index 2e5b8d1..0000000 --- a/include/entt/stl/atomic.hpp +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef ENTT_STL_ATOMIC_HPP -#define ENTT_STL_ATOMIC_HPP - -/*! @cond ENTT_INTERNAL */ -#if __has_include() -# include -#else -# include - -namespace entt::stl { - -using std::atomic; - -} // namespace entt::stl -#endif -/*! @endcond */ - -#endif diff --git a/include/entt/stl/bit.hpp b/include/entt/stl/bit.hpp deleted file mode 100644 index 3dca634..0000000 --- a/include/entt/stl/bit.hpp +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef ENTT_STL_BIT_HPP -#define ENTT_STL_BIT_HPP - -/*! @cond ENTT_INTERNAL */ -#if __has_include() -# include -#else -# include - -namespace entt::stl { - -using std::bit_ceil; -using std::has_single_bit; -using std::popcount; - -} // namespace entt::stl -#endif -/*! @endcond */ - -#endif diff --git a/include/entt/stl/cmath.hpp b/include/entt/stl/cmath.hpp deleted file mode 100644 index 932ba0f..0000000 --- a/include/entt/stl/cmath.hpp +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef ENTT_STL_CMATH_HPP -#define ENTT_STL_CMATH_HPP - -/*! @cond ENTT_INTERNAL */ -#if __has_include() -# include -#else -# include - -namespace entt::stl { - -using std::ceil; - -} // namespace entt::stl -#endif -/*! @endcond */ - -#endif diff --git a/include/entt/stl/concepts.hpp b/include/entt/stl/concepts.hpp deleted file mode 100644 index 27d78a1..0000000 --- a/include/entt/stl/concepts.hpp +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef ENTT_STL_CONCEPTS_HPP -#define ENTT_STL_CONCEPTS_HPP - -/*! @cond ENTT_INTERNAL */ -#if __has_include() -# include -#else -# include - -namespace entt::stl { - -using std::constructible_from; -using std::default_initializable; -using std::derived_from; -using std::integral; -using std::invocable; -using std::same_as; -using std::unsigned_integral; - -} // namespace entt::stl -#endif -/*! @endcond */ - -#endif diff --git a/include/entt/stl/cstddef.hpp b/include/entt/stl/cstddef.hpp deleted file mode 100644 index 512d233..0000000 --- a/include/entt/stl/cstddef.hpp +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef ENTT_STL_CSTDDEF_HPP -#define ENTT_STL_CSTDDEF_HPP - -/*! @cond ENTT_INTERNAL */ -#if __has_include() -# include -#else -# include - -namespace entt::stl { - -using std::byte; -using std::nullptr_t; -using std::ptrdiff_t; -using std::size_t; - -} // namespace entt::stl -#endif -/*! @endcond */ - -#endif diff --git a/include/entt/stl/cstdint.hpp b/include/entt/stl/cstdint.hpp deleted file mode 100644 index ff6dfcb..0000000 --- a/include/entt/stl/cstdint.hpp +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef ENTT_STL_CSTDINT_HPP -#define ENTT_STL_CSTDINT_HPP - -/*! @cond ENTT_INTERNAL */ -#if __has_include() -# include -#else -# include - -namespace entt::stl { - -using std::uint16_t; -using std::uint32_t; -using std::uint64_t; -using std::uint8_t; - -} // namespace entt::stl -#endif -/*! @endcond */ - -#endif diff --git a/include/entt/stl/functional.hpp b/include/entt/stl/functional.hpp deleted file mode 100644 index 0b6b50b..0000000 --- a/include/entt/stl/functional.hpp +++ /dev/null @@ -1,55 +0,0 @@ -#ifndef ENTT_STL_FUNCTIONAL_HPP -#define ENTT_STL_FUNCTIONAL_HPP - -/*! @cond ENTT_INTERNAL */ -#if __has_include() -# include -#else -# include -# include -# include "../config/config.h" - -namespace entt::stl { - -using std::equal_to; -using std::function; -using std::hash; -using std::invoke; -using std::less; - -} // namespace entt::stl - -# ifndef ENTT_FORCE_STL -# if defined(__cpp_lib_ranges) -# define ENTT_HAS_IDENTITY -namespace entt::stl { - -using std::identity; - -} // namespace entt::stl -# endif -# endif - -# ifndef ENTT_HAS_IDENTITY -# include - -namespace entt::stl { - -struct identity { - using is_transparent = void; - - template - [[nodiscard]] constexpr Type &&operator()(Type &&value) const noexcept { - return std::forward(value); - } -}; - -} // namespace entt::stl -# endif - -#endif -/*! @endcond */ - -#undef ENTT_HAS_IDENTITY - -#endif diff --git a/include/entt/stl/ios.hpp b/include/entt/stl/ios.hpp deleted file mode 100644 index e1b692e..0000000 --- a/include/entt/stl/ios.hpp +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef ENTT_STL_IOS_HPP -#define ENTT_STL_IOS_HPP - -/*! @cond ENTT_INTERNAL */ -#if __has_include() -# include -#else -# include - -namespace entt::stl { - -using std::boolalpha; - -} // namespace entt::stl -#endif -/*! @endcond */ - -#endif diff --git a/include/entt/stl/iterator.hpp b/include/entt/stl/iterator.hpp deleted file mode 100644 index 1723e03..0000000 --- a/include/entt/stl/iterator.hpp +++ /dev/null @@ -1,110 +0,0 @@ -#ifndef ENTT_STL_ITERATOR_HPP -#define ENTT_STL_ITERATOR_HPP - -/*! @cond ENTT_INTERNAL */ -#if __has_include() -# include -#else -# include -# include -# include "../config/config.h" - -namespace entt::stl { - -using std::advance; -using std::bidirectional_iterator_tag; -using std::distance; -using std::forward_iterator_tag; -using std::input_iterator_tag; -using std::iterator_traits; -using std::make_reverse_iterator; -using std::random_access_iterator_tag; -using std::reverse_iterator; - -# ifndef ENTT_FORCE_STL -# if defined(__cpp_lib_ranges) -# define ENTT_HAS_ITERATOR_CONCEPTS - -using std::bidirectional_iterator; -using std::forward_iterator; -using std::input_iterator; -using std::input_or_output_iterator; -using std::output_iterator; -using std::random_access_iterator; -using std::sentinel_for; - -# endif -# endif - -# ifndef ENTT_HAS_ITERATOR_CONCEPTS -# include -# include - -namespace internal { - -template -concept has_iterator_category = requires { - typename std::iterator_traits::iterator_category; -}; - -template -concept has_iterator_concept = has_iterator_category && requires { - typename It::iterator_concept; -}; - -template -struct iterator_tag { - using type = typename std::iterator_traits::iterator_category; -}; - -template -struct iterator_tag { - using type = typename It::iterator_concept; -}; - -template -concept has_iterator_tag = std::derived_from::type, Tag>; - -} // namespace internal - -// Bare minimum definitions to support broken platforms like PS4. -// EnTT does not provide full featured definitions for iterator concepts. - -template -concept input_or_output_iterator = requires(It it) { - *it; - { ++it } -> std::same_as; - it++; -}; - -template -concept input_iterator = input_or_output_iterator && internal::has_iterator_tag; - -template -concept output_iterator = input_or_output_iterator && requires(It it, Type &&value) { - *it++ = std::forward(value); -}; - -template -concept forward_iterator = input_iterator && internal::has_iterator_tag; - -template -concept bidirectional_iterator = forward_iterator && internal::has_iterator_tag; - -template -concept random_access_iterator = bidirectional_iterator && internal::has_iterator_tag; - -template -concept sentinel_for = input_or_output_iterator && requires(Sentinel sentinel, It it) { - { it == sentinel } -> std::same_as; -}; - -# endif - -} // namespace entt::stl -#endif -/*! @endcond */ - -#undef ENTT_HAS_ITERATOR_CONCEPTS - -#endif diff --git a/include/entt/stl/limits.hpp b/include/entt/stl/limits.hpp deleted file mode 100644 index fca169b..0000000 --- a/include/entt/stl/limits.hpp +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef ENTT_STL_LIMITS_HPP -#define ENTT_STL_LIMITS_HPP - -/*! @cond ENTT_INTERNAL */ -#if __has_include() -# include -#else -# include - -namespace entt::stl { - -using std::numeric_limits; - -} // namespace entt::stl -#endif -/*! @endcond */ - -#endif diff --git a/include/entt/stl/memory.hpp b/include/entt/stl/memory.hpp deleted file mode 100644 index e75fcab..0000000 --- a/include/entt/stl/memory.hpp +++ /dev/null @@ -1,74 +0,0 @@ -#ifndef ENTT_STL_MEMORY_HPP -#define ENTT_STL_MEMORY_HPP - -/*! @cond ENTT_INTERNAL */ -#if __has_include() -# include -#else -# include -# include -# include "../config/config.h" - -namespace entt::stl { - -using std::addressof; -using std::allocate_shared; -using std::allocator; -using std::allocator_arg; -using std::allocator_arg_t; -using std::allocator_traits; -using std::default_delete; -using std::destroy; -using std::enable_shared_from_this; -using std::make_shared; -using std::make_unique; -using std::pointer_traits; -using std::shared_ptr; -using std::static_pointer_cast; -using std::uninitialized_fill; -using std::unique_ptr; -using std::uses_allocator_v; - -} // namespace entt::stl - -# ifndef ENTT_FORCE_STL -# if defined(__cpp_lib_to_address) -# define ENTT_HAS_TO_ADDRESS - -namespace entt::stl { - -using std::to_address; - -} // namespace entt::stl - -# endif -# endif - -# ifndef ENTT_HAS_TO_ADDRESS -# include - -namespace entt::stl { - -template -constexpr Type *to_address(Type *ptr) noexcept { - static_assert(!std::is_function_v, "Invalid type"); - return ptr; -} - -template -constexpr auto to_address(const Type &ptr) noexcept { - if constexpr(requires { std::pointer_traits::to_address(ptr); }) { - return std::pointer_traits::to_address(ptr); - } else { - return to_address(ptr.operator->()); - } -} - -} // namespace entt::stl -# endif -#endif -/*! @endcond */ - -#undef ENTT_HAS_TO_ADDRESS - -#endif diff --git a/include/entt/stl/ostream.hpp b/include/entt/stl/ostream.hpp deleted file mode 100644 index f185c9e..0000000 --- a/include/entt/stl/ostream.hpp +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef ENTT_STL_OSTREAM_HPP -#define ENTT_STL_OSTREAM_HPP - -/*! @cond ENTT_INTERNAL */ -#if __has_include() -# include -#else -# include - -namespace entt::stl { - -using std::ostream; - -} // namespace entt::stl -#endif -/*! @endcond */ - -#endif diff --git a/include/entt/stl/sstream.hpp b/include/entt/stl/sstream.hpp deleted file mode 100644 index 0c5c4b4..0000000 --- a/include/entt/stl/sstream.hpp +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef ENTT_STL_SSTREAM_HPP -#define ENTT_STL_SSTREAM_HPP - -/*! @cond ENTT_INTERNAL */ -#if __has_include() -# include -#else -# include - -namespace entt::stl { - -using std::stringstream; - -} // namespace entt::stl -#endif -/*! @endcond */ - -#endif diff --git a/include/entt/stl/string.hpp b/include/entt/stl/string.hpp deleted file mode 100644 index a0cc88f..0000000 --- a/include/entt/stl/string.hpp +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef ENTT_STL_STRING_HPP -#define ENTT_STL_STRING_HPP - -/*! @cond ENTT_INTERNAL */ -#if __has_include() -# include -#else -# include - -namespace entt::stl { - -using std::string; - -} // namespace entt::stl -#endif -/*! @endcond */ - -#endif diff --git a/include/entt/stl/string_view.hpp b/include/entt/stl/string_view.hpp deleted file mode 100644 index bfe8956..0000000 --- a/include/entt/stl/string_view.hpp +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef ENTT_STL_STRING_VIEW_HPP -#define ENTT_STL_STRING_VIEW_HPP - -/*! @cond ENTT_INTERNAL */ -#if __has_include() -# include -#else -# include - -namespace entt::stl { - -using std::string_view; -using std::swap; - -} // namespace entt::stl -#endif -/*! @endcond */ - -#endif diff --git a/include/entt/stl/tuple.hpp b/include/entt/stl/tuple.hpp deleted file mode 100644 index fa085cd..0000000 --- a/include/entt/stl/tuple.hpp +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef ENTT_STL_TUPLE_HPP -#define ENTT_STL_TUPLE_HPP - -/*! @cond ENTT_INTERNAL */ -#if __has_include() -# include -#else -# include - -namespace entt::stl { - -using std::apply; -using std::forward_as_tuple; -using std::get; -using std::make_from_tuple; -using std::make_tuple; -using std::tuple; -using std::tuple_cat; -using std::tuple_element; -using std::tuple_element_t; -using std::tuple_size; -using std::tuple_size_v; - -} // namespace entt::stl -#endif -/*! @endcond */ - -#endif diff --git a/include/entt/stl/type_traits.hpp b/include/entt/stl/type_traits.hpp deleted file mode 100644 index 882f627..0000000 --- a/include/entt/stl/type_traits.hpp +++ /dev/null @@ -1,70 +0,0 @@ -#ifndef ENTT_STL_TYPE_TRAITS_HPP -#define ENTT_STL_TYPE_TRAITS_HPP - -/*! @cond ENTT_INTERNAL */ -#if __has_include() -# include -#else -# include - -namespace entt::stl { - -using std::bool_constant; -using std::common_type_t; -using std::conditional_t; -using std::decay_t; -using std::extent_v; -using std::false_type; -using std::integral_constant; -using std::invoke_result_t; -using std::is_aggregate_v; -using std::is_arithmetic_v; -using std::is_array_v; -using std::is_base_of_v; -using std::is_class_v; -using std::is_const_v; -using std::is_constructible_v; -using std::is_convertible_v; -using std::is_copy_assignable_v; -using std::is_copy_constructible_v; -using std::is_default_constructible_v; -using std::is_empty_v; -using std::is_enum_v; -using std::is_final_v; -using std::is_function_v; -using std::is_integral_v; -using std::is_invocable; -using std::is_invocable_r; -using std::is_invocable_r_v; -using std::is_invocable_v; -using std::is_lvalue_reference_v; -using std::is_member_function_pointer_v; -using std::is_member_object_pointer_v; -using std::is_member_pointer_v; -using std::is_move_assignable_v; -using std::is_move_constructible_v; -using std::is_nothrow_constructible_v; -using std::is_nothrow_copy_constructible_v; -using std::is_nothrow_default_constructible_v; -using std::is_nothrow_destructible_v; -using std::is_nothrow_invocable_v; -using std::is_nothrow_move_constructible_v; -using std::is_pointer_v; -using std::is_reference_v; -using std::is_same_v; -using std::is_signed_v; -using std::is_trivially_destructible_v; -using std::is_void_v; -using std::remove_const_t; -using std::remove_cvref_t; -using std::remove_pointer_t; -using std::remove_reference_t; -using std::true_type; -using std::type_identity; -using std::underlying_type_t; - -} // namespace entt::stl -#endif -/*! @endcond */ - -#endif diff --git a/include/entt/stl/utility.hpp b/include/entt/stl/utility.hpp deleted file mode 100644 index 2450d1b..0000000 --- a/include/entt/stl/utility.hpp +++ /dev/null @@ -1,34 +0,0 @@ -#ifndef ENTT_STL_UTILITY_HPP -#define ENTT_STL_UTILITY_HPP - -/*! @cond ENTT_INTERNAL */ -#if __has_include() -# include -#else -# include - -namespace entt::stl { - -using std::as_const; -using std::declval; -using std::exchange; -using std::forward; -using std::in_place; -using std::in_place_t; -using std::in_place_type; -using std::in_place_type_t; -using std::index_sequence; -using std::index_sequence_for; -using std::make_index_sequence; -using std::make_pair; -using std::move; -using std::pair; -using std::piecewise_construct; -using std::piecewise_construct_t; -using std::swap; - -} // namespace entt::stl -#endif -/*! @endcond */ - -#endif diff --git a/include/entt/stl/vector.hpp b/include/entt/stl/vector.hpp deleted file mode 100644 index f5200d3..0000000 --- a/include/entt/stl/vector.hpp +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef ENTT_STL_VECTOR_HPP -#define ENTT_STL_VECTOR_HPP - -/*! @cond ENTT_INTERNAL */ -#if __has_include() -# include -#else -# include - -namespace entt::stl { - -using std::vector; - -} // namespace entt::stl -#endif -/*! @endcond */ - -#endif diff --git a/include/entt/tools.hpp b/include/entt/tools.hpp deleted file mode 100644 index 66e9813..0000000 --- a/include/entt/tools.hpp +++ /dev/null @@ -1,3 +0,0 @@ -// IWYU pragma: begin_exports -#include "tools/davey.hpp" -// IWYU pragma: end_exports diff --git a/include/entt/tools/davey.hpp b/include/entt/tools/davey.hpp deleted file mode 100644 index c305613..0000000 --- a/include/entt/tools/davey.hpp +++ /dev/null @@ -1,343 +0,0 @@ -#ifndef ENTT_TOOLS_DAVEY_HPP -#define ENTT_TOOLS_DAVEY_HPP - -#include "../config/config.h" -#include "../entity/mixin.hpp" -#include "../entity/registry.hpp" -#include "../entity/sparse_set.hpp" -#include "../entity/storage.hpp" -#include "../locator/locator.hpp" -#include "../meta/container.hpp" -#include "../meta/context.hpp" -#include "../meta/meta.hpp" -#include "../meta/pointer.hpp" -#include "../meta/resolve.hpp" -#include "../stl/cstdint.hpp" -#include "../stl/ios.hpp" -#include "../stl/sstream.hpp" -#include "../stl/string.hpp" - -#if __has_include() -# include -#endif - -namespace entt { - -/*! @cond ENTT_INTERNAL */ -namespace internal { - -template -static void present_element(const meta_any &obj, OnEntity on_entity) { - for([[maybe_unused]] const auto [id, data]: obj.type().data()) { - const auto elem = data.get(obj); - const stl::string name = data.name().empty() ? stl::string{data.type().info().name()} : stl::string{data.name()}; - const char *const label = name.c_str(); - - if(auto type = data.type(); type.info() == type_id()) { - ImGui::Text("%s: %s", label, elem.template cast()); - } else if(type.info() == type_id()) { - ImGui::Text("%s: %s", label, elem.template cast().data()); - } else if(type.info() == type_id()) { - if(const auto entt = elem.template cast(); entt == null) { - ImGui::Text("%s: %s", label, "null"); - } else { - on_entity(label, entt); - } - } else if(type.is_enum()) { - const char *as_string = nullptr; - - for(auto [id, curr]: type.data()) { - if(curr.get({}) == elem) { - as_string = curr.name().data(); - break; - } - } - - if(as_string) { - ImGui::Text("%s: %s", label, as_string); - } else { - ImGui::Text("%s: %zu", label, elem.template allow_cast().template cast()); - } - } else if(type.is_arithmetic()) { - if(type.info() == type_id()) { - stl::stringstream buffer{}; - buffer << stl::boolalpha << elem.template cast(); - ImGui::Text("%s: %s", label, buffer.str().data()); - } else if(type.info() == type_id()) { - ImGui::Text("%s: %c", label, elem.template cast()); - } else if(type.is_integral()) { - ImGui::Text("%s: %zu", label, elem.template allow_cast().template cast()); - } else { - ImGui::Text("%s: %f", label, elem.template allow_cast().template cast()); - } - } else if(type.is_pointer_like()) { - if(auto deref = *obj; deref) { - if(ImGui::TreeNode(label)) { - present_element(*obj, on_entity); - ImGui::TreePop(); - } - } else { - ImGui::Text("%s: %s", label, "null"); - } - } else if(type.is_sequence_container()) { - if(ImGui::TreeNode(label)) { - meta_sequence_container view = elem.as_sequence_container(); - - for(stl::size_t pos{}, last = view.size(); pos < last; ++pos) { - ImGui::PushID(static_cast(pos)); - - if(ImGui::TreeNode(label, "%zu", pos)) { - present_element(view[pos], on_entity); - ImGui::TreePop(); - } - - ImGui::PopID(); - } - - ImGui::TreePop(); - } - } else if(type.is_associative_container()) { - if(ImGui::TreeNode(label)) { - meta_associative_container view = elem.as_associative_container(); - auto it = view.begin(); - - for(stl::size_t pos{}, last = view.size(); pos < last; ++pos, ++it) { - ImGui::PushID(static_cast(pos)); - - if(ImGui::TreeNode(label, "%zu", pos)) { - const auto [key, value] = *it; - - if(ImGui::TreeNode("key")) { - present_element(key, on_entity); - ImGui::TreePop(); - } - - if(ImGui::TreeNode("value")) { - present_element(value, on_entity); - ImGui::TreePop(); - } - - ImGui::TreePop(); - } - - ImGui::PopID(); - } - - ImGui::TreePop(); - } - } else if(type.is_class()) { - if(ImGui::TreeNode(label)) { - present_element(elem, on_entity); - ImGui::TreePop(); - } - } else { - const stl::string underlying_type{data.type().info().name()}; - ImGui::Text("%s: %s", label, underlying_type.data()); - } - } - - for([[maybe_unused]] const auto [id, base]: obj.type().base()) { - present_element(obj.allow_cast(base.type()), on_entity); - } -} - -template -static void present_storage(const meta_ctx &ctx, const basic_sparse_set &storage) { - if(auto type = resolve(ctx, storage.info()); type) { - for(auto entt: storage) { - ImGui::PushID(static_cast(to_entity(entt))); - - if(ImGui::TreeNode(&storage.info(), "%d [%d/%d]", to_integral(entt), to_entity(entt), to_version(entt))) { - if(const auto obj = type.from_void(storage.value(entt)); obj) { - present_element::entity_type>(obj, [](const char *name, const Entity entt) { - ImGui::Text("%s: %d [%d/%d]", name, to_integral(entt), to_entity(entt), to_version(entt)); - }); - } - - ImGui::TreePop(); - } - - ImGui::PopID(); - } - } else { - for(auto entt: storage) { - ImGui::Text("%d [%d/%d]", to_integral(entt), to_entity(entt), to_version(entt)); - } - } -} - -template -static void present_entity(const meta_ctx &ctx, const Entity entt, const It from, const It to) { - for(auto it = from; it != to; ++it) { - if(const auto &storage = it->second; storage.contains(entt)) { - if(auto type = resolve(ctx, storage.info()); type) { - const stl::string name = type.name().empty() ? stl::string{storage.info().name()} : stl::string{type.name()}; - const char *const label = name.c_str(); - - if(ImGui::TreeNode(&storage.info(), "%s", label)) { - if(const auto obj = type.from_void(storage.value(entt)); obj) { - present_element(obj, [&ctx, from, to](const char *name, const Entity other) { - if(ImGui::TreeNode(name, "%s: %d [%d/%d]", name, to_integral(other), to_entity(other), to_version(other))) { - present_entity(ctx, other, from, to); - ImGui::TreePop(); - } - }); - } - - ImGui::TreePop(); - } - } else { - const stl::string name{storage.info().name()}; - ImGui::Text("%s", name.data()); - } - } - } -} - -template -static void present_view(const meta_ctx &ctx, const basic_view, exclude_t> &view, stl::index_sequence) { - using view_type = basic_view, exclude_t>; - const stl::array range{view.template storage()...}; - - for(auto tup: view.each()) { - const auto entt = stl::get<0>(tup); - ImGui::PushID(static_cast(to_entity(entt))); - - if(ImGui::TreeNode(&type_id(), "%d [%d/%d]", to_integral(entt), to_entity(entt), to_version(entt))) { - for(const auto *storage: range) { - if(auto type = resolve(ctx, storage->info()); type) { - const stl::string name = type.name().empty() ? stl::string{storage->info().name()} : stl::string{type.name()}; - const char *const label = name.c_str(); - - if(ImGui::TreeNode(&storage->info(), "%s", label)) { - if(const auto obj = type.from_void(storage->value(entt)); obj) { - present_element(obj, [](const char *name, const view_type::entity_type entt) { - ImGui::Text("%s: %d [%d/%d]", name, to_integral(entt), to_entity(entt), to_version(entt)); - }); - } - - ImGui::TreePop(); - } - } else { - const stl::string name{storage->info().name()}; - ImGui::Text("%s", name.data()); - } - } - - ImGui::TreePop(); - } - - ImGui::PopID(); - } -} - -} // namespace internal -/*! @endcond */ - -/** - * @brief ImGui-based introspection tool for storage types. - * @tparam Type Storage element type. - * @tparam Entity Storage entity type. - * @tparam Allocator Storage allocator type. - * @param ctx The context from which to search for meta types. - * @param storage An instance of the storage type. - */ -template -void davey(const meta_ctx &ctx, const basic_storage &storage) { - internal::present_storage(ctx, storage); -} - -/** - * @brief ImGui-based introspection tool for storage types. - * @tparam Type Storage element type. - * @tparam Entity Storage entity type. - * @tparam Allocator Storage allocator type. - * @param storage An instance of the storage type. - */ -template -void davey(const basic_storage &storage) { - davey(locator::value_or(), storage); -} - -/** - * @brief ImGui-based introspection tool for view types. - * @tparam Get Types of storage iterated by the view. - * @tparam Exclude Types of storage used to filter the view. - * @param ctx The context from which to search for meta types. - * @param view An instance of the view type. - */ -template -void davey(const meta_ctx &ctx, const basic_view, exclude_t> &view) { - internal::present_view(ctx, view, stl::index_sequence_for{}); -} - -/** - * @brief ImGui-based introspection tool for view types. - * @tparam Get Types of storage iterated by the view. - * @tparam Exclude Types of storage used to filter the view. - * @param view An instance of the view type. - */ -template -void davey(const basic_view, exclude_t> &view) { - davey(locator::value_or(), view); -} - -/** - * @brief ImGui-based introspection tool for registry types. - * @tparam Entity Registry entity type. - * @tparam Allocator Registry allocator type. - * @param ctx The context from which to search for meta types. - * @param registry An instance of the registry type. - */ -template -void davey(const meta_ctx &ctx, const basic_registry ®istry) { - ImGui::BeginTabBar("#tabs"); - - if(ImGui::BeginTabItem("Entity")) { - for(const auto [entt]: registry.template storage()->each()) { - ImGui::PushID(static_cast(to_entity(entt))); - - if(ImGui::TreeNode(&type_id(), "%d [%d/%d]", to_integral(entt), to_entity(entt), to_version(entt))) { - const auto range = registry.storage(); - internal::present_entity(ctx, entt, range.begin(), range.end()); - ImGui::TreePop(); - } - - ImGui::PopID(); - } - - ImGui::EndTabItem(); - } - - if(ImGui::BeginTabItem("Storage")) { - for([[maybe_unused]] auto [id, storage]: registry.storage()) { - const auto type = resolve(ctx, storage.info()); - const stl::string name = type.name().empty() ? stl::string{storage.info().name()} : stl::string{type.name()}; - const char *const label = name.c_str(); - - if(ImGui::TreeNode(&storage.info(), "%s (%zu)", label, storage.size())) { - internal::present_storage(ctx, storage); - ImGui::TreePop(); - } - } - - ImGui::EndTabItem(); - } - - ImGui::EndTabBar(); -} - -/** - * @brief ImGui-based introspection tool for registry types. - * @tparam Entity Registry entity type. - * @tparam Allocator Registry allocator type. - * @param registry An instance of the registry type. - */ -template -void davey(const basic_registry ®istry) { - davey(locator::value_or(), registry); -} - -} // namespace entt - -#endif diff --git a/src/gameplay/client_world.cpp b/src/gameplay/client_world.cpp index ee4702e..b63248c 100644 --- a/src/gameplay/client_world.cpp +++ b/src/gameplay/client_world.cpp @@ -772,7 +772,6 @@ void ClientWorld::receive_voice_message(VoiceMsg& msg) { m_voice_queue.emplace(msg.opus_data(), pos); } bool ClientWorld::enable_voice_chat() const { return m_voice_chat.load(); } -const entt::registry& ClientWorld::get_registry() { return m_registry; } int ClientWorld::get_per_tick_time() const { return m_per_tick_time; } void ClientWorld::send_chat_message(ChatMessage& message) { Arena arena; diff --git a/src/gameplay/move_system.cpp b/src/gameplay/move_system.cpp deleted file mode 100644 index 2cac70f..0000000 --- a/src/gameplay/move_system.cpp +++ /dev/null @@ -1,123 +0,0 @@ -#include "Cubed/gameplay/move_system.hpp" - -#include "Cubed/gameplay/entity.hpp" -#include "Cubed/gameplay/hitbox_manager.hpp" -namespace Cubed { -void MoveSystem::update(World& world, entt::registry& registry) { - auto view = registry.view(); - for (auto entity : view) { - auto [transform, v, info] = - view.get(entity); - move_x(world, transform, v, info); - move_y(world, transform, v, info); - move_z(world, transform, v, info); - } -} - -void MoveSystem::move_x(World& world, Transform& transform, Velocity& v, - const EntityInfo& info) { - - auto& pos = transform.pos; - float distance = v.dx * world.get_per_tick_time() / 1000.0f; - pos.x += distance; - - AABB box = HitboxManager::aabb( - std::format("model/creature/{}/collision.json", info.name)); - glm::vec3 min = box.min(); - glm::vec3 max = box.max(); - - int minx = std::floor(min.x); - int maxx = std::floor(max.x); - int miny = std::floor(min.y); - int maxy = std::floor(max.y); - int minz = std::floor(min.z); - int maxz = std::floor(max.z); - - for (int x = minx; x <= maxx; ++x) { - for (int y = miny; y <= maxy; ++y) { - for (int z = minz; z <= maxz; ++z) { - glm::ivec3 block_pos{x, y, z}; - if (!world.can_pass_block(block_pos)) { - AABB block_box = World::get_block_aabb(block_pos); - if (box.intersects(block_box)) { - pos.x -= distance; - v.dx = 0.0f; - return; - } - } - } - } - } -} - -void MoveSystem::move_y(World& world, Transform& transform, Velocity& v, - const EntityInfo& info) { - auto& pos = transform.pos; - float distance = v.dy * world.get_per_tick_time() / 1000.0f; - pos.y += distance; - - AABB box = HitboxManager::aabb( - std::format("model/creature/{}/collision.json", info.name)); - glm::vec3 min = box.min(); - glm::vec3 max = box.max(); - - int minx = std::floor(min.x); - int maxx = std::floor(max.x); - int miny = std::floor(min.y); - int maxy = std::floor(max.y); - int minz = std::floor(min.z); - int maxz = std::floor(max.z); - - for (int x = minx; x <= maxx; ++x) { - for (int y = miny; y <= maxy; ++y) { - for (int z = minz; z <= maxz; ++z) { - glm::ivec3 block_pos{x, y, z}; - if (!world.can_pass_block(block_pos)) { - AABB block_box = World::get_block_aabb(block_pos); - if (box.intersects(block_box)) { - pos.y -= distance; - v.dy = 0.0f; - return; - } - } - } - } - } -} - -void MoveSystem::move_z(World& world, Transform& transform, Velocity& v, - const EntityInfo& info) { - auto& pos = transform.pos; - float distance = v.dz * world.get_per_tick_time() / 1000.0f; - pos.z += distance; - - AABB box = HitboxManager::aabb( - std::format("model/creature/{}/collision.json", info.name)); - glm::vec3 min = box.min(); - glm::vec3 max = box.max(); - - int minx = std::floor(min.x); - int maxx = std::floor(max.x); - int miny = std::floor(min.y); - int maxy = std::floor(max.y); - int minz = std::floor(min.z); - int maxz = std::floor(max.z); - - for (int x = minx; x <= maxx; ++x) { - for (int y = miny; y <= maxy; ++y) { - for (int z = minz; z <= maxz; ++z) { - glm::ivec3 block_pos{x, y, z}; - if (!world.can_pass_block(block_pos)) { - AABB block_box = World::get_block_aabb(block_pos); - if (box.intersects(block_box)) { - pos.z -= distance; - v.dz = 0.0f; - return; - } - } - } - } - } -} - -} // namespace Cubed \ No newline at end of file diff --git a/src/ui/credits_ui.cpp b/src/ui/credits_ui.cpp index 5bb02b7..f814f8f 100644 --- a/src/ui/credits_ui.cpp +++ b/src/ui/credits_ui.cpp @@ -64,7 +64,6 @@ void CreditsUI::init() { add_text("utf8cpp – BSL-1.0"); add_text("stb - public domain / MIT licensed"); add_text("assimp - BSD-3-Clause"); - add_text("EnTT - MIT licensed"); add_text("Music", 0.8f); add_text("'Find a Peaceful Place' by ROZKOL (Free Music Archive), CC " "BY 4.0.");