From eebd9cd384b7a377ab6a879807009fd584155d71 Mon Sep 17 00:00:00 2001 From: caiowakamatsu Date: Sun, 21 Jun 2026 16:37:51 -0300 Subject: [PATCH 01/10] Add entt as C++ module * Make EnTT consumable as C++ module * Added `ENTT_MODULE` CMake option enabling EnTT compilation as C++ module * Added `ENTT_USER_CONFIG` CMake option to be able to specify C++ config defines --- CMakeLists.txt | 52 +- README.md | 5 + src/entt/config/module.h | 16 + src/entt/container/dense_map.hpp | 48 +- src/entt/container/dense_set.hpp | 45 +- src/entt/container/fwd.hpp | 65 +- src/entt/container/table.hpp | 34 +- src/entt/core/algorithm.hpp | 249 +- src/entt/core/any.hpp | 32 +- src/entt/core/bit.hpp | 37 +- src/entt/core/compressed_pair.hpp | 35 +- src/entt/core/enum.hpp | 71 +- src/entt/core/family.hpp | 10 +- src/entt/core/fwd.hpp | 91 +- src/entt/core/hashed_string.hpp | 14 +- src/entt/core/ident.hpp | 51 +- src/entt/core/iterator.hpp | 335 +-- src/entt/core/memory.hpp | 393 ++-- src/entt/core/monostate.hpp | 10 +- src/entt/core/ranges.hpp | 25 +- src/entt/core/tuple.hpp | 141 +- src/entt/core/type_info.hpp | 22 +- src/entt/core/type_traits.hpp | 1759 +++++++------- src/entt/core/utility.hpp | 133 +- src/entt/entity/component.hpp | 20 +- src/entt/entity/entity.hpp | 24 +- src/entt/entity/fwd.hpp | 571 ++--- src/entt/entity/group.hpp | 38 +- src/entt/entity/handle.hpp | 26 +- src/entt/entity/helper.hpp | 427 ++-- src/entt/entity/mixin.hpp | 30 +- src/entt/entity/organizer.hpp | 30 +- src/entt/entity/ranges.hpp | 22 +- src/entt/entity/registry.hpp | 8 + src/entt/entity/runtime_view.hpp | 22 +- src/entt/entity/snapshot.hpp | 8 + src/entt/entity/sparse_set.hpp | 8 + src/entt/entity/storage.hpp | 44 +- src/entt/entity/view.hpp | 36 +- src/entt/entt.ixx | 109 + src/entt/graph/adjacency_matrix.hpp | 28 +- src/entt/graph/dot.hpp | 91 +- src/entt/graph/flow.hpp | 581 ++--- src/entt/graph/fwd.hpp | 33 +- src/entt/locator/locator.hpp | 297 +-- src/entt/meta/adl_pointer.hpp | 4 +- src/entt/meta/container.hpp | 30 +- src/entt/meta/context.hpp | 21 +- src/entt/meta/factory.hpp | 52 +- src/entt/meta/fwd.hpp | 45 +- src/entt/meta/meta.hpp | 3317 ++++++++++++++------------- src/entt/meta/node.hpp | 42 +- src/entt/meta/pointer.hpp | 69 +- src/entt/meta/policy.hpp | 10 +- src/entt/meta/range.hpp | 24 +- src/entt/meta/resolve.hpp | 181 +- src/entt/meta/template.hpp | 8 +- src/entt/meta/type_traits.hpp | 99 +- src/entt/meta/utility.hpp | 32 +- src/entt/poly/fwd.hpp | 25 +- src/entt/poly/poly.hpp | 555 ++--- src/entt/process/fwd.hpp | 25 +- src/entt/process/process.hpp | 23 +- src/entt/process/scheduler.hpp | 409 ++-- src/entt/resource/cache.hpp | 40 +- src/entt/resource/fwd.hpp | 19 +- src/entt/resource/loader.hpp | 47 +- src/entt/resource/resource.hpp | 403 ++-- src/entt/signal/delegate.hpp | 25 +- src/entt/signal/dispatcher.hpp | 34 +- src/entt/signal/emitter.hpp | 323 +-- src/entt/signal/fwd.hpp | 59 +- src/entt/signal/sigh.hpp | 1015 ++++---- 73 files changed, 6800 insertions(+), 6262 deletions(-) create mode 100644 src/entt/config/module.h create mode 100644 src/entt/entt.ixx diff --git a/CMakeLists.txt b/CMakeLists.txt index 401c5d6863..2b58b66454 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -22,7 +22,7 @@ project( if(NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE Debug) endif() - + message(VERBOSE "*") message(VERBOSE "* ${PROJECT_NAME} v${PROJECT_VERSION} (${CMAKE_BUILD_TYPE})") message(VERBOSE "* Copyright (c) 2017-2026 Michele Caini ") @@ -37,6 +37,13 @@ list(INSERT CMAKE_MODULE_PATH 0 ${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules) option(ENTT_USE_LIBCPP "Use libc++ by adding -stdlib=libc++ flag if available." OFF) option(ENTT_USE_SANITIZER "Enable sanitizers by adding -fsanitize=address -fno-omit-frame-pointer -fsanitize=undefined flags if available." OFF) option(ENTT_USE_CLANG_TIDY "Enable static analysis with clang-tidy" OFF) +option(ENTT_MODULE "Build EnTT module instead of a regular header-only library." OFF) + +set(ENTT_USER_CONFIG "" CACHE FILEPATH "Path to a file containing user EnTT configuration.") + +if (NOT ENTT_MODULE AND ENTT_USER_CONFIG) + message(FATAL_ERROR "The option ENTT_USER_CONFIG can be used only when ENTT_MODULE is ON") +endif() if(ENTT_USE_LIBCPP) if(NOT WIN32) @@ -83,12 +90,24 @@ endif() include(GNUInstallDirs) -add_library(EnTT INTERFACE) +if (ENTT_MODULE) + if (CMAKE_VERSION VERSION_LESS 3.28) + message(FATAL_ERROR "CMake >= 3.28 is required to build EnTT as a module") + endif() + + set(ENTT_LIBRARY_TYPE STATIC) + set(ENTT_SCOPE PUBLIC) +else() + set(ENTT_LIBRARY_TYPE INTERFACE) + set(ENTT_SCOPE INTERFACE) +endif() + +add_library(EnTT ${ENTT_LIBRARY_TYPE}) add_library(EnTT::EnTT ALIAS EnTT) target_include_directories( EnTT - INTERFACE + ${ENTT_SCOPE} $ $ ) @@ -96,12 +115,27 @@ target_include_directories( target_compile_features(EnTT INTERFACE cxx_std_20) if(ENTT_HAS_LIBCPP) - target_compile_options(EnTT BEFORE INTERFACE -stdlib=libc++) + target_compile_options(EnTT BEFORE ${ENTT_SCOPE} -stdlib=libc++) + if(ENTT_MODULE) + target_link_options(EnTT ${ENTT_SCOPE} -stdlib=libc++) + endif() endif() if(ENTT_HAS_SANITIZER) - target_compile_options(EnTT INTERFACE $<$:-fsanitize=address -fno-omit-frame-pointer -fsanitize=undefined>) - target_link_libraries(EnTT INTERFACE $<$:-fsanitize=address -fno-omit-frame-pointer -fsanitize=undefined>) + target_compile_options(EnTT ${ENTT_SCOPE} $<$:-fsanitize=address -fno-omit-frame-pointer -fsanitize=undefined>) + target_link_options(EnTT ${ENTT_SCOPE} $<$:-fsanitize=address -fno-omit-frame-pointer -fsanitize=undefined>) +endif() + +if (ENTT_USER_CONFIG) + target_compile_definitions(EnTT ${ENTT_SCOPE} ENTT_USER_CONFIG=\"${ENTT_USER_CONFIG}\") +endif() + +if (ENTT_MODULE) + target_sources(EnTT + PUBLIC + FILE_SET cxx_modules TYPE CXX_MODULES FILES + ${EnTT_SOURCE_DIR}/src/entt/entt.ixx + ) endif() if(ENTT_CLANG_TIDY_EXECUTABLE) @@ -299,6 +333,8 @@ if(ENTT_INSTALL) TARGETS EnTT EXPORT EnTTTargets ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} + $<$:FILE_SET cxx_modules DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/entt> ) write_basic_package_version_file( @@ -357,12 +393,12 @@ if(ENTT_BUILD_TESTING OR ENTT_BUILD_TESTBED) # Tests and tesetbed do not work together because SDL gets confused with EnTT tests if(ENTT_BUILD_TESTING) option(ENTT_FIND_GTEST_PACKAGE "Enable finding gtest package." OFF) - + option(ENTT_BUILD_BENCHMARK "Build benchmark." OFF) option(ENTT_BUILD_EXAMPLE "Build examples." OFF) option(ENTT_BUILD_LIB "Build lib tests." OFF) option(ENTT_BUILD_SNAPSHOT "Build snapshot test with Cereal." OFF) - + include(CTest) enable_testing() add_subdirectory(test) diff --git a/README.md b/README.md index cc753ac59c..291b9154ea 100644 --- a/README.md +++ b/README.md @@ -111,6 +111,8 @@ mind. ```cpp #include +// or import entt; +// See Integration > CMake for details. struct position { float x; @@ -246,6 +248,9 @@ using `EnTT` as a submodule without conflicting with user logic.
It is therefore necessary to set the option to true to take advantage of the installation logic provided by this library. +Note that `EnTT` can be consumed also as a C++ module. To enable module support, +the `ENTT_MODULE` option has to be set to `ON` in `CMake`. + ## Natvis support When using `CMake`, just enable the option `ENTT_INCLUDE_NATVIS` and enjoy diff --git a/src/entt/config/module.h b/src/entt/config/module.h new file mode 100644 index 0000000000..4e80a12838 --- /dev/null +++ b/src/entt/config/module.h @@ -0,0 +1,16 @@ +#ifndef ENTT_MODULE_H +#define ENTT_MODULE_H + +#ifndef ENTT_MODULE_EXPORT +# define ENTT_MODULE_EXPORT +#endif // ENTT_MODULE_EXPORT + +#ifndef ENTT_MODULE_EXPORT_BEGIN +# define ENTT_MODULE_EXPORT_BEGIN +#endif // ENTT_MODULE_EXPORT_BEGIN + +#ifndef ENTT_MODULE_EXPORT_END +# define ENTT_MODULE_EXPORT_END +#endif // ENTT_MODULE_EXPORT_END + +#endif // ENTT_MODULE_H diff --git a/src/entt/container/dense_map.hpp b/src/entt/container/dense_map.hpp index e4f5ee5aa9..bd7e754d62 100644 --- a/src/entt/container/dense_map.hpp +++ b/src/entt/container/dense_map.hpp @@ -1,26 +1,30 @@ #ifndef ENTT_CONTAINER_DENSE_MAP_HPP #define ENTT_CONTAINER_DENSE_MAP_HPP -#include -#include "../config/config.h" -#include "../core/bit.hpp" -#include "../core/compressed_pair.hpp" -#include "../core/iterator.hpp" -#include "../core/memory.hpp" -#include "../core/type_traits.hpp" -#include "../stl/bit.hpp" -#include "../stl/cmath.hpp" -#include "../stl/concepts.hpp" -#include "../stl/cstddef.hpp" -#include "../stl/functional.hpp" -#include "../stl/iterator.hpp" -#include "../stl/limits.hpp" -#include "../stl/memory.hpp" -#include "../stl/tuple.hpp" -#include "../stl/type_traits.hpp" -#include "../stl/utility.hpp" -#include "../stl/vector.hpp" -#include "fwd.hpp" +#include "../config/module.h" + +#ifndef ENTT_MODULE +# include +# include "../config/config.h" +# include "../core/bit.hpp" +# include "../core/compressed_pair.hpp" +# include "../core/iterator.hpp" +# include "../core/memory.hpp" +# include "../core/type_traits.hpp" +# include "../stl/bit.hpp" +# include "../stl/cmath.hpp" +# include "../stl/concepts.hpp" +# include "../stl/cstddef.hpp" +# include "../stl/functional.hpp" +# include "../stl/iterator.hpp" +# include "../stl/limits.hpp" +# include "../stl/memory.hpp" +# include "../stl/tuple.hpp" +# include "../stl/type_traits.hpp" +# include "../stl/utility.hpp" +# include "../stl/vector.hpp" +# include "fwd.hpp" +#endif // ENTT_MODULE namespace entt { @@ -214,6 +218,8 @@ class dense_map_local_iterator final { } // namespace internal /*! @endcond */ +ENTT_MODULE_EXPORT_BEGIN + /** * @brief Associative container for key-value pairs with unique keys. * @@ -1009,6 +1015,8 @@ class dense_map { float threshold{default_threshold}; }; +ENTT_MODULE_EXPORT_END + } // namespace entt /*! @cond ENTT_INTERNAL */ diff --git a/src/entt/container/dense_set.hpp b/src/entt/container/dense_set.hpp index df71b72585..bb991adc96 100644 --- a/src/entt/container/dense_set.hpp +++ b/src/entt/container/dense_set.hpp @@ -1,27 +1,30 @@ #ifndef ENTT_CONTAINER_DENSE_SET_HPP #define ENTT_CONTAINER_DENSE_SET_HPP -#include -#include "../config/config.h" -#include "../core/bit.hpp" -#include "../core/compressed_pair.hpp" -#include "../core/type_traits.hpp" -#include "../stl/bit.hpp" -#include "../stl/cmath.hpp" -#include "../stl/concepts.hpp" -#include "../stl/cstddef.hpp" -#include "../stl/functional.hpp" -#include "../stl/iterator.hpp" -#include "../stl/limits.hpp" -#include "../stl/memory.hpp" -#include "../stl/tuple.hpp" -#include "../stl/type_traits.hpp" -#include "../stl/utility.hpp" -#include "../stl/vector.hpp" -#include "fwd.hpp" +#include "../config/module.h" + +#ifndef ENTT_MODULE +# include +# include "../config/config.h" +# include "../core/bit.hpp" +# include "../core/compressed_pair.hpp" +# include "../core/type_traits.hpp" +# include "../stl/bit.hpp" +# include "../stl/cmath.hpp" +# include "../stl/concepts.hpp" +# include "../stl/cstddef.hpp" +# include "../stl/functional.hpp" +# include "../stl/iterator.hpp" +# include "../stl/limits.hpp" +# include "../stl/memory.hpp" +# include "../stl/tuple.hpp" +# include "../stl/type_traits.hpp" +# include "../stl/utility.hpp" +# include "../stl/vector.hpp" +# include "fwd.hpp" +#endif // ENTT_MODULE namespace entt { - /*! @cond ENTT_INTERNAL */ namespace internal { @@ -179,6 +182,8 @@ class dense_set_local_iterator final { } // namespace internal /*! @endcond */ +ENTT_MODULE_EXPORT_BEGIN + /** * @brief Associative container for unique objects of a given type. * @@ -885,6 +890,8 @@ class dense_set { float threshold{default_threshold}; }; +ENTT_MODULE_EXPORT_END + } // namespace entt #endif diff --git a/src/entt/container/fwd.hpp b/src/entt/container/fwd.hpp index 72f0906b8f..5a8c43482a 100644 --- a/src/entt/container/fwd.hpp +++ b/src/entt/container/fwd.hpp @@ -1,37 +1,40 @@ #ifndef ENTT_CONTAINER_FWD_HPP #define ENTT_CONTAINER_FWD_HPP -#include "../stl/functional.hpp" -#include "../stl/memory.hpp" -#include "../stl/utility.hpp" -#include "../stl/vector.hpp" - -namespace entt { - -template< - typename Key, - typename Type, - typename = stl::hash, - typename = stl::equal_to<>, - typename = stl::allocator>> -class dense_map; - -template< - typename Type, - typename = stl::hash, - typename = stl::equal_to<>, - typename = stl::allocator> -class dense_set; - -template -class basic_table; - -/** - * @brief Alias declaration for the most common use case. - * @tparam Type Element types. - */ -template -using table = basic_table...>; +#include "../config/module.h" + +#ifndef ENTT_MODULE +# include "../stl/functional.hpp" +# include "../stl/memory.hpp" +# include "../stl/utility.hpp" +# include "../stl/vector.hpp" +#endif // ENTT_MODULE + +ENTT_MODULE_EXPORT namespace entt { + template< + typename Key, + typename Type, + typename = stl::hash, + typename = stl::equal_to<>, + typename = stl::allocator>> + class dense_map; + + template< + typename Type, + typename = stl::hash, + typename = stl::equal_to<>, + typename = stl::allocator> + class dense_set; + + template + class basic_table; + + /** + * @brief Alias declaration for the most common use case. + * @tparam Type Element types. + */ + template + using table = basic_table...>; } // namespace entt diff --git a/src/entt/container/table.hpp b/src/entt/container/table.hpp index 86e278d21a..28b458f3a7 100644 --- a/src/entt/container/table.hpp +++ b/src/entt/container/table.hpp @@ -1,14 +1,18 @@ #ifndef ENTT_CONTAINER_TABLE_HPP #define ENTT_CONTAINER_TABLE_HPP -#include "../config/config.h" -#include "../core/iterator.hpp" -#include "../stl/concepts.hpp" -#include "../stl/cstddef.hpp" -#include "../stl/iterator.hpp" -#include "../stl/tuple.hpp" -#include "../stl/utility.hpp" -#include "fwd.hpp" +#include "../config/module.h" + +#ifndef ENTT_MODULE +# include "../config/config.h" +# include "../core/iterator.hpp" +# include "../stl/concepts.hpp" +# include "../stl/cstddef.hpp" +# include "../stl/iterator.hpp" +# include "../stl/tuple.hpp" +# include "../stl/utility.hpp" +# include "fwd.hpp" +#endif // ENTT_MODULE namespace entt { @@ -108,6 +112,8 @@ class table_iterator { } // namespace internal /*! @endcond */ +ENTT_MODULE_EXPORT_BEGIN + /** * @brief Basic table implementation. * @@ -417,16 +423,18 @@ class basic_table { container_type payload; }; +ENTT_MODULE_EXPORT_END + } // namespace entt /*! @cond ENTT_INTERNAL */ #include -namespace std { - -template -struct uses_allocator, Allocator> - : entt::stl::bool_constant<(entt::stl::uses_allocator_v && ...)> {}; +/*! @cond TURN_OFF_DOXYGEN */ +ENTT_MODULE_EXPORT namespace std { + template + struct uses_allocator, Allocator> + : entt::stl::bool_constant<(entt::stl::uses_allocator_v && ...)> {}; } // namespace std /*! @endcond */ diff --git a/src/entt/core/algorithm.hpp b/src/entt/core/algorithm.hpp index 758f0cde05..dc1bca27e3 100644 --- a/src/entt/core/algorithm.hpp +++ b/src/entt/core/algorithm.hpp @@ -1,142 +1,145 @@ #ifndef ENTT_CORE_ALGORITHM_HPP #define ENTT_CORE_ALGORITHM_HPP -#include "../stl/algorithm.hpp" -#include "../stl/concepts.hpp" -#include "../stl/cstddef.hpp" -#include "../stl/functional.hpp" -#include "../stl/iterator.hpp" -#include "../stl/utility.hpp" -#include "../stl/vector.hpp" - -namespace entt { - -/** - * @brief Function object to wrap `stl::sort` in a class type. - * - * Unfortunately, `stl::sort` cannot be passed as template argument to a class - * template or a function template.
- * This class fills the gap by wrapping some flavors of `stl::sort` in a - * function object. - */ -struct std_sort { +#include "../config/module.h" + +#ifndef ENTT_MODULE +# include "../stl/algorithm.hpp" +# include "../stl/concepts.hpp" +# include "../stl/cstddef.hpp" +# include "../stl/functional.hpp" +# include "../stl/iterator.hpp" +# include "../stl/utility.hpp" +# include "../stl/vector.hpp" +#endif // ENTT_MODULE + +ENTT_MODULE_EXPORT namespace entt { /** - * @brief Sorts the elements in a range. + * @brief Function object to wrap `stl::sort` in a class type. * - * Sorts the elements in a range using the given binary comparison function. - * - * @tparam Compare Type of comparison function object. - * @tparam Args Types of arguments to forward to the sort function. - * @param first An iterator to the first element of the range to sort. - * @param last An iterator past the last element of the range to sort. - * @param compare A valid comparison function object. - * @param args Arguments to forward to the sort function, if any. - */ - template, typename... Args> - void operator()(stl::random_access_iterator auto first, stl::random_access_iterator auto last, Compare compare = Compare{}, Args &&...args) const { - stl::sort(stl::forward(args)..., stl::move(first), stl::move(last), stl::move(compare)); - } -}; - -/*! @brief Function object for performing insertion sort. */ -struct insertion_sort { - /** - * @brief Sorts the elements in a range. - * - * Sorts the elements in a range using the given binary comparison function. - * - * @tparam Compare Type of comparison function object. - * @param first An iterator to the first element of the range to sort. - * @param last An iterator past the last element of the range to sort. - * @param compare A valid comparison function object. + * Unfortunately, `stl::sort` cannot be passed as template argument to a class + * template or a function template.
+ * This class fills the gap by wrapping some flavors of `stl::sort` in a + * function object. */ - template> - void operator()(stl::random_access_iterator auto first, stl::random_access_iterator auto last, Compare compare = Compare{}) const { - if(first < last) { - for(auto it = first + 1; it < last; ++it) { - auto value = stl::move(*it); - auto pre = it; - - // NOLINTBEGIN(cppcoreguidelines-pro-bounds-pointer-arithmetic) - for(; pre > first && compare(value, *(pre - 1)); --pre) { - *pre = stl::move(*(pre - 1)); + struct std_sort { + /** + * @brief Sorts the elements in a range. + * + * Sorts the elements in a range using the given binary comparison function. + * + * @tparam Compare Type of comparison function object. + * @tparam Args Types of arguments to forward to the sort function. + * @param first An iterator to the first element of the range to sort. + * @param last An iterator past the last element of the range to sort. + * @param compare A valid comparison function object. + * @param args Arguments to forward to the sort function, if any. + */ + template, typename... Args> + void operator()(stl::random_access_iterator auto first, stl::random_access_iterator auto last, Compare compare = Compare{}, Args &&...args) const { + stl::sort(stl::forward(args)..., stl::move(first), stl::move(last), stl::move(compare)); + } + }; + + /*! @brief Function object for performing insertion sort. */ + struct insertion_sort { + /** + * @brief Sorts the elements in a range. + * + * Sorts the elements in a range using the given binary comparison function. + * + * @tparam Compare Type of comparison function object. + * @param first An iterator to the first element of the range to sort. + * @param last An iterator past the last element of the range to sort. + * @param compare A valid comparison function object. + */ + template> + void operator()(stl::random_access_iterator auto first, stl::random_access_iterator auto last, Compare compare = Compare{}) const { + if(first < last) { + for(auto it = first + 1; it < last; ++it) { + auto value = stl::move(*it); + auto pre = it; + + // NOLINTBEGIN(cppcoreguidelines-pro-bounds-pointer-arithmetic) + for(; pre > first && compare(value, *(pre - 1)); --pre) { + *pre = stl::move(*(pre - 1)); + } + // NOLINTEND(cppcoreguidelines-pro-bounds-pointer-arithmetic) + + *pre = stl::move(value); } - // NOLINTEND(cppcoreguidelines-pro-bounds-pointer-arithmetic) - - *pre = stl::move(value); } } - } -}; - -/** - * @brief Function object for performing LSD radix sort. - * @tparam Bit Number of bits processed per pass. - * @tparam N Maximum number of bits to sort. - */ -template -requires ((N % Bit) == 0) // The maximum number of bits to sort must be a multiple of the number of bits processed per pass -struct radix_sort { + }; + /** - * @brief Sorts the elements in a range. - * - * Sorts the elements in a range using the given _getter_ to access the - * actual data to be sorted. - * - * This implementation is inspired by the online book - * [Physically Based Rendering](http://www.pbr-book.org/3ed-2018/Primitives_and_Intersection_Acceleration/Bounding_Volume_Hierarchies.html#RadixSort). - * - * @tparam It Type of random access iterator. - * @tparam Getter Type of _getter_ function object. - * @param first An iterator to the first element of the range to sort. - * @param last An iterator past the last element of the range to sort. - * @param getter A valid _getter_ function object. + * @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 - void operator()(It first, It last, Getter getter = Getter{}) const { - if(first < last) { - constexpr auto passes = N / Bit; - - using value_type = stl::iterator_traits::value_type; - using difference_type = stl::iterator_traits::difference_type; - stl::vector aux(static_cast(stl::distance(first, last))); - - auto part = [getter = stl::move(getter)](auto from, auto to, auto out, auto start) { - constexpr auto mask = (1 << Bit) - 1; - constexpr auto buckets = 1 << Bit; - - // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays, modernize-avoid-c-arrays, misc-const-correctness) - stl::size_t count[buckets]{}; - - for(auto it = from; it != to; ++it) { - ++count[(getter(*it) >> start) & mask]; - } - - // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays, modernize-avoid-c-arrays) - stl::size_t index[buckets]{}; - - for(stl::size_t pos{}, end = buckets - 1u; pos < end; ++pos) { - index[pos + 1u] = index[pos] + count[pos]; + template + requires ((N % Bit) == 0) // The maximum number of bits to sort must be a multiple of the number of bits processed per pass + struct radix_sort { + /** + * @brief Sorts the elements in a range. + * + * Sorts the elements in a range using the given _getter_ to access the + * actual data to be sorted. + * + * This implementation is inspired by the online book + * [Physically Based Rendering](http://www.pbr-book.org/3ed-2018/Primitives_and_Intersection_Acceleration/Bounding_Volume_Hierarchies.html#RadixSort). + * + * @tparam It Type of random access iterator. + * @tparam Getter Type of _getter_ function object. + * @param first An iterator to the first element of the range to sort. + * @param last An iterator past the last element of the range to sort. + * @param getter A valid _getter_ function object. + */ + template + void operator()(It first, It last, Getter getter = Getter{}) const { + if(first < last) { + constexpr auto passes = N / Bit; + + using value_type = stl::iterator_traits::value_type; + using difference_type = stl::iterator_traits::difference_type; + stl::vector aux(static_cast(stl::distance(first, last))); + + auto part = [getter = stl::move(getter)](auto from, auto to, auto out, auto start) { + constexpr auto mask = (1 << Bit) - 1; + constexpr auto buckets = 1 << Bit; + + // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays, modernize-avoid-c-arrays, misc-const-correctness) + stl::size_t count[buckets]{}; + + for(auto it = from; it != to; ++it) { + ++count[(getter(*it) >> start) & mask]; + } + + // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays, modernize-avoid-c-arrays) + stl::size_t index[buckets]{}; + + for(stl::size_t pos{}, end = buckets - 1u; pos < end; ++pos) { + index[pos + 1u] = index[pos] + count[pos]; + } + + for(auto it = from; it != to; ++it) { + const auto pos = index[(getter(*it) >> start) & mask]++; + out[static_cast(pos)] = stl::move(*it); + } + }; + + for(stl::size_t pass = 0; pass < (passes & ~1u); pass += 2) { + part(first, last, aux.begin(), pass * Bit); + part(aux.begin(), aux.end(), first, (pass + 1) * Bit); } - for(auto it = from; it != to; ++it) { - const auto pos = index[(getter(*it) >> start) & mask]++; - out[static_cast(pos)] = stl::move(*it); + if constexpr(passes & 1) { + part(first, last, aux.begin(), (passes - 1) * Bit); + stl::move(aux.begin(), aux.end(), first); } - }; - - for(stl::size_t pass = 0; pass < (passes & ~1u); pass += 2) { - part(first, last, aux.begin(), pass * Bit); - part(aux.begin(), aux.end(), first, (pass + 1) * Bit); - } - - if constexpr(passes & 1) { - part(first, last, aux.begin(), (passes - 1) * Bit); - stl::move(aux.begin(), aux.end(), first); } } - } -}; + }; } // namespace entt diff --git a/src/entt/core/any.hpp b/src/entt/core/any.hpp index 74e27d6f77..ad35e9ebc8 100644 --- a/src/entt/core/any.hpp +++ b/src/entt/core/any.hpp @@ -1,18 +1,22 @@ #ifndef ENTT_CORE_ANY_HPP #define ENTT_CORE_ANY_HPP -#include "../config/config.h" -#include "../core/concepts.hpp" -#include "../stl/concepts.hpp" -#include "../stl/cstddef.hpp" -#include "../stl/cstdint.hpp" -#include "../stl/memory.hpp" -#include "../stl/type_traits.hpp" -#include "../stl/utility.hpp" -#include "fwd.hpp" -#include "type_info.hpp" -#include "type_traits.hpp" -#include "utility.hpp" +#include "../config/module.h" + +#ifndef ENTT_MODULE +# include "../config/config.h" +# include "../core/concepts.hpp" +# include "../stl/concepts.hpp" +# include "../stl/cstddef.hpp" +# include "../stl/cstdint.hpp" +# include "../stl/memory.hpp" +# include "../stl/type_traits.hpp" +# include "../stl/utility.hpp" +# include "fwd.hpp" +# include "type_info.hpp" +# include "type_traits.hpp" +# include "utility.hpp" +#endif // ENTT_MODULE namespace entt { @@ -54,6 +58,8 @@ struct in_situ: stl::false_type {}; } // namespace internal /*! @endcond */ +ENTT_MODULE_EXPORT_BEGIN + /** * @brief A SBO friendly, type-safe container for single values of any type. * @tparam Len Size of the buffer reserved for the small buffer optimization. @@ -618,6 +624,8 @@ template::length, stl::size_t Align = basic_any{stl::in_place_type, stl::forward(value)}; } +ENTT_MODULE_EXPORT_END + } // namespace entt #endif diff --git a/src/entt/core/bit.hpp b/src/entt/core/bit.hpp index d0698f2e72..b1c6c6bed4 100644 --- a/src/entt/core/bit.hpp +++ b/src/entt/core/bit.hpp @@ -1,25 +1,28 @@ #ifndef ENTT_CORE_BIT_HPP #define ENTT_CORE_BIT_HPP -#include "../config/config.h" -#include "../stl/bit.hpp" -#include "../stl/concepts.hpp" -#include "../stl/cstddef.hpp" +#include "../config/module.h" -namespace entt { +#ifndef ENTT_MODULE +# include "../config/config.h" +# include "../stl/bit.hpp" +# include "../stl/concepts.hpp" +# include "../stl/cstddef.hpp" +#endif // ENTT_MODULE -/** - * @brief Fast module utility function (powers of two only). - * @tparam Type Unsigned integer type. - * @param value A value of unsigned integer type. - * @param mod _Modulus_, it must be a power of two. - * @return The common remainder. - */ -template -[[nodiscard]] constexpr Type fast_mod(const Type value, const stl::size_t mod) noexcept { - ENTT_ASSERT_CONSTEXPR(stl::has_single_bit(mod), "Value must be a power of two"); - return static_cast(value & (mod - 1u)); -} +ENTT_MODULE_EXPORT namespace entt { + /** + * @brief Fast module utility function (powers of two only). + * @tparam Type Unsigned integer type. + * @param value A value of unsigned integer type. + * @param mod _Modulus_, it must be a power of two. + * @return The common remainder. + */ + template + [[nodiscard]] constexpr Type fast_mod(const Type value, const stl::size_t mod) noexcept { + ENTT_ASSERT_CONSTEXPR(stl::has_single_bit(mod), "Value must be a power of two"); + return static_cast(value & (mod - 1u)); + } } // namespace entt diff --git a/src/entt/core/compressed_pair.hpp b/src/entt/core/compressed_pair.hpp index 9f45225295..4db1a68f0d 100644 --- a/src/entt/core/compressed_pair.hpp +++ b/src/entt/core/compressed_pair.hpp @@ -1,13 +1,17 @@ #ifndef ENTT_CORE_COMPRESSED_PAIR_HPP #define ENTT_CORE_COMPRESSED_PAIR_HPP -#include "../stl/concepts.hpp" -#include "../stl/cstddef.hpp" -#include "../stl/tuple.hpp" -#include "../stl/type_traits.hpp" -#include "../stl/utility.hpp" -#include "fwd.hpp" -#include "type_traits.hpp" +#include "../config/module.h" + +#ifndef ENTT_MODULE +# include "../stl/concepts.hpp" +# include "../stl/cstddef.hpp" +# include "../stl/tuple.hpp" +# include "../stl/type_traits.hpp" +# include "../stl/utility.hpp" +# include "fwd.hpp" +# include "type_traits.hpp" +#endif // ENTT_MODULE namespace entt { @@ -76,6 +80,8 @@ struct compressed_pair_element: Type { } // namespace internal /*! @endcond */ +ENTT_MODULE_EXPORT_BEGIN + /** * @brief A compressed pair. * @@ -246,19 +252,20 @@ constexpr void swap(compressed_pair &lhs, compressed_pair -namespace std { +ENTT_MODULE_EXPORT namespace std { + template + struct tuple_size>: integral_constant {}; -template -struct tuple_size>: integral_constant {}; - -template -requires (Index <= 1u) -struct tuple_element>: conditional {}; + template + requires (Index <= 1u) + struct tuple_element>: conditional {}; } // namespace std /*! @endcond */ diff --git a/src/entt/core/enum.hpp b/src/entt/core/enum.hpp index ed1b093a9a..f497dd364e 100644 --- a/src/entt/core/enum.hpp +++ b/src/entt/core/enum.hpp @@ -1,40 +1,43 @@ #ifndef ENTT_CORE_ENUM_HPP #define ENTT_CORE_ENUM_HPP -#include "../stl/concepts.hpp" -#include "../stl/type_traits.hpp" - -namespace entt { - -/** - * @brief Enable bitmask support for enum classes. - * @tparam Type The enum type for which to enable bitmask support. - */ -template -struct enum_as_bitmask: stl::false_type {}; - -/*! @copydoc enum_as_bitmask */ -template -requires requires { - requires stl::is_enum_v; - { Type::_entt_enum_as_bitmask } -> stl::same_as; -} -struct enum_as_bitmask: stl::true_type {}; - -/** - * @brief Helper variable template. - * @tparam Type The enum class type for which to enable bitmask support. - */ -template -inline constexpr bool enum_as_bitmask_v = enum_as_bitmask::value; - -/** - * @brief Specifies that an enum class supports bitmask operations. - * @tparam Type Enum class type. - */ -template -// check again that it is an enum to deal with incorrect specializations -concept enum_bitmask = stl::is_enum_v && enum_as_bitmask_v; +#include "../config/module.h" + +#ifndef ENTT_MODULE +# include "../stl/concepts.hpp" +# include "../stl/type_traits.hpp" +#endif // ENTT_MODULE + +ENTT_MODULE_EXPORT namespace entt { + /** + * @brief Enable bitmask support for enum classes. + * @tparam Type The enum type for which to enable bitmask support. + */ + template + struct enum_as_bitmask: stl::false_type {}; + + /*! @copydoc enum_as_bitmask */ + template + requires requires { + requires stl::is_enum_v; + { Type::_entt_enum_as_bitmask } -> stl::same_as; + } + struct enum_as_bitmask: stl::true_type {}; + + /** + * @brief Helper variable template. + * @tparam Type The enum class type for which to enable bitmask support. + */ + template + inline constexpr bool enum_as_bitmask_v = enum_as_bitmask::value; + + /** + * @brief Specifies that an enum class supports bitmask operations. + * @tparam Type Enum class type. + */ + template + // check again that it is an enum to deal with incorrect specializations + concept enum_bitmask = stl::is_enum_v && enum_as_bitmask_v; } // namespace entt diff --git a/src/entt/core/family.hpp b/src/entt/core/family.hpp index 953c12db6b..c966c10da3 100644 --- a/src/entt/core/family.hpp +++ b/src/entt/core/family.hpp @@ -1,10 +1,14 @@ #ifndef ENTT_CORE_FAMILY_HPP #define ENTT_CORE_FAMILY_HPP -#include "../config/config.h" -#include "fwd.hpp" +#include "../config/module.h" -namespace entt { +#ifndef ENTT_MODULE +# include "../config/config.h" +# include "fwd.hpp" +#endif // ENTT_MODULE + +ENTT_MODULE_EXPORT namespace entt { /** * @brief Dynamic identifier generator. diff --git a/src/entt/core/fwd.hpp b/src/entt/core/fwd.hpp index c454e8e212..7c429aa993 100644 --- a/src/entt/core/fwd.hpp +++ b/src/entt/core/fwd.hpp @@ -1,50 +1,53 @@ #ifndef ENTT_CORE_FWD_HPP #define ENTT_CORE_FWD_HPP -#include "../config/config.h" -#include "../stl/cstddef.hpp" -#include "../stl/cstdint.hpp" - -namespace entt { - -/*! @brief Possible modes of an any object. */ -enum class any_policy : stl::uint8_t { - /*! @brief Default mode, no element available. */ - empty, - /*! @brief Owning mode, dynamically allocated element. */ - dynamic, - /*! @brief Owning mode, embedded element. */ - embedded, - /*! @brief Aliasing mode, non-const reference. */ - ref, - /*! @brief Const aliasing mode, const reference. */ - cref -}; - -// NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays, modernize-avoid-c-arrays) -template -class basic_any; - -/*! @brief Alias declaration for type identifiers. */ -using id_type = ENTT_ID_TYPE; - -/*! @brief Alias declaration for the most common use case. */ -using any = basic_any<>; - -template -class compressed_pair; - -template -class basic_hashed_string; - -/*! @brief Aliases for common character types. */ -using hashed_string = basic_hashed_string; - -/*! @brief Aliases for common character types. */ -using hashed_wstring = basic_hashed_string; - -// NOLINTNEXTLINE(bugprone-forward-declaration-namespace) -struct type_info; +#include "../config/module.h" + +#ifndef ENTT_MODULE +# include "../config/config.h" +# include "../stl/cstddef.hpp" +# include "../stl/cstdint.hpp" +#endif // ENTT_MODULE + +ENTT_MODULE_EXPORT namespace entt { + /*! @brief Possible modes of an any object. */ + enum class any_policy : stl::uint8_t { + /*! @brief Default mode, no element available. */ + empty, + /*! @brief Owning mode, dynamically allocated element. */ + dynamic, + /*! @brief Owning mode, embedded element. */ + embedded, + /*! @brief Aliasing mode, non-const reference. */ + ref, + /*! @brief Const aliasing mode, const reference. */ + cref + }; + + // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays, modernize-avoid-c-arrays) + template + class basic_any; + + /*! @brief Alias declaration for type identifiers. */ + using id_type = ENTT_ID_TYPE; + + /*! @brief Alias declaration for the most common use case. */ + using any = basic_any<>; + + template + class compressed_pair; + + template + class basic_hashed_string; + + /*! @brief Aliases for common character types. */ + using hashed_string = basic_hashed_string; + + /*! @brief Aliases for common character types. */ + using hashed_wstring = basic_hashed_string; + + // NOLINTNEXTLINE(bugprone-forward-declaration-namespace) + struct type_info; } // namespace entt diff --git a/src/entt/core/hashed_string.hpp b/src/entt/core/hashed_string.hpp index f3398af8b1..b8ac96aade 100644 --- a/src/entt/core/hashed_string.hpp +++ b/src/entt/core/hashed_string.hpp @@ -1,9 +1,13 @@ #ifndef ENTT_CORE_HASHED_STRING_HPP #define ENTT_CORE_HASHED_STRING_HPP -#include "../stl/cstddef.hpp" -#include "../stl/cstdint.hpp" -#include "fwd.hpp" +#include "../config/module.h" + +#ifndef ENTT_MODULE +# include "../stl/cstddef.hpp" +# include "../stl/cstdint.hpp" +# include "fwd.hpp" +#endif // ENTT_MODULE namespace entt { @@ -39,6 +43,8 @@ struct basic_hashed_string { } // namespace internal /*! @endcond */ +ENTT_MODULE_EXPORT_BEGIN + /** * @brief Zero overhead unique identifier. * @@ -255,6 +261,8 @@ inline namespace literals { } // namespace literals +ENTT_MODULE_EXPORT_END + } // namespace entt #endif diff --git a/src/entt/core/ident.hpp b/src/entt/core/ident.hpp index 3413393e5d..8812a3af97 100644 --- a/src/entt/core/ident.hpp +++ b/src/entt/core/ident.hpp @@ -1,34 +1,37 @@ #ifndef ENTT_CORE_IDENT_HPP #define ENTT_CORE_IDENT_HPP -#include "../stl/cstddef.hpp" -#include "../stl/type_traits.hpp" -#include "../stl/utility.hpp" -#include "fwd.hpp" -#include "type_traits.hpp" +#include "../config/module.h" -namespace entt { +#ifndef ENTT_MODULE +# include "../stl/cstddef.hpp" +# include "../stl/type_traits.hpp" +# include "../stl/utility.hpp" +# include "fwd.hpp" +# include "type_traits.hpp" +#endif // ENTT_MODULE -/** - * @brief Type integral identifiers. - * @tparam Type List of types for which to generate identifiers. - */ -template -class ident { - template - [[nodiscard]] static ENTT_CONSTEVAL id_type get(stl::index_sequence) noexcept { - return (0 + ... + (stl::is_same_v...>>> ? id_type{Index} : id_type{})); - } +ENTT_MODULE_EXPORT namespace entt { + /** + * @brief Type integral identifiers. + * @tparam Type List of types for which to generate identifiers. + */ + template + class ident { + template + [[nodiscard]] static ENTT_CONSTEVAL id_type get(stl::index_sequence) noexcept { + return (0 + ... + (stl::is_same_v...>>> ? id_type{Index} : id_type{})); + } -public: - /*! @brief Unsigned integer type. */ - using value_type = id_type; + public: + /*! @brief Unsigned integer type. */ + using value_type = id_type; - /*! @brief Statically generated unique identifier for the given type. */ - template - requires (stl::is_same_v, Type> || ...) - static constexpr value_type value = get>(stl::index_sequence_for{}); -}; + /*! @brief Statically generated unique identifier for the given type. */ + template + requires (stl::is_same_v, Type> || ...) + static constexpr value_type value = get>(stl::index_sequence_for{}); + }; } // namespace entt diff --git a/src/entt/core/iterator.hpp b/src/entt/core/iterator.hpp index f389e232d0..80bb01e9df 100644 --- a/src/entt/core/iterator.hpp +++ b/src/entt/core/iterator.hpp @@ -1,180 +1,183 @@ #ifndef ENTT_CORE_ITERATOR_HPP #define ENTT_CORE_ITERATOR_HPP -#include "../stl/concepts.hpp" -#include "../stl/cstddef.hpp" -#include "../stl/iterator.hpp" -#include "../stl/memory.hpp" -#include "../stl/type_traits.hpp" -#include "../stl/utility.hpp" - -namespace entt { - -/** - * @brief Helper type to use as pointer with input iterators. - * @tparam Type of wrapped value. - */ -template -struct input_iterator_pointer final { - /*! @brief Value type. */ - using value_type = Type; - /*! @brief Pointer type. */ - using pointer = Type *; - /*! @brief Reference type. */ - using reference = Type &; - - /** - * @brief Constructs a proxy object by move. - * @param val Value to use to initialize the proxy object. - */ - constexpr input_iterator_pointer(value_type &&val) noexcept(stl::is_nothrow_move_constructible_v) - : value{stl::move(val)} {} - - /** - * @brief Access operator for accessing wrapped values. - * @return A pointer to the wrapped value. - */ - [[nodiscard]] constexpr pointer operator->() noexcept { - return stl::addressof(value); - } - - /** - * @brief Dereference operator for accessing wrapped values. - * @return A reference to the wrapped value. - */ - [[nodiscard]] constexpr reference operator*() noexcept { - return value; - } - -private: - Type value; -}; - -/** - * @brief Plain iota iterator (waiting for C++20). - * @tparam Type Value type. - */ -template -struct iota_iterator final { - /*! @brief Value type, likely an integral one. */ - using value_type = Type; - /*! @brief Invalid pointer type. */ - using pointer = void; - /*! @brief Non-reference type, same as value type. */ - using reference = value_type; - /*! @brief Difference type. */ - using difference_type = stl::ptrdiff_t; - /*! @brief Iterator category. */ - using iterator_category = stl::input_iterator_tag; - - /*! @brief Default constructor. */ - constexpr iota_iterator() noexcept - : current{} {} - - /** - * @brief Constructs an iota iterator from a given value. - * @param init The initial value assigned to the iota iterator. - */ - constexpr iota_iterator(const value_type init) noexcept - : current{init} {} - - /** - * @brief Pre-increment operator. - * @return This iota iterator. - */ - constexpr iota_iterator &operator++() noexcept { - return ++current, *this; - } - - /** - * @brief Post-increment operator. - * @return This iota iterator. - */ - constexpr iota_iterator operator++(int) noexcept { - const iota_iterator orig = *this; - return ++(*this), orig; - } - - /** - * @brief Dereference operator. - * @return The underlying value. - */ - [[nodiscard]] constexpr reference operator*() const noexcept { - return current; - } - - /** - * @brief Comparison operator. - * @param other A properly initialized iota iterator. - * @return True if the two iterators are identical, false otherwise. - */ - [[nodiscard]] constexpr bool operator==(const iota_iterator &other) const noexcept { - return current == other.current; - } - -private: - value_type current; -}; - -/** - * @brief Utility class to create an iterable object from a pair of iterators. - * @tparam It Type of iterator. - * @tparam Sentinel Type of sentinel. - */ -template Sentinel = It> -struct iterable_adaptor final { - /*! @brief Value type. */ - using value_type = stl::iterator_traits::value_type; - /*! @brief Iterator type. */ - using iterator = It; - /*! @brief Sentinel type. */ - using sentinel = Sentinel; - - /*! @brief Default constructor. */ - constexpr iterable_adaptor() noexcept(stl::is_nothrow_default_constructible_v && stl::is_nothrow_default_constructible_v) - : first{}, - last{} {} - +#include "../config/module.h" + +#ifndef ENTT_MODULE +# include "../stl/concepts.hpp" +# include "../stl/cstddef.hpp" +# include "../stl/iterator.hpp" +# include "../stl/memory.hpp" +# include "../stl/type_traits.hpp" +# include "../stl/utility.hpp" +#endif // ENTT_MODULE + +ENTT_MODULE_EXPORT namespace entt { /** - * @brief Creates an iterable object from a pair of iterators. - * @param from Begin iterator. - * @param to End iterator. + * @brief Helper type to use as pointer with input iterators. + * @tparam Type of wrapped value. */ - constexpr iterable_adaptor(iterator from, sentinel to) noexcept(stl::is_nothrow_move_constructible_v && stl::is_nothrow_move_constructible_v) - : first{stl::move(from)}, - last{stl::move(to)} {} + template + struct input_iterator_pointer final { + /*! @brief Value type. */ + using value_type = Type; + /*! @brief Pointer type. */ + using pointer = Type *; + /*! @brief Reference type. */ + using reference = Type &; + + /** + * @brief Constructs a proxy object by move. + * @param val Value to use to initialize the proxy object. + */ + constexpr input_iterator_pointer(value_type &&val) noexcept(stl::is_nothrow_move_constructible_v) + : value{stl::move(val)} {} + + /** + * @brief Access operator for accessing wrapped values. + * @return A pointer to the wrapped value. + */ + [[nodiscard]] constexpr pointer operator->() noexcept { + return stl::addressof(value); + } + + /** + * @brief Dereference operator for accessing wrapped values. + * @return A reference to the wrapped value. + */ + [[nodiscard]] constexpr reference operator*() noexcept { + return value; + } + + private: + Type value; + }; /** - * @brief Returns an iterator to the beginning. - * @return An iterator to the first element of the range. + * @brief Plain iota iterator (waiting for C++20). + * @tparam Type Value type. */ - [[nodiscard]] constexpr iterator begin() const noexcept { - return first; - } + template + struct iota_iterator final { + /*! @brief Value type, likely an integral one. */ + using value_type = Type; + /*! @brief Invalid pointer type. */ + using pointer = void; + /*! @brief Non-reference type, same as value type. */ + using reference = value_type; + /*! @brief Difference type. */ + using difference_type = stl::ptrdiff_t; + /*! @brief Iterator category. */ + using iterator_category = stl::input_iterator_tag; + + /*! @brief Default constructor. */ + constexpr iota_iterator() noexcept + : current{} {} + + /** + * @brief Constructs an iota iterator from a given value. + * @param init The initial value assigned to the iota iterator. + */ + constexpr iota_iterator(const value_type init) noexcept + : current{init} {} + + /** + * @brief Pre-increment operator. + * @return This iota iterator. + */ + constexpr iota_iterator &operator++() noexcept { + return ++current, *this; + } + + /** + * @brief Post-increment operator. + * @return This iota iterator. + */ + constexpr iota_iterator operator++(int) noexcept { + const iota_iterator orig = *this; + return ++(*this), orig; + } + + /** + * @brief Dereference operator. + * @return The underlying value. + */ + [[nodiscard]] constexpr reference operator*() const noexcept { + return current; + } + + /** + * @brief Comparison operator. + * @param other A properly initialized iota iterator. + * @return True if the two iterators are identical, false otherwise. + */ + [[nodiscard]] constexpr bool operator==(const iota_iterator &other) const noexcept { + return current == other.current; + } + + private: + value_type current; + }; /** - * @brief Returns an iterator to the end. - * @return An iterator to the element following the last element of the - * range. + * @brief Utility class to create an iterable object from a pair of iterators. + * @tparam It Type of iterator. + * @tparam Sentinel Type of sentinel. */ - [[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; -}; + template Sentinel = It> + struct iterable_adaptor final { + /*! @brief Value type. */ + using value_type = stl::iterator_traits::value_type; + /*! @brief Iterator type. */ + using iterator = It; + /*! @brief Sentinel type. */ + using sentinel = Sentinel; + + /*! @brief Default constructor. */ + constexpr iterable_adaptor() noexcept(stl::is_nothrow_default_constructible_v && stl::is_nothrow_default_constructible_v) + : first{}, + last{} {} + + /** + * @brief Creates an iterable object from a pair of iterators. + * @param from Begin iterator. + * @param to End iterator. + */ + constexpr iterable_adaptor(iterator from, sentinel to) noexcept(stl::is_nothrow_move_constructible_v && stl::is_nothrow_move_constructible_v) + : first{stl::move(from)}, + last{stl::move(to)} {} + + /** + * @brief Returns an iterator to the beginning. + * @return An iterator to the first element of the range. + */ + [[nodiscard]] constexpr iterator begin() const noexcept { + return first; + } + + /** + * @brief Returns an iterator to the end. + * @return An iterator to the element following the last element of the + * range. + */ + [[nodiscard]] constexpr sentinel end() const noexcept { + return last; + } + + /*! @copydoc begin */ + [[nodiscard]] constexpr iterator cbegin() const noexcept { + return begin(); + } + + /*! @copydoc end */ + [[nodiscard]] constexpr sentinel cend() const noexcept { + return end(); + } + + private: + It first; + Sentinel last; + }; } // namespace entt diff --git a/src/entt/core/memory.hpp b/src/entt/core/memory.hpp index 4ec18aa501..f6992652de 100644 --- a/src/entt/core/memory.hpp +++ b/src/entt/core/memory.hpp @@ -1,224 +1,227 @@ #ifndef ENTT_CORE_MEMORY_HPP #define ENTT_CORE_MEMORY_HPP -#include "../config/config.h" -#include "../stl/cstddef.hpp" -#include "../stl/memory.hpp" -#include "../stl/tuple.hpp" -#include "../stl/type_traits.hpp" -#include "../stl/utility.hpp" - -namespace entt { - -/** - * @brief Utility function to design allocation-aware containers. - * @tparam Allocator Type of allocator. - * @param lhs A valid allocator. - * @param rhs Another valid allocator. - */ -template -constexpr void propagate_on_container_copy_assignment([[maybe_unused]] Allocator &lhs, [[maybe_unused]] Allocator &rhs) noexcept { - if constexpr(stl::allocator_traits::propagate_on_container_copy_assignment::value) { - lhs = rhs; +#include "../config/module.h" + +#ifndef ENTT_MODULE +# include "../config/config.h" +# include "../stl/cstddef.hpp" +# include "../stl/memory.hpp" +# include "../stl/tuple.hpp" +# include "../stl/type_traits.hpp" +# include "../stl/utility.hpp" +#endif // ENTT_MODULE + +ENTT_MODULE_EXPORT namespace entt { + /** + * @brief Utility function to design allocation-aware containers. + * @tparam Allocator Type of allocator. + * @param lhs A valid allocator. + * @param rhs Another valid allocator. + */ + template + constexpr void propagate_on_container_copy_assignment([[maybe_unused]] Allocator & lhs, [[maybe_unused]] Allocator & rhs) noexcept { + if constexpr(stl::allocator_traits::propagate_on_container_copy_assignment::value) { + lhs = rhs; + } } -} - -/** - * @brief Utility function to design allocation-aware containers. - * @tparam Allocator Type of allocator. - * @param lhs A valid allocator. - * @param rhs Another valid allocator. - */ -template -constexpr void propagate_on_container_move_assignment([[maybe_unused]] Allocator &lhs, [[maybe_unused]] Allocator &rhs) noexcept { - if constexpr(stl::allocator_traits::propagate_on_container_move_assignment::value) { - lhs = stl::move(rhs); + + /** + * @brief Utility function to design allocation-aware containers. + * @tparam Allocator Type of allocator. + * @param lhs A valid allocator. + * @param rhs Another valid allocator. + */ + template + constexpr void propagate_on_container_move_assignment([[maybe_unused]] Allocator & lhs, [[maybe_unused]] Allocator & rhs) noexcept { + if constexpr(stl::allocator_traits::propagate_on_container_move_assignment::value) { + lhs = stl::move(rhs); + } } -} - -/** - * @brief Utility function to design allocation-aware containers. - * @tparam Allocator Type of allocator. - * @param lhs A valid allocator. - * @param rhs Another valid allocator. - */ -template -constexpr void propagate_on_container_swap([[maybe_unused]] Allocator &lhs, [[maybe_unused]] Allocator &rhs) noexcept { - if constexpr(stl::allocator_traits::propagate_on_container_swap::value) { - using stl::swap; - swap(lhs, rhs); - } else { - ENTT_ASSERT_CONSTEXPR(lhs == rhs, "Cannot swap the containers"); + + /** + * @brief Utility function to design allocation-aware containers. + * @tparam Allocator Type of allocator. + * @param lhs A valid allocator. + * @param rhs Another valid allocator. + */ + template + constexpr void propagate_on_container_swap([[maybe_unused]] Allocator & lhs, [[maybe_unused]] Allocator & rhs) noexcept { + if constexpr(stl::allocator_traits::propagate_on_container_swap::value) { + using stl::swap; + swap(lhs, rhs); + } else { + ENTT_ASSERT_CONSTEXPR(lhs == rhs, "Cannot swap the containers"); + } } -} - -/** - * @brief Deleter for allocator-aware unique pointers (waiting for C++20). - * @tparam Allocator Type of allocator used to manage memory and elements. - */ -template -struct allocation_deleter: private Allocator { - /*! @brief Allocator type. */ - using allocator_type = Allocator; - /*! @brief Pointer type. */ - using pointer = stl::allocator_traits::pointer; /** - * @brief Inherited constructors. - * @param alloc The allocator to use. + * @brief Deleter for allocator-aware unique pointers (waiting for C++20). + * @tparam Allocator Type of allocator used to manage memory and elements. */ - constexpr allocation_deleter(const allocator_type &alloc) noexcept(stl::is_nothrow_copy_constructible_v) - : Allocator{alloc} {} + template + struct allocation_deleter: private Allocator { + /*! @brief Allocator type. */ + using allocator_type = Allocator; + /*! @brief Pointer type. */ + using pointer = stl::allocator_traits::pointer; + + /** + * @brief Inherited constructors. + * @param alloc The allocator to use. + */ + constexpr allocation_deleter(const allocator_type &alloc) noexcept(stl::is_nothrow_copy_constructible_v) + : Allocator{alloc} {} + + /** + * @brief Destroys the pointed object and deallocates its memory. + * @param ptr A valid pointer to an object of the given type. + */ + constexpr void operator()(pointer ptr) noexcept(stl::is_nothrow_destructible_v) { + using alloc_traits = stl::allocator_traits; + alloc_traits::destroy(*this, stl::to_address(ptr)); + alloc_traits::deallocate(*this, ptr, 1u); + } + }; /** - * @brief Destroys the pointed object and deallocates its memory. - * @param ptr A valid pointer to an object of the given type. + * @brief Allows `stl::unique_ptr` to use allocators (waiting for C++20). + * @tparam Type Type of object to allocate for and to construct. + * @tparam Allocator Type of allocator used to manage memory and elements. + * @tparam Args Types of arguments to use to construct the object. + * @param allocator The allocator to use. + * @param args Parameters to use to construct the object. + * @return A properly initialized unique pointer with a custom deleter. */ - constexpr void operator()(pointer ptr) noexcept(stl::is_nothrow_destructible_v) { - using alloc_traits = stl::allocator_traits; - alloc_traits::destroy(*this, stl::to_address(ptr)); - alloc_traits::deallocate(*this, ptr, 1u); - } -}; - -/** - * @brief Allows `stl::unique_ptr` to use allocators (waiting for C++20). - * @tparam Type Type of object to allocate for and to construct. - * @tparam Allocator Type of allocator used to manage memory and elements. - * @tparam Args Types of arguments to use to construct the object. - * @param allocator The allocator to use. - * @param args Parameters to use to construct the object. - * @return A properly initialized unique pointer with a custom deleter. - */ -template -constexpr auto allocate_unique(Allocator &allocator, Args &&...args) { - static_assert(!stl::is_array_v, "Array types are not supported"); - - using alloc_traits = stl::allocator_traits::template rebind_traits; - using allocator_type = alloc_traits::allocator_type; - - allocator_type alloc{allocator}; - auto ptr = alloc_traits::allocate(alloc, 1u); - - ENTT_TRY { - alloc_traits::construct(alloc, stl::to_address(ptr), stl::forward(args)...); - } - ENTT_CATCH { - alloc_traits::deallocate(alloc, ptr, 1u); - ENTT_THROW; - } + template + constexpr auto allocate_unique(Allocator & allocator, Args && ...args) { + static_assert(!stl::is_array_v, "Array types are not supported"); - return stl::unique_ptr>{ptr, alloc}; -} + using alloc_traits = stl::allocator_traits::template rebind_traits; + using allocator_type = alloc_traits::allocator_type; -/*! @cond ENTT_INTERNAL */ -namespace internal { + allocator_type alloc{allocator}; + auto ptr = alloc_traits::allocate(alloc, 1u); -template -struct uses_allocator_construction { - template - static constexpr auto args([[maybe_unused]] const Allocator &allocator, Params &&...params) noexcept { - if constexpr(!stl::uses_allocator_v && stl::is_constructible_v) { - return stl::forward_as_tuple(stl::forward(params)...); - } else { - static_assert(stl::uses_allocator_v, "Ill-formed request"); + ENTT_TRY { + alloc_traits::construct(alloc, stl::to_address(ptr), stl::forward(args)...); + } + ENTT_CATCH { + alloc_traits::deallocate(alloc, ptr, 1u); + ENTT_THROW; + } + + return stl::unique_ptr>{ptr, alloc}; + } + + /*! @cond ENTT_INTERNAL */ + namespace internal { - if constexpr(stl::is_constructible_v) { - return stl::tuple{stl::allocator_arg, allocator, stl::forward(params)...}; + template + struct uses_allocator_construction { + template + static constexpr auto args([[maybe_unused]] const Allocator &allocator, Params &&...params) noexcept { + if constexpr(!stl::uses_allocator_v && stl::is_constructible_v) { + return stl::forward_as_tuple(stl::forward(params)...); } else { - static_assert(stl::is_constructible_v, "Ill-formed request"); - return stl::forward_as_tuple(stl::forward(params)..., allocator); + static_assert(stl::uses_allocator_v, "Ill-formed request"); + + if constexpr(stl::is_constructible_v) { + return stl::tuple{stl::allocator_arg, allocator, stl::forward(params)...}; + } else { + static_assert(stl::is_constructible_v, "Ill-formed request"); + return stl::forward_as_tuple(stl::forward(params)..., allocator); + } } } - } -}; - -template -struct uses_allocator_construction> { - using type = stl::pair; - - template - static constexpr auto args(const auto &allocator, stl::piecewise_construct_t, First &&first, Second &&second) noexcept { - return stl::make_tuple( - stl::piecewise_construct, - stl::apply([&allocator](auto &&...curr) { return uses_allocator_construction::args(allocator, stl::forward(curr)...); }, stl::forward(first)), - stl::apply([&allocator](auto &&...curr) { return uses_allocator_construction::args(allocator, stl::forward(curr)...); }, stl::forward(second))); - } + }; + + template + struct uses_allocator_construction> { + using type = stl::pair; + + template + static constexpr auto args(const auto &allocator, stl::piecewise_construct_t, First &&first, Second &&second) noexcept { + return stl::make_tuple( + stl::piecewise_construct, + stl::apply([&allocator](auto &&...curr) { return uses_allocator_construction::args(allocator, stl::forward(curr)...); }, stl::forward(first)), + stl::apply([&allocator](auto &&...curr) { return uses_allocator_construction::args(allocator, stl::forward(curr)...); }, stl::forward(second))); + } - static constexpr auto args(const auto &allocator) noexcept { - return uses_allocator_construction::args(allocator, stl::piecewise_construct, stl::tuple<>{}, stl::tuple<>{}); - } + static constexpr auto args(const auto &allocator) noexcept { + return uses_allocator_construction::args(allocator, stl::piecewise_construct, stl::tuple<>{}, stl::tuple<>{}); + } + + template + static constexpr auto args(const auto &allocator, First &&first, Second &&second) noexcept { + return uses_allocator_construction::args(allocator, stl::piecewise_construct, stl::forward_as_tuple(stl::forward(first)), stl::forward_as_tuple(stl::forward(second))); + } + + template + static constexpr auto args(const auto &allocator, const stl::pair &value) noexcept { + return uses_allocator_construction::args(allocator, stl::piecewise_construct, stl::forward_as_tuple(value.first), stl::forward_as_tuple(value.second)); + } + + template + static constexpr auto args(const auto &allocator, stl::pair &&value) noexcept { + return uses_allocator_construction::args(allocator, stl::piecewise_construct, stl::forward_as_tuple(stl::move(value.first)), stl::forward_as_tuple(stl::move(value.second))); + } + }; - template - static constexpr auto args(const auto &allocator, First &&first, Second &&second) noexcept { - return uses_allocator_construction::args(allocator, stl::piecewise_construct, stl::forward_as_tuple(stl::forward(first)), stl::forward_as_tuple(stl::forward(second))); + } // namespace internal + /*! @endcond */ + + /** + * @brief Uses-allocator construction utility (waiting for C++20). + * + * Primarily intended for internal use. Prepares the argument list needed to + * create an object of a given type by means of uses-allocator construction. + * + * @tparam Type Type to return arguments for. + * @tparam Args Types of arguments to use to construct the object. + * @param allocator The allocator to use. + * @param args Parameters to use to construct the object. + * @return The arguments needed to create an object of the given type. + */ + template + constexpr auto uses_allocator_construction_args(const auto &allocator, Args &&...args) noexcept { + return internal::uses_allocator_construction::args(allocator, stl::forward(args)...); } - template - static constexpr auto args(const auto &allocator, const stl::pair &value) noexcept { - return uses_allocator_construction::args(allocator, stl::piecewise_construct, stl::forward_as_tuple(value.first), stl::forward_as_tuple(value.second)); + /** + * @brief Uses-allocator construction utility (waiting for C++20). + * + * Primarily intended for internal use. Creates an object of a given type by + * means of uses-allocator construction. + * + * @tparam Type Type of object to create. + * @tparam Args Types of arguments to use to construct the object. + * @param allocator The allocator to use. + * @param args Parameters to use to construct the object. + * @return A newly created object of the given type. + */ + template + constexpr Type make_obj_using_allocator(const auto &allocator, Args &&...args) { + return stl::make_from_tuple(internal::uses_allocator_construction::args(allocator, stl::forward(args)...)); } - template - static constexpr auto args(const auto &allocator, stl::pair &&value) noexcept { - return uses_allocator_construction::args(allocator, stl::piecewise_construct, stl::forward_as_tuple(stl::move(value.first)), stl::forward_as_tuple(stl::move(value.second))); + /** + * @brief Uses-allocator construction utility (waiting for C++20). + * + * Primarily intended for internal use. Creates an object of a given type by + * means of uses-allocator construction at an uninitialized memory location. + * + * @tparam Type Type of object to create. + * @tparam Args Types of arguments to use to construct the object. + * @param value Memory location in which to place the object. + * @param allocator The allocator to use. + * @param args Parameters to use to construct the object. + * @return A pointer to the newly created object of the given type. + */ + template + constexpr Type *uninitialized_construct_using_allocator(Type * value, const auto &allocator, Args &&...args) { + return stl::apply([value](auto &&...curr) { return ::new(value) Type(stl::forward(curr)...); }, internal::uses_allocator_construction::args(allocator, stl::forward(args)...)); } -}; - -} // namespace internal -/*! @endcond */ - -/** - * @brief Uses-allocator construction utility (waiting for C++20). - * - * Primarily intended for internal use. Prepares the argument list needed to - * create an object of a given type by means of uses-allocator construction. - * - * @tparam Type Type to return arguments for. - * @tparam Args Types of arguments to use to construct the object. - * @param allocator The allocator to use. - * @param args Parameters to use to construct the object. - * @return The arguments needed to create an object of the given type. - */ -template -constexpr auto uses_allocator_construction_args(const auto &allocator, Args &&...args) noexcept { - return internal::uses_allocator_construction::args(allocator, stl::forward(args)...); -} - -/** - * @brief Uses-allocator construction utility (waiting for C++20). - * - * Primarily intended for internal use. Creates an object of a given type by - * means of uses-allocator construction. - * - * @tparam Type Type of object to create. - * @tparam Args Types of arguments to use to construct the object. - * @param allocator The allocator to use. - * @param args Parameters to use to construct the object. - * @return A newly created object of the given type. - */ -template -constexpr Type make_obj_using_allocator(const auto &allocator, Args &&...args) { - return stl::make_from_tuple(internal::uses_allocator_construction::args(allocator, stl::forward(args)...)); -} - -/** - * @brief Uses-allocator construction utility (waiting for C++20). - * - * Primarily intended for internal use. Creates an object of a given type by - * means of uses-allocator construction at an uninitialized memory location. - * - * @tparam Type Type of object to create. - * @tparam Args Types of arguments to use to construct the object. - * @param value Memory location in which to place the object. - * @param allocator The allocator to use. - * @param args Parameters to use to construct the object. - * @return A pointer to the newly created object of the given type. - */ -template -constexpr Type *uninitialized_construct_using_allocator(Type *value, const auto &allocator, Args &&...args) { - return stl::apply([value](auto &&...curr) { return ::new(value) Type(stl::forward(curr)...); }, internal::uses_allocator_construction::args(allocator, stl::forward(args)...)); -} } // namespace entt diff --git a/src/entt/core/monostate.hpp b/src/entt/core/monostate.hpp index 4116bda853..417a81dfeb 100644 --- a/src/entt/core/monostate.hpp +++ b/src/entt/core/monostate.hpp @@ -1,10 +1,14 @@ #ifndef ENTT_CORE_MONOSTATE_HPP #define ENTT_CORE_MONOSTATE_HPP -#include "../config/config.h" -#include "fwd.hpp" +#include "../config/module.h" -namespace entt { +#ifndef ENTT_MODULE +# include "../config/config.h" +# include "fwd.hpp" +#endif // ENTT_MODULE + +ENTT_MODULE_EXPORT namespace entt { /** * @brief Minimal implementation of the monostate pattern. diff --git a/src/entt/core/ranges.hpp b/src/entt/core/ranges.hpp index 255d7d746c..dc17ce9fc6 100644 --- a/src/entt/core/ranges.hpp +++ b/src/entt/core/ranges.hpp @@ -1,22 +1,25 @@ #ifndef ENTT_CORE_RANGES_HPP #define ENTT_CORE_RANGES_HPP -#include - -#if defined(__cpp_lib_ranges) -# include -# include "iterator.hpp" - +#include "../config/module.h" +#if __has_include() +# ifndef ENTT_MODULE +# include +# endif // ENTT_MODULE +# +# if defined(__cpp_lib_ranges) +# ifndef ENTT_MODULE +# include +# include "iterator.hpp" +# endif // ENTT_MODULE +ENTT_MODULE_EXPORT_BEGIN namespace std::ranges { - template inline constexpr bool enable_borrowed_range>{true}; - template inline constexpr bool enable_view>{true}; - } // namespace std::ranges - +ENTT_MODULE_EXPORT_END +# endif #endif - #endif diff --git a/src/entt/core/tuple.hpp b/src/entt/core/tuple.hpp index dff6a0b530..5a3a973421 100644 --- a/src/entt/core/tuple.hpp +++ b/src/entt/core/tuple.hpp @@ -1,89 +1,92 @@ #ifndef ENTT_CORE_TUPLE_HPP #define ENTT_CORE_TUPLE_HPP -#include "../stl/tuple.hpp" -#include "../stl/type_traits.hpp" -#include "../stl/utility.hpp" +#include "../config/module.h" -namespace entt { +#ifndef ENTT_MODULE +# include "../stl/tuple.hpp" +# include "../stl/type_traits.hpp" +# include "../stl/utility.hpp" +#endif // ENTT_MODULE -/** - * @brief Provides the member constant `value` to true if a given type is a - * tuple, false otherwise. - * @tparam Type The type to test. - */ -template -struct is_tuple: stl::false_type {}; - -/** - * @copybrief is_tuple - * @tparam Args Tuple template arguments. - */ -template -struct is_tuple>: stl::true_type {}; - -/** - * @brief Helper variable template. - * @tparam Type The type to test. - */ -template -inline constexpr bool is_tuple_v = is_tuple::value; - -/** - * @brief Utility function to unwrap tuples of a single element. - * @tparam Type Tuple type of any sizes. - * @param value A tuple object of the given type. - * @return The tuple itself if it contains more than one element, the first - * element otherwise. - */ -template -constexpr decltype(auto) unwrap_tuple(Type &&value) noexcept { - if constexpr(stl::tuple_size_v> == 1u) { - return stl::get<0>(stl::forward(value)); - } else { - return stl::forward(value); - } -} +ENTT_MODULE_EXPORT namespace entt { + /** + * @brief Provides the member constant `value` to true if a given type is a + * tuple, false otherwise. + * @tparam Type The type to test. + */ + template + struct is_tuple: stl::false_type {}; -/** - * @brief Utility class to forward-and-apply tuple objects. - * @tparam Func Type of underlying invocable object. - */ -template -struct forward_apply: private Func { /** - * @brief Constructs a forward-and-apply object. - * @tparam Args Types of arguments to use to construct the new instance. - * @param args Parameters to use to construct the instance. + * @copybrief is_tuple + * @tparam Args Tuple template arguments. */ template - constexpr forward_apply(Args &&...args) noexcept(stl::is_nothrow_constructible_v) - : Func{stl::forward(args)...} {} + struct is_tuple>: stl::true_type {}; /** - * @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. + * @brief Helper variable template. + * @tparam Type The type to test. */ template - constexpr decltype(auto) operator()(Type &&args) noexcept(noexcept(stl::apply(stl::declval(), args))) { - return stl::apply(static_cast(*this), stl::forward(args)); - } + inline constexpr bool is_tuple_v = is_tuple::value; - /*! @copydoc operator()() */ + /** + * @brief Utility function to unwrap tuples of a single element. + * @tparam Type Tuple type of any sizes. + * @param value A tuple object of the given type. + * @return The tuple itself if it contains more than one element, the first + * element otherwise. + */ template - constexpr decltype(auto) operator()(Type &&args) const noexcept(noexcept(stl::apply(stl::declval(), args))) { - return stl::apply(static_cast(*this), stl::forward(args)); + constexpr decltype(auto) unwrap_tuple(Type && value) noexcept { + if constexpr(stl::tuple_size_v> == 1u) { + return stl::get<0>(stl::forward(value)); + } else { + return stl::forward(value); + } } -}; -/** - * @brief Deduction guide. - * @tparam Func Type of underlying invocable object. - */ -template -forward_apply(Func) -> forward_apply>; + /** + * @brief Utility class to forward-and-apply tuple objects. + * @tparam Func Type of underlying invocable object. + */ + template + struct forward_apply: private Func { + /** + * @brief Constructs a forward-and-apply object. + * @tparam Args Types of arguments to use to construct the new instance. + * @param args Parameters to use to construct the instance. + */ + template + constexpr forward_apply(Args &&...args) noexcept(stl::is_nothrow_constructible_v) + : Func{stl::forward(args)...} {} + + /** + * @brief Forwards and applies the arguments with the underlying function. + * @tparam Type Tuple-like type to forward to the underlying function. + * @param args Parameters to forward to the underlying function. + * @return Return value of the underlying function, if any. + */ + template + constexpr decltype(auto) operator()(Type &&args) noexcept(noexcept(stl::apply(stl::declval(), args))) { + return stl::apply(static_cast(*this), stl::forward(args)); + } + + /*! @copydoc operator()() */ + template + constexpr decltype(auto) operator()(Type &&args) const noexcept(noexcept(stl::apply(stl::declval(), args))) { + return stl::apply(static_cast(*this), stl::forward(args)); + } + }; + + /** + * @brief Deduction guide. + * @tparam Func Type of underlying invocable object. + */ + template + forward_apply(Func) -> forward_apply>; } // namespace entt diff --git a/src/entt/core/type_info.hpp b/src/entt/core/type_info.hpp index 1c251abb54..c8f4ecec1f 100644 --- a/src/entt/core/type_info.hpp +++ b/src/entt/core/type_info.hpp @@ -1,13 +1,17 @@ #ifndef ENTT_CORE_TYPE_INFO_HPP #define ENTT_CORE_TYPE_INFO_HPP -#include -#include "../config/config.h" -#include "../stl/string_view.hpp" -#include "../stl/type_traits.hpp" -#include "../stl/utility.hpp" -#include "fwd.hpp" -#include "hashed_string.hpp" +#include "../config/module.h" + +#ifndef ENTT_MODULE +# include +# include "../config/config.h" +# include "../stl/string_view.hpp" +# include "../stl/type_traits.hpp" +# include "../stl/utility.hpp" +# include "fwd.hpp" +# include "hashed_string.hpp" +#endif // ENTT_MODULE namespace entt { @@ -72,6 +76,8 @@ template } // namespace internal /*! @endcond */ +ENTT_MODULE_EXPORT_BEGIN + /** * @brief Type sequential identifier. * @tparam Type Type for which to generate a sequential identifier. @@ -227,6 +233,8 @@ template return type_id>(); } +ENTT_MODULE_EXPORT_END + } // namespace entt #endif diff --git a/src/entt/core/type_traits.hpp b/src/entt/core/type_traits.hpp index 571c4c427e..a4bfac2e56 100644 --- a/src/entt/core/type_traits.hpp +++ b/src/entt/core/type_traits.hpp @@ -1,899 +1,904 @@ #ifndef ENTT_CORE_TYPE_TRAITS_HPP #define ENTT_CORE_TYPE_TRAITS_HPP -#include "../config/config.h" -#include "../stl/concepts.hpp" -#include "../stl/cstddef.hpp" -#include "../stl/iterator.hpp" -#include "../stl/tuple.hpp" -#include "../stl/type_traits.hpp" -#include "../stl/utility.hpp" -#include "fwd.hpp" - -namespace entt { - -/** - * @brief Utility class to disambiguate overloaded functions. - * @tparam N Number of choices available. - */ -template -struct choice_t - // unfortunately, doxygen cannot parse such a construct - : /*! @cond ENTT_INTERNAL */ choice_t /*! @endcond */ -{}; - -/*! @copybrief choice_t */ -template<> -struct choice_t<0> {}; - -/** - * @brief Variable template for the choice trick. - * @tparam N Number of choices available. - */ -template -inline constexpr choice_t choice{}; - -/** - * @brief A type-only `sizeof` wrapper that returns 0 where `sizeof` complains. - * @tparam Type The type of which to return the size. - */ -template -struct size_of: stl::integral_constant {}; - -/*! @copydoc size_of */ -template -requires requires { sizeof(Type); } -struct size_of - // NOLINTNEXTLINE(bugprone-sizeof-expression) - : stl::integral_constant {}; - -/** - * @brief Helper variable template. - * @tparam Type The type of which to return the size. - */ -template -inline constexpr stl::size_t size_of_v = size_of::value; - -/** - * @brief Using declaration to be used to _repeat_ the same type a number of - * times equal to the size of a given parameter pack. - * @tparam Type A type to repeat. - */ -template -using unpack_as_type = Type; - -/** - * @brief Helper variable template to be used to _repeat_ the same value a - * number of times equal to the size of a given parameter pack. - * @tparam Value A value to repeat. - */ -template -inline constexpr auto unpack_as_value = Value; - -/** - * @brief Wraps a static constant. - * @tparam Value A static constant. - */ -template -using integral_constant = stl::integral_constant; - -/** - * @brief Alias template to facilitate the creation of named values. - * @tparam Value A constant value at least convertible to `id_type`. - */ -template -using tag = integral_constant; - -/** - * @brief A class to use to push around lists of types, nothing more. - * @tparam Type Types provided by the type list. - */ -template -struct type_list { - /*! @brief Type list type. */ - using type = type_list; - /*! @brief Compile-time number of elements in the type list. */ - static constexpr auto size = sizeof...(Type); -}; - -/*! @brief Primary template isn't defined on purpose. */ -template -struct type_list_element; - -/** - * @brief Provides compile-time indexed access to the types of a type list. - * @tparam Index Index of the type to return. - * @tparam First First type provided by the type list. - * @tparam Other Other types provided by the type list. - */ -template -struct type_list_element> - : type_list_element> {}; - -/** - * @brief Provides compile-time indexed access to the types of a type list. - * @tparam First First type provided by the type list. - * @tparam Other Other types provided by the type list. - */ -template -struct type_list_element<0u, type_list> { - /*! @brief Searched type. */ - using type = First; -}; - -/** - * @brief Helper type. - * @tparam Index Index of the type to return. - * @tparam List Type list to search into. - */ -template -using type_list_element_t = type_list_element::type; - -/*! @brief Primary template isn't defined on purpose. */ -template -struct type_list_index; - -/** - * @brief Provides compile-time type access to the types of a type list. - * @tparam Type Type to look for and for which to return the index. - * @tparam First First type provided by the type list. - * @tparam Other Other types provided by the type list. - */ -template -struct type_list_index> { - /*! @brief Unsigned integer type. */ - using value_type = stl::size_t; - /*! @brief Compile-time position of the given type in the sublist. */ - static constexpr value_type value = 1u + type_list_index>::value; -}; - -/** - * @brief Provides compile-time type access to the types of a type list. - * @tparam Type Type to look for and for which to return the index. - * @tparam Other Other types provided by the type list. - */ -template -requires (type_list_index>::value == sizeof...(Other)) -struct type_list_index> { - /*! @brief Unsigned integer type. */ - using value_type = stl::size_t; - /*! @brief Compile-time position of the given type in the sublist. */ - static constexpr value_type value = 0u; -}; - -/** - * @brief Provides compile-time type access to the types of a type list. - * @tparam Type Type to look for and for which to return the index. - */ -template -struct type_list_index> { - /*! @brief Unsigned integer type. */ - using value_type = stl::size_t; - /*! @brief Compile-time position of the given type in the sublist. */ - static constexpr value_type value = 0u; -}; - -/** - * @brief Helper variable template. - * @tparam List Type list. - * @tparam Type Type to look for and for which to return the index. - */ -template -inline constexpr stl::size_t type_list_index_v = type_list_index::value; - -/** - * @brief Concatenates multiple type lists. - * @tparam Type Types provided by the first type list. - * @tparam Other Types provided by the second type list. - * @return A type list composed by the types of both the type lists. - */ -template -ENTT_CONSTEVAL type_list operator+(type_list, type_list) { - return {}; -} - -/*! @brief Primary template isn't defined on purpose. */ -template -struct type_list_cat; - -/*! @brief Concatenates multiple type lists. */ -template<> -struct type_list_cat<> { - /*! @brief A type list composed by the types of all the type lists. */ - using type = type_list<>; -}; - -/** - * @brief Concatenates multiple type lists. - * @tparam Type Types provided by the first type list. - * @tparam Other Types provided by the second type list. - * @tparam List Other type lists, if any. - */ -template -struct type_list_cat, type_list, List...> { - /*! @brief A type list composed by the types of all the type lists. */ - using type = type_list_cat, List...>::type; -}; - -/** - * @brief Concatenates multiple type lists. - * @tparam Type Types provided by the type list. - */ -template -struct type_list_cat> { - /*! @brief A type list composed by the types of all the type lists. */ - using type = type_list; -}; +#include "../config/module.h" + +#ifndef ENTT_MODULE +# include "../config/config.h" +# include "../stl/concepts.hpp" +# include "../stl/cstddef.hpp" +# include "../stl/iterator.hpp" +# include "../stl/tuple.hpp" +# include "../stl/type_traits.hpp" +# include "../stl/utility.hpp" +# include "fwd.hpp" +#endif // ENTT_MODULE + +ENTT_MODULE_EXPORT namespace entt { + /** + * @brief Utility class to disambiguate overloaded functions. + * @tparam N Number of choices available. + */ + template + struct choice_t + // unfortunately, doxygen cannot parse such a construct + : /*! @cond ENTT_INTERNAL */ choice_t /*! @endcond */ + {}; + + /*! @copybrief choice_t */ + template<> + struct choice_t<0> {}; + + /** + * @brief Variable template for the choice trick. + * @tparam N Number of choices available. + */ + template + inline constexpr choice_t choice{}; + + /** + * @brief A type-only `sizeof` wrapper that returns 0 where `sizeof` complains. + * @tparam Type The type of which to return the size. + */ + template + struct size_of: stl::integral_constant {}; + + /*! @copydoc size_of */ + template + requires requires { sizeof(Type); } + struct size_of + // NOLINTNEXTLINE(bugprone-sizeof-expression) + : stl::integral_constant {}; + + /** + * @brief Helper variable template. + * @tparam Type The type of which to return the size. + */ + template + inline constexpr stl::size_t size_of_v = size_of::value; + + /** + * @brief Using declaration to be used to _repeat_ the same type a number of + * times equal to the size of a given parameter pack. + * @tparam Type A type to repeat. + */ + template + using unpack_as_type = Type; + + /** + * @brief Helper variable template to be used to _repeat_ the same value a + * number of times equal to the size of a given parameter pack. + * @tparam Value A value to repeat. + */ + template + inline constexpr auto unpack_as_value = Value; + + /** + * @brief Wraps a static constant. + * @tparam Value A static constant. + */ + template + using integral_constant = stl::integral_constant; + + /** + * @brief Alias template to facilitate the creation of named values. + * @tparam Value A constant value at least convertible to `id_type`. + */ + template + using tag = integral_constant; + + /** + * @brief A class to use to push around lists of types, nothing more. + * @tparam Type Types provided by the type list. + */ + template + struct type_list { + /*! @brief Type list type. */ + using type = type_list; + /*! @brief Compile-time number of elements in the type list. */ + static constexpr auto size = sizeof...(Type); + }; + + /*! @brief Primary template isn't defined on purpose. */ + template + struct type_list_element; + + /** + * @brief Provides compile-time indexed access to the types of a type list. + * @tparam Index Index of the type to return. + * @tparam First First type provided by the type list. + * @tparam Other Other types provided by the type list. + */ + template + struct type_list_element> + : type_list_element> {}; + + /** + * @brief Provides compile-time indexed access to the types of a type list. + * @tparam First First type provided by the type list. + * @tparam Other Other types provided by the type list. + */ + template + struct type_list_element<0u, type_list> { + /*! @brief Searched type. */ + using type = First; + }; + + /** + * @brief Helper type. + * @tparam Index Index of the type to return. + * @tparam List Type list to search into. + */ + template + using type_list_element_t = type_list_element::type; + + /*! @brief Primary template isn't defined on purpose. */ + template + struct type_list_index; + + /** + * @brief Provides compile-time type access to the types of a type list. + * @tparam Type Type to look for and for which to return the index. + * @tparam First First type provided by the type list. + * @tparam Other Other types provided by the type list. + */ + template + struct type_list_index> { + /*! @brief Unsigned integer type. */ + using value_type = stl::size_t; + /*! @brief Compile-time position of the given type in the sublist. */ + static constexpr value_type value = 1u + type_list_index>::value; + }; + + /** + * @brief Provides compile-time type access to the types of a type list. + * @tparam Type Type to look for and for which to return the index. + * @tparam Other Other types provided by the type list. + */ + template + requires (type_list_index>::value == sizeof...(Other)) + struct type_list_index> { + /*! @brief Unsigned integer type. */ + using value_type = stl::size_t; + /*! @brief Compile-time position of the given type in the sublist. */ + static constexpr value_type value = 0u; + }; + + /** + * @brief Provides compile-time type access to the types of a type list. + * @tparam Type Type to look for and for which to return the index. + */ + template + struct type_list_index> { + /*! @brief Unsigned integer type. */ + using value_type = stl::size_t; + /*! @brief Compile-time position of the given type in the sublist. */ + static constexpr value_type value = 0u; + }; + + /** + * @brief Helper variable template. + * @tparam List Type list. + * @tparam Type Type to look for and for which to return the index. + */ + template + inline constexpr stl::size_t type_list_index_v = type_list_index::value; + + /** + * @brief Concatenates multiple type lists. + * @tparam Type Types provided by the first type list. + * @tparam Other Types provided by the second type list. + * @return A type list composed by the types of both the type lists. + */ + template + ENTT_CONSTEVAL type_list operator+(type_list, type_list) { + return {}; + } -/** - * @brief Helper type. - * @tparam List Type lists to concatenate. - */ -template -using type_list_cat_t = type_list_cat::type; + /*! @brief Primary template isn't defined on purpose. */ + template + struct type_list_cat; + + /*! @brief Concatenates multiple type lists. */ + template<> + struct type_list_cat<> { + /*! @brief A type list composed by the types of all the type lists. */ + using type = type_list<>; + }; + + /** + * @brief Concatenates multiple type lists. + * @tparam Type Types provided by the first type list. + * @tparam Other Types provided by the second type list. + * @tparam List Other type lists, if any. + */ + template + struct type_list_cat, type_list, List...> { + /*! @brief A type list composed by the types of all the type lists. */ + using type = type_list_cat, List...>::type; + }; + + /** + * @brief Concatenates multiple type lists. + * @tparam Type Types provided by the type list. + */ + template + struct type_list_cat> { + /*! @brief A type list composed by the types of all the type lists. */ + using type = type_list; + }; + + /** + * @brief Helper type. + * @tparam List Type lists to concatenate. + */ + template + using type_list_cat_t = type_list_cat::type; + + /*! @cond ENTT_INTERNAL */ + namespace internal { + + template + struct type_list_unique; + + template + struct type_list_unique, Type...> + : stl::conditional_t<(stl::is_same_v || ...), type_list_unique, Type...>, type_list_unique, Type..., First>> {}; + + template + struct type_list_unique, Type...> { + using type = type_list; + }; + + } // namespace internal + /*! @endcond */ + + /** + * @brief Removes duplicates types from a type list. + * @tparam List Type list. + */ + template + struct type_list_unique { + /*! @brief A type list without duplicate types. */ + using type = internal::type_list_unique::type; + }; + + /** + * @brief Helper type. + * @tparam List Type list. + */ + template + using type_list_unique_t = type_list_unique::type; + + /** + * @brief Provides the member constant `value` to true if a type list contains a + * given type, false otherwise. + * @tparam List Type list. + * @tparam Type Type to look for. + */ + template + struct type_list_contains; + + /** + * @copybrief type_list_contains + * @tparam Type Types provided by the type list. + * @tparam Other Type to look for. + */ + template + struct type_list_contains, Other> + : stl::bool_constant<(stl::is_same_v || ...)> {}; + + /** + * @brief Helper variable template. + * @tparam List Type list. + * @tparam Type Type to look for. + */ + template + inline constexpr bool type_list_contains_v = type_list_contains::value; + + /*! @brief Primary template isn't defined on purpose. */ + template + struct type_list_diff; + + /** + * @brief Computes the difference between two type lists. + * @tparam Type Types provided by the first type list. + * @tparam Other Types provided by the second type list. + */ + template + struct type_list_diff, type_list> { + /*! @brief A type list that is the difference between the two type lists. */ + using type = type_list_cat_t, Type>, type_list<>, type_list>...>; + }; + + /** + * @brief Helper type. + * @tparam List Type lists between which to compute the difference. + */ + template + using type_list_diff_t = type_list_diff::type; + + /*! @brief Primary template isn't defined on purpose. */ + template class> + struct type_list_transform; + + /** + * @brief Applies a given _function_ to a type list and 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 class Op> + struct type_list_transform, Op> { + /*! @brief Resulting type list after applying the transform function. */ + // NOLINTNEXTLINE(modernize-type-traits) + using type = type_list::type...>; + }; + + /** + * @brief Helper type. + * @tparam List Type list. + * @tparam Op Unary operation as template class with a type member named `type`. + */ + template class Op> + using type_list_transform_t = type_list_transform::type; + + /** + * @brief A class to use to push around lists of constant values, nothing more. + * @tparam Value Values provided by the value list. + */ + template + struct value_list { + /*! @brief Value list type. */ + using type = value_list; + /*! @brief Compile-time number of elements in the value list. */ + static constexpr auto size = sizeof...(Value); + }; + + /*! @brief Primary template isn't defined on purpose. */ + template + struct value_list_element; + + /** + * @brief Provides compile-time indexed access to the values of a value list. + * @tparam Index Index of the value to return. + * @tparam Value First value provided by the value list. + * @tparam Other Other values provided by the value list. + */ + template + struct value_list_element> + : value_list_element> {}; + + /** + * @brief Provides compile-time indexed access to the types of a type list. + * @tparam Value First value provided by the value list. + * @tparam Other Other values provided by the value list. + */ + template + struct value_list_element<0u, value_list> { + /*! @brief Searched type. */ + using type = decltype(Value); + /*! @brief Searched value. */ + static constexpr auto value = Value; + }; + + /** + * @brief Helper type. + * @tparam Index Index of the type to return. + * @tparam List Value list to search into. + */ + template + using value_list_element_t = value_list_element::type; + + /** + * @brief Helper type. + * @tparam Index Index of the value to return. + * @tparam List Value list to search into. + */ + template + inline constexpr auto value_list_element_v = value_list_element::value; + + /*! @brief Primary template isn't defined on purpose. */ + template + struct value_list_index; + + /** + * @brief Provides compile-time type access to the values of a value list. + * @tparam Value Value to look for and for which to return the index. + * @tparam First First value provided by the value list. + * @tparam Other Other values provided by the value list. + */ + template + struct value_list_index> { + /*! @brief Unsigned integer type. */ + using value_type = stl::size_t; + /*! @brief Compile-time position of the given value in the sublist. */ + static constexpr value_type value = 1u + value_list_index>::value; + }; + + /** + * @brief Provides compile-time type access to the values of a value list. + * @tparam Value Value to look for and for which to return the index. + * @tparam Other Other values provided by the value list. + */ + template + requires (value_list_index>::value == sizeof...(Other)) + struct value_list_index> { + /*! @brief Unsigned integer type. */ + using value_type = stl::size_t; + /*! @brief Compile-time position of the given value in the sublist. */ + static constexpr value_type value = 0u; + }; + + /** + * @brief Provides compile-time type access to the values of a value list. + * @tparam Value Value to look for and for which to return the index. + */ + template + struct value_list_index> { + /*! @brief Unsigned integer type. */ + using value_type = stl::size_t; + /*! @brief Compile-time position of the given type in the sublist. */ + static constexpr value_type value = 0u; + }; + + /** + * @brief Helper variable template. + * @tparam List Value list. + * @tparam Value Value to look for and for which to return the index. + */ + template + inline constexpr stl::size_t value_list_index_v = value_list_index::value; + + /** + * @brief Concatenates multiple value lists. + * @tparam Value Values provided by the first value list. + * @tparam Other Values provided by the second value list. + * @return A value list composed by the values of both the value lists. + */ + template + ENTT_CONSTEVAL value_list operator+(value_list, value_list) { + return {}; + } -/*! @cond ENTT_INTERNAL */ -namespace internal { + /*! @brief Primary template isn't defined on purpose. */ + template + struct value_list_cat; + + /*! @brief Concatenates multiple value lists. */ + template<> + struct value_list_cat<> { + /*! @brief A value list composed by the values of all the value lists. */ + using type = value_list<>; + }; + + /** + * @brief Concatenates multiple value lists. + * @tparam Value Values provided by the first value list. + * @tparam Other Values provided by the second value list. + * @tparam List Other value lists, if any. + */ + template + struct value_list_cat, value_list, List...> { + /*! @brief A value list composed by the values of all the value lists. */ + using type = value_list_cat, List...>::type; + }; + + /** + * @brief Concatenates multiple value lists. + * @tparam Value Values provided by the value list. + */ + template + struct value_list_cat> { + /*! @brief A value list composed by the values of all the value lists. */ + using type = value_list; + }; + + /** + * @brief Helper type. + * @tparam List Value lists to concatenate. + */ + template + using value_list_cat_t = value_list_cat::type; + + /*! @brief Primary template isn't defined on purpose. */ + template + struct value_list_unique; + + /** + * @brief Removes duplicates values from a value list. + * @tparam Value One of the values provided by the given value list. + * @tparam Other The other values provided by the given value list. + */ + template + struct value_list_unique> { + /*! @brief A value list without duplicate types. */ + using type = stl::conditional_t< + ((Value == Other) || ...), + typename value_list_unique>::type, + value_list_cat_t, typename value_list_unique>::type>>; + }; + + /*! @brief Removes duplicates values from a value list. */ + template<> + struct value_list_unique> { + /*! @brief A value list without duplicate types. */ + using type = value_list<>; + }; + + /** + * @brief Helper type. + * @tparam Type A value list. + */ + template + using value_list_unique_t = value_list_unique::type; + + /** + * @brief Provides the member constant `value` to true if a value list contains + * a given value, false otherwise. + * @tparam List Value list. + * @tparam Value Value to look for. + */ + template + struct value_list_contains; + + /** + * @copybrief value_list_contains + * @tparam Value Values provided by the value list. + * @tparam Other Value to look for. + */ + template + struct value_list_contains, Other> + : stl::bool_constant<((Value == Other) || ...)> {}; + + /** + * @brief Helper variable template. + * @tparam List Value list. + * @tparam Value Value to look for. + */ + template + inline constexpr bool value_list_contains_v = value_list_contains::value; + + /*! @brief Primary template isn't defined on purpose. */ + template + struct value_list_diff; + + /** + * @brief Computes the difference between two value lists. + * @tparam Value Values provided by the first value list. + * @tparam Other Values provided by the second value list. + */ + template + struct value_list_diff, value_list> { + /*! @brief A value list that is the difference between the two value lists. */ + using type = value_list_cat_t, Value>, value_list<>, value_list>...>; + }; + + /** + * @brief Helper type. + * @tparam List Value lists between which to compute the difference. + */ + template + using value_list_diff_t = value_list_diff::type; + + /*! @brief Same as stl::is_invocable, but with tuples. */ + template + struct is_applicable: stl::false_type {}; + + /** + * @copybrief is_applicable + * @tparam Func A valid function type. + * @tparam Tuple Tuple-like type. + * @tparam Args The list of arguments to use to probe the function type. + */ + template class Tuple, typename... Args> + struct is_applicable>: stl::is_invocable {}; + + /** + * @copybrief is_applicable + * @tparam Func A valid function type. + * @tparam Tuple Tuple-like type. + * @tparam Args The list of arguments to use to probe the function type. + */ + template class Tuple, typename... Args> + struct is_applicable>: stl::is_invocable {}; + + /** + * @brief Helper variable template. + * @tparam Func A valid function type. + * @tparam Args The list of arguments to use to probe the function type. + */ + template + inline constexpr bool is_applicable_v = is_applicable::value; + + /*! @brief Same as stl::is_invocable_r, but with tuples for arguments. */ + template + struct is_applicable_r: stl::false_type {}; + + /** + * @copybrief is_applicable_r + * @tparam Ret The type to which the return type of the function should be + * convertible. + * @tparam Func A valid function type. + * @tparam Args The list of arguments to use to probe the function type. + */ + template + struct is_applicable_r>: stl::is_invocable_r {}; + + /** + * @brief Helper variable template. + * @tparam Ret The type to which the return type of the function should be + * convertible. + * @tparam Func A valid function type. + * @tparam Args The list of arguments to use to probe the function type. + */ + template + inline constexpr bool is_applicable_r_v = is_applicable_r::value; + + /** + * @brief Provides the member constant `value` to true if a given type is + * complete, false otherwise. + * @tparam Type The type to test. + */ + template + struct is_complete: stl::false_type {}; -template -struct type_list_unique; + /*! @copydoc is_complete */ + template + requires requires { sizeof(Type); } + struct is_complete: stl::true_type {}; -template -struct type_list_unique, Type...> - : stl::conditional_t<(stl::is_same_v || ...), type_list_unique, Type...>, type_list_unique, Type..., First>> {}; + /** + * @brief Helper variable template. + * @tparam Type The type to test. + */ + template + inline constexpr bool is_complete_v = is_complete::value; -template -struct type_list_unique, Type...> { - using type = type_list; -}; - -} // namespace internal -/*! @endcond */ - -/** - * @brief Removes duplicates types from a type list. - * @tparam List Type list. - */ -template -struct type_list_unique { - /*! @brief A type list without duplicate types. */ - using type = internal::type_list_unique::type; -}; - -/** - * @brief Helper type. - * @tparam List Type list. - */ -template -using type_list_unique_t = type_list_unique::type; - -/** - * @brief Provides the member constant `value` to true if a type list contains a - * given type, false otherwise. - * @tparam List Type list. - * @tparam Type Type to look for. - */ -template -struct type_list_contains; - -/** - * @copybrief type_list_contains - * @tparam Type Types provided by the type list. - * @tparam Other Type to look for. - */ -template -struct type_list_contains, Other> - : stl::bool_constant<(stl::is_same_v || ...)> {}; - -/** - * @brief Helper variable template. - * @tparam List Type list. - * @tparam Type Type to look for. - */ -template -inline constexpr bool type_list_contains_v = type_list_contains::value; - -/*! @brief Primary template isn't defined on purpose. */ -template -struct type_list_diff; - -/** - * @brief Computes the difference between two type lists. - * @tparam Type Types provided by the first type list. - * @tparam Other Types provided by the second type list. - */ -template -struct type_list_diff, type_list> { - /*! @brief A type list that is the difference between the two type lists. */ - using type = type_list_cat_t, Type>, type_list<>, type_list>...>; -}; - -/** - * @brief Helper type. - * @tparam List Type lists between which to compute the difference. - */ -template -using type_list_diff_t = type_list_diff::type; - -/*! @brief Primary template isn't defined on purpose. */ -template class> -struct type_list_transform; - -/** - * @brief Applies a given _function_ to a type list and 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 class Op> -struct type_list_transform, Op> { - /*! @brief Resulting type list after applying the transform function. */ - // NOLINTNEXTLINE(modernize-type-traits) - using type = type_list::type...>; -}; - -/** - * @brief Helper type. - * @tparam List Type list. - * @tparam Op Unary operation as template class with a type member named `type`. - */ -template class Op> -using type_list_transform_t = type_list_transform::type; - -/** - * @brief A class to use to push around lists of constant values, nothing more. - * @tparam Value Values provided by the value list. - */ -template -struct value_list { - /*! @brief Value list type. */ - using type = value_list; - /*! @brief Compile-time number of elements in the value list. */ - static constexpr auto size = sizeof...(Value); -}; - -/*! @brief Primary template isn't defined on purpose. */ -template -struct value_list_element; - -/** - * @brief Provides compile-time indexed access to the values of a value list. - * @tparam Index Index of the value to return. - * @tparam Value First value provided by the value list. - * @tparam Other Other values provided by the value list. - */ -template -struct value_list_element> - : value_list_element> {}; - -/** - * @brief Provides compile-time indexed access to the types of a type list. - * @tparam Value First value provided by the value list. - * @tparam Other Other values provided by the value list. - */ -template -struct value_list_element<0u, value_list> { - /*! @brief Searched type. */ - using type = decltype(Value); - /*! @brief Searched value. */ - static constexpr auto value = Value; -}; - -/** - * @brief Helper type. - * @tparam Index Index of the type to return. - * @tparam List Value list to search into. - */ -template -using value_list_element_t = value_list_element::type; - -/** - * @brief Helper type. - * @tparam Index Index of the value to return. - * @tparam List Value list to search into. - */ -template -inline constexpr auto value_list_element_v = value_list_element::value; - -/*! @brief Primary template isn't defined on purpose. */ -template -struct value_list_index; - -/** - * @brief Provides compile-time type access to the values of a value list. - * @tparam Value Value to look for and for which to return the index. - * @tparam First First value provided by the value list. - * @tparam Other Other values provided by the value list. - */ -template -struct value_list_index> { - /*! @brief Unsigned integer type. */ - using value_type = stl::size_t; - /*! @brief Compile-time position of the given value in the sublist. */ - static constexpr value_type value = 1u + value_list_index>::value; -}; - -/** - * @brief Provides compile-time type access to the values of a value list. - * @tparam Value Value to look for and for which to return the index. - * @tparam Other Other values provided by the value list. - */ -template -requires (value_list_index>::value == sizeof...(Other)) -struct value_list_index> { - /*! @brief Unsigned integer type. */ - using value_type = stl::size_t; - /*! @brief Compile-time position of the given value in the sublist. */ - static constexpr value_type value = 0u; -}; - -/** - * @brief Provides compile-time type access to the values of a value list. - * @tparam Value Value to look for and for which to return the index. - */ -template -struct value_list_index> { - /*! @brief Unsigned integer type. */ - using value_type = stl::size_t; - /*! @brief Compile-time position of the given type in the sublist. */ - static constexpr value_type value = 0u; -}; - -/** - * @brief Helper variable template. - * @tparam List Value list. - * @tparam Value Value to look for and for which to return the index. - */ -template -inline constexpr stl::size_t value_list_index_v = value_list_index::value; - -/** - * @brief Concatenates multiple value lists. - * @tparam Value Values provided by the first value list. - * @tparam Other Values provided by the second value list. - * @return A value list composed by the values of both the value lists. - */ -template -ENTT_CONSTEVAL value_list operator+(value_list, value_list) { - return {}; -} - -/*! @brief Primary template isn't defined on purpose. */ -template -struct value_list_cat; - -/*! @brief Concatenates multiple value lists. */ -template<> -struct value_list_cat<> { - /*! @brief A value list composed by the values of all the value lists. */ - using type = value_list<>; -}; - -/** - * @brief Concatenates multiple value lists. - * @tparam Value Values provided by the first value list. - * @tparam Other Values provided by the second value list. - * @tparam List Other value lists, if any. - */ -template -struct value_list_cat, value_list, List...> { - /*! @brief A value list composed by the values of all the value lists. */ - using type = value_list_cat, List...>::type; -}; - -/** - * @brief Concatenates multiple value lists. - * @tparam Value Values provided by the value list. - */ -template -struct value_list_cat> { - /*! @brief A value list composed by the values of all the value lists. */ - using type = value_list; -}; - -/** - * @brief Helper type. - * @tparam List Value lists to concatenate. - */ -template -using value_list_cat_t = value_list_cat::type; - -/*! @brief Primary template isn't defined on purpose. */ -template -struct value_list_unique; - -/** - * @brief Removes duplicates values from a value list. - * @tparam Value One of the values provided by the given value list. - * @tparam Other The other values provided by the given value list. - */ -template -struct value_list_unique> { - /*! @brief A value list without duplicate types. */ - using type = stl::conditional_t< - ((Value == Other) || ...), - typename value_list_unique>::type, - value_list_cat_t, typename value_list_unique>::type>>; -}; - -/*! @brief Removes duplicates values from a value list. */ -template<> -struct value_list_unique> { - /*! @brief A value list without duplicate types. */ - using type = value_list<>; -}; - -/** - * @brief Helper type. - * @tparam Type A value list. - */ -template -using value_list_unique_t = value_list_unique::type; - -/** - * @brief Provides the member constant `value` to true if a value list contains - * a given value, false otherwise. - * @tparam List Value list. - * @tparam Value Value to look for. - */ -template -struct value_list_contains; - -/** - * @copybrief value_list_contains - * @tparam Value Values provided by the value list. - * @tparam Other Value to look for. - */ -template -struct value_list_contains, Other> - : stl::bool_constant<((Value == Other) || ...)> {}; - -/** - * @brief Helper variable template. - * @tparam List Value list. - * @tparam Value Value to look for. - */ -template -inline constexpr bool value_list_contains_v = value_list_contains::value; - -/*! @brief Primary template isn't defined on purpose. */ -template -struct value_list_diff; - -/** - * @brief Computes the difference between two value lists. - * @tparam Value Values provided by the first value list. - * @tparam Other Values provided by the second value list. - */ -template -struct value_list_diff, value_list> { - /*! @brief A value list that is the difference between the two value lists. */ - using type = value_list_cat_t, Value>, value_list<>, value_list>...>; -}; - -/** - * @brief Helper type. - * @tparam List Value lists between which to compute the difference. - */ -template -using value_list_diff_t = value_list_diff::type; - -/*! @brief Same as stl::is_invocable, but with tuples. */ -template -struct is_applicable: stl::false_type {}; - -/** - * @copybrief is_applicable - * @tparam Func A valid function type. - * @tparam Tuple Tuple-like type. - * @tparam Args The list of arguments to use to probe the function type. - */ -template class Tuple, typename... Args> -struct is_applicable>: stl::is_invocable {}; - -/** - * @copybrief is_applicable - * @tparam Func A valid function type. - * @tparam Tuple Tuple-like type. - * @tparam Args The list of arguments to use to probe the function type. - */ -template class Tuple, typename... Args> -struct is_applicable>: stl::is_invocable {}; - -/** - * @brief Helper variable template. - * @tparam Func A valid function type. - * @tparam Args The list of arguments to use to probe the function type. - */ -template -inline constexpr bool is_applicable_v = is_applicable::value; - -/*! @brief Same as stl::is_invocable_r, but with tuples for arguments. */ -template -struct is_applicable_r: stl::false_type {}; - -/** - * @copybrief is_applicable_r - * @tparam Ret The type to which the return type of the function should be - * convertible. - * @tparam Func A valid function type. - * @tparam Args The list of arguments to use to probe the function type. - */ -template -struct is_applicable_r>: stl::is_invocable_r {}; - -/** - * @brief Helper variable template. - * @tparam Ret The type to which the return type of the function should be - * convertible. - * @tparam Func A valid function type. - * @tparam Args The list of arguments to use to probe the function type. - */ -template -inline constexpr bool is_applicable_r_v = is_applicable_r::value; - -/** - * @brief Provides the member constant `value` to true if a given type is - * complete, false otherwise. - * @tparam Type The type to test. - */ -template -struct is_complete: stl::false_type {}; - -/*! @copydoc is_complete */ -template -requires requires { sizeof(Type); } -struct is_complete: stl::true_type {}; - -/** - * @brief Helper variable template. - * @tparam Type The type to test. - */ -template -inline constexpr bool is_complete_v = is_complete::value; - -/** - * @brief Provides the member constant `value` to true if a given type is an - * iterator, false otherwise. - * @tparam Type The type to test. - */ -template -struct is_iterator: stl::false_type {}; - -/*! @cond ENTT_INTERNAL */ -namespace internal { - -template -struct has_iterator_category: stl::false_type {}; - -template -requires requires { typename stl::iterator_traits::iterator_category; } -struct has_iterator_category: stl::true_type {}; - -} // namespace internal -/*! @endcond */ - -/*! @copydoc is_iterator */ -template -requires (!stl::is_void_v>>) -struct is_iterator: internal::has_iterator_category {}; - -/** - * @brief Helper variable template. - * @tparam Type The type to test. - */ -template -inline constexpr bool is_iterator_v = is_iterator::value; - -/** - * @brief Provides the member constant `value` to true if a given type is both - * an empty and non-final class, false otherwise. - * @tparam Type The type to test - */ -template -struct is_ebco_eligible: stl::bool_constant && !stl::is_final_v> {}; - -/** - * @brief Helper variable template. - * @tparam Type The type to test. - */ -template -inline constexpr bool is_ebco_eligible_v = is_ebco_eligible::value; - -/** - * @brief Provides the member constant `value` to true if `Type::is_transparent` - * is valid and denotes a type, false otherwise. - * @tparam Type The type to test. - */ -template -struct is_transparent: stl::false_type {}; - -/*! @copydoc is_transparent */ -template -requires requires { typename Type::is_transparent; } -struct is_transparent: stl::true_type {}; - -/** - * @brief Helper variable template. - * @tparam Type The type to test. - */ -template -inline constexpr bool is_transparent_v = is_transparent::value; - -/*! @cond ENTT_INTERNAL */ -namespace internal { - -template -struct has_tuple_size_value: stl::false_type {}; - -template -requires is_complete_v> -struct has_tuple_size_value: stl::true_type {}; - -template -struct has_value_type: stl::false_type {}; - -template -requires requires { typename Type::value_type; } -struct has_value_type: stl::true_type {}; - -template -[[nodiscard]] ENTT_CONSTEVAL bool dispatch_is_equality_comparable(); - -template -[[nodiscard]] ENTT_CONSTEVAL bool unpack_maybe_equality_comparable(stl::index_sequence) { - return (dispatch_is_equality_comparable>() && ...); -} - -template -[[nodiscard]] ENTT_CONSTEVAL bool maybe_equality_comparable(char) { - return false; -} - -template -[[nodiscard]] ENTT_CONSTEVAL auto maybe_equality_comparable(int) -> decltype(stl::declval() == stl::declval()) { - return true; -} - -template -[[nodiscard]] ENTT_CONSTEVAL bool dispatch_is_equality_comparable() { - // NOLINTBEGIN(modernize-use-transparent-functors) - if constexpr(stl::is_array_v) { + /** + * @brief Provides the member constant `value` to true if a given type is an + * iterator, false otherwise. + * @tparam Type The type to test. + */ + template + struct is_iterator: stl::false_type {}; + + /*! @cond ENTT_INTERNAL */ + namespace internal { + + template + struct has_iterator_category: stl::false_type {}; + + template + requires requires { typename stl::iterator_traits::iterator_category; } + struct has_iterator_category: stl::true_type {}; + + } // namespace internal + /*! @endcond */ + + /*! @copydoc is_iterator */ + template + requires (!stl::is_void_v>>) + struct is_iterator: internal::has_iterator_category {}; + + /** + * @brief Helper variable template. + * @tparam Type The type to test. + */ + template + inline constexpr bool is_iterator_v = is_iterator::value; + + /** + * @brief Provides the member constant `value` to true if a given type is both + * an empty and non-final class, false otherwise. + * @tparam Type The type to test + */ + template + struct is_ebco_eligible: stl::bool_constant && !stl::is_final_v> {}; + + /** + * @brief Helper variable template. + * @tparam Type The type to test. + */ + template + inline constexpr bool is_ebco_eligible_v = is_ebco_eligible::value; + + /** + * @brief Provides the member constant `value` to true if `Type::is_transparent` + * is valid and denotes a type, false otherwise. + * @tparam Type The type to test. + */ + template + struct is_transparent: stl::false_type {}; + + /*! @copydoc is_transparent */ + template + requires requires { typename Type::is_transparent; } + struct is_transparent: stl::true_type {}; + + /** + * @brief Helper variable template. + * @tparam Type The type to test. + */ + template + inline constexpr bool is_transparent_v = is_transparent::value; + + /*! @cond ENTT_INTERNAL */ + namespace internal { + + template + struct has_tuple_size_value: stl::false_type {}; + + template + requires is_complete_v> + struct has_tuple_size_value: stl::true_type {}; + + template + struct has_value_type: stl::false_type {}; + + template + requires requires { typename Type::value_type; } + struct has_value_type: stl::true_type {}; + + template + [[nodiscard]] ENTT_CONSTEVAL bool dispatch_is_equality_comparable(); + + template + [[nodiscard]] ENTT_CONSTEVAL bool unpack_maybe_equality_comparable(stl::index_sequence) { + return (dispatch_is_equality_comparable>() && ...); + } + + template + [[nodiscard]] ENTT_CONSTEVAL bool maybe_equality_comparable(char) { return false; - } else if constexpr(is_complete_v>>) { - if constexpr(has_tuple_size_value::value) { - return maybe_equality_comparable(0) && unpack_maybe_equality_comparable(stl::make_index_sequence::value>{}); + } + + template + [[nodiscard]] ENTT_CONSTEVAL auto maybe_equality_comparable(int) -> decltype(stl::declval() == stl::declval()) { + return true; + } + + template + [[nodiscard]] ENTT_CONSTEVAL bool dispatch_is_equality_comparable() { + // NOLINTBEGIN(modernize-use-transparent-functors) + if constexpr(stl::is_array_v) { + return false; + } else if constexpr(is_complete_v>>) { + if constexpr(has_tuple_size_value::value) { + return maybe_equality_comparable(0) && unpack_maybe_equality_comparable(stl::make_index_sequence::value>{}); + } else { + return maybe_equality_comparable(0); + } + } else if constexpr(has_value_type::value) { + if constexpr(is_iterator_v || stl::is_same_v || dispatch_is_equality_comparable()) { + return maybe_equality_comparable(0); + } else { + return false; + } } else { return maybe_equality_comparable(0); } - } else if constexpr(has_value_type::value) { - if constexpr(is_iterator_v || stl::is_same_v || dispatch_is_equality_comparable()) { - return maybe_equality_comparable(0); - } else { - return false; - } - } else { - return maybe_equality_comparable(0); + // NOLINTEND(modernize-use-transparent-functors) } - // 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 -struct is_equality_comparable: stl::bool_constant()> {}; - -/*! @copydoc is_equality_comparable */ -template -struct is_equality_comparable: is_equality_comparable {}; - -/** - * @brief Helper variable template. - * @tparam Type The type to test. - */ -template -inline constexpr bool is_equality_comparable_v = is_equality_comparable::value; - -/** - * @brief Transcribes the constness of a type to another type. - * @tparam To The type to which to transcribe the constness. - * @tparam From The type from which to transcribe the constness. - */ -template -struct constness_as { - /*! @brief The type resulting from the transcription of the constness. */ - using type = stl::remove_const_t; -}; - -/*! @copydoc constness_as */ -template -struct constness_as { - /*! @brief The type resulting from the transcription of the constness. */ - using type = const To; -}; - -/** - * @brief Alias template to facilitate the transcription of the constness. - * @tparam To The type to which to transcribe the constness. - * @tparam From The type from which to transcribe the constness. - */ -template -using constness_as_t = constness_as::type; - -/*! @brief Primary template isn't defined on purpose. */ -template -class member_class; - -/** - * @brief Extracts the class of a non-static member object or function. - * @tparam Member A pointer to a non-static member object or function. - */ -template -requires stl::is_member_pointer_v -class member_class { - template - static Class *clazz(Ret (Class::*)(Args...)); - - template - static Class *clazz(Ret (Class::*)(Args...) const); - - template - static Class *clazz(Type Class::*); - -public: - /*! @brief The class of the given non-static member object or function. */ - using type = stl::remove_pointer_t()))>; -}; - -/** - * @brief Helper type. - * @tparam Member A pointer to a non-static member object or function. - */ -template -using member_class_t = member_class::type; - -/** - * @brief Extracts the n-th argument of a _callable_ type. - * @tparam Index The index of the argument to extract. - * @tparam Candidate A valid _callable_ type. - */ -template -class nth_argument { - template - static ENTT_CONSTEVAL type_list pick_up(Ret (*)(Args...)); - - template - static ENTT_CONSTEVAL type_list pick_up(Ret (Class ::*)(Args...)); - - template - static ENTT_CONSTEVAL type_list pick_up(Ret (Class ::*)(Args...) const); - - template - static ENTT_CONSTEVAL type_list pick_up(Type Class ::*); + } // 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 - static ENTT_CONSTEVAL decltype(pick_up(&Type::operator())) pick_up(Type &&); + struct is_equality_comparable: stl::bool_constant()> {}; -public: - /*! @brief N-th argument of the _callable_ type. */ - using type = type_list_element_t()))>; -}; + /*! @copydoc is_equality_comparable */ + template + struct is_equality_comparable: is_equality_comparable {}; -/** - * @brief Helper type. - * @tparam Index The index of the argument to extract. - * @tparam Candidate A valid function, member function or data member type. - */ -template -using nth_argument_t = nth_argument::type; + /** + * @brief Helper variable template. + * @tparam Type The type to test. + */ + template + inline constexpr bool is_equality_comparable_v = is_equality_comparable::value; + + /** + * @brief Transcribes the constness of a type to another type. + * @tparam To The type to which to transcribe the constness. + * @tparam From The type from which to transcribe the constness. + */ + template + struct constness_as { + /*! @brief The type resulting from the transcription of the constness. */ + using type = stl::remove_const_t; + }; + + /*! @copydoc constness_as */ + template + struct constness_as { + /*! @brief The type resulting from the transcription of the constness. */ + using type = const To; + }; + + /** + * @brief Alias template to facilitate the transcription of the constness. + * @tparam To The type to which to transcribe the constness. + * @tparam From The type from which to transcribe the constness. + */ + template + using constness_as_t = constness_as::type; + + /*! @brief Primary template isn't defined on purpose. */ + template + class member_class; + + /** + * @brief Extracts the class of a non-static member object or function. + * @tparam Member A pointer to a non-static member object or function. + */ + template + requires stl::is_member_pointer_v + class member_class { + template + static Class *clazz(Ret (Class::*)(Args...)); + + template + static Class *clazz(Ret (Class::*)(Args...) const); + + template + static Class *clazz(Type Class::*); + + public: + /*! @brief The class of the given non-static member object or function. */ + using type = stl::remove_pointer_t()))>; + }; + + /** + * @brief Helper type. + * @tparam Member A pointer to a non-static member object or function. + */ + template + using member_class_t = member_class::type; + + /** + * @brief Extracts the n-th argument of a _callable_ type. + * @tparam Index The index of the argument to extract. + * @tparam Candidate A valid _callable_ type. + */ + template + class nth_argument { + template + static ENTT_CONSTEVAL type_list pick_up(Ret (*)(Args...)); + + template + static ENTT_CONSTEVAL type_list pick_up(Ret (Class ::*)(Args...)); + + template + static ENTT_CONSTEVAL type_list pick_up(Ret (Class ::*)(Args...) const); + + template + static ENTT_CONSTEVAL type_list pick_up(Type Class ::*); + + template + static ENTT_CONSTEVAL decltype(pick_up(&Type::operator())) pick_up(Type &&); + + public: + /*! @brief N-th argument of the _callable_ type. */ + using type = type_list_element_t()))>; + }; + + /** + * @brief Helper type. + * @tparam Index The index of the argument to extract. + * @tparam Candidate A valid function, member function or data member type. + */ + template + using nth_argument_t = nth_argument::type; } // namespace entt +ENTT_MODULE_EXPORT_BEGIN + template struct entt::stl::tuple_size>: entt::stl::integral_constant::size> {}; @@ -906,4 +911,6 @@ struct entt::stl::tuple_size>: entt::stl::integral_co template struct entt::stl::tuple_element>: entt::value_list_element> {}; +ENTT_MODULE_EXPORT_END + #endif diff --git a/src/entt/core/utility.hpp b/src/entt/core/utility.hpp index b7e50c4d87..08cf40bc3a 100644 --- a/src/entt/core/utility.hpp +++ b/src/entt/core/utility.hpp @@ -1,83 +1,86 @@ #ifndef ENTT_CORE_UTILITY_HPP #define ENTT_CORE_UTILITY_HPP -#include "../stl/type_traits.hpp" -#include "../stl/utility.hpp" +#include "../config/module.h" -namespace entt { +#ifndef ENTT_MODULE +# include "../stl/type_traits.hpp" +# include "../stl/utility.hpp" +#endif // ENTT_MODULE -/** - * @brief Constant utility to disambiguate overloaded members of a class. - * @tparam Type Type of the desired overload. - * @tparam Class Type of class to which the member belongs. - * @param member A valid pointer to a member. - * @return Pointer to the member. - */ -template -[[nodiscard]] constexpr auto overload(Type Class::*member) noexcept { - return member; -} - -/** - * @brief Constant utility to disambiguate overloaded functions. - * @tparam Func Function type of the desired overload. - * @param func A valid pointer to a function. - * @return Pointer to the function. - */ -template -[[nodiscard]] constexpr auto overload(Func *func) noexcept { - return func; -} +ENTT_MODULE_EXPORT namespace entt { + /** + * @brief Constant utility to disambiguate overloaded members of a class. + * @tparam Type Type of the desired overload. + * @tparam Class Type of class to which the member belongs. + * @param member A valid pointer to a member. + * @return Pointer to the member. + */ + template + [[nodiscard]] constexpr auto overload(Type Class::*member) noexcept { + return member; + } -/** - * @brief Helper type for visitors. - * @tparam Func Types of function objects. - */ -template -struct overloaded: Func... { - using Func::operator()...; -}; + /** + * @brief Constant utility to disambiguate overloaded functions. + * @tparam Func Function type of the desired overload. + * @param func A valid pointer to a function. + * @return Pointer to the function. + */ + template + [[nodiscard]] constexpr auto overload(Func * func) noexcept { + return func; + } -/** - * @brief Deduction guide. - * @tparam Func Types of function objects. - */ -template -overloaded(Func...) -> overloaded; + /** + * @brief Helper type for visitors. + * @tparam Func Types of function objects. + */ + template + struct overloaded: Func... { + using Func::operator()...; + }; -/** - * @brief Basic implementation of a y-combinator. - * @tparam Func Type of a potentially recursive function. - */ -template -struct y_combinator { /** - * @brief Constructs a y-combinator from a given function. - * @param recursive A potentially recursive function. + * @brief Deduction guide. + * @tparam Func Types of function objects. */ - constexpr y_combinator(Func recursive) noexcept(stl::is_nothrow_move_constructible_v) - : func{stl::move(recursive)} {} + template + overloaded(Func...) -> overloaded; /** - * @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. + * @brief Basic implementation of a y-combinator. + * @tparam Func Type of a potentially recursive function. */ - template - constexpr decltype(auto) operator()(Args &&...args) const noexcept(stl::is_nothrow_invocable_v) { - return func(*this, stl::forward(args)...); - } + template + struct y_combinator { + /** + * @brief Constructs a y-combinator from a given function. + * @param recursive A potentially recursive function. + */ + constexpr y_combinator(Func recursive) noexcept(stl::is_nothrow_move_constructible_v) + : func{stl::move(recursive)} {} - /*! @copydoc operator()() */ - template - constexpr decltype(auto) operator()(Args &&...args) noexcept(stl::is_nothrow_invocable_v) { - return func(*this, stl::forward(args)...); - } + /** + * @brief Invokes a y-combinator and therefore its underlying function. + * @tparam Args Types of arguments to use to invoke the underlying function. + * @param args Parameters to use to invoke the underlying function. + * @return Return value of the underlying function, if any. + */ + template + constexpr decltype(auto) operator()(Args &&...args) const noexcept(stl::is_nothrow_invocable_v) { + return func(*this, stl::forward(args)...); + } + + /*! @copydoc operator()() */ + template + constexpr decltype(auto) operator()(Args &&...args) noexcept(stl::is_nothrow_invocable_v) { + return func(*this, stl::forward(args)...); + } -private: - Func func; -}; + private: + Func func; + }; } // namespace entt diff --git a/src/entt/entity/component.hpp b/src/entt/entity/component.hpp index 6730fc3173..05756a9e7c 100644 --- a/src/entt/entity/component.hpp +++ b/src/entt/entity/component.hpp @@ -1,12 +1,16 @@ #ifndef ENTT_ENTITY_COMPONENT_HPP #define ENTT_ENTITY_COMPONENT_HPP -#include "../config/config.h" -#include "../core/concepts.hpp" -#include "../stl/concepts.hpp" -#include "../stl/cstddef.hpp" -#include "../stl/type_traits.hpp" -#include "fwd.hpp" +#include "../config/module.h" + +#ifndef ENTT_MODULE +# include "../config/config.h" +# include "../core/concepts.hpp" +# include "../stl/concepts.hpp" +# include "../stl/cstddef.hpp" +# include "../stl/type_traits.hpp" +# include "fwd.hpp" +#endif // ENTT_MODULE namespace entt { @@ -36,6 +40,8 @@ struct page_size: stl::integral_constant {}; } // namespace internal /*! @endcond */ +ENTT_MODULE_EXPORT_BEGIN + /** * @brief Common way to access various properties of components. * @tparam Type Element type. @@ -54,6 +60,8 @@ struct component_traits { static constexpr stl::size_t page_size = internal::page_size::value; }; +ENTT_MODULE_EXPORT_END + } // namespace entt #endif diff --git a/src/entt/entity/entity.hpp b/src/entt/entity/entity.hpp index 111574a29c..5f6174ae86 100644 --- a/src/entt/entity/entity.hpp +++ b/src/entt/entity/entity.hpp @@ -1,14 +1,18 @@ #ifndef ENTT_ENTITY_ENTITY_HPP #define ENTT_ENTITY_ENTITY_HPP -#include "../config/config.h" -#include "../core/bit.hpp" -#include "../stl/bit.hpp" -#include "../stl/concepts.hpp" -#include "../stl/cstddef.hpp" -#include "../stl/cstdint.hpp" -#include "../stl/type_traits.hpp" -#include "fwd.hpp" +#include "../config/module.h" + +#ifndef ENTT_MODULE +# include "../config/config.h" +# include "../core/bit.hpp" +# include "../stl/bit.hpp" +# include "../stl/concepts.hpp" +# include "../stl/cstddef.hpp" +# include "../stl/cstdint.hpp" +# include "../stl/type_traits.hpp" +# include "fwd.hpp" +#endif // ENTT_MODULE namespace entt { @@ -59,6 +63,8 @@ struct entt_traits { } // namespace internal /*! @endcond */ +ENTT_MODULE_EXPORT_BEGIN + /** * @brief Specifies that a type is an entity-like type. * @tparam Type Type to check. @@ -307,6 +313,8 @@ inline constexpr null_t null{}; */ inline constexpr tombstone_t tombstone{}; +ENTT_MODULE_EXPORT_END + } // namespace entt #endif diff --git a/src/entt/entity/fwd.hpp b/src/entt/entity/fwd.hpp index f1d1a895d9..a063d3ffa7 100644 --- a/src/entt/entity/fwd.hpp +++ b/src/entt/entity/fwd.hpp @@ -1,290 +1,293 @@ #ifndef ENTT_ENTITY_FWD_HPP #define ENTT_ENTITY_FWD_HPP -#include "../config/config.h" -#include "../core/concepts.hpp" -#include "../core/fwd.hpp" -#include "../core/type_traits.hpp" -#include "../stl/cstdint.hpp" -#include "../stl/memory.hpp" -#include "../stl/type_traits.hpp" - -namespace entt { - -/*! @brief Default entity identifier. */ -enum class entity : id_type {}; - -/*! @brief Storage deletion policy. */ -enum class deletion_policy : stl::uint8_t { - /*! @brief Swap-and-pop deletion policy. */ - swap_and_pop = 0u, - /*! @brief In-place deletion policy. */ - in_place = 1u, - /*! @brief Swap-only deletion policy. */ - swap_only = 2u, - /*! @brief Unspecified deletion policy. */ - unspecified = swap_and_pop -}; - -template -struct component_traits; - -template> -class basic_sparse_set; - -template> -class basic_storage; - -template -class basic_sigh_mixin; - -template -class basic_reactive_mixin; - -template> -class basic_registry; - -template -class basic_view; - -template> -class basic_runtime_view; - -template -class basic_group; - -template -class basic_organizer; - -template -class basic_handle; - -template -class basic_snapshot; - -template -class basic_snapshot_loader; - -template -class basic_continuous_loader; - -/*! @brief Alias declaration for the most common use case. */ -using sparse_set = basic_sparse_set<>; - -/** - * @brief Alias declaration for the most common use case. - * @tparam Type Element type. - */ -template -using storage = basic_storage; - -/** - * @brief Alias declaration for the most common use case. - * @tparam Type Underlying storage type. - */ -template -using sigh_mixin = basic_sigh_mixin>; - -/** - * @brief Alias declaration for the most common use case. - * @tparam Type Underlying storage type. - */ -template -using reactive_mixin = basic_reactive_mixin>; - -/*! @brief Alias declaration for the most common use case. */ -using registry = basic_registry<>; - -/*! @brief Alias declaration for the most common use case. */ -using organizer = basic_organizer; - -/*! @brief Alias declaration for the most common use case. */ -using handle = basic_handle; - -/*! @brief Alias declaration for the most common use case. */ -using const_handle = basic_handle; - -/** - * @brief Alias declaration for the most common use case. - * @tparam Args Other template parameters. - */ -template -using handle_view = basic_handle; - -/** - * @brief Alias declaration for the most common use case. - * @tparam Args Other template parameters. - */ -template -using const_handle_view = basic_handle; - -/*! @brief Alias declaration for the most common use case. */ -using snapshot = basic_snapshot; - -/*! @brief Alias declaration for the most common use case. */ -using snapshot_loader = basic_snapshot_loader; - -/*! @brief Alias declaration for the most common use case. */ -using continuous_loader = basic_continuous_loader; - -/*! @brief Alias declaration for the most common use case. */ -using runtime_view = basic_runtime_view; - -/*! @brief Alias declaration for the most common use case. */ -using const_runtime_view = basic_runtime_view; - -/** - * @brief Alias for exclusion lists. - * @tparam Type List of types. - */ -template -struct exclude_t final: type_list { - /*! @brief Default constructor. */ - explicit ENTT_CONSTEVAL exclude_t() = default; -}; - -/** - * @brief Variable template for exclusion lists. - * @tparam Type List of types. - */ -template -inline constexpr exclude_t exclude{}; - -/** - * @brief Alias for lists of observed elements. - * @tparam Type List of types. - */ -template -struct get_t final: type_list { - /*! @brief Default constructor. */ - explicit ENTT_CONSTEVAL get_t() = default; -}; - -/** - * @brief Variable template for lists of observed elements. - * @tparam Type List of types. - */ -template -inline constexpr get_t get{}; - -/** - * @brief Alias for lists of owned elements. - * @tparam Type List of types. - */ -template -struct owned_t final: type_list { - /*! @brief Default constructor. */ - explicit ENTT_CONSTEVAL owned_t() = default; -}; - -/** - * @brief Variable template for lists of owned elements. - * @tparam Type List of types. - */ -template -inline constexpr owned_t owned{}; - -/** - * @brief Applies a given _function_ to a get list and generate a new list. - * @tparam Type Types provided by the get list. - * @tparam Op Unary operation as template class with a type member named `type`. - */ -template class Op> -struct type_list_transform, Op> { - /*! @brief Resulting get list after applying the transform function. */ - using type = get_t::type...>; -}; - -/** - * @brief Applies a given _function_ to an exclude list and generate a new list. - * @tparam Type Types provided by the exclude list. - * @tparam Op Unary operation as template class with a type member named `type`. - */ -template class Op> -struct type_list_transform, Op> { - /*! @brief Resulting exclude list after applying the transform function. */ - using type = exclude_t::type...>; -}; - -/** - * @brief Applies a given _function_ to an owned list and generate a new list. - * @tparam Type Types provided by the owned list. - * @tparam Op Unary operation as template class with a type member named `type`. - */ -template class Op> -struct type_list_transform, Op> { - /*! @brief Resulting owned list after applying the transform function. */ - using type = owned_t::type...>; -}; - -/** - * @brief Provides a common way to define storage types. - * @tparam Type Storage value type. - * @tparam Entity A valid entity type. - * @tparam Allocator Type of allocator used to manage memory and elements. - */ -template> -struct storage_type { - /*! @brief Type-to-storage conversion result. */ - using type = ENTT_STORAGE(sigh_mixin, basic_storage); -}; - -/*! @brief Empty value type for reactive storage types. */ -struct reactive final {}; - -/** - * @ brief Partial specialization for reactive storage types. - * @tparam Entity A valid entity type. - * @tparam Allocator Type of allocator used to manage memory and elements. - */ -template -struct storage_type { - /*! @brief Type-to-storage conversion result. */ - using type = ENTT_STORAGE(reactive_mixin, basic_storage); -}; - -/** - * @brief Helper type. - * @tparam Args Arguments to forward. - */ -template -using storage_type_t = storage_type::type; - -/** - * Type-to-storage conversion utility that preserves constness. - * @tparam Type Storage value type, eventually const. - * @tparam Entity A valid entity type. - * @tparam Allocator Type of allocator used to manage memory and elements. - */ -template>> -struct storage_for { - /*! @brief Type-to-storage conversion result. */ - using type = constness_as_t, Entity, Allocator>, Type>; -}; - -/** - * @brief Helper type. - * @tparam Args Arguments to forward. - */ -template -using storage_for_t = storage_for::type; - -/** - * @brief Alias declaration for the most common use case. - * @tparam Get Types of storage iterated by the view. - * @tparam Exclude Types of storage used to filter the view. - */ -template> -using view = basic_view, type_list_transform_t>; - -/** - * @brief Alias declaration for the most common use case. - * @tparam Owned Types of storage _owned_ by the group. - * @tparam Get Types of storage _observed_ by the group. - * @tparam Exclude Types of storage used to filter the group. - */ -template, typename Exclude = exclude_t<>> -using group = basic_group, type_list_transform_t, type_list_transform_t>; +#include "../config/module.h" + +#ifndef ENTT_MODULE +# include "../config/config.h" +# include "../core/concepts.hpp" +# include "../core/fwd.hpp" +# include "../core/type_traits.hpp" +# include "../stl/cstdint.hpp" +# include "../stl/memory.hpp" +# include "../stl/type_traits.hpp" +#endif // ENTT_MODULE + +ENTT_MODULE_EXPORT namespace entt { + /*! @brief Default entity identifier. */ + enum class entity : id_type {}; + + /*! @brief Storage deletion policy. */ + enum class deletion_policy : stl::uint8_t { + /*! @brief Swap-and-pop deletion policy. */ + swap_and_pop = 0u, + /*! @brief In-place deletion policy. */ + in_place = 1u, + /*! @brief Swap-only deletion policy. */ + swap_only = 2u, + /*! @brief Unspecified deletion policy. */ + unspecified = swap_and_pop + }; + + template + struct component_traits; + + template> + class basic_sparse_set; + + template> + class basic_storage; + + template + class basic_sigh_mixin; + + template + class basic_reactive_mixin; + + template> + class basic_registry; + + template + class basic_view; + + template> + class basic_runtime_view; + + template + class basic_group; + + template + class basic_organizer; + + template + class basic_handle; + + template + class basic_snapshot; + + template + class basic_snapshot_loader; + + template + class basic_continuous_loader; + + /*! @brief Alias declaration for the most common use case. */ + using sparse_set = basic_sparse_set<>; + + /** + * @brief Alias declaration for the most common use case. + * @tparam Type Element type. + */ + template + using storage = basic_storage; + + /** + * @brief Alias declaration for the most common use case. + * @tparam Type Underlying storage type. + */ + template + using sigh_mixin = basic_sigh_mixin>; + + /** + * @brief Alias declaration for the most common use case. + * @tparam Type Underlying storage type. + */ + template + using reactive_mixin = basic_reactive_mixin>; + + /*! @brief Alias declaration for the most common use case. */ + using registry = basic_registry<>; + + /*! @brief Alias declaration for the most common use case. */ + using organizer = basic_organizer; + + /*! @brief Alias declaration for the most common use case. */ + using handle = basic_handle; + + /*! @brief Alias declaration for the most common use case. */ + using const_handle = basic_handle; + + /** + * @brief Alias declaration for the most common use case. + * @tparam Args Other template parameters. + */ + template + using handle_view = basic_handle; + + /** + * @brief Alias declaration for the most common use case. + * @tparam Args Other template parameters. + */ + template + using const_handle_view = basic_handle; + + /*! @brief Alias declaration for the most common use case. */ + using snapshot = basic_snapshot; + + /*! @brief Alias declaration for the most common use case. */ + using snapshot_loader = basic_snapshot_loader; + + /*! @brief Alias declaration for the most common use case. */ + using continuous_loader = basic_continuous_loader; + + /*! @brief Alias declaration for the most common use case. */ + using runtime_view = basic_runtime_view; + + /*! @brief Alias declaration for the most common use case. */ + using const_runtime_view = basic_runtime_view; + + /** + * @brief Alias for exclusion lists. + * @tparam Type List of types. + */ + template + struct exclude_t final: type_list { + /*! @brief Default constructor. */ + explicit ENTT_CONSTEVAL exclude_t() = default; + }; + + /** + * @brief Variable template for exclusion lists. + * @tparam Type List of types. + */ + template + inline constexpr exclude_t exclude{}; + + /** + * @brief Alias for lists of observed elements. + * @tparam Type List of types. + */ + template + struct get_t final: type_list { + /*! @brief Default constructor. */ + explicit ENTT_CONSTEVAL get_t() = default; + }; + + /** + * @brief Variable template for lists of observed elements. + * @tparam Type List of types. + */ + template + inline constexpr get_t get{}; + + /** + * @brief Alias for lists of owned elements. + * @tparam Type List of types. + */ + template + struct owned_t final: type_list { + /*! @brief Default constructor. */ + explicit ENTT_CONSTEVAL owned_t() = default; + }; + + /** + * @brief Variable template for lists of owned elements. + * @tparam Type List of types. + */ + template + inline constexpr owned_t owned{}; + + /** + * @brief Applies a given _function_ to a get list and generate a new list. + * @tparam Type Types provided by the get list. + * @tparam Op Unary operation as template class with a type member named `type`. + */ + template class Op> + struct type_list_transform, Op> { + /*! @brief Resulting get list after applying the transform function. */ + using type = get_t::type...>; + }; + + /** + * @brief Applies a given _function_ to an exclude list and generate a new list. + * @tparam Type Types provided by the exclude list. + * @tparam Op Unary operation as template class with a type member named `type`. + */ + template class Op> + struct type_list_transform, Op> { + /*! @brief Resulting exclude list after applying the transform function. */ + using type = exclude_t::type...>; + }; + + /** + * @brief Applies a given _function_ to an owned list and generate a new list. + * @tparam Type Types provided by the owned list. + * @tparam Op Unary operation as template class with a type member named `type`. + */ + template class Op> + struct type_list_transform, Op> { + /*! @brief Resulting owned list after applying the transform function. */ + using type = owned_t::type...>; + }; + + /** + * @brief Provides a common way to define storage types. + * @tparam Type Storage value type. + * @tparam Entity A valid entity type. + * @tparam Allocator Type of allocator used to manage memory and elements. + */ + template> + struct storage_type { + /*! @brief Type-to-storage conversion result. */ + using type = ENTT_STORAGE(sigh_mixin, basic_storage); + }; + + /*! @brief Empty value type for reactive storage types. */ + struct reactive final {}; + + /** + * @ brief Partial specialization for reactive storage types. + * @tparam Entity A valid entity type. + * @tparam Allocator Type of allocator used to manage memory and elements. + */ + template + struct storage_type { + /*! @brief Type-to-storage conversion result. */ + using type = ENTT_STORAGE(reactive_mixin, basic_storage); + }; + + /** + * @brief Helper type. + * @tparam Args Arguments to forward. + */ + template + using storage_type_t = storage_type::type; + + /** + * Type-to-storage conversion utility that preserves constness. + * @tparam Type Storage value type, eventually const. + * @tparam Entity A valid entity type. + * @tparam Allocator Type of allocator used to manage memory and elements. + */ + template>> + struct storage_for { + /*! @brief Type-to-storage conversion result. */ + using type = constness_as_t, Entity, Allocator>, Type>; + }; + + /** + * @brief Helper type. + * @tparam Args Arguments to forward. + */ + template + using storage_for_t = storage_for::type; + + /** + * @brief Alias declaration for the most common use case. + * @tparam Get Types of storage iterated by the view. + * @tparam Exclude Types of storage used to filter the view. + */ + template> + using view = basic_view, type_list_transform_t>; + + /** + * @brief Alias declaration for the most common use case. + * @tparam Owned Types of storage _owned_ by the group. + * @tparam Get Types of storage _observed_ by the group. + * @tparam Exclude Types of storage used to filter the group. + */ + template, typename Exclude = exclude_t<>> + using group = basic_group, type_list_transform_t, type_list_transform_t>; } // namespace entt diff --git a/src/entt/entity/group.hpp b/src/entt/entity/group.hpp index dcb1714971..2ede997f6c 100644 --- a/src/entt/entity/group.hpp +++ b/src/entt/entity/group.hpp @@ -1,21 +1,25 @@ #ifndef ENTT_ENTITY_GROUP_HPP #define ENTT_ENTITY_GROUP_HPP -#include "../config/config.h" -#include "../core/algorithm.hpp" -#include "../core/fwd.hpp" -#include "../core/iterator.hpp" -#include "../core/type_info.hpp" -#include "../core/type_traits.hpp" -#include "../stl/array.hpp" -#include "../stl/concepts.hpp" -#include "../stl/cstddef.hpp" -#include "../stl/iterator.hpp" -#include "../stl/tuple.hpp" -#include "../stl/type_traits.hpp" -#include "../stl/utility.hpp" -#include "entity.hpp" -#include "fwd.hpp" +#include "../config/module.h" + +#ifndef ENTT_MODULE +# include "../config/config.h" +# include "../core/algorithm.hpp" +# include "../core/fwd.hpp" +# include "../core/iterator.hpp" +# include "../core/type_info.hpp" +# include "../core/type_traits.hpp" +# include "../stl/array.hpp" +# include "../stl/concepts.hpp" +# include "../stl/cstddef.hpp" +# include "../stl/iterator.hpp" +# include "../stl/tuple.hpp" +# include "../stl/type_traits.hpp" +# include "../stl/utility.hpp" +# include "entity.hpp" +# include "fwd.hpp" +#endif // ENTT_MODULE namespace entt { @@ -240,6 +244,8 @@ class group_handler final: public group_descriptor { } // namespace internal /*! @endcond */ +ENTT_MODULE_EXPORT_BEGIN + /** * @brief Group. * @@ -1047,6 +1053,8 @@ class basic_group, get_t, exclude_t> { handler *descriptor; }; +ENTT_MODULE_EXPORT_END + } // namespace entt #endif diff --git a/src/entt/entity/handle.hpp b/src/entt/entity/handle.hpp index a14016f654..453b1c565c 100644 --- a/src/entt/entity/handle.hpp +++ b/src/entt/entity/handle.hpp @@ -1,15 +1,19 @@ #ifndef ENTT_ENTITY_HANDLE_HPP #define ENTT_ENTITY_HANDLE_HPP -#include "../config/config.h" -#include "../core/iterator.hpp" -#include "../core/type_traits.hpp" -#include "../stl/iterator.hpp" -#include "../stl/tuple.hpp" -#include "../stl/type_traits.hpp" -#include "../stl/utility.hpp" -#include "entity.hpp" -#include "fwd.hpp" +#include "../config/module.h" + +#ifndef ENTT_MODULE +# include "../config/config.h" +# include "../core/iterator.hpp" +# include "../core/type_traits.hpp" +# include "../stl/iterator.hpp" +# include "../stl/tuple.hpp" +# include "../stl/type_traits.hpp" +# include "../stl/utility.hpp" +# include "entity.hpp" +# include "fwd.hpp" +#endif // ENTT_MODULE namespace entt { @@ -78,6 +82,8 @@ class handle_storage_iterator final { } // namespace internal /*! @endcond */ +ENTT_MODULE_EXPORT_BEGIN + /** * @brief Non-owning handle to an entity. * @@ -363,6 +369,8 @@ class basic_handle { entity_type entt; }; +ENTT_MODULE_EXPORT_END + } // namespace entt #endif diff --git a/src/entt/entity/helper.hpp b/src/entt/entity/helper.hpp index 3a89c2ff72..015023d595 100644 --- a/src/entt/entity/helper.hpp +++ b/src/entt/entity/helper.hpp @@ -1,255 +1,258 @@ #ifndef ENTT_ENTITY_HELPER_HPP #define ENTT_ENTITY_HELPER_HPP -#include "../core/fwd.hpp" -#include "../core/type_traits.hpp" -#include "../stl/memory.hpp" -#include "../stl/type_traits.hpp" -#include "../stl/utility.hpp" -#include "component.hpp" -#include "fwd.hpp" -#include "group.hpp" -#include "storage.hpp" -#include "view.hpp" +#include "../config/module.h" -namespace entt { - -/** - * @brief Converts a registry to a view. - * @tparam Registry Basic registry type. - */ -template -class as_view { - template - [[nodiscard]] auto dispatch(get_t, exclude_t) const { - return reg->template view...>(exclude_t...>{}); - } - -public: - /*! @brief Type of registry to convert. */ - using registry_type = Registry; - /*! @brief Underlying entity identifier. */ - using entity_type = registry_type::entity_type; +#ifndef ENTT_MODULE +# include "../core/fwd.hpp" +# include "../core/type_traits.hpp" +# include "../stl/memory.hpp" +# include "../stl/type_traits.hpp" +# include "../stl/utility.hpp" +# include "component.hpp" +# include "fwd.hpp" +# include "group.hpp" +# include "storage.hpp" +# include "view.hpp" +#endif // ENTT_MODULE +ENTT_MODULE_EXPORT namespace entt { /** - * @brief Constructs a converter for a given registry. - * @param source A valid reference to a registry. + * @brief Converts a registry to a view. + * @tparam Registry Basic registry type. */ - as_view(registry_type &source) noexcept - : reg{&source} {} + template + class as_view { + template + [[nodiscard]] auto dispatch(get_t, exclude_t) const { + return reg->template view...>(exclude_t...>{}); + } - /** - * @brief Conversion function from a registry to a view. - * @tparam Get Type of storage used to construct the view. - * @tparam Exclude Types of storage used to filter the view. - * @return A newly created view. - */ - template - operator basic_view() const { - return dispatch(Get{}, Exclude{}); - } + public: + /*! @brief Type of registry to convert. */ + using registry_type = Registry; + /*! @brief Underlying entity identifier. */ + using entity_type = registry_type::entity_type; -private: - registry_type *reg; -}; + /** + * @brief Constructs a converter for a given registry. + * @param source A valid reference to a registry. + */ + as_view(registry_type &source) noexcept + : reg{&source} {} -/** - * @brief Converts a registry to a group. - * @tparam Registry Basic registry type. - */ -template -class as_group { - template - [[nodiscard]] auto dispatch(owned_t, get_t, exclude_t) const { - if constexpr(stl::is_const_v) { - return reg->template group_if_exists(get_t{}, exclude_t{}); - } else { - return reg->template group...>(get_t...>{}, exclude_t...>{}); + /** + * @brief Conversion function from a registry to a view. + * @tparam Get Type of storage used to construct the view. + * @tparam Exclude Types of storage used to filter the view. + * @return A newly created view. + */ + template + operator basic_view() const { + return dispatch(Get{}, Exclude{}); } - } - -public: - /*! @brief Type of registry to convert. */ - using registry_type = Registry; - /*! @brief Underlying entity identifier. */ - using entity_type = registry_type::entity_type; - /** - * @brief Constructs a converter for a given registry. - * @param source A valid reference to a registry. - */ - as_group(registry_type &source) noexcept - : reg{&source} {} + private: + registry_type *reg; + }; /** - * @brief Conversion function from a registry to a group. - * @tparam Owned Types of _owned_ by the group. - * @tparam Get Types of storage _observed_ by the group. - * @tparam Exclude Types of storage used to filter the group. - * @return A newly created group. + * @brief Converts a registry to a group. + * @tparam Registry Basic registry type. */ - template - operator basic_group() const { - return dispatch(Owned{}, Get{}, Exclude{}); - } - -private: - registry_type *reg; -}; + template + class as_group { + template + [[nodiscard]] auto dispatch(owned_t, get_t, exclude_t) const { + if constexpr(stl::is_const_v) { + return reg->template group_if_exists(get_t{}, exclude_t{}); + } else { + return reg->template group...>(get_t...>{}, exclude_t...>{}); + } + } -/** - * @brief Helper to create a listener that directly invokes a member function. - * @tparam Member Member function to invoke on an element of the given type. - * @tparam Registry Basic registry type. - * @param reg A registry that contains the given entity and its elements. - * @param entt Entity from which to get the element. - */ -template>> -void invoke(Registry ®, const typename Registry::entity_type entt) { - static_assert(stl::is_member_function_pointer_v, "Invalid pointer to non-static member function"); - (reg.template get>(entt).*Member)(reg, entt); -} + public: + /*! @brief Type of registry to convert. */ + using registry_type = Registry; + /*! @brief Underlying entity identifier. */ + using entity_type = registry_type::entity_type; -/** - * @brief Returns the entity associated with a given element. - * - * @warning - * Currently, this function only works correctly with the default storage as it - * makes assumptions about how the elements are laid out. - * - * @tparam Args Storage type template parameters. - * @param storage A storage that contains the given element. - * @param instance A valid element instance. - * @return The entity associated with the given element. - */ -template -basic_storage::entity_type to_entity(const basic_storage &storage, const typename basic_storage::value_type &instance) { - using traits_type = component_traits::value_type, typename basic_storage::entity_type>; - static_assert(traits_type::page_size != 0u, "Unexpected page size"); - const auto *page = storage.raw(); + /** + * @brief Constructs a converter for a given registry. + * @param source A valid reference to a registry. + */ + as_group(registry_type &source) noexcept + : reg{&source} {} - // NOLINTBEGIN(cppcoreguidelines-pro-bounds-pointer-arithmetic) - for(stl::size_t pos{}, count = storage.size(); pos < count; pos += traits_type::page_size, ++page) { - if(const auto dist = (stl::addressof(instance) - *page); dist >= 0 && dist < static_cast(traits_type::page_size)) { - return *(static_cast::base_type &>(storage).rbegin() + static_cast(pos) + dist); + /** + * @brief Conversion function from a registry to a group. + * @tparam Owned Types of _owned_ by the group. + * @tparam Get Types of storage _observed_ by the group. + * @tparam Exclude Types of storage used to filter the group. + * @return A newly created group. + */ + template + operator basic_group() const { + return dispatch(Owned{}, Get{}, Exclude{}); } - } - // NOLINTEND(cppcoreguidelines-pro-bounds-pointer-arithmetic) - - return null; -} -/*! @brief Primary template isn't defined on purpose. */ -template -struct sigh_helper; - -/** - * @brief Signal connection helper for registries. - * @tparam Registry Basic registry type. - */ -template -struct sigh_helper { - /*! @brief Registry type. */ - using registry_type = Registry; + private: + registry_type *reg; + }; /** - * @brief Constructs a helper for a given registry. - * @param ref A valid reference to a registry. + * @brief Helper to create a listener that directly invokes a member function. + * @tparam Member Member function to invoke on an element of the given type. + * @tparam Registry Basic registry type. + * @param reg A registry that contains the given entity and its elements. + * @param entt Entity from which to get the element. */ - sigh_helper(registry_type &ref) - : bucket{&ref} {} + template>> + void invoke(Registry & reg, const typename Registry::entity_type entt) { + static_assert(stl::is_member_function_pointer_v, "Invalid pointer to non-static member function"); + (reg.template get>(entt).*Member)(reg, entt); + } /** - * @brief Binds a properly initialized helper to a given signal type. - * @tparam Type Type of signal to bind the helper to. - * @param id Optional name for the underlying storage to use. - * @return A helper for a given registry and signal type. + * @brief Returns the entity associated with a given element. + * + * @warning + * Currently, this function only works correctly with the default storage as it + * makes assumptions about how the elements are laid out. + * + * @tparam Args Storage type template parameters. + * @param storage A storage that contains the given element. + * @param instance A valid element instance. + * @return The entity associated with the given element. */ - template - auto with(const id_type id = type_hash::value()) noexcept { - return sigh_helper{*bucket, id}; + template + basic_storage::entity_type to_entity(const basic_storage &storage, const typename basic_storage::value_type &instance) { + using traits_type = component_traits::value_type, typename basic_storage::entity_type>; + static_assert(traits_type::page_size != 0u, "Unexpected page size"); + const auto *page = storage.raw(); + + // NOLINTBEGIN(cppcoreguidelines-pro-bounds-pointer-arithmetic) + for(stl::size_t pos{}, count = storage.size(); pos < count; pos += traits_type::page_size, ++page) { + if(const auto dist = (stl::addressof(instance) - *page); dist >= 0 && dist < static_cast(traits_type::page_size)) { + return *(static_cast::base_type &>(storage).rbegin() + static_cast(pos) + dist); + } + } + // NOLINTEND(cppcoreguidelines-pro-bounds-pointer-arithmetic) + + return null; } + /*! @brief Primary template isn't defined on purpose. */ + template + struct sigh_helper; + /** - * @brief Returns a reference to the underlying registry. - * @return A reference to the underlying registry. + * @brief Signal connection helper for registries. + * @tparam Registry Basic registry type. */ - [[nodiscard]] registry_type ®istry() noexcept { - return *bucket; - } + template + struct sigh_helper { + /*! @brief Registry type. */ + using registry_type = Registry; -private: - registry_type *bucket; -}; + /** + * @brief Constructs a helper for a given registry. + * @param ref A valid reference to a registry. + */ + sigh_helper(registry_type &ref) + : bucket{&ref} {} -/** - * @brief Signal connection helper for registries. - * @tparam Registry Basic registry type. - * @tparam Type Type of signal to connect listeners to. - */ -template -struct sigh_helper final: sigh_helper { - /*! @brief Registry type. */ - using registry_type = Registry; + /** + * @brief Binds a properly initialized helper to a given signal type. + * @tparam Type Type of signal to bind the helper to. + * @param id Optional name for the underlying storage to use. + * @return A helper for a given registry and signal type. + */ + template + auto with(const id_type id = type_hash::value()) noexcept { + return sigh_helper{*bucket, id}; + } - /** - * @brief Constructs a helper for a given registry. - * @param ref A valid reference to a registry. - * @param id Optional name for the underlying storage to use. - */ - sigh_helper(registry_type &ref, const id_type id = type_hash::value()) - : sigh_helper{ref}, - name{id} {} + /** + * @brief Returns a reference to the underlying registry. + * @return A reference to the underlying registry. + */ + [[nodiscard]] registry_type ®istry() noexcept { + return *bucket; + } - /** - * @brief Forwards the call to `on_construct` on the underlying storage. - * @tparam Candidate Function or member to connect. - * @tparam Args Type of class or type of payload, if any. - * @param args A valid object that fits the purpose, if any. - * @return This helper. - */ - template - auto on_construct(Args &&...args) { - this->registry().template on_construct(name).template connect(stl::forward(args)...); - return *this; - } + private: + registry_type *bucket; + }; /** - * @brief Forwards the call to `on_update` on the underlying storage. - * @tparam Candidate Function or member to connect. - * @tparam Args Type of class or type of payload, if any. - * @param args A valid object that fits the purpose, if any. - * @return This helper. + * @brief Signal connection helper for registries. + * @tparam Registry Basic registry type. + * @tparam Type Type of signal to connect listeners to. */ - template - auto on_update(Args &&...args) { - this->registry().template on_update(name).template connect(stl::forward(args)...); - return *this; - } + template + struct sigh_helper final: sigh_helper { + /*! @brief Registry type. */ + using registry_type = Registry; - /** - * @brief Forwards the call to `on_destroy` on the underlying storage. - * @tparam Candidate Function or member to connect. - * @tparam Args Type of class or type of payload, if any. - * @param args A valid object that fits the purpose, if any. - * @return This helper. - */ - template - auto on_destroy(Args &&...args) { - this->registry().template on_destroy(name).template connect(stl::forward(args)...); - return *this; - } + /** + * @brief Constructs a helper for a given registry. + * @param ref A valid reference to a registry. + * @param id Optional name for the underlying storage to use. + */ + sigh_helper(registry_type &ref, const id_type id = type_hash::value()) + : sigh_helper{ref}, + name{id} {} + + /** + * @brief Forwards the call to `on_construct` on the underlying storage. + * @tparam Candidate Function or member to connect. + * @tparam Args Type of class or type of payload, if any. + * @param args A valid object that fits the purpose, if any. + * @return This helper. + */ + template + auto on_construct(Args &&...args) { + this->registry().template on_construct(name).template connect(stl::forward(args)...); + return *this; + } + + /** + * @brief Forwards the call to `on_update` on the underlying storage. + * @tparam Candidate Function or member to connect. + * @tparam Args Type of class or type of payload, if any. + * @param args A valid object that fits the purpose, if any. + * @return This helper. + */ + template + auto on_update(Args &&...args) { + this->registry().template on_update(name).template connect(stl::forward(args)...); + return *this; + } + + /** + * @brief Forwards the call to `on_destroy` on the underlying storage. + * @tparam Candidate Function or member to connect. + * @tparam Args Type of class or type of payload, if any. + * @param args A valid object that fits the purpose, if any. + * @return This helper. + */ + template + auto on_destroy(Args &&...args) { + this->registry().template on_destroy(name).template connect(stl::forward(args)...); + return *this; + } -private: - id_type name; -}; + private: + id_type name; + }; -/** - * @brief Deduction guide. - * @tparam Registry Basic registry type. - */ -template -sigh_helper(Registry &) -> sigh_helper; + /** + * @brief Deduction guide. + * @tparam Registry Basic registry type. + */ + template + sigh_helper(Registry &) -> sigh_helper; } // namespace entt diff --git a/src/entt/entity/mixin.hpp b/src/entt/entity/mixin.hpp index d5a15b9be9..237d7bf3ba 100644 --- a/src/entt/entity/mixin.hpp +++ b/src/entt/entity/mixin.hpp @@ -1,17 +1,21 @@ #ifndef ENTT_ENTITY_MIXIN_HPP #define ENTT_ENTITY_MIXIN_HPP -#include "../config/config.h" -#include "../core/any.hpp" -#include "../core/type_info.hpp" -#include "../signal/sigh.hpp" -#include "../stl/concepts.hpp" -#include "../stl/iterator.hpp" -#include "../stl/type_traits.hpp" -#include "../stl/utility.hpp" -#include "../stl/vector.hpp" -#include "entity.hpp" -#include "fwd.hpp" +#include "../config/module.h" + +#ifndef ENTT_MODULE +# include "../config/config.h" +# include "../core/any.hpp" +# include "../core/type_info.hpp" +# include "../signal/sigh.hpp" +# include "../stl/concepts.hpp" +# include "../stl/iterator.hpp" +# include "../stl/type_traits.hpp" +# include "../stl/utility.hpp" +# include "../stl/vector.hpp" +# include "entity.hpp" +# include "fwd.hpp" +#endif // ENTT_MODULE namespace entt { @@ -42,6 +46,8 @@ struct has_on_destroy: stl::true_type {}; } // namespace internal /*! @endcond */ +ENTT_MODULE_EXPORT_BEGIN + /** * @brief Mixin type used to add signal support to storage types. * @@ -588,6 +594,8 @@ class basic_reactive_mixin final: public Type { container_type conn; }; +ENTT_MODULE_EXPORT_END + } // namespace entt #endif diff --git a/src/entt/entity/organizer.hpp b/src/entt/entity/organizer.hpp index 711d4b4e2a..c7dc73ed1c 100644 --- a/src/entt/entity/organizer.hpp +++ b/src/entt/entity/organizer.hpp @@ -1,17 +1,21 @@ #ifndef ENTT_ENTITY_ORGANIZER_HPP #define ENTT_ENTITY_ORGANIZER_HPP -#include "../core/type_info.hpp" -#include "../core/type_traits.hpp" -#include "../core/utility.hpp" -#include "../graph/adjacency_matrix.hpp" -#include "../graph/flow.hpp" -#include "../stl/cstddef.hpp" -#include "../stl/type_traits.hpp" -#include "../stl/utility.hpp" -#include "../stl/vector.hpp" -#include "fwd.hpp" -#include "helper.hpp" +#include "../config/module.h" + +#ifndef ENTT_MODULE +# include "../core/type_info.hpp" +# include "../core/type_traits.hpp" +# include "../core/utility.hpp" +# include "../graph/adjacency_matrix.hpp" +# include "../graph/flow.hpp" +# include "../stl/cstddef.hpp" +# include "../stl/type_traits.hpp" +# include "../stl/utility.hpp" +# include "../stl/vector.hpp" +# include "fwd.hpp" +# include "helper.hpp" +#endif // ENTT_MODULE namespace entt { @@ -105,6 +109,8 @@ resource_traits...>, type_list } // namespace internal /*! @endcond */ +ENTT_MODULE_EXPORT_BEGIN + /** * @brief Utility class for creating a static task graph. * @@ -432,6 +438,8 @@ class basic_organizer final { flow builder; }; +ENTT_MODULE_EXPORT_END + } // namespace entt #endif diff --git a/src/entt/entity/ranges.hpp b/src/entt/entity/ranges.hpp index 284e5f5fde..08747399f7 100644 --- a/src/entt/entity/ranges.hpp +++ b/src/entt/entity/ranges.hpp @@ -1,12 +1,20 @@ #ifndef ENTT_ENTITY_RANGES_HPP #define ENTT_ENTITY_RANGES_HPP -#include +#include "../config/module.h" -#if defined(__cpp_lib_ranges) -# include -# include "fwd.hpp" +#if __has_include() +# ifndef ENTT_MODULE +# include +# endif // ENTT_MODULE +# if defined(__cpp_lib_ranges) +# ifndef ENTT_MODULE +# include +# include "fwd.hpp" +# endif // ENTT_MODULE + +ENTT_MODULE_EXPORT_BEGIN namespace std::ranges { template @@ -22,7 +30,9 @@ template inline constexpr bool enable_view>{true}; } // namespace std::ranges +ENTT_MODULE_EXPORT_END -#endif +# endif // defined(__cpp_lib_ranges) +#endif // __has_include() -#endif +#endif // ENTT_ENTITY_RANGES_HPP diff --git a/src/entt/entity/registry.hpp b/src/entt/entity/registry.hpp index 4123b5c52d..ebfe7b65a2 100644 --- a/src/entt/entity/registry.hpp +++ b/src/entt/entity/registry.hpp @@ -1,6 +1,9 @@ #ifndef ENTT_ENTITY_REGISTRY_HPP #define ENTT_ENTITY_REGISTRY_HPP +#include "../config/module.h" + +#ifndef ENTT_MODULE #include #include "../config/config.h" #include "../container/dense_map.hpp" @@ -29,6 +32,7 @@ #include "sparse_set.hpp" #include "storage.hpp" #include "view.hpp" +#endif // ENTT_MODULE namespace entt { @@ -202,6 +206,8 @@ class registry_context { } // namespace internal /*! @endcond */ +ENTT_MODULE_EXPORT_BEGIN + /** * @brief Fast and reliable entity-component system. * @tparam Entity A valid entity type. @@ -1176,6 +1182,8 @@ class basic_registry { storage_for_type entities; }; +ENTT_MODULE_EXPORT_END + } // namespace entt #endif diff --git a/src/entt/entity/runtime_view.hpp b/src/entt/entity/runtime_view.hpp index 1c69c8d10f..7ebe4b97df 100644 --- a/src/entt/entity/runtime_view.hpp +++ b/src/entt/entity/runtime_view.hpp @@ -1,13 +1,17 @@ #ifndef ENTT_ENTITY_RUNTIME_VIEW_HPP #define ENTT_ENTITY_RUNTIME_VIEW_HPP -#include "../stl/algorithm.hpp" -#include "../stl/cstddef.hpp" -#include "../stl/iterator.hpp" -#include "../stl/utility.hpp" -#include "../stl/vector.hpp" -#include "entity.hpp" -#include "fwd.hpp" +#include "../config/module.h" + +#ifndef ENTT_MODULE +# include "../stl/algorithm.hpp" +# include "../stl/cstddef.hpp" +# include "../stl/iterator.hpp" +# include "../stl/utility.hpp" +# include "../stl/vector.hpp" +# include "entity.hpp" +# include "fwd.hpp" +#endif // ENTT_MODULE namespace entt { @@ -92,6 +96,8 @@ class runtime_view_iterator final { } // namespace internal /*! @endcond */ +ENTT_MODULE_EXPORT_BEGIN + /** * @brief Generic runtime view. * @@ -317,6 +323,8 @@ class basic_runtime_view { container_type filter; }; +ENTT_MODULE_EXPORT_END + } // namespace entt #endif diff --git a/src/entt/entity/snapshot.hpp b/src/entt/entity/snapshot.hpp index fd14b260c7..600d23a7dd 100644 --- a/src/entt/entity/snapshot.hpp +++ b/src/entt/entity/snapshot.hpp @@ -1,6 +1,9 @@ #ifndef ENTT_ENTITY_SNAPSHOT_HPP #define ENTT_ENTITY_SNAPSHOT_HPP +#include "../config/module.h" + +#ifndef ENTT_MODULE #include "../config/config.h" #include "../container/dense_map.hpp" #include "../core/type_traits.hpp" @@ -13,6 +16,7 @@ #include "entity.hpp" #include "fwd.hpp" #include "view.hpp" +#endif // ENTT_MODULE namespace entt { @@ -31,6 +35,8 @@ void orphans(Registry ®istry) { } // namespace internal /*! @endcond */ +ENTT_MODULE_EXPORT_BEGIN + /** * @brief Utility class to create snapshots from a registry. * @@ -504,6 +510,8 @@ class basic_continuous_loader { registry_type *reg; }; +ENTT_MODULE_EXPORT_END + } // namespace entt #endif diff --git a/src/entt/entity/sparse_set.hpp b/src/entt/entity/sparse_set.hpp index 39540e3a29..92e5ca49c4 100644 --- a/src/entt/entity/sparse_set.hpp +++ b/src/entt/entity/sparse_set.hpp @@ -1,6 +1,9 @@ #ifndef ENTT_ENTITY_SPARSE_SET_HPP #define ENTT_ENTITY_SPARSE_SET_HPP +#include "../config/module.h" + +#ifndef ENTT_MODULE #include #include "../config/config.h" #include "../core/algorithm.hpp" @@ -16,6 +19,7 @@ #include "../stl/vector.hpp" #include "entity.hpp" #include "fwd.hpp" +#endif // ENTT_MODULE namespace entt { @@ -116,6 +120,8 @@ struct sparse_set_iterator final { } // namespace internal /*! @endcond */ +ENTT_MODULE_EXPORT_BEGIN + /** * @brief Sparse set implementation. * @@ -1071,6 +1077,8 @@ class basic_sparse_set { size_type head; }; +ENTT_MODULE_EXPORT_END + } // namespace entt #endif diff --git a/src/entt/entity/storage.hpp b/src/entt/entity/storage.hpp index d12bf7d275..95a3430138 100644 --- a/src/entt/entity/storage.hpp +++ b/src/entt/entity/storage.hpp @@ -1,24 +1,28 @@ #ifndef ENTT_ENTITY_STORAGE_HPP #define ENTT_ENTITY_STORAGE_HPP -#include -#include "../config/config.h" -#include "../core/bit.hpp" -#include "../core/iterator.hpp" -#include "../core/memory.hpp" -#include "../core/type_info.hpp" -#include "../stl/concepts.hpp" -#include "../stl/cstddef.hpp" -#include "../stl/iterator.hpp" -#include "../stl/memory.hpp" -#include "../stl/tuple.hpp" -#include "../stl/type_traits.hpp" -#include "../stl/utility.hpp" -#include "../stl/vector.hpp" -#include "component.hpp" -#include "entity.hpp" -#include "fwd.hpp" -#include "sparse_set.hpp" +#include "../config/module.h" + +#ifndef ENTT_MODULE +# include +# include "../config/config.h" +# include "../core/bit.hpp" +# include "../core/iterator.hpp" +# include "../core/memory.hpp" +# include "../core/type_info.hpp" +# include "../stl/concepts.hpp" +# include "../stl/cstddef.hpp" +# include "../stl/iterator.hpp" +# include "../stl/memory.hpp" +# include "../stl/tuple.hpp" +# include "../stl/type_traits.hpp" +# include "../stl/utility.hpp" +# include "../stl/vector.hpp" +# include "component.hpp" +# include "entity.hpp" +# include "fwd.hpp" +# include "sparse_set.hpp" +#endif // ENTT_MODULE namespace entt { @@ -189,6 +193,8 @@ class extended_storage_iterator final { } // namespace internal /*! @endcond */ +ENTT_MODULE_EXPORT_BEGIN + /** * @brief Storage implementation. * @@ -1217,6 +1223,8 @@ class basic_storage size_type placeholder{}; }; +ENTT_MODULE_EXPORT_END + } // namespace entt #endif diff --git a/src/entt/entity/view.hpp b/src/entt/entity/view.hpp index feb54c404f..4a01588d32 100644 --- a/src/entt/entity/view.hpp +++ b/src/entt/entity/view.hpp @@ -1,19 +1,23 @@ #ifndef ENTT_ENTITY_VIEW_HPP #define ENTT_ENTITY_VIEW_HPP -#include "../config/config.h" -#include "../core/concepts.hpp" -#include "../core/iterator.hpp" -#include "../core/type_traits.hpp" -#include "../stl/array.hpp" -#include "../stl/concepts.hpp" -#include "../stl/cstddef.hpp" -#include "../stl/iterator.hpp" -#include "../stl/tuple.hpp" -#include "../stl/type_traits.hpp" -#include "../stl/utility.hpp" -#include "entity.hpp" -#include "fwd.hpp" +#include "../config/module.h" + +#ifndef ENTT_MODULE +# include "../config/config.h" +# include "../core/concepts.hpp" +# include "../core/iterator.hpp" +# include "../core/type_traits.hpp" +# include "../stl/array.hpp" +# include "../stl/concepts.hpp" +# include "../stl/cstddef.hpp" +# include "../stl/iterator.hpp" +# include "../stl/tuple.hpp" +# include "../stl/type_traits.hpp" +# include "../stl/utility.hpp" +# include "entity.hpp" +# include "fwd.hpp" +#endif // ENTT_MODULE namespace entt { @@ -22,7 +26,7 @@ namespace internal { template // NOLINTNEXTLINE(misc-redundant-expression) -static constexpr bool tombstone_check_v = ((sizeof...(Type) == 1u) && ... && (Type::storage_policy == deletion_policy::in_place)); +inline constexpr bool tombstone_check_v = ((sizeof...(Type) == 1u) && ... && (Type::storage_policy == deletion_policy::in_place)); template const Type *view_placeholder() { @@ -179,6 +183,8 @@ struct extended_view_iterator final { } // namespace internal /*! @endcond */ +ENTT_MODULE_EXPORT_BEGIN + /** * @brief View implementation. * @@ -1137,6 +1143,8 @@ basic_view(Type &...storage) -> basic_view, exclude_t<>>; template basic_view(stl::tuple, stl::tuple = {}) -> basic_view, exclude_t>; +ENTT_MODULE_EXPORT_END + } // namespace entt #endif diff --git a/src/entt/entt.ixx b/src/entt/entt.ixx new file mode 100644 index 0000000000..fec60f5116 --- /dev/null +++ b/src/entt/entt.ixx @@ -0,0 +1,109 @@ +module; + +#define ENTT_MODULE +#define ENTT_MODULE_EXPORT export +#define ENTT_MODULE_EXPORT_BEGIN export { +#define ENTT_MODULE_EXPORT_END } + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef ENTT_USER_CONFIG +# include ENTT_USER_CONFIG +#endif // ENTT_USER_CONFIG + +#include "config/config.h" +#include "config/macro.h" +#include "config/version.h" +#include "core/attribute.h" + +export module entt; + +#include "core/fwd.hpp" +#include "core/utility.hpp" +#include "core/algorithm.hpp" +#include "core/hashed_string.hpp" +#include "core/type_info.hpp" +#include "core/type_traits.hpp" +#include "core/any.hpp" +#include "core/bit.hpp" +#include "core/compressed_pair.hpp" +#include "core/enum.hpp" +#include "core/family.hpp" +#include "core/ident.hpp" +#include "core/iterator.hpp" +#include "core/memory.hpp" +#include "core/monostate.hpp" +#include "core/ranges.hpp" +#include "core/tuple.hpp" + +#include "container/fwd.hpp" +#include "container/dense_map.hpp" +#include "container/dense_set.hpp" +#include "container/table.hpp" + +#include "signal/fwd.hpp" +#include "signal/delegate.hpp" +#include "signal/dispatcher.hpp" +#include "signal/emitter.hpp" +#include "signal/sigh.hpp" + +#include "graph/fwd.hpp" +#include "graph/adjacency_matrix.hpp" +#include "graph/dot.hpp" +#include "graph/flow.hpp" + +#include "entity/fwd.hpp" +#include "entity/component.hpp" +#include "entity/entity.hpp" +#include "entity/group.hpp" +#include "entity/handle.hpp" +#include "entity/helper.hpp" +#include "entity/mixin.hpp" +#include "entity/organizer.hpp" +#include "entity/ranges.hpp" +#include "entity/registry.hpp" +#include "entity/runtime_view.hpp" +#include "entity/snapshot.hpp" +#include "entity/sparse_set.hpp" +#include "entity/storage.hpp" +#include "entity/view.hpp" + +#include "locator/locator.hpp" + +#include "meta/fwd.hpp" +#include "meta/adl_pointer.hpp" +#include "meta/context.hpp" +#include "meta/type_traits.hpp" +#include "meta/node.hpp" +#include "meta/range.hpp" +#include "meta/meta.hpp" +#include "meta/container.hpp" +#include "meta/resolve.hpp" +#include "meta/policy.hpp" +#include "meta/utility.hpp" +#include "meta/factory.hpp" +#include "meta/pointer.hpp" +#include "meta/template.hpp" + +#include "poly/fwd.hpp" +#include "poly/poly.hpp" + +#include "process/fwd.hpp" +#include "process/process.hpp" +#include "process/scheduler.hpp" + +#include "resource/fwd.hpp" +#include "resource/cache.hpp" +#include "resource/loader.hpp" +#include "resource/resource.hpp" \ No newline at end of file diff --git a/src/entt/graph/adjacency_matrix.hpp b/src/entt/graph/adjacency_matrix.hpp index ba835615d6..a60a2ae224 100644 --- a/src/entt/graph/adjacency_matrix.hpp +++ b/src/entt/graph/adjacency_matrix.hpp @@ -1,16 +1,20 @@ #ifndef ENTT_GRAPH_ADJACENCY_MATRIX_HPP #define ENTT_GRAPH_ADJACENCY_MATRIX_HPP -#include "../config/config.h" -#include "../core/iterator.hpp" -#include "../stl/concepts.hpp" -#include "../stl/cstddef.hpp" -#include "../stl/iterator.hpp" -#include "../stl/memory.hpp" -#include "../stl/type_traits.hpp" -#include "../stl/utility.hpp" -#include "../stl/vector.hpp" -#include "fwd.hpp" +#include "../config/module.h" + +#ifndef ENTT_MODULE +# include "../config/config.h" +# include "../core/iterator.hpp" +# include "../stl/concepts.hpp" +# include "../stl/cstddef.hpp" +# include "../stl/iterator.hpp" +# include "../stl/memory.hpp" +# include "../stl/type_traits.hpp" +# include "../stl/utility.hpp" +# include "../stl/vector.hpp" +# include "fwd.hpp" +#endif // ENTT_MODULE namespace entt { @@ -79,6 +83,8 @@ class edge_iterator { } // namespace internal /*! @endcond */ +ENTT_MODULE_EXPORT_BEGIN + /** * @brief Basic implementation of a directed adjacency matrix. * @tparam Category Either a directed or undirected category tag. @@ -327,6 +333,8 @@ class adjacency_matrix { size_type vert; }; +ENTT_MODULE_EXPORT_END + } // namespace entt #endif diff --git a/src/entt/graph/dot.hpp b/src/entt/graph/dot.hpp index e8d237a691..b7e018f4aa 100644 --- a/src/entt/graph/dot.hpp +++ b/src/entt/graph/dot.hpp @@ -1,55 +1,58 @@ #ifndef ENTT_GRAPH_DOT_HPP #define ENTT_GRAPH_DOT_HPP -#include "../stl/concepts.hpp" -#include "../stl/ostream.hpp" -#include "fwd.hpp" - -namespace entt { - -/** - * @brief Outputs a graph in dot format. - * @tparam Graph Graph type, valid as long as it exposes edges and vertices. - * @param out A standard output stream. - * @param graph The graph to output. - * @param writer Vertex decorator object. - */ -template -requires stl::derived_from -void dot(stl::ostream &out, const Graph &graph, stl::invocable auto writer) { - if constexpr(stl::same_as) { - out << "graph{"; - } else { - out << "digraph{"; - } - - for(auto &&vertex: graph.vertices()) { - out << vertex << "["; - writer(out, vertex); - out << "];"; - } - - for(auto [lhs, rhs]: graph.edges()) { +#include "../config/module.h" + +#ifndef ENTT_MODULE +# include "../stl/concepts.hpp" +# include "../stl/ostream.hpp" +# include "fwd.hpp" +#endif // ENTT_MODULE + +ENTT_MODULE_EXPORT namespace entt { + /** + * @brief Outputs a graph in dot format. + * @tparam Graph Graph type, valid as long as it exposes edges and vertices. + * @param out A standard output stream. + * @param graph The graph to output. + * @param writer Vertex decorator object. + */ + template + requires stl::derived_from + void dot(stl::ostream & out, const Graph &graph, stl::invocable auto writer) { if constexpr(stl::same_as) { - out << lhs << "--" << rhs << ";"; + out << "graph{"; } else { - out << lhs << "->" << rhs << ";"; + out << "digraph{"; + } + + for(auto &&vertex: graph.vertices()) { + out << vertex << "["; + writer(out, vertex); + out << "];"; + } + + for(auto [lhs, rhs]: graph.edges()) { + if constexpr(stl::same_as) { + out << lhs << "--" << rhs << ";"; + } else { + out << lhs << "->" << rhs << ";"; + } } + + out << "}"; } - out << "}"; -} - -/** - * @brief Outputs a graph in dot format. - * @tparam Graph Graph type, valid as long as it exposes edges and vertices. - * @param out A standard output stream. - * @param graph The graph to output. - */ -template -void dot(stl::ostream &out, const Graph &graph) { - return dot(out, graph, [](auto &&...) {}); -} + /** + * @brief Outputs a graph in dot format. + * @tparam Graph Graph type, valid as long as it exposes edges and vertices. + * @param out A standard output stream. + * @param graph The graph to output. + */ + template + void dot(stl::ostream & out, const Graph &graph) { + return dot(out, graph, [](auto &&...) {}); + } } // namespace entt diff --git a/src/entt/graph/flow.hpp b/src/entt/graph/flow.hpp index df4372f574..82c96cecb8 100644 --- a/src/entt/graph/flow.hpp +++ b/src/entt/graph/flow.hpp @@ -1,344 +1,347 @@ #ifndef ENTT_GRAPH_FLOW_HPP #define ENTT_GRAPH_FLOW_HPP -#include "../config/config.h" -#include "../container/dense_map.hpp" -#include "../container/dense_set.hpp" -#include "../core/compressed_pair.hpp" -#include "../core/fwd.hpp" -#include "../core/iterator.hpp" -#include "../stl/algorithm.hpp" -#include "../stl/concepts.hpp" -#include "../stl/cstddef.hpp" -#include "../stl/functional.hpp" -#include "../stl/iterator.hpp" -#include "../stl/memory.hpp" -#include "../stl/type_traits.hpp" -#include "../stl/utility.hpp" -#include "../stl/vector.hpp" -#include "adjacency_matrix.hpp" -#include "fwd.hpp" - -namespace entt { - -/** - * @brief Utility class for creating task graphs. - * @tparam Allocator Type of allocator used to manage memory and elements. - */ -template -class basic_flow { - using alloc_traits = stl::allocator_traits; - static_assert(stl::is_same_v, "Invalid value type"); - using task_container_type = dense_set, typename alloc_traits::template rebind_alloc>; - using ro_rw_container_type = stl::vector, typename alloc_traits::template rebind_alloc>>; - using deps_container_type = dense_map, typename alloc_traits::template rebind_alloc>>; - using adjacency_matrix_type = adjacency_matrix>; - - void emplace(const id_type res, const bool is_rw) { - ENTT_ASSERT(index.first() < vertices.size(), "Invalid node"); - - if(!deps.contains(res) && sync_on != vertices.size()) { - deps[res].emplace_back(sync_on, true); +#include "../config/module.h" + +#ifndef ENTT_MODULE +# include "../config/config.h" +# include "../container/dense_map.hpp" +# include "../container/dense_set.hpp" +# include "../core/compressed_pair.hpp" +# include "../core/fwd.hpp" +# include "../core/iterator.hpp" +# include "../stl/algorithm.hpp" +# include "../stl/concepts.hpp" +# include "../stl/cstddef.hpp" +# include "../stl/functional.hpp" +# include "../stl/iterator.hpp" +# include "../stl/memory.hpp" +# include "../stl/type_traits.hpp" +# include "../stl/utility.hpp" +# include "../stl/vector.hpp" +# include "adjacency_matrix.hpp" +# include "fwd.hpp" +#endif // ENTT_MODULE + +ENTT_MODULE_EXPORT namespace entt { + /** + * @brief Utility class for creating task graphs. + * @tparam Allocator Type of allocator used to manage memory and elements. + */ + template + class basic_flow { + using alloc_traits = stl::allocator_traits; + static_assert(stl::is_same_v, "Invalid value type"); + using task_container_type = dense_set, typename alloc_traits::template rebind_alloc>; + using ro_rw_container_type = stl::vector, typename alloc_traits::template rebind_alloc>>; + using deps_container_type = dense_map, typename alloc_traits::template rebind_alloc>>; + using adjacency_matrix_type = adjacency_matrix>; + + void emplace(const id_type res, const bool is_rw) { + ENTT_ASSERT(index.first() < vertices.size(), "Invalid node"); + + if(!deps.contains(res) && sync_on != vertices.size()) { + deps[res].emplace_back(sync_on, true); + } + + deps[res].emplace_back(index.first(), is_rw); } - deps[res].emplace_back(index.first(), is_rw); - } - - void setup_graph(adjacency_matrix_type &matrix) const { - for(const auto &elem: deps) { - const auto last = elem.second.cend(); - auto it = elem.second.cbegin(); - - while(it != last) { - if(it->second) { - // rw item - if(auto curr = it++; it != last) { - if(it->second) { - matrix.insert(curr->first, it->first); - } else if(const auto next = stl::find_if(it, last, [](const auto &value) { return value.second; }); next != last) { - for(; it != next; ++it) { + void setup_graph(adjacency_matrix_type &matrix) const { + for(const auto &elem: deps) { + const auto last = elem.second.cend(); + auto it = elem.second.cbegin(); + + while(it != last) { + if(it->second) { + // rw item + if(auto curr = it++; it != last) { + if(it->second) { matrix.insert(curr->first, it->first); - matrix.insert(it->first, next->first); + } else if(const auto next = stl::find_if(it, last, [](const auto &value) { return value.second; }); next != last) { + for(; it != next; ++it) { + matrix.insert(curr->first, it->first); + matrix.insert(it->first, next->first); + } + } else { + for(; it != next; ++it) { + matrix.insert(curr->first, it->first); + } } - } else { + } + } else { + // ro item (first iteration only) + if(const auto next = stl::find_if(it, last, [](const auto &value) { return value.second; }); next != last) { for(; it != next; ++it) { - matrix.insert(curr->first, it->first); + matrix.insert(it->first, next->first); } + } else { + it = last; } } - } else { - // ro item (first iteration only) - if(const auto next = stl::find_if(it, last, [](const auto &value) { return value.second; }); next != last) { - for(; it != next; ++it) { - matrix.insert(it->first, next->first); - } - } else { - it = last; - } } } } - } - void transitive_closure(adjacency_matrix_type &matrix) const { - const auto length = matrix.size(); + void transitive_closure(adjacency_matrix_type &matrix) const { + const auto length = matrix.size(); - for(stl::size_t vk{}; vk < length; ++vk) { - for(stl::size_t vi{}; vi < length; ++vi) { - for(stl::size_t vj{}; vj < length; ++vj) { - if(matrix.contains(vi, vk) && matrix.contains(vk, vj)) { - matrix.insert(vi, vj); + for(stl::size_t vk{}; vk < length; ++vk) { + for(stl::size_t vi{}; vi < length; ++vi) { + for(stl::size_t vj{}; vj < length; ++vj) { + if(matrix.contains(vi, vk) && matrix.contains(vk, vj)) { + matrix.insert(vi, vj); + } } } } } - } - void transitive_reduction(adjacency_matrix_type &matrix) const { - const auto length = matrix.size(); + void transitive_reduction(adjacency_matrix_type &matrix) const { + const auto length = matrix.size(); - for(stl::size_t vert{}; vert < length; ++vert) { - matrix.erase(vert, vert); - } + for(stl::size_t vert{}; vert < length; ++vert) { + matrix.erase(vert, vert); + } - for(stl::size_t vj{}; vj < length; ++vj) { - for(stl::size_t vi{}; vi < length; ++vi) { - if(matrix.contains(vi, vj)) { - for(stl::size_t vk{}; vk < length; ++vk) { - if(matrix.contains(vj, vk)) { - matrix.erase(vi, vk); + for(stl::size_t vj{}; vj < length; ++vj) { + for(stl::size_t vi{}; vi < length; ++vi) { + if(matrix.contains(vi, vj)) { + for(stl::size_t vk{}; vk < length; ++vk) { + if(matrix.contains(vj, vk)) { + matrix.erase(vi, vk); + } } } } } } - } - -public: - /*! @brief Allocator type. */ - using allocator_type = Allocator; - /*! @brief Unsigned integer type. */ - using size_type = stl::size_t; - /*! @brief Iterable task list. */ - using iterable = iterable_adaptor; - /*! @brief Adjacency matrix type. */ - using graph_type = adjacency_matrix_type; - - /*! @brief Default constructor. */ - basic_flow() - : basic_flow{allocator_type{}} {} - - /** - * @brief Constructs a flow builder with a given allocator. - * @param allocator The allocator to use. - */ - explicit basic_flow(const allocator_type &allocator) - : index{0u, allocator}, - vertices{allocator}, - deps{allocator} {} - - /*! @brief Default copy constructor. */ - basic_flow(const basic_flow &) = default; - /** - * @brief Allocator-extended copy constructor. - * @param other The instance to copy from. - * @param allocator The allocator to use. - */ - basic_flow(const basic_flow &other, const allocator_type &allocator) - : index{other.index.first(), allocator}, - vertices{other.vertices, allocator}, - deps{other.deps, allocator}, - sync_on{other.sync_on} {} + public: + /*! @brief Allocator type. */ + using allocator_type = Allocator; + /*! @brief Unsigned integer type. */ + using size_type = stl::size_t; + /*! @brief Iterable task list. */ + using iterable = iterable_adaptor; + /*! @brief Adjacency matrix type. */ + using graph_type = adjacency_matrix_type; + + /*! @brief Default constructor. */ + basic_flow() + : basic_flow{allocator_type{}} {} + + /** + * @brief Constructs a flow builder with a given allocator. + * @param allocator The allocator to use. + */ + explicit basic_flow(const allocator_type &allocator) + : index{0u, allocator}, + vertices{allocator}, + deps{allocator} {} + + /*! @brief Default copy constructor. */ + basic_flow(const basic_flow &) = default; + + /** + * @brief Allocator-extended copy constructor. + * @param other The instance to copy from. + * @param allocator The allocator to use. + */ + basic_flow(const basic_flow &other, const allocator_type &allocator) + : index{other.index.first(), allocator}, + vertices{other.vertices, allocator}, + deps{other.deps, allocator}, + sync_on{other.sync_on} {} + + /*! @brief Default move constructor. */ + basic_flow(basic_flow &&) noexcept = default; + + /** + * @brief Allocator-extended move constructor. + * @param other The instance to move from. + * @param allocator The allocator to use. + */ + basic_flow(basic_flow &&other, const allocator_type &allocator) + : index{other.index.first(), allocator}, + vertices{stl::move(other.vertices), allocator}, + deps{stl::move(other.deps), allocator}, + sync_on{other.sync_on} {} + + /*! @brief Default destructor. */ + ~basic_flow() = default; + + /** + * @brief Default copy assignment operator. + * @return This flow builder. + */ + basic_flow &operator=(const basic_flow &) = default; + + /** + * @brief Default move assignment operator. + * @return This flow builder. + */ + basic_flow &operator=(basic_flow &&) noexcept = default; + + /** + * @brief Exchanges the contents with those of a given flow builder. + * @param other Flow builder to exchange the content with. + */ + void swap(basic_flow &other) noexcept { + using stl::swap; + swap(index, other.index); + swap(vertices, other.vertices); + swap(deps, other.deps); + swap(sync_on, other.sync_on); + } - /*! @brief Default move constructor. */ - basic_flow(basic_flow &&) noexcept = default; + /** + * @brief Returns the associated allocator. + * @return The associated allocator. + */ + [[nodiscard]] constexpr allocator_type get_allocator() const noexcept { + return allocator_type{index.second()}; + } - /** - * @brief Allocator-extended move constructor. - * @param other The instance to move from. - * @param allocator The allocator to use. - */ - basic_flow(basic_flow &&other, const allocator_type &allocator) - : index{other.index.first(), allocator}, - vertices{stl::move(other.vertices), allocator}, - deps{stl::move(other.deps), allocator}, - sync_on{other.sync_on} {} + /** + * @brief Returns the identifier at specified location. + * @param pos Position of the identifier to return. + * @return The requested identifier. + */ + [[nodiscard]] id_type operator[](const size_type pos) const { + return vertices.cbegin()[static_cast(pos)]; + } - /*! @brief Default destructor. */ - ~basic_flow() = default; + /*! @brief Clears the flow builder. */ + void clear() noexcept { + index.first() = {}; + vertices.clear(); + deps.clear(); + sync_on = {}; + } - /** - * @brief Default copy assignment operator. - * @return This flow builder. - */ - basic_flow &operator=(const basic_flow &) = default; + /** + * @brief Returns true if a flow builder contains no tasks, false otherwise. + * @return True if the flow builder contains no tasks, false otherwise. + */ + [[nodiscard]] bool empty() const noexcept { + return vertices.empty(); + } - /** - * @brief Default move assignment operator. - * @return This flow builder. - */ - basic_flow &operator=(basic_flow &&) noexcept = default; + /** + * @brief Returns the number of tasks. + * @return The number of tasks. + */ + [[nodiscard]] size_type size() const noexcept { + return vertices.size(); + } - /** - * @brief Exchanges the contents with those of a given flow builder. - * @param other Flow builder to exchange the content with. - */ - void swap(basic_flow &other) noexcept { - using stl::swap; - swap(index, other.index); - swap(vertices, other.vertices); - swap(deps, other.deps); - swap(sync_on, other.sync_on); - } + /** + * @brief Binds a task to a flow builder. + * @param value Task identifier. + * @return This flow builder. + */ + basic_flow &bind(const id_type value) { + sync_on += (sync_on == vertices.size()); + const auto it = vertices.emplace(value).first; + index.first() = size_type(it - vertices.begin()); + return *this; + } - /** - * @brief Returns the associated allocator. - * @return The associated allocator. - */ - [[nodiscard]] constexpr allocator_type get_allocator() const noexcept { - return allocator_type{index.second()}; - } + /** + * @brief Turns the current task into a sync point. + * @return This flow builder. + */ + basic_flow &sync() { + ENTT_ASSERT(index.first() < vertices.size(), "Invalid node"); + sync_on = index.first(); - /** - * @brief Returns the identifier at specified location. - * @param pos Position of the identifier to return. - * @return The requested identifier. - */ - [[nodiscard]] id_type operator[](const size_type pos) const { - return vertices.cbegin()[static_cast(pos)]; - } - - /*! @brief Clears the flow builder. */ - void clear() noexcept { - index.first() = {}; - vertices.clear(); - deps.clear(); - sync_on = {}; - } + for(const auto &elem: deps) { + elem.second.emplace_back(sync_on, true); + } - /** - * @brief Returns true if a flow builder contains no tasks, false otherwise. - * @return True if the flow builder contains no tasks, false otherwise. - */ - [[nodiscard]] bool empty() const noexcept { - return vertices.empty(); - } + return *this; + } - /** - * @brief Returns the number of tasks. - * @return The number of tasks. - */ - [[nodiscard]] size_type size() const noexcept { - return vertices.size(); - } + /** + * @brief Assigns a resource to the current task with a given access mode. + * @param res Resource identifier. + * @param is_rw Access mode. + * @return This flow builder. + */ + basic_flow &set(const id_type res, bool is_rw = false) { + emplace(res, is_rw); + return *this; + } - /** - * @brief Binds a task to a flow builder. - * @param value Task identifier. - * @return This flow builder. - */ - basic_flow &bind(const id_type value) { - sync_on += (sync_on == vertices.size()); - const auto it = vertices.emplace(value).first; - index.first() = size_type(it - vertices.begin()); - return *this; - } + /** + * @brief Assigns a read-only resource to the current task. + * @param res Resource identifier. + * @return This flow builder. + */ + basic_flow &ro(const id_type res) { + emplace(res, false); + return *this; + } - /** - * @brief Turns the current task into a sync point. - * @return This flow builder. - */ - basic_flow &sync() { - ENTT_ASSERT(index.first() < vertices.size(), "Invalid node"); - sync_on = index.first(); + /** + * @brief Assigns a range of read-only resources to the current task. + * @param first An iterator to the first element of the range of elements. + * @param last An iterator past the last element of the range of elements. + * @return This flow builder. + */ + basic_flow &ro(stl::input_iterator auto first, stl::input_iterator auto last) { + for(; first != last; ++first) { + emplace(*first, false); + } - for(const auto &elem: deps) { - elem.second.emplace_back(sync_on, true); + return *this; } - return *this; - } - - /** - * @brief Assigns a resource to the current task with a given access mode. - * @param res Resource identifier. - * @param is_rw Access mode. - * @return This flow builder. - */ - basic_flow &set(const id_type res, bool is_rw = false) { - emplace(res, is_rw); - return *this; - } + /** + * @brief Assigns a writable resource to the current task. + * @param res Resource identifier. + * @return This flow builder. + */ + basic_flow &rw(const id_type res) { + emplace(res, true); + return *this; + } - /** - * @brief Assigns a read-only resource to the current task. - * @param res Resource identifier. - * @return This flow builder. - */ - basic_flow &ro(const id_type res) { - emplace(res, false); - return *this; - } + /** + * @brief Assigns a range of writable resources to the current task. + * @param first An iterator to the first element of the range of elements. + * @param last An iterator past the last element of the range of elements. + * @return This flow builder. + */ + basic_flow &rw(stl::input_iterator auto first, stl::input_iterator auto last) { + for(; first != last; ++first) { + emplace(*first, true); + } - /** - * @brief Assigns a range of read-only resources to the current task. - * @param first An iterator to the first element of the range of elements. - * @param last An iterator past the last element of the range of elements. - * @return This flow builder. - */ - basic_flow &ro(stl::input_iterator auto first, stl::input_iterator auto last) { - for(; first != last; ++first) { - emplace(*first, false); + return *this; } - return *this; - } + /** + * @brief Generates a task graph for the current content. + * @return The adjacency matrix of the task graph. + */ + [[nodiscard]] graph_type graph() const { + graph_type matrix{vertices.size(), get_allocator()}; - /** - * @brief Assigns a writable resource to the current task. - * @param res Resource identifier. - * @return This flow builder. - */ - basic_flow &rw(const id_type res) { - emplace(res, true); - return *this; - } + setup_graph(matrix); + transitive_closure(matrix); + transitive_reduction(matrix); - /** - * @brief Assigns a range of writable resources to the current task. - * @param first An iterator to the first element of the range of elements. - * @param last An iterator past the last element of the range of elements. - * @return This flow builder. - */ - basic_flow &rw(stl::input_iterator auto first, stl::input_iterator auto last) { - for(; first != last; ++first) { - emplace(*first, true); + return matrix; } - return *this; - } - - /** - * @brief Generates a task graph for the current content. - * @return The adjacency matrix of the task graph. - */ - [[nodiscard]] graph_type graph() const { - graph_type matrix{vertices.size(), get_allocator()}; - - setup_graph(matrix); - transitive_closure(matrix); - transitive_reduction(matrix); - - return matrix; - } - -private: - compressed_pair index; - task_container_type vertices; - deps_container_type deps; - size_type sync_on{}; -}; + private: + compressed_pair index; + task_container_type vertices; + deps_container_type deps; + size_type sync_on{}; + }; } // namespace entt diff --git a/src/entt/graph/fwd.hpp b/src/entt/graph/fwd.hpp index c1fd58edd6..476a2861f8 100644 --- a/src/entt/graph/fwd.hpp +++ b/src/entt/graph/fwd.hpp @@ -1,27 +1,30 @@ #ifndef ENTT_GRAPH_FWD_HPP #define ENTT_GRAPH_FWD_HPP -#include "../core/fwd.hpp" -#include "../stl/concepts.hpp" -#include "../stl/cstddef.hpp" -#include "../stl/memory.hpp" +#include "../config/module.h" -namespace entt { +#ifndef ENTT_MODULE +# include "../core/fwd.hpp" +# include "../stl/concepts.hpp" +# include "../stl/cstddef.hpp" +# include "../stl/memory.hpp" +#endif // ENTT_MODULE -/*! @brief Undirected graph category tag. */ -struct directed_tag {}; +ENTT_MODULE_EXPORT namespace entt { + /*! @brief Undirected graph category tag. */ + struct directed_tag {}; -/*! @brief Directed graph category tag. */ -struct undirected_tag: directed_tag {}; + /*! @brief Directed graph category tag. */ + struct undirected_tag: directed_tag {}; -template, typename = stl::allocator> -class adjacency_matrix; + template, typename = stl::allocator> + class adjacency_matrix; -template> -class basic_flow; + template> + class basic_flow; -/*! @brief Alias declaration for the most common use case. */ -using flow = basic_flow<>; + /*! @brief Alias declaration for the most common use case. */ + using flow = basic_flow<>; } // namespace entt diff --git a/src/entt/locator/locator.hpp b/src/entt/locator/locator.hpp index 0d6fecf7e5..fdf89c226f 100644 --- a/src/entt/locator/locator.hpp +++ b/src/entt/locator/locator.hpp @@ -1,160 +1,163 @@ #ifndef ENTT_LOCATOR_LOCATOR_HPP #define ENTT_LOCATOR_LOCATOR_HPP -#include "../config/config.h" -#include "../stl/concepts.hpp" -#include "../stl/memory.hpp" -#include "../stl/utility.hpp" - -namespace entt { - -/** - * @brief Service locator, nothing more. - * - * A service locator is used to do what it promises: locate services.
- * Usually service locators are tightly bound to the services they expose and - * thus it's hard to define a general purpose class to do that. This tiny class - * tries to fill the gap and to get rid of the burden of defining a different - * specific locator for each application. - * - * @note - * Users shouldn't retain references to a service. The recommended way is to - * retrieve the service implementation currently set each and every time the - * need for it arises. The risk is to incur in unexpected behaviors otherwise. - * - * @tparam Service Service type. - */ -template -class locator final { - class service_handle { - friend class locator; - stl::shared_ptr value{}; - }; - -public: - /*! @brief Service type. */ - using type = Service; - /*! @brief Service node type. */ - using node_type = service_handle; - - /*! @brief Default constructor, deleted on purpose. */ - locator() = delete; - - /*! @brief Default copy constructor, deleted on purpose. */ - locator(const locator &) = delete; +#include "../config/module.h" - /*! @brief Default destructor, deleted on purpose. */ - ~locator() = delete; +#ifndef ENTT_MODULE +# include "../config/config.h" +# include "../stl/concepts.hpp" +# include "../stl/memory.hpp" +# include "../stl/utility.hpp" +#endif // ENTT_MODULE +ENTT_MODULE_EXPORT namespace entt { /** - * @brief Default copy assignment operator, deleted on purpose. - * @return This locator. - */ - locator &operator=(const locator &) = delete; - - /** - * @brief Checks whether a service locator contains a value. - * @return True if the service locator contains a value, false otherwise. - */ - [[nodiscard]] static bool has_value() noexcept { - return (service != nullptr); - } - - /** - * @brief Returns a reference to a valid service, if any. + * @brief Service locator, nothing more. * - * @warning - * Invoking this function can result in undefined behavior if the service - * hasn't been set yet. + * A service locator is used to do what it promises: locate services.
+ * Usually service locators are tightly bound to the services they expose and + * thus it's hard to define a general purpose class to do that. This tiny class + * tries to fill the gap and to get rid of the burden of defining a different + * specific locator for each application. * - * @return A reference to the service currently set, if any. - */ - [[nodiscard]] static Service &value() noexcept { - ENTT_ASSERT(has_value(), "Service not available"); - return *service; - } - - /** - * @brief Returns a service if available or sets it from a fallback type. - * - * Arguments are used only if a service doesn't already exist. In all other - * cases, they are discarded. + * @note + * Users shouldn't retain references to a service. The recommended way is to + * retrieve the service implementation currently set each and every time the + * need for it arises. The risk is to incur in unexpected behaviors otherwise. * - * @tparam Args Types of arguments to use to construct the fallback service. - * @tparam Type Fallback service type. - * @param args Parameters to use to construct the fallback service. - * @return A reference to a valid service. - */ - template Type = Service, typename... Args> - requires stl::constructible_from - [[nodiscard]] static Service &value_or(Args &&...args) { - return service ? *service : emplace(stl::forward(args)...); - } - - /** - * @brief Sets or replaces a service. - * @tparam Type Service type. - * @tparam Args Types of arguments to use to construct the service. - * @param args Parameters to use to construct the service. - * @return A reference to a valid service. - */ - template Type = Service, typename... Args> - requires stl::constructible_from - static Service &emplace(Args &&...args) { - service = stl::make_shared(stl::forward(args)...); - return *service; - } - - /** - * @brief Sets or replaces a service using a given allocator. - * @tparam Type Service type. - * @tparam Args Types of arguments to use to construct the service. - * @param alloc The allocator to use. - * @param args Parameters to use to construct the service. - * @return A reference to a valid service. - */ - template Type = Service, typename... Args> - requires stl::constructible_from - static Service &emplace(stl::allocator_arg_t, auto alloc, Args &&...args) { - service = stl::allocate_shared(alloc, stl::forward(args)...); - return *service; - } - - /** - * @brief Returns a handle to the underlying service. - * @return A handle to the underlying service. + * @tparam Service Service type. */ - static node_type handle() noexcept { - node_type node{}; - node.value = service; - return node; - } - - /** - * @brief Resets or replaces a service. - * @param other Optional handle with which to replace the service. - */ - static void reset(const node_type &other = {}) noexcept { - service = other.value; - } - - /** - * @brief Resets or replaces a service. - * @tparam Type Service type. - * @tparam Deleter Deleter type. - * @param elem A pointer to a service to manage. - * @param deleter A deleter to use to destroy the service. - */ - template Type, typename Deleter = stl::default_delete> - static void reset(Type *elem, Deleter deleter = {}) { - service = stl::shared_ptr{elem, stl::move(deleter)}; - } - -private: - // stl::shared_ptr because of its type erased allocator which is useful here - // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) - inline static stl::shared_ptr service{}; -}; + template + class locator final { + class service_handle { + friend class locator; + stl::shared_ptr value{}; + }; + + public: + /*! @brief Service type. */ + using type = Service; + /*! @brief Service node type. */ + using node_type = service_handle; + + /*! @brief Default constructor, deleted on purpose. */ + locator() = delete; + + /*! @brief Default copy constructor, deleted on purpose. */ + locator(const locator &) = delete; + + /*! @brief Default destructor, deleted on purpose. */ + ~locator() = delete; + + /** + * @brief Default copy assignment operator, deleted on purpose. + * @return This locator. + */ + locator &operator=(const locator &) = delete; + + /** + * @brief Checks whether a service locator contains a value. + * @return True if the service locator contains a value, false otherwise. + */ + [[nodiscard]] static bool has_value() noexcept { + return (service != nullptr); + } + + /** + * @brief Returns a reference to a valid service, if any. + * + * @warning + * Invoking this function can result in undefined behavior if the service + * hasn't been set yet. + * + * @return A reference to the service currently set, if any. + */ + [[nodiscard]] static Service &value() noexcept { + ENTT_ASSERT(has_value(), "Service not available"); + return *service; + } + + /** + * @brief Returns a service if available or sets it from a fallback type. + * + * Arguments are used only if a service doesn't already exist. In all other + * cases, they are discarded. + * + * @tparam Args Types of arguments to use to construct the fallback service. + * @tparam Type Fallback service type. + * @param args Parameters to use to construct the fallback service. + * @return A reference to a valid service. + */ + template Type = Service, typename... Args> + requires stl::constructible_from + [[nodiscard]] static Service &value_or(Args &&...args) { + return service ? *service : emplace(stl::forward(args)...); + } + + /** + * @brief Sets or replaces a service. + * @tparam Type Service type. + * @tparam Args Types of arguments to use to construct the service. + * @param args Parameters to use to construct the service. + * @return A reference to a valid service. + */ + template Type = Service, typename... Args> + requires stl::constructible_from + static Service &emplace(Args &&...args) { + service = stl::make_shared(stl::forward(args)...); + return *service; + } + + /** + * @brief Sets or replaces a service using a given allocator. + * @tparam Type Service type. + * @tparam Args Types of arguments to use to construct the service. + * @param alloc The allocator to use. + * @param args Parameters to use to construct the service. + * @return A reference to a valid service. + */ + template Type = Service, typename... Args> + requires stl::constructible_from + static Service &emplace(stl::allocator_arg_t, auto alloc, Args &&...args) { + service = stl::allocate_shared(alloc, stl::forward(args)...); + return *service; + } + + /** + * @brief Returns a handle to the underlying service. + * @return A handle to the underlying service. + */ + static node_type handle() noexcept { + node_type node{}; + node.value = service; + return node; + } + + /** + * @brief Resets or replaces a service. + * @param other Optional handle with which to replace the service. + */ + static void reset(const node_type &other = {}) noexcept { + service = other.value; + } + + /** + * @brief Resets or replaces a service. + * @tparam Type Service type. + * @tparam Deleter Deleter type. + * @param elem A pointer to a service to manage. + * @param deleter A deleter to use to destroy the service. + */ + template Type, typename Deleter = stl::default_delete> + static void reset(Type *elem, Deleter deleter = {}) { + service = stl::shared_ptr{elem, stl::move(deleter)}; + } + + private: + // stl::shared_ptr because of its type erased allocator which is useful here + // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) + inline static stl::shared_ptr service{}; + }; } // namespace entt diff --git a/src/entt/meta/adl_pointer.hpp b/src/entt/meta/adl_pointer.hpp index 5bb768ac70..de086c3be1 100644 --- a/src/entt/meta/adl_pointer.hpp +++ b/src/entt/meta/adl_pointer.hpp @@ -1,7 +1,9 @@ #ifndef ENTT_META_ADL_POINTER_HPP #define ENTT_META_ADL_POINTER_HPP -namespace entt { +#include "../config/module.h" + +ENTT_MODULE_EXPORT namespace entt { /** * @brief ADL based lookup function for dereferencing meta pointer-like types. diff --git a/src/entt/meta/container.hpp b/src/entt/meta/container.hpp index 9c131be766..8a4e55bdb6 100644 --- a/src/entt/meta/container.hpp +++ b/src/entt/meta/container.hpp @@ -3,17 +3,21 @@ #ifndef ENTT_META_CONTAINER_HPP #define ENTT_META_CONTAINER_HPP -#include "../core/concepts.hpp" -#include "../core/type_traits.hpp" -#include "../stl/concepts.hpp" -#include "../stl/cstddef.hpp" -#include "../stl/iterator.hpp" -#include "../stl/type_traits.hpp" -#include "../stl/utility.hpp" -#include "context.hpp" -#include "fwd.hpp" -#include "meta.hpp" -#include "type_traits.hpp" +#include "../config/module.h" + +#ifndef ENTT_MODULE +# include "../core/concepts.hpp" +# include "../core/type_traits.hpp" +# include "../stl/concepts.hpp" +# include "../stl/cstddef.hpp" +# include "../stl/iterator.hpp" +# include "../stl/type_traits.hpp" +# include "../stl/utility.hpp" +# include "context.hpp" +# include "fwd.hpp" +# include "meta.hpp" +# include "type_traits.hpp" +#endif // ENTT_MODULE namespace entt { @@ -55,6 +59,8 @@ concept meta_associative_container_like = requires(Type value) { } // namespace internal /*! @endcond */ +ENTT_MODULE_EXPORT_BEGIN + /** * @brief General purpose implementation of meta sequence container traits. * @tparam Type Type of underlying sequence container. @@ -293,6 +299,8 @@ struct meta_sequence_container_traits: basic_meta_sequence_container_trait template struct meta_associative_container_traits: basic_meta_associative_container_traits {}; +ENTT_MODULE_EXPORT_END + } // namespace entt #endif diff --git a/src/entt/meta/context.hpp b/src/entt/meta/context.hpp index 4d3e34ee0a..5a7617857d 100644 --- a/src/entt/meta/context.hpp +++ b/src/entt/meta/context.hpp @@ -1,14 +1,17 @@ #ifndef ENTT_META_CTX_HPP #define ENTT_META_CTX_HPP -#include "../container/dense_map.hpp" -#include "../core/fwd.hpp" -#include "../stl/functional.hpp" -#include "../stl/memory.hpp" -#include "fwd.hpp" +#include "../config/module.h" -namespace entt { +#ifndef ENTT_MODULE +# include "../container/dense_map.hpp" +# include "../core/fwd.hpp" +# include "../stl/functional.hpp" +# include "../stl/memory.hpp" +# include "fwd.hpp" +#endif // ENTT_MODULE +namespace entt { /*! @cond ENTT_INTERNAL */ namespace internal { @@ -26,17 +29,17 @@ struct meta_context { } // namespace internal /*! @endcond */ +ENTT_MODULE_EXPORT_BEGIN /*! @brief Opaque meta context type. */ struct meta_ctx: private internal::meta_context { // attorney idiom like model to access the base class friend struct internal::meta_context; }; - -/*! @cond ENTT_INTERNAL */ +ENTT_MODULE_EXPORT_END +/*! @cond TURN_OFF_DOXYGEN */ [[nodiscard]] inline internal::meta_context &internal::meta_context::from(meta_ctx &ctx) { return ctx; } - [[nodiscard]] inline const internal::meta_context &internal::meta_context::from(const meta_ctx &ctx) { return ctx; } diff --git a/src/entt/meta/factory.hpp b/src/entt/meta/factory.hpp index 3294c5b934..5a4aec5ec9 100644 --- a/src/entt/meta/factory.hpp +++ b/src/entt/meta/factory.hpp @@ -1,28 +1,32 @@ #ifndef ENTT_META_FACTORY_HPP #define ENTT_META_FACTORY_HPP -#include "../config/config.h" -#include "../core/bit.hpp" -#include "../core/fwd.hpp" -#include "../core/hashed_string.hpp" -#include "../core/type_info.hpp" -#include "../core/type_traits.hpp" -#include "../locator/locator.hpp" -#include "../stl/algorithm.hpp" -#include "../stl/concepts.hpp" -#include "../stl/cstddef.hpp" -#include "../stl/cstdint.hpp" -#include "../stl/functional.hpp" -#include "../stl/memory.hpp" -#include "../stl/type_traits.hpp" -#include "../stl/utility.hpp" -#include "context.hpp" -#include "fwd.hpp" -#include "meta.hpp" -#include "node.hpp" -#include "policy.hpp" -#include "range.hpp" -#include "utility.hpp" +#include "../config/module.h" + +#ifndef ENTT_MODULE +# include "../config/config.h" +# include "../core/bit.hpp" +# include "../core/fwd.hpp" +# include "../core/hashed_string.hpp" +# include "../core/type_info.hpp" +# include "../core/type_traits.hpp" +# include "../locator/locator.hpp" +# include "../stl/algorithm.hpp" +# include "../stl/concepts.hpp" +# include "../stl/cstddef.hpp" +# include "../stl/cstdint.hpp" +# include "../stl/functional.hpp" +# include "../stl/memory.hpp" +# include "../stl/type_traits.hpp" +# include "../stl/utility.hpp" +# include "context.hpp" +# include "fwd.hpp" +# include "meta.hpp" +# include "node.hpp" +# include "policy.hpp" +# include "range.hpp" +# include "utility.hpp" +#endif // ENTT_MODULE namespace entt { @@ -162,6 +166,8 @@ class basic_meta_factory { } // namespace internal /*! @endcond */ +ENTT_MODULE_EXPORT_BEGIN + /** * @brief Meta factory to be used for reflection purposes. * @tparam Type Type for which the factory was created. @@ -639,6 +645,8 @@ inline void meta_reset() noexcept { meta_reset(locator::value_or()); } +ENTT_MODULE_EXPORT_END + } // namespace entt #endif diff --git a/src/entt/meta/fwd.hpp b/src/entt/meta/fwd.hpp index ac949c7661..86bcbddd56 100644 --- a/src/entt/meta/fwd.hpp +++ b/src/entt/meta/fwd.hpp @@ -1,42 +1,45 @@ #ifndef ENTT_META_FWD_HPP #define ENTT_META_FWD_HPP -#include "../stl/cstddef.hpp" -#include "../stl/limits.hpp" +#include "../config/module.h" -namespace entt { +#ifndef ENTT_MODULE +# include "../stl/cstddef.hpp" +# include "../stl/limits.hpp" +#endif // ENTT_MODULE -struct meta_ctx; +ENTT_MODULE_EXPORT namespace entt { + struct meta_ctx; -class meta_sequence_container; + class meta_sequence_container; -class meta_associative_container; + class meta_associative_container; -class meta_any; + class meta_any; -class meta_handle; + class meta_handle; -struct meta_custom; + struct meta_custom; -struct meta_data; + struct meta_data; -struct meta_func; + struct meta_func; -struct meta_base; + struct meta_base; -class meta_type; + class meta_type; -template -class meta_factory; + template + class meta_factory; -/*! @brief Used to identicate that a sequence container has not a fixed size. */ -inline constexpr stl::size_t meta_dynamic_extent = (stl::numeric_limits::max)(); + /*! @brief Used to identicate that a sequence container has not a fixed size. */ + inline constexpr stl::size_t meta_dynamic_extent = (stl::numeric_limits::max)(); -/*! @brief Disambiguation tag for constructors and the like. */ -struct meta_ctx_arg_t final {}; + /*! @brief Disambiguation tag for constructors and the like. */ + struct meta_ctx_arg_t final {}; -/*! @brief Constant of type meta_context_arg_t used to disambiguate calls. */ -inline constexpr meta_ctx_arg_t meta_ctx_arg{}; + /*! @brief Constant of type meta_context_arg_t used to disambiguate calls. */ + inline constexpr meta_ctx_arg_t meta_ctx_arg{}; } // namespace entt diff --git a/src/entt/meta/meta.hpp b/src/entt/meta/meta.hpp index da3821834d..9aff6fa3fe 100644 --- a/src/entt/meta/meta.hpp +++ b/src/entt/meta/meta.hpp @@ -1,1909 +1,1912 @@ #ifndef ENTT_META_META_HPP #define ENTT_META_META_HPP -#include "../config/config.h" -#include "../core/any.hpp" -#include "../core/concepts.hpp" -#include "../core/fwd.hpp" -#include "../core/iterator.hpp" -#include "../core/type_info.hpp" -#include "../core/type_traits.hpp" -#include "../core/utility.hpp" -#include "../locator/locator.hpp" -#include "../stl/array.hpp" -#include "../stl/concepts.hpp" -#include "../stl/cstddef.hpp" -#include "../stl/iterator.hpp" -#include "../stl/memory.hpp" -#include "../stl/string_view.hpp" -#include "../stl/type_traits.hpp" -#include "../stl/utility.hpp" -#include "adl_pointer.hpp" -#include "context.hpp" -#include "fwd.hpp" -#include "node.hpp" -#include "range.hpp" -#include "type_traits.hpp" - -namespace entt { - -/*! @cond ENTT_INTERNAL */ -namespace internal { - -template -struct basic_meta_object { - [[nodiscard]] auto &node_or_assert() const noexcept { - ENTT_ASSERT(node != nullptr, "Invalid pointer to node"); - return *node; - } - - const Type *node{}; - const meta_ctx *ctx{&locator::value_or()}; -}; - -} // namespace internal -/*! @endcond */ - -/*! @brief Proxy object for sequence containers. */ -class meta_sequence_container { - class meta_iterator; - -public: - /*! @brief Unsigned integer type. */ - using size_type = stl::size_t; - /*! @brief Meta iterator type. */ - using iterator = meta_iterator; +#include "../config/module.h" + +#ifndef ENTT_MODULE +# include "../config/config.h" +# include "../core/any.hpp" +# include "../core/concepts.hpp" +# include "../core/fwd.hpp" +# include "../core/iterator.hpp" +# include "../core/type_info.hpp" +# include "../core/type_traits.hpp" +# include "../core/utility.hpp" +# include "../locator/locator.hpp" +# include "../stl/array.hpp" +# include "../stl/concepts.hpp" +# include "../stl/cstddef.hpp" +# include "../stl/iterator.hpp" +# include "../stl/memory.hpp" +# include "../stl/string_view.hpp" +# include "../stl/type_traits.hpp" +# include "../stl/utility.hpp" +# include "adl_pointer.hpp" +# include "context.hpp" +# include "fwd.hpp" +# include "node.hpp" +# include "range.hpp" +# include "type_traits.hpp" +#endif // ENTT_MODULE + +ENTT_MODULE_EXPORT namespace entt { + /*! @cond ENTT_INTERNAL */ + namespace internal { - /*! @brief Default constructor. */ - meta_sequence_container() = default; - - /** - * @brief Context aware constructor. - * @tparam Type Type of container to wrap. - * @param area The context from which to search for meta types. - * @param instance The container to wrap. - */ template - meta_sequence_container(const meta_ctx &area, Type &instance) noexcept - : ctx{&area}, - data{&instance}, - value_type_node{&internal::resolve}, - const_reference_node{&internal::resolve>}, - size_fn{meta_sequence_container_traits>::size}, - clear_fn{meta_sequence_container_traits>::clear}, - reserve_fn{meta_sequence_container_traits>::reserve}, - resize_fn{meta_sequence_container_traits>::resize}, - begin_end_fn{meta_sequence_container_traits>::iter}, - insert_fn{meta_sequence_container_traits>::insert}, - erase_fn{meta_sequence_container_traits>::erase}, - const_only{stl::is_const_v} {} - - [[nodiscard]] inline meta_type value_type() const noexcept; - [[nodiscard]] inline size_type size() const noexcept; - inline bool resize(size_type); - inline bool clear(); - inline bool reserve(size_type); - [[nodiscard]] inline iterator begin(); - [[nodiscard]] inline iterator end(); - inline iterator insert(const iterator &, meta_any); - inline iterator erase(const iterator &); - [[nodiscard]] inline meta_any operator[](size_type); - [[nodiscard]] inline explicit operator bool() const noexcept; - -private: - const meta_ctx *ctx{}; - const void *data{}; - const internal::meta_type_node &(*value_type_node)(const internal::meta_context &){}; - const internal::meta_type_node &(*const_reference_node)(const internal::meta_context &){}; - size_type (*size_fn)(const void *){}; - bool (*clear_fn)(void *){}; - bool (*reserve_fn)(void *, const size_type){}; - bool (*resize_fn)(void *, const size_type){}; - iterator (*begin_end_fn)(const meta_ctx &, void *, const void *, const bool){}; - iterator (*insert_fn)(const meta_ctx &, void *, const void *, const void *, const iterator &){}; - iterator (*erase_fn)(const meta_ctx &, void *, const iterator &){}; - bool const_only{}; -}; - -/*! @brief Proxy object for associative containers. */ -class meta_associative_container { - class meta_iterator; - -public: - /*! @brief Unsigned integer type. */ - using size_type = stl::size_t; - /*! @brief Meta iterator type. */ - using iterator = meta_iterator; - - /*! @brief Default constructor. */ - meta_associative_container() = default; + struct basic_meta_object { + [[nodiscard]] auto &node_or_assert() const noexcept { + ENTT_ASSERT(node != nullptr, "Invalid pointer to node"); + return *node; + } - /** - * @brief Context aware constructor. - * @tparam Type Type of container to wrap. - * @param area The context from which to search for meta types. - * @param instance The container to wrap. - */ - template - meta_associative_container(const meta_ctx &area, Type &instance) noexcept - : ctx{&area}, - data{&instance}, - key_type_node{&internal::resolve}, - value_type_node{&internal::resolve}, - size_fn{&meta_associative_container_traits>::size}, - clear_fn{&meta_associative_container_traits>::clear}, - reserve_fn{&meta_associative_container_traits>::reserve}, - begin_end_fn{&meta_associative_container_traits>::iter}, - insert_fn{&meta_associative_container_traits>::insert}, - erase_fn{&meta_associative_container_traits>::erase}, - find_fn{&meta_associative_container_traits>::find}, - const_only{stl::is_const_v} { - if constexpr(!meta_associative_container_traits>::key_only) { - mapped_type_node = &internal::resolve; + const Type *node{}; + const meta_ctx *ctx{&locator::value_or()}; + }; + + } // namespace internal + /*! @endcond */ + + /*! @brief Proxy object for sequence containers. */ + class meta_sequence_container { + class meta_iterator; + + public: + /*! @brief Unsigned integer type. */ + using size_type = stl::size_t; + /*! @brief Meta iterator type. */ + using iterator = meta_iterator; + + /*! @brief Default constructor. */ + meta_sequence_container() = default; + + /** + * @brief Context aware constructor. + * @tparam Type Type of container to wrap. + * @param area The context from which to search for meta types. + * @param instance The container to wrap. + */ + template + meta_sequence_container(const meta_ctx &area, Type &instance) noexcept + : ctx{&area}, + data{&instance}, + value_type_node{&internal::resolve}, + const_reference_node{&internal::resolve>}, + size_fn{meta_sequence_container_traits>::size}, + clear_fn{meta_sequence_container_traits>::clear}, + reserve_fn{meta_sequence_container_traits>::reserve}, + resize_fn{meta_sequence_container_traits>::resize}, + begin_end_fn{meta_sequence_container_traits>::iter}, + insert_fn{meta_sequence_container_traits>::insert}, + erase_fn{meta_sequence_container_traits>::erase}, + const_only{stl::is_const_v} {} + + [[nodiscard]] inline meta_type value_type() const noexcept; + [[nodiscard]] inline size_type size() const noexcept; + inline bool resize(size_type); + inline bool clear(); + inline bool reserve(size_type); + [[nodiscard]] inline iterator begin(); + [[nodiscard]] inline iterator end(); + inline iterator insert(const iterator &, meta_any); + inline iterator erase(const iterator &); + [[nodiscard]] inline meta_any operator[](size_type); + [[nodiscard]] inline explicit operator bool() const noexcept; + + private: + const meta_ctx *ctx{}; + const void *data{}; + const internal::meta_type_node &(*value_type_node)(const internal::meta_context &){}; + const internal::meta_type_node &(*const_reference_node)(const internal::meta_context &){}; + size_type (*size_fn)(const void *){}; + bool (*clear_fn)(void *){}; + bool (*reserve_fn)(void *, const size_type){}; + bool (*resize_fn)(void *, const size_type){}; + iterator (*begin_end_fn)(const meta_ctx &, void *, const void *, const bool){}; + iterator (*insert_fn)(const meta_ctx &, void *, const void *, const void *, const iterator &){}; + iterator (*erase_fn)(const meta_ctx &, void *, const iterator &){}; + bool const_only{}; + }; + + /*! @brief Proxy object for associative containers. */ + class meta_associative_container { + class meta_iterator; + + public: + /*! @brief Unsigned integer type. */ + using size_type = stl::size_t; + /*! @brief Meta iterator type. */ + using iterator = meta_iterator; + + /*! @brief Default constructor. */ + meta_associative_container() = default; + + /** + * @brief Context aware constructor. + * @tparam Type Type of container to wrap. + * @param area The context from which to search for meta types. + * @param instance The container to wrap. + */ + template + meta_associative_container(const meta_ctx &area, Type &instance) noexcept + : ctx{&area}, + data{&instance}, + key_type_node{&internal::resolve}, + value_type_node{&internal::resolve}, + size_fn{&meta_associative_container_traits>::size}, + clear_fn{&meta_associative_container_traits>::clear}, + reserve_fn{&meta_associative_container_traits>::reserve}, + begin_end_fn{&meta_associative_container_traits>::iter}, + insert_fn{&meta_associative_container_traits>::insert}, + erase_fn{&meta_associative_container_traits>::erase}, + find_fn{&meta_associative_container_traits>::find}, + const_only{stl::is_const_v} { + if constexpr(!meta_associative_container_traits>::key_only) { + mapped_type_node = &internal::resolve; + } } - } - [[nodiscard]] inline meta_type key_type() const noexcept; - [[nodiscard]] inline meta_type mapped_type() const noexcept; - [[nodiscard]] inline meta_type value_type() const noexcept; - [[nodiscard]] inline size_type size() const noexcept; - inline bool clear(); - inline bool reserve(size_type); - [[nodiscard]] inline iterator begin(); - [[nodiscard]] inline iterator end(); - inline bool insert(meta_any, meta_any); - inline size_type erase(meta_any); - [[nodiscard]] inline iterator find(meta_any); - [[nodiscard]] inline explicit operator bool() const noexcept; - -private: - const meta_ctx *ctx{}; - const void *data{}; - const internal::meta_type_node &(*key_type_node)(const internal::meta_context &){}; - const internal::meta_type_node &(*mapped_type_node)(const internal::meta_context &){}; - const internal::meta_type_node &(*value_type_node)(const internal::meta_context &){}; - size_type (*size_fn)(const void *){}; - bool (*clear_fn)(void *){}; - bool (*reserve_fn)(void *, const size_type){}; - iterator (*begin_end_fn)(const meta_ctx &, void *, const void *, const bool){}; - bool (*insert_fn)(void *, const void *, const void *){}; - size_type (*erase_fn)(void *, const void *){}; - iterator (*find_fn)(const meta_ctx &, void *, const void *, const void *){}; - bool const_only{}; -}; - -/*! @brief Opaque wrapper for values of any type. */ -class meta_any { - using vtable_type = void(const internal::meta_traits, const meta_any &, void *); - - template - static void basic_vtable(const internal::meta_traits req, const meta_any &value, [[maybe_unused]] void *other) { - if(req == internal::meta_traits::is_none) { - value.node = &internal::resolve(internal::meta_context::from(*value.ctx)); - } - - if constexpr(is_meta_pointer_like_v) { - if(req == internal::meta_traits::is_pointer) { - if constexpr(!stl::is_void_v::element_type>>) { - if constexpr(stl::is_constructible_v) { - if(const auto &pointer_like = any_cast(value.storage); pointer_like) { - static_cast(other)->emplace::dereference(stl::declval()))>(adl_meta_pointer_like::dereference(pointer_like)); + [[nodiscard]] inline meta_type key_type() const noexcept; + [[nodiscard]] inline meta_type mapped_type() const noexcept; + [[nodiscard]] inline meta_type value_type() const noexcept; + [[nodiscard]] inline size_type size() const noexcept; + inline bool clear(); + inline bool reserve(size_type); + [[nodiscard]] inline iterator begin(); + [[nodiscard]] inline iterator end(); + inline bool insert(meta_any, meta_any); + inline size_type erase(meta_any); + [[nodiscard]] inline iterator find(meta_any); + [[nodiscard]] inline explicit operator bool() const noexcept; + + private: + const meta_ctx *ctx{}; + const void *data{}; + const internal::meta_type_node &(*key_type_node)(const internal::meta_context &){}; + const internal::meta_type_node &(*mapped_type_node)(const internal::meta_context &){}; + const internal::meta_type_node &(*value_type_node)(const internal::meta_context &){}; + size_type (*size_fn)(const void *){}; + bool (*clear_fn)(void *){}; + bool (*reserve_fn)(void *, const size_type){}; + iterator (*begin_end_fn)(const meta_ctx &, void *, const void *, const bool){}; + bool (*insert_fn)(void *, const void *, const void *){}; + size_type (*erase_fn)(void *, const void *){}; + iterator (*find_fn)(const meta_ctx &, void *, const void *, const void *){}; + bool const_only{}; + }; + + /*! @brief Opaque wrapper for values of any type. */ + class meta_any { + using vtable_type = void(const internal::meta_traits, const meta_any &, void *); + + template + static void basic_vtable(const internal::meta_traits req, const meta_any &value, [[maybe_unused]] void *other) { + if(req == internal::meta_traits::is_none) { + value.node = &internal::resolve(internal::meta_context::from(*value.ctx)); + } + + if constexpr(is_meta_pointer_like_v) { + if(req == internal::meta_traits::is_pointer) { + if constexpr(!stl::is_void_v::element_type>>) { + if constexpr(stl::is_constructible_v) { + if(const auto &pointer_like = any_cast(value.storage); pointer_like) { + static_cast(other)->emplace::dereference(stl::declval()))>(adl_meta_pointer_like::dereference(pointer_like)); + } + } else { + static_cast(other)->emplace::dereference(stl::declval()))>(adl_meta_pointer_like::dereference(any_cast(value.storage))); } - } else { - static_cast(other)->emplace::dereference(stl::declval()))>(adl_meta_pointer_like::dereference(any_cast(value.storage))); } } - } - } else if constexpr(requires(Type elem) { *elem; }) { - if(req == internal::meta_traits::is_pointer) { - if constexpr(stl::is_class_v) { - if(const auto &elem = any_cast(value.storage); elem) { - return (value.storage.policy() == any_policy::cref) ? static_cast(other)->emplace(*elem) : static_cast(other)->emplace(elem))>(*const_cast(elem)); - } - } else if constexpr(!stl::is_array_v && !stl::is_void_v>>) { - if(auto *pointer = any_cast(value.storage); pointer) { - static_cast(other)->emplace>>, Type, stl::remove_pointer_t &>>(*pointer); + } else if constexpr(requires(Type elem) { *elem; }) { + if(req == internal::meta_traits::is_pointer) { + if constexpr(stl::is_class_v) { + if(const auto &elem = any_cast(value.storage); elem) { + return (value.storage.policy() == any_policy::cref) ? static_cast(other)->emplace(*elem) : static_cast(other)->emplace(elem))>(*const_cast(elem)); + } + } else if constexpr(!stl::is_array_v && !stl::is_void_v>>) { + if(auto *pointer = any_cast(value.storage); pointer) { + static_cast(other)->emplace>>, Type, stl::remove_pointer_t &>>(*pointer); + } } } + } else if constexpr(is_complete_v> || is_complete_v>) { + if(constexpr auto flag = (is_complete_v> ? internal::meta_traits::is_sequence_container : internal::meta_traits::is_associative_container); req == flag) { + using container_type = stl::conditional_t>, meta_sequence_container, meta_associative_container>; + *static_cast(other) = (value.storage.policy() == any_policy::cref) ? container_type{*value.ctx, any_cast(value.storage)} : container_type{*value.ctx, any_cast(const_cast(value).storage)}; + } } - } else if constexpr(is_complete_v> || is_complete_v>) { - if(constexpr auto flag = (is_complete_v> ? internal::meta_traits::is_sequence_container : internal::meta_traits::is_associative_container); req == flag) { - using container_type = stl::conditional_t>, meta_sequence_container, meta_associative_container>; - *static_cast(other) = (value.storage.policy() == any_policy::cref) ? container_type{*value.ctx, any_cast(value.storage)} : container_type{*value.ctx, any_cast(const_cast(value).storage)}; - } - } - } - - [[nodiscard]] const auto &fetch_node() const { - if(node == nullptr) { - ENTT_ASSERT(*this, "Invalid vtable function"); - vtable(internal::meta_traits::is_none, *this, nullptr); } - ENTT_ASSERT(node != nullptr, "Invalid pointer to node"); - return *node; - } - - meta_any(const meta_any &other, any elem) - : storage{stl::move(elem)}, - ctx{other.ctx}, - node{other.node}, - vtable{other.vtable} {} - -public: - /*! Default constructor. */ - meta_any() = default; - - /** - * @brief Context aware constructor. - * @param area The context from which to search for meta types. - */ - meta_any(meta_ctx_arg_t, const meta_ctx &area) - : ctx{&area} {} - - /** - * @brief Constructs a wrapper by directly initializing the new object. - * @tparam Type Type of object to use to initialize the wrapper. - * @param args Parameters to use to construct the instance. - */ - template - explicit meta_any(stl::in_place_type_t, auto &&...args) - : meta_any{locator::value_or(), stl::in_place_type, stl::forward(args)...} {} - - /** - * @brief Constructs a wrapper by directly initializing the new object. - * @tparam Type Type of object to use to initialize the wrapper. - * @param area The context from which to search for meta types. - * @param args Parameters to use to construct the instance. - */ - template - explicit meta_any(const meta_ctx &area, stl::in_place_type_t, auto &&...args) - : storage{stl::in_place_type, stl::forward(args)...}, - ctx{&area}, - vtable{&basic_vtable>} {} - - /** - * @brief Constructs a wrapper taking ownership of the passed object. - * @param value A pointer to an object to take ownership of. - */ - explicit meta_any(stl::in_place_t, auto *value) - : meta_any{locator::value_or(), stl::in_place, value} {} - - /** - * @brief Constructs a wrapper taking ownership of the passed object. - * @param area The context from which to search for meta types. - * @param value A pointer to an object to take ownership of. - */ - explicit meta_any(const meta_ctx &area, stl::in_place_t, auto *value) - : storage{stl::in_place, value}, - ctx{&area}, - vtable{storage ? &basic_vtable>> : nullptr} { - } - - /** - * @brief Constructs a wrapper from a given value. - * @param value An instance of an object to use to initialize the wrapper. - */ - meta_any(auto &&value) - requires (!stl::same_as, meta_any>) - : meta_any{locator::value_or(), stl::forward(value)} {} - - /** - * @brief Constructs a wrapper from a given value. - * @param area The context from which to search for meta types. - * @param value An instance of an object to use to initialize the wrapper. - */ - meta_any(const meta_ctx &area, auto &&value) - requires (!stl::same_as, meta_any>) - : meta_any{area, stl::in_place_type>, stl::forward(value)} {} + [[nodiscard]] const auto &fetch_node() const { + if(node == nullptr) { + ENTT_ASSERT(*this, "Invalid vtable function"); + vtable(internal::meta_traits::is_none, *this, nullptr); + } - /** - * @brief Context aware copy constructor. - * @param area The context from which to search for meta types. - * @param other The instance to copy from. - */ - meta_any(const meta_ctx &area, const meta_any &other) - : storage{other.storage}, - ctx{&area}, - node{(ctx == other.ctx) ? other.node : nullptr}, - vtable{other.vtable} {} + ENTT_ASSERT(node != nullptr, "Invalid pointer to node"); + return *node; + } - /** - * @brief Context aware move constructor. - * @param area The context from which to search for meta types. - * @param other The instance to move from. - */ - meta_any(const meta_ctx &area, meta_any &&other) - : storage{stl::move(other.storage)}, - ctx{&area}, - node{(ctx == other.ctx) ? stl::exchange(other.node, nullptr) : nullptr}, - vtable{stl::exchange(other.vtable, nullptr)} {} + meta_any(const meta_any &other, any elem) + : storage{stl::move(elem)}, + ctx{other.ctx}, + node{other.node}, + vtable{other.vtable} {} + + public: + /*! Default constructor. */ + meta_any() = default; + + /** + * @brief Context aware constructor. + * @param area The context from which to search for meta types. + */ + meta_any(meta_ctx_arg_t, const meta_ctx &area) + : ctx{&area} {} + + /** + * @brief Constructs a wrapper by directly initializing the new object. + * @tparam Type Type of object to use to initialize the wrapper. + * @param args Parameters to use to construct the instance. + */ + template + explicit meta_any(stl::in_place_type_t, auto &&...args) + : meta_any{locator::value_or(), stl::in_place_type, stl::forward(args)...} {} + + /** + * @brief Constructs a wrapper by directly initializing the new object. + * @tparam Type Type of object to use to initialize the wrapper. + * @param area The context from which to search for meta types. + * @param args Parameters to use to construct the instance. + */ + template + explicit meta_any(const meta_ctx &area, stl::in_place_type_t, auto &&...args) + : storage{stl::in_place_type, stl::forward(args)...}, + ctx{&area}, + vtable{&basic_vtable>} {} + + /** + * @brief Constructs a wrapper taking ownership of the passed object. + * @param value A pointer to an object to take ownership of. + */ + explicit meta_any(stl::in_place_t, auto *value) + : meta_any{locator::value_or(), stl::in_place, value} {} + + /** + * @brief Constructs a wrapper taking ownership of the passed object. + * @param area The context from which to search for meta types. + * @param value A pointer to an object to take ownership of. + */ + explicit meta_any(const meta_ctx &area, stl::in_place_t, auto *value) + : storage{stl::in_place, value}, + ctx{&area}, + vtable{storage ? &basic_vtable>> : nullptr} { + } - /** - * @brief Copy constructor. - * @param other The instance to copy from. - */ - meta_any(const meta_any &other) - : storage{other.storage}, - ctx{other.ctx}, - node{(other.storage && !storage) ? nullptr : other.node}, - vtable{(other.storage && !storage) ? nullptr : other.vtable} { - } + /** + * @brief Constructs a wrapper from a given value. + * @param value An instance of an object to use to initialize the wrapper. + */ + meta_any(auto &&value) + requires (!stl::same_as, meta_any>) + : meta_any{locator::value_or(), stl::forward(value)} {} + + /** + * @brief Constructs a wrapper from a given value. + * @param area The context from which to search for meta types. + * @param value An instance of an object to use to initialize the wrapper. + */ + meta_any(const meta_ctx &area, auto &&value) + requires (!stl::same_as, meta_any>) + : meta_any{area, stl::in_place_type>, stl::forward(value)} {} + + /** + * @brief Context aware copy constructor. + * @param area The context from which to search for meta types. + * @param other The instance to copy from. + */ + meta_any(const meta_ctx &area, const meta_any &other) + : storage{other.storage}, + ctx{&area}, + node{(ctx == other.ctx) ? other.node : nullptr}, + vtable{other.vtable} {} + + /** + * @brief Context aware move constructor. + * @param area The context from which to search for meta types. + * @param other The instance to move from. + */ + meta_any(const meta_ctx &area, meta_any &&other) + : storage{stl::move(other.storage)}, + ctx{&area}, + node{(ctx == other.ctx) ? stl::exchange(other.node, nullptr) : nullptr}, + vtable{stl::exchange(other.vtable, nullptr)} {} + + /** + * @brief Copy constructor. + * @param other The instance to copy from. + */ + meta_any(const meta_any &other) + : storage{other.storage}, + ctx{other.ctx}, + node{(other.storage && !storage) ? nullptr : other.node}, + vtable{(other.storage && !storage) ? nullptr : other.vtable} { + } - /** - * @brief Move constructor. - * @param other The instance to move from. - */ - meta_any(meta_any &&other) noexcept - : storage{stl::move(other.storage)}, - ctx{other.ctx}, - node{stl::exchange(other.node, nullptr)}, - vtable{stl::exchange(other.vtable, nullptr)} {} + /** + * @brief Move constructor. + * @param other The instance to move from. + */ + meta_any(meta_any &&other) noexcept + : storage{stl::move(other.storage)}, + ctx{other.ctx}, + node{stl::exchange(other.node, nullptr)}, + vtable{stl::exchange(other.vtable, nullptr)} {} + + /*! @brief Default destructor. */ + ~meta_any() = default; + + /** + * @brief Copy assignment operator. + * @param other The instance to copy from. + * @return This meta any object. + */ + meta_any &operator=(const meta_any &other) { + if(this != &other) { + ctx = other.ctx; + storage = other.storage; + node = (other.storage && !storage) ? nullptr : other.node; + vtable = (other.storage && !storage) ? nullptr : other.vtable; + } - /*! @brief Default destructor. */ - ~meta_any() = default; + return *this; + } - /** - * @brief Copy assignment operator. - * @param other The instance to copy from. - * @return This meta any object. - */ - meta_any &operator=(const meta_any &other) { - if(this != &other) { + /** + * @brief Move assignment operator. + * @param other The instance to move from. + * @return This meta any object. + */ + meta_any &operator=(meta_any &&other) noexcept { + storage = stl::move(other.storage); ctx = other.ctx; - storage = other.storage; - node = (other.storage && !storage) ? nullptr : other.node; - vtable = (other.storage && !storage) ? nullptr : other.vtable; + node = stl::exchange(other.node, nullptr); + vtable = stl::exchange(other.vtable, nullptr); + return *this; } - return *this; - } - - /** - * @brief Move assignment operator. - * @param other The instance to move from. - * @return This meta any object. - */ - meta_any &operator=(meta_any &&other) noexcept { - storage = stl::move(other.storage); - ctx = other.ctx; - node = stl::exchange(other.node, nullptr); - vtable = stl::exchange(other.vtable, nullptr); - return *this; - } - - /** - * @brief Value assignment operator. - * @param value An instance of an object to use to initialize the wrapper. - * @return This meta any object. - */ - meta_any &operator=(auto &&value) - requires (!stl::same_as, meta_any>) { - emplace>(stl::forward(value)); - return *this; - } - - /** - * @brief Returns the meta type associated with the contained instance. - * @return The meta type associated with the contained instance. - */ - [[nodiscard]] inline meta_type type() const noexcept; - - /** - * @brief Sets a meta type for the contained instance. - * @param alias The meta to use with the contained instance. - */ - inline void type(const meta_type &alias) noexcept; - - /** - * @brief Invokes the underlying function, if possible. - * @param id Unique identifier. - * @param args Parameters to use to invoke the function. - * @return A wrapper containing the returned value, if any. - */ - meta_any invoke(id_type id, auto &&...args) const; - - /*! @copydoc invoke */ - meta_any invoke(id_type id, auto &&...args); - - /** - * @brief Sets the value of a given variable. - * @param id Unique identifier. - * @param value Parameter to use to set the underlying variable. - * @return True in case of success, false otherwise. - */ - bool set(id_type id, auto &&value); - - /** - * @brief Gets the value of a given variable. - * @param id Unique identifier. - * @return A wrapper containing the value of the underlying variable. - */ - [[nodiscard]] meta_any get(id_type id) const; - - /*! @copydoc get */ - [[nodiscard]] meta_any get(id_type id); - - /** - * @brief Tries to cast an instance to a given type. - * @tparam Type Type to which to cast the instance. - * @return A (possibly null) pointer to the contained instance. - */ - template - [[nodiscard]] const Type *try_cast() const { - const auto *elem = any_cast(&storage); - return ((elem != nullptr) || !*this) ? elem : static_cast(internal::try_cast(internal::meta_context::from(*ctx), fetch_node(), type_hash>::value(), storage.data())); - } - - /*! @copydoc try_cast */ - template - [[nodiscard]] Type *try_cast() { - return ((storage.policy() == any_policy::cref) && !stl::is_const_v) ? nullptr : const_cast(stl::as_const(*this).try_cast>()); - } + /** + * @brief Value assignment operator. + * @param value An instance of an object to use to initialize the wrapper. + * @return This meta any object. + */ + meta_any &operator=(auto &&value) + requires (!stl::same_as, meta_any>) { + emplace>(stl::forward(value)); + return *this; + } - /** - * @brief Tries to cast an instance to a given type. - * @tparam Type Type to which to cast the instance. - * @return A reference to the contained instance. - */ - template - [[nodiscard]] stl::remove_const_t cast() const { - auto *const instance = try_cast>(); - ENTT_ASSERT(instance, "Invalid instance"); - return static_cast(*instance); - } + /** + * @brief Returns the meta type associated with the contained instance. + * @return The meta type associated with the contained instance. + */ + [[nodiscard]] inline meta_type type() const noexcept; + + /** + * @brief Sets a meta type for the contained instance. + * @param alias The meta to use with the contained instance. + */ + inline void type(const meta_type &alias) noexcept; + + /** + * @brief Invokes the underlying function, if possible. + * @param id Unique identifier. + * @param args Parameters to use to invoke the function. + * @return A wrapper containing the returned value, if any. + */ + meta_any invoke(id_type id, auto &&...args) const; + + /*! @copydoc invoke */ + meta_any invoke(id_type id, auto &&...args); + + /** + * @brief Sets the value of a given variable. + * @param id Unique identifier. + * @param value Parameter to use to set the underlying variable. + * @return True in case of success, false otherwise. + */ + bool set(id_type id, auto &&value); + + /** + * @brief Gets the value of a given variable. + * @param id Unique identifier. + * @return A wrapper containing the value of the underlying variable. + */ + [[nodiscard]] meta_any get(id_type id) const; + + /*! @copydoc get */ + [[nodiscard]] meta_any get(id_type id); + + /** + * @brief Tries to cast an instance to a given type. + * @tparam Type Type to which to cast the instance. + * @return A (possibly null) pointer to the contained instance. + */ + template + [[nodiscard]] const Type *try_cast() const { + const auto *elem = any_cast(&storage); + return ((elem != nullptr) || !*this) ? elem : static_cast(internal::try_cast(internal::meta_context::from(*ctx), fetch_node(), type_hash>::value(), storage.data())); + } - /*! @copydoc cast */ - template - [[nodiscard]] stl::remove_const_t cast() { - // forces const on non-reference types to make them work also with wrappers for const references - auto *const instance = try_cast>(); - ENTT_ASSERT(instance, "Invalid instance"); - return static_cast(*instance); - } + /*! @copydoc try_cast */ + template + [[nodiscard]] Type *try_cast() { + return ((storage.policy() == any_policy::cref) && !stl::is_const_v) ? nullptr : const_cast(stl::as_const(*this).try_cast>()); + } - /** - * @brief Converts an object in such a way that a given cast becomes viable. - * @param type Meta type to which the cast is requested. - * @return A valid meta object if convertible, an invalid one otherwise. - */ - [[nodiscard]] meta_any allow_cast(const meta_type &type) const; + /** + * @brief Tries to cast an instance to a given type. + * @tparam Type Type to which to cast the instance. + * @return A reference to the contained instance. + */ + template + [[nodiscard]] stl::remove_const_t cast() const { + auto *const instance = try_cast>(); + ENTT_ASSERT(instance, "Invalid instance"); + return static_cast(*instance); + } - /** - * @brief Converts an object in such a way that a given cast becomes viable. - * @param type Meta type to which the cast is requested. - * @return True if convertible, false otherwise. - */ - [[nodiscard]] bool allow_cast(const meta_type &type); + /*! @copydoc cast */ + template + [[nodiscard]] stl::remove_const_t cast() { + // forces const on non-reference types to make them work also with wrappers for const references + auto *const instance = try_cast>(); + ENTT_ASSERT(instance, "Invalid instance"); + return static_cast(*instance); + } - /** - * @brief Converts an object in such a way that a given cast becomes viable. - * @tparam Type Type to which the cast is requested. - * @return A valid meta object if convertible, an invalid one otherwise. - */ - template - [[nodiscard]] meta_any allow_cast() const { - if constexpr(!stl::is_reference_v || stl::is_const_v>) { - if(storage.has_value>()) { - return as_ref(); - } else if(*this) { - if constexpr(stl::is_arithmetic_v> || stl::is_enum_v>) { - if(const auto &from = fetch_node(); from.conversion_helper) { - return meta_any{*ctx, static_cast(from.conversion_helper(nullptr, storage.data()))}; + /** + * @brief Converts an object in such a way that a given cast becomes viable. + * @param type Meta type to which the cast is requested. + * @return A valid meta object if convertible, an invalid one otherwise. + */ + [[nodiscard]] meta_any allow_cast(const meta_type &type) const; + + /** + * @brief Converts an object in such a way that a given cast becomes viable. + * @param type Meta type to which the cast is requested. + * @return True if convertible, false otherwise. + */ + [[nodiscard]] bool allow_cast(const meta_type &type); + + /** + * @brief Converts an object in such a way that a given cast becomes viable. + * @tparam Type Type to which the cast is requested. + * @return A valid meta object if convertible, an invalid one otherwise. + */ + template + [[nodiscard]] meta_any allow_cast() const { + if constexpr(!stl::is_reference_v || stl::is_const_v>) { + if(storage.has_value>()) { + return as_ref(); + } else if(*this) { + if constexpr(stl::is_arithmetic_v> || stl::is_enum_v>) { + if(const auto &from = fetch_node(); from.conversion_helper) { + return meta_any{*ctx, static_cast(from.conversion_helper(nullptr, storage.data()))}; + } } - } - if(const auto &from = fetch_node(); from.details != nullptr) { - if(const auto *elem = internal::find_member(from.details->conv, entt::type_hash>::value()); elem != nullptr) { - return elem->conv(*ctx, storage.data()); - } + if(const auto &from = fetch_node(); from.details != nullptr) { + if(const auto *elem = internal::find_member(from.details->conv, entt::type_hash>::value()); elem != nullptr) { + return elem->conv(*ctx, storage.data()); + } - for(auto &&curr: from.details->base) { - if(auto other = curr.type(internal::meta_context::from(*ctx)).from_void(*ctx, nullptr, curr.cast(storage.data())); curr.id == entt::type_hash>::value()) { - return other; - } else if(auto from_base = stl::as_const(other).template allow_cast(); from_base) { - return from_base; + for(auto &&curr: from.details->base) { + if(auto other = curr.type(internal::meta_context::from(*ctx)).from_void(*ctx, nullptr, curr.cast(storage.data())); curr.id == entt::type_hash>::value()) { + return other; + } else if(auto from_base = stl::as_const(other).template allow_cast(); from_base) { + return from_base; + } } } } } + + return meta_any{meta_ctx_arg, *ctx}; } - return meta_any{meta_ctx_arg, *ctx}; - } + /** + * @brief Converts an object in such a way that a given cast becomes viable. + * @tparam Type Type to which the cast is requested. + * @return True if convertible, false otherwise. + */ + template + [[nodiscard]] bool allow_cast() { + if constexpr(stl::is_reference_v && !stl::is_const_v>) { + return allow_cast &>() && (storage.policy() != any_policy::cref); + } else { + if(storage.has_value>()) { + return true; + } else if(auto other = stl::as_const(*this).allow_cast>(); other) { + if(other.storage.owner()) { + stl::swap(*this, other); + } - /** - * @brief Converts an object in such a way that a given cast becomes viable. - * @tparam Type Type to which the cast is requested. - * @return True if convertible, false otherwise. - */ - template - [[nodiscard]] bool allow_cast() { - if constexpr(stl::is_reference_v && !stl::is_const_v>) { - return allow_cast &>() && (storage.policy() != any_policy::cref); - } else { - if(storage.has_value>()) { - return true; - } else if(auto other = stl::as_const(*this).allow_cast>(); other) { - if(other.storage.owner()) { - stl::swap(*this, other); + return true; } - return true; + return false; } - - return false; } - } - /*! @copydoc any::emplace */ - template - void emplace(auto &&...args) { - storage.emplace(stl::forward(args)...); - auto *prev = stl::exchange(vtable, &basic_vtable>); - node = (prev == vtable) ? node : nullptr; - } + /*! @copydoc any::emplace */ + template + void emplace(auto &&...args) { + storage.emplace(stl::forward(args)...); + auto *prev = stl::exchange(vtable, &basic_vtable>); + node = (prev == vtable) ? node : nullptr; + } - /*! @copydoc any::assign */ - bool assign(const meta_any &other); + /*! @copydoc any::assign */ + bool assign(const meta_any &other); - /*! @copydoc any::assign */ - bool assign(meta_any &&other); + /*! @copydoc any::assign */ + bool assign(meta_any &&other); - /*! @copydoc any::reset */ - void reset() { - storage.reset(); - node = nullptr; - vtable = nullptr; - } + /*! @copydoc any::reset */ + void reset() { + storage.reset(); + node = nullptr; + vtable = nullptr; + } - /** - * @brief Returns a sequence container proxy. - * @return A sequence container proxy for the underlying object. - */ - [[nodiscard]] meta_sequence_container as_sequence_container() noexcept { - meta_sequence_container proxy{}; - if(*this) { vtable(internal::meta_traits::is_sequence_container, *this, &proxy); } - return proxy; - } + /** + * @brief Returns a sequence container proxy. + * @return A sequence container proxy for the underlying object. + */ + [[nodiscard]] meta_sequence_container as_sequence_container() noexcept { + meta_sequence_container proxy{}; + if(*this) { vtable(internal::meta_traits::is_sequence_container, *this, &proxy); } + return proxy; + } - /*! @copydoc as_sequence_container */ - [[nodiscard]] meta_sequence_container as_sequence_container() const noexcept { - meta_sequence_container proxy{}; - if(*this) { vtable(internal::meta_traits::is_sequence_container, as_ref(), &proxy); } - return proxy; - } + /*! @copydoc as_sequence_container */ + [[nodiscard]] meta_sequence_container as_sequence_container() const noexcept { + meta_sequence_container proxy{}; + if(*this) { vtable(internal::meta_traits::is_sequence_container, as_ref(), &proxy); } + return proxy; + } - /** - * @brief Returns an associative container proxy. - * @return An associative container proxy for the underlying object. - */ - [[nodiscard]] meta_associative_container as_associative_container() noexcept { - meta_associative_container proxy{}; - if(*this) { vtable(internal::meta_traits::is_associative_container, *this, &proxy); } - return proxy; - } + /** + * @brief Returns an associative container proxy. + * @return An associative container proxy for the underlying object. + */ + [[nodiscard]] meta_associative_container as_associative_container() noexcept { + meta_associative_container proxy{}; + if(*this) { vtable(internal::meta_traits::is_associative_container, *this, &proxy); } + return proxy; + } - /*! @copydoc as_associative_container */ - [[nodiscard]] meta_associative_container as_associative_container() const noexcept { - meta_associative_container proxy{}; - if(*this) { vtable(internal::meta_traits::is_associative_container, as_ref(), &proxy); } - return proxy; - } + /*! @copydoc as_associative_container */ + [[nodiscard]] meta_associative_container as_associative_container() const noexcept { + meta_associative_container proxy{}; + if(*this) { vtable(internal::meta_traits::is_associative_container, as_ref(), &proxy); } + return proxy; + } - /** - * @brief Indirection operator for dereferencing opaque objects. - * @return A wrapper that shares a reference to an unmanaged object if the - * wrapped element is dereferenceable, an invalid meta any otherwise. - */ - [[nodiscard]] meta_any operator*() noexcept { - meta_any ret{meta_ctx_arg, *ctx}; - if(*this) { vtable(internal::meta_traits::is_pointer, *this, &ret); } - return ret; - } + /** + * @brief Indirection operator for dereferencing opaque objects. + * @return A wrapper that shares a reference to an unmanaged object if the + * wrapped element is dereferenceable, an invalid meta any otherwise. + */ + [[nodiscard]] meta_any operator*() noexcept { + meta_any ret{meta_ctx_arg, *ctx}; + if(*this) { vtable(internal::meta_traits::is_pointer, *this, &ret); } + return ret; + } - /*! @copydoc operator* */ - [[nodiscard]] meta_any operator*() const noexcept { - meta_any ret{meta_ctx_arg, *ctx}; - if(*this) { vtable(internal::meta_traits::is_pointer, as_ref(), &ret); } - return ret; - } + /*! @copydoc operator* */ + [[nodiscard]] meta_any operator*() const noexcept { + meta_any ret{meta_ctx_arg, *ctx}; + if(*this) { vtable(internal::meta_traits::is_pointer, as_ref(), &ret); } + return ret; + } - /*! @copydoc any::operator bool */ - [[nodiscard]] explicit operator bool() const noexcept { - return !(vtable == nullptr); - } + /*! @copydoc any::operator bool */ + [[nodiscard]] explicit operator bool() const noexcept { + return !(vtable == nullptr); + } - /*! @copydoc any::operator== */ - [[nodiscard]] bool operator==(const meta_any &other) const noexcept { - return (ctx == other.ctx) && (!*this == !other) && (storage == other.storage); - } + /*! @copydoc any::operator== */ + [[nodiscard]] bool operator==(const meta_any &other) const noexcept { + return (ctx == other.ctx) && (!*this == !other) && (storage == other.storage); + } - /*! @copydoc any::as_ref */ - [[nodiscard]] meta_any as_ref() noexcept { - return meta_any{*this, storage.as_ref()}; - } + /*! @copydoc any::as_ref */ + [[nodiscard]] meta_any as_ref() noexcept { + return meta_any{*this, storage.as_ref()}; + } - /*! @copydoc any::as_ref */ - [[nodiscard]] meta_any as_ref() const noexcept { - return meta_any{*this, storage.as_ref()}; - } + /*! @copydoc any::as_ref */ + [[nodiscard]] meta_any as_ref() const noexcept { + return meta_any{*this, storage.as_ref()}; + } - /** - * @brief Returns the underlying storage. - * @return The underlyig storage. - */ - [[nodiscard]] const any &base() const noexcept { - return storage; - } + /** + * @brief Returns the underlying storage. + * @return The underlyig storage. + */ + [[nodiscard]] const any &base() const noexcept { + return storage; + } - /** - * @brief Returns the underlying meta context. - * @return The underlying meta context. - */ - [[nodiscard]] const meta_ctx &context() const noexcept { - return *ctx; - } + /** + * @brief Returns the underlying meta context. + * @return The underlying meta context. + */ + [[nodiscard]] const meta_ctx &context() const noexcept { + return *ctx; + } -private: - any storage{}; - const meta_ctx *ctx{&locator::value_or()}; - mutable const internal::meta_type_node *node{}; - vtable_type *vtable{}; -}; - -/** - * @brief Forwards its argument and avoids copies for lvalue references. - * @param value Parameter to use to construct the instance. - * @param ctx The context from which to search for meta types. - * @return A properly initialized and not necessarily owning wrapper. - */ -[[nodiscard]] meta_any forward_as_meta(const meta_ctx &ctx, auto &&value) { - return meta_any{ctx, stl::in_place_type, stl::forward(value)}; -} - -/** - * @brief Forwards its argument and avoids copies for lvalue references. - * @param value Parameter to use to construct the instance. - * @return A properly initialized and not necessarily owning wrapper. - */ -[[nodiscard]] meta_any forward_as_meta(auto &&value) { - return forward_as_meta(locator::value_or(), stl::forward(value)); -} - -/*! @brief Opaque pointers to instances of any type. */ -class meta_handle { - meta_handle(int, auto &value, auto &&...args) - requires stl::same_as, meta_any> - : any{stl::forward(args)..., value.as_ref()} {} - - meta_handle(char, auto &value, auto &&...args) - : any{stl::forward(args)..., stl::in_place_type, value} {} - -public: - /*! Default constructor. */ - meta_handle() = default; + private: + any storage{}; + const meta_ctx *ctx{&locator::value_or()}; + mutable const internal::meta_type_node *node{}; + vtable_type *vtable{}; + }; /** - * @brief Creates a handle that points to an unmanaged object. + * @brief Forwards its argument and avoids copies for lvalue references. + * @param value Parameter to use to construct the instance. * @param ctx The context from which to search for meta types. - * @param value An instance of an object to use to initialize the handle. - */ - meta_handle(const meta_ctx &ctx, auto &value) - requires (!stl::same_as, meta_handle>) - : meta_handle{0, value, ctx} {} + * @return A properly initialized and not necessarily owning wrapper. + */ + [[nodiscard]] meta_any forward_as_meta(const meta_ctx &ctx, auto &&value) { + return meta_any{ctx, stl::in_place_type, stl::forward(value)}; + } + + /** + * @brief Forwards its argument and avoids copies for lvalue references. + * @param value Parameter to use to construct the instance. + * @return A properly initialized and not necessarily owning wrapper. + */ + [[nodiscard]] meta_any forward_as_meta(auto &&value) { + return forward_as_meta(locator::value_or(), stl::forward(value)); + } + + /*! @brief Opaque pointers to instances of any type. */ + class meta_handle { + meta_handle(int, auto &value, auto &&...args) + requires stl::same_as, meta_any> + : any{stl::forward(args)..., value.as_ref()} {} + + meta_handle(char, auto &value, auto &&...args) + : any{stl::forward(args)..., stl::in_place_type, value} {} + + public: + /*! Default constructor. */ + meta_handle() = default; + + /** + * @brief Creates a handle that points to an unmanaged object. + * @param ctx The context from which to search for meta types. + * @param value An instance of an object to use to initialize the handle. + */ + meta_handle(const meta_ctx &ctx, auto &value) + requires (!stl::same_as, meta_handle>) + : meta_handle{0, value, ctx} {} + + /** + * @brief Creates a handle that points to an unmanaged object. + * @param value An instance of an object to use to initialize the handle. + */ + meta_handle(auto &value) + requires (!stl::same_as, meta_handle>) + : meta_handle{0, value} {} + + /** + * @brief Context aware move constructor. + * @param area The context from which to search for meta types. + * @param other The instance to move from. + */ + meta_handle(const meta_ctx &area, meta_handle &&other) + : any{area, stl::move(other.any)} {} + + /*! @brief Default copy constructor, deleted on purpose. */ + meta_handle(const meta_handle &) = delete; + + /*! @brief Default move constructor. */ + meta_handle(meta_handle &&) = default; + + /*! @brief Default destructor. */ + ~meta_handle() = default; + + /** + * @brief Default copy assignment operator, deleted on purpose. + * @return This meta handle. + */ + meta_handle &operator=(const meta_handle &) = delete; + + /** + * @brief Default move assignment operator. + * @return This meta handle. + */ + meta_handle &operator=(meta_handle &&) = default; + + /** + * @brief Returns false if a handle is invalid, true otherwise. + * @return False if the handle is invalid, true otherwise. + */ + [[nodiscard]] explicit operator bool() const noexcept { + return static_cast(any); + } - /** - * @brief Creates a handle that points to an unmanaged object. - * @param value An instance of an object to use to initialize the handle. - */ - meta_handle(auto &value) - requires (!stl::same_as, meta_handle>) - : meta_handle{0, value} {} + /** + * @brief Access operator for accessing the contained opaque object. + * @return A wrapper that shares a reference to an unmanaged object. + */ + [[nodiscard]] meta_any *operator->() { + return &any; + } + + private: + meta_any any{}; + }; + + /*! @brief Opaque wrapper for user defined data of any type. */ + struct meta_custom { + /*! @brief Default constructor. */ + meta_custom() noexcept = default; + + /** + * @brief Basic constructor for meta objects. + * @param curr The underlying node with which to construct the instance. + */ + meta_custom(const internal::meta_custom_node &curr) noexcept + : node{&curr} {} + + /** + * @brief Generic conversion operator. + * @tparam Type Type to which conversion is requested. + */ + template + [[nodiscard]] operator Type *() const noexcept { + return ((node != nullptr) && (type_hash>::value() == node->id)) ? static_cast(node->value.get()) : nullptr; + } + + /** + * @brief Generic conversion operator. + * @tparam Type Type to which conversion is requested. + */ + template + [[nodiscard]] operator Type &() const noexcept { + ENTT_ASSERT(static_cast(*this) != nullptr, "Invalid type"); + return *static_cast(node->value.get()); + } + + private: + const internal::meta_custom_node *node{}; + }; /** - * @brief Context aware move constructor. - * @param area The context from which to search for meta types. - * @param other The instance to move from. + * @brief Common opaque wrapper for meta objects. + * @tparam Type Underlying meta node type. */ - meta_handle(const meta_ctx &area, meta_handle &&other) - : any{area, stl::move(other.any)} {} + template + struct meta_object: protected internal::basic_meta_object { + /*! @brief Underlying meta node type. */ + using node_type = Type; + /*! @brief Unsigned integer type. */ + using size_type = std::size_t; + + /*! @brief Default constructor. */ + meta_object() noexcept = default; + + /** + * @brief Context aware constructor for meta objects. + * @param area The context from which to search for meta types. + * @param curr The underlying node with which to construct the instance. + */ + meta_object(const meta_ctx &area, const node_type &curr) noexcept + : internal::basic_meta_object{&curr, &area} { + } - /*! @brief Default copy constructor, deleted on purpose. */ - meta_handle(const meta_handle &) = delete; + /** + * @brief Returns true if an object is valid, false otherwise. + * @return True if the object is valid, false otherwise. + */ + [[nodiscard]] explicit operator bool() const noexcept { + return (this->node != nullptr); + } - /*! @brief Default move constructor. */ - meta_handle(meta_handle &&) = default; + /** + * @brief Checks if two objects refer to the same type. + * @param other The object with which to compare. + * @return True if the objects refer to the same type, false otherwise. + */ + [[nodiscard]] bool operator==(const meta_object &other) const noexcept { + return (this->ctx == other.ctx) && (this->node == other.node); + } + }; + + /*! @brief Opaque wrapper for data members. */ + struct meta_data: meta_object { + using meta_object::meta_object; + + /** + * @brief Returns the name assigned to a data member, if any. + * @return The name assigned to the data member, if any. + */ + [[nodiscard]] stl::string_view name() const noexcept { + return (node_or_assert().name == nullptr) ? stl::string_view{} : stl::string_view{node_or_assert().name}; + } - /*! @brief Default destructor. */ - ~meta_handle() = default; + /** + * @brief Indicates whether a data member is constant or not. + * @return True if the data member is constant, false otherwise. + */ + [[nodiscard]] bool is_const() const noexcept { + return !!(node_or_assert().traits & internal::meta_traits::is_const); + } - /** - * @brief Default copy assignment operator, deleted on purpose. - * @return This meta handle. - */ - meta_handle &operator=(const meta_handle &) = delete; + /** + * @brief Indicates whether a data member is static or not. + * @return True if the data member is static, false otherwise. + */ + [[nodiscard]] bool is_static() const noexcept { + return !!(node_or_assert().traits & internal::meta_traits::is_static); + } - /** - * @brief Default move assignment operator. - * @return This meta handle. - */ - meta_handle &operator=(meta_handle &&) = default; + /*! @copydoc meta_any::type */ + [[nodiscard]] inline meta_type type() const noexcept; + + /** + * @brief Sets the value of a given variable. + * @tparam Instance Type of instance to operate on. + * @param instance An instance that fits the underlying type. + * @param value Parameter to use to set the underlying variable. + * @return True in case of success, false otherwise. + */ + template + // NOLINTNEXTLINE(modernize-use-nodiscard) + bool set(Instance &&instance, auto &&value) const { + return node_or_assert().set(meta_handle{*ctx, stl::forward(instance)}, meta_any{*ctx, stl::forward(value)}); + } - /** - * @brief Returns false if a handle is invalid, true otherwise. - * @return False if the handle is invalid, true otherwise. - */ - [[nodiscard]] explicit operator bool() const noexcept { - return static_cast(any); - } + /** + * @brief Gets the value of a given variable. + * @tparam Instance Type of instance to operate on. + * @param instance An instance that fits the underlying type. + * @return A wrapper containing the value of the underlying variable. + */ + template + [[nodiscard]] meta_any get(Instance &&instance) const { + return node_or_assert().get(meta_handle{*ctx, stl::forward(instance)}); + } - /** - * @brief Access operator for accessing the contained opaque object. - * @return A wrapper that shares a reference to an unmanaged object. - */ - [[nodiscard]] meta_any *operator->() { - return &any; - } + /** + * @brief Returns the type of the argument of a data member. + * @return The type of the argument of a data member. + */ + [[nodiscard]] inline meta_type arg() const noexcept; + + /** + * @brief Returns all meta traits for a given meta object. + * @tparam Type The type to convert the meta traits to. + * @return The registered meta traits, if any. + */ + template + [[nodiscard]] Type traits() const noexcept { + return internal::meta_to_user_traits(node_or_assert().traits); + } -private: - meta_any any{}; -}; + /** + * @brief Returns user defined data for a given meta object. + * @return User defined arbitrary data. + */ + [[nodiscard]] meta_custom custom() const noexcept { + return {node_or_assert().custom}; + } + }; + + /*! @brief Opaque wrapper for member functions. */ + struct meta_func: meta_object { + using meta_object::meta_object; + + /** + * @brief Returns the name assigned to a member function, if any. + * @return The name assigned to the member function, if any. + */ + [[nodiscard]] stl::string_view name() const noexcept { + return (node_or_assert().name == nullptr) ? stl::string_view{} : stl::string_view{node_or_assert().name}; + } -/*! @brief Opaque wrapper for user defined data of any type. */ -struct meta_custom { - /*! @brief Default constructor. */ - meta_custom() noexcept = default; + /** + * @brief Returns the number of arguments accepted by a member function. + * @return The number of arguments accepted by the member function. + */ + [[nodiscard]] size_type arity() const noexcept { + return node_or_assert().arity; + } - /** - * @brief Basic constructor for meta objects. - * @param curr The underlying node with which to construct the instance. - */ - meta_custom(const internal::meta_custom_node &curr) noexcept - : node{&curr} {} + /** + * @brief Indicates whether a member function is constant or not. + * @return True if the member function is constant, false otherwise. + */ + [[nodiscard]] bool is_const() const noexcept { + return !!(node_or_assert().traits & internal::meta_traits::is_const); + } - /** - * @brief Generic conversion operator. - * @tparam Type Type to which conversion is requested. - */ - template - [[nodiscard]] operator Type *() const noexcept { - return ((node != nullptr) && (type_hash>::value() == node->id)) ? static_cast(node->value.get()) : nullptr; - } + /** + * @brief Indicates whether a member function is static or not. + * @return True if the member function is static, false otherwise. + */ + [[nodiscard]] bool is_static() const noexcept { + return !!(node_or_assert().traits & internal::meta_traits::is_static); + } - /** - * @brief Generic conversion operator. - * @tparam Type Type to which conversion is requested. - */ - template - [[nodiscard]] operator Type &() const noexcept { - ENTT_ASSERT(static_cast(*this) != nullptr, "Invalid type"); - return *static_cast(node->value.get()); - } + /** + * @brief Returns the return type of a member function. + * @return The return type of the member function. + */ + [[nodiscard]] inline meta_type ret() const noexcept; + + /** + * @brief Returns the type of the i-th argument of a member function. + * @param index Index of the argument of which to return the type. + * @return The type of the i-th argument of a member function. + */ + [[nodiscard]] inline meta_type arg(size_type index) const noexcept; + + /** + * @brief Invokes the underlying function, if possible. + * @tparam Instance Type of instance to operate on. + * @param instance An instance that fits the underlying type. + * @param args Parameters to use to invoke the function. + * @param sz Number of parameters to use to invoke the function. + * @return A wrapper containing the returned value, if any. + */ + template + meta_any invoke(Instance &&instance, meta_any *const args, const size_type sz) const { + return (sz == arity()) ? node_or_assert().invoke(meta_handle{*ctx, stl::forward(instance)}, args) : meta_any{meta_ctx_arg, *ctx}; + } -private: - const internal::meta_custom_node *node{}; -}; + /** + * @copybrief invoke + * @tparam Instance Type of instance to operate on. + * @param instance An instance that fits the underlying type. + * @param args Parameters to use to invoke the function. + * @return A wrapper containing the returned value, if any. + */ + template + // NOLINTNEXTLINE(modernize-use-nodiscard) + meta_any invoke(Instance &&instance, auto &&...args) const { + return invoke(stl::forward(instance), stl::array{meta_any{*ctx, stl::forward(args)}...}.data(), sizeof...(args)); + } -/** - * @brief Common opaque wrapper for meta objects. - * @tparam Type Underlying meta node type. - */ -template -struct meta_object: protected internal::basic_meta_object { - /*! @brief Underlying meta node type. */ - using node_type = Type; - /*! @brief Unsigned integer type. */ - using size_type = std::size_t; + /*! @copydoc meta_data::traits */ + template + [[nodiscard]] Type traits() const noexcept { + return internal::meta_to_user_traits(node_or_assert().traits); + } - /*! @brief Default constructor. */ - meta_object() noexcept = default; + /*! @copydoc meta_data::custom */ + [[nodiscard]] meta_custom custom() const noexcept { + return {node_or_assert().custom}; + } - /** - * @brief Context aware constructor for meta objects. - * @param area The context from which to search for meta types. - * @param curr The underlying node with which to construct the instance. - */ - meta_object(const meta_ctx &area, const node_type &curr) noexcept - : internal::basic_meta_object{&curr, &area} { - } + /** + * @brief Returns the next overload of a given function, if any. + * @return The next overload of the given function, if any. + */ + [[nodiscard]] meta_func next() const { + return (node_or_assert().next != nullptr) ? meta_func{*ctx, *node_or_assert().next} : meta_func{}; + } + }; - /** - * @brief Returns true if an object is valid, false otherwise. - * @return True if the object is valid, false otherwise. - */ - [[nodiscard]] explicit operator bool() const noexcept { - return (this->node != nullptr); - } + /*! @brief Opaque wrapper for base types. */ + struct meta_base: meta_object { + using meta_object::meta_object; - /** - * @brief Checks if two objects refer to the same type. - * @param other The object with which to compare. - * @return True if the objects refer to the same type, false otherwise. - */ - [[nodiscard]] bool operator==(const meta_object &other) const noexcept { - return (this->ctx == other.ctx) && (this->node == other.node); - } -}; + /*! @copydoc meta_any::type */ + [[nodiscard]] inline meta_type type() const noexcept; + }; -/*! @brief Opaque wrapper for data members. */ -struct meta_data: meta_object { - using meta_object::meta_object; + /*! @brief Opaque wrapper for types. */ + class meta_type { + friend class meta_any; - /** - * @brief Returns the name assigned to a data member, if any. - * @return The name assigned to the data member, if any. - */ - [[nodiscard]] stl::string_view name() const noexcept { - return (node_or_assert().name == nullptr) ? stl::string_view{} : stl::string_view{node_or_assert().name}; - } + [[nodiscard]] const auto &fetch_node() const { + return (node == nullptr) ? internal::resolve(internal::meta_context::from(*ctx)) : *node; + } - /** - * @brief Indicates whether a data member is constant or not. - * @return True if the data member is constant, false otherwise. - */ - [[nodiscard]] bool is_const() const noexcept { - return !!(node_or_assert().traits & internal::meta_traits::is_const); - } + [[nodiscard]] auto lookup(meta_any *const args, const internal::meta_type_node::size_type sz, [[maybe_unused]] bool constness, auto next) const { + decltype(next()) candidate = nullptr; + size_type same{}; + bool ambiguous{}; - /** - * @brief Indicates whether a data member is static or not. - * @return True if the data member is static, false otherwise. - */ - [[nodiscard]] bool is_static() const noexcept { - return !!(node_or_assert().traits & internal::meta_traits::is_static); - } + for(auto curr = next(); curr; curr = next()) { + if constexpr(stl::is_same_v, internal::meta_func_node>) { + if(constness && !(curr->traits & internal::meta_traits::is_const)) { + continue; + } + } - /*! @copydoc meta_any::type */ - [[nodiscard]] inline meta_type type() const noexcept; + if(curr->arity == sz) { + size_type match{}; + size_type pos{}; - /** - * @brief Sets the value of a given variable. - * @tparam Instance Type of instance to operate on. - * @param instance An instance that fits the underlying type. - * @param value Parameter to use to set the underlying variable. - * @return True in case of success, false otherwise. - */ - template - // NOLINTNEXTLINE(modernize-use-nodiscard) - bool set(Instance &&instance, auto &&value) const { - return node_or_assert().set(meta_handle{*ctx, stl::forward(instance)}, meta_any{*ctx, stl::forward(value)}); - } + // NOLINTBEGIN(cppcoreguidelines-pro-bounds-pointer-arithmetic) - waiting for C++20 (and stl::span) + for(; pos < sz && args[pos]; ++pos) { + const auto other = curr->arg(*ctx, pos); + const auto type = args[pos].type(); - /** - * @brief Gets the value of a given variable. - * @tparam Instance Type of instance to operate on. - * @param instance An instance that fits the underlying type. - * @return A wrapper containing the value of the underlying variable. - */ - template - [[nodiscard]] meta_any get(Instance &&instance) const { - return node_or_assert().get(meta_handle{*ctx, stl::forward(instance)}); - } + if(const auto &info = other.info(); info == type.info()) { + ++match; + } else if(!(type.fetch_node().conversion_helper && other.fetch_node().conversion_helper) && !(type.fetch_node().details && (internal::find_member(type.fetch_node().details->base, info.hash()) || internal::find_member(type.fetch_node().details->conv, info.hash())))) { + break; + } + } + // NOLINTEND(cppcoreguidelines-pro-bounds-pointer-arithmetic) + + if(pos == sz) { + if(!candidate || match > same) { + candidate = curr; + same = match; + ambiguous = false; + } else if(match == same) { + if constexpr(stl::is_same_v, internal::meta_func_node>) { + if(!!(curr->traits & internal::meta_traits::is_const) != !!(candidate->traits & internal::meta_traits::is_const)) { + candidate = !!(candidate->traits & internal::meta_traits::is_const) ? curr : candidate; + ambiguous = false; + continue; + } + } - /** - * @brief Returns the type of the argument of a data member. - * @return The type of the argument of a data member. - */ - [[nodiscard]] inline meta_type arg() const noexcept; + ambiguous = true; + } + } + } + } - /** - * @brief Returns all meta traits for a given meta object. - * @tparam Type The type to convert the meta traits to. - * @return The registered meta traits, if any. - */ - template - [[nodiscard]] Type traits() const noexcept { - return internal::meta_to_user_traits(node_or_assert().traits); - } + return ambiguous ? nullptr : candidate; + } - /** - * @brief Returns user defined data for a given meta object. - * @return User defined arbitrary data. - */ - [[nodiscard]] meta_custom custom() const noexcept { - return {node_or_assert().custom}; - } -}; + public: + /*! @brief Unsigned integer type. */ + using size_type = internal::meta_type_node::size_type; + + /*! @brief Default constructor. */ + meta_type() noexcept = default; + + /** + * @brief Context aware constructor for meta objects. + * @param area The context from which to search for meta types. + * @param curr The underlying node with which to construct the instance. + */ + meta_type(const meta_ctx &area, const internal::meta_type_node &curr) noexcept + : node{&curr}, + ctx{&area} {} + + /** + * @brief Returns the type info object of the underlying type. + * @return The type info object of the underlying type. + */ + [[nodiscard]] const type_info &info() const noexcept { + return *fetch_node().info; + } -/*! @brief Opaque wrapper for member functions. */ -struct meta_func: meta_object { - using meta_object::meta_object; + /** + * @brief Returns the alias assigned to a type. + * @return The alias assigned to the type. + */ + [[nodiscard]] id_type alias() const noexcept { + return fetch_node().alias; + } - /** - * @brief Returns the name assigned to a member function, if any. - * @return The name assigned to the member function, if any. - */ - [[nodiscard]] stl::string_view name() const noexcept { - return (node_or_assert().name == nullptr) ? stl::string_view{} : stl::string_view{node_or_assert().name}; - } + /** + * @brief Returns the name assigned to a type, if any. + * @return The name assigned to the type, if any. + */ + [[nodiscard]] stl::string_view name() const noexcept { + return (fetch_node().name == nullptr) ? stl::string_view{} : stl::string_view{fetch_node().name}; + } - /** - * @brief Returns the number of arguments accepted by a member function. - * @return The number of arguments accepted by the member function. - */ - [[nodiscard]] size_type arity() const noexcept { - return node_or_assert().arity; - } + /** + * @brief Returns the size of the underlying type if known. + * @return The size of the underlying type if known, 0 otherwise. + */ + [[nodiscard]] size_type size_of() const noexcept { + return fetch_node().size_of; + } - /** - * @brief Indicates whether a member function is constant or not. - * @return True if the member function is constant, false otherwise. - */ - [[nodiscard]] bool is_const() const noexcept { - return !!(node_or_assert().traits & internal::meta_traits::is_const); - } + /** + * @brief Checks whether a type refers to an arithmetic type or not. + * @return True if the underlying type is an arithmetic type, false + * otherwise. + */ + [[nodiscard]] bool is_arithmetic() const noexcept { + return !!(fetch_node().traits & internal::meta_traits::is_arithmetic); + } - /** - * @brief Indicates whether a member function is static or not. - * @return True if the member function is static, false otherwise. - */ - [[nodiscard]] bool is_static() const noexcept { - return !!(node_or_assert().traits & internal::meta_traits::is_static); - } + /** + * @brief Checks whether a type refers to an integral type or not. + * @return True if the underlying type is an integral type, false otherwise. + */ + [[nodiscard]] bool is_integral() const noexcept { + return !!(fetch_node().traits & internal::meta_traits::is_integral); + } - /** - * @brief Returns the return type of a member function. - * @return The return type of the member function. - */ - [[nodiscard]] inline meta_type ret() const noexcept; + /** + * @brief Checks whether a type refers to a signed type or not. + * @return True if the underlying type is a signed type, false otherwise. + */ + [[nodiscard]] bool is_signed() const noexcept { + return !!(fetch_node().traits & internal::meta_traits::is_signed); + } - /** - * @brief Returns the type of the i-th argument of a member function. - * @param index Index of the argument of which to return the type. - * @return The type of the i-th argument of a member function. - */ - [[nodiscard]] inline meta_type arg(size_type index) const noexcept; + /** + * @brief Checks whether a type refers to an array type or not. + * @return True if the underlying type is an array type, false otherwise. + */ + [[nodiscard]] bool is_array() const noexcept { + return !!(fetch_node().traits & internal::meta_traits::is_array); + } - /** - * @brief Invokes the underlying function, if possible. - * @tparam Instance Type of instance to operate on. - * @param instance An instance that fits the underlying type. - * @param args Parameters to use to invoke the function. - * @param sz Number of parameters to use to invoke the function. - * @return A wrapper containing the returned value, if any. - */ - template - meta_any invoke(Instance &&instance, meta_any *const args, const size_type sz) const { - return (sz == arity()) ? node_or_assert().invoke(meta_handle{*ctx, stl::forward(instance)}, args) : meta_any{meta_ctx_arg, *ctx}; - } + /** + * @brief Checks whether a type refers to an enum or not. + * @return True if the underlying type is an enum, false otherwise. + */ + [[nodiscard]] bool is_enum() const noexcept { + return !!(fetch_node().traits & internal::meta_traits::is_enum); + } - /** - * @copybrief invoke - * @tparam Instance Type of instance to operate on. - * @param instance An instance that fits the underlying type. - * @param args Parameters to use to invoke the function. - * @return A wrapper containing the returned value, if any. - */ - template - // NOLINTNEXTLINE(modernize-use-nodiscard) - meta_any invoke(Instance &&instance, auto &&...args) const { - return invoke(stl::forward(instance), stl::array{meta_any{*ctx, stl::forward(args)}...}.data(), sizeof...(args)); - } + /** + * @brief Checks whether a type refers to a class or not. + * @return True if the underlying type is a class, false otherwise. + */ + [[nodiscard]] bool is_class() const noexcept { + return !!(fetch_node().traits & internal::meta_traits::is_class); + } - /*! @copydoc meta_data::traits */ - template - [[nodiscard]] Type traits() const noexcept { - return internal::meta_to_user_traits(node_or_assert().traits); - } + /** + * @brief Checks whether a type refers to a pointer or not. + * @return True if the underlying type is a pointer, false otherwise. + */ + [[nodiscard]] bool is_pointer() const noexcept { + return !!(fetch_node().traits & internal::meta_traits::is_pointer); + } + + /** + * @brief Provides the type for which the pointer is defined. + * @return The type for which the pointer is defined or this type if it + * doesn't refer to a pointer type. + */ + [[nodiscard]] meta_type remove_pointer() const noexcept { + return meta_type{*ctx, fetch_node().remove_pointer(internal::meta_context::from(*ctx))}; + } + + /** + * @brief Checks whether a type is a pointer-like type or not. + * @return True if the underlying type is pointer-like, false otherwise. + */ + [[nodiscard]] bool is_pointer_like() const noexcept { + return !!(fetch_node().traits & internal::meta_traits::is_pointer_like); + } - /*! @copydoc meta_data::custom */ - [[nodiscard]] meta_custom custom() const noexcept { - return {node_or_assert().custom}; - } + /** + * @brief Checks whether a type refers to a sequence container or not. + * @return True if the type is a sequence container, false otherwise. + */ + [[nodiscard]] bool is_sequence_container() const noexcept { + return !!(fetch_node().traits & internal::meta_traits::is_sequence_container); + } - /** - * @brief Returns the next overload of a given function, if any. - * @return The next overload of the given function, if any. - */ - [[nodiscard]] meta_func next() const { - return (node_or_assert().next != nullptr) ? meta_func{*ctx, *node_or_assert().next} : meta_func{}; - } -}; + /** + * @brief Checks whether a type refers to an associative container or not. + * @return True if the type is an associative container, false otherwise. + */ + [[nodiscard]] bool is_associative_container() const noexcept { + return !!(fetch_node().traits & internal::meta_traits::is_associative_container); + } + + /** + * @brief Checks whether a type refers to a template specialization or not. + * @return True if the type is a template specialization, false otherwise. + */ + [[nodiscard]] bool is_template_specialization() const noexcept { + return (fetch_node().templ.arity != 0u); + } -/*! @brief Opaque wrapper for base types. */ -struct meta_base: meta_object { - using meta_object::meta_object; + /** + * @brief Returns the number of template arguments. + * @return The number of template arguments. + */ + [[nodiscard]] size_type template_arity() const noexcept { + return fetch_node().templ.arity; + } - /*! @copydoc meta_any::type */ - [[nodiscard]] inline meta_type type() const noexcept; -}; + /** + * @brief Returns a tag for the class template of the underlying type. + * @return The tag for the class template of the underlying type. + */ + [[nodiscard]] meta_type template_type() const noexcept { + return (fetch_node().templ.resolve != nullptr) ? meta_type{*ctx, fetch_node().templ.resolve(internal::meta_context::from(*ctx))} : meta_type{}; + } -/*! @brief Opaque wrapper for types. */ -class meta_type { - friend class meta_any; + /** + * @brief Returns the type of the i-th template argument of a type. + * @param index Index of the template argument of which to return the type. + * @return The type of the i-th template argument of a type. + */ + [[nodiscard]] meta_type template_arg(const size_type index) const noexcept { + return index < template_arity() ? meta_type{*ctx, fetch_node().templ.arg(internal::meta_context::from(*ctx), index)} : meta_type{}; + } - [[nodiscard]] const auto &fetch_node() const { - return (node == nullptr) ? internal::resolve(internal::meta_context::from(*ctx)) : *node; - } + /** + * @brief Checks if a type supports direct casting to another type. + * @param other The meta type to test for. + * @return True if direct casting is allowed, false otherwise. + */ + [[nodiscard]] bool can_cast(const meta_type &other) const noexcept { + // casting this is UB in all cases but we aren't going to use the resulting pointer, so... + return other && ((*this == other) || (internal::try_cast(internal::meta_context::from(*ctx), fetch_node(), other.fetch_node().info->hash(), this) != nullptr)); + } - [[nodiscard]] auto lookup(meta_any *const args, const internal::meta_type_node::size_type sz, [[maybe_unused]] bool constness, auto next) const { - decltype(next()) candidate = nullptr; - size_type same{}; - bool ambiguous{}; + /** + * @brief Checks whether a type supports conversion to another type. + * @param other The meta type to test for. + * @return True if the conversion is allowed, false otherwise. + */ + [[nodiscard]] bool can_convert(const meta_type &other) const noexcept { + if(const auto &to = other.info().hash(); (info().hash() == to) || ((fetch_node().conversion_helper != nullptr) && (other.is_arithmetic() || other.is_enum()))) { + return true; + } else if(const auto &from = fetch_node(); from.details) { + if(const auto *elem = internal::find_member(from.details->conv, to); elem != nullptr) { + return true; + } - for(auto curr = next(); curr; curr = next()) { - if constexpr(stl::is_same_v, internal::meta_func_node>) { - if(constness && !(curr->traits & internal::meta_traits::is_const)) { - continue; + for(auto &&curr: from.details->base) { + if(curr.id == to || meta_type{*ctx, curr.type(internal::meta_context::from(*ctx))}.can_convert(other)) { + return true; + } } } - if(curr->arity == sz) { - size_type match{}; - size_type pos{}; + return false; + } - // NOLINTBEGIN(cppcoreguidelines-pro-bounds-pointer-arithmetic) - waiting for C++20 (and stl::span) - for(; pos < sz && args[pos]; ++pos) { - const auto other = curr->arg(*ctx, pos); - const auto type = args[pos].type(); + /** + * @brief Returns a range to visit registered top-level base meta types. + * @return An iterable range to visit registered top-level base meta types. + */ + [[nodiscard]] meta_range base() const noexcept { + using range_type = meta_range; + return fetch_node().details ? range_type{{*ctx, fetch_node().details->base.cbegin()}, {*ctx, fetch_node().details->base.cend()}} : range_type{}; + } - if(const auto &info = other.info(); info == type.info()) { - ++match; - } else if(!(type.fetch_node().conversion_helper && other.fetch_node().conversion_helper) && !(type.fetch_node().details && (internal::find_member(type.fetch_node().details->base, info.hash()) || internal::find_member(type.fetch_node().details->conv, info.hash())))) { - break; - } - } - // NOLINTEND(cppcoreguidelines-pro-bounds-pointer-arithmetic) - - if(pos == sz) { - if(!candidate || match > same) { - candidate = curr; - same = match; - ambiguous = false; - } else if(match == same) { - if constexpr(stl::is_same_v, internal::meta_func_node>) { - if(!!(curr->traits & internal::meta_traits::is_const) != !!(candidate->traits & internal::meta_traits::is_const)) { - candidate = !!(candidate->traits & internal::meta_traits::is_const) ? curr : candidate; - ambiguous = false; - continue; - } - } + /** + * @brief Returns a range to visit registered top-level meta data. + * @return An iterable range to visit registered top-level meta data. + */ + [[nodiscard]] meta_range data() const noexcept { + using range_type = meta_range; + return fetch_node().details ? range_type{{*ctx, fetch_node().details->data.cbegin()}, {*ctx, fetch_node().details->data.cend()}} : range_type{}; + } - ambiguous = true; - } + /** + * @brief Lookup utility for meta data (bases are also visited). + * @param id Unique identifier. + * @param recursive True for a search in the base classes, false otherwise. + * @return The registered meta data for the given identifier, if any. + */ + [[nodiscard]] meta_data data(const id_type id, const bool recursive = true) const { + const auto *elem = internal::look_for<&internal::meta_type_descriptor::data>(internal::meta_context::from(*ctx), fetch_node(), id, recursive); + return (elem != nullptr) ? meta_data{*ctx, *elem} : meta_data{}; + } + + /** + * @brief Returns a range to visit registered top-level functions. + * @return An iterable range to visit registered top-level functions. + */ + [[nodiscard]] meta_range func() const noexcept { + using return_type = meta_range; + return fetch_node().details ? return_type{{*ctx, fetch_node().details->func.cbegin()}, {*ctx, fetch_node().details->func.cend()}} : return_type{}; + } + + /** + * @brief Lookup utility for meta functions (bases are also visited). + * @param id Unique identifier. + * @param recursive True for a search in the base classes, false otherwise. + * @return The registered meta function for the given identifier, if any. + */ + [[nodiscard]] meta_func func(const id_type id, const bool recursive = true) const { + const auto *elem = internal::look_for<&internal::meta_type_descriptor::func>(internal::meta_context::from(*ctx), fetch_node(), id, recursive); + return (elem != nullptr) ? meta_func{*ctx, *elem} : meta_func{}; + } + + /** + * @brief Creates an instance of the underlying type, if possible. + * @param args Parameters to use to construct the instance. + * @param sz Number of parameters to use to construct the instance. + * @return A wrapper containing the new instance, if any. + */ + [[nodiscard]] meta_any construct(meta_any *const args, const size_type sz) const { + if(const auto &ref = fetch_node(); ref.details) { + if(const auto *candidate = lookup(args, sz, false, [first = ref.details->ctor.cbegin(), last = ref.details->ctor.cend()]() mutable { return first == last ? nullptr : &*(first++); }); candidate) { + return candidate->invoke(*ctx, args); } } + + if(const auto &ref = fetch_node(); (sz == 0u) && (ref.default_constructor != nullptr)) { + return ref.default_constructor(*ctx); + } + + return meta_any{meta_ctx_arg, *ctx}; } - return ambiguous ? nullptr : candidate; - } + /** + * @copybrief construct + * @param args Parameters to use to construct the instance. + * @return A wrapper containing the new instance, if any. + */ + [[nodiscard]] meta_any construct(auto &&...args) const { + return construct(stl::array{meta_any{*ctx, stl::forward(args)}...}.data(), sizeof...(args)); + // NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks) + } -public: - /*! @brief Unsigned integer type. */ - using size_type = internal::meta_type_node::size_type; + /** + * @brief Wraps an opaque element of the underlying type. + * @param elem A valid pointer to an element of the underlying type. + * @param transfer_ownership True to transfer ownership, false otherwise. + * @return A wrapper that references the given instance. + */ + [[nodiscard]] meta_any from_void(void *elem, bool transfer_ownership = false) const { + return ((elem != nullptr) && (fetch_node().from_void != nullptr)) ? fetch_node().from_void(*ctx, elem, transfer_ownership ? elem : nullptr) : meta_any{meta_ctx_arg, *ctx}; + } - /*! @brief Default constructor. */ - meta_type() noexcept = default; + /** + * @brief Wraps an opaque element of the underlying type. + * @param elem A valid pointer to an element of the underlying type. + * @return A wrapper that references the given instance. + */ + [[nodiscard]] meta_any from_void(const void *elem) const { + return ((elem != nullptr) && (fetch_node().from_void != nullptr)) ? fetch_node().from_void(*ctx, nullptr, elem) : meta_any{meta_ctx_arg, *ctx}; + } - /** - * @brief Context aware constructor for meta objects. - * @param area The context from which to search for meta types. - * @param curr The underlying node with which to construct the instance. - */ - meta_type(const meta_ctx &area, const internal::meta_type_node &curr) noexcept - : node{&curr}, - ctx{&area} {} + /** + * @brief Invokes a function given an identifier, if possible. + * @tparam Instance Type of instance to operate on. + * @param id Unique identifier. + * @param instance An instance that fits the underlying type. + * @param args Parameters to use to invoke the function. + * @param sz Number of parameters to use to invoke the function. + * @return A wrapper containing the returned value, if any. + */ + template + // NOLINTNEXTLINE(modernize-use-nodiscard) + meta_any invoke(const id_type id, Instance &&instance, meta_any *const args, const size_type sz) const { + meta_handle wrapped{*ctx, stl::forward(instance)}; + + if(const auto &ref = fetch_node(); ref.details) { + if(auto *elem = internal::find_member(ref.details->func, id); elem != nullptr) { + if(const auto *candidate = lookup(args, sz, (wrapped->base().policy() == any_policy::cref), [curr = elem]() mutable { return (curr != nullptr) ? stl::exchange(curr, curr->next.get()) : nullptr; }); candidate) { + return candidate->invoke(stl::move(wrapped), args); + } + } + } - /** - * @brief Returns the type info object of the underlying type. - * @return The type info object of the underlying type. - */ - [[nodiscard]] const type_info &info() const noexcept { - return *fetch_node().info; - } + for(auto &&curr: base()) { + if(auto elem = curr.second.type().invoke(id, *wrapped.operator->(), args, sz); elem) { + return elem; + } + } - /** - * @brief Returns the alias assigned to a type. - * @return The alias assigned to the type. - */ - [[nodiscard]] id_type alias() const noexcept { - return fetch_node().alias; - } + return meta_any{meta_ctx_arg, *ctx}; + } - /** - * @brief Returns the name assigned to a type, if any. - * @return The name assigned to the type, if any. - */ - [[nodiscard]] stl::string_view name() const noexcept { - return (fetch_node().name == nullptr) ? stl::string_view{} : stl::string_view{fetch_node().name}; - } + /** + * @copybrief invoke + * @param id Unique identifier. + * @tparam Instance Type of instance to operate on. + * @param instance An instance that fits the underlying type. + * @param args Parameters to use to invoke the function. + * @return A wrapper containing the returned value, if any. + */ + template + // NOLINTNEXTLINE(modernize-use-nodiscard) + meta_any invoke(const id_type id, Instance &&instance, auto &&...args) const { + return invoke(id, stl::forward(instance), stl::array{meta_any{*ctx, stl::forward(args)}...}.data(), sizeof...(args)); + } - /** - * @brief Returns the size of the underlying type if known. - * @return The size of the underlying type if known, 0 otherwise. - */ - [[nodiscard]] size_type size_of() const noexcept { - return fetch_node().size_of; - } + /** + * @brief Sets the value of a given variable. + * @tparam Instance Type of instance to operate on. + * @param id Unique identifier. + * @param instance An instance that fits the underlying type. + * @param value Parameter to use to set the underlying variable. + * @return True in case of success, false otherwise. + */ + template + // NOLINTNEXTLINE(modernize-use-nodiscard) + bool set(const id_type id, Instance &&instance, auto &&value) const { + const auto candidate = data(id); + return candidate && candidate.set(stl::forward(instance), stl::forward(value)); + } - /** - * @brief Checks whether a type refers to an arithmetic type or not. - * @return True if the underlying type is an arithmetic type, false - * otherwise. - */ - [[nodiscard]] bool is_arithmetic() const noexcept { - return !!(fetch_node().traits & internal::meta_traits::is_arithmetic); - } + /** + * @brief Gets the value of a given variable. + * @tparam Instance Type of instance to operate on. + * @param id Unique identifier. + * @param instance An instance that fits the underlying type. + * @return A wrapper containing the value of the underlying variable. + */ + template + [[nodiscard]] meta_any get(const id_type id, Instance &&instance) const { + const auto candidate = data(id); + return candidate ? candidate.get(stl::forward(instance)) : meta_any{meta_ctx_arg, *ctx}; + } - /** - * @brief Checks whether a type refers to an integral type or not. - * @return True if the underlying type is an integral type, false otherwise. - */ - [[nodiscard]] bool is_integral() const noexcept { - return !!(fetch_node().traits & internal::meta_traits::is_integral); - } + /*! @copydoc meta_data::traits */ + template + [[nodiscard]] Type traits() const noexcept { + return internal::meta_to_user_traits(fetch_node().traits); + } - /** - * @brief Checks whether a type refers to a signed type or not. - * @return True if the underlying type is a signed type, false otherwise. - */ - [[nodiscard]] bool is_signed() const noexcept { - return !!(fetch_node().traits & internal::meta_traits::is_signed); - } + /*! @copydoc meta_data::custom */ + [[nodiscard]] meta_custom custom() const noexcept { + return fetch_node().custom; + } - /** - * @brief Checks whether a type refers to an array type or not. - * @return True if the underlying type is an array type, false otherwise. - */ - [[nodiscard]] bool is_array() const noexcept { - return !!(fetch_node().traits & internal::meta_traits::is_array); - } + /*! @copydoc meta_data::operator bool */ + [[nodiscard]] explicit operator bool() const noexcept { + return (node != nullptr); + } - /** - * @brief Checks whether a type refers to an enum or not. - * @return True if the underlying type is an enum, false otherwise. - */ - [[nodiscard]] bool is_enum() const noexcept { - return !!(fetch_node().traits & internal::meta_traits::is_enum); - } + /*! @copydoc meta_data::operator== */ + [[nodiscard]] bool operator==(const meta_type &other) const noexcept { + return (ctx == other.ctx) && (fetch_node().alias == other.fetch_node().alias); + } - /** - * @brief Checks whether a type refers to a class or not. - * @return True if the underlying type is a class, false otherwise. - */ - [[nodiscard]] bool is_class() const noexcept { - return !!(fetch_node().traits & internal::meta_traits::is_class); - } + private: + mutable const internal::meta_type_node *node{}; + const meta_ctx *ctx{&locator::value_or()}; + }; - /** - * @brief Checks whether a type refers to a pointer or not. - * @return True if the underlying type is a pointer, false otherwise. - */ - [[nodiscard]] bool is_pointer() const noexcept { - return !!(fetch_node().traits & internal::meta_traits::is_pointer); + [[nodiscard]] inline meta_type meta_any::type() const noexcept { + return *this ? meta_type{*ctx, fetch_node()} : meta_type{}; } - /** - * @brief Provides the type for which the pointer is defined. - * @return The type for which the pointer is defined or this type if it - * doesn't refer to a pointer type. - */ - [[nodiscard]] meta_type remove_pointer() const noexcept { - return meta_type{*ctx, fetch_node().remove_pointer(internal::meta_context::from(*ctx))}; + inline void meta_any::type(const meta_type &alias) noexcept { + ENTT_ASSERT(storage.info() == alias.info(), "Unexpected type"); + node = alias.node; + ctx = alias.ctx; } - /** - * @brief Checks whether a type is a pointer-like type or not. - * @return True if the underlying type is pointer-like, false otherwise. - */ - [[nodiscard]] bool is_pointer_like() const noexcept { - return !!(fetch_node().traits & internal::meta_traits::is_pointer_like); + // NOLINTNEXTLINE(modernize-use-nodiscard) + meta_any meta_any::invoke(const id_type id, auto &&...args) const { + return type().invoke(id, *this, stl::forward(args)...); } - /** - * @brief Checks whether a type refers to a sequence container or not. - * @return True if the type is a sequence container, false otherwise. - */ - [[nodiscard]] bool is_sequence_container() const noexcept { - return !!(fetch_node().traits & internal::meta_traits::is_sequence_container); + meta_any meta_any::invoke(const id_type id, auto &&...args) { + return type().invoke(id, *this, stl::forward(args)...); } - /** - * @brief Checks whether a type refers to an associative container or not. - * @return True if the type is an associative container, false otherwise. - */ - [[nodiscard]] bool is_associative_container() const noexcept { - return !!(fetch_node().traits & internal::meta_traits::is_associative_container); + bool meta_any::set(const id_type id, auto &&value) { + return type().set(id, *this, stl::forward(value)); } - /** - * @brief Checks whether a type refers to a template specialization or not. - * @return True if the type is a template specialization, false otherwise. - */ - [[nodiscard]] bool is_template_specialization() const noexcept { - return (fetch_node().templ.arity != 0u); + [[nodiscard]] inline meta_any meta_any::get(const id_type id) const { + return type().get(id, *this); } - /** - * @brief Returns the number of template arguments. - * @return The number of template arguments. - */ - [[nodiscard]] size_type template_arity() const noexcept { - return fetch_node().templ.arity; + [[nodiscard]] inline meta_any meta_any::get(const id_type id) { + return type().get(id, *this); } - /** - * @brief Returns a tag for the class template of the underlying type. - * @return The tag for the class template of the underlying type. - */ - [[nodiscard]] meta_type template_type() const noexcept { - return (fetch_node().templ.resolve != nullptr) ? meta_type{*ctx, fetch_node().templ.resolve(internal::meta_context::from(*ctx))} : meta_type{}; - } + [[nodiscard]] inline meta_any meta_any::allow_cast(const meta_type &type) const { + if(storage.has_value(type.info())) { + return as_ref(); + } else if(*this) { + if(const auto &from = fetch_node(); (from.conversion_helper != nullptr) && (type.is_arithmetic() || type.is_enum())) { + auto other = type.construct(); + const auto value = from.conversion_helper(nullptr, storage.data()); + other.fetch_node().conversion_helper(other.storage.data(), &value); + return other; + } - /** - * @brief Returns the type of the i-th template argument of a type. - * @param index Index of the template argument of which to return the type. - * @return The type of the i-th template argument of a type. - */ - [[nodiscard]] meta_type template_arg(const size_type index) const noexcept { - return index < template_arity() ? meta_type{*ctx, fetch_node().templ.arg(internal::meta_context::from(*ctx), index)} : meta_type{}; - } + if(const auto &from = fetch_node(); from.details) { + if(const auto *elem = internal::find_member(from.details->conv, type.info().hash()); elem != nullptr) { + return elem->conv(*ctx, storage.data()); + } - /** - * @brief Checks if a type supports direct casting to another type. - * @param other The meta type to test for. - * @return True if direct casting is allowed, false otherwise. - */ - [[nodiscard]] bool can_cast(const meta_type &other) const noexcept { - // casting this is UB in all cases but we aren't going to use the resulting pointer, so... - return other && ((*this == other) || (internal::try_cast(internal::meta_context::from(*ctx), fetch_node(), other.fetch_node().info->hash(), this) != nullptr)); + for(auto &&curr: from.details->base) { + if(auto other = curr.type(internal::meta_context::from(*ctx)).from_void(*ctx, nullptr, curr.cast(storage.data())); curr.id == type.info().hash()) { + return other; + } else if(auto from_base = stl::as_const(other).allow_cast(type); from_base) { + return from_base; + } + } + } + } + + return meta_any{meta_ctx_arg, *ctx}; } - /** - * @brief Checks whether a type supports conversion to another type. - * @param other The meta type to test for. - * @return True if the conversion is allowed, false otherwise. - */ - [[nodiscard]] bool can_convert(const meta_type &other) const noexcept { - if(const auto &to = other.info().hash(); (info().hash() == to) || ((fetch_node().conversion_helper != nullptr) && (other.is_arithmetic() || other.is_enum()))) { + [[nodiscard]] inline bool meta_any::allow_cast(const meta_type &type) { + if(storage.has_value(type.info())) { return true; - } else if(const auto &from = fetch_node(); from.details) { - if(const auto *elem = internal::find_member(from.details->conv, to); elem != nullptr) { - return true; + } else if(auto other = stl::as_const(*this).allow_cast(type); other) { + if(other.storage.owner()) { + stl::swap(*this, other); } - for(auto &&curr: from.details->base) { - if(curr.id == to || meta_type{*ctx, curr.type(internal::meta_context::from(*ctx))}.can_convert(other)) { - return true; - } - } + return true; } return false; } - /** - * @brief Returns a range to visit registered top-level base meta types. - * @return An iterable range to visit registered top-level base meta types. - */ - [[nodiscard]] meta_range base() const noexcept { - using range_type = meta_range; - return fetch_node().details ? range_type{{*ctx, fetch_node().details->base.cbegin()}, {*ctx, fetch_node().details->base.cend()}} : range_type{}; - } - - /** - * @brief Returns a range to visit registered top-level meta data. - * @return An iterable range to visit registered top-level meta data. - */ - [[nodiscard]] meta_range data() const noexcept { - using range_type = meta_range; - return fetch_node().details ? range_type{{*ctx, fetch_node().details->data.cbegin()}, {*ctx, fetch_node().details->data.cend()}} : range_type{}; - } + inline bool meta_any::assign(const meta_any &other) { + if(!storage.assign(other.storage)) { + auto value = other.allow_cast(type()); + return storage.assign(value.storage); + } - /** - * @brief Lookup utility for meta data (bases are also visited). - * @param id Unique identifier. - * @param recursive True for a search in the base classes, false otherwise. - * @return The registered meta data for the given identifier, if any. - */ - [[nodiscard]] meta_data data(const id_type id, const bool recursive = true) const { - const auto *elem = internal::look_for<&internal::meta_type_descriptor::data>(internal::meta_context::from(*ctx), fetch_node(), id, recursive); - return (elem != nullptr) ? meta_data{*ctx, *elem} : meta_data{}; + return true; } - /** - * @brief Returns a range to visit registered top-level functions. - * @return An iterable range to visit registered top-level functions. - */ - [[nodiscard]] meta_range func() const noexcept { - using return_type = meta_range; - return fetch_node().details ? return_type{{*ctx, fetch_node().details->func.cbegin()}, {*ctx, fetch_node().details->func.cend()}} : return_type{}; + inline bool meta_any::assign(meta_any && other) { + return storage.assign(stl::move(other.storage)) || storage.assign(stl::as_const(other).allow_cast(type()).storage); } - /** - * @brief Lookup utility for meta functions (bases are also visited). - * @param id Unique identifier. - * @param recursive True for a search in the base classes, false otherwise. - * @return The registered meta function for the given identifier, if any. - */ - [[nodiscard]] meta_func func(const id_type id, const bool recursive = true) const { - const auto *elem = internal::look_for<&internal::meta_type_descriptor::func>(internal::meta_context::from(*ctx), fetch_node(), id, recursive); - return (elem != nullptr) ? meta_func{*ctx, *elem} : meta_func{}; + [[nodiscard]] inline meta_type meta_data::type() const noexcept { + return meta_type{*ctx, node_or_assert().type(internal::meta_context::from(*ctx))}; } - /** - * @brief Creates an instance of the underlying type, if possible. - * @param args Parameters to use to construct the instance. - * @param sz Number of parameters to use to construct the instance. - * @return A wrapper containing the new instance, if any. - */ - [[nodiscard]] meta_any construct(meta_any *const args, const size_type sz) const { - if(const auto &ref = fetch_node(); ref.details) { - if(const auto *candidate = lookup(args, sz, false, [first = ref.details->ctor.cbegin(), last = ref.details->ctor.cend()]() mutable { return first == last ? nullptr : &*(first++); }); candidate) { - return candidate->invoke(*ctx, args); - } - } - - if(const auto &ref = fetch_node(); (sz == 0u) && (ref.default_constructor != nullptr)) { - return ref.default_constructor(*ctx); - } - - return meta_any{meta_ctx_arg, *ctx}; + [[nodiscard]] inline meta_type meta_data::arg() const noexcept { + return (node_or_assert().arg == nullptr) ? meta_type{} : meta_type{*ctx, node_or_assert().arg(internal::meta_context::from(*ctx))}; } - /** - * @copybrief construct - * @param args Parameters to use to construct the instance. - * @return A wrapper containing the new instance, if any. - */ - [[nodiscard]] meta_any construct(auto &&...args) const { - return construct(stl::array{meta_any{*ctx, stl::forward(args)}...}.data(), sizeof...(args)); - // NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks) + [[nodiscard]] inline meta_type meta_func::ret() const noexcept { + return meta_type{*ctx, node_or_assert().ret(internal::meta_context::from(*ctx))}; } - /** - * @brief Wraps an opaque element of the underlying type. - * @param elem A valid pointer to an element of the underlying type. - * @param transfer_ownership True to transfer ownership, false otherwise. - * @return A wrapper that references the given instance. - */ - [[nodiscard]] meta_any from_void(void *elem, bool transfer_ownership = false) const { - return ((elem != nullptr) && (fetch_node().from_void != nullptr)) ? fetch_node().from_void(*ctx, elem, transfer_ownership ? elem : nullptr) : meta_any{meta_ctx_arg, *ctx}; + [[nodiscard]] inline meta_type meta_func::arg(const size_type index) const noexcept { + return index < arity() ? node_or_assert().arg(*ctx, index) : meta_type{}; } - /** - * @brief Wraps an opaque element of the underlying type. - * @param elem A valid pointer to an element of the underlying type. - * @return A wrapper that references the given instance. - */ - [[nodiscard]] meta_any from_void(const void *elem) const { - return ((elem != nullptr) && (fetch_node().from_void != nullptr)) ? fetch_node().from_void(*ctx, nullptr, elem) : meta_any{meta_ctx_arg, *ctx}; + [[nodiscard]] inline meta_type meta_base::type() const noexcept { + return meta_type{*ctx, node_or_assert().type(internal::meta_context::from(*ctx))}; } - /** - * @brief Invokes a function given an identifier, if possible. - * @tparam Instance Type of instance to operate on. - * @param id Unique identifier. - * @param instance An instance that fits the underlying type. - * @param args Parameters to use to invoke the function. - * @param sz Number of parameters to use to invoke the function. - * @return A wrapper containing the returned value, if any. - */ - template - // NOLINTNEXTLINE(modernize-use-nodiscard) - meta_any invoke(const id_type id, Instance &&instance, meta_any *const args, const size_type sz) const { - meta_handle wrapped{*ctx, stl::forward(instance)}; - - if(const auto &ref = fetch_node(); ref.details) { - if(auto *elem = internal::find_member(ref.details->func, id); elem != nullptr) { - if(const auto *candidate = lookup(args, sz, (wrapped->base().policy() == any_policy::cref), [curr = elem]() mutable { return (curr != nullptr) ? stl::exchange(curr, curr->next.get()) : nullptr; }); candidate) { - return candidate->invoke(stl::move(wrapped), args); - } - } - } + /*! @cond ENTT_INTERNAL */ + class meta_sequence_container::meta_iterator final { + using vtable_type = void(const void *, const stl::ptrdiff_t, meta_any *); - for(auto &&curr: base()) { - if(auto elem = curr.second.type().invoke(id, *wrapped.operator->(), args, sz); elem) { - return elem; - } + template + static void basic_vtable(const void *value, const stl::ptrdiff_t offset, meta_any *other) { + const auto &it = *static_cast(value); + other ? other->emplace(*it) : stl::advance(const_cast(it), offset); } - return meta_any{meta_ctx_arg, *ctx}; - } - - /** - * @copybrief invoke - * @param id Unique identifier. - * @tparam Instance Type of instance to operate on. - * @param instance An instance that fits the underlying type. - * @param args Parameters to use to invoke the function. - * @return A wrapper containing the returned value, if any. - */ - template - // NOLINTNEXTLINE(modernize-use-nodiscard) - meta_any invoke(const id_type id, Instance &&instance, auto &&...args) const { - return invoke(id, stl::forward(instance), stl::array{meta_any{*ctx, stl::forward(args)}...}.data(), sizeof...(args)); - } + public: + using value_type = meta_any; + using pointer = input_iterator_pointer; + using reference = value_type; + using difference_type = stl::ptrdiff_t; + using iterator_category = stl::input_iterator_tag; + using iterator_concept = stl::bidirectional_iterator_tag; - /** - * @brief Sets the value of a given variable. - * @tparam Instance Type of instance to operate on. - * @param id Unique identifier. - * @param instance An instance that fits the underlying type. - * @param value Parameter to use to set the underlying variable. - * @return True in case of success, false otherwise. - */ - template - // NOLINTNEXTLINE(modernize-use-nodiscard) - bool set(const id_type id, Instance &&instance, auto &&value) const { - const auto candidate = data(id); - return candidate && candidate.set(stl::forward(instance), stl::forward(value)); - } + meta_iterator() = default; - /** - * @brief Gets the value of a given variable. - * @tparam Instance Type of instance to operate on. - * @param id Unique identifier. - * @param instance An instance that fits the underlying type. - * @return A wrapper containing the value of the underlying variable. - */ - template - [[nodiscard]] meta_any get(const id_type id, Instance &&instance) const { - const auto candidate = data(id); - return candidate ? candidate.get(stl::forward(instance)) : meta_any{meta_ctx_arg, *ctx}; - } + meta_iterator(const meta_ctx &area, stl::bidirectional_iterator auto iter) noexcept + : ctx{&area}, + vtable{&basic_vtable}, + handle{iter} {} - /*! @copydoc meta_data::traits */ - template - [[nodiscard]] Type traits() const noexcept { - return internal::meta_to_user_traits(fetch_node().traits); - } + meta_iterator &operator++() noexcept { + return vtable(handle.data(), 1, nullptr), *this; + } - /*! @copydoc meta_data::custom */ - [[nodiscard]] meta_custom custom() const noexcept { - return fetch_node().custom; - } + meta_iterator operator++(int value) noexcept { + meta_iterator orig = *this; + vtable(handle.data(), ++value, nullptr); + return orig; + } - /*! @copydoc meta_data::operator bool */ - [[nodiscard]] explicit operator bool() const noexcept { - return (node != nullptr); - } + meta_iterator &operator--() noexcept { + return vtable(handle.data(), -1, nullptr), *this; + } - /*! @copydoc meta_data::operator== */ - [[nodiscard]] bool operator==(const meta_type &other) const noexcept { - return (ctx == other.ctx) && (fetch_node().alias == other.fetch_node().alias); - } + meta_iterator operator--(int value) noexcept { + meta_iterator orig = *this; + vtable(handle.data(), --value, nullptr); + return orig; + } -private: - mutable const internal::meta_type_node *node{}; - const meta_ctx *ctx{&locator::value_or()}; -}; - -[[nodiscard]] inline meta_type meta_any::type() const noexcept { - return *this ? meta_type{*ctx, fetch_node()} : meta_type{}; -} - -inline void meta_any::type(const meta_type &alias) noexcept { - ENTT_ASSERT(storage.info() == alias.info(), "Unexpected type"); - node = alias.node; - ctx = alias.ctx; -} - -// NOLINTNEXTLINE(modernize-use-nodiscard) -meta_any meta_any::invoke(const id_type id, auto &&...args) const { - return type().invoke(id, *this, stl::forward(args)...); -} - -meta_any meta_any::invoke(const id_type id, auto &&...args) { - return type().invoke(id, *this, stl::forward(args)...); -} - -bool meta_any::set(const id_type id, auto &&value) { - return type().set(id, *this, stl::forward(value)); -} - -[[nodiscard]] inline meta_any meta_any::get(const id_type id) const { - return type().get(id, *this); -} - -[[nodiscard]] inline meta_any meta_any::get(const id_type id) { - return type().get(id, *this); -} - -[[nodiscard]] inline meta_any meta_any::allow_cast(const meta_type &type) const { - if(storage.has_value(type.info())) { - return as_ref(); - } else if(*this) { - if(const auto &from = fetch_node(); (from.conversion_helper != nullptr) && (type.is_arithmetic() || type.is_enum())) { - auto other = type.construct(); - const auto value = from.conversion_helper(nullptr, storage.data()); - other.fetch_node().conversion_helper(other.storage.data(), &value); + [[nodiscard]] reference operator*() const { + reference other{meta_ctx_arg, *ctx}; + vtable(handle.data(), 0, &other); return other; } - if(const auto &from = fetch_node(); from.details) { - if(const auto *elem = internal::find_member(from.details->conv, type.info().hash()); elem != nullptr) { - return elem->conv(*ctx, storage.data()); - } - - for(auto &&curr: from.details->base) { - if(auto other = curr.type(internal::meta_context::from(*ctx)).from_void(*ctx, nullptr, curr.cast(storage.data())); curr.id == type.info().hash()) { - return other; - } else if(auto from_base = stl::as_const(other).allow_cast(type); from_base) { - return from_base; - } - } + [[nodiscard]] pointer operator->() const { + return operator*(); } - } - return meta_any{meta_ctx_arg, *ctx}; -} - -[[nodiscard]] inline bool meta_any::allow_cast(const meta_type &type) { - if(storage.has_value(type.info())) { - return true; - } else if(auto other = stl::as_const(*this).allow_cast(type); other) { - if(other.storage.owner()) { - stl::swap(*this, other); + [[nodiscard]] explicit operator bool() const noexcept { + return (vtable != nullptr); } - return true; - } - - return false; -} + [[nodiscard]] bool operator==(const meta_iterator &other) const noexcept { + return handle == other.handle; + } -inline bool meta_any::assign(const meta_any &other) { - if(!storage.assign(other.storage)) { - auto value = other.allow_cast(type()); - return storage.assign(value.storage); - } + [[nodiscard]] const any &base() const noexcept { + return handle; + } - return true; -} + private: + const meta_ctx *ctx{}; + vtable_type *vtable{}; + any handle{}; + }; + + class meta_associative_container::meta_iterator final { + using vtable_type = void(const void *, stl::pair *); + + template + static void basic_vtable(const void *value, stl::pair *other) { + if(const auto &it = *static_cast(value); other) { + if constexpr(KeyOnly) { + other->first.emplace(*it); + } else { + other->first.emplacefirst))>(it->first); + other->second.emplacesecond))>(it->second); + } + } else { + ++const_cast(it); + } + } -inline bool meta_any::assign(meta_any &&other) { - return storage.assign(stl::move(other.storage)) || storage.assign(stl::as_const(other).allow_cast(type()).storage); -} + public: + using value_type = stl::pair; + using pointer = input_iterator_pointer; + using reference = value_type; + using difference_type = stl::ptrdiff_t; + using iterator_category = stl::input_iterator_tag; + using iterator_concept = stl::forward_iterator_tag; -[[nodiscard]] inline meta_type meta_data::type() const noexcept { - return meta_type{*ctx, node_or_assert().type(internal::meta_context::from(*ctx))}; -} + meta_iterator() = default; -[[nodiscard]] inline meta_type meta_data::arg() const noexcept { - return (node_or_assert().arg == nullptr) ? meta_type{} : meta_type{*ctx, node_or_assert().arg(internal::meta_context::from(*ctx))}; -} + template + meta_iterator(const meta_ctx &area, stl::bool_constant, stl::forward_iterator auto iter) noexcept + : ctx{&area}, + vtable{&basic_vtable}, + handle{iter} {} -[[nodiscard]] inline meta_type meta_func::ret() const noexcept { - return meta_type{*ctx, node_or_assert().ret(internal::meta_context::from(*ctx))}; -} + meta_iterator &operator++() noexcept { + return vtable(handle.data(), nullptr), *this; + } -[[nodiscard]] inline meta_type meta_func::arg(const size_type index) const noexcept { - return index < arity() ? node_or_assert().arg(*ctx, index) : meta_type{}; -} + meta_iterator operator++(int) noexcept { + meta_iterator orig = *this; + vtable(handle.data(), nullptr); + return orig; + } -[[nodiscard]] inline meta_type meta_base::type() const noexcept { - return meta_type{*ctx, node_or_assert().type(internal::meta_context::from(*ctx))}; -} + [[nodiscard]] reference operator*() const { + reference other{{meta_ctx_arg, *ctx}, {meta_ctx_arg, *ctx}}; + vtable(handle.data(), &other); + return other; + } -/*! @cond ENTT_INTERNAL */ -class meta_sequence_container::meta_iterator final { - using vtable_type = void(const void *, const stl::ptrdiff_t, meta_any *); + [[nodiscard]] pointer operator->() const { + return operator*(); + } - template - static void basic_vtable(const void *value, const stl::ptrdiff_t offset, meta_any *other) { - const auto &it = *static_cast(value); - other ? other->emplace(*it) : stl::advance(const_cast(it), offset); - } + [[nodiscard]] explicit operator bool() const noexcept { + return (vtable != nullptr); + } -public: - using value_type = meta_any; - using pointer = input_iterator_pointer; - using reference = value_type; - using difference_type = stl::ptrdiff_t; - using iterator_category = stl::input_iterator_tag; - using iterator_concept = stl::bidirectional_iterator_tag; + [[nodiscard]] bool operator==(const meta_iterator &other) const noexcept { + return handle == other.handle; + } - meta_iterator() = default; + private: + const meta_ctx *ctx{}; + vtable_type *vtable{}; + any handle{}; + }; - meta_iterator(const meta_ctx &area, stl::bidirectional_iterator auto iter) noexcept - : ctx{&area}, - vtable{&basic_vtable}, - handle{iter} {} + /*! @endcond */ - meta_iterator &operator++() noexcept { - return vtable(handle.data(), 1, nullptr), *this; + /** + * @brief Returns the meta value type of a container. + * @return The meta value type of the container. + */ + [[nodiscard]] inline meta_type meta_sequence_container::value_type() const noexcept { + return (value_type_node != nullptr) ? meta_type{*ctx, value_type_node(internal::meta_context::from(*ctx))} : meta_type{}; } - meta_iterator operator++(int value) noexcept { - meta_iterator orig = *this; - vtable(handle.data(), ++value, nullptr); - return orig; + /** + * @brief Returns the size of a container. + * @return The size of the container. + */ + [[nodiscard]] inline meta_sequence_container::size_type meta_sequence_container::size() const noexcept { + return size_fn(data); } - meta_iterator &operator--() noexcept { - return vtable(handle.data(), -1, nullptr), *this; + /** + * @brief Resizes a container to contain a given number of elements. + * @param sz The new size of the container. + * @return True in case of success, false otherwise. + */ + inline bool meta_sequence_container::resize(const size_type sz) { + return !const_only && resize_fn(const_cast(data), sz); } - meta_iterator operator--(int value) noexcept { - meta_iterator orig = *this; - vtable(handle.data(), --value, nullptr); - return orig; + /** + * @brief Clears the content of a container. + * @return True in case of success, false otherwise. + */ + inline bool meta_sequence_container::clear() { + return !const_only && clear_fn(const_cast(data)); } - [[nodiscard]] reference operator*() const { - reference other{meta_ctx_arg, *ctx}; - vtable(handle.data(), 0, &other); - return other; + /** + * @brief Reserves storage for at least the given number of elements. + * @param sz The new capacity of the container. + * @return True in case of success, false otherwise. + */ + inline bool meta_sequence_container::reserve(const size_type sz) { + return !const_only && reserve_fn(const_cast(data), sz); } - [[nodiscard]] pointer operator->() const { - return operator*(); + /** + * @brief Returns an iterator to the first element of a container. + * @return An iterator to the first element of the container. + */ + [[nodiscard]] inline meta_sequence_container::iterator meta_sequence_container::begin() { + return begin_end_fn(*ctx, const_only ? nullptr : const_cast(data), data, false); } - [[nodiscard]] explicit operator bool() const noexcept { - return (vtable != nullptr); + /** + * @brief Returns an iterator that is past the last element of a container. + * @return An iterator that is past the last element of the container. + */ + [[nodiscard]] inline meta_sequence_container::iterator meta_sequence_container::end() { + return begin_end_fn(*ctx, const_only ? nullptr : const_cast(data), data, true); } - [[nodiscard]] bool operator==(const meta_iterator &other) const noexcept { - return handle == other.handle; + /** + * @brief Inserts an element at a specified location of a container. + * @param it Iterator before which the element will be inserted. + * @param value Element value to insert. + * @return A possibly invalid iterator to the inserted element. + */ + inline meta_sequence_container::iterator meta_sequence_container::insert(const iterator &it, meta_any value) { + // this abomination is necessary because only on macos value_type and const_reference are different types for stl::vector + if(const auto &vtype = value_type_node(internal::meta_context::from(*ctx)); !const_only && (value.allow_cast({*ctx, vtype}) || value.allow_cast({*ctx, const_reference_node(internal::meta_context::from(*ctx))}))) { + const bool is_value_type = (value.type().info() == *vtype.info); + return insert_fn(*ctx, const_cast(data), is_value_type ? value.base().data() : nullptr, is_value_type ? nullptr : value.base().data(), it); + } + + return iterator{}; } - [[nodiscard]] const any &base() const noexcept { - return handle; + /** + * @brief Removes a given element from a container. + * @param it Iterator to the element to remove. + * @return A possibly invalid iterator following the last removed element. + */ + inline meta_sequence_container::iterator meta_sequence_container::erase(const iterator &it) { + return const_only ? iterator{} : erase_fn(*ctx, const_cast(data), it); } -private: - const meta_ctx *ctx{}; - vtable_type *vtable{}; - any handle{}; -}; + /** + * @brief Returns a reference to the element at a given location of a container. + * @param pos The position of the element to return. + * @return A reference to the requested element properly wrapped. + */ + [[nodiscard]] inline meta_any meta_sequence_container::operator[](const size_type pos) { + auto it = begin(); + it.operator++(static_cast(pos) - 1); + return *it; + } -class meta_associative_container::meta_iterator final { - using vtable_type = void(const void *, stl::pair *); + /** + * @brief Returns false if a proxy is invalid, true otherwise. + * @return False if the proxy is invalid, true otherwise. + */ + [[nodiscard]] inline meta_sequence_container::operator bool() const noexcept { + return (data != nullptr); + } - template - static void basic_vtable(const void *value, stl::pair *other) { - if(const auto &it = *static_cast(value); other) { - if constexpr(KeyOnly) { - other->first.emplace(*it); - } else { - other->first.emplacefirst))>(it->first); - other->second.emplacesecond))>(it->second); - } - } else { - ++const_cast(it); - } + /** + * @brief Returns the meta key type of a container. + * @return The meta key type of the a container. + */ + [[nodiscard]] inline meta_type meta_associative_container::key_type() const noexcept { + return (key_type_node != nullptr) ? meta_type{*ctx, key_type_node(internal::meta_context::from(*ctx))} : meta_type{}; } -public: - using value_type = stl::pair; - using pointer = input_iterator_pointer; - using reference = value_type; - using difference_type = stl::ptrdiff_t; - using iterator_category = stl::input_iterator_tag; - using iterator_concept = stl::forward_iterator_tag; + /** + * @brief Returns the meta mapped type of a container. + * @return The meta mapped type of the a container. + */ + [[nodiscard]] inline meta_type meta_associative_container::mapped_type() const noexcept { + return (mapped_type_node != nullptr) ? meta_type{*ctx, mapped_type_node(internal::meta_context::from(*ctx))} : meta_type{}; + } - meta_iterator() = default; + /*! @copydoc meta_sequence_container::value_type */ + [[nodiscard]] inline meta_type meta_associative_container::value_type() const noexcept { + return (value_type_node != nullptr) ? meta_type{*ctx, value_type_node(internal::meta_context::from(*ctx))} : meta_type{}; + } - template - meta_iterator(const meta_ctx &area, stl::bool_constant, stl::forward_iterator auto iter) noexcept - : ctx{&area}, - vtable{&basic_vtable}, - handle{iter} {} + /*! @copydoc meta_sequence_container::size */ + [[nodiscard]] inline meta_associative_container::size_type meta_associative_container::size() const noexcept { + return size_fn(data); + } - meta_iterator &operator++() noexcept { - return vtable(handle.data(), nullptr), *this; + /*! @copydoc meta_sequence_container::clear */ + inline bool meta_associative_container::clear() { + return !const_only && clear_fn(const_cast(data)); } - meta_iterator operator++(int) noexcept { - meta_iterator orig = *this; - vtable(handle.data(), nullptr); - return orig; + /*! @copydoc meta_sequence_container::reserve */ + inline bool meta_associative_container::reserve(const size_type sz) { + return !const_only && reserve_fn(const_cast(data), sz); } - [[nodiscard]] reference operator*() const { - reference other{{meta_ctx_arg, *ctx}, {meta_ctx_arg, *ctx}}; - vtable(handle.data(), &other); - return other; + /*! @copydoc meta_sequence_container::begin */ + [[nodiscard]] inline meta_associative_container::iterator meta_associative_container::begin() { + return begin_end_fn(*ctx, const_only ? nullptr : const_cast(data), data, false); } - [[nodiscard]] pointer operator->() const { - return operator*(); + /*! @copydoc meta_sequence_container::end */ + [[nodiscard]] inline meta_associative_container::iterator meta_associative_container::end() { + return begin_end_fn(*ctx, const_only ? nullptr : const_cast(data), data, true); } - [[nodiscard]] explicit operator bool() const noexcept { - return (vtable != nullptr); + /** + * @brief Inserts a key-only or key/value element into a container. + * @param key The key of the element to insert. + * @param value The value of the element to insert, if needed. + * @return A bool denoting whether the insertion took place. + */ + inline bool meta_associative_container::insert(meta_any key, meta_any value = {}) { + return !const_only && key.allow_cast(meta_type{*ctx, key_type_node(internal::meta_context::from(*ctx))}) + && ((mapped_type_node == nullptr) || value.allow_cast(meta_type{*ctx, mapped_type_node(internal::meta_context::from(*ctx))})) + && insert_fn(const_cast(data), key.base().data(), value.base().data()); } - [[nodiscard]] bool operator==(const meta_iterator &other) const noexcept { - return handle == other.handle; + /** + * @brief Removes the specified element from a container. + * @param key The key of the element to remove. + * @return A bool denoting whether the removal took place. + */ + inline meta_associative_container::size_type meta_associative_container::erase(meta_any key) { + return (!const_only && key.allow_cast(meta_type{*ctx, key_type_node(internal::meta_context::from(*ctx))})) ? erase_fn(const_cast(data), key.base().data()) : 0u; } -private: - const meta_ctx *ctx{}; - vtable_type *vtable{}; - any handle{}; -}; - -/*! @endcond */ - -/** - * @brief Returns the meta value type of a container. - * @return The meta value type of the container. - */ -[[nodiscard]] inline meta_type meta_sequence_container::value_type() const noexcept { - return (value_type_node != nullptr) ? meta_type{*ctx, value_type_node(internal::meta_context::from(*ctx))} : meta_type{}; -} - -/** - * @brief Returns the size of a container. - * @return The size of the container. - */ -[[nodiscard]] inline meta_sequence_container::size_type meta_sequence_container::size() const noexcept { - return size_fn(data); -} - -/** - * @brief Resizes a container to contain a given number of elements. - * @param sz The new size of the container. - * @return True in case of success, false otherwise. - */ -inline bool meta_sequence_container::resize(const size_type sz) { - return !const_only && resize_fn(const_cast(data), sz); -} - -/** - * @brief Clears the content of a container. - * @return True in case of success, false otherwise. - */ -inline bool meta_sequence_container::clear() { - return !const_only && clear_fn(const_cast(data)); -} - -/** - * @brief Reserves storage for at least the given number of elements. - * @param sz The new capacity of the container. - * @return True in case of success, false otherwise. - */ -inline bool meta_sequence_container::reserve(const size_type sz) { - return !const_only && reserve_fn(const_cast(data), sz); -} - -/** - * @brief Returns an iterator to the first element of a container. - * @return An iterator to the first element of the container. - */ -[[nodiscard]] inline meta_sequence_container::iterator meta_sequence_container::begin() { - return begin_end_fn(*ctx, const_only ? nullptr : const_cast(data), data, false); -} - -/** - * @brief Returns an iterator that is past the last element of a container. - * @return An iterator that is past the last element of the container. - */ -[[nodiscard]] inline meta_sequence_container::iterator meta_sequence_container::end() { - return begin_end_fn(*ctx, const_only ? nullptr : const_cast(data), data, true); -} - -/** - * @brief Inserts an element at a specified location of a container. - * @param it Iterator before which the element will be inserted. - * @param value Element value to insert. - * @return A possibly invalid iterator to the inserted element. - */ -inline meta_sequence_container::iterator meta_sequence_container::insert(const iterator &it, meta_any value) { - // this abomination is necessary because only on macos value_type and const_reference are different types for stl::vector - if(const auto &vtype = value_type_node(internal::meta_context::from(*ctx)); !const_only && (value.allow_cast({*ctx, vtype}) || value.allow_cast({*ctx, const_reference_node(internal::meta_context::from(*ctx))}))) { - const bool is_value_type = (value.type().info() == *vtype.info); - return insert_fn(*ctx, const_cast(data), is_value_type ? value.base().data() : nullptr, is_value_type ? nullptr : value.base().data(), it); + /** + * @brief Returns an iterator to the element with a given key, if any. + * @param key The key of the element to search. + * @return An iterator to the element with the given key, if any. + */ + [[nodiscard]] inline meta_associative_container::iterator meta_associative_container::find(meta_any key) { + return key.allow_cast(meta_type{*ctx, key_type_node(internal::meta_context::from(*ctx))}) ? find_fn(*ctx, const_only ? nullptr : const_cast(data), data, key.base().data()) : iterator{}; } - return iterator{}; -} - -/** - * @brief Removes a given element from a container. - * @param it Iterator to the element to remove. - * @return A possibly invalid iterator following the last removed element. - */ -inline meta_sequence_container::iterator meta_sequence_container::erase(const iterator &it) { - return const_only ? iterator{} : erase_fn(*ctx, const_cast(data), it); -} - -/** - * @brief Returns a reference to the element at a given location of a container. - * @param pos The position of the element to return. - * @return A reference to the requested element properly wrapped. - */ -[[nodiscard]] inline meta_any meta_sequence_container::operator[](const size_type pos) { - auto it = begin(); - it.operator++(static_cast(pos) - 1); - return *it; -} - -/** - * @brief Returns false if a proxy is invalid, true otherwise. - * @return False if the proxy is invalid, true otherwise. - */ -[[nodiscard]] inline meta_sequence_container::operator bool() const noexcept { - return (data != nullptr); -} - -/** - * @brief Returns the meta key type of a container. - * @return The meta key type of the a container. - */ -[[nodiscard]] inline meta_type meta_associative_container::key_type() const noexcept { - return (key_type_node != nullptr) ? meta_type{*ctx, key_type_node(internal::meta_context::from(*ctx))} : meta_type{}; -} - -/** - * @brief Returns the meta mapped type of a container. - * @return The meta mapped type of the a container. - */ -[[nodiscard]] inline meta_type meta_associative_container::mapped_type() const noexcept { - return (mapped_type_node != nullptr) ? meta_type{*ctx, mapped_type_node(internal::meta_context::from(*ctx))} : meta_type{}; -} - -/*! @copydoc meta_sequence_container::value_type */ -[[nodiscard]] inline meta_type meta_associative_container::value_type() const noexcept { - return (value_type_node != nullptr) ? meta_type{*ctx, value_type_node(internal::meta_context::from(*ctx))} : meta_type{}; -} - -/*! @copydoc meta_sequence_container::size */ -[[nodiscard]] inline meta_associative_container::size_type meta_associative_container::size() const noexcept { - return size_fn(data); -} - -/*! @copydoc meta_sequence_container::clear */ -inline bool meta_associative_container::clear() { - return !const_only && clear_fn(const_cast(data)); -} - -/*! @copydoc meta_sequence_container::reserve */ -inline bool meta_associative_container::reserve(const size_type sz) { - return !const_only && reserve_fn(const_cast(data), sz); -} - -/*! @copydoc meta_sequence_container::begin */ -[[nodiscard]] inline meta_associative_container::iterator meta_associative_container::begin() { - return begin_end_fn(*ctx, const_only ? nullptr : const_cast(data), data, false); -} - -/*! @copydoc meta_sequence_container::end */ -[[nodiscard]] inline meta_associative_container::iterator meta_associative_container::end() { - return begin_end_fn(*ctx, const_only ? nullptr : const_cast(data), data, true); -} - -/** - * @brief Inserts a key-only or key/value element into a container. - * @param key The key of the element to insert. - * @param value The value of the element to insert, if needed. - * @return A bool denoting whether the insertion took place. - */ -inline bool meta_associative_container::insert(meta_any key, meta_any value = {}) { - return !const_only && key.allow_cast(meta_type{*ctx, key_type_node(internal::meta_context::from(*ctx))}) - && ((mapped_type_node == nullptr) || value.allow_cast(meta_type{*ctx, mapped_type_node(internal::meta_context::from(*ctx))})) - && insert_fn(const_cast(data), key.base().data(), value.base().data()); -} - -/** - * @brief Removes the specified element from a container. - * @param key The key of the element to remove. - * @return A bool denoting whether the removal took place. - */ -inline meta_associative_container::size_type meta_associative_container::erase(meta_any key) { - return (!const_only && key.allow_cast(meta_type{*ctx, key_type_node(internal::meta_context::from(*ctx))})) ? erase_fn(const_cast(data), key.base().data()) : 0u; -} - -/** - * @brief Returns an iterator to the element with a given key, if any. - * @param key The key of the element to search. - * @return An iterator to the element with the given key, if any. - */ -[[nodiscard]] inline meta_associative_container::iterator meta_associative_container::find(meta_any key) { - return key.allow_cast(meta_type{*ctx, key_type_node(internal::meta_context::from(*ctx))}) ? find_fn(*ctx, const_only ? nullptr : const_cast(data), data, key.base().data()) : iterator{}; -} - -/** - * @brief Returns false if a proxy is invalid, true otherwise. - * @return False if the proxy is invalid, true otherwise. - */ -[[nodiscard]] inline meta_associative_container::operator bool() const noexcept { - return (data != nullptr); -} + /** + * @brief Returns false if a proxy is invalid, true otherwise. + * @return False if the proxy is invalid, true otherwise. + */ + [[nodiscard]] inline meta_associative_container::operator bool() const noexcept { + return (data != nullptr); + } } // namespace entt diff --git a/src/entt/meta/node.hpp b/src/entt/meta/node.hpp index 01909af0bf..db9ff73891 100644 --- a/src/entt/meta/node.hpp +++ b/src/entt/meta/node.hpp @@ -1,25 +1,29 @@ #ifndef ENTT_META_NODE_HPP #define ENTT_META_NODE_HPP -#include "../config/config.h" -#include "../core/bit.hpp" -#include "../core/concepts.hpp" -#include "../core/enum.hpp" -#include "../core/fwd.hpp" -#include "../core/type_info.hpp" -#include "../core/type_traits.hpp" -#include "../core/utility.hpp" -#include "../stl/array.hpp" -#include "../stl/bit.hpp" -#include "../stl/cstddef.hpp" -#include "../stl/cstdint.hpp" -#include "../stl/memory.hpp" -#include "../stl/type_traits.hpp" -#include "../stl/utility.hpp" -#include "../stl/vector.hpp" -#include "context.hpp" -#include "fwd.hpp" -#include "type_traits.hpp" +#include "../config/module.h" + +#ifndef ENTT_MODULE +# include "../config/config.h" +# include "../core/bit.hpp" +# include "../core/concepts.hpp" +# include "../core/enum.hpp" +# include "../core/fwd.hpp" +# include "../core/type_info.hpp" +# include "../core/type_traits.hpp" +# include "../core/utility.hpp" +# include "../stl/array.hpp" +# include "../stl/bit.hpp" +# include "../stl/cstddef.hpp" +# include "../stl/cstdint.hpp" +# include "../stl/memory.hpp" +# include "../stl/type_traits.hpp" +# include "../stl/utility.hpp" +# include "../stl/vector.hpp" +# include "context.hpp" +# include "fwd.hpp" +# include "type_traits.hpp" +#endif // ENTT_MODULE namespace entt { diff --git a/src/entt/meta/pointer.hpp b/src/entt/meta/pointer.hpp index e347756f54..73e0d53caa 100644 --- a/src/entt/meta/pointer.hpp +++ b/src/entt/meta/pointer.hpp @@ -3,39 +3,42 @@ #ifndef ENTT_META_POINTER_HPP #define ENTT_META_POINTER_HPP -#include "../stl/memory.hpp" -#include "../stl/type_traits.hpp" -#include "type_traits.hpp" - -namespace entt { - -/** - * @brief Makes `stl::shared_ptr`s of any type pointer-like types for the meta - * system. - * @tparam Type Element type. - */ -template -struct is_meta_pointer_like> - : stl::true_type {}; - -/** - * @brief Makes `stl::unique_ptr`s of any type pointer-like types for the meta - * system. - * @tparam Type Element type. - * @tparam Args Other arguments. - */ -template -struct is_meta_pointer_like> - : stl::true_type {}; - -/** - * @brief Specialization for self-proclaimed meta pointer like types. - * @tparam Type Element type. - */ -template -requires requires { typename Type::is_meta_pointer_like; } -struct is_meta_pointer_like - : stl::true_type {}; +#include "../config/module.h" + +#ifndef ENTT_MODULE +# include "../stl/memory.hpp" +# include "../stl/type_traits.hpp" +# include "type_traits.hpp" +#endif // ENTT_MODULE + +ENTT_MODULE_EXPORT namespace entt { + /** + * @brief Makes `stl::shared_ptr`s of any type pointer-like types for the meta + * system. + * @tparam Type Element type. + */ + template + struct is_meta_pointer_like> + : stl::true_type {}; + + /** + * @brief Makes `stl::unique_ptr`s of any type pointer-like types for the meta + * system. + * @tparam Type Element type. + * @tparam Args Other arguments. + */ + template + struct is_meta_pointer_like> + : stl::true_type {}; + + /** + * @brief Specialization for self-proclaimed meta pointer like types. + * @tparam Type Element type. + */ + template + requires requires { typename Type::is_meta_pointer_like; } + struct is_meta_pointer_like + : stl::true_type {}; } // namespace entt diff --git a/src/entt/meta/policy.hpp b/src/entt/meta/policy.hpp index b72464da9f..b57245a30b 100644 --- a/src/entt/meta/policy.hpp +++ b/src/entt/meta/policy.hpp @@ -1,7 +1,11 @@ #ifndef ENTT_META_POLICY_HPP #define ENTT_META_POLICY_HPP -#include "../stl/type_traits.hpp" +#include "../config/module.h" + +#ifndef ENTT_MODULE +# include "../stl/type_traits.hpp" +#endif // ENTT_MODULE namespace entt { @@ -13,6 +17,8 @@ struct meta_policy {}; } // namespace internal /*! @endcond */ +ENTT_MODULE_EXPORT_BEGIN + /*! @brief Empty class type used to request the _as-is_ policy. */ struct as_value_t final: private internal::meta_policy { /*! @cond ENTT_INTERNAL */ @@ -76,6 +82,8 @@ inline constexpr bool is_meta_policy_v = is_meta_policy::value; template concept meta_policy = is_meta_policy_v; +ENTT_MODULE_EXPORT_END + } // namespace entt #endif diff --git a/src/entt/meta/range.hpp b/src/entt/meta/range.hpp index 2e47d791d8..323963c094 100644 --- a/src/entt/meta/range.hpp +++ b/src/entt/meta/range.hpp @@ -1,14 +1,18 @@ #ifndef ENTT_META_RANGE_HPP #define ENTT_META_RANGE_HPP -#include -#include "../core/fwd.hpp" -#include "../core/iterator.hpp" -#include "../stl/concepts.hpp" -#include "../stl/cstddef.hpp" -#include "../stl/iterator.hpp" -#include "../stl/utility.hpp" -#include "context.hpp" +#include "../config/module.h" + +#ifndef ENTT_MODULE +# include +# include "../core/fwd.hpp" +# include "../core/iterator.hpp" +# include "../stl/concepts.hpp" +# include "../stl/cstddef.hpp" +# include "../stl/iterator.hpp" +# include "../stl/utility.hpp" +# include "context.hpp" +#endif // ENTT_MODULE namespace entt { @@ -106,6 +110,8 @@ struct meta_range_iterator final { } // namespace internal /*! @endcond */ +ENTT_MODULE_EXPORT_BEGIN + /** * @brief Iterable range to use to iterate all types of meta objects. * @tparam Type Type of meta objects returned. @@ -114,6 +120,8 @@ struct meta_range_iterator final { template using meta_range = iterable_adaptor>; +ENTT_MODULE_EXPORT_END + } // namespace entt #endif diff --git a/src/entt/meta/resolve.hpp b/src/entt/meta/resolve.hpp index 7f3eb97eaf..ec2fcf83b4 100644 --- a/src/entt/meta/resolve.hpp +++ b/src/entt/meta/resolve.hpp @@ -1,108 +1,111 @@ #ifndef ENTT_META_RESOLVE_HPP #define ENTT_META_RESOLVE_HPP -#include "../core/type_info.hpp" -#include "../locator/locator.hpp" -#include "../stl/type_traits.hpp" -#include "context.hpp" -#include "meta.hpp" -#include "node.hpp" -#include "range.hpp" +#include "../config/module.h" -namespace entt { +#ifndef ENTT_MODULE +# include "../core/type_info.hpp" +# include "../locator/locator.hpp" +# include "../stl/type_traits.hpp" +# include "context.hpp" +# include "meta.hpp" +# include "node.hpp" +# include "range.hpp" +#endif // ENTT_MODULE -/** - * @brief Returns the meta type associated with a given type. - * @tparam Type Type to use to search for a meta type. - * @param ctx The context from which to search for meta types. - * @return The meta type associated with the given type, if any. - */ -template -[[nodiscard]] meta_type resolve(const meta_ctx &ctx) noexcept { - const auto &context = internal::meta_context::from(ctx); - return {ctx, internal::resolve>(context)}; -} +ENTT_MODULE_EXPORT namespace entt { + /** + * @brief Returns the meta type associated with a given type. + * @tparam Type Type to use to search for a meta type. + * @param ctx The context from which to search for meta types. + * @return The meta type associated with the given type, if any. + */ + template + [[nodiscard]] meta_type resolve(const meta_ctx &ctx) noexcept { + const auto &context = internal::meta_context::from(ctx); + return {ctx, internal::resolve>(context)}; + } -/** - * @brief Returns the meta type associated with a given type. - * @tparam Type Type to use to search for a meta type. - * @return The meta type associated with the given type, if any. - */ -template -[[nodiscard]] meta_type resolve() noexcept { - return resolve(locator::value_or()); -} + /** + * @brief Returns the meta type associated with a given type. + * @tparam Type Type to use to search for a meta type. + * @return The meta type associated with the given type, if any. + */ + template + [[nodiscard]] meta_type resolve() noexcept { + return resolve(locator::value_or()); + } -/** - * @brief Returns a range to use to visit all meta types. - * @param ctx The context from which to search for meta types. - * @return An iterable range to use to visit all meta types. - */ -[[nodiscard]] inline meta_range resolve(const meta_ctx &ctx) noexcept { - const auto &context = internal::meta_context::from(ctx); - return {{ctx, context.bucket.cbegin()}, {ctx, context.bucket.cend()}}; -} + /** + * @brief Returns a range to use to visit all meta types. + * @param ctx The context from which to search for meta types. + * @return An iterable range to use to visit all meta types. + */ + [[nodiscard]] inline meta_range resolve(const meta_ctx &ctx) noexcept { + const auto &context = internal::meta_context::from(ctx); + return {{ctx, context.bucket.cbegin()}, {ctx, context.bucket.cend()}}; + } -/** - * @brief Returns a range to use to visit all meta types. - * @return An iterable range to use to visit all meta types. - */ -[[nodiscard]] inline meta_range resolve() noexcept { - return resolve(locator::value_or()); -} + /** + * @brief Returns a range to use to visit all meta types. + * @return An iterable range to use to visit all meta types. + */ + [[nodiscard]] inline meta_range resolve() noexcept { + return resolve(locator::value_or()); + } -/** - * @brief Returns the meta type associated with a given identifier, if any. - * @param ctx The context from which to search for meta types. - * @param alias Unique identifier. - * @return The meta type associated with the given identifier, if any. - */ -[[nodiscard]] inline meta_type resolve(const meta_ctx &ctx, const id_type alias) noexcept { - const auto &context = internal::meta_context::from(ctx); + /** + * @brief Returns the meta type associated with a given identifier, if any. + * @param ctx The context from which to search for meta types. + * @param alias Unique identifier. + * @return The meta type associated with the given identifier, if any. + */ + [[nodiscard]] inline meta_type resolve(const meta_ctx &ctx, const id_type alias) noexcept { + const auto &context = internal::meta_context::from(ctx); - // fast lookup for unsearchable and overloaded types - if(const auto it = context.bucket.find(alias); it != context.bucket.end()) { - return meta_type{ctx, *it->second}; - } + // fast lookup for unsearchable and overloaded types + if(const auto it = context.bucket.find(alias); it != context.bucket.end()) { + return meta_type{ctx, *it->second}; + } - for(auto &&curr: context.bucket) { - if(curr.second->alias == alias) { - return meta_type{ctx, *curr.second}; + for(auto &&curr: context.bucket) { + if(curr.second->alias == alias) { + return meta_type{ctx, *curr.second}; + } } - } - return meta_type{}; -} + return meta_type{}; + } -/** - * @brief Returns the meta type associated with a given identifier, if any. - * @param alias Unique identifier. - * @return The meta type associated with the given identifier, if any. - */ -[[nodiscard]] inline meta_type resolve(const id_type alias) noexcept { - return resolve(locator::value_or(), alias); -} + /** + * @brief Returns the meta type associated with a given identifier, if any. + * @param alias Unique identifier. + * @return The meta type associated with the given identifier, if any. + */ + [[nodiscard]] inline meta_type resolve(const id_type alias) noexcept { + return resolve(locator::value_or(), alias); + } -/** - * @brief Returns the meta type associated with a given type info object. - * @param ctx The context from which to search for meta types. - * @param info The type info object of the requested type. - * @return The meta type associated with the given type info object, if any. - */ -[[nodiscard]] inline meta_type resolve(const meta_ctx &ctx, const type_info &info) noexcept { - const auto &context = internal::meta_context::from(ctx); - const auto it = context.bucket.find(info.hash()); - return (it == context.bucket.cend()) ? meta_type{} : meta_type{ctx, *it->second}; -} + /** + * @brief Returns the meta type associated with a given type info object. + * @param ctx The context from which to search for meta types. + * @param info The type info object of the requested type. + * @return The meta type associated with the given type info object, if any. + */ + [[nodiscard]] inline meta_type resolve(const meta_ctx &ctx, const type_info &info) noexcept { + const auto &context = internal::meta_context::from(ctx); + const auto it = context.bucket.find(info.hash()); + return (it == context.bucket.cend()) ? meta_type{} : meta_type{ctx, *it->second}; + } -/** - * @brief Returns the meta type associated with a given type info object. - * @param info The type info object of the requested type. - * @return The meta type associated with the given type info object, if any. - */ -[[nodiscard]] inline meta_type resolve(const type_info &info) noexcept { - return resolve(locator::value_or(), info); -} + /** + * @brief Returns the meta type associated with a given type info object. + * @param info The type info object of the requested type. + * @return The meta type associated with the given type info object, if any. + */ + [[nodiscard]] inline meta_type resolve(const type_info &info) noexcept { + return resolve(locator::value_or(), info); + } } // namespace entt diff --git a/src/entt/meta/template.hpp b/src/entt/meta/template.hpp index 5eab2afcd8..ba402db238 100644 --- a/src/entt/meta/template.hpp +++ b/src/entt/meta/template.hpp @@ -3,9 +3,13 @@ #ifndef ENTT_META_TEMPLATE_HPP #define ENTT_META_TEMPLATE_HPP -#include "../core/type_traits.hpp" +#include "../config/module.h" -namespace entt { +#ifndef ENTT_MODULE +# include "../core/type_traits.hpp" +#endif // ENTT_MODULE + +ENTT_MODULE_EXPORT namespace entt { /*! @brief Utility class to disambiguate class templates. */ template class> diff --git a/src/entt/meta/type_traits.hpp b/src/entt/meta/type_traits.hpp index 91cad448fe..cc0868ebae 100644 --- a/src/entt/meta/type_traits.hpp +++ b/src/entt/meta/type_traits.hpp @@ -1,53 +1,58 @@ #ifndef ENTT_META_TYPE_TRAITS_HPP #define ENTT_META_TYPE_TRAITS_HPP -#include "../stl/type_traits.hpp" -#include "../stl/utility.hpp" - -namespace entt { - -/** - * @brief Traits class template to be specialized to enable support for meta - * template information. - */ -template -struct meta_template_traits; - -/** - * @brief Traits class template to be specialized to enable support for meta - * sequence containers. - */ -template -struct meta_sequence_container_traits; - -/** - * @brief Traits class template to be specialized to enable support for meta - * associative containers. - */ -template -struct meta_associative_container_traits; - -/** - * @brief Provides the member constant `value` to true if a given type is a - * pointer-like type from the point of view of the meta system, false otherwise. - */ -template -struct is_meta_pointer_like: stl::false_type {}; - -/** - * @brief Partial specialization to ensure that const pointer-like types are - * also accepted. - * @tparam Type Potentially pointer-like type. - */ -template -struct is_meta_pointer_like: is_meta_pointer_like {}; - -/** - * @brief Helper variable template. - * @tparam Type Potentially pointer-like type. - */ -template -inline constexpr auto is_meta_pointer_like_v = is_meta_pointer_like::value; +#include "../config/module.h" + +#ifndef ENTT_MODULE +# include +# include +# include "../stl/type_traits.hpp" +# include "../stl/utility.hpp" +#endif // ENTT_MODULE + +ENTT_MODULE_EXPORT namespace entt { + /** + * @brief Traits class template to be specialized to enable support for meta + * template information. + */ + template + struct meta_template_traits; + + /** + * @brief Traits class template to be specialized to enable support for meta + * sequence containers. + */ + template + struct meta_sequence_container_traits; + + /** + * @brief Traits class template to be specialized to enable support for meta + * associative containers. + */ + template + struct meta_associative_container_traits; + + /** + * @brief Provides the member constant `value` to true if a given type is a + * pointer-like type from the point of view of the meta system, false otherwise. + */ + template + struct is_meta_pointer_like: stl::false_type {}; + + /** + * @brief Partial specialization to ensure that const pointer-like types are + * also accepted. + * @tparam Type Potentially pointer-like type. + */ + template + struct is_meta_pointer_like: is_meta_pointer_like {}; + + /** + * @brief Helper variable template. + * @tparam Type Potentially pointer-like type. + */ + template + inline constexpr auto is_meta_pointer_like_v = is_meta_pointer_like::value; } // namespace entt diff --git a/src/entt/meta/utility.hpp b/src/entt/meta/utility.hpp index 40bd571d56..9c2903f3d9 100644 --- a/src/entt/meta/utility.hpp +++ b/src/entt/meta/utility.hpp @@ -1,18 +1,24 @@ #ifndef ENTT_META_UTILITY_HPP #define ENTT_META_UTILITY_HPP -#include "../core/type_traits.hpp" -#include "../locator/locator.hpp" -#include "../stl/cstddef.hpp" -#include "../stl/functional.hpp" -#include "../stl/type_traits.hpp" -#include "../stl/utility.hpp" -#include "meta.hpp" -#include "node.hpp" -#include "policy.hpp" +#include "../config/module.h" + +#ifndef ENTT_MODULE +# include "../core/type_traits.hpp" +# include "../locator/locator.hpp" +# include "../stl/cstddef.hpp" +# include "../stl/functional.hpp" +# include "../stl/type_traits.hpp" +# include "../stl/utility.hpp" +# include "meta.hpp" +# include "node.hpp" +# include "policy.hpp" +#endif // ENTT_MODULE namespace entt { +ENTT_MODULE_EXPORT_BEGIN + /** * @brief Meta function descriptor traits. * @tparam Ret Function return type. @@ -191,7 +197,11 @@ template return meta_dispatch(locator::value_or(), stl::forward(value)); } +ENTT_MODULE_EXPORT_END + +/*! @cond TURN_OFF_DOXYGEN */ /*! @cond ENTT_INTERNAL */ + namespace internal { template @@ -241,6 +251,8 @@ template } // namespace internal /*! @endcond */ +ENTT_MODULE_EXPORT_BEGIN + /** * @brief Returns the meta type of the i-th element of a list of arguments. * @tparam Type Type list of the actual types of arguments. @@ -474,6 +486,8 @@ template return meta_construct(locator::value_or(), args); } +ENTT_MODULE_EXPORT_END + } // namespace entt #endif diff --git a/src/entt/poly/fwd.hpp b/src/entt/poly/fwd.hpp index 4d513e3a21..1ae25efe3e 100644 --- a/src/entt/poly/fwd.hpp +++ b/src/entt/poly/fwd.hpp @@ -1,20 +1,23 @@ #ifndef ENTT_POLY_FWD_HPP #define ENTT_POLY_FWD_HPP -#include "../stl/cstddef.hpp" +#include "../config/module.h" -namespace entt { +#ifndef ENTT_MODULE +# include "../stl/cstddef.hpp" +#endif // ENTT_MODULE -// NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays, modernize-avoid-c-arrays) -template -class basic_poly; +ENTT_MODULE_EXPORT namespace entt { + // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays, modernize-avoid-c-arrays) + template + class basic_poly; -/** - * @brief Alias declaration for the most common use case. - * @tparam Concept Concept descriptor. - */ -template -using poly = basic_poly; + /** + * @brief Alias declaration for the most common use case. + * @tparam Concept Concept descriptor. + */ + template + using poly = basic_poly; } // namespace entt diff --git a/src/entt/poly/poly.hpp b/src/entt/poly/poly.hpp index a409c9a9b1..5d74cf1f2b 100644 --- a/src/entt/poly/poly.hpp +++ b/src/entt/poly/poly.hpp @@ -1,315 +1,318 @@ #ifndef ENTT_POLY_POLY_HPP #define ENTT_POLY_POLY_HPP -#include "../core/any.hpp" -#include "../core/concepts.hpp" -#include "../core/type_info.hpp" -#include "../core/type_traits.hpp" -#include "../stl/concepts.hpp" -#include "../stl/cstddef.hpp" -#include "../stl/functional.hpp" -#include "../stl/tuple.hpp" -#include "../stl/type_traits.hpp" -#include "../stl/utility.hpp" -#include "fwd.hpp" - -namespace entt { - -/*! @brief Inspector class used to infer the type of the virtual table. */ -struct poly_inspector { - /** - * @brief Generic conversion operator (definition only). - * @tparam Type Type to which conversion is requested. - */ - template - operator Type &&() const; +#include "../config/module.h" + +#ifndef ENTT_MODULE +# include "../core/any.hpp" +# include "../core/concepts.hpp" +# include "../core/type_info.hpp" +# include "../core/type_traits.hpp" +# include "../stl/concepts.hpp" +# include "../stl/cstddef.hpp" +# include "../stl/functional.hpp" +# include "../stl/tuple.hpp" +# include "../stl/type_traits.hpp" +# include "../stl/utility.hpp" +# include "fwd.hpp" +#endif // ENTT_MODULE + +ENTT_MODULE_EXPORT namespace entt { + /*! @brief Inspector class used to infer the type of the virtual table. */ + struct poly_inspector { + /** + * @brief Generic conversion operator (definition only). + * @tparam Type Type to which conversion is requested. + */ + template + operator Type &&() const; + + /** + * @brief Dummy invocation function (definition only). + * @tparam Member Index of the function to invoke. + * @tparam Args Types of arguments to pass to the function. + * @param args The arguments to pass to the function. + * @return A poly inspector convertible to any type. + */ + template + [[nodiscard]] poly_inspector invoke(Args &&...args) const; + + /*! @copydoc invoke */ + template + [[nodiscard]] poly_inspector invoke(Args &&...args); + }; /** - * @brief Dummy invocation function (definition only). - * @tparam Member Index of the function to invoke. - * @tparam Args Types of arguments to pass to the function. - * @param args The arguments to pass to the function. - * @return A poly inspector convertible to any type. + * @brief Static virtual table factory. + * @tparam Concept Concept descriptor. + * @tparam Len Size of the storage reserved for the small buffer optimization. + * @tparam Align Alignment requirement. */ - template - [[nodiscard]] poly_inspector invoke(Args &&...args) const; - - /*! @copydoc invoke */ - template - [[nodiscard]] poly_inspector invoke(Args &&...args); -}; - -/** - * @brief Static virtual table factory. - * @tparam Concept Concept descriptor. - * @tparam Len Size of the storage reserved for the small buffer optimization. - * @tparam Align Alignment requirement. - */ -template -class poly_vtable { - using inspector = Concept::template type; - - template - requires stl::derived_from> - static auto vtable_entry(Ret (*)(Clazz &, Args...)) - -> Ret (*)(constness_as_t, Clazz> &, Args...); - - template - static auto vtable_entry(Ret (*)(Args...)) - -> Ret (*)(const basic_any &, Args...); - - template - requires stl::derived_from - static auto vtable_entry(Ret (Clazz::*)(Args...)) - -> Ret (*)(basic_any &, Args...); - - template - requires stl::derived_from - static auto vtable_entry(Ret (Clazz::*)(Args...) const) - -> Ret (*)(const basic_any &, Args...); - - template - static auto make_vtable(value_list) noexcept - -> decltype(stl::make_tuple(vtable_entry(Candidate)...)); - - template - [[nodiscard]] static ENTT_CONSTEVAL auto make_vtable(type_list) noexcept { - if constexpr(sizeof...(Func) == 0u) { - return decltype(make_vtable(typename Concept::template impl{})){}; - } else if constexpr((stl::is_function_v && ...)) { - return decltype(stl::make_tuple(vtable_entry(stl::declval())...)){}; + template + class poly_vtable { + using inspector = Concept::template type; + + template + requires stl::derived_from> + static auto vtable_entry(Ret (*)(Clazz &, Args...)) + -> Ret (*)(constness_as_t, Clazz> &, Args...); + + template + static auto vtable_entry(Ret (*)(Args...)) + -> Ret (*)(const basic_any &, Args...); + + template + requires stl::derived_from + static auto vtable_entry(Ret (Clazz::*)(Args...)) + -> Ret (*)(basic_any &, Args...); + + template + requires stl::derived_from + static auto vtable_entry(Ret (Clazz::*)(Args...) const) + -> Ret (*)(const basic_any &, Args...); + + template + static auto make_vtable(value_list) noexcept + -> decltype(stl::make_tuple(vtable_entry(Candidate)...)); + + template + [[nodiscard]] static ENTT_CONSTEVAL auto make_vtable(type_list) noexcept { + if constexpr(sizeof...(Func) == 0u) { + return decltype(make_vtable(typename Concept::template impl{})){}; + } else if constexpr((stl::is_function_v && ...)) { + return decltype(stl::make_tuple(vtable_entry(stl::declval())...)){}; + } } - } - template - static void fill_vtable_entry(Ret (*&entry)(Any &, Args...)) noexcept { - if constexpr(stl::is_invocable_r_v) { - entry = +[](Any &, Args... args) -> Ret { - return stl::invoke(Candidate, stl::forward(args)...); - }; - } else { - entry = +[](Any &instance, Args... args) -> Ret { - return static_cast(stl::invoke(Candidate, any_cast &>(instance), stl::forward(args)...)); - }; + template + static void fill_vtable_entry(Ret (*&entry)(Any &, Args...)) noexcept { + if constexpr(stl::is_invocable_r_v) { + entry = +[](Any &, Args... args) -> Ret { + return stl::invoke(Candidate, stl::forward(args)...); + }; + } else { + entry = +[](Any &instance, Args... args) -> Ret { + return static_cast(stl::invoke(Candidate, any_cast &>(instance), stl::forward(args)...)); + }; + } } - } - template - [[nodiscard]] static auto fill_vtable(stl::index_sequence) noexcept { - vtable_type impl{}; - (fill_vtable_entry>>(stl::get(impl)), ...); - return impl; - } - - using vtable_type = decltype(make_vtable(Concept{})); - static constexpr bool is_mono = stl::tuple_size_v == 1u; + template + [[nodiscard]] static auto fill_vtable(stl::index_sequence) noexcept { + vtable_type impl{}; + (fill_vtable_entry>>(stl::get(impl)), ...); + return impl; + } -public: - /*! @brief Virtual table type. */ - using type = stl::conditional_t, const vtable_type *>; + using vtable_type = decltype(make_vtable(Concept{})); + static constexpr bool is_mono = stl::tuple_size_v == 1u; + + public: + /*! @brief Virtual table type. */ + using type = stl::conditional_t, const vtable_type *>; + + /** + * @brief Returns a static virtual table for a specific concept and type. + * @tparam Type The type for which to generate the virtual table. + * @return A static virtual table for the given concept and type. + */ + template + [[nodiscard]] static type instance() noexcept { + static const vtable_type vtable = fill_vtable(stl::make_index_sequence::size>{}); + + if constexpr(is_mono) { + return stl::get<0>(vtable); + } else { + return &vtable; + } + } + }; /** - * @brief Returns a static virtual table for a specific concept and type. - * @tparam Type The type for which to generate the virtual table. - * @return A static virtual table for the given concept and type. + * @brief Poly base class used to inject functionalities into concepts. + * @tparam Poly The outermost poly class. */ - template - [[nodiscard]] static type instance() noexcept { - static const vtable_type vtable = fill_vtable(stl::make_index_sequence::size>{}); - - if constexpr(is_mono) { - return stl::get<0>(vtable); - } else { - return &vtable; + template + struct poly_base { + /** + * @brief Invokes a function from the static virtual table. + * @tparam Member Index of the function to invoke. + * @tparam Args Types of arguments to pass to the function. + * @param self A reference to the poly object that made the call. + * @param args The arguments to pass to the function. + * @return The return value of the invoked function, if any. + */ + template + [[nodiscard]] decltype(auto) invoke(const poly_base &self, Args &&...args) const { + const auto &poly = static_cast(self); + + if constexpr(stl::is_function_v>) { + return poly.vtable(poly.storage, stl::forward(args)...); + } else { + return stl::get(*poly.vtable)(poly.storage, stl::forward(args)...); + } } - } -}; - -/** - * @brief Poly base class used to inject functionalities into concepts. - * @tparam Poly The outermost poly class. - */ -template -struct poly_base { + + /*! @copydoc invoke */ + template + [[nodiscard]] decltype(auto) invoke(poly_base &self, Args &&...args) { + auto &poly = static_cast(self); + + if constexpr(stl::is_function_v>) { + static_assert(Member == 0u, "Unknown member"); + return poly.vtable(poly.storage, stl::forward(args)...); + } else { + return stl::get(*poly.vtable)(poly.storage, stl::forward(args)...); + } + } + }; + /** - * @brief Invokes a function from the static virtual table. + * @brief Shortcut for calling `poly_base::invoke`. * @tparam Member Index of the function to invoke. + * @tparam Poly A fully defined poly object. * @tparam Args Types of arguments to pass to the function. * @param self A reference to the poly object that made the call. * @param args The arguments to pass to the function. * @return The return value of the invoked function, if any. */ - template - [[nodiscard]] decltype(auto) invoke(const poly_base &self, Args &&...args) const { - const auto &poly = static_cast(self); - - if constexpr(stl::is_function_v>) { - return poly.vtable(poly.storage, stl::forward(args)...); - } else { - return stl::get(*poly.vtable)(poly.storage, stl::forward(args)...); - } + template + decltype(auto) poly_call(Poly && self, Args && ...args) { + return stl::forward(self).template invoke(self, stl::forward(args)...); } - /*! @copydoc invoke */ - template - [[nodiscard]] decltype(auto) invoke(poly_base &self, Args &&...args) { - auto &poly = static_cast(self); - - if constexpr(stl::is_function_v>) { - static_assert(Member == 0u, "Unknown member"); - return poly.vtable(poly.storage, stl::forward(args)...); - } else { - return stl::get(*poly.vtable)(poly.storage, stl::forward(args)...); - } - } -}; - -/** - * @brief Shortcut for calling `poly_base::invoke`. - * @tparam Member Index of the function to invoke. - * @tparam Poly A fully defined poly object. - * @tparam Args Types of arguments to pass to the function. - * @param self A reference to the poly object that made the call. - * @param args The arguments to pass to the function. - * @return The return value of the invoked function, if any. - */ -template -decltype(auto) poly_call(Poly &&self, Args &&...args) { - return stl::forward(self).template invoke(self, stl::forward(args)...); -} - -/** - * @brief Static polymorphism made simple and within everyone's reach. - * - * Static polymorphism is a very powerful tool in C++, albeit sometimes - * cumbersome to obtain.
- * This class aims to make it simple and easy to use. - * - * @note - * Both deduced and defined static virtual tables are supported.
- * Moreover, the `poly` class template also works with unmanaged objects. - * - * @tparam Concept Concept descriptor. - * @tparam Len Size of the storage reserved for the small buffer optimization. - * @tparam Align Optional alignment requirement. - */ -template -class basic_poly: private Concept::template type>> { - friend struct poly_base; - -public: - /*! @brief Concept type. */ - using concept_type = Concept::template type>; - /*! @brief Virtual table type. */ - using vtable_type = poly_vtable::type; - - /*! @brief Default constructor. */ - basic_poly() noexcept = default; - - /** - * @brief Constructs a poly by directly initializing the new object. - * @tparam Type Type of object to use to initialize the poly. - * @tparam Args Types of arguments to use to construct the new instance. - * @param args Parameters to use to construct the instance. - */ - template - explicit basic_poly(stl::in_place_type_t, Args &&...args) - : storage{stl::in_place_type, stl::forward(args)...}, - vtable{poly_vtable::template instance>()} {} - /** - * @brief Constructs a poly from a given value. - * @tparam Type Type of object to use to initialize the poly. - * @param value An instance of an object to use to initialize the poly. + * @brief Static polymorphism made simple and within everyone's reach. + * + * Static polymorphism is a very powerful tool in C++, albeit sometimes + * cumbersome to obtain.
+ * This class aims to make it simple and easy to use. + * + * @note + * Both deduced and defined static virtual tables are supported.
+ * Moreover, the `poly` class template also works with unmanaged objects. + * + * @tparam Concept Concept descriptor. + * @tparam Len Size of the storage reserved for the small buffer optimization. + * @tparam Align Optional alignment requirement. */ - template - requires (!stl::same_as, basic_poly>) - basic_poly(Type &&value) noexcept - : basic_poly{stl::in_place_type>, stl::forward(value)} {} - - /** - * @brief Returns the object type info if any, `type_id()` otherwise. - * @return The object type info if any, `type_id()` otherwise. - */ - [[nodiscard]] const type_info &info() const noexcept { - return storage.info(); - } + template + class basic_poly: private Concept::template type>> { + friend struct poly_base; + + public: + /*! @brief Concept type. */ + using concept_type = Concept::template type>; + /*! @brief Virtual table type. */ + using vtable_type = poly_vtable::type; + + /*! @brief Default constructor. */ + basic_poly() noexcept = default; + + /** + * @brief Constructs a poly by directly initializing the new object. + * @tparam Type Type of object to use to initialize the poly. + * @tparam Args Types of arguments to use to construct the new instance. + * @param args Parameters to use to construct the instance. + */ + template + explicit basic_poly(stl::in_place_type_t, Args &&...args) + : storage{stl::in_place_type, stl::forward(args)...}, + vtable{poly_vtable::template instance>()} {} + + /** + * @brief Constructs a poly from a given value. + * @tparam Type Type of object to use to initialize the poly. + * @param value An instance of an object to use to initialize the poly. + */ + template + requires (!stl::same_as, basic_poly>) + basic_poly(Type &&value) noexcept + : basic_poly{stl::in_place_type>, stl::forward(value)} {} + + /** + * @brief Returns the object type info if any, `type_id()` otherwise. + * @return The object type info if any, `type_id()` otherwise. + */ + [[nodiscard]] const type_info &info() const noexcept { + return storage.info(); + } - /** - * @brief Returns an opaque pointer to the contained instance. - * @return An opaque pointer the contained instance, if any. - */ - [[nodiscard]] const void *data() const noexcept { - return storage.data(); - } + /** + * @brief Returns an opaque pointer to the contained instance. + * @return An opaque pointer the contained instance, if any. + */ + [[nodiscard]] const void *data() const noexcept { + return storage.data(); + } - /*! @copydoc data */ - [[nodiscard]] void *data() noexcept { - return storage.data(); - } + /*! @copydoc data */ + [[nodiscard]] void *data() noexcept { + return storage.data(); + } - /** - * @brief Replaces the contained object by creating a new instance directly. - * @tparam Type Type of object to use to initialize the poly. - * @tparam Args Types of arguments to use to construct the new instance. - * @param args Parameters to use to construct the instance. - */ - template - void emplace(Args &&...args) { - storage.template emplace(stl::forward(args)...); - vtable = poly_vtable::template instance>(); - } + /** + * @brief Replaces the contained object by creating a new instance directly. + * @tparam Type Type of object to use to initialize the poly. + * @tparam Args Types of arguments to use to construct the new instance. + * @param args Parameters to use to construct the instance. + */ + template + void emplace(Args &&...args) { + storage.template emplace(stl::forward(args)...); + vtable = poly_vtable::template instance>(); + } - /*! @brief Destroys contained object */ - void reset() { - storage.reset(); - vtable = {}; - } + /*! @brief Destroys contained object */ + void reset() { + storage.reset(); + vtable = {}; + } - /** - * @brief Returns false if a poly is empty, true otherwise. - * @return False if the poly is empty, true otherwise. - */ - [[nodiscard]] explicit operator bool() const noexcept { - return static_cast(storage); - } + /** + * @brief Returns false if a poly is empty, true otherwise. + * @return False if the poly is empty, true otherwise. + */ + [[nodiscard]] explicit operator bool() const noexcept { + return static_cast(storage); + } - /** - * @brief Returns a pointer to the underlying concept. - * @return A pointer to the underlying concept. - */ - [[nodiscard]] concept_type *operator->() noexcept { - return this; - } + /** + * @brief Returns a pointer to the underlying concept. + * @return A pointer to the underlying concept. + */ + [[nodiscard]] concept_type *operator->() noexcept { + return this; + } - /*! @copydoc operator-> */ - [[nodiscard]] const concept_type *operator->() const noexcept { - return this; - } + /*! @copydoc operator-> */ + [[nodiscard]] const concept_type *operator->() const noexcept { + return this; + } - /** - * @brief Aliasing constructor. - * @return A poly that shares a reference to an unmanaged object. - */ - [[nodiscard]] basic_poly as_ref() noexcept { - basic_poly ref{}; - ref.storage = storage.as_ref(); - ref.vtable = vtable; - return ref; - } + /** + * @brief Aliasing constructor. + * @return A poly that shares a reference to an unmanaged object. + */ + [[nodiscard]] basic_poly as_ref() noexcept { + basic_poly ref{}; + ref.storage = storage.as_ref(); + ref.vtable = vtable; + return ref; + } - /*! @copydoc as_ref */ - [[nodiscard]] basic_poly as_ref() const noexcept { - basic_poly ref{}; - ref.storage = storage.as_ref(); - ref.vtable = vtable; - return ref; - } + /*! @copydoc as_ref */ + [[nodiscard]] basic_poly as_ref() const noexcept { + basic_poly ref{}; + ref.storage = storage.as_ref(); + ref.vtable = vtable; + return ref; + } -private: - basic_any storage{}; - vtable_type vtable{}; -}; + private: + basic_any storage{}; + vtable_type vtable{}; + }; } // namespace entt diff --git a/src/entt/process/fwd.hpp b/src/entt/process/fwd.hpp index 77bc4954a7..258ca08762 100644 --- a/src/entt/process/fwd.hpp +++ b/src/entt/process/fwd.hpp @@ -1,22 +1,25 @@ #ifndef ENTT_PROCESS_FWD_HPP #define ENTT_PROCESS_FWD_HPP -#include "../stl/cstdint.hpp" -#include "../stl/memory.hpp" +#include "../config/module.h" -namespace entt { +#ifndef ENTT_MODULE +# include "../stl/cstdint.hpp" +# include "../stl/memory.hpp" +#endif // ENTT_MODULE -template> -class basic_process; +ENTT_MODULE_EXPORT namespace entt { + template> + class basic_process; -/*! @brief Alias declaration for the most common use case. */ -using process = basic_process; + /*! @brief Alias declaration for the most common use case. */ + using process = basic_process; -template> -class basic_scheduler; + template> + class basic_scheduler; -/*! @brief Alias declaration for the most common use case. */ -using scheduler = basic_scheduler; + /*! @brief Alias declaration for the most common use case. */ + using scheduler = basic_scheduler; } // namespace entt diff --git a/src/entt/process/process.hpp b/src/entt/process/process.hpp index 8e5c950e83..b1a6a06fa2 100644 --- a/src/entt/process/process.hpp +++ b/src/entt/process/process.hpp @@ -1,13 +1,17 @@ #ifndef ENTT_PROCESS_PROCESS_HPP #define ENTT_PROCESS_PROCESS_HPP -#include "../core/compressed_pair.hpp" -#include "../core/type_traits.hpp" -#include "../stl/cstdint.hpp" -#include "../stl/memory.hpp" -#include "../stl/type_traits.hpp" -#include "../stl/utility.hpp" -#include "fwd.hpp" +#include "../config/module.h" + +#ifndef ENTT_MODULE +# include "../core/compressed_pair.hpp" +# include "../core/type_traits.hpp" +# include "../stl/cstdint.hpp" +# include "../stl/memory.hpp" +# include "../stl/type_traits.hpp" +# include "../stl/utility.hpp" +# include "fwd.hpp" +#endif // ENTT_MODULE namespace entt { @@ -20,6 +24,8 @@ struct process_adaptor; } // namespace internal /*! @endcond */ +ENTT_MODULE_EXPORT_BEGIN + /** * @brief Base class for processes. * @@ -286,6 +292,9 @@ class basic_process: public stl::enable_shared_from_this next; state current; }; +ENTT_MODULE_EXPORT_END + +/*! @cond TURN_OFF_DOXYGEN */ /*! @cond ENTT_INTERNAL */ namespace internal { diff --git a/src/entt/process/scheduler.hpp b/src/entt/process/scheduler.hpp index 554f7c28c2..d8ca440be3 100644 --- a/src/entt/process/scheduler.hpp +++ b/src/entt/process/scheduler.hpp @@ -1,226 +1,229 @@ #ifndef ENTT_PROCESS_SCHEDULER_HPP #define ENTT_PROCESS_SCHEDULER_HPP -#include "../config/config.h" -#include "../core/compressed_pair.hpp" -#include "../stl/cstddef.hpp" -#include "../stl/memory.hpp" -#include "../stl/type_traits.hpp" -#include "../stl/utility.hpp" -#include "../stl/vector.hpp" -#include "fwd.hpp" -#include "process.hpp" - -namespace entt { - -/** - * @brief Cooperative scheduler for processes. - * - * A cooperative scheduler runs processes and helps managing their life cycles. - * - * Each process is invoked once per tick. If a process terminates, it's - * removed automatically from the scheduler and it's never invoked again.
- * A process can also have a child. In this case, the process is replaced with - * its child when it terminates if it returns with success. In case of errors, - * both the process and its child are discarded. - * - * In order to invoke all scheduled processes, call the `update` member function - * passing it the elapsed time to forward to the tasks. - * - * @sa process - * - * @tparam Delta Type to use to provide elapsed time. - * @tparam Allocator Type of allocator used to manage memory and elements. - */ -template -class basic_scheduler { - using base_type = basic_process; - using alloc_traits = stl::allocator_traits; - using container_allocator = alloc_traits::template rebind_alloc>; - using container_type = stl::vector, container_allocator>; - -public: - /*! @brief Process type. */ - using type = base_type; - /*! @brief Allocator type. */ - using allocator_type = Allocator; - /*! @brief Unsigned integer type. */ - using size_type = stl::size_t; - /*! @brief Unsigned integer type. */ - using delta_type = Delta; - - /*! @brief Default constructor. */ - basic_scheduler() - : basic_scheduler{allocator_type{}} {} - - /** - * @brief Constructs a scheduler with a given allocator. - * @param allocator The allocator to use. - */ - explicit basic_scheduler(const allocator_type &allocator) - : handlers{allocator, allocator} {} - - /*! @brief Default copy constructor, deleted on purpose. */ - basic_scheduler(const basic_scheduler &) = delete; - - /** - * @brief Move constructor. - * @param other The instance to move from. - */ - basic_scheduler(basic_scheduler &&other) noexcept - : handlers{stl::move(other.handlers)} {} - +#include "../config/module.h" + +#ifndef ENTT_MODULE +# include "../config/config.h" +# include "../core/compressed_pair.hpp" +# include "../stl/cstddef.hpp" +# include "../stl/memory.hpp" +# include "../stl/type_traits.hpp" +# include "../stl/utility.hpp" +# include "../stl/vector.hpp" +# include "fwd.hpp" +# include "process.hpp" +#endif // ENTT_MODULE + +ENTT_MODULE_EXPORT namespace entt { /** - * @brief Allocator-extended move constructor. - * @param other The instance to move from. - * @param allocator The allocator to use. - */ - basic_scheduler(basic_scheduler &&other, const allocator_type &allocator) - : handlers{container_type{stl::move(other.handlers.first()), allocator}, allocator} { - ENTT_ASSERT(alloc_traits::is_always_equal::value || get_allocator() == other.get_allocator(), "Copying a scheduler is not allowed"); - } - - /*! @brief Default destructor. */ - ~basic_scheduler() = default; - - /** - * @brief Default copy assignment operator, deleted on purpose. - * @return This process scheduler. - */ - basic_scheduler &operator=(const basic_scheduler &) = delete; - - /** - * @brief Move assignment operator. - * @param other The instance to move from. - * @return This process scheduler. + * @brief Cooperative scheduler for processes. + * + * A cooperative scheduler runs processes and helps managing their life cycles. + * + * Each process is invoked once per tick. If a process terminates, it's + * removed automatically from the scheduler and it's never invoked again.
+ * A process can also have a child. In this case, the process is replaced with + * its child when it terminates if it returns with success. In case of errors, + * both the process and its child are discarded. + * + * In order to invoke all scheduled processes, call the `update` member function + * passing it the elapsed time to forward to the tasks. + * + * @sa process + * + * @tparam Delta Type to use to provide elapsed time. + * @tparam Allocator Type of allocator used to manage memory and elements. */ - basic_scheduler &operator=(basic_scheduler &&other) noexcept { - ENTT_ASSERT(alloc_traits::is_always_equal::value || get_allocator() == other.get_allocator(), "Copying a scheduler is not allowed"); - swap(other); - return *this; - } + template + class basic_scheduler { + using base_type = basic_process; + using alloc_traits = stl::allocator_traits; + using container_allocator = alloc_traits::template rebind_alloc>; + using container_type = stl::vector, container_allocator>; + + public: + /*! @brief Process type. */ + using type = base_type; + /*! @brief Allocator type. */ + using allocator_type = Allocator; + /*! @brief Unsigned integer type. */ + using size_type = stl::size_t; + /*! @brief Unsigned integer type. */ + using delta_type = Delta; + + /*! @brief Default constructor. */ + basic_scheduler() + : basic_scheduler{allocator_type{}} {} + + /** + * @brief Constructs a scheduler with a given allocator. + * @param allocator The allocator to use. + */ + explicit basic_scheduler(const allocator_type &allocator) + : handlers{allocator, allocator} {} + + /*! @brief Default copy constructor, deleted on purpose. */ + basic_scheduler(const basic_scheduler &) = delete; + + /** + * @brief Move constructor. + * @param other The instance to move from. + */ + basic_scheduler(basic_scheduler &&other) noexcept + : handlers{stl::move(other.handlers)} {} + + /** + * @brief Allocator-extended move constructor. + * @param other The instance to move from. + * @param allocator The allocator to use. + */ + basic_scheduler(basic_scheduler &&other, const allocator_type &allocator) + : handlers{container_type{stl::move(other.handlers.first()), allocator}, allocator} { + ENTT_ASSERT(alloc_traits::is_always_equal::value || get_allocator() == other.get_allocator(), "Copying a scheduler is not allowed"); + } - /** - * @brief Exchanges the contents with those of a given scheduler. - * @param other Scheduler to exchange the content with. - */ - void swap(basic_scheduler &other) noexcept { - using stl::swap; - swap(handlers, other.handlers); - } + /*! @brief Default destructor. */ + ~basic_scheduler() = default; + + /** + * @brief Default copy assignment operator, deleted on purpose. + * @return This process scheduler. + */ + basic_scheduler &operator=(const basic_scheduler &) = delete; + + /** + * @brief Move assignment operator. + * @param other The instance to move from. + * @return This process scheduler. + */ + basic_scheduler &operator=(basic_scheduler &&other) noexcept { + ENTT_ASSERT(alloc_traits::is_always_equal::value || get_allocator() == other.get_allocator(), "Copying a scheduler is not allowed"); + swap(other); + return *this; + } - /** - * @brief Returns the associated allocator. - * @return The associated allocator. - */ - [[nodiscard]] constexpr allocator_type get_allocator() const noexcept { - return handlers.second(); - } + /** + * @brief Exchanges the contents with those of a given scheduler. + * @param other Scheduler to exchange the content with. + */ + void swap(basic_scheduler &other) noexcept { + using stl::swap; + swap(handlers, other.handlers); + } - /** - * @brief Number of processes currently scheduled. - * @return Number of processes currently scheduled. - */ - [[nodiscard]] size_type size() const noexcept { - return handlers.first().size(); - } + /** + * @brief Returns the associated allocator. + * @return The associated allocator. + */ + [[nodiscard]] constexpr allocator_type get_allocator() const noexcept { + return handlers.second(); + } - /** - * @brief Returns true if at least a process is currently scheduled. - * @return True if there are scheduled processes, false otherwise. - */ - [[nodiscard]] bool empty() const noexcept { - return handlers.first().empty(); - } + /** + * @brief Number of processes currently scheduled. + * @return Number of processes currently scheduled. + */ + [[nodiscard]] size_type size() const noexcept { + return handlers.first().size(); + } - /** - * @brief Discards all scheduled processes. - * - * Processes aren't aborted. They are discarded along with their children - * and never executed again. - */ - void clear() { - handlers.first().clear(); - } + /** + * @brief Returns true if at least a process is currently scheduled. + * @return True if there are scheduled processes, false otherwise. + */ + [[nodiscard]] bool empty() const noexcept { + return handlers.first().empty(); + } - /** - * @brief Schedules a process for the next tick. - * @tparam Type Type of process to create. - * @tparam Args Types of arguments to use to initialize the process. - * @param args Parameters to use to initialize the process. - * @return A reference to the newly created process. - */ - template - type &attach(Args &&...args) { - const auto &allocator = handlers.second(); - return *handlers.first().emplace_back(stl::allocate_shared(allocator, allocator, stl::forward(args)...)); - } + /** + * @brief Discards all scheduled processes. + * + * Processes aren't aborted. They are discarded along with their children + * and never executed again. + */ + void clear() { + handlers.first().clear(); + } - /** - * @brief Schedules a process for the next tick. - * @tparam Func Type of process to create. - * @param func Either a lambda or a functor to use as a process. - * @return A reference to the newly created process. - */ - template - type &attach(Func func) { - const auto &allocator = handlers.second(); - using process_type = internal::process_adaptor; - return *handlers.first().emplace_back(stl::allocate_shared(allocator, allocator, stl::move(func))); - } + /** + * @brief Schedules a process for the next tick. + * @tparam Type Type of process to create. + * @tparam Args Types of arguments to use to initialize the process. + * @param args Parameters to use to initialize the process. + * @return A reference to the newly created process. + */ + template + type &attach(Args &&...args) { + const auto &allocator = handlers.second(); + return *handlers.first().emplace_back(stl::allocate_shared(allocator, allocator, stl::forward(args)...)); + } - /** - * @brief Updates all scheduled processes. - * - * All scheduled processes are executed in no specific order.
- * If a process terminates with success, it's replaced with its child, if - * any. Otherwise, if a process terminates with an error, it's removed along - * with its child. - * - * @param delta Elapsed time. - * @param data Optional data. - */ - void update(const delta_type delta, void *data = nullptr) { - for(auto next = handlers.first().size(); next; --next) { - const auto pos = next - 1u; - handlers.first()[pos]->tick(delta, data); - // updating might spawn/reallocate, cannot hold refs until here - auto &elem = handlers.first()[pos]; - - if(elem->finished()) { - elem = elem->peek(); - } + /** + * @brief Schedules a process for the next tick. + * @tparam Func Type of process to create. + * @param func Either a lambda or a functor to use as a process. + * @return A reference to the newly created process. + */ + template + type &attach(Func func) { + const auto &allocator = handlers.second(); + using process_type = internal::process_adaptor; + return *handlers.first().emplace_back(stl::allocate_shared(allocator, allocator, stl::move(func))); + } - if(!elem || elem->rejected()) { - elem = stl::move(handlers.first().back()); - handlers.first().pop_back(); + /** + * @brief Updates all scheduled processes. + * + * All scheduled processes are executed in no specific order.
+ * If a process terminates with success, it's replaced with its child, if + * any. Otherwise, if a process terminates with an error, it's removed along + * with its child. + * + * @param delta Elapsed time. + * @param data Optional data. + */ + void update(const delta_type delta, void *data = nullptr) { + for(auto next = handlers.first().size(); next; --next) { + const auto pos = next - 1u; + handlers.first()[pos]->tick(delta, data); + // updating might spawn/reallocate, cannot hold refs until here + auto &elem = handlers.first()[pos]; + + if(elem->finished()) { + elem = elem->peek(); + } + + if(!elem || elem->rejected()) { + elem = stl::move(handlers.first().back()); + handlers.first().pop_back(); + } } } - } - - /** - * @brief Aborts all scheduled processes. - * - * Unless an immediate operation is requested, the abort is scheduled for - * the next tick. Processes won't be executed anymore in any case.
- * Once a process is fully aborted and thus finished, it's discarded along - * with its child, if any. - * - * @param immediate Requests an immediate operation. - */ - void abort(const bool immediate = false) { - for(auto &&curr: handlers.first()) { - curr->abort(); - if(immediate) { - curr->tick({}); + /** + * @brief Aborts all scheduled processes. + * + * Unless an immediate operation is requested, the abort is scheduled for + * the next tick. Processes won't be executed anymore in any case.
+ * Once a process is fully aborted and thus finished, it's discarded along + * with its child, if any. + * + * @param immediate Requests an immediate operation. + */ + void abort(const bool immediate = false) { + for(auto &&curr: handlers.first()) { + curr->abort(); + + if(immediate) { + curr->tick({}); + } } } - } -private: - compressed_pair handlers; -}; + private: + compressed_pair handlers; + }; } // namespace entt diff --git a/src/entt/resource/cache.hpp b/src/entt/resource/cache.hpp index 6f124caacb..92173e1c49 100644 --- a/src/entt/resource/cache.hpp +++ b/src/entt/resource/cache.hpp @@ -1,22 +1,26 @@ #ifndef ENTT_RESOURCE_RESOURCE_CACHE_HPP #define ENTT_RESOURCE_RESOURCE_CACHE_HPP -#include -#include "../container/dense_map.hpp" -#include "../core/compressed_pair.hpp" -#include "../core/fwd.hpp" -#include "../core/iterator.hpp" -#include "../stl/concepts.hpp" -#include "../stl/cstddef.hpp" -#include "../stl/functional.hpp" -#include "../stl/iterator.hpp" -#include "../stl/memory.hpp" -#include "../stl/tuple.hpp" -#include "../stl/type_traits.hpp" -#include "../stl/utility.hpp" -#include "fwd.hpp" -#include "loader.hpp" -#include "resource.hpp" +#include "../config/module.h" + +#ifndef ENTT_MODULE +# include +# include "../container/dense_map.hpp" +# include "../core/compressed_pair.hpp" +# include "../core/fwd.hpp" +# include "../core/iterator.hpp" +# include "../stl/concepts.hpp" +# include "../stl/cstddef.hpp" +# include "../stl/functional.hpp" +# include "../stl/iterator.hpp" +# include "../stl/memory.hpp" +# include "../stl/tuple.hpp" +# include "../stl/type_traits.hpp" +# include "../stl/utility.hpp" +# include "fwd.hpp" +# include "loader.hpp" +# include "resource.hpp" +#endif // ENTT_MODULE namespace entt { @@ -116,6 +120,8 @@ class resource_cache_iterator final { } // namespace internal /*! @endcond */ +ENTT_MODULE_EXPORT_BEGIN + /** * @brief Basic cache for resources of any type. * @tparam Type Type of resources managed by a cache. @@ -381,6 +387,8 @@ class resource_cache { compressed_pair pool; }; +ENTT_MODULE_EXPORT_END + } // namespace entt #endif diff --git a/src/entt/resource/fwd.hpp b/src/entt/resource/fwd.hpp index bb9c542df5..a6b5097dbb 100644 --- a/src/entt/resource/fwd.hpp +++ b/src/entt/resource/fwd.hpp @@ -1,18 +1,21 @@ #ifndef ENTT_RESOURCE_FWD_HPP #define ENTT_RESOURCE_FWD_HPP -#include "../stl/memory.hpp" +#include "../config/module.h" -namespace entt { +#ifndef ENTT_MODULE +# include "../stl/memory.hpp" +#endif // ENTT_MODULE -template -struct resource_loader; +ENTT_MODULE_EXPORT namespace entt { + template + struct resource_loader; -template, typename = stl::allocator> -class resource_cache; + template, typename = stl::allocator> + class resource_cache; -template -class resource; + template + class resource; } // namespace entt diff --git a/src/entt/resource/loader.hpp b/src/entt/resource/loader.hpp index 2df95d07f8..27b40e5cb8 100644 --- a/src/entt/resource/loader.hpp +++ b/src/entt/resource/loader.hpp @@ -1,32 +1,35 @@ #ifndef ENTT_RESOURCE_LOADER_HPP #define ENTT_RESOURCE_LOADER_HPP -#include "../stl/memory.hpp" -#include "../stl/utility.hpp" -#include "fwd.hpp" +#include "../config/module.h" -namespace entt { - -/** - * @brief Transparent loader for shared resources. - * @tparam Type Type of resources created by the loader. - */ -template -struct resource_loader { - /*! @brief Result type. */ - using result_type = stl::shared_ptr; +#ifndef ENTT_MODULE +# include "../stl/memory.hpp" +# include "../stl/utility.hpp" +# include "fwd.hpp" +#endif // ENTT_MODULE +ENTT_MODULE_EXPORT namespace entt { /** - * @brief Constructs a shared pointer to a resource from its arguments. - * @tparam Args Types of arguments to use to construct the resource. - * @param args Parameters to use to construct the resource. - * @return A shared pointer to a resource of the given type. + * @brief Transparent loader for shared resources. + * @tparam Type Type of resources created by the loader. */ - template - result_type operator()(Args &&...args) const { - return stl::make_shared(stl::forward(args)...); - } -}; + template + struct resource_loader { + /*! @brief Result type. */ + using result_type = stl::shared_ptr; + + /** + * @brief Constructs a shared pointer to a resource from its arguments. + * @tparam Args Types of arguments to use to construct the resource. + * @param args Parameters to use to construct the resource. + * @return A shared pointer to a resource of the given type. + */ + template + result_type operator()(Args &&...args) const { + return stl::make_shared(stl::forward(args)...); + } + }; } // namespace entt diff --git a/src/entt/resource/resource.hpp b/src/entt/resource/resource.hpp index ce3d2b9278..4482e88d2f 100644 --- a/src/entt/resource/resource.hpp +++ b/src/entt/resource/resource.hpp @@ -1,211 +1,214 @@ #ifndef ENTT_RESOURCE_RESOURCE_HPP #define ENTT_RESOURCE_RESOURCE_HPP -#include -#include "../stl/concepts.hpp" -#include "../stl/memory.hpp" -#include "../stl/utility.hpp" -#include "fwd.hpp" - -namespace entt { - -/** - * @brief Basic resource handle. - * - * A handle wraps a resource and extends its lifetime. It also shares the same - * resource with all other handles constructed from the same element.
- * As a rule of thumb, resources should never be copied nor moved. Handles are - * the way to go to push references around. - * - * @tparam Type Type of resource managed by a handle. - */ -template -class resource { - template - friend class resource; - -public: - /*! @brief Resource type. */ - using element_type = Type; - /*! @brief Handle type. */ - using handle_type = stl::shared_ptr; - - /*! @brief Default constructor. */ - resource() noexcept - : value{} {} +#include "../config/module.h" - /** - * @brief Creates a new resource handle. - * @param res A handle to a resource. - */ - explicit resource(handle_type res) noexcept - : value{stl::move(res)} {} - - /*! @brief Default copy constructor. */ - resource(const resource &) noexcept = default; - - /*! @brief Default move constructor. */ - resource(resource &&) noexcept = default; - - /** - * @brief Aliasing constructor. - * @tparam Other Type of resource managed by the received handle. - * @param other The handle with which to share ownership information. - * @param res Unrelated and unmanaged resources. - */ - template - resource(const resource &other, element_type &res) noexcept - : value{other.value, stl::addressof(res)} {} - - /** - * @brief Copy constructs a handle which shares ownership of the resource. - * @tparam Other Type of resource managed by the received handle. - * @param other The handle to copy from. - */ - template - requires (!stl::same_as && stl::constructible_from) - resource(const resource &other) noexcept - : value{other.value} {} - - /** - * @brief Move constructs a handle which takes ownership of the resource. - * @tparam Other Type of resource managed by the received handle. - * @param other The handle to move from. - */ - template - requires (!stl::same_as && stl::constructible_from) - resource(resource &&other) noexcept - : value{stl::move(other.value)} {} - - /*! @brief Default destructor. */ - ~resource() = default; - - /** - * @brief Default copy assignment operator. - * @return This resource handle. - */ - resource &operator=(const resource &) noexcept = default; - - /** - * @brief Default move assignment operator. - * @return This resource handle. - */ - resource &operator=(resource &&) noexcept = default; - - /** - * @brief Copy assignment operator from foreign handle. - * @tparam Other Type of resource managed by the received handle. - * @param other The handle to copy from. - * @return This resource handle. - */ - template - requires (!stl::same_as && stl::constructible_from) - resource &operator=(const resource &other) noexcept { - value = other.value; - return *this; - } - - /** - * @brief Move assignment operator from foreign handle. - * @tparam Other Type of resource managed by the received handle. - * @param other The handle to move from. - * @return This resource handle. - */ - template - requires (!stl::same_as && stl::constructible_from) - resource &operator=(resource &&other) noexcept { - value = stl::move(other.value); - return *this; - } +#ifndef ENTT_MODULE +# include +# include "../stl/concepts.hpp" +# include "../stl/memory.hpp" +# include "../stl/utility.hpp" +# include "fwd.hpp" +#endif // ENTT_MODULE +ENTT_MODULE_EXPORT namespace entt { /** - * @brief Exchanges the content with that of a given resource. - * @param other Resource to exchange the content with. - */ - void swap(resource &other) noexcept { - using stl::swap; - swap(value, other.value); - } - - /** - * @brief Returns a reference to the managed resource. + * @brief Basic resource handle. * - * @warning - * The behavior is undefined if the handle doesn't contain a resource. + * A handle wraps a resource and extends its lifetime. It also shares the same + * resource with all other handles constructed from the same element.
+ * As a rule of thumb, resources should never be copied nor moved. Handles are + * the way to go to push references around. * - * @return A reference to the managed resource. - */ - [[nodiscard]] element_type &operator*() const noexcept { - return *value; - } - - /*! @copydoc operator* */ - [[nodiscard]] operator element_type &() const noexcept { - return *value; - } - - /** - * @brief Returns a pointer to the managed resource. - * @return A pointer to the managed resource. - */ - [[nodiscard]] element_type *operator->() const noexcept { - return value.get(); - } - - /** - * @brief Returns true if a handle contains a resource, false otherwise. - * @return True if the handle contains a resource, false otherwise. - */ - [[nodiscard]] explicit operator bool() const noexcept { - return static_cast(value); - } - - /** - * @brief Compares two handles. - * @tparam Other Type of resource managed by the other handle. - * @param other A valid handle. - * @return True if both handles refer to the same resource, false otherwise. - */ - template - [[nodiscard]] bool operator==(const resource &other) const noexcept { - return (stl::addressof(*value) == stl::addressof(*other.value)); - } - - /** - * @brief Lexicographically compares two handles. - * @tparam Other Type of resource managed by the other handle. - * @param other A valid handle. - * @return The relative order between the two handles. - */ - template - [[nodiscard]] auto operator<=>(const resource &other) const noexcept { - return (stl::addressof(*value) <=> stl::addressof(*other.value)); - } - - /*! @brief Releases the ownership of the managed resource. */ - void reset() { - value.reset(); - } - - /** - * @brief Replaces the managed resource. - * @param other A handle to a resource. - */ - void reset(handle_type other) { - value = stl::move(other); - } - - /** - * @brief Returns the underlying resource handle. - * @return The underlying resource handle. - */ - [[nodiscard]] handle_type handle() const noexcept { - return value; - } - -private: - handle_type value; -}; + * @tparam Type Type of resource managed by a handle. + */ + template + class resource { + template + friend class resource; + + public: + /*! @brief Resource type. */ + using element_type = Type; + /*! @brief Handle type. */ + using handle_type = stl::shared_ptr; + + /*! @brief Default constructor. */ + resource() noexcept + : value{} {} + + /** + * @brief Creates a new resource handle. + * @param res A handle to a resource. + */ + explicit resource(handle_type res) noexcept + : value{stl::move(res)} {} + + /*! @brief Default copy constructor. */ + resource(const resource &) noexcept = default; + + /*! @brief Default move constructor. */ + resource(resource &&) noexcept = default; + + /** + * @brief Aliasing constructor. + * @tparam Other Type of resource managed by the received handle. + * @param other The handle with which to share ownership information. + * @param res Unrelated and unmanaged resources. + */ + template + resource(const resource &other, element_type &res) noexcept + : value{other.value, stl::addressof(res)} {} + + /** + * @brief Copy constructs a handle which shares ownership of the resource. + * @tparam Other Type of resource managed by the received handle. + * @param other The handle to copy from. + */ + template + requires (!stl::same_as && stl::constructible_from) + resource(const resource &other) noexcept + : value{other.value} {} + + /** + * @brief Move constructs a handle which takes ownership of the resource. + * @tparam Other Type of resource managed by the received handle. + * @param other The handle to move from. + */ + template + requires (!stl::same_as && stl::constructible_from) + resource(resource &&other) noexcept + : value{stl::move(other.value)} {} + + /*! @brief Default destructor. */ + ~resource() = default; + + /** + * @brief Default copy assignment operator. + * @return This resource handle. + */ + resource &operator=(const resource &) noexcept = default; + + /** + * @brief Default move assignment operator. + * @return This resource handle. + */ + resource &operator=(resource &&) noexcept = default; + + /** + * @brief Copy assignment operator from foreign handle. + * @tparam Other Type of resource managed by the received handle. + * @param other The handle to copy from. + * @return This resource handle. + */ + template + requires (!stl::same_as && stl::constructible_from) + resource &operator=(const resource &other) noexcept { + value = other.value; + return *this; + } + + /** + * @brief Move assignment operator from foreign handle. + * @tparam Other Type of resource managed by the received handle. + * @param other The handle to move from. + * @return This resource handle. + */ + template + requires (!stl::same_as && stl::constructible_from) + resource &operator=(resource &&other) noexcept { + value = stl::move(other.value); + return *this; + } + + /** + * @brief Exchanges the content with that of a given resource. + * @param other Resource to exchange the content with. + */ + void swap(resource &other) noexcept { + using stl::swap; + swap(value, other.value); + } + + /** + * @brief Returns a reference to the managed resource. + * + * @warning + * The behavior is undefined if the handle doesn't contain a resource. + * + * @return A reference to the managed resource. + */ + [[nodiscard]] element_type &operator*() const noexcept { + return *value; + } + + /*! @copydoc operator* */ + [[nodiscard]] operator element_type &() const noexcept { + return *value; + } + + /** + * @brief Returns a pointer to the managed resource. + * @return A pointer to the managed resource. + */ + [[nodiscard]] element_type *operator->() const noexcept { + return value.get(); + } + + /** + * @brief Returns true if a handle contains a resource, false otherwise. + * @return True if the handle contains a resource, false otherwise. + */ + [[nodiscard]] explicit operator bool() const noexcept { + return static_cast(value); + } + + /** + * @brief Compares two handles. + * @tparam Other Type of resource managed by the other handle. + * @param other A valid handle. + * @return True if both handles refer to the same resource, false otherwise. + */ + template + [[nodiscard]] bool operator==(const resource &other) const noexcept { + return (stl::addressof(*value) == stl::addressof(*other.value)); + } + + /** + * @brief Lexicographically compares two handles. + * @tparam Other Type of resource managed by the other handle. + * @param other A valid handle. + * @return The relative order between the two handles. + */ + template + [[nodiscard]] auto operator<=>(const resource &other) const noexcept { + return (stl::addressof(*value) <=> stl::addressof(*other.value)); + } + + /*! @brief Releases the ownership of the managed resource. */ + void reset() { + value.reset(); + } + + /** + * @brief Replaces the managed resource. + * @param other A handle to a resource. + */ + void reset(handle_type other) { + value = stl::move(other); + } + + /** + * @brief Returns the underlying resource handle. + * @return The underlying resource handle. + */ + [[nodiscard]] handle_type handle() const noexcept { + return value; + } + + private: + handle_type value; + }; } // namespace entt diff --git a/src/entt/signal/delegate.hpp b/src/entt/signal/delegate.hpp index 0ecedcdacc..e1be83270a 100644 --- a/src/entt/signal/delegate.hpp +++ b/src/entt/signal/delegate.hpp @@ -1,17 +1,20 @@ #ifndef ENTT_SIGNAL_DELEGATE_HPP #define ENTT_SIGNAL_DELEGATE_HPP -#include "../config/config.h" -#include "../core/type_traits.hpp" -#include "../stl/cstddef.hpp" -#include "../stl/functional.hpp" -#include "../stl/tuple.hpp" -#include "../stl/type_traits.hpp" -#include "../stl/utility.hpp" -#include "fwd.hpp" +#include "../config/module.h" + +#ifndef ENTT_MODULE +# include "../config/config.h" +# include "../core/type_traits.hpp" +# include "../stl/cstddef.hpp" +# include "../stl/functional.hpp" +# include "../stl/tuple.hpp" +# include "../stl/type_traits.hpp" +# include "../stl/utility.hpp" +# include "fwd.hpp" +#endif // ENTT_MODULE namespace entt { - /*! @cond ENTT_INTERNAL */ namespace internal { @@ -42,6 +45,8 @@ template } // namespace internal /*! @endcond */ +ENTT_MODULE_EXPORT_BEGIN + /** * @brief Basic delegate implementation. * @@ -309,6 +314,8 @@ delegate(connect_arg_t, Type &&) -> delegate delegate(Ret (*)(const void *, Args...), const void * = nullptr) -> delegate; +ENTT_MODULE_EXPORT_END + } // namespace entt #endif diff --git a/src/entt/signal/dispatcher.hpp b/src/entt/signal/dispatcher.hpp index 3a3cceec6f..f6b0a14115 100644 --- a/src/entt/signal/dispatcher.hpp +++ b/src/entt/signal/dispatcher.hpp @@ -1,19 +1,23 @@ #ifndef ENTT_SIGNAL_DISPATCHER_HPP #define ENTT_SIGNAL_DISPATCHER_HPP -#include "../container/dense_map.hpp" -#include "../core/compressed_pair.hpp" -#include "../core/concepts.hpp" -#include "../core/fwd.hpp" -#include "../core/type_info.hpp" -#include "../stl/cstddef.hpp" -#include "../stl/functional.hpp" -#include "../stl/memory.hpp" -#include "../stl/type_traits.hpp" -#include "../stl/utility.hpp" -#include "../stl/vector.hpp" -#include "fwd.hpp" -#include "sigh.hpp" +#include "../config/module.h" + +#ifndef ENTT_MODULE +# include "../container/dense_map.hpp" +# include "../core/compressed_pair.hpp" +# include "../core/concepts.hpp" +# include "../core/fwd.hpp" +# include "../core/type_info.hpp" +# include "../stl/cstddef.hpp" +# include "../stl/functional.hpp" +# include "../stl/memory.hpp" +# include "../stl/type_traits.hpp" +# include "../stl/utility.hpp" +# include "../stl/vector.hpp" +# include "fwd.hpp" +# include "sigh.hpp" +#endif // ENTT_MODULE namespace entt { @@ -87,6 +91,8 @@ class dispatcher_handler final: public basic_dispatcher_handler { } // namespace internal /*! @endcond */ +ENTT_MODULE_EXPORT_BEGIN + /** * @brief Basic dispatcher implementation. * @@ -386,6 +392,8 @@ class basic_dispatcher { compressed_pair pools; }; +ENTT_MODULE_EXPORT_END + } // namespace entt #endif diff --git a/src/entt/signal/emitter.hpp b/src/entt/signal/emitter.hpp index 1ef49515a7..29a2fd01fa 100644 --- a/src/entt/signal/emitter.hpp +++ b/src/entt/signal/emitter.hpp @@ -1,180 +1,183 @@ #ifndef ENTT_SIGNAL_EMITTER_HPP #define ENTT_SIGNAL_EMITTER_HPP -#include "../container/dense_map.hpp" -#include "../core/compressed_pair.hpp" -#include "../core/fwd.hpp" -#include "../core/type_info.hpp" -#include "../stl/functional.hpp" -#include "../stl/type_traits.hpp" -#include "../stl/utility.hpp" -#include "fwd.hpp" - -namespace entt { - -/** - * @brief General purpose event emitter. - * - * To create an emitter type, derived classes must inherit from the base as: - * - * @code{.cpp} - * struct my_emitter: emitter { - * // ... - * } - * @endcode - * - * Handlers for the different events are created internally on the fly. It's not - * required to specify in advance the full list of accepted events.
- * Moreover, whenever an event is published, an emitter also passes a reference - * to itself to its listeners. - * - * @tparam Derived Emitter type. - * @tparam Allocator Type of allocator used to manage memory and elements. - */ -template -class emitter { - using key_type = id_type; - using mapped_type = stl::function; - - using alloc_traits = stl::allocator_traits; - using container_allocator = alloc_traits::template rebind_alloc>; - using container_type = dense_map, container_allocator>; - -public: - /*! @brief Allocator type. */ - using allocator_type = Allocator; - /*! @brief Unsigned integer type. */ - using size_type = stl::size_t; - - /*! @brief Default constructor. */ - emitter() - : emitter{allocator_type{}} {} - - /** - * @brief Constructs an emitter with a given allocator. - * @param allocator The allocator to use. - */ - explicit emitter(const allocator_type &allocator) - : handlers{allocator, allocator} {} - - /*! @brief Default copy constructor, deleted on purpose. */ - emitter(const emitter &) = delete; - +#include "../config/module.h" + +#ifndef ENTT_MODULE +# include "../container/dense_map.hpp" +# include "../core/compressed_pair.hpp" +# include "../core/fwd.hpp" +# include "../core/type_info.hpp" +# include "../stl/functional.hpp" +# include "../stl/type_traits.hpp" +# include "../stl/utility.hpp" +# include "fwd.hpp" +#endif // ENTT_MODULE + +ENTT_MODULE_EXPORT namespace entt { /** - * @brief Move constructor. - * @param other The instance to move from. + * @brief General purpose event emitter. + * + * To create an emitter type, derived classes must inherit from the base as: + * + * @code{.cpp} + * struct my_emitter: emitter { + * // ... + * } + * @endcode + * + * Handlers for the different events are created internally on the fly. It's not + * required to specify in advance the full list of accepted events.
+ * Moreover, whenever an event is published, an emitter also passes a reference + * to itself to its listeners. + * + * @tparam Derived Emitter type. + * @tparam Allocator Type of allocator used to manage memory and elements. */ - emitter(emitter &&other) noexcept - : handlers{stl::move(other.handlers)} {} - - /** - * @brief Allocator-extended move constructor. - * @param other The instance to move from. - * @param allocator The allocator to use. - */ - emitter(emitter &&other, const allocator_type &allocator) - : handlers{container_type{stl::move(other.handlers.first()), allocator}, allocator} { - ENTT_ASSERT(alloc_traits::is_always_equal::value || handlers.second() == other.handlers.second(), "Copying an emitter is not allowed"); - } - - /*! @brief Default destructor. */ - virtual ~emitter() { - static_assert(stl::is_base_of_v, Derived>, "Invalid emitter type"); - } + template + class emitter { + using key_type = id_type; + using mapped_type = stl::function; + + using alloc_traits = stl::allocator_traits; + using container_allocator = alloc_traits::template rebind_alloc>; + using container_type = dense_map, container_allocator>; + + public: + /*! @brief Allocator type. */ + using allocator_type = Allocator; + /*! @brief Unsigned integer type. */ + using size_type = stl::size_t; + + /*! @brief Default constructor. */ + emitter() + : emitter{allocator_type{}} {} + + /** + * @brief Constructs an emitter with a given allocator. + * @param allocator The allocator to use. + */ + explicit emitter(const allocator_type &allocator) + : handlers{allocator, allocator} {} + + /*! @brief Default copy constructor, deleted on purpose. */ + emitter(const emitter &) = delete; + + /** + * @brief Move constructor. + * @param other The instance to move from. + */ + emitter(emitter &&other) noexcept + : handlers{stl::move(other.handlers)} {} + + /** + * @brief Allocator-extended move constructor. + * @param other The instance to move from. + * @param allocator The allocator to use. + */ + emitter(emitter &&other, const allocator_type &allocator) + : handlers{container_type{stl::move(other.handlers.first()), allocator}, allocator} { + ENTT_ASSERT(alloc_traits::is_always_equal::value || handlers.second() == other.handlers.second(), "Copying an emitter is not allowed"); + } - /** - * @brief Default copy assignment operator, deleted on purpose. - * @return This emitter. - */ - emitter &operator=(const emitter &) = delete; + /*! @brief Default destructor. */ + virtual ~emitter() { + static_assert(stl::is_base_of_v, Derived>, "Invalid emitter type"); + } - /** - * @brief Move assignment operator. - * @param other The instance to move from. - * @return This emitter. - */ - emitter &operator=(emitter &&other) noexcept { - ENTT_ASSERT(alloc_traits::is_always_equal::value || handlers.second() == other.handlers.second(), "Copying an emitter is not allowed"); - swap(other); - return *this; - } + /** + * @brief Default copy assignment operator, deleted on purpose. + * @return This emitter. + */ + emitter &operator=(const emitter &) = delete; + + /** + * @brief Move assignment operator. + * @param other The instance to move from. + * @return This emitter. + */ + emitter &operator=(emitter &&other) noexcept { + ENTT_ASSERT(alloc_traits::is_always_equal::value || handlers.second() == other.handlers.second(), "Copying an emitter is not allowed"); + swap(other); + return *this; + } - /** - * @brief Exchanges the contents with those of a given emitter. - * @param other Emitter to exchange the content with. - */ - void swap(emitter &other) noexcept { - using stl::swap; - swap(handlers, other.handlers); - } + /** + * @brief Exchanges the contents with those of a given emitter. + * @param other Emitter to exchange the content with. + */ + void swap(emitter &other) noexcept { + using stl::swap; + swap(handlers, other.handlers); + } - /** - * @brief Returns the associated allocator. - * @return The associated allocator. - */ - [[nodiscard]] constexpr allocator_type get_allocator() const noexcept { - return handlers.second(); - } + /** + * @brief Returns the associated allocator. + * @return The associated allocator. + */ + [[nodiscard]] constexpr allocator_type get_allocator() const noexcept { + return handlers.second(); + } - /** - * @brief Publishes a given event. - * @tparam Type Type of event to trigger. - * @param value An instance of the given type of event. - */ - template - void publish(Type value) { - if(const auto id = type_id().hash(); handlers.first().contains(id)) { - handlers.first()[id](&value); + /** + * @brief Publishes a given event. + * @tparam Type Type of event to trigger. + * @param value An instance of the given type of event. + */ + template + void publish(Type value) { + if(const auto id = type_id().hash(); handlers.first().contains(id)) { + handlers.first()[id](&value); + } } - } - /** - * @brief Registers a listener with the event emitter. - * @tparam Type Type of event to which to connect the listener. - * @param func The listener to register. - */ - template - void on(stl::function func) { - handlers.first().insert_or_assign(type_id().hash(), [func = stl::move(func), this](void *value) { - func(*static_cast(value), static_cast(*this)); - }); - } + /** + * @brief Registers a listener with the event emitter. + * @tparam Type Type of event to which to connect the listener. + * @param func The listener to register. + */ + template + void on(stl::function func) { + handlers.first().insert_or_assign(type_id().hash(), [func = stl::move(func), this](void *value) { + func(*static_cast(value), static_cast(*this)); + }); + } - /** - * @brief Disconnects a listener from the event emitter. - * @tparam Type Type of event of the listener. - */ - template - void erase() { - handlers.first().erase(type_hash>::value()); - } + /** + * @brief Disconnects a listener from the event emitter. + * @tparam Type Type of event of the listener. + */ + template + void erase() { + handlers.first().erase(type_hash>::value()); + } - /*! @brief Disconnects all the listeners. */ - void clear() noexcept { - handlers.first().clear(); - } + /*! @brief Disconnects all the listeners. */ + void clear() noexcept { + handlers.first().clear(); + } - /** - * @brief Checks if there are listeners registered for the specific event. - * @tparam Type Type of event to test. - * @return True if there are no listeners registered, false otherwise. - */ - template - [[nodiscard]] bool contains() const { - return handlers.first().contains(type_hash>::value()); - } + /** + * @brief Checks if there are listeners registered for the specific event. + * @tparam Type Type of event to test. + * @return True if there are no listeners registered, false otherwise. + */ + template + [[nodiscard]] bool contains() const { + return handlers.first().contains(type_hash>::value()); + } - /** - * @brief Checks if there are listeners registered with the event emitter. - * @return True if there are no listeners registered, false otherwise. - */ - [[nodiscard]] bool empty() const noexcept { - return handlers.first().empty(); - } + /** + * @brief Checks if there are listeners registered with the event emitter. + * @return True if there are no listeners registered, false otherwise. + */ + [[nodiscard]] bool empty() const noexcept { + return handlers.first().empty(); + } -private: - compressed_pair handlers; -}; + private: + compressed_pair handlers; + }; } // namespace entt diff --git a/src/entt/signal/fwd.hpp b/src/entt/signal/fwd.hpp index 4543622e2b..acb75f6d0b 100644 --- a/src/entt/signal/fwd.hpp +++ b/src/entt/signal/fwd.hpp @@ -1,45 +1,48 @@ #ifndef ENTT_SIGNAL_FWD_HPP #define ENTT_SIGNAL_FWD_HPP -#include "../stl/memory.hpp" +#include "../config/module.h" -namespace entt { +#ifndef ENTT_MODULE +# include "../stl/memory.hpp" +#endif // ENTT_MODULE -template -class delegate; +ENTT_MODULE_EXPORT namespace entt { + template + class delegate; -template> -class basic_dispatcher; + template> + class basic_dispatcher; -template> -class emitter; + template> + class emitter; -class connection; + class connection; -struct scoped_connection; + struct scoped_connection; -template -class sink; + template + class sink; -template> -class sigh; + template> + class sigh; -/*! @brief Alias declaration for the most common use case. */ -using dispatcher = basic_dispatcher<>; + /*! @brief Alias declaration for the most common use case. */ + using dispatcher = basic_dispatcher<>; -/*! @brief Disambiguation tag for constructors and the like. */ -template -struct connect_arg_t { - /*! @brief Default constructor. */ - explicit connect_arg_t() = default; -}; + /*! @brief Disambiguation tag for constructors and the like. */ + template + struct connect_arg_t { + /*! @brief Default constructor. */ + explicit connect_arg_t() = default; + }; -/** - * @brief Constant of type connect_arg_t used to disambiguate calls. - * @tparam Candidate Element to connect (likely a free or member function). - */ -template -inline constexpr connect_arg_t connect_arg{}; + /** + * @brief Constant of type connect_arg_t used to disambiguate calls. + * @tparam Candidate Element to connect (likely a free or member function). + */ + template + inline constexpr connect_arg_t connect_arg{}; } // namespace entt diff --git a/src/entt/signal/sigh.hpp b/src/entt/signal/sigh.hpp index 6b0afdfbb3..6dca774091 100644 --- a/src/entt/signal/sigh.hpp +++ b/src/entt/signal/sigh.hpp @@ -1,572 +1,575 @@ #ifndef ENTT_SIGNAL_SIGH_HPP #define ENTT_SIGNAL_SIGH_HPP -#include "../stl/cstddef.hpp" -#include "../stl/memory.hpp" -#include "../stl/type_traits.hpp" -#include "../stl/utility.hpp" -#include "../stl/vector.hpp" -#include "delegate.hpp" -#include "fwd.hpp" - -namespace entt { - -/** - * @brief Sink class. - * - * Primary template isn't defined on purpose. All the specializations give a - * compile-time error unless the template parameter is a function type. - * - * @tparam Type A valid signal handler type. - */ -template -class sink; - -/** - * @brief Unmanaged signal handler. - * - * Primary template isn't defined on purpose. All the specializations give a - * compile-time error unless the template parameter is a function type. - * - * @tparam Type A valid function type. - * @tparam Allocator Type of allocator used to manage memory and elements. - */ -template -class sigh; - -/** - * @brief Unmanaged signal handler. - * - * It works directly with references to classes and pointers to member functions - * as well as pointers to free functions. Users of this class are in charge of - * disconnecting instances before deleting them. - * - * This class serves mainly two purposes: - * - * * Creating signals to use later to notify a bunch of listeners. - * * Collecting results from a set of functions like in a voting system. - * - * @tparam Ret Return type of a function type. - * @tparam Args Types of arguments of a function type. - * @tparam Allocator Type of allocator used to manage memory and elements. - */ -template -class sigh { - friend class sink>; - - using alloc_traits = stl::allocator_traits; - using delegate_type = delegate; - using container_type = stl::vector>; - -public: - /*! @brief Allocator type. */ - using allocator_type = Allocator; - /*! @brief Unsigned integer type. */ - using size_type = stl::size_t; - /*! @brief Sink type. */ - using sink_type = sink>; - - /*! @brief Default constructor. */ - sigh() noexcept(noexcept(allocator_type{})) - : sigh{allocator_type{}} {} - - /** - * @brief Constructs a signal handler with a given allocator. - * @param allocator The allocator to use. - */ - explicit sigh(const allocator_type &allocator) noexcept - : calls{allocator} {} - +#include "../config/module.h" + +#ifndef ENTT_MODULE +# include "../stl/cstddef.hpp" +# include "../stl/memory.hpp" +# include "../stl/type_traits.hpp" +# include "../stl/utility.hpp" +# include "../stl/vector.hpp" +# include "delegate.hpp" +# include "fwd.hpp" +#endif // ENTT_MODULE + +ENTT_MODULE_EXPORT namespace entt { /** - * @brief Copy constructor. - * @param other The instance to copy from. - */ - sigh(const sigh &other) - : calls{other.calls} {} - - /** - * @brief Allocator-extended copy constructor. - * @param other The instance to copy from. - * @param allocator The allocator to use. - */ - sigh(const sigh &other, const allocator_type &allocator) - : calls{other.calls, allocator} {} - - /** - * @brief Move constructor. - * @param other The instance to move from. + * @brief Sink class. + * + * Primary template isn't defined on purpose. All the specializations give a + * compile-time error unless the template parameter is a function type. + * + * @tparam Type A valid signal handler type. */ - sigh(sigh &&other) noexcept - : calls{stl::move(other.calls)} {} + template + class sink; /** - * @brief Allocator-extended move constructor. - * @param other The instance to move from. - * @param allocator The allocator to use. - */ - sigh(sigh &&other, const allocator_type &allocator) - : calls{stl::move(other.calls), allocator} {} - - /*! @brief Default destructor. */ - ~sigh() = default; - - /** - * @brief Copy assignment operator. - * @param other The instance to copy from. - * @return This signal handler. + * @brief Unmanaged signal handler. + * + * Primary template isn't defined on purpose. All the specializations give a + * compile-time error unless the template parameter is a function type. + * + * @tparam Type A valid function type. + * @tparam Allocator Type of allocator used to manage memory and elements. */ - sigh &operator=(const sigh &other) { - calls = other.calls; - return *this; - } + template + class sigh; /** - * @brief Move assignment operator. - * @param other The instance to move from. - * @return This signal handler. + * @brief Unmanaged signal handler. + * + * It works directly with references to classes and pointers to member functions + * as well as pointers to free functions. Users of this class are in charge of + * disconnecting instances before deleting them. + * + * This class serves mainly two purposes: + * + * * Creating signals to use later to notify a bunch of listeners. + * * Collecting results from a set of functions like in a voting system. + * + * @tparam Ret Return type of a function type. + * @tparam Args Types of arguments of a function type. + * @tparam Allocator Type of allocator used to manage memory and elements. */ - sigh &operator=(sigh &&other) noexcept { - swap(other); - return *this; - } + template + class sigh { + friend class sink>; + + using alloc_traits = stl::allocator_traits; + using delegate_type = delegate; + using container_type = stl::vector>; + + public: + /*! @brief Allocator type. */ + using allocator_type = Allocator; + /*! @brief Unsigned integer type. */ + using size_type = stl::size_t; + /*! @brief Sink type. */ + using sink_type = sink>; + + /*! @brief Default constructor. */ + sigh() noexcept(noexcept(allocator_type{})) + : sigh{allocator_type{}} {} + + /** + * @brief Constructs a signal handler with a given allocator. + * @param allocator The allocator to use. + */ + explicit sigh(const allocator_type &allocator) noexcept + : calls{allocator} {} + + /** + * @brief Copy constructor. + * @param other The instance to copy from. + */ + sigh(const sigh &other) + : calls{other.calls} {} + + /** + * @brief Allocator-extended copy constructor. + * @param other The instance to copy from. + * @param allocator The allocator to use. + */ + sigh(const sigh &other, const allocator_type &allocator) + : calls{other.calls, allocator} {} + + /** + * @brief Move constructor. + * @param other The instance to move from. + */ + sigh(sigh &&other) noexcept + : calls{stl::move(other.calls)} {} + + /** + * @brief Allocator-extended move constructor. + * @param other The instance to move from. + * @param allocator The allocator to use. + */ + sigh(sigh &&other, const allocator_type &allocator) + : calls{stl::move(other.calls), allocator} {} + + /*! @brief Default destructor. */ + ~sigh() = default; + + /** + * @brief Copy assignment operator. + * @param other The instance to copy from. + * @return This signal handler. + */ + sigh &operator=(const sigh &other) { + calls = other.calls; + return *this; + } - /** - * @brief Exchanges the contents with those of a given signal handler. - * @param other Signal handler to exchange the content with. - */ - void swap(sigh &other) noexcept { - using stl::swap; - swap(calls, other.calls); - } + /** + * @brief Move assignment operator. + * @param other The instance to move from. + * @return This signal handler. + */ + sigh &operator=(sigh &&other) noexcept { + swap(other); + return *this; + } - /** - * @brief Returns the associated allocator. - * @return The associated allocator. - */ - [[nodiscard]] constexpr allocator_type get_allocator() const noexcept { - return calls.get_allocator(); - } + /** + * @brief Exchanges the contents with those of a given signal handler. + * @param other Signal handler to exchange the content with. + */ + void swap(sigh &other) noexcept { + using stl::swap; + swap(calls, other.calls); + } - /** - * @brief Number of listeners connected to the signal. - * @return Number of listeners currently connected. - */ - [[nodiscard]] size_type size() const noexcept { - return calls.size(); - } + /** + * @brief Returns the associated allocator. + * @return The associated allocator. + */ + [[nodiscard]] constexpr allocator_type get_allocator() const noexcept { + return calls.get_allocator(); + } - /** - * @brief Returns false if at least a listener is connected to the signal. - * @return True if the signal has no listeners connected, false otherwise. - */ - [[nodiscard]] bool empty() const noexcept { - return calls.empty(); - } + /** + * @brief Number of listeners connected to the signal. + * @return Number of listeners currently connected. + */ + [[nodiscard]] size_type size() const noexcept { + return calls.size(); + } - /** - * @brief Triggers a signal. - * - * All the listeners are notified. Order isn't guaranteed. - * - * @param args Arguments to use to invoke listeners. - */ - void publish(Args... args) const { - for(auto pos = calls.size(); pos; --pos) { - calls[pos - 1u](args...); + /** + * @brief Returns false if at least a listener is connected to the signal. + * @return True if the signal has no listeners connected, false otherwise. + */ + [[nodiscard]] bool empty() const noexcept { + return calls.empty(); } - } - /** - * @brief Collects return values from the listeners. - * - * The collector must expose a call operator with the following properties: - * - * * The return type is either `void` or such that it's convertible to - * `bool`. In the second case, a true value will stop the iteration. - * * The list of parameters is empty if `Ret` is `void`, otherwise it - * contains a single element such that `Ret` is convertible to it. - * - * @tparam Func Type of collector to use, if any. - * @param func A valid function object. - * @param args Arguments to use to invoke listeners. - */ - template - void collect(Func func, Args... args) const { - for(auto pos = calls.size(); pos; --pos) { - if constexpr(stl::is_void_v || !stl::is_invocable_v) { + /** + * @brief Triggers a signal. + * + * All the listeners are notified. Order isn't guaranteed. + * + * @param args Arguments to use to invoke listeners. + */ + void publish(Args... args) const { + for(auto pos = calls.size(); pos; --pos) { calls[pos - 1u](args...); + } + } - if constexpr(stl::is_invocable_r_v) { - if(func()) { + /** + * @brief Collects return values from the listeners. + * + * The collector must expose a call operator with the following properties: + * + * * The return type is either `void` or such that it's convertible to + * `bool`. In the second case, a true value will stop the iteration. + * * The list of parameters is empty if `Ret` is `void`, otherwise it + * contains a single element such that `Ret` is convertible to it. + * + * @tparam Func Type of collector to use, if any. + * @param func A valid function object. + * @param args Arguments to use to invoke listeners. + */ + template + void collect(Func func, Args... args) const { + for(auto pos = calls.size(); pos; --pos) { + if constexpr(stl::is_void_v || !stl::is_invocable_v) { + calls[pos - 1u](args...); + + if constexpr(stl::is_invocable_r_v) { + if(func()) { + break; + } + } else { + func(); + } + } else if constexpr(stl::is_invocable_r_v) { + if(func(calls[pos - 1u](args...))) { break; } } else { - func(); + func(calls[pos - 1u](args...)); } - } else if constexpr(stl::is_invocable_r_v) { - if(func(calls[pos - 1u](args...))) { - break; - } - } else { - func(calls[pos - 1u](args...)); } } - } - -private: - container_type calls; -}; - -/** - * @brief Connection class. - * - * Opaque object the aim of which is to allow users to release an already - * estabilished connection without having to keep a reference to the signal or - * the sink that generated it. - */ -class connection { - template - friend class sink; - - connection(delegate fn, void *ref) - : disconnect{fn}, signal{ref} {} - -public: - /*! @brief Default constructor. */ - connection() - : signal{} {} + + private: + container_type calls; + }; /** - * @brief Checks whether a connection is properly initialized. - * @return True if the connection is properly initialized, false otherwise. + * @brief Connection class. + * + * Opaque object the aim of which is to allow users to release an already + * estabilished connection without having to keep a reference to the signal or + * the sink that generated it. */ - [[nodiscard]] explicit operator bool() const noexcept { - return static_cast(disconnect); - } - - /*! @brief Breaks the connection. */ - void release() { - if(disconnect) { - disconnect(signal); - disconnect.reset(); + class connection { + template + friend class sink; + + connection(delegate fn, void *ref) + : disconnect{fn}, signal{ref} {} + + public: + /*! @brief Default constructor. */ + connection() + : signal{} {} + + /** + * @brief Checks whether a connection is properly initialized. + * @return True if the connection is properly initialized, false otherwise. + */ + [[nodiscard]] explicit operator bool() const noexcept { + return static_cast(disconnect); } - } - -private: - delegate disconnect; - void *signal; -}; - -/** - * @brief Scoped connection class. - * - * Opaque object the aim of which is to allow users to release an already - * estabilished connection without having to keep a reference to the signal or - * the sink that generated it.
- * A scoped connection automatically breaks the link between the two objects - * when it goes out of scope. - */ -struct scoped_connection { - /*! @brief Default constructor. */ - scoped_connection() = default; - /** - * @brief Constructs a scoped connection from a basic connection. - * @param other A valid connection object. - */ - scoped_connection(const connection &other) - : conn{other} {} + /*! @brief Breaks the connection. */ + void release() { + if(disconnect) { + disconnect(signal); + disconnect.reset(); + } + } - /*! @brief Default copy constructor, deleted on purpose. */ - scoped_connection(const scoped_connection &) = delete; + private: + delegate disconnect; + void *signal; + }; /** - * @brief Move constructor. - * @param other The scoped connection to move from. + * @brief Scoped connection class. + * + * Opaque object the aim of which is to allow users to release an already + * estabilished connection without having to keep a reference to the signal or + * the sink that generated it.
+ * A scoped connection automatically breaks the link between the two objects + * when it goes out of scope. */ - scoped_connection(scoped_connection &&other) noexcept - : conn{stl::exchange(other.conn, {})} {} + struct scoped_connection { + /*! @brief Default constructor. */ + scoped_connection() = default; + + /** + * @brief Constructs a scoped connection from a basic connection. + * @param other A valid connection object. + */ + scoped_connection(const connection &other) + : conn{other} {} + + /*! @brief Default copy constructor, deleted on purpose. */ + scoped_connection(const scoped_connection &) = delete; + + /** + * @brief Move constructor. + * @param other The scoped connection to move from. + */ + scoped_connection(scoped_connection &&other) noexcept + : conn{stl::exchange(other.conn, {})} {} + + /*! @brief Automatically breaks the link on destruction. */ + ~scoped_connection() { + conn.release(); + } + + /** + * @brief Default copy assignment operator, deleted on purpose. + * @return This scoped connection. + */ + scoped_connection &operator=(const scoped_connection &) = delete; + + /** + * @brief Move assignment operator. + * @param other The scoped connection to move from. + * @return This scoped connection. + */ + scoped_connection &operator=(scoped_connection &&other) noexcept { + conn = stl::exchange(other.conn, {}); + return *this; + } - /*! @brief Automatically breaks the link on destruction. */ - ~scoped_connection() { - conn.release(); - } + /** + * @brief Acquires a connection. + * @param other The connection object to acquire. + * @return This scoped connection. + */ + scoped_connection &operator=(connection other) { + conn = other; + return *this; + } - /** - * @brief Default copy assignment operator, deleted on purpose. - * @return This scoped connection. - */ - scoped_connection &operator=(const scoped_connection &) = delete; + /** + * @brief Checks whether a scoped connection is properly initialized. + * @return True if the connection is properly initialized, false otherwise. + */ + [[nodiscard]] explicit operator bool() const noexcept { + return static_cast(conn); + } - /** - * @brief Move assignment operator. - * @param other The scoped connection to move from. - * @return This scoped connection. - */ - scoped_connection &operator=(scoped_connection &&other) noexcept { - conn = stl::exchange(other.conn, {}); - return *this; - } + /*! @brief Breaks the connection. */ + void release() { + conn.release(); + } - /** - * @brief Acquires a connection. - * @param other The connection object to acquire. - * @return This scoped connection. - */ - scoped_connection &operator=(connection other) { - conn = other; - return *this; - } + private: + connection conn; + }; /** - * @brief Checks whether a scoped connection is properly initialized. - * @return True if the connection is properly initialized, false otherwise. + * @brief Sink class. + * + * A sink is used to connect listeners to signals and to disconnect them.
+ * The function type for a listener is the one of the signal to which it + * belongs. + * + * The clear separation between a signal and a sink permits to store the former + * as private data member without exposing the publish functionality to the + * users of the class. + * + * @warning + * Lifetime of a sink must not overcome that of the signal to which it refers. + * In any other case, attempting to use a sink results in undefined behavior. + * + * @tparam Ret Return type of a function type. + * @tparam Args Types of arguments of a function type. + * @tparam Allocator Type of allocator used to manage memory and elements. */ - [[nodiscard]] explicit operator bool() const noexcept { - return static_cast(conn); - } - - /*! @brief Breaks the connection. */ - void release() { - conn.release(); - } - -private: - connection conn; -}; - -/** - * @brief Sink class. - * - * A sink is used to connect listeners to signals and to disconnect them.
- * The function type for a listener is the one of the signal to which it - * belongs. - * - * The clear separation between a signal and a sink permits to store the former - * as private data member without exposing the publish functionality to the - * users of the class. - * - * @warning - * Lifetime of a sink must not overcome that of the signal to which it refers. - * In any other case, attempting to use a sink results in undefined behavior. - * - * @tparam Ret Return type of a function type. - * @tparam Args Types of arguments of a function type. - * @tparam Allocator Type of allocator used to manage memory and elements. - */ -template -class sink> { - using signal_type = sigh; - using delegate_type = signal_type::delegate_type; - using difference_type = signal_type::container_type::difference_type; - - template - static void release(Type value_or_instance, void *signal) { - sink{*static_cast(signal)}.disconnect(value_or_instance); - } - - template - static void release(void *signal) { - sink{*static_cast(signal)}.disconnect(); - } - - template - void disconnect_if(Func callback) { - auto &ref = signal_or_assert(); - - for(auto pos = ref.calls.size(); pos; --pos) { - if(auto &elem = ref.calls[pos - 1u]; callback(elem)) { - elem = stl::move(ref.calls.back()); - ref.calls.pop_back(); - } + template + class sink> { + using signal_type = sigh; + using delegate_type = signal_type::delegate_type; + using difference_type = signal_type::container_type::difference_type; + + template + static void release(Type value_or_instance, void *signal) { + sink{*static_cast(signal)}.disconnect(value_or_instance); } - } - [[nodiscard]] auto &signal_or_assert() const noexcept { - ENTT_ASSERT(signal != nullptr, "Invalid pointer to signal"); - return *signal; - } + template + static void release(void *signal) { + sink{*static_cast(signal)}.disconnect(); + } -public: - /*! @brief Constructs an invalid sink. */ - sink() noexcept - : signal{} {} + template + void disconnect_if(Func callback) { + auto &ref = signal_or_assert(); - /** - * @brief Constructs a sink that is allowed to modify a given signal. - * @param ref A valid reference to a signal object. - */ - sink(sigh &ref) noexcept - : signal{&ref} {} + for(auto pos = ref.calls.size(); pos; --pos) { + if(auto &elem = ref.calls[pos - 1u]; callback(elem)) { + elem = stl::move(ref.calls.back()); + ref.calls.pop_back(); + } + } + } - /** - * @brief Returns false if at least a listener is connected to the sink. - * @return True if the sink has no listeners connected, false otherwise. - */ - [[nodiscard]] bool empty() const noexcept { - return signal_or_assert().calls.empty(); - } + [[nodiscard]] auto &signal_or_assert() const noexcept { + ENTT_ASSERT(signal != nullptr, "Invalid pointer to signal"); + return *signal; + } - /** - * @brief Connects a free function or an unbound member to a signal. - * @tparam Candidate Function or member to connect to the signal. - * @return A properly initialized connection object. - */ - template - connection connect() { - disconnect(); + public: + /*! @brief Constructs an invalid sink. */ + sink() noexcept + : signal{} {} + + /** + * @brief Constructs a sink that is allowed to modify a given signal. + * @param ref A valid reference to a signal object. + */ + sink(sigh &ref) noexcept + : signal{&ref} {} + + /** + * @brief Returns false if at least a listener is connected to the sink. + * @return True if the sink has no listeners connected, false otherwise. + */ + [[nodiscard]] bool empty() const noexcept { + return signal_or_assert().calls.empty(); + } - delegate_type call{}; - call.template connect(); - signal_or_assert().calls.push_back(stl::move(call)); + /** + * @brief Connects a free function or an unbound member to a signal. + * @tparam Candidate Function or member to connect to the signal. + * @return A properly initialized connection object. + */ + template + connection connect() { + disconnect(); + + delegate_type call{}; + call.template connect(); + signal_or_assert().calls.push_back(stl::move(call)); + + delegate conn{}; + conn.template connect<&release>(); + return {conn, signal}; + } - delegate conn{}; - conn.template connect<&release>(); - return {conn, signal}; - } + /** + * @brief Connects a free function with payload or a bound member to a + * signal. + * + * The signal isn't responsible for the connected object or the payload. + * Users must always guarantee that the lifetime of the instance overcomes + * the one of the signal.
+ * When used to connect a free function with payload, its signature must be + * such that the instance is the first argument before the ones used to + * define the signal itself. + * + * @tparam Candidate Function or member to connect to the signal. + * @tparam Type Type of class or type of payload. + * @param value_or_instance A valid reference that fits the purpose. + * @return A properly initialized connection object. + */ + template + connection connect(Type &value_or_instance) { + disconnect(value_or_instance); + + delegate_type call{}; + call.template connect(value_or_instance); + signal_or_assert().calls.push_back(stl::move(call)); + + delegate conn{}; + conn.template connect<&release>(value_or_instance); + return {conn, signal}; + } - /** - * @brief Connects a free function with payload or a bound member to a - * signal. - * - * The signal isn't responsible for the connected object or the payload. - * Users must always guarantee that the lifetime of the instance overcomes - * the one of the signal.
- * When used to connect a free function with payload, its signature must be - * such that the instance is the first argument before the ones used to - * define the signal itself. - * - * @tparam Candidate Function or member to connect to the signal. - * @tparam Type Type of class or type of payload. - * @param value_or_instance A valid reference that fits the purpose. - * @return A properly initialized connection object. - */ - template - connection connect(Type &value_or_instance) { - disconnect(value_or_instance); + /** + * @brief Connects a free function with payload or a bound member to a + * signal. + * + * @sa connect(Type &) + * + * @tparam Candidate Function or member to connect to the signal. + * @tparam Type Type of class or type of payload. + * @param value_or_instance A valid pointer that fits the purpose. + * @return A properly initialized connection object. + */ + template + connection connect(Type *value_or_instance) { + disconnect(value_or_instance); + + delegate_type call{}; + call.template connect(value_or_instance); + signal_or_assert().calls.push_back(stl::move(call)); + + delegate conn{}; + conn.template connect<&release>(value_or_instance); + return {conn, signal}; + } - delegate_type call{}; - call.template connect(value_or_instance); - signal_or_assert().calls.push_back(stl::move(call)); + /** + * @brief Disconnects a free function or an unbound member from a signal. + * @tparam Candidate Function or member to disconnect from the signal. + */ + template + void disconnect() { + delegate_type call{}; + call.template connect(); + disconnect_if([&call](const auto &elem) { return elem == call; }); + } - delegate conn{}; - conn.template connect<&release>(value_or_instance); - return {conn, signal}; - } + /** + * @brief Disconnects a free function with payload or a bound member from a + * signal. + * + * The signal isn't responsible for the connected object or the payload. + * Users must always guarantee that the lifetime of the instance overcomes + * the one of the signal.
+ * When used to connect a free function with payload, its signature must be + * such that the instance is the first argument before the ones used to + * define the signal itself. + * + * @tparam Candidate Function or member to disconnect from the signal. + * @tparam Type Type of class or type of payload, if any. + * @param value_or_instance A valid reference that fits the purpose. + */ + template + void disconnect(Type &value_or_instance) { + delegate_type call{}; + call.template connect(value_or_instance); + disconnect_if([&call](const auto &elem) { return elem == call; }); + } - /** - * @brief Connects a free function with payload or a bound member to a - * signal. - * - * @sa connect(Type &) - * - * @tparam Candidate Function or member to connect to the signal. - * @tparam Type Type of class or type of payload. - * @param value_or_instance A valid pointer that fits the purpose. - * @return A properly initialized connection object. - */ - template - connection connect(Type *value_or_instance) { - disconnect(value_or_instance); + /** + * @brief Disconnects a free function with payload or a bound member from a + * signal. + * + * @sa disconnect(Type &) + * + * @tparam Candidate Function or member to disconnect from the signal. + * @tparam Type Type of class or type of payload, if any. + * @param value_or_instance A valid pointer that fits the purpose. + */ + template + void disconnect(Type *value_or_instance) { + delegate_type call{}; + call.template connect(value_or_instance); + disconnect_if([&call](const auto &elem) { return elem == call; }); + } - delegate_type call{}; - call.template connect(value_or_instance); - signal_or_assert().calls.push_back(stl::move(call)); + /** + * @brief Disconnects free functions with payload or bound members from a + * signal. + * @param value_or_instance A valid object that fits the purpose. + */ + void disconnect(const void *value_or_instance) { + ENTT_ASSERT(value_or_instance != nullptr, "Invalid value or instance"); + disconnect_if([value_or_instance](const auto &elem) { return elem.data() == value_or_instance; }); + } - delegate conn{}; - conn.template connect<&release>(value_or_instance); - return {conn, signal}; - } + /*! @brief Disconnects all the listeners from a signal. */ + void disconnect() { + signal_or_assert().calls.clear(); + } - /** - * @brief Disconnects a free function or an unbound member from a signal. - * @tparam Candidate Function or member to disconnect from the signal. - */ - template - void disconnect() { - delegate_type call{}; - call.template connect(); - disconnect_if([&call](const auto &elem) { return elem == call; }); - } + /** + * @brief Returns true if a sink is correctly initialized, false otherwise. + * @return True if a sink is correctly initialized, false otherwise. + */ + [[nodiscard]] explicit operator bool() const noexcept { + return signal != nullptr; + } - /** - * @brief Disconnects a free function with payload or a bound member from a - * signal. - * - * The signal isn't responsible for the connected object or the payload. - * Users must always guarantee that the lifetime of the instance overcomes - * the one of the signal.
- * When used to connect a free function with payload, its signature must be - * such that the instance is the first argument before the ones used to - * define the signal itself. - * - * @tparam Candidate Function or member to disconnect from the signal. - * @tparam Type Type of class or type of payload, if any. - * @param value_or_instance A valid reference that fits the purpose. - */ - template - void disconnect(Type &value_or_instance) { - delegate_type call{}; - call.template connect(value_or_instance); - disconnect_if([&call](const auto &elem) { return elem == call; }); - } + private: + signal_type *signal; + }; /** - * @brief Disconnects a free function with payload or a bound member from a - * signal. + * @brief Deduction guide. * - * @sa disconnect(Type &) + * It allows to deduce the signal handler type of a sink directly from the + * signal it refers to. * - * @tparam Candidate Function or member to disconnect from the signal. - * @tparam Type Type of class or type of payload, if any. - * @param value_or_instance A valid pointer that fits the purpose. - */ - template - void disconnect(Type *value_or_instance) { - delegate_type call{}; - call.template connect(value_or_instance); - disconnect_if([&call](const auto &elem) { return elem == call; }); - } - - /** - * @brief Disconnects free functions with payload or bound members from a - * signal. - * @param value_or_instance A valid object that fits the purpose. - */ - void disconnect(const void *value_or_instance) { - ENTT_ASSERT(value_or_instance != nullptr, "Invalid value or instance"); - disconnect_if([value_or_instance](const auto &elem) { return elem.data() == value_or_instance; }); - } - - /*! @brief Disconnects all the listeners from a signal. */ - void disconnect() { - signal_or_assert().calls.clear(); - } - - /** - * @brief Returns true if a sink is correctly initialized, false otherwise. - * @return True if a sink is correctly initialized, false otherwise. + * @tparam Ret Return type of a function type. + * @tparam Args Types of arguments of a function type. + * @tparam Allocator Type of allocator used to manage memory and elements. */ - [[nodiscard]] explicit operator bool() const noexcept { - return signal != nullptr; - } - -private: - signal_type *signal; -}; - -/** - * @brief Deduction guide. - * - * It allows to deduce the signal handler type of a sink directly from the - * signal it refers to. - * - * @tparam Ret Return type of a function type. - * @tparam Args Types of arguments of a function type. - * @tparam Allocator Type of allocator used to manage memory and elements. - */ -template -sink(sigh &) -> sink>; + template + sink(sigh &) -> sink>; } // namespace entt From 4d6de3428f298b2654fcb283b4e61270e2ba07dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Milan=20Borov=C3=BD?= Date: Thu, 23 Oct 2025 00:17:57 +0200 Subject: [PATCH 02/10] Export operators, Prevent friend class injection --- src/entt/container/dense_map.hpp | 57 ++++++++++++++++- src/entt/container/dense_set.hpp | 57 ++++++++++++++++- src/entt/container/table.hpp | 41 ++++++++++++- src/entt/core/enum.hpp | 4 ++ src/entt/entity/group.hpp | 14 +++++ src/entt/entity/handle.hpp | 14 +++++ src/entt/entity/registry.hpp | 95 ++++++++++++++++++++--------- src/entt/entity/snapshot.hpp | 24 ++++---- src/entt/entity/sparse_set.hpp | 69 ++++++++++++++++----- src/entt/entity/storage.hpp | 53 ++++++++++++++++ src/entt/entity/view.hpp | 33 +++++++++- src/entt/graph/adjacency_matrix.hpp | 14 +++++ src/entt/meta/range.hpp | 39 ++++++++++++ src/entt/resource/cache.hpp | 41 ++++++++++++- 14 files changed, 493 insertions(+), 62 deletions(-) diff --git a/src/entt/container/dense_map.hpp b/src/entt/container/dense_map.hpp index bd7e754d62..623d4d61fc 100644 --- a/src/entt/container/dense_map.hpp +++ b/src/entt/container/dense_map.hpp @@ -62,7 +62,7 @@ struct dense_map_node final { template class dense_map_iterator final { template - friend class dense_map_iterator; + friend class internal::dense_map_iterator; static_assert(stl::is_pointer_v, "Not a pointer type"); using first_type = decltype(stl::as_const(stl::declval()->element.first)); @@ -154,10 +154,49 @@ class dense_map_iterator final { It it; }; +ENTT_MODULE_EXPORT_BEGIN + +template +[[nodiscard]] constexpr std::ptrdiff_t operator-(const dense_map_iterator &lhs, const dense_map_iterator &rhs) noexcept { + return lhs.it - rhs.it; +} + +template +[[nodiscard]] constexpr bool operator==(const dense_map_iterator &lhs, const dense_map_iterator &rhs) noexcept { + return lhs.it == rhs.it; +} + +template +[[nodiscard]] constexpr bool operator!=(const dense_map_iterator &lhs, const dense_map_iterator &rhs) noexcept { + return !(lhs == rhs); +} + +template +[[nodiscard]] constexpr bool operator<(const dense_map_iterator &lhs, const dense_map_iterator &rhs) noexcept { + return lhs.it < rhs.it; +} + +template +[[nodiscard]] constexpr bool operator>(const dense_map_iterator &lhs, const dense_map_iterator &rhs) noexcept { + return rhs < lhs; +} + +template +[[nodiscard]] constexpr bool operator<=(const dense_map_iterator &lhs, const dense_map_iterator &rhs) noexcept { + return !(lhs > rhs); +} + +template +[[nodiscard]] constexpr bool operator>=(const dense_map_iterator &lhs, const dense_map_iterator &rhs) noexcept { + return !(lhs < rhs); +} + +ENTT_MODULE_EXPORT_END + template class dense_map_local_iterator final { template - friend class dense_map_local_iterator; + friend class internal::dense_map_local_iterator; static_assert(stl::is_pointer_v, "Not a pointer type"); using first_type = decltype(stl::as_const(stl::declval()->element.first)); @@ -215,6 +254,20 @@ class dense_map_local_iterator final { stl::size_t offset{dense_map_placeholder_position}; }; +ENTT_MODULE_EXPORT_BEGIN + +template +[[nodiscard]] constexpr bool operator==(const dense_map_local_iterator &lhs, const dense_map_local_iterator &rhs) noexcept { + return lhs.index() == rhs.index(); +} + +template +[[nodiscard]] constexpr bool operator!=(const dense_map_local_iterator &lhs, const dense_map_local_iterator &rhs) noexcept { + return !(lhs == rhs); +} + +ENTT_MODULE_EXPORT_END + } // namespace internal /*! @endcond */ diff --git a/src/entt/container/dense_set.hpp b/src/entt/container/dense_set.hpp index bb991adc96..49f0ce2495 100644 --- a/src/entt/container/dense_set.hpp +++ b/src/entt/container/dense_set.hpp @@ -33,7 +33,7 @@ static constexpr stl::size_t dense_set_placeholder_position = (stl::numeric_limi template class dense_set_iterator final { template - friend class dense_set_iterator; + friend class internal::dense_set_iterator; static_assert(stl::is_pointer_v, "Not a pointer type"); @@ -122,10 +122,49 @@ class dense_set_iterator final { It it; }; +ENTT_MODULE_EXPORT_BEGIN + +template +[[nodiscard]] constexpr std::ptrdiff_t operator-(const dense_set_iterator &lhs, const dense_set_iterator &rhs) noexcept { + return lhs.it - rhs.it; +} + +template +[[nodiscard]] constexpr bool operator==(const dense_set_iterator &lhs, const dense_set_iterator &rhs) noexcept { + return lhs.it == rhs.it; +} + +template +[[nodiscard]] constexpr bool operator!=(const dense_set_iterator &lhs, const dense_set_iterator &rhs) noexcept { + return !(lhs == rhs); +} + +template +[[nodiscard]] constexpr bool operator<(const dense_set_iterator &lhs, const dense_set_iterator &rhs) noexcept { + return lhs.it < rhs.it; +} + +template +[[nodiscard]] constexpr bool operator>(const dense_set_iterator &lhs, const dense_set_iterator &rhs) noexcept { + return rhs < lhs; +} + +template +[[nodiscard]] constexpr bool operator<=(const dense_set_iterator &lhs, const dense_set_iterator &rhs) noexcept { + return !(lhs > rhs); +} + +template +[[nodiscard]] constexpr bool operator>=(const dense_set_iterator &lhs, const dense_set_iterator &rhs) noexcept { + return !(lhs < rhs); +} + +ENTT_MODULE_EXPORT_END + template class dense_set_local_iterator final { template - friend class dense_set_local_iterator; + friend class internal::dense_set_local_iterator; static_assert(stl::is_pointer_v, "Not a pointer type"); @@ -179,6 +218,20 @@ class dense_set_local_iterator final { stl::size_t offset{dense_set_placeholder_position}; }; +ENTT_MODULE_EXPORT_BEGIN + +template +[[nodiscard]] constexpr bool operator==(const dense_set_local_iterator &lhs, const dense_set_local_iterator &rhs) noexcept { + return lhs.index() == rhs.index(); +} + +template +[[nodiscard]] constexpr bool operator!=(const dense_set_local_iterator &lhs, const dense_set_local_iterator &rhs) noexcept { + return !(lhs == rhs); +} + +ENTT_MODULE_EXPORT_END + } // namespace internal /*! @endcond */ diff --git a/src/entt/container/table.hpp b/src/entt/container/table.hpp index 28b458f3a7..8eca495d1a 100644 --- a/src/entt/container/table.hpp +++ b/src/entt/container/table.hpp @@ -22,7 +22,7 @@ namespace internal { template class table_iterator { template - friend class table_iterator; + friend class internal::table_iterator; public: using value_type = decltype(stl::forward_as_tuple(*stl::declval()...)); @@ -109,6 +109,45 @@ class table_iterator { stl::tuple it; }; +ENTT_MODULE_EXPORT_BEGIN + +template +[[nodiscard]] constexpr std::ptrdiff_t operator-(const table_iterator &lhs, const table_iterator &rhs) noexcept { + return std::get<0>(lhs.it) - std::get<0>(rhs.it); +} + +template +[[nodiscard]] constexpr bool operator==(const table_iterator &lhs, const table_iterator &rhs) noexcept { + return std::get<0>(lhs.it) == std::get<0>(rhs.it); +} + +template +[[nodiscard]] constexpr bool operator!=(const table_iterator &lhs, const table_iterator &rhs) noexcept { + return !(lhs == rhs); +} + +template +[[nodiscard]] constexpr bool operator<(const table_iterator &lhs, const table_iterator &rhs) noexcept { + return std::get<0>(lhs.it) < std::get<0>(rhs.it); +} + +template +[[nodiscard]] constexpr bool operator>(const table_iterator &lhs, const table_iterator &rhs) noexcept { + return rhs < lhs; +} + +template +[[nodiscard]] constexpr bool operator<=(const table_iterator &lhs, const table_iterator &rhs) noexcept { + return !(lhs > rhs); +} + +template +[[nodiscard]] constexpr bool operator>=(const table_iterator &lhs, const table_iterator &rhs) noexcept { + return !(lhs < rhs); +} + +ENTT_MODULE_EXPORT_END + } // namespace internal /*! @endcond */ diff --git a/src/entt/core/enum.hpp b/src/entt/core/enum.hpp index f497dd364e..86662512c2 100644 --- a/src/entt/core/enum.hpp +++ b/src/entt/core/enum.hpp @@ -41,6 +41,8 @@ ENTT_MODULE_EXPORT namespace entt { } // namespace entt +ENTT_MODULE_EXPORT_BEGIN + /** * @brief Operator available for enums for which bitmask support is enabled. * @tparam Type Enum class type. @@ -102,4 +104,6 @@ constexpr Type &operator^=(Type &lhs, const Type rhs) noexcept { return (lhs = (lhs ^ rhs)); } +ENTT_MODULE_EXPORT_END + #endif diff --git a/src/entt/entity/group.hpp b/src/entt/entity/group.hpp index 2ede997f6c..d46873e740 100644 --- a/src/entt/entity/group.hpp +++ b/src/entt/entity/group.hpp @@ -88,6 +88,20 @@ class extended_group_iterator, get_t> { stl::tuple pools; }; +ENTT_MODULE_EXPORT_BEGIN + +template +[[nodiscard]] constexpr bool operator==(const extended_group_iterator &lhs, const extended_group_iterator &rhs) noexcept { + return lhs.it == rhs.it; +} + +template +[[nodiscard]] constexpr bool operator!=(const extended_group_iterator &lhs, const extended_group_iterator &rhs) noexcept { + return !(lhs == rhs); +} + +ENTT_MODULE_EXPORT_END + struct group_descriptor { using size_type = stl::size_t; virtual ~group_descriptor() = default; diff --git a/src/entt/entity/handle.hpp b/src/entt/entity/handle.hpp index 453b1c565c..df79dc34ff 100644 --- a/src/entt/entity/handle.hpp +++ b/src/entt/entity/handle.hpp @@ -79,6 +79,20 @@ class handle_storage_iterator final { It last; }; +ENTT_MODULE_EXPORT_BEGIN + +template +[[nodiscard]] constexpr bool operator==(const handle_storage_iterator &lhs, const handle_storage_iterator &rhs) noexcept { + return lhs.it == rhs.it; +} + +template +[[nodiscard]] constexpr bool operator!=(const handle_storage_iterator &lhs, const handle_storage_iterator &rhs) noexcept { + return !(lhs == rhs); +} + +ENTT_MODULE_EXPORT_END + } // namespace internal /*! @endcond */ diff --git a/src/entt/entity/registry.hpp b/src/entt/entity/registry.hpp index ebfe7b65a2..96d7807573 100644 --- a/src/entt/entity/registry.hpp +++ b/src/entt/entity/registry.hpp @@ -4,34 +4,34 @@ #include "../config/module.h" #ifndef ENTT_MODULE -#include -#include "../config/config.h" -#include "../container/dense_map.hpp" -#include "../core/algorithm.hpp" -#include "../core/any.hpp" -#include "../core/concepts.hpp" -#include "../core/fwd.hpp" -#include "../core/iterator.hpp" -#include "../core/memory.hpp" -#include "../core/type_info.hpp" -#include "../core/type_traits.hpp" -#include "../stl/algorithm.hpp" -#include "../stl/array.hpp" -#include "../stl/concepts.hpp" -#include "../stl/cstddef.hpp" -#include "../stl/functional.hpp" -#include "../stl/iterator.hpp" -#include "../stl/memory.hpp" -#include "../stl/tuple.hpp" -#include "../stl/type_traits.hpp" -#include "../stl/utility.hpp" -#include "entity.hpp" -#include "fwd.hpp" -#include "group.hpp" -#include "mixin.hpp" -#include "sparse_set.hpp" -#include "storage.hpp" -#include "view.hpp" +# include +# include "../config/config.h" +# include "../container/dense_map.hpp" +# include "../core/algorithm.hpp" +# include "../core/any.hpp" +# include "../core/concepts.hpp" +# include "../core/fwd.hpp" +# include "../core/iterator.hpp" +# include "../core/memory.hpp" +# include "../core/type_info.hpp" +# include "../core/type_traits.hpp" +# include "../stl/algorithm.hpp" +# include "../stl/array.hpp" +# include "../stl/concepts.hpp" +# include "../stl/cstddef.hpp" +# include "../stl/functional.hpp" +# include "../stl/iterator.hpp" +# include "../stl/memory.hpp" +# include "../stl/tuple.hpp" +# include "../stl/type_traits.hpp" +# include "../stl/utility.hpp" +# include "entity.hpp" +# include "fwd.hpp" +# include "group.hpp" +# include "mixin.hpp" +# include "sparse_set.hpp" +# include "storage.hpp" +# include "view.hpp" #endif // ENTT_MODULE namespace entt { @@ -132,6 +132,45 @@ class registry_storage_iterator final { It it; }; +ENTT_MODULE_EXPORT_BEGIN + +template +[[nodiscard]] constexpr std::ptrdiff_t operator-(const registry_storage_iterator &lhs, const registry_storage_iterator &rhs) noexcept { + return lhs.it - rhs.it; +} + +template +[[nodiscard]] constexpr bool operator==(const registry_storage_iterator &lhs, const registry_storage_iterator &rhs) noexcept { + return lhs.it == rhs.it; +} + +template +[[nodiscard]] constexpr bool operator!=(const registry_storage_iterator &lhs, const registry_storage_iterator &rhs) noexcept { + return !(lhs == rhs); +} + +template +[[nodiscard]] constexpr bool operator<(const registry_storage_iterator &lhs, const registry_storage_iterator &rhs) noexcept { + return lhs.it < rhs.it; +} + +template +[[nodiscard]] constexpr bool operator>(const registry_storage_iterator &lhs, const registry_storage_iterator &rhs) noexcept { + return rhs < lhs; +} + +template +[[nodiscard]] constexpr bool operator<=(const registry_storage_iterator &lhs, const registry_storage_iterator &rhs) noexcept { + return !(lhs > rhs); +} + +template +[[nodiscard]] constexpr bool operator>=(const registry_storage_iterator &lhs, const registry_storage_iterator &rhs) noexcept { + return !(lhs < rhs); +} + +ENTT_MODULE_EXPORT_END + template class registry_context { using alloc_traits = stl::allocator_traits; diff --git a/src/entt/entity/snapshot.hpp b/src/entt/entity/snapshot.hpp index 600d23a7dd..c88a15753b 100644 --- a/src/entt/entity/snapshot.hpp +++ b/src/entt/entity/snapshot.hpp @@ -4,18 +4,18 @@ #include "../config/module.h" #ifndef ENTT_MODULE -#include "../config/config.h" -#include "../container/dense_map.hpp" -#include "../core/type_traits.hpp" -#include "../stl/concepts.hpp" -#include "../stl/cstddef.hpp" -#include "../stl/iterator.hpp" -#include "../stl/tuple.hpp" -#include "../stl/type_traits.hpp" -#include "../stl/utility.hpp" -#include "entity.hpp" -#include "fwd.hpp" -#include "view.hpp" +# include "../config/config.h" +# include "../container/dense_map.hpp" +# include "../core/type_traits.hpp" +# include "../stl/concepts.hpp" +# include "../stl/cstddef.hpp" +# include "../stl/iterator.hpp" +# include "../stl/tuple.hpp" +# include "../stl/type_traits.hpp" +# include "../stl/utility.hpp" +# include "entity.hpp" +# include "fwd.hpp" +# include "view.hpp" #endif // ENTT_MODULE namespace entt { diff --git a/src/entt/entity/sparse_set.hpp b/src/entt/entity/sparse_set.hpp index 92e5ca49c4..a9673fe520 100644 --- a/src/entt/entity/sparse_set.hpp +++ b/src/entt/entity/sparse_set.hpp @@ -4,21 +4,21 @@ #include "../config/module.h" #ifndef ENTT_MODULE -#include -#include "../config/config.h" -#include "../core/algorithm.hpp" -#include "../core/any.hpp" -#include "../core/bit.hpp" -#include "../core/type_info.hpp" -#include "../stl/concepts.hpp" -#include "../stl/cstddef.hpp" -#include "../stl/iterator.hpp" -#include "../stl/memory.hpp" -#include "../stl/type_traits.hpp" -#include "../stl/utility.hpp" -#include "../stl/vector.hpp" -#include "entity.hpp" -#include "fwd.hpp" +# include +# include "../config/config.h" +# include "../core/algorithm.hpp" +# include "../core/any.hpp" +# include "../core/bit.hpp" +# include "../core/type_info.hpp" +# include "../stl/concepts.hpp" +# include "../stl/cstddef.hpp" +# include "../stl/iterator.hpp" +# include "../stl/memory.hpp" +# include "../stl/type_traits.hpp" +# include "../stl/utility.hpp" +# include "../stl/vector.hpp" +# include "entity.hpp" +# include "fwd.hpp" #endif // ENTT_MODULE namespace entt { @@ -117,6 +117,45 @@ struct sparse_set_iterator final { difference_type offset; }; +ENTT_MODULE_EXPORT_BEGIN + +template +[[nodiscard]] constexpr std::ptrdiff_t operator-(const sparse_set_iterator &lhs, const sparse_set_iterator &rhs) noexcept { + return rhs.index() - lhs.index(); +} + +template +[[nodiscard]] constexpr bool operator==(const sparse_set_iterator &lhs, const sparse_set_iterator &rhs) noexcept { + return lhs.index() == rhs.index(); +} + +template +[[nodiscard]] constexpr bool operator!=(const sparse_set_iterator &lhs, const sparse_set_iterator &rhs) noexcept { + return !(lhs == rhs); +} + +template +[[nodiscard]] constexpr bool operator<(const sparse_set_iterator &lhs, const sparse_set_iterator &rhs) noexcept { + return lhs.index() > rhs.index(); +} + +template +[[nodiscard]] constexpr bool operator>(const sparse_set_iterator &lhs, const sparse_set_iterator &rhs) noexcept { + return rhs < lhs; +} + +template +[[nodiscard]] constexpr bool operator<=(const sparse_set_iterator &lhs, const sparse_set_iterator &rhs) noexcept { + return !(lhs > rhs); +} + +template +[[nodiscard]] constexpr bool operator>=(const sparse_set_iterator &lhs, const sparse_set_iterator &rhs) noexcept { + return !(lhs < rhs); +} + +ENTT_MODULE_EXPORT_END + } // namespace internal /*! @endcond */ diff --git a/src/entt/entity/storage.hpp b/src/entt/entity/storage.hpp index 95a3430138..3551f587dc 100644 --- a/src/entt/entity/storage.hpp +++ b/src/entt/entity/storage.hpp @@ -135,6 +135,45 @@ class storage_iterator final { difference_type offset; }; +ENTT_MODULE_EXPORT_BEGIN + +template +[[nodiscard]] constexpr std::ptrdiff_t operator-(const storage_iterator &lhs, const storage_iterator &rhs) noexcept { + return rhs.index() - lhs.index(); +} + +template +[[nodiscard]] constexpr bool operator==(const storage_iterator &lhs, const storage_iterator &rhs) noexcept { + return lhs.index() == rhs.index(); +} + +template +[[nodiscard]] constexpr bool operator!=(const storage_iterator &lhs, const storage_iterator &rhs) noexcept { + return !(lhs == rhs); +} + +template +[[nodiscard]] constexpr bool operator<(const storage_iterator &lhs, const storage_iterator &rhs) noexcept { + return lhs.index() > rhs.index(); +} + +template +[[nodiscard]] constexpr bool operator>(const storage_iterator &lhs, const storage_iterator &rhs) noexcept { + return rhs < lhs; +} + +template +[[nodiscard]] constexpr bool operator<=(const storage_iterator &lhs, const storage_iterator &rhs) noexcept { + return !(lhs > rhs); +} + +template +[[nodiscard]] constexpr bool operator>=(const storage_iterator &lhs, const storage_iterator &rhs) noexcept { + return !(lhs < rhs); +} + +ENTT_MODULE_EXPORT_END + template class extended_storage_iterator final { template @@ -190,6 +229,20 @@ class extended_storage_iterator final { stl::tuple it; }; +ENTT_MODULE_EXPORT_BEGIN + +template +[[nodiscard]] constexpr bool operator==(const extended_storage_iterator &lhs, const extended_storage_iterator &rhs) noexcept { + return std::get<0>(lhs.it) == std::get<0>(rhs.it); +} + +template +[[nodiscard]] constexpr bool operator!=(const extended_storage_iterator &lhs, const extended_storage_iterator &rhs) noexcept { + return !(lhs == rhs); +} + +ENTT_MODULE_EXPORT_END + } // namespace internal /*! @endcond */ diff --git a/src/entt/entity/view.hpp b/src/entt/entity/view.hpp index 4a01588d32..fed55cec99 100644 --- a/src/entt/entity/view.hpp +++ b/src/entt/entity/view.hpp @@ -61,7 +61,10 @@ template +template +class extended_view_iterator; + +template class view_iterator final { template friend struct extended_view_iterator; @@ -132,6 +135,20 @@ class view_iterator final { difference_type index; }; +ENTT_MODULE_EXPORT_BEGIN + +template +[[nodiscard]] constexpr bool operator==(const view_iterator &lhs, const view_iterator &rhs) noexcept { + return lhs.it == rhs.it; +} + +template +[[nodiscard]] constexpr bool operator!=(const view_iterator &lhs, const view_iterator &rhs) noexcept { + return !(lhs == rhs); +} + +ENTT_MODULE_EXPORT_END + template struct extended_view_iterator final { using iterator_type = It; @@ -180,6 +197,20 @@ struct extended_view_iterator final { It it; }; +ENTT_MODULE_EXPORT_BEGIN + +template +[[nodiscard]] constexpr bool operator==(const extended_view_iterator &lhs, const extended_view_iterator &rhs) noexcept { + return lhs.it == rhs.it; +} + +template +[[nodiscard]] constexpr bool operator!=(const extended_view_iterator &lhs, const extended_view_iterator &rhs) noexcept { + return !(lhs == rhs); +} + +ENTT_MODULE_EXPORT_END + } // namespace internal /*! @endcond */ diff --git a/src/entt/graph/adjacency_matrix.hpp b/src/entt/graph/adjacency_matrix.hpp index a60a2ae224..bd9b8f7fff 100644 --- a/src/entt/graph/adjacency_matrix.hpp +++ b/src/entt/graph/adjacency_matrix.hpp @@ -80,6 +80,20 @@ class edge_iterator { size_type offset{}; }; +ENTT_MODULE_EXPORT_BEGIN + +template +[[nodiscard]] constexpr bool operator==(const edge_iterator &lhs, const edge_iterator &rhs) noexcept { + return lhs.pos == rhs.pos; +} + +template +[[nodiscard]] constexpr bool operator!=(const edge_iterator &lhs, const edge_iterator &rhs) noexcept { + return !(lhs == rhs); +} + +ENTT_MODULE_EXPORT_END + } // namespace internal /*! @endcond */ diff --git a/src/entt/meta/range.hpp b/src/entt/meta/range.hpp index 323963c094..d21b4b9e95 100644 --- a/src/entt/meta/range.hpp +++ b/src/entt/meta/range.hpp @@ -107,6 +107,45 @@ struct meta_range_iterator final { const meta_ctx *ctx; }; +ENTT_MODULE_EXPORT_BEGIN + +template +[[nodiscard]] constexpr std::ptrdiff_t operator-(const meta_range_iterator &lhs, const meta_range_iterator &rhs) noexcept { + return lhs.it - rhs.it; +} + +template +[[nodiscard]] constexpr bool operator==(const meta_range_iterator &lhs, const meta_range_iterator &rhs) noexcept { + return lhs.it == rhs.it; +} + +template +[[nodiscard]] constexpr bool operator!=(const meta_range_iterator &lhs, const meta_range_iterator &rhs) noexcept { + return !(lhs == rhs); +} + +template +[[nodiscard]] constexpr bool operator<(const meta_range_iterator &lhs, const meta_range_iterator &rhs) noexcept { + return lhs.it < rhs.it; +} + +template +[[nodiscard]] constexpr bool operator>(const meta_range_iterator &lhs, const meta_range_iterator &rhs) noexcept { + return rhs < lhs; +} + +template +[[nodiscard]] constexpr bool operator<=(const meta_range_iterator &lhs, const meta_range_iterator &rhs) noexcept { + return !(lhs > rhs); +} + +template +[[nodiscard]] constexpr bool operator>=(const meta_range_iterator &lhs, const meta_range_iterator &rhs) noexcept { + return !(lhs < rhs); +} + +ENTT_MODULE_EXPORT_END + } // namespace internal /*! @endcond */ diff --git a/src/entt/resource/cache.hpp b/src/entt/resource/cache.hpp index 92173e1c49..805aea6b84 100644 --- a/src/entt/resource/cache.hpp +++ b/src/entt/resource/cache.hpp @@ -30,7 +30,7 @@ namespace internal { template class resource_cache_iterator final { template - friend class resource_cache_iterator; + friend class internal::resource_cache_iterator; public: using value_type = stl::pair>; @@ -117,6 +117,45 @@ class resource_cache_iterator final { It it; }; +ENTT_MODULE_EXPORT_BEGIN + +template +[[nodiscard]] constexpr std::ptrdiff_t operator-(const resource_cache_iterator &lhs, const resource_cache_iterator &rhs) noexcept { + return lhs.it - rhs.it; +} + +template +[[nodiscard]] constexpr bool operator==(const resource_cache_iterator &lhs, const resource_cache_iterator &rhs) noexcept { + return lhs.it == rhs.it; +} + +template +[[nodiscard]] constexpr bool operator!=(const resource_cache_iterator &lhs, const resource_cache_iterator &rhs) noexcept { + return !(lhs == rhs); +} + +template +[[nodiscard]] constexpr bool operator<(const resource_cache_iterator &lhs, const resource_cache_iterator &rhs) noexcept { + return lhs.it < rhs.it; +} + +template +[[nodiscard]] constexpr bool operator>(const resource_cache_iterator &lhs, const resource_cache_iterator &rhs) noexcept { + return rhs < lhs; +} + +template +[[nodiscard]] constexpr bool operator<=(const resource_cache_iterator &lhs, const resource_cache_iterator &rhs) noexcept { + return !(lhs > rhs); +} + +template +[[nodiscard]] constexpr bool operator>=(const resource_cache_iterator &lhs, const resource_cache_iterator &rhs) noexcept { + return !(lhs < rhs); +} + +ENTT_MODULE_EXPORT_END + } // namespace internal /*! @endcond */ From 32287f03f7be814f2eb2aeb355dc35874eb1f3f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Milan=20Borov=C3=BD?= Date: Thu, 23 Oct 2025 23:15:51 +0200 Subject: [PATCH 03/10] Fix module install --- CMakeLists.txt | 68 ++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 49 insertions(+), 19 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2b58b66454..b5c1d21aa4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -133,7 +133,9 @@ endif() if (ENTT_MODULE) target_sources(EnTT PUBLIC - FILE_SET cxx_modules TYPE CXX_MODULES FILES + FILE_SET cxx_modules TYPE CXX_MODULES + BASE_DIRS ${EnTT_SOURCE_DIR}/src/entt + FILES ${EnTT_SOURCE_DIR}/src/entt/entt.ixx ) endif() @@ -329,13 +331,22 @@ if(ENTT_INSTALL) include(CMakePackageConfigHelpers) - install( - TARGETS EnTT - EXPORT EnTTTargets - ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} - INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} - $<$:FILE_SET cxx_modules DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/entt> - ) + if(ENTT_MODULE) + install( + TARGETS EnTT + EXPORT EnTTTargets + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} + FILE_SET cxx_modules DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/entt + ) + else() + install( + TARGETS EnTT + EXPORT EnTTTargets + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} + ) + endif() write_basic_package_version_file( EnTTConfigVersion.cmake @@ -349,18 +360,37 @@ if(ENTT_INSTALL) INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/EnTT/cmake ) - export( - EXPORT EnTTTargets - FILE ${CMAKE_CURRENT_BINARY_DIR}/EnTTTargets.cmake - NAMESPACE EnTT:: - ) + if(ENTT_MODULE) + export( + TARGETS EnTT + FILE "${CMAKE_CURRENT_BINARY_DIR}/EnTTTargets.cmake" + NAMESPACE EnTT:: + CXX_MODULES_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/cxx-modules" + ) + else() + export( + TARGETS EnTT + FILE "${CMAKE_CURRENT_BINARY_DIR}/EnTTTargets.cmake" + NAMESPACE EnTT:: + ) + endif() - install( - EXPORT EnTTTargets - FILE EnTTTargets.cmake - DESTINATION ${CMAKE_INSTALL_LIBDIR}/EnTT/cmake - NAMESPACE EnTT:: - ) + if(ENTT_MODULE) + install( + EXPORT EnTTTargets + FILE EnTTTargets.cmake + DESTINATION ${CMAKE_INSTALL_LIBDIR}/EnTT/cmake + NAMESPACE EnTT:: + CXX_MODULES_DIRECTORY ${CMAKE_INSTALL_LIBDIR}/EnTT/cmake/cxx-modules + ) + else() + install( + EXPORT EnTTTargets + FILE EnTTTargets.cmake + DESTINATION ${CMAKE_INSTALL_LIBDIR}/EnTT/cmake + NAMESPACE EnTT:: + ) + endif() install( FILES From e915314c1a6137a77b421623f25a1a7fe3b0de74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Milan=20Borov=C3=BD?= Date: Tue, 18 Nov 2025 19:52:24 +0100 Subject: [PATCH 04/10] Add ENTT_USER_CONFIG documentation --- docs/md/config.md | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/docs/md/config.md b/docs/md/config.md index 06c001a618..b45acee059 100644 --- a/docs/md/config.md +++ b/docs/md/config.md @@ -142,3 +142,35 @@ paths appropriately.
For example, `CMake` allows users to _bind_ additional include directories to a target with `target_include_directories`. See the test suite, and in particular the `config_ext` test for a practical example. + +## When consumed as a module + +When `EnTT` is consumed as a C++20 module, all the above definitions can be +put into a custom configuration file that can be referred to through the +`ENTT_USER_CONFIG` compile definition using its path.
+ +In case the module is built through CMake, the variable +`ENTT_USER_CONFIG` can be set directly from the `CMakeLists.txt` file before +including the library through `add_subdirectory`.
+ +Example of a custom configuration file and CMake setup: +```c++ +// user_config.h + +#define ENTT_ID_TYPE std::uint64_t +#define ENTT_USE_ATOMIC +``` +```c++ +// CMakeLists.txt + +set(ENTT_MODULE ON) +set(ENTT_USER_CONFIG "path/to/user_config.h") + +... + +add_subdirectory(path/to/entt) + +... + +target_link_libraries(your_target PUBLIC EnTT::EnTT) +``` From d70ac5e4531c2dd3e22bb019ed2ae6942c42001c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Milan=20Borov=C3=BD?= Date: Wed, 10 Dec 2025 12:51:55 +0100 Subject: [PATCH 05/10] Add missing dependencies --- src/entt/entt.ixx | 40 +++++++++++++++++++++------------------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/src/entt/entt.ixx b/src/entt/entt.ixx index fec60f5116..502c3bd313 100644 --- a/src/entt/entt.ixx +++ b/src/entt/entt.ixx @@ -6,6 +6,7 @@ module; #define ENTT_MODULE_EXPORT_END } #include +#include #include #include #include @@ -13,13 +14,14 @@ module; #include #include #include +#include #include #include #include #include #ifdef ENTT_USER_CONFIG -# include ENTT_USER_CONFIG +# include ENTT_USER_CONFIG #endif // ENTT_USER_CONFIG #include "config/config.h" @@ -29,43 +31,43 @@ module; export module entt; -#include "core/fwd.hpp" -#include "core/utility.hpp" #include "core/algorithm.hpp" -#include "core/hashed_string.hpp" -#include "core/type_info.hpp" -#include "core/type_traits.hpp" #include "core/any.hpp" #include "core/bit.hpp" #include "core/compressed_pair.hpp" #include "core/enum.hpp" #include "core/family.hpp" +#include "core/fwd.hpp" +#include "core/hashed_string.hpp" #include "core/ident.hpp" #include "core/iterator.hpp" #include "core/memory.hpp" #include "core/monostate.hpp" #include "core/ranges.hpp" #include "core/tuple.hpp" +#include "core/type_info.hpp" +#include "core/type_traits.hpp" +#include "core/utility.hpp" -#include "container/fwd.hpp" #include "container/dense_map.hpp" #include "container/dense_set.hpp" +#include "container/fwd.hpp" #include "container/table.hpp" -#include "signal/fwd.hpp" #include "signal/delegate.hpp" #include "signal/dispatcher.hpp" #include "signal/emitter.hpp" +#include "signal/fwd.hpp" #include "signal/sigh.hpp" -#include "graph/fwd.hpp" #include "graph/adjacency_matrix.hpp" #include "graph/dot.hpp" #include "graph/flow.hpp" +#include "graph/fwd.hpp" -#include "entity/fwd.hpp" #include "entity/component.hpp" #include "entity/entity.hpp" +#include "entity/fwd.hpp" #include "entity/group.hpp" #include "entity/handle.hpp" #include "entity/helper.hpp" @@ -81,20 +83,20 @@ export module entt; #include "locator/locator.hpp" -#include "meta/fwd.hpp" #include "meta/adl_pointer.hpp" +#include "meta/container.hpp" #include "meta/context.hpp" -#include "meta/type_traits.hpp" +#include "meta/factory.hpp" +#include "meta/fwd.hpp" +#include "meta/meta.hpp" #include "meta/node.hpp" +#include "meta/pointer.hpp" +#include "meta/policy.hpp" #include "meta/range.hpp" -#include "meta/meta.hpp" -#include "meta/container.hpp" #include "meta/resolve.hpp" -#include "meta/policy.hpp" -#include "meta/utility.hpp" -#include "meta/factory.hpp" -#include "meta/pointer.hpp" #include "meta/template.hpp" +#include "meta/type_traits.hpp" +#include "meta/utility.hpp" #include "poly/fwd.hpp" #include "poly/poly.hpp" @@ -103,7 +105,7 @@ export module entt; #include "process/process.hpp" #include "process/scheduler.hpp" -#include "resource/fwd.hpp" #include "resource/cache.hpp" +#include "resource/fwd.hpp" #include "resource/loader.hpp" #include "resource/resource.hpp" \ No newline at end of file From 9ec792670fb4494ba5790c4a8a4bbabe02cebab9 Mon Sep 17 00:00:00 2001 From: caiowakamatsu Date: Sat, 27 Jun 2026 14:28:42 -0300 Subject: [PATCH 06/10] remove missing attribute include --- src/entt/entt.ixx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/entt/entt.ixx b/src/entt/entt.ixx index 502c3bd313..9c26297d97 100644 --- a/src/entt/entt.ixx +++ b/src/entt/entt.ixx @@ -27,7 +27,6 @@ module; #include "config/config.h" #include "config/macro.h" #include "config/version.h" -#include "core/attribute.h" export module entt; @@ -108,4 +107,4 @@ export module entt; #include "resource/cache.hpp" #include "resource/fwd.hpp" #include "resource/loader.hpp" -#include "resource/resource.hpp" \ No newline at end of file +#include "resource/resource.hpp" From c693baf516dc78d1a4c9e196bd6ce7a891e99b70 Mon Sep 17 00:00:00 2001 From: caiowakamatsu Date: Sat, 27 Jun 2026 14:32:36 -0300 Subject: [PATCH 07/10] change order of includes to match what seemingly works --- src/entt/entt.ixx | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/src/entt/entt.ixx b/src/entt/entt.ixx index 9c26297d97..8619ca86bd 100644 --- a/src/entt/entt.ixx +++ b/src/entt/entt.ixx @@ -5,6 +5,7 @@ module; #define ENTT_MODULE_EXPORT_BEGIN export { #define ENTT_MODULE_EXPORT_END } +// clang-format off #include #include #include @@ -19,6 +20,7 @@ module; #include #include #include +#include #ifdef ENTT_USER_CONFIG # include ENTT_USER_CONFIG @@ -31,12 +33,13 @@ module; export module entt; #include "core/algorithm.hpp" +#include "core/fwd.hpp" +#include "core/type_traits.hpp" #include "core/any.hpp" #include "core/bit.hpp" #include "core/compressed_pair.hpp" #include "core/enum.hpp" #include "core/family.hpp" -#include "core/fwd.hpp" #include "core/hashed_string.hpp" #include "core/ident.hpp" #include "core/iterator.hpp" @@ -45,7 +48,6 @@ export module entt; #include "core/ranges.hpp" #include "core/tuple.hpp" #include "core/type_info.hpp" -#include "core/type_traits.hpp" #include "core/utility.hpp" #include "container/dense_map.hpp" @@ -53,16 +55,16 @@ export module entt; #include "container/fwd.hpp" #include "container/table.hpp" +#include "signal/fwd.hpp" #include "signal/delegate.hpp" #include "signal/dispatcher.hpp" #include "signal/emitter.hpp" -#include "signal/fwd.hpp" #include "signal/sigh.hpp" +#include "graph/fwd.hpp" #include "graph/adjacency_matrix.hpp" #include "graph/dot.hpp" #include "graph/flow.hpp" -#include "graph/fwd.hpp" #include "entity/component.hpp" #include "entity/entity.hpp" @@ -83,19 +85,19 @@ export module entt; #include "locator/locator.hpp" #include "meta/adl_pointer.hpp" -#include "meta/container.hpp" -#include "meta/context.hpp" -#include "meta/factory.hpp" #include "meta/fwd.hpp" -#include "meta/meta.hpp" +#include "meta/context.hpp" +#include "meta/type_traits.hpp" #include "meta/node.hpp" -#include "meta/pointer.hpp" -#include "meta/policy.hpp" #include "meta/range.hpp" +#include "meta/meta.hpp" #include "meta/resolve.hpp" -#include "meta/template.hpp" -#include "meta/type_traits.hpp" +#include "meta/container.hpp" +#include "meta/policy.hpp" #include "meta/utility.hpp" +#include "meta/factory.hpp" +#include "meta/pointer.hpp" +#include "meta/template.hpp" #include "poly/fwd.hpp" #include "poly/poly.hpp" @@ -104,7 +106,7 @@ export module entt; #include "process/process.hpp" #include "process/scheduler.hpp" +#include "resource/resource.hpp" #include "resource/cache.hpp" #include "resource/fwd.hpp" #include "resource/loader.hpp" -#include "resource/resource.hpp" From 1dc2c0d729044a95d3c00cb38532d7b7f12e8495 Mon Sep 17 00:00:00 2001 From: caiowakamatsu Date: Sat, 27 Jun 2026 16:08:13 -0300 Subject: [PATCH 08/10] add std less to utility --- src/entt/stl/utility.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/entt/stl/utility.hpp b/src/entt/stl/utility.hpp index 2450d1bd82..52568199d8 100644 --- a/src/entt/stl/utility.hpp +++ b/src/entt/stl/utility.hpp @@ -19,6 +19,7 @@ using std::in_place_type; using std::in_place_type_t; using std::index_sequence; using std::index_sequence_for; +using std::less; using std::make_index_sequence; using std::make_pair; using std::move; From ca0652e602bf529233f143a70076ac81d0a469ef Mon Sep 17 00:00:00 2001 From: caiowakamatsu Date: Sat, 27 Jun 2026 16:37:42 -0300 Subject: [PATCH 09/10] change internal linkage for modules --- src/entt/container/dense_map.hpp | 2 +- src/entt/container/dense_set.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/entt/container/dense_map.hpp b/src/entt/container/dense_map.hpp index 623d4d61fc..3edd7a06f3 100644 --- a/src/entt/container/dense_map.hpp +++ b/src/entt/container/dense_map.hpp @@ -31,7 +31,7 @@ namespace entt { /*! @cond ENTT_INTERNAL */ namespace internal { -static constexpr stl::size_t dense_map_placeholder_position = (stl::numeric_limits::max)(); +inline constexpr stl::size_t dense_map_placeholder_position = (stl::numeric_limits::max)(); template struct dense_map_node final { diff --git a/src/entt/container/dense_set.hpp b/src/entt/container/dense_set.hpp index 49f0ce2495..ba687382d1 100644 --- a/src/entt/container/dense_set.hpp +++ b/src/entt/container/dense_set.hpp @@ -28,7 +28,7 @@ namespace entt { /*! @cond ENTT_INTERNAL */ namespace internal { -static constexpr stl::size_t dense_set_placeholder_position = (stl::numeric_limits::max)(); +inline constexpr stl::size_t dense_set_placeholder_position = (stl::numeric_limits::max)(); template class dense_set_iterator final { From 85ea38fb404bbaf88048c3444a50c8b9741a4f71 Mon Sep 17 00:00:00 2001 From: caiowakamatsu Date: Sat, 27 Jun 2026 16:37:48 -0300 Subject: [PATCH 10/10] fix include ordering --- src/entt/entt.ixx | 44 +++++++++++++++++++++++++++----------------- 1 file changed, 27 insertions(+), 17 deletions(-) diff --git a/src/entt/entt.ixx b/src/entt/entt.ixx index 8619ca86bd..636ae1a7cf 100644 --- a/src/entt/entt.ixx +++ b/src/entt/entt.ixx @@ -6,21 +6,28 @@ module; #define ENTT_MODULE_EXPORT_END } // clang-format off -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include "stl/algorithm.hpp" +#include "stl/array.hpp" +#include "stl/atomic.hpp" +#include "stl/bit.hpp" +#include "stl/cmath.hpp" +#include "stl/concepts.hpp" +#include "stl/cstddef.hpp" +#include "stl/cstdint.hpp" +#include "stl/functional.hpp" +#include "stl/ios.hpp" +#include "stl/iterator.hpp" +#include "stl/limits.hpp" +#include "stl/memory.hpp" +#include "stl/ostream.hpp" +#include "stl/sstream.hpp" +#include "stl/string.hpp" +#include "stl/string_view.hpp" +#include "stl/tuple.hpp" +#include "stl/type_traits.hpp" +#include "stl/utility.hpp" +#include "stl/vector.hpp" + #ifdef ENTT_USER_CONFIG # include ENTT_USER_CONFIG @@ -35,19 +42,20 @@ export module entt; #include "core/algorithm.hpp" #include "core/fwd.hpp" #include "core/type_traits.hpp" +#include "core/concepts.hpp" +#include "core/hashed_string.hpp" +#include "core/type_info.hpp" #include "core/any.hpp" #include "core/bit.hpp" #include "core/compressed_pair.hpp" #include "core/enum.hpp" #include "core/family.hpp" -#include "core/hashed_string.hpp" #include "core/ident.hpp" #include "core/iterator.hpp" #include "core/memory.hpp" #include "core/monostate.hpp" #include "core/ranges.hpp" #include "core/tuple.hpp" -#include "core/type_info.hpp" #include "core/utility.hpp" #include "container/dense_map.hpp" @@ -110,3 +118,5 @@ export module entt; #include "resource/cache.hpp" #include "resource/fwd.hpp" #include "resource/loader.hpp" + +// clang-format on