diff options
Diffstat (limited to 'deps/include/entt/core')
| -rw-r--r-- | deps/include/entt/core/algorithm.hpp | 143 | ||||
| -rw-r--r-- | deps/include/entt/core/any.hpp | 513 | ||||
| -rw-r--r-- | deps/include/entt/core/attribute.h | 30 | ||||
| -rw-r--r-- | deps/include/entt/core/bit.hpp | 69 | ||||
| -rw-r--r-- | deps/include/entt/core/compressed_pair.hpp | 272 | ||||
| -rw-r--r-- | deps/include/entt/core/enum.hpp | 97 | ||||
| -rw-r--r-- | deps/include/entt/core/family.hpp | 33 | ||||
| -rw-r--r-- | deps/include/entt/core/fwd.hpp | 36 | ||||
| -rw-r--r-- | deps/include/entt/core/hashed_string.hpp | 311 | ||||
| -rw-r--r-- | deps/include/entt/core/ident.hpp | 35 | ||||
| -rw-r--r-- | deps/include/entt/core/iterator.hpp | 197 | ||||
| -rw-r--r-- | deps/include/entt/core/memory.hpp | 244 | ||||
| -rw-r--r-- | deps/include/entt/core/monostate.hpp | 60 | ||||
| -rw-r--r-- | deps/include/entt/core/ranges.hpp | 20 | ||||
| -rw-r--r-- | deps/include/entt/core/tuple.hpp | 95 | ||||
| -rw-r--r-- | deps/include/entt/core/type_info.hpp | 268 | ||||
| -rw-r--r-- | deps/include/entt/core/type_traits.hpp | 919 | ||||
| -rw-r--r-- | deps/include/entt/core/utility.hpp | 101 |
18 files changed, 3443 insertions, 0 deletions
diff --git a/deps/include/entt/core/algorithm.hpp b/deps/include/entt/core/algorithm.hpp new file mode 100644 index 0000000..35bdf94 --- /dev/null +++ b/deps/include/entt/core/algorithm.hpp @@ -0,0 +1,143 @@ +#ifndef ENTT_CORE_ALGORITHM_HPP
+#define ENTT_CORE_ALGORITHM_HPP
+
+#include <algorithm>
+#include <functional>
+#include <iterator>
+#include <utility>
+#include <vector>
+#include "utility.hpp"
+
+namespace entt {
+
+/**
+ * @brief Function object to wrap `std::sort` in a class type.
+ *
+ * Unfortunately, `std::sort` cannot be passed as template argument to a class
+ * template or a function template.<br/>
+ * This class fills the gap by wrapping some flavors of `std::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 It Type of random access iterator.
+ * @tparam Compare Type of comparison function object.
+ * @tparam Args Types of arguments to forward to the sort function.
+ * @param first An iterator to the first element of the range to sort.
+ * @param last An iterator past the last element of the range to sort.
+ * @param compare A valid comparison function object.
+ * @param args Arguments to forward to the sort function, if any.
+ */
+ template<typename It, typename Compare = std::less<>, typename... Args>
+ void operator()(It first, It last, Compare compare = Compare{}, Args &&...args) const {
+ std::sort(std::forward<Args>(args)..., std::move(first), std::move(last), std::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 It Type of random access iterator.
+ * @tparam Compare Type of comparison function object.
+ * @param first An iterator to the first element of the range to sort.
+ * @param last An iterator past the last element of the range to sort.
+ * @param compare A valid comparison function object.
+ */
+ template<typename It, typename Compare = std::less<>>
+ void operator()(It first, It last, Compare compare = Compare{}) const {
+ if(first < last) {
+ for(auto it = first + 1; it < last; ++it) {
+ auto value = std::move(*it);
+ auto pre = it;
+
+ // NOLINTBEGIN(cppcoreguidelines-pro-bounds-pointer-arithmetic)
+ for(; pre > first && compare(value, *(pre - 1)); --pre) {
+ *pre = std::move(*(pre - 1));
+ }
+ // NOLINTEND(cppcoreguidelines-pro-bounds-pointer-arithmetic)
+
+ *pre = std::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<std::size_t Bit, std::size_t N>
+struct radix_sort {
+ static_assert((N % Bit) == 0, "The maximum number of bits to sort must be a multiple of the number of bits processed per pass");
+
+ /**
+ * @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<typename It, typename Getter = identity>
+ void operator()(It first, It last, Getter getter = Getter{}) const {
+ if(first < last) {
+ constexpr auto passes = N / Bit;
+
+ using value_type = typename std::iterator_traits<It>::value_type;
+ std::vector<value_type> aux(std::distance(first, last));
+
+ auto part = [getter = std::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)
+ std::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)
+ std::size_t index[buckets]{};
+
+ for(std::size_t pos{}, end = buckets - 1u; pos < end; ++pos) {
+ index[pos + 1u] = index[pos] + count[pos];
+ }
+
+ for(auto it = from; it != to; ++it) {
+ out[index[(getter(*it) >> start) & mask]++] = std::move(*it);
+ }
+ };
+
+ for(std::size_t pass = 0; pass < (passes & ~1); 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);
+ std::move(aux.begin(), aux.end(), first);
+ }
+ }
+ }
+};
+
+} // namespace entt
+
+#endif
diff --git a/deps/include/entt/core/any.hpp b/deps/include/entt/core/any.hpp new file mode 100644 index 0000000..9707996 --- /dev/null +++ b/deps/include/entt/core/any.hpp @@ -0,0 +1,513 @@ +#ifndef ENTT_CORE_ANY_HPP
+#define ENTT_CORE_ANY_HPP
+
+#include <cstddef>
+#include <memory>
+#include <type_traits>
+#include <utility>
+#include "../config/config.h"
+#include "../core/utility.hpp"
+#include "fwd.hpp"
+#include "type_info.hpp"
+#include "type_traits.hpp"
+
+namespace entt {
+
+/*! @cond TURN_OFF_DOXYGEN */
+namespace internal {
+
+enum class any_operation : std::uint8_t {
+ copy,
+ move,
+ transfer,
+ assign,
+ destroy,
+ compare,
+ get
+};
+
+} // namespace internal
+/*! @endcond */
+
+/*! @brief Possible modes of an any object. */
+enum class any_policy : std::uint8_t {
+ /*! @brief Default mode, the object owns the contained element. */
+ owner,
+ /*! @brief Aliasing mode, the object _points_ to a non-const element. */
+ ref,
+ /*! @brief Const aliasing mode, the object _points_ to a const element. */
+ cref
+};
+
+/**
+ * @brief A SBO friendly, type-safe container for single values of any type.
+ * @tparam Len Size of the storage reserved for the small buffer optimization.
+ * @tparam Align Optional alignment requirement.
+ */
+template<std::size_t Len, std::size_t Align>
+class basic_any {
+ using operation = internal::any_operation;
+ using vtable_type = const void *(const operation, const basic_any &, const void *);
+
+ struct storage_type {
+ // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays, modernize-avoid-c-arrays)
+ alignas(Align) std::byte data[Len + !Len];
+ };
+
+ template<typename Type>
+ static constexpr bool in_situ = Len && alignof(Type) <= Align && sizeof(Type) <= Len && std::is_nothrow_move_constructible_v<Type>;
+
+ template<typename Type>
+ static const void *basic_vtable(const operation op, const basic_any &value, const void *other) {
+ static_assert(!std::is_void_v<Type> && std::is_same_v<std::remove_cv_t<std::remove_reference_t<Type>>, Type>, "Invalid type");
+ const Type *elem = nullptr;
+
+ if constexpr(in_situ<Type>) {
+ elem = (value.mode == any_policy::owner) ? reinterpret_cast<const Type *>(&value.storage) : static_cast<const Type *>(value.instance);
+ } else {
+ elem = static_cast<const Type *>(value.instance);
+ }
+
+ switch(op) {
+ case operation::copy:
+ if constexpr(std::is_copy_constructible_v<Type>) {
+ static_cast<basic_any *>(const_cast<void *>(other))->initialize<Type>(*elem);
+ }
+ break;
+ case operation::move:
+ if constexpr(in_situ<Type>) {
+ if(value.mode == any_policy::owner) {
+ return ::new(&static_cast<basic_any *>(const_cast<void *>(other))->storage) Type{std::move(*const_cast<Type *>(elem))};
+ }
+ }
+
+ return (static_cast<basic_any *>(const_cast<void *>(other))->instance = std::exchange(const_cast<basic_any &>(value).instance, nullptr));
+ case operation::transfer:
+ if constexpr(std::is_move_assignable_v<Type>) {
+ *const_cast<Type *>(elem) = std::move(*static_cast<Type *>(const_cast<void *>(other)));
+ return other;
+ }
+ [[fallthrough]];
+ case operation::assign:
+ if constexpr(std::is_copy_assignable_v<Type>) {
+ *const_cast<Type *>(elem) = *static_cast<const Type *>(other);
+ return other;
+ }
+ break;
+ case operation::destroy:
+ if constexpr(in_situ<Type>) {
+ elem->~Type();
+ } else if constexpr(std::is_array_v<Type>) {
+ delete[] elem;
+ } else {
+ delete elem;
+ }
+ break;
+ case operation::compare:
+ if constexpr(!std::is_function_v<Type> && !std::is_array_v<Type> && is_equality_comparable_v<Type>) {
+ return *elem == *static_cast<const Type *>(other) ? other : nullptr;
+ } else {
+ return (elem == other) ? other : nullptr;
+ }
+ case operation::get:
+ return elem;
+ }
+
+ return nullptr;
+ }
+
+ template<typename Type, typename... Args>
+ void initialize([[maybe_unused]] Args &&...args) {
+ using plain_type = std::remove_cv_t<std::remove_reference_t<Type>>;
+ info = &type_id<plain_type>();
+
+ if constexpr(!std::is_void_v<Type>) {
+ vtable = basic_vtable<plain_type>;
+
+ if constexpr(std::is_lvalue_reference_v<Type>) {
+ static_assert((std::is_lvalue_reference_v<Args> && ...) && (sizeof...(Args) == 1u), "Invalid arguments");
+ mode = std::is_const_v<std::remove_reference_t<Type>> ? any_policy::cref : any_policy::ref;
+ instance = (std::addressof(args), ...);
+ } else if constexpr(in_situ<plain_type>) {
+ if constexpr(std::is_aggregate_v<plain_type> && (sizeof...(Args) != 0u || !std::is_default_constructible_v<plain_type>)) {
+ ::new(&storage) plain_type{std::forward<Args>(args)...};
+ } else {
+ ::new(&storage) plain_type(std::forward<Args>(args)...);
+ }
+ } else {
+ if constexpr(std::is_aggregate_v<plain_type> && (sizeof...(Args) != 0u || !std::is_default_constructible_v<plain_type>)) {
+ instance = new plain_type{std::forward<Args>(args)...};
+ } else if constexpr(std::is_array_v<plain_type>) {
+ static_assert(sizeof...(Args) == 0u, "Invalid arguments");
+ instance = new plain_type[std::extent_v<plain_type>]();
+ } else {
+ instance = new plain_type(std::forward<Args>(args)...);
+ }
+ }
+ }
+ }
+
+ basic_any(const basic_any &other, const any_policy pol) noexcept
+ : instance{other.data()},
+ info{other.info},
+ vtable{other.vtable},
+ mode{pol} {}
+
+public:
+ /*! @brief Size of the internal storage. */
+ static constexpr auto length = Len;
+ /*! @brief Alignment requirement. */
+ static constexpr auto alignment = Align;
+
+ /*! @brief Default constructor. */
+ constexpr basic_any() noexcept
+ : basic_any{std::in_place_type<void>} {}
+
+ /**
+ * @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<typename Type, typename... Args>
+ explicit basic_any(std::in_place_type_t<Type>, Args &&...args)
+ : instance{},
+ info{},
+ vtable{},
+ mode{any_policy::owner} {
+ initialize<Type>(std::forward<Args>(args)...);
+ }
+
+ /**
+ * @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<typename Type, typename = std::enable_if_t<!std::is_same_v<std::decay_t<Type>, basic_any>>>
+ basic_any(Type &&value)
+ : basic_any{std::in_place_type<std::decay_t<Type>>, std::forward<Type>(value)} {}
+
+ /**
+ * @brief Copy constructor.
+ * @param other The instance to copy from.
+ */
+ basic_any(const basic_any &other)
+ : basic_any{} {
+ if(other.vtable) {
+ other.vtable(operation::copy, other, this);
+ }
+ }
+
+ /**
+ * @brief Move constructor.
+ * @param other The instance to move from.
+ */
+ basic_any(basic_any &&other) noexcept
+ : instance{},
+ info{other.info},
+ vtable{other.vtable},
+ mode{other.mode} {
+ if(other.vtable) {
+ other.vtable(operation::move, other, this);
+ }
+ }
+
+ /*! @brief Frees the internal storage, whatever it means. */
+ ~basic_any() noexcept {
+ if(vtable && (mode == any_policy::owner)) {
+ vtable(operation::destroy, *this, nullptr);
+ }
+ }
+
+ /**
+ * @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) {
+ reset();
+
+ if(other.vtable) {
+ other.vtable(operation::copy, other, this);
+ }
+ }
+
+ return *this;
+ }
+
+ /**
+ * @brief Move assignment operator.
+ * @param other The instance to move from.
+ * @return This any object.
+ */
+ basic_any &operator=(basic_any &&other) noexcept {
+ ENTT_ASSERT(this != &other, "Self move assignment");
+
+ reset();
+
+ if(other.vtable) {
+ other.vtable(operation::move, other, this);
+ info = other.info;
+ vtable = other.vtable;
+ 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<typename Type, typename = std::enable_if_t<!std::is_same_v<std::decay_t<Type>, basic_any>>>
+ basic_any &operator=(Type &&value) {
+ emplace<std::decay_t<Type>>(std::forward<Type>(value));
+ return *this;
+ }
+
+ /**
+ * @brief Returns the object type if any, `type_id<void>()` otherwise.
+ * @return The object type if any, `type_id<void>()` otherwise.
+ */
+ [[nodiscard]] const type_info &type() const noexcept {
+ return *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 vtable ? vtable(operation::get, *this, nullptr) : nullptr;
+ }
+
+ /**
+ * @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 *info == req ? 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<void *>(std::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<void *>(std::as_const(*this).data(req));
+ }
+
+ /**
+ * @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<typename Type, typename... Args>
+ void emplace(Args &&...args) {
+ reset();
+ initialize<Type>(std::forward<Args>(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(vtable && mode != any_policy::cref && *info == *other.info) {
+ return (vtable(operation::assign, *this, other.data()) != nullptr);
+ }
+
+ return false;
+ }
+
+ /*! @copydoc assign */
+ bool assign(basic_any &&other) {
+ if(vtable && mode != any_policy::cref && *info == *other.info) {
+ if(auto *val = other.data(); val) {
+ return (vtable(operation::transfer, *this, val) != nullptr);
+ } else {
+ return (vtable(operation::assign, *this, std::as_const(other).data()) != nullptr);
+ }
+ }
+
+ return false;
+ }
+
+ /*! @brief Destroys contained object */
+ void reset() {
+ if(vtable && (mode == any_policy::owner)) {
+ vtable(operation::destroy, *this, nullptr);
+ }
+
+ // unnecessary but it helps to detect nasty bugs
+ ENTT_ASSERT((instance = nullptr) == nullptr, "");
+ info = &type_id<void>();
+ vtable = nullptr;
+ mode = any_policy::owner;
+ }
+
+ /**
+ * @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 vtable != nullptr;
+ }
+
+ /**
+ * @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(vtable && *info == *other.info) {
+ return (vtable(operation::compare, *this, other.data()) != nullptr);
+ }
+
+ return (!vtable && !other.vtable);
+ }
+
+ /**
+ * @brief Checks if two wrappers differ in their content.
+ * @param other Wrapper with which to compare.
+ * @return True if the two objects differ in their content, false otherwise.
+ */
+ [[nodiscard]] bool operator!=(const basic_any &other) const noexcept {
+ return !(*this == other);
+ }
+
+ /**
+ * @brief Aliasing constructor.
+ * @return A wrapper that shares a reference to an unmanaged object.
+ */
+ [[nodiscard]] basic_any as_ref() noexcept {
+ return basic_any{*this, (mode == any_policy::cref ? any_policy::cref : any_policy::ref)};
+ }
+
+ /*! @copydoc as_ref */
+ [[nodiscard]] basic_any as_ref() const noexcept {
+ return basic_any{*this, any_policy::cref};
+ }
+
+ /**
+ * @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:
+ union {
+ const void *instance;
+ storage_type storage;
+ };
+ const type_info *info;
+ vtable_type *vtable;
+ 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 storage reserved for the small buffer optimization.
+ * @tparam Align Alignment requirement.
+ * @param data Target any object.
+ * @return The element converted to the requested type.
+ */
+template<typename Type, std::size_t Len, std::size_t Align>
+[[nodiscard]] Type any_cast(const basic_any<Len, Align> &data) noexcept {
+ const auto *const instance = any_cast<std::remove_reference_t<Type>>(&data);
+ ENTT_ASSERT(instance, "Invalid instance");
+ return static_cast<Type>(*instance);
+}
+
+/*! @copydoc any_cast */
+template<typename Type, std::size_t Len, std::size_t Align>
+[[nodiscard]] Type any_cast(basic_any<Len, Align> &data) noexcept {
+ // forces const on non-reference types to make them work also with wrappers for const references
+ auto *const instance = any_cast<std::remove_reference_t<const Type>>(&data);
+ ENTT_ASSERT(instance, "Invalid instance");
+ return static_cast<Type>(*instance);
+}
+
+/*! @copydoc any_cast */
+template<typename Type, std::size_t Len, std::size_t Align>
+[[nodiscard]] Type any_cast(basic_any<Len, Align> &&data) noexcept {
+ if constexpr(std::is_copy_constructible_v<std::remove_cv_t<std::remove_reference_t<Type>>>) {
+ if(auto *const instance = any_cast<std::remove_reference_t<Type>>(&data); instance) {
+ return static_cast<Type>(std::move(*instance));
+ } else {
+ return any_cast<Type>(data);
+ }
+ } else {
+ auto *const instance = any_cast<std::remove_reference_t<Type>>(&data);
+ ENTT_ASSERT(instance, "Invalid instance");
+ return static_cast<Type>(std::move(*instance));
+ }
+}
+
+/*! @copydoc any_cast */
+template<typename Type, std::size_t Len, std::size_t Align>
+[[nodiscard]] const Type *any_cast(const basic_any<Len, Align> *data) noexcept {
+ const auto &info = type_id<std::remove_cv_t<Type>>();
+ return static_cast<const Type *>(data->data(info));
+}
+
+/*! @copydoc any_cast */
+template<typename Type, std::size_t Len, std::size_t Align>
+[[nodiscard]] Type *any_cast(basic_any<Len, Align> *data) noexcept {
+ if constexpr(std::is_const_v<Type>) {
+ // last attempt to make wrappers for const references return their values
+ return any_cast<Type>(&std::as_const(*data));
+ } else {
+ const auto &info = type_id<std::remove_cv_t<Type>>();
+ return static_cast<Type *>(data->data(info));
+ }
+}
+
+/**
+ * @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 storage 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<typename Type, std::size_t Len = basic_any<>::length, std::size_t Align = basic_any<Len>::alignment, typename... Args>
+[[nodiscard]] basic_any<Len, Align> make_any(Args &&...args) {
+ return basic_any<Len, Align>{std::in_place_type<Type>, std::forward<Args>(args)...};
+}
+
+/**
+ * @brief Forwards its argument and avoids copies for lvalue references.
+ * @tparam Len Size of the storage 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<std::size_t Len = basic_any<>::length, std::size_t Align = basic_any<Len>::alignment, typename Type>
+[[nodiscard]] basic_any<Len, Align> forward_as_any(Type &&value) {
+ return basic_any<Len, Align>{std::in_place_type<Type &&>, std::forward<Type>(value)};
+}
+
+} // namespace entt
+
+#endif
diff --git a/deps/include/entt/core/attribute.h b/deps/include/entt/core/attribute.h new file mode 100644 index 0000000..2af32d9 --- /dev/null +++ b/deps/include/entt/core/attribute.h @@ -0,0 +1,30 @@ +#ifndef ENTT_CORE_ATTRIBUTE_H
+#define ENTT_CORE_ATTRIBUTE_H
+
+#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
+
+#endif
diff --git a/deps/include/entt/core/bit.hpp b/deps/include/entt/core/bit.hpp new file mode 100644 index 0000000..6a28058 --- /dev/null +++ b/deps/include/entt/core/bit.hpp @@ -0,0 +1,69 @@ +#ifndef ENTT_CORE_BIT_HPP
+#define ENTT_CORE_BIT_HPP
+
+#include <cstddef>
+#include <limits>
+#include <type_traits>
+#include "../config/config.h"
+
+namespace entt {
+
+/**
+ * @brief Returns the number of set bits in a value (waiting for C++20 and
+ * `std::popcount`).
+ * @tparam Type Unsigned integer type.
+ * @param value A value of unsigned integer type.
+ * @return The number of set bits in the value.
+ */
+template<typename Type>
+[[nodiscard]] constexpr std::enable_if_t<std::is_unsigned_v<Type>, int> popcount(const Type value) noexcept {
+ return value ? (int(value & 1) + popcount(static_cast<Type>(value >> 1))) : 0;
+}
+
+/**
+ * @brief Checks whether a value is a power of two or not (waiting for C++20 and
+ * `std::has_single_bit`).
+ * @tparam Type Unsigned integer type.
+ * @param value A value of unsigned integer type.
+ * @return True if the value is a power of two, false otherwise.
+ */
+template<typename Type>
+[[nodiscard]] constexpr std::enable_if_t<std::is_unsigned_v<Type>, bool> has_single_bit(const Type value) noexcept {
+ return value && ((value & (value - 1)) == 0);
+}
+
+/**
+ * @brief Computes the smallest power of two greater than or equal to a value
+ * (waiting for C++20 and `std::bit_ceil`).
+ * @tparam Type Unsigned integer type.
+ * @param value A value of unsigned integer type.
+ * @return The smallest power of two greater than or equal to the given value.
+ */
+template<typename Type>
+[[nodiscard]] constexpr std::enable_if_t<std::is_unsigned_v<Type>, Type> next_power_of_two(const Type value) noexcept {
+ ENTT_ASSERT_CONSTEXPR(value < (Type{1u} << (std::numeric_limits<Type>::digits - 1)), "Numeric limits exceeded");
+ Type curr = value - (value != 0u);
+
+ for(int next = 1; next < std::numeric_limits<Type>::digits; next = next * 2) {
+ curr |= (curr >> next);
+ }
+
+ return ++curr;
+}
+
+/**
+ * @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<typename Type>
+[[nodiscard]] constexpr std::enable_if_t<std::is_unsigned_v<Type>, Type> fast_mod(const Type value, const std::size_t mod) noexcept {
+ ENTT_ASSERT_CONSTEXPR(has_single_bit(mod), "Value must be a power of two");
+ return value & (mod - 1u);
+}
+
+} // namespace entt
+
+#endif
diff --git a/deps/include/entt/core/compressed_pair.hpp b/deps/include/entt/core/compressed_pair.hpp new file mode 100644 index 0000000..a10589f --- /dev/null +++ b/deps/include/entt/core/compressed_pair.hpp @@ -0,0 +1,272 @@ +#ifndef ENTT_CORE_COMPRESSED_PAIR_HPP
+#define ENTT_CORE_COMPRESSED_PAIR_HPP
+
+#include <cstddef>
+#include <tuple>
+#include <type_traits>
+#include <utility>
+#include "fwd.hpp"
+#include "type_traits.hpp"
+
+namespace entt {
+
+/*! @cond TURN_OFF_DOXYGEN */
+namespace internal {
+
+template<typename Type, std::size_t, typename = void>
+struct compressed_pair_element {
+ using reference = Type &;
+ using const_reference = const Type &;
+
+ template<typename Dummy = Type, typename = std::enable_if_t<std::is_default_constructible_v<Dummy>>>
+ // NOLINTNEXTLINE(modernize-use-equals-default)
+ constexpr compressed_pair_element() noexcept(std::is_nothrow_default_constructible_v<Type>) {}
+
+ template<typename Arg, typename = std::enable_if_t<!std::is_same_v<std::remove_cv_t<std::remove_reference_t<Arg>>, compressed_pair_element>>>
+ constexpr compressed_pair_element(Arg &&arg) noexcept(std::is_nothrow_constructible_v<Type, Arg>)
+ : value{std::forward<Arg>(arg)} {}
+
+ template<typename... Args, std::size_t... Index>
+ constexpr compressed_pair_element(std::tuple<Args...> args, std::index_sequence<Index...>) noexcept(std::is_nothrow_constructible_v<Type, Args...>)
+ : value{std::forward<Args>(std::get<Index>(args))...} {}
+
+ [[nodiscard]] constexpr reference get() noexcept {
+ return value;
+ }
+
+ [[nodiscard]] constexpr const_reference get() const noexcept {
+ return value;
+ }
+
+private:
+ Type value{};
+};
+
+template<typename Type, std::size_t Tag>
+struct compressed_pair_element<Type, Tag, std::enable_if_t<is_ebco_eligible_v<Type>>>: Type {
+ using reference = Type &;
+ using const_reference = const Type &;
+ using base_type = Type;
+
+ template<typename Dummy = Type, typename = std::enable_if_t<std::is_default_constructible_v<Dummy>>>
+ constexpr compressed_pair_element() noexcept(std::is_nothrow_default_constructible_v<base_type>)
+ : base_type{} {}
+
+ template<typename Arg, typename = std::enable_if_t<!std::is_same_v<std::remove_cv_t<std::remove_reference_t<Arg>>, compressed_pair_element>>>
+ constexpr compressed_pair_element(Arg &&arg) noexcept(std::is_nothrow_constructible_v<base_type, Arg>)
+ : base_type{std::forward<Arg>(arg)} {}
+
+ template<typename... Args, std::size_t... Index>
+ constexpr compressed_pair_element(std::tuple<Args...> args, std::index_sequence<Index...>) noexcept(std::is_nothrow_constructible_v<base_type, Args...>)
+ : base_type{std::forward<Args>(std::get<Index>(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<typename First, typename Second>
+class compressed_pair final
+ : internal::compressed_pair_element<First, 0u>,
+ internal::compressed_pair_element<Second, 1u> {
+ using first_base = internal::compressed_pair_element<First, 0u>;
+ using second_base = internal::compressed_pair_element<Second, 1u>;
+
+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.
+ *
+ * @tparam Dummy Dummy template parameter used for internal purposes.
+ */
+ template<bool Dummy = true, typename = std::enable_if_t<Dummy && std::is_default_constructible_v<first_type> && std::is_default_constructible_v<second_type>>>
+ constexpr compressed_pair() noexcept(std::is_nothrow_default_constructible_v<first_base> && std::is_nothrow_default_constructible_v<second_base>)
+ : first_base{},
+ second_base{} {}
+
+ /**
+ * @brief Copy constructor.
+ * @param other The instance to copy from.
+ */
+ constexpr compressed_pair(const compressed_pair &other) noexcept(std::is_nothrow_copy_constructible_v<first_base> && std::is_nothrow_copy_constructible_v<second_base>) = default;
+
+ /**
+ * @brief Move constructor.
+ * @param other The instance to move from.
+ */
+ constexpr compressed_pair(compressed_pair &&other) noexcept(std::is_nothrow_move_constructible_v<first_base> && std::is_nothrow_move_constructible_v<second_base>) = 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<typename Arg, typename Other>
+ constexpr compressed_pair(Arg &&arg, Other &&other) noexcept(std::is_nothrow_constructible_v<first_base, Arg> && std::is_nothrow_constructible_v<second_base, Other>)
+ : first_base{std::forward<Arg>(arg)},
+ second_base{std::forward<Other>(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<typename... Args, typename... Other>
+ constexpr compressed_pair(std::piecewise_construct_t, std::tuple<Args...> args, std::tuple<Other...> other) noexcept(std::is_nothrow_constructible_v<first_base, Args...> && std::is_nothrow_constructible_v<second_base, Other...>)
+ : first_base{std::move(args), std::index_sequence_for<Args...>{}},
+ second_base{std::move(other), std::index_sequence_for<Other...>{}} {}
+
+ /*! @brief Default destructor. */
+ ~compressed_pair() noexcept(std::is_nothrow_destructible_v<First> && std::is_nothrow_destructible_v<Second>) = 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) noexcept(std::is_nothrow_copy_assignable_v<first_base> && std::is_nothrow_copy_assignable_v<second_base>) = 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(std::is_nothrow_move_assignable_v<first_base> && std::is_nothrow_move_assignable_v<second_base>) = 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<first_base &>(*this).get();
+ }
+
+ /*! @copydoc first */
+ [[nodiscard]] constexpr const first_type &first() const noexcept {
+ return static_cast<const first_base &>(*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<second_base &>(*this).get();
+ }
+
+ /*! @copydoc second */
+ [[nodiscard]] constexpr const second_type &second() const noexcept {
+ return static_cast<const second_base &>(*this).get();
+ }
+
+ /**
+ * @brief Swaps two compressed pair objects.
+ * @param other The compressed pair to swap with.
+ */
+ constexpr void swap(compressed_pair &other) noexcept(std::is_nothrow_swappable_v<first_type> && std::is_nothrow_swappable_v<second_type>) {
+ using std::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<std::size_t Index>
+ [[nodiscard]] constexpr decltype(auto) get() noexcept {
+ if constexpr(Index == 0u) {
+ return first();
+ } else {
+ static_assert(Index == 1u, "Index out of bounds");
+ return second();
+ }
+ }
+
+ /*! @copydoc get */
+ template<std::size_t Index>
+ [[nodiscard]] constexpr decltype(auto) get() const noexcept {
+ if constexpr(Index == 0u) {
+ return first();
+ } else {
+ static_assert(Index == 1u, "Index out of bounds");
+ 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<typename Type, typename Other>
+compressed_pair(Type &&, Other &&) -> compressed_pair<std::decay_t<Type>, std::decay_t<Other>>;
+
+/**
+ * @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<typename First, typename Second>
+inline constexpr void swap(compressed_pair<First, Second> &lhs, compressed_pair<First, Second> &rhs) {
+ lhs.swap(rhs);
+}
+
+} // namespace entt
+
+namespace std {
+
+/**
+ * @brief `std::tuple_size` specialization for `compressed_pair`s.
+ * @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<typename First, typename Second>
+struct tuple_size<entt::compressed_pair<First, Second>>: integral_constant<size_t, 2u> {};
+
+/**
+ * @brief `std::tuple_element` specialization for `compressed_pair`s.
+ * @tparam Index The index of the type to return.
+ * @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<size_t Index, typename First, typename Second>
+struct tuple_element<Index, entt::compressed_pair<First, Second>>: conditional<Index == 0u, First, Second> {
+ static_assert(Index < 2u, "Index out of bounds");
+};
+
+} // namespace std
+
+#endif
diff --git a/deps/include/entt/core/enum.hpp b/deps/include/entt/core/enum.hpp new file mode 100644 index 0000000..c78ad5a --- /dev/null +++ b/deps/include/entt/core/enum.hpp @@ -0,0 +1,97 @@ +#ifndef ENTT_CORE_ENUM_HPP
+#define ENTT_CORE_ENUM_HPP
+
+#include <type_traits>
+
+namespace entt {
+
+/**
+ * @brief Enable bitmask support for enum classes.
+ * @tparam Type The enum type for which to enable bitmask support.
+ */
+template<typename Type, typename = void>
+struct enum_as_bitmask: std::false_type {};
+
+/*! @copydoc enum_as_bitmask */
+template<typename Type>
+struct enum_as_bitmask<Type, std::void_t<decltype(Type::_entt_enum_as_bitmask)>>: std::is_enum<Type> {};
+
+/**
+ * @brief Helper variable template.
+ * @tparam Type The enum class type for which to enable bitmask support.
+ */
+template<typename Type>
+inline constexpr bool enum_as_bitmask_v = enum_as_bitmask<Type>::value;
+
+} // 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<typename Type>
+[[nodiscard]] constexpr std::enable_if_t<entt::enum_as_bitmask_v<Type>, Type>
+operator|(const Type lhs, const Type rhs) noexcept {
+ return static_cast<Type>(static_cast<std::underlying_type_t<Type>>(lhs) | static_cast<std::underlying_type_t<Type>>(rhs));
+}
+
+/*! @copydoc operator| */
+template<typename Type>
+[[nodiscard]] constexpr std::enable_if_t<entt::enum_as_bitmask_v<Type>, Type>
+operator&(const Type lhs, const Type rhs) noexcept {
+ return static_cast<Type>(static_cast<std::underlying_type_t<Type>>(lhs) & static_cast<std::underlying_type_t<Type>>(rhs));
+}
+
+/*! @copydoc operator| */
+template<typename Type>
+[[nodiscard]] constexpr std::enable_if_t<entt::enum_as_bitmask_v<Type>, Type>
+operator^(const Type lhs, const Type rhs) noexcept {
+ return static_cast<Type>(static_cast<std::underlying_type_t<Type>>(lhs) ^ static_cast<std::underlying_type_t<Type>>(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<typename Type>
+[[nodiscard]] constexpr std::enable_if_t<entt::enum_as_bitmask_v<Type>, Type>
+operator~(const Type value) noexcept {
+ return static_cast<Type>(~static_cast<std::underlying_type_t<Type>>(value));
+}
+
+/*! @copydoc operator~ */
+template<typename Type>
+[[nodiscard]] constexpr std::enable_if_t<entt::enum_as_bitmask_v<Type>, bool>
+operator!(const Type value) noexcept {
+ return !static_cast<std::underlying_type_t<Type>>(value);
+}
+
+/*! @copydoc operator| */
+template<typename Type>
+constexpr std::enable_if_t<entt::enum_as_bitmask_v<Type>, Type &>
+operator|=(Type &lhs, const Type rhs) noexcept {
+ return (lhs = (lhs | rhs));
+}
+
+/*! @copydoc operator| */
+template<typename Type>
+constexpr std::enable_if_t<entt::enum_as_bitmask_v<Type>, Type &>
+operator&=(Type &lhs, const Type rhs) noexcept {
+ return (lhs = (lhs & rhs));
+}
+
+/*! @copydoc operator| */
+template<typename Type>
+constexpr std::enable_if_t<entt::enum_as_bitmask_v<Type>, Type &>
+operator^=(Type &lhs, const Type rhs) noexcept {
+ return (lhs = (lhs ^ rhs));
+}
+
+#endif
diff --git a/deps/include/entt/core/family.hpp b/deps/include/entt/core/family.hpp new file mode 100644 index 0000000..7c7f3e1 --- /dev/null +++ b/deps/include/entt/core/family.hpp @@ -0,0 +1,33 @@ +#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<typename...>
+class family {
+ // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
+ inline static ENTT_MAYBE_ATOMIC(id_type) identifier{};
+
+public:
+ /*! @brief Unsigned integer type. */
+ using value_type = id_type;
+
+ /*! @brief Statically generated unique identifier for the given type. */
+ template<typename... Type>
+ // at the time I'm writing, clang crashes during compilation if auto is used instead of family_type
+ inline static const value_type value = identifier++;
+};
+
+} // namespace entt
+
+#endif
diff --git a/deps/include/entt/core/fwd.hpp b/deps/include/entt/core/fwd.hpp new file mode 100644 index 0000000..8760a85 --- /dev/null +++ b/deps/include/entt/core/fwd.hpp @@ -0,0 +1,36 @@ +#ifndef ENTT_CORE_FWD_HPP
+#define ENTT_CORE_FWD_HPP
+
+#include <cstddef>
+#include "../config/config.h"
+
+namespace entt {
+
+// NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays, modernize-avoid-c-arrays)
+template<std::size_t Len = sizeof(double[2]), std::size_t = alignof(double[2])>
+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<typename, typename>
+class compressed_pair;
+
+template<typename>
+class basic_hashed_string;
+
+/*! @brief Aliases for common character types. */
+using hashed_string = basic_hashed_string<char>;
+
+/*! @brief Aliases for common character types. */
+using hashed_wstring = basic_hashed_string<wchar_t>;
+
+// NOLINTNEXTLINE(bugprone-forward-declaration-namespace)
+struct type_info;
+
+} // namespace entt
+
+#endif
diff --git a/deps/include/entt/core/hashed_string.hpp b/deps/include/entt/core/hashed_string.hpp new file mode 100644 index 0000000..c4b1313 --- /dev/null +++ b/deps/include/entt/core/hashed_string.hpp @@ -0,0 +1,311 @@ +#ifndef ENTT_CORE_HASHED_STRING_HPP
+#define ENTT_CORE_HASHED_STRING_HPP
+
+#include <cstddef>
+#include <cstdint>
+#include <string_view>
+#include "fwd.hpp"
+
+namespace entt {
+
+/*! @cond TURN_OFF_DOXYGEN */
+namespace internal {
+
+template<typename = id_type>
+struct fnv_1a_params;
+
+template<>
+struct fnv_1a_params<std::uint32_t> {
+ static constexpr auto offset = 2166136261;
+ static constexpr auto prime = 16777619;
+};
+
+template<>
+struct fnv_1a_params<std::uint64_t> {
+ static constexpr auto offset = 14695981039346656037ull;
+ static constexpr auto prime = 1099511628211ull;
+};
+
+template<typename Char>
+struct basic_hashed_string {
+ using value_type = Char;
+ using size_type = std::size_t;
+ using hash_type = id_type;
+
+ const value_type *repr;
+ size_type length;
+ hash_type hash;
+};
+
+} // 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.<br/>
+ * 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<typename Char>
+class basic_hashed_string: internal::basic_hashed_string<Char> {
+ using base_type = internal::basic_hashed_string<Char>;
+ using params = internal::fnv_1a_params<>;
+
+ struct const_wrapper {
+ // non-explicit constructor on purpose
+ constexpr const_wrapper(const Char *str) noexcept
+ : repr{str} {}
+
+ const Char *repr;
+ };
+
+ // Fowler–Noll–Vo hash function v. 1a - the good
+ [[nodiscard]] static constexpr auto helper(const std::basic_string_view<Char> view) noexcept {
+ base_type base{view.data(), view.size(), params::offset};
+
+ for(auto &&curr: view) {
+ base.hash = (base.hash ^ static_cast<id_type>(curr)) * params::prime;
+ }
+
+ return base;
+ }
+
+public:
+ /*! @brief Character type. */
+ using value_type = typename base_type::value_type;
+ /*! @brief Unsigned integer type. */
+ using size_type = typename base_type::size_type;
+ /*! @brief Unsigned integer type. */
+ using hash_type = typename 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<std::size_t N>
+ // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays, modernize-avoid-c-arrays)
+ [[nodiscard]] static constexpr 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
+ : base_type{helper({str, len})} {}
+
+ /**
+ * @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<std::size_t N>
+ // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays, modernize-avoid-c-arrays)
+ constexpr basic_hashed_string(const value_type (&str)[N]) noexcept
+ : base_type{helper({static_cast<const value_type *>(str)})} {}
+
+ /**
+ * @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{helper({wrapper.repr})} {}
+
+ /**
+ * @brief Returns the size 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]] 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 Deduction guide.
+ * @tparam Char Character type.
+ * @param str Human-readable identifier.
+ * @param len Length of the string to hash.
+ */
+template<typename Char>
+basic_hashed_string(const Char *str, const std::size_t len) -> basic_hashed_string<Char>;
+
+/**
+ * @brief Deduction guide.
+ * @tparam Char Character type.
+ * @tparam N Number of characters of the identifier.
+ * @param str Human-readable identifier.
+ */
+template<typename Char, std::size_t N>
+// NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays, modernize-avoid-c-arrays)
+basic_hashed_string(const Char (&str)[N]) -> basic_hashed_string<Char>;
+
+/**
+ * @brief Compares two hashed strings.
+ * @tparam Char Character type.
+ * @param lhs A valid hashed string.
+ * @param rhs A valid hashed string.
+ * @return True if the two hashed strings are identical, false otherwise.
+ */
+template<typename Char>
+[[nodiscard]] constexpr bool operator==(const basic_hashed_string<Char> &lhs, const basic_hashed_string<Char> &rhs) noexcept {
+ return lhs.value() == rhs.value();
+}
+
+/**
+ * @brief Compares two hashed strings.
+ * @tparam Char Character type.
+ * @param lhs A valid hashed string.
+ * @param rhs A valid hashed string.
+ * @return True if the two hashed strings differ, false otherwise.
+ */
+template<typename Char>
+[[nodiscard]] constexpr bool operator!=(const basic_hashed_string<Char> &lhs, const basic_hashed_string<Char> &rhs) noexcept {
+ return !(lhs == rhs);
+}
+
+/**
+ * @brief Compares two hashed strings.
+ * @tparam Char Character type.
+ * @param lhs A valid hashed string.
+ * @param rhs A valid hashed string.
+ * @return True if the first element is less than the second, false otherwise.
+ */
+template<typename Char>
+[[nodiscard]] constexpr bool operator<(const basic_hashed_string<Char> &lhs, const basic_hashed_string<Char> &rhs) noexcept {
+ return lhs.value() < rhs.value();
+}
+
+/**
+ * @brief Compares two hashed strings.
+ * @tparam Char Character type.
+ * @param lhs A valid hashed string.
+ * @param rhs A valid hashed string.
+ * @return True if the first element is less than or equal to the second, false
+ * otherwise.
+ */
+template<typename Char>
+[[nodiscard]] constexpr bool operator<=(const basic_hashed_string<Char> &lhs, const basic_hashed_string<Char> &rhs) noexcept {
+ return !(rhs < lhs);
+}
+
+/**
+ * @brief Compares two hashed strings.
+ * @tparam Char Character type.
+ * @param lhs A valid hashed string.
+ * @param rhs A valid hashed string.
+ * @return True if the first element is greater than the second, false
+ * otherwise.
+ */
+template<typename Char>
+[[nodiscard]] constexpr bool operator>(const basic_hashed_string<Char> &lhs, const basic_hashed_string<Char> &rhs) noexcept {
+ return rhs < lhs;
+}
+
+/**
+ * @brief Compares two hashed strings.
+ * @tparam Char Character type.
+ * @param lhs A valid hashed string.
+ * @param rhs A valid hashed string.
+ * @return True if the first element is greater than or equal to the second,
+ * false otherwise.
+ */
+template<typename Char>
+[[nodiscard]] constexpr bool operator>=(const basic_hashed_string<Char> &lhs, const basic_hashed_string<Char> &rhs) noexcept {
+ return !(lhs < rhs);
+}
+
+inline namespace literals {
+
+/**
+ * @brief User defined literal for hashed strings.
+ * @param str The literal without its suffix.
+ * @return A properly initialized hashed string.
+ */
+[[nodiscard]] constexpr hashed_string operator"" _hs(const char *str, std::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]] constexpr hashed_wstring operator"" _hws(const wchar_t *str, std::size_t) noexcept {
+ return hashed_wstring{str};
+}
+
+} // namespace literals
+
+} // namespace entt
+
+#endif
diff --git a/deps/include/entt/core/ident.hpp b/deps/include/entt/core/ident.hpp new file mode 100644 index 0000000..5944ea2 --- /dev/null +++ b/deps/include/entt/core/ident.hpp @@ -0,0 +1,35 @@ +#ifndef ENTT_CORE_IDENT_HPP
+#define ENTT_CORE_IDENT_HPP
+
+#include <cstddef>
+#include <type_traits>
+#include <utility>
+#include "fwd.hpp"
+#include "type_traits.hpp"
+
+namespace entt {
+
+/**
+ * @brief Type integral identifiers.
+ * @tparam Type List of types for which to generate identifiers.
+ */
+template<typename... Type>
+class ident {
+ template<typename Curr, std::size_t... Index>
+ [[nodiscard]] static constexpr id_type get(std::index_sequence<Index...>) noexcept {
+ static_assert((std::is_same_v<Curr, Type> || ...), "Invalid type");
+ return (0 + ... + (std::is_same_v<Curr, type_list_element_t<Index, type_list<std::decay_t<Type>...>>> ? 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<typename Curr>
+ static constexpr value_type value = get<std::decay_t<Curr>>(std::index_sequence_for<Type...>{});
+};
+
+} // namespace entt
+
+#endif
diff --git a/deps/include/entt/core/iterator.hpp b/deps/include/entt/core/iterator.hpp new file mode 100644 index 0000000..fdb2ee2 --- /dev/null +++ b/deps/include/entt/core/iterator.hpp @@ -0,0 +1,197 @@ +#ifndef ENTT_CORE_ITERATOR_HPP
+#define ENTT_CORE_ITERATOR_HPP
+
+#include <iterator>
+#include <memory>
+#include <type_traits>
+#include <utility>
+
+namespace entt {
+
+/**
+ * @brief Helper type to use as pointer with input iterators.
+ * @tparam Type of wrapped value.
+ */
+template<typename Type>
+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(std::is_nothrow_move_constructible_v<value_type>)
+ : value{std::move(val)} {}
+
+ /**
+ * @brief Access operator for accessing wrapped values.
+ * @return A pointer to the wrapped value.
+ */
+ [[nodiscard]] constexpr pointer operator->() noexcept {
+ return std::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<typename Type>
+class iota_iterator final {
+ static_assert(std::is_integral_v<Type>, "Not an integral type");
+
+public:
+ /*! @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 = std::ptrdiff_t;
+ /*! @brief Iterator category. */
+ using iterator_category = std::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 {
+ iota_iterator orig = *this;
+ return ++(*this), orig;
+ }
+
+ /**
+ * @brief Dereference operator.
+ * @return The underlying value.
+ */
+ [[nodiscard]] constexpr reference operator*() const noexcept {
+ return current;
+ }
+
+private:
+ value_type current;
+};
+
+/**
+ * @brief Comparison operator.
+ * @tparam Type Value type of the iota iterator.
+ * @param lhs A properly initialized iota iterator.
+ * @param rhs A properly initialized iota iterator.
+ * @return True if the two iterators are identical, false otherwise.
+ */
+template<typename Type>
+[[nodiscard]] constexpr bool operator==(const iota_iterator<Type> &lhs, const iota_iterator<Type> &rhs) noexcept {
+ return *lhs == *rhs;
+}
+
+/**
+ * @brief Comparison operator.
+ * @tparam Type Value type of the iota iterator.
+ * @param lhs A properly initialized iota iterator.
+ * @param rhs A properly initialized iota iterator.
+ * @return True if the two iterators differ, false otherwise.
+ */
+template<typename Type>
+[[nodiscard]] constexpr bool operator!=(const iota_iterator<Type> &lhs, const iota_iterator<Type> &rhs) noexcept {
+ return !(lhs == rhs);
+}
+
+/**
+ * @brief Utility class to create an iterable object from a pair of iterators.
+ * @tparam It Type of iterator.
+ * @tparam Sentinel Type of sentinel.
+ */
+template<typename It, typename Sentinel = It>
+struct iterable_adaptor final {
+ /*! @brief Value type. */
+ using value_type = typename std::iterator_traits<It>::value_type;
+ /*! @brief Iterator type. */
+ using iterator = It;
+ /*! @brief Sentinel type. */
+ using sentinel = Sentinel;
+
+ /*! @brief Default constructor. */
+ constexpr iterable_adaptor() noexcept(std::is_nothrow_default_constructible_v<iterator> &&std::is_nothrow_default_constructible_v<sentinel>)
+ : 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(std::is_nothrow_move_constructible_v<iterator> &&std::is_nothrow_move_constructible_v<sentinel>)
+ : first{std::move(from)},
+ last{std::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/deps/include/entt/core/memory.hpp b/deps/include/entt/core/memory.hpp new file mode 100644 index 0000000..58fda45 --- /dev/null +++ b/deps/include/entt/core/memory.hpp @@ -0,0 +1,244 @@ +#ifndef ENTT_CORE_MEMORY_HPP
+#define ENTT_CORE_MEMORY_HPP
+
+#include <cstddef>
+#include <memory>
+#include <tuple>
+#include <type_traits>
+#include <utility>
+#include "../config/config.h"
+
+namespace entt {
+
+/**
+ * @brief Unwraps fancy pointers, does nothing otherwise (waiting for C++20).
+ * @tparam Type Pointer type.
+ * @param ptr Fancy or raw pointer.
+ * @return A raw pointer that represents the address of the original pointer.
+ */
+template<typename Type>
+[[nodiscard]] constexpr auto to_address(Type &&ptr) noexcept {
+ if constexpr(std::is_pointer_v<std::decay_t<Type>>) {
+ return ptr;
+ } else {
+ return to_address(std::forward<Type>(ptr).operator->());
+ }
+}
+
+/**
+ * @brief Utility function to design allocation-aware containers.
+ * @tparam Allocator Type of allocator.
+ * @param lhs A valid allocator.
+ * @param rhs Another valid allocator.
+ */
+template<typename Allocator>
+constexpr void propagate_on_container_copy_assignment([[maybe_unused]] Allocator &lhs, [[maybe_unused]] Allocator &rhs) noexcept {
+ if constexpr(std::allocator_traits<Allocator>::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<typename Allocator>
+constexpr void propagate_on_container_move_assignment([[maybe_unused]] Allocator &lhs, [[maybe_unused]] Allocator &rhs) noexcept {
+ if constexpr(std::allocator_traits<Allocator>::propagate_on_container_move_assignment::value) {
+ lhs = std::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<typename Allocator>
+constexpr void propagate_on_container_swap([[maybe_unused]] Allocator &lhs, [[maybe_unused]] Allocator &rhs) noexcept {
+ if constexpr(std::allocator_traits<Allocator>::propagate_on_container_swap::value) {
+ using std::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<typename Allocator>
+struct allocation_deleter: private Allocator {
+ /*! @brief Allocator type. */
+ using allocator_type = Allocator;
+ /*! @brief Pointer type. */
+ using pointer = typename std::allocator_traits<Allocator>::pointer;
+
+ /**
+ * @brief Inherited constructors.
+ * @param alloc The allocator to use.
+ */
+ constexpr allocation_deleter(const allocator_type &alloc) noexcept(std::is_nothrow_copy_constructible_v<allocator_type>)
+ : 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(std::is_nothrow_destructible_v<typename allocator_type::value_type>) {
+ using alloc_traits = std::allocator_traits<Allocator>;
+ alloc_traits::destroy(*this, to_address(ptr));
+ alloc_traits::deallocate(*this, ptr, 1u);
+ }
+};
+
+/**
+ * @brief Allows `std::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<typename Type, typename Allocator, typename... Args>
+ENTT_CONSTEXPR auto allocate_unique(Allocator &allocator, Args &&...args) {
+ static_assert(!std::is_array_v<Type>, "Array types are not supported");
+
+ using alloc_traits = typename std::allocator_traits<Allocator>::template rebind_traits<Type>;
+ using allocator_type = typename alloc_traits::allocator_type;
+
+ allocator_type alloc{allocator};
+ auto ptr = alloc_traits::allocate(alloc, 1u);
+
+ ENTT_TRY {
+ alloc_traits::construct(alloc, to_address(ptr), std::forward<Args>(args)...);
+ }
+ ENTT_CATCH {
+ alloc_traits::deallocate(alloc, ptr, 1u);
+ ENTT_THROW;
+ }
+
+ return std::unique_ptr<Type, allocation_deleter<allocator_type>>{ptr, alloc};
+}
+
+/*! @cond TURN_OFF_DOXYGEN */
+namespace internal {
+
+template<typename Type>
+struct uses_allocator_construction {
+ template<typename Allocator, typename... Params>
+ static constexpr auto args([[maybe_unused]] const Allocator &allocator, Params &&...params) noexcept {
+ if constexpr(!std::uses_allocator_v<Type, Allocator> && std::is_constructible_v<Type, Params...>) {
+ return std::forward_as_tuple(std::forward<Params>(params)...);
+ } else {
+ static_assert(std::uses_allocator_v<Type, Allocator>, "Ill-formed request");
+
+ if constexpr(std::is_constructible_v<Type, std::allocator_arg_t, const Allocator &, Params...>) {
+ return std::tuple<std::allocator_arg_t, const Allocator &, Params &&...>{std::allocator_arg, allocator, std::forward<Params>(params)...};
+ } else {
+ static_assert(std::is_constructible_v<Type, Params..., const Allocator &>, "Ill-formed request");
+ return std::forward_as_tuple(std::forward<Params>(params)..., allocator);
+ }
+ }
+ }
+};
+
+template<typename Type, typename Other>
+struct uses_allocator_construction<std::pair<Type, Other>> {
+ using type = std::pair<Type, Other>;
+
+ template<typename Allocator, typename First, typename Second>
+ static constexpr auto args(const Allocator &allocator, std::piecewise_construct_t, First &&first, Second &&second) noexcept {
+ return std::make_tuple(
+ std::piecewise_construct,
+ std::apply([&allocator](auto &&...curr) { return uses_allocator_construction<Type>::args(allocator, std::forward<decltype(curr)>(curr)...); }, std::forward<First>(first)),
+ std::apply([&allocator](auto &&...curr) { return uses_allocator_construction<Other>::args(allocator, std::forward<decltype(curr)>(curr)...); }, std::forward<Second>(second)));
+ }
+
+ template<typename Allocator>
+ static constexpr auto args(const Allocator &allocator) noexcept {
+ return uses_allocator_construction<type>::args(allocator, std::piecewise_construct, std::tuple<>{}, std::tuple<>{});
+ }
+
+ template<typename Allocator, typename First, typename Second>
+ static constexpr auto args(const Allocator &allocator, First &&first, Second &&second) noexcept {
+ return uses_allocator_construction<type>::args(allocator, std::piecewise_construct, std::forward_as_tuple(std::forward<First>(first)), std::forward_as_tuple(std::forward<Second>(second)));
+ }
+
+ template<typename Allocator, typename First, typename Second>
+ static constexpr auto args(const Allocator &allocator, const std::pair<First, Second> &value) noexcept {
+ return uses_allocator_construction<type>::args(allocator, std::piecewise_construct, std::forward_as_tuple(value.first), std::forward_as_tuple(value.second));
+ }
+
+ template<typename Allocator, typename First, typename Second>
+ static constexpr auto args(const Allocator &allocator, std::pair<First, Second> &&value) noexcept {
+ return uses_allocator_construction<type>::args(allocator, std::piecewise_construct, std::forward_as_tuple(std::move(value.first)), std::forward_as_tuple(std::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 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 The arguments needed to create an object of the given type.
+ */
+template<typename Type, typename Allocator, typename... Args>
+constexpr auto uses_allocator_construction_args(const Allocator &allocator, Args &&...args) noexcept {
+ return internal::uses_allocator_construction<Type>::args(allocator, std::forward<Args>(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 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 newly created object of the given type.
+ */
+template<typename Type, typename Allocator, typename... Args>
+constexpr Type make_obj_using_allocator(const Allocator &allocator, Args &&...args) {
+ return std::make_from_tuple<Type>(internal::uses_allocator_construction<Type>::args(allocator, std::forward<Args>(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 Allocator Type of allocator used to manage memory and elements.
+ * @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<typename Type, typename Allocator, typename... Args>
+constexpr Type *uninitialized_construct_using_allocator(Type *value, const Allocator &allocator, Args &&...args) {
+ return std::apply([value](auto &&...curr) { return ::new(value) Type(std::forward<decltype(curr)>(curr)...); }, internal::uses_allocator_construction<Type>::args(allocator, std::forward<Args>(args)...));
+}
+
+} // namespace entt
+
+#endif
diff --git a/deps/include/entt/core/monostate.hpp b/deps/include/entt/core/monostate.hpp new file mode 100644 index 0000000..57f5f41 --- /dev/null +++ b/deps/include/entt/core/monostate.hpp @@ -0,0 +1,60 @@ +#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.<br/>
+ * 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<id_type>
+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<typename Type>
+ monostate &operator=(Type val) noexcept {
+ value<Type> = 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<typename Type>
+ operator Type() const noexcept {
+ return value<Type>;
+ }
+
+private:
+ template<typename Type>
+ // 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<id_type Value>
+// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
+inline monostate<Value> monostate_v{};
+
+} // namespace entt
+
+#endif
diff --git a/deps/include/entt/core/ranges.hpp b/deps/include/entt/core/ranges.hpp new file mode 100644 index 0000000..430229f --- /dev/null +++ b/deps/include/entt/core/ranges.hpp @@ -0,0 +1,20 @@ +#ifndef ENTT_CORE_RANGES_HPP
+#define ENTT_CORE_RANGES_HPP
+
+#if __has_include(<version>)
+# include <version>
+#
+# if defined(__cpp_lib_ranges)
+# include <ranges>
+# include "iterator.hpp"
+
+template<class... Args>
+inline constexpr bool std::ranges::enable_borrowed_range<entt::iterable_adaptor<Args...>>{true};
+
+template<class... Args>
+inline constexpr bool std::ranges::enable_view<entt::iterable_adaptor<Args...>>{true};
+
+# endif
+#endif
+
+#endif
\ No newline at end of file diff --git a/deps/include/entt/core/tuple.hpp b/deps/include/entt/core/tuple.hpp new file mode 100644 index 0000000..a64c51c --- /dev/null +++ b/deps/include/entt/core/tuple.hpp @@ -0,0 +1,95 @@ +#ifndef ENTT_CORE_TUPLE_HPP
+#define ENTT_CORE_TUPLE_HPP
+
+#include <tuple>
+#include <type_traits>
+#include <utility>
+
+namespace entt {
+
+/*! @cond TURN_OFF_DOXYGEN */
+namespace internal {
+
+template<typename>
+struct is_tuple_impl: std::false_type {};
+
+template<typename... Args>
+struct is_tuple_impl<std::tuple<Args...>>: std::true_type {};
+
+} // namespace internal
+/*! @endcond */
+
+/**
+ * @brief Provides the member constant `value` to true if a given type is a
+ * tuple, false otherwise.
+ * @tparam Type The type to test.
+ */
+template<typename Type>
+struct is_tuple: internal::is_tuple_impl<std::remove_cv_t<Type>> {};
+
+/**
+ * @brief Helper variable template.
+ * @tparam Type The type to test.
+ */
+template<typename Type>
+inline constexpr bool is_tuple_v = is_tuple<Type>::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<typename Type>
+constexpr decltype(auto) unwrap_tuple(Type &&value) noexcept {
+ if constexpr(std::tuple_size_v<std::remove_reference_t<Type>> == 1u) {
+ return std::get<0>(std::forward<Type>(value));
+ } else {
+ return std::forward<Type>(value);
+ }
+}
+
+/**
+ * @brief Utility class to forward-and-apply tuple objects.
+ * @tparam Func Type of underlying invocable object.
+ */
+template<typename Func>
+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<typename... Args>
+ constexpr forward_apply(Args &&...args) noexcept(std::is_nothrow_constructible_v<Func, Args...>)
+ : Func{std::forward<Args>(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<typename Type>
+ constexpr decltype(auto) operator()(Type &&args) noexcept(noexcept(std::apply(std::declval<Func &>(), args))) {
+ return std::apply(static_cast<Func &>(*this), std::forward<Type>(args));
+ }
+
+ /*! @copydoc operator()() */
+ template<typename Type>
+ constexpr decltype(auto) operator()(Type &&args) const noexcept(noexcept(std::apply(std::declval<const Func &>(), args))) {
+ return std::apply(static_cast<const Func &>(*this), std::forward<Type>(args));
+ }
+};
+
+/**
+ * @brief Deduction guide.
+ * @tparam Func Type of underlying invocable object.
+ */
+template<typename Func>
+forward_apply(Func) -> forward_apply<std::remove_reference_t<std::remove_cv_t<Func>>>;
+
+} // namespace entt
+
+#endif
diff --git a/deps/include/entt/core/type_info.hpp b/deps/include/entt/core/type_info.hpp new file mode 100644 index 0000000..e03a8e1 --- /dev/null +++ b/deps/include/entt/core/type_info.hpp @@ -0,0 +1,268 @@ +#ifndef ENTT_CORE_TYPE_INFO_HPP
+#define ENTT_CORE_TYPE_INFO_HPP
+
+#include <string_view>
+#include <type_traits>
+#include <utility>
+#include "../config/config.h"
+#include "../core/attribute.h"
+#include "fwd.hpp"
+#include "hashed_string.hpp"
+
+namespace entt {
+
+/*! @cond TURN_OFF_DOXYGEN */
+namespace internal {
+
+struct ENTT_API type_index final {
+ [[nodiscard]] static id_type next() noexcept {
+ static ENTT_MAYBE_ATOMIC(id_type) value{};
+ return value++;
+ }
+};
+
+template<typename Type>
+[[nodiscard]] constexpr auto stripped_type_name() noexcept {
+#if defined ENTT_PRETTY_FUNCTION
+ std::string_view pretty_function{static_cast<const char *>(ENTT_PRETTY_FUNCTION)};
+ auto first = pretty_function.find_first_not_of(' ', pretty_function.find_first_of(ENTT_PRETTY_FUNCTION_PREFIX) + 1);
+ auto value = pretty_function.substr(first, pretty_function.find_last_of(ENTT_PRETTY_FUNCTION_SUFFIX) - first);
+ return value;
+#else
+ return std::string_view{""};
+#endif
+}
+
+template<typename Type, auto = stripped_type_name<Type>().find_first_of('.')>
+[[nodiscard]] constexpr std::string_view type_name(int) noexcept {
+ constexpr auto value = stripped_type_name<Type>();
+ return value;
+}
+
+template<typename Type>
+[[nodiscard]] std::string_view type_name(char) noexcept {
+ static const auto value = stripped_type_name<Type>();
+ return value;
+}
+
+template<typename Type, auto = stripped_type_name<Type>().find_first_of('.')>
+[[nodiscard]] constexpr id_type type_hash(int) noexcept {
+ constexpr auto stripped = stripped_type_name<Type>();
+ constexpr auto value = hashed_string::value(stripped.data(), stripped.size());
+ return value;
+}
+
+template<typename Type>
+[[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<Type>());
+ return value;
+}
+
+} // namespace internal
+/*! @endcond */
+
+/**
+ * @brief Type sequential identifier.
+ * @tparam Type Type for which to generate a sequential identifier.
+ */
+template<typename Type, typename = void>
+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<typename Type, typename = void>
+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<Type>(0);
+#else
+ [[nodiscard]] static constexpr id_type value() noexcept {
+ return type_index<Type>::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<typename Type, typename = void>
+struct type_name final {
+ /**
+ * @brief Returns the name of a given type.
+ * @return The name of the given type.
+ */
+ [[nodiscard]] static constexpr std::string_view value() noexcept {
+ return internal::type_name<Type>(0);
+ }
+
+ /*! @copydoc value */
+ [[nodiscard]] constexpr operator std::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<typename Type>
+ // NOLINTBEGIN(modernize-use-transparent-functors)
+ constexpr type_info(std::in_place_type_t<Type>) noexcept
+ : seq{type_index<std::remove_cv_t<std::remove_reference_t<Type>>>::value()},
+ identifier{type_hash<std::remove_cv_t<std::remove_reference_t<Type>>>::value()},
+ alias{type_name<std::remove_cv_t<std::remove_reference_t<Type>>>::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 std::string_view name() const noexcept {
+ return alias;
+ }
+
+private:
+ id_type seq;
+ id_type identifier;
+ std::string_view alias;
+};
+
+/**
+ * @brief Compares the contents of two type info objects.
+ * @param lhs A type info object.
+ * @param rhs A type info object.
+ * @return True if the two type info objects are identical, false otherwise.
+ */
+[[nodiscard]] inline constexpr bool operator==(const type_info &lhs, const type_info &rhs) noexcept {
+ return lhs.hash() == rhs.hash();
+}
+
+/**
+ * @brief Compares the contents of two type info objects.
+ * @param lhs A type info object.
+ * @param rhs A type info object.
+ * @return True if the two type info objects differ, false otherwise.
+ */
+[[nodiscard]] inline constexpr bool operator!=(const type_info &lhs, const type_info &rhs) noexcept {
+ return !(lhs == rhs);
+}
+
+/**
+ * @brief Compares two type info objects.
+ * @param lhs A valid type info object.
+ * @param rhs A valid type info object.
+ * @return True if the first element is less than the second, false otherwise.
+ */
+[[nodiscard]] inline constexpr bool operator<(const type_info &lhs, const type_info &rhs) noexcept {
+ return lhs.index() < rhs.index();
+}
+
+/**
+ * @brief Compares two type info objects.
+ * @param lhs A valid type info object.
+ * @param rhs A valid type info object.
+ * @return True if the first element is less than or equal to the second, false
+ * otherwise.
+ */
+[[nodiscard]] inline constexpr bool operator<=(const type_info &lhs, const type_info &rhs) noexcept {
+ return !(rhs < lhs);
+}
+
+/**
+ * @brief Compares two type info objects.
+ * @param lhs A valid type info object.
+ * @param rhs A valid type info object.
+ * @return True if the first element is greater than the second, false
+ * otherwise.
+ */
+[[nodiscard]] inline constexpr bool operator>(const type_info &lhs, const type_info &rhs) noexcept {
+ return rhs < lhs;
+}
+
+/**
+ * @brief Compares two type info objects.
+ * @param lhs A valid type info object.
+ * @param rhs A valid type info object.
+ * @return True if the first element is greater than or equal to the second,
+ * false otherwise.
+ */
+[[nodiscard]] inline constexpr bool operator>=(const type_info &lhs, const type_info &rhs) noexcept {
+ return !(lhs < rhs);
+}
+
+/**
+ * @brief Returns the type info object associated to a given type.
+ *
+ * The returned element refers to an object with static storage duration.<br/>
+ * 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<typename Type>
+[[nodiscard]] const type_info &type_id() noexcept {
+ if constexpr(std::is_same_v<Type, std::remove_cv_t<std::remove_reference_t<Type>>>) {
+ static type_info instance{std::in_place_type<Type>};
+ return instance;
+ } else {
+ return type_id<std::remove_cv_t<std::remove_reference_t<Type>>>();
+ }
+}
+
+/*! @copydoc type_id */
+template<typename Type>
+[[nodiscard]] const type_info &type_id(Type &&) noexcept {
+ return type_id<std::remove_cv_t<std::remove_reference_t<Type>>>();
+}
+
+} // namespace entt
+
+#endif
diff --git a/deps/include/entt/core/type_traits.hpp b/deps/include/entt/core/type_traits.hpp new file mode 100644 index 0000000..16b4dad --- /dev/null +++ b/deps/include/entt/core/type_traits.hpp @@ -0,0 +1,919 @@ +#ifndef ENTT_CORE_TYPE_TRAITS_HPP
+#define ENTT_CORE_TYPE_TRAITS_HPP
+
+#include <cstddef>
+#include <iterator>
+#include <tuple>
+#include <type_traits>
+#include <utility>
+#include "../config/config.h"
+#include "fwd.hpp"
+
+namespace entt {
+
+/**
+ * @brief Utility class to disambiguate overloaded functions.
+ * @tparam N Number of choices available.
+ */
+template<std::size_t N>
+struct choice_t
+ // unfortunately, doxygen cannot parse such a construct
+ : /*! @cond TURN_OFF_DOXYGEN */ choice_t<N - 1> /*! @endcond */
+{};
+
+/*! @copybrief choice_t */
+template<>
+struct choice_t<0> {};
+
+/**
+ * @brief Variable template for the choice trick.
+ * @tparam N Number of choices available.
+ */
+template<std::size_t N>
+inline constexpr choice_t<N> choice{};
+
+/**
+ * @brief Identity type trait.
+ *
+ * Useful to establish non-deduced contexts in template argument deduction
+ * (waiting for C++20) or to provide types through function arguments.
+ *
+ * @tparam Type A type.
+ */
+template<typename Type>
+struct type_identity {
+ /*! @brief Identity type. */
+ using type = Type;
+};
+
+/**
+ * @brief Helper type.
+ * @tparam Type A type.
+ */
+template<typename Type>
+using type_identity_t = typename type_identity<Type>::type;
+
+/**
+ * @brief A type-only `sizeof` wrapper that returns 0 where `sizeof` complains.
+ * @tparam Type The type of which to return the size.
+ */
+template<typename Type, typename = void>
+struct size_of: std::integral_constant<std::size_t, 0u> {};
+
+/*! @copydoc size_of */
+template<typename Type>
+struct size_of<Type, std::void_t<decltype(sizeof(Type))>>
+ : std::integral_constant<std::size_t, sizeof(Type)> {};
+
+/**
+ * @brief Helper variable template.
+ * @tparam Type The type of which to return the size.
+ */
+template<typename Type>
+inline constexpr std::size_t size_of_v = size_of<Type>::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<typename Type, typename>
+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<auto Value, typename>
+inline constexpr auto unpack_as_value = Value;
+
+/**
+ * @brief Wraps a static constant.
+ * @tparam Value A static constant.
+ */
+template<auto Value>
+using integral_constant = std::integral_constant<decltype(Value), Value>;
+
+/**
+ * @brief Alias template to facilitate the creation of named values.
+ * @tparam Value A constant value at least convertible to `id_type`.
+ */
+template<id_type Value>
+using tag = integral_constant<Value>;
+
+/**
+ * @brief A class to use to push around lists of types, nothing more.
+ * @tparam Type Types provided by the type list.
+ */
+template<typename... Type>
+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<std::size_t, typename>
+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<std::size_t Index, typename First, typename... Other>
+struct type_list_element<Index, type_list<First, Other...>>
+ : type_list_element<Index - 1u, type_list<Other...>> {};
+
+/**
+ * @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<typename First, typename... Other>
+struct type_list_element<0u, type_list<First, Other...>> {
+ /*! @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<std::size_t Index, typename List>
+using type_list_element_t = typename type_list_element<Index, List>::type;
+
+/*! @brief Primary template isn't defined on purpose. */
+template<typename, typename>
+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<typename Type, typename First, typename... Other>
+struct type_list_index<Type, type_list<First, Other...>> {
+ /*! @brief Unsigned integer type. */
+ using value_type = std::size_t;
+ /*! @brief Compile-time position of the given type in the sublist. */
+ static constexpr value_type value = 1u + type_list_index<Type, type_list<Other...>>::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<typename Type, typename... Other>
+struct type_list_index<Type, type_list<Type, Other...>> {
+ static_assert(type_list_index<Type, type_list<Other...>>::value == sizeof...(Other), "Non-unique type");
+ /*! @brief Unsigned integer type. */
+ using value_type = std::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<typename Type>
+struct type_list_index<Type, type_list<>> {
+ /*! @brief Unsigned integer type. */
+ using value_type = std::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<typename Type, typename List>
+inline constexpr std::size_t type_list_index_v = type_list_index<Type, List>::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<typename... Type, typename... Other>
+constexpr type_list<Type..., Other...> operator+(type_list<Type...>, type_list<Other...>) {
+ return {};
+}
+
+/*! @brief Primary template isn't defined on purpose. */
+template<typename...>
+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<typename... Type, typename... Other, typename... List>
+struct type_list_cat<type_list<Type...>, type_list<Other...>, List...> {
+ /*! @brief A type list composed by the types of all the type lists. */
+ using type = typename type_list_cat<type_list<Type..., Other...>, List...>::type;
+};
+
+/**
+ * @brief Concatenates multiple type lists.
+ * @tparam Type Types provided by the type list.
+ */
+template<typename... Type>
+struct type_list_cat<type_list<Type...>> {
+ /*! @brief A type list composed by the types of all the type lists. */
+ using type = type_list<Type...>;
+};
+
+/**
+ * @brief Helper type.
+ * @tparam List Type lists to concatenate.
+ */
+template<typename... List>
+using type_list_cat_t = typename type_list_cat<List...>::type;
+
+/*! @cond TURN_OFF_DOXYGEN */
+namespace internal {
+
+template<typename...>
+struct type_list_unique;
+
+template<typename First, typename... Other, typename... Type>
+struct type_list_unique<type_list<First, Other...>, Type...>
+ : std::conditional_t<(std::is_same_v<First, Type> || ...), type_list_unique<type_list<Other...>, Type...>, type_list_unique<type_list<Other...>, Type..., First>> {};
+
+template<typename... Type>
+struct type_list_unique<type_list<>, Type...> {
+ using type = type_list<Type...>;
+};
+
+} // namespace internal
+/*! @endcond */
+
+/**
+ * @brief Removes duplicates types from a type list.
+ * @tparam List Type list.
+ */
+template<typename List>
+struct type_list_unique {
+ /*! @brief A type list without duplicate types. */
+ using type = typename internal::type_list_unique<List>::type;
+};
+
+/**
+ * @brief Helper type.
+ * @tparam List Type list.
+ */
+template<typename List>
+using type_list_unique_t = typename type_list_unique<List>::type;
+
+/**
+ * @brief Provides the member constant `value` to true if a type list contains a
+ * given type, false otherwise.
+ * @tparam List Type list.
+ * @tparam Type Type to look for.
+ */
+template<typename List, typename Type>
+struct type_list_contains;
+
+/**
+ * @copybrief type_list_contains
+ * @tparam Type Types provided by the type list.
+ * @tparam Other Type to look for.
+ */
+template<typename... Type, typename Other>
+struct type_list_contains<type_list<Type...>, Other>
+ : std::bool_constant<(std::is_same_v<Type, Other> || ...)> {};
+
+/**
+ * @brief Helper variable template.
+ * @tparam List Type list.
+ * @tparam Type Type to look for.
+ */
+template<typename List, typename Type>
+inline constexpr bool type_list_contains_v = type_list_contains<List, Type>::value;
+
+/*! @brief Primary template isn't defined on purpose. */
+template<typename...>
+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<typename... Type, typename... Other>
+struct type_list_diff<type_list<Type...>, type_list<Other...>> {
+ /*! @brief A type list that is the difference between the two type lists. */
+ using type = type_list_cat_t<std::conditional_t<type_list_contains_v<type_list<Other...>, Type>, type_list<>, type_list<Type>>...>;
+};
+
+/**
+ * @brief Helper type.
+ * @tparam List Type lists between which to compute the difference.
+ */
+template<typename... List>
+using type_list_diff_t = typename type_list_diff<List...>::type;
+
+/*! @brief Primary template isn't defined on purpose. */
+template<typename, template<typename...> class>
+struct type_list_transform;
+
+/**
+ * @brief Applies a given _function_ to a type list and generate 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<typename... Type, template<typename...> class Op>
+struct type_list_transform<type_list<Type...>, Op> {
+ /*! @brief Resulting type list after applying the transform function. */
+ using type = type_list<typename Op<Type>::type...>;
+};
+
+/**
+ * @brief Helper type.
+ * @tparam List Type list.
+ * @tparam Op Unary operation as template class with a type member named `type`.
+ */
+template<typename List, template<typename...> class Op>
+using type_list_transform_t = typename type_list_transform<List, Op>::type;
+
+/**
+ * @brief A class to use to push around lists of constant values, nothing more.
+ * @tparam Value Values provided by the value list.
+ */
+template<auto... Value>
+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<std::size_t, typename>
+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<std::size_t Index, auto Value, auto... Other>
+struct value_list_element<Index, value_list<Value, Other...>>
+ : value_list_element<Index - 1u, value_list<Other...>> {};
+
+/**
+ * @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<auto Value, auto... Other>
+struct value_list_element<0u, value_list<Value, Other...>> {
+ /*! @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<std::size_t Index, typename List>
+using value_list_element_t = typename value_list_element<Index, List>::type;
+
+/**
+ * @brief Helper type.
+ * @tparam Index Index of the value to return.
+ * @tparam List Value list to search into.
+ */
+template<std::size_t Index, typename List>
+inline constexpr auto value_list_element_v = value_list_element<Index, List>::value;
+
+/*! @brief Primary template isn't defined on purpose. */
+template<auto, typename>
+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<auto Value, auto First, auto... Other>
+struct value_list_index<Value, value_list<First, Other...>> {
+ /*! @brief Unsigned integer type. */
+ using value_type = std::size_t;
+ /*! @brief Compile-time position of the given value in the sublist. */
+ static constexpr value_type value = 1u + value_list_index<Value, value_list<Other...>>::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<auto Value, auto... Other>
+struct value_list_index<Value, value_list<Value, Other...>> {
+ static_assert(value_list_index<Value, value_list<Other...>>::value == sizeof...(Other), "Non-unique type");
+ /*! @brief Unsigned integer type. */
+ using value_type = std::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<auto Value>
+struct value_list_index<Value, value_list<>> {
+ /*! @brief Unsigned integer type. */
+ using value_type = std::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<auto Value, typename List>
+inline constexpr std::size_t value_list_index_v = value_list_index<Value, List>::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<auto... Value, auto... Other>
+constexpr value_list<Value..., Other...> operator+(value_list<Value...>, value_list<Other...>) {
+ return {};
+}
+
+/*! @brief Primary template isn't defined on purpose. */
+template<typename...>
+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<auto... Value, auto... Other, typename... List>
+struct value_list_cat<value_list<Value...>, value_list<Other...>, List...> {
+ /*! @brief A value list composed by the values of all the value lists. */
+ using type = typename value_list_cat<value_list<Value..., Other...>, List...>::type;
+};
+
+/**
+ * @brief Concatenates multiple value lists.
+ * @tparam Value Values provided by the value list.
+ */
+template<auto... Value>
+struct value_list_cat<value_list<Value...>> {
+ /*! @brief A value list composed by the values of all the value lists. */
+ using type = value_list<Value...>;
+};
+
+/**
+ * @brief Helper type.
+ * @tparam List Value lists to concatenate.
+ */
+template<typename... List>
+using value_list_cat_t = typename value_list_cat<List...>::type;
+
+/*! @brief Primary template isn't defined on purpose. */
+template<typename>
+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<auto Value, auto... Other>
+struct value_list_unique<value_list<Value, Other...>> {
+ /*! @brief A value list without duplicate types. */
+ using type = std::conditional_t<
+ ((Value == Other) || ...),
+ typename value_list_unique<value_list<Other...>>::type,
+ value_list_cat_t<value_list<Value>, typename value_list_unique<value_list<Other...>>::type>>;
+};
+
+/*! @brief Removes duplicates values from a value list. */
+template<>
+struct value_list_unique<value_list<>> {
+ /*! @brief A value list without duplicate types. */
+ using type = value_list<>;
+};
+
+/**
+ * @brief Helper type.
+ * @tparam Type A value list.
+ */
+template<typename Type>
+using value_list_unique_t = typename value_list_unique<Type>::type;
+
+/**
+ * @brief Provides the member constant `value` to true if a value list contains
+ * a given value, false otherwise.
+ * @tparam List Value list.
+ * @tparam Value Value to look for.
+ */
+template<typename List, auto Value>
+struct value_list_contains;
+
+/**
+ * @copybrief value_list_contains
+ * @tparam Value Values provided by the value list.
+ * @tparam Other Value to look for.
+ */
+template<auto... Value, auto Other>
+struct value_list_contains<value_list<Value...>, Other>
+ : std::bool_constant<((Value == Other) || ...)> {};
+
+/**
+ * @brief Helper variable template.
+ * @tparam List Value list.
+ * @tparam Value Value to look for.
+ */
+template<typename List, auto Value>
+inline constexpr bool value_list_contains_v = value_list_contains<List, Value>::value;
+
+/*! @brief Primary template isn't defined on purpose. */
+template<typename...>
+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<auto... Value, auto... Other>
+struct value_list_diff<value_list<Value...>, value_list<Other...>> {
+ /*! @brief A value list that is the difference between the two value lists. */
+ using type = value_list_cat_t<std::conditional_t<value_list_contains_v<value_list<Other...>, Value>, value_list<>, value_list<Value>>...>;
+};
+
+/**
+ * @brief Helper type.
+ * @tparam List Value lists between which to compute the difference.
+ */
+template<typename... List>
+using value_list_diff_t = typename value_list_diff<List...>::type;
+
+/*! @brief Same as std::is_invocable, but with tuples. */
+template<typename, typename>
+struct is_applicable: std::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<typename Func, template<typename...> class Tuple, typename... Args>
+struct is_applicable<Func, Tuple<Args...>>: std::is_invocable<Func, Args...> {};
+
+/**
+ * @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<typename Func, template<typename...> class Tuple, typename... Args>
+struct is_applicable<Func, const Tuple<Args...>>: std::is_invocable<Func, Args...> {};
+
+/**
+ * @brief Helper variable template.
+ * @tparam Func A valid function type.
+ * @tparam Args The list of arguments to use to probe the function type.
+ */
+template<typename Func, typename Args>
+inline constexpr bool is_applicable_v = is_applicable<Func, Args>::value;
+
+/*! @brief Same as std::is_invocable_r, but with tuples for arguments. */
+template<typename, typename, typename>
+struct is_applicable_r: std::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<typename Ret, typename Func, typename... Args>
+struct is_applicable_r<Ret, Func, std::tuple<Args...>>: std::is_invocable_r<Ret, Func, Args...> {};
+
+/**
+ * @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<typename Ret, typename Func, typename Args>
+inline constexpr bool is_applicable_r_v = is_applicable_r<Ret, Func, Args>::value;
+
+/**
+ * @brief Provides the member constant `value` to true if a given type is
+ * complete, false otherwise.
+ * @tparam Type The type to test.
+ */
+template<typename Type, typename = void>
+struct is_complete: std::false_type {};
+
+/*! @copydoc is_complete */
+template<typename Type>
+struct is_complete<Type, std::void_t<decltype(sizeof(Type))>>: std::true_type {};
+
+/**
+ * @brief Helper variable template.
+ * @tparam Type The type to test.
+ */
+template<typename Type>
+inline constexpr bool is_complete_v = is_complete<Type>::value;
+
+/**
+ * @brief Provides the member constant `value` to true if a given type is an
+ * iterator, false otherwise.
+ * @tparam Type The type to test.
+ */
+template<typename Type, typename = void>
+struct is_iterator: std::false_type {};
+
+/*! @cond TURN_OFF_DOXYGEN */
+namespace internal {
+
+template<typename, typename = void>
+struct has_iterator_category: std::false_type {};
+
+template<typename Type>
+struct has_iterator_category<Type, std::void_t<typename std::iterator_traits<Type>::iterator_category>>: std::true_type {};
+
+} // namespace internal
+/*! @endcond */
+
+/*! @copydoc is_iterator */
+template<typename Type>
+struct is_iterator<Type, std::enable_if_t<!std::is_void_v<std::remove_cv_t<std::remove_pointer_t<Type>>>>>
+ : internal::has_iterator_category<Type> {};
+
+/**
+ * @brief Helper variable template.
+ * @tparam Type The type to test.
+ */
+template<typename Type>
+inline constexpr bool is_iterator_v = is_iterator<Type>::value;
+
+/**
+ * @brief Provides the member constant `value` to true if a given type is both
+ * an empty and non-final class, false otherwise.
+ * @tparam Type The type to test
+ */
+template<typename Type>
+struct is_ebco_eligible
+ : std::bool_constant<std::is_empty_v<Type> && !std::is_final_v<Type>> {};
+
+/**
+ * @brief Helper variable template.
+ * @tparam Type The type to test.
+ */
+template<typename Type>
+inline constexpr bool is_ebco_eligible_v = is_ebco_eligible<Type>::value;
+
+/**
+ * @brief Provides the member constant `value` to true if `Type::is_transparent`
+ * is valid and denotes a type, false otherwise.
+ * @tparam Type The type to test.
+ */
+template<typename Type, typename = void>
+struct is_transparent: std::false_type {};
+
+/*! @copydoc is_transparent */
+template<typename Type>
+struct is_transparent<Type, std::void_t<typename Type::is_transparent>>: std::true_type {};
+
+/**
+ * @brief Helper variable template.
+ * @tparam Type The type to test.
+ */
+template<typename Type>
+inline constexpr bool is_transparent_v = is_transparent<Type>::value;
+
+/*! @cond TURN_OFF_DOXYGEN */
+namespace internal {
+
+template<typename, typename = void>
+struct has_tuple_size_value: std::false_type {};
+
+template<typename Type>
+struct has_tuple_size_value<Type, std::void_t<decltype(std::tuple_size<const Type>::value)>>: std::true_type {};
+
+template<typename, typename = void>
+struct has_value_type: std::false_type {};
+
+template<typename Type>
+struct has_value_type<Type, std::void_t<typename Type::value_type>>: std::true_type {};
+
+template<typename>
+[[nodiscard]] constexpr bool dispatch_is_equality_comparable();
+
+template<typename Type, std::size_t... Index>
+[[nodiscard]] constexpr bool unpack_maybe_equality_comparable(std::index_sequence<Index...>) {
+ return (dispatch_is_equality_comparable<std::tuple_element_t<Index, Type>>() && ...);
+}
+
+template<typename>
+[[nodiscard]] constexpr bool maybe_equality_comparable(char) {
+ return false;
+}
+
+template<typename Type>
+[[nodiscard]] constexpr auto maybe_equality_comparable(int) -> decltype(std::declval<Type>() == std::declval<Type>()) {
+ return true;
+}
+
+template<typename Type>
+[[nodiscard]] constexpr bool dispatch_is_equality_comparable() {
+ // NOLINTBEGIN(modernize-use-transparent-functors)
+ if constexpr(std::is_array_v<Type>) {
+ return false;
+ } else if constexpr(!is_iterator_v<Type> && has_value_type<Type>::value) {
+ if constexpr(std::is_same_v<typename Type::value_type, Type> || dispatch_is_equality_comparable<typename Type::value_type>()) {
+ return maybe_equality_comparable<Type>(0);
+ } else {
+ return false;
+ }
+ } else if constexpr(is_complete_v<std::tuple_size<std::remove_cv_t<Type>>>) {
+ if constexpr(has_tuple_size_value<Type>::value) {
+ return maybe_equality_comparable<Type>(0) && unpack_maybe_equality_comparable<Type>(std::make_index_sequence<std::tuple_size<Type>::value>{});
+ } else {
+ return maybe_equality_comparable<Type>(0);
+ }
+ } else {
+ return maybe_equality_comparable<Type>(0);
+ }
+ // NOLINTEND(modernize-use-transparent-functors)
+}
+
+} // namespace internal
+/*! @endcond */
+
+/**
+ * @brief Provides the member constant `value` to true if a given type is
+ * equality comparable, false otherwise.
+ * @tparam Type The type to test.
+ */
+template<typename Type>
+struct is_equality_comparable: std::bool_constant<internal::dispatch_is_equality_comparable<Type>()> {};
+
+/*! @copydoc is_equality_comparable */
+template<typename Type>
+struct is_equality_comparable<const Type>: is_equality_comparable<Type> {};
+
+/**
+ * @brief Helper variable template.
+ * @tparam Type The type to test.
+ */
+template<typename Type>
+inline constexpr bool is_equality_comparable_v = is_equality_comparable<Type>::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<typename To, typename From>
+struct constness_as {
+ /*! @brief The type resulting from the transcription of the constness. */
+ using type = std::remove_const_t<To>;
+};
+
+/*! @copydoc constness_as */
+template<typename To, typename From>
+struct constness_as<To, const From> {
+ /*! @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<typename To, typename From>
+using constness_as_t = typename constness_as<To, From>::type;
+
+/**
+ * @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<typename Member>
+class member_class {
+ static_assert(std::is_member_pointer_v<Member>, "Invalid pointer type to non-static member object or function");
+
+ template<typename Class, typename Ret, typename... Args>
+ static Class *clazz(Ret (Class::*)(Args...));
+
+ template<typename Class, typename Ret, typename... Args>
+ static Class *clazz(Ret (Class::*)(Args...) const);
+
+ template<typename Class, typename Type>
+ static Class *clazz(Type Class::*);
+
+public:
+ /*! @brief The class of the given non-static member object or function. */
+ using type = std::remove_pointer_t<decltype(clazz(std::declval<Member>()))>;
+};
+
+/**
+ * @brief Helper type.
+ * @tparam Member A pointer to a non-static member object or function.
+ */
+template<typename Member>
+using member_class_t = typename member_class<Member>::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<std::size_t Index, typename Candidate>
+class nth_argument {
+ template<typename Ret, typename... Args>
+ static constexpr type_list<Args...> pick_up(Ret (*)(Args...));
+
+ template<typename Ret, typename Class, typename... Args>
+ static constexpr type_list<Args...> pick_up(Ret (Class ::*)(Args...));
+
+ template<typename Ret, typename Class, typename... Args>
+ static constexpr type_list<Args...> pick_up(Ret (Class ::*)(Args...) const);
+
+ template<typename Type, typename Class>
+ static constexpr type_list<Type> pick_up(Type Class ::*);
+
+ template<typename Type>
+ static constexpr decltype(pick_up(&Type::operator())) pick_up(Type &&);
+
+public:
+ /*! @brief N-th argument of the _callable_ type. */
+ using type = type_list_element_t<Index, decltype(pick_up(std::declval<Candidate>()))>;
+};
+
+/**
+ * @brief Helper type.
+ * @tparam Index The index of the argument to extract.
+ * @tparam Candidate A valid function, member function or data member type.
+ */
+template<std::size_t Index, typename Candidate>
+using nth_argument_t = typename nth_argument<Index, Candidate>::type;
+
+} // namespace entt
+
+template<typename... Type>
+struct std::tuple_size<entt::type_list<Type...>>: std::integral_constant<std::size_t, entt::type_list<Type...>::size> {};
+
+template<std::size_t Index, typename... Type>
+struct std::tuple_element<Index, entt::type_list<Type...>>: entt::type_list_element<Index, entt::type_list<Type...>> {};
+
+template<auto... Value>
+struct std::tuple_size<entt::value_list<Value...>>: std::integral_constant<std::size_t, entt::value_list<Value...>::size> {};
+
+template<std::size_t Index, auto... Value>
+struct std::tuple_element<Index, entt::value_list<Value...>>: entt::value_list_element<Index, entt::value_list<Value...>> {};
+
+#endif
diff --git a/deps/include/entt/core/utility.hpp b/deps/include/entt/core/utility.hpp new file mode 100644 index 0000000..ddab926 --- /dev/null +++ b/deps/include/entt/core/utility.hpp @@ -0,0 +1,101 @@ +#ifndef ENTT_CORE_UTILITY_HPP
+#define ENTT_CORE_UTILITY_HPP
+
+#include <type_traits>
+#include <utility>
+
+namespace entt {
+
+/*! @brief Identity function object (waiting for C++20). */
+struct identity {
+ /*! @brief Indicates that this is a transparent function object. */
+ using is_transparent = void;
+
+ /**
+ * @brief Returns its argument unchanged.
+ * @tparam Type Type of the argument.
+ * @param value The actual argument.
+ * @return The submitted value as-is.
+ */
+ template<typename Type>
+ [[nodiscard]] constexpr Type &&operator()(Type &&value) const noexcept {
+ return std::forward<Type>(value);
+ }
+};
+
+/**
+ * @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<typename Type, typename Class>
+[[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<typename Func>
+[[nodiscard]] constexpr auto overload(Func *func) noexcept {
+ return func;
+}
+
+/**
+ * @brief Helper type for visitors.
+ * @tparam Func Types of function objects.
+ */
+template<typename... Func>
+struct overloaded: Func... {
+ using Func::operator()...;
+};
+
+/**
+ * @brief Deduction guide.
+ * @tparam Func Types of function objects.
+ */
+template<typename... Func>
+overloaded(Func...) -> overloaded<Func...>;
+
+/**
+ * @brief Basic implementation of a y-combinator.
+ * @tparam Func Type of a potentially recursive function.
+ */
+template<typename Func>
+struct y_combinator {
+ /**
+ * @brief Constructs a y-combinator from a given function.
+ * @param recursive A potentially recursive function.
+ */
+ constexpr y_combinator(Func recursive) noexcept(std::is_nothrow_move_constructible_v<Func>)
+ : func{std::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<typename... Args>
+ constexpr decltype(auto) operator()(Args &&...args) const noexcept(std::is_nothrow_invocable_v<Func, const y_combinator &, Args...>) {
+ return func(*this, std::forward<Args>(args)...);
+ }
+
+ /*! @copydoc operator()() */
+ template<typename... Args>
+ constexpr decltype(auto) operator()(Args &&...args) noexcept(std::is_nothrow_invocable_v<Func, y_combinator &, Args...>) {
+ return func(*this, std::forward<Args>(args)...);
+ }
+
+private:
+ Func func;
+};
+
+} // namespace entt
+
+#endif
|
