diff --git a/CMakeLists.txt b/CMakeLists.txt index 401c5d6863..b5c1d21aa4 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,29 @@ 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 + BASE_DIRS ${EnTT_SOURCE_DIR}/src/entt + FILES + ${EnTT_SOURCE_DIR}/src/entt/entt.ixx + ) endif() if(ENTT_CLANG_TIDY_EXECUTABLE) @@ -295,11 +331,22 @@ if(ENTT_INSTALL) include(CMakePackageConfigHelpers) - install( - TARGETS EnTT - EXPORT EnTTTargets - ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} - ) + 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 @@ -313,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 @@ -357,12 +423,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/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) +``` 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..3edd7a06f3 100644 --- a/src/entt/container/dense_map.hpp +++ b/src/entt/container/dense_map.hpp @@ -1,33 +1,37 @@ #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 { /*! @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 { @@ -58,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)); @@ -150,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)); @@ -211,9 +254,25 @@ 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 */ +ENTT_MODULE_EXPORT_BEGIN + /** * @brief Associative container for key-value pairs with unique keys. * @@ -1009,6 +1068,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..ba687382d1 100644 --- a/src/entt/container/dense_set.hpp +++ b/src/entt/container/dense_set.hpp @@ -1,36 +1,39 @@ #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 { -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 { template - friend class dense_set_iterator; + friend class internal::dense_set_iterator; static_assert(stl::is_pointer_v, "Not a pointer type"); @@ -119,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"); @@ -176,9 +218,25 @@ 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 */ +ENTT_MODULE_EXPORT_BEGIN + /** * @brief Associative container for unique objects of a given type. * @@ -885,6 +943,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..8eca495d1a 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 { @@ -18,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()...)); @@ -105,9 +109,50 @@ 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 */ +ENTT_MODULE_EXPORT_BEGIN + /** * @brief Basic table implementation. * @@ -417,16 +462,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..86662512c2 100644 --- a/src/entt/core/enum.hpp +++ b/src/entt/core/enum.hpp @@ -1,43 +1,48 @@ #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 +ENTT_MODULE_EXPORT_BEGIN + /** * @brief Operator available for enums for which bitmask support is enabled. * @tparam Type Enum class type. @@ -99,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/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..d46873e740 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 { @@ -84,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; @@ -240,6 +258,8 @@ class group_handler final: public group_descriptor { } // namespace internal /*! @endcond */ +ENTT_MODULE_EXPORT_BEGIN + /** * @brief Group. * @@ -1047,6 +1067,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..df79dc34ff 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 { @@ -75,9 +79,25 @@ 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 */ +ENTT_MODULE_EXPORT_BEGIN + /** * @brief Non-owning handle to an entity. * @@ -363,6 +383,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..96d7807573 100644 --- a/src/entt/entity/registry.hpp +++ b/src/entt/entity/registry.hpp @@ -1,34 +1,38 @@ #ifndef ENTT_ENTITY_REGISTRY_HPP #define ENTT_ENTITY_REGISTRY_HPP -#include -#include "../config/config.h" -#include "../container/dense_map.hpp" -#include "../core/algorithm.hpp" -#include "../core/any.hpp" -#include "../core/concepts.hpp" -#include "../core/fwd.hpp" -#include "../core/iterator.hpp" -#include "../core/memory.hpp" -#include "../core/type_info.hpp" -#include "../core/type_traits.hpp" -#include "../stl/algorithm.hpp" -#include "../stl/array.hpp" -#include "../stl/concepts.hpp" -#include "../stl/cstddef.hpp" -#include "../stl/functional.hpp" -#include "../stl/iterator.hpp" -#include "../stl/memory.hpp" -#include "../stl/tuple.hpp" -#include "../stl/type_traits.hpp" -#include "../stl/utility.hpp" -#include "entity.hpp" -#include "fwd.hpp" -#include "group.hpp" -#include "mixin.hpp" -#include "sparse_set.hpp" -#include "storage.hpp" -#include "view.hpp" +#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" +#endif // ENTT_MODULE namespace entt { @@ -128,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; @@ -202,6 +245,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 +1221,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..c88a15753b 100644 --- a/src/entt/entity/snapshot.hpp +++ b/src/entt/entity/snapshot.hpp @@ -1,18 +1,22 @@ #ifndef ENTT_ENTITY_SNAPSHOT_HPP #define ENTT_ENTITY_SNAPSHOT_HPP -#include "../config/config.h" -#include "../container/dense_map.hpp" -#include "../core/type_traits.hpp" -#include "../stl/concepts.hpp" -#include "../stl/cstddef.hpp" -#include "../stl/iterator.hpp" -#include "../stl/tuple.hpp" -#include "../stl/type_traits.hpp" -#include "../stl/utility.hpp" -#include "entity.hpp" -#include "fwd.hpp" -#include "view.hpp" +#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" +#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..a9673fe520 100644 --- a/src/entt/entity/sparse_set.hpp +++ b/src/entt/entity/sparse_set.hpp @@ -1,21 +1,25 @@ #ifndef ENTT_ENTITY_SPARSE_SET_HPP #define ENTT_ENTITY_SPARSE_SET_HPP -#include -#include "../config/config.h" -#include "../core/algorithm.hpp" -#include "../core/any.hpp" -#include "../core/bit.hpp" -#include "../core/type_info.hpp" -#include "../stl/concepts.hpp" -#include "../stl/cstddef.hpp" -#include "../stl/iterator.hpp" -#include "../stl/memory.hpp" -#include "../stl/type_traits.hpp" -#include "../stl/utility.hpp" -#include "../stl/vector.hpp" -#include "entity.hpp" -#include "fwd.hpp" +#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" +#endif // ENTT_MODULE namespace entt { @@ -113,9 +117,50 @@ 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 */ +ENTT_MODULE_EXPORT_BEGIN + /** * @brief Sparse set implementation. * @@ -1071,6 +1116,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..3551f587dc 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 { @@ -131,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 @@ -186,9 +229,25 @@ 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 */ +ENTT_MODULE_EXPORT_BEGIN + /** * @brief Storage implementation. * @@ -1217,6 +1276,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..fed55cec99 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() { @@ -57,7 +61,10 @@ template +template +class extended_view_iterator; + +template class view_iterator final { template friend struct extended_view_iterator; @@ -128,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; @@ -176,9 +197,25 @@ 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 */ +ENTT_MODULE_EXPORT_BEGIN + /** * @brief View implementation. * @@ -1137,6 +1174,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..636ae1a7cf --- /dev/null +++ b/src/entt/entt.ixx @@ -0,0 +1,122 @@ +module; + +#define ENTT_MODULE +#define ENTT_MODULE_EXPORT export +#define ENTT_MODULE_EXPORT_BEGIN export { +#define ENTT_MODULE_EXPORT_END } + +// clang-format off +#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 +#endif // ENTT_USER_CONFIG + +#include "config/config.h" +#include "config/macro.h" +#include "config/version.h" + +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/ident.hpp" +#include "core/iterator.hpp" +#include "core/memory.hpp" +#include "core/monostate.hpp" +#include "core/ranges.hpp" +#include "core/tuple.hpp" +#include "core/utility.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/sigh.hpp" + +#include "graph/fwd.hpp" +#include "graph/adjacency_matrix.hpp" +#include "graph/dot.hpp" +#include "graph/flow.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" +#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/adl_pointer.hpp" +#include "meta/fwd.hpp" +#include "meta/context.hpp" +#include "meta/type_traits.hpp" +#include "meta/node.hpp" +#include "meta/range.hpp" +#include "meta/meta.hpp" +#include "meta/resolve.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" + +#include "process/fwd.hpp" +#include "process/process.hpp" +#include "process/scheduler.hpp" + +#include "resource/resource.hpp" +#include "resource/cache.hpp" +#include "resource/fwd.hpp" +#include "resource/loader.hpp" + +// clang-format on diff --git a/src/entt/graph/adjacency_matrix.hpp b/src/entt/graph/adjacency_matrix.hpp index ba835615d6..bd9b8f7fff 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 { @@ -76,9 +80,25 @@ 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 */ +ENTT_MODULE_EXPORT_BEGIN + /** * @brief Basic implementation of a directed adjacency matrix. * @tparam Category Either a directed or undirected category tag. @@ -327,6 +347,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..732f1e4037 100644 --- a/src/entt/meta/context.hpp +++ b/src/entt/meta/context.hpp @@ -1,23 +1,26 @@ #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 { struct meta_type_node; struct meta_context { - using bucket_type = dense_map, stl::identity>; + using container_type = dense_map, stl::identity>; - bucket_type bucket; + container_type bucket; [[nodiscard]] inline static meta_context &from(meta_ctx &); [[nodiscard]] inline static const meta_context &from(const meta_ctx &); @@ -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 e91888a7e4..a5b4f1371b 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 { @@ -30,7 +34,7 @@ namespace entt { namespace internal { class basic_meta_factory { - using invoke_type = stl::remove_pointer_t; + using invoke_type = std::remove_pointer_t; enum class mode { type, @@ -51,30 +55,26 @@ class basic_meta_factory { return overload; } - bool unique_alias(const id_type alias) const noexcept { - return (ctx->bucket.find(alias) == ctx->bucket.cend()) && (stl::find_if(ctx->bucket.cbegin(), ctx->bucket.cend(), [alias](const auto &value) { return value.second->alias == alias; }) == ctx->bucket.cend()); - } - protected: - void type(const id_type alias, const char *name) noexcept { + void type(const id_type id, const char *name) noexcept { state = mode::type; - ENTT_ASSERT((parent->alias == alias) || unique_alias(alias), "Duplicate identifier"); - parent->alias = alias; + ENTT_ASSERT(parent->id == id || !resolve(*ctx, id), "Duplicate identifier"); parent->name = name; + parent->id = id; } template void insert_or_assign(Type node) { state = mode::type; - if constexpr(stl::is_same_v) { + if constexpr(std::is_same_v) { auto *member = find_member(parent->details->base, node.id); member ? (*member = node) : parent->details->base.emplace_back(node); - } else if constexpr(stl::is_same_v) { + } else if constexpr(std::is_same_v) { auto *member = find_member(parent->details->conv, node.id); member ? (*member = node) : parent->details->conv.emplace_back(node); } else { - static_assert(stl::is_same_v, "Unexpected type"); + static_assert(std::is_same_v, "Unexpected type"); auto *member = find_member(parent->details->ctor, node.id); member ? (*member = node) : parent->details->ctor.emplace_back(node); } @@ -85,9 +85,9 @@ class basic_meta_factory { bucket = node.id; if(auto *member = find_member(parent->details->data, node.id); member == nullptr) { - parent->details->data.emplace_back(stl::move(node)); + parent->details->data.emplace_back(std::move(node)); } else if(member->set != node.set || member->get != node.get) { - *member = stl::move(node); + *member = std::move(node); } } @@ -97,10 +97,10 @@ class basic_meta_factory { invoke = node.invoke; if(auto *member = find_member(parent->details->func, node.id); member == nullptr) { - parent->details->func.emplace_back(stl::move(node)); + parent->details->func.emplace_back(std::move(node)); } else if(auto *overload = find_overload(member, node.invoke); overload == nullptr) { while(member->next != nullptr) { member = member->next.get(); } - member->next = stl::make_unique(stl::move(node)); + member->next = std::make_unique(std::move(node)); } } @@ -125,37 +125,35 @@ class basic_meta_factory { void custom(meta_custom_node node) { switch(state) { case mode::type: - parent->custom = stl::move(node); + parent->custom = std::move(node); break; case mode::data: - find_member_or_assert()->custom = stl::move(node); + find_member_or_assert()->custom = std::move(node); break; case mode::func: - find_overload_or_assert()->custom = stl::move(node); + find_overload_or_assert()->custom = std::move(node); break; } } public: - basic_meta_factory(meta_ctx &area, meta_type_node node, const id_type id) - : ctx{&meta_context::from(area)}, - bucket{}, + basic_meta_factory(meta_ctx &area, meta_type_node node) + : ctx{&area}, + bucket{node.info->hash()}, state{mode::type} { - if(const auto it = ctx->bucket.find(id); it == ctx->bucket.cend()) { - ENTT_ASSERT(unique_alias(id), "Duplicate identifier"); - parent = ctx->bucket.emplace(id, stl::make_unique(stl::move(node))).first->second.get(); - parent->details = stl::make_unique(); - parent->alias = id; + if(const auto it = meta_context::from(*ctx).bucket.find(bucket); it == meta_context::from(*ctx).bucket.cend()) { + parent = meta_context::from(*ctx).bucket.emplace(node.info->hash(), std::make_unique(std::move(node))).first->second.get(); + parent->details = std::make_unique(); } else { parent = it->second.get(); } } private: - meta_context *ctx{}; + meta_ctx *ctx{}; + id_type bucket{}; invoke_type *invoke{}; meta_type_node *parent{}; - id_type bucket{}; mode state{}; }; @@ -183,22 +181,7 @@ class meta_factory: private internal::basic_meta_factory { * @param area The context into which to construct meta types. */ meta_factory(meta_ctx &area) noexcept - : base_type{area, internal::setup_node_for(), type_hash::value()} {} - - /** - * @brief Constructs an unconstrained type assigned to a given identifier. - * @param id A custom unique identifier. - */ - meta_factory(const id_type id) noexcept - : meta_factory{locator::value_or(), id} {} - - /** - * @brief Context aware constructor. - * @param id A custom unique identifier. - * @param area The context into which to construct meta types. - */ - meta_factory(meta_ctx &area, const id_type id) noexcept - : base_type{area, internal::setup_node_for(), id} {} + : internal::basic_meta_factory{area, internal::setup_node_for()} {} /** * @brief Assigns a custom unique identifier to a meta type. @@ -211,12 +194,12 @@ class meta_factory: private internal::basic_meta_factory { /** * @brief Assigns a custom unique identifier to a meta type. - * @param alias A custom unique identifier. + * @param id A custom unique identifier. * @param name An optional name for the type as a **string literal**. * @return A meta factory for the given type. */ - meta_factory type(const id_type alias, const char *name = nullptr) noexcept { - base_type::type(alias, name); + meta_factory type(const id_type id, const char *name = nullptr) noexcept { + base_type::type(id, name); return *this; } @@ -229,10 +212,10 @@ class meta_factory: private internal::basic_meta_factory { * @return A meta factory for the parent type. */ template - requires stl::derived_from + requires std::derived_from meta_factory base() noexcept { - if constexpr(!stl::same_as) { - auto *const op = +[](const void *instance) noexcept { return static_cast(static_cast(static_cast(instance))); }; + if constexpr(!std::same_as) { + auto *const op = +[](const void *instance) noexcept { return static_cast(static_cast(static_cast(instance))); }; base_type::insert_or_assign( internal::meta_base_node{ @@ -258,8 +241,8 @@ class meta_factory: private internal::basic_meta_factory { */ template auto conv() noexcept { - using conv_type = stl::remove_cvref_t>; - auto *const op = +[](const meta_ctx &area, const void *instance) { return forward_as_meta(area, stl::invoke(Candidate, *static_cast(instance))); }; + using conv_type = std::remove_cvref_t>; + auto *const op = +[](const meta_ctx &area, const void *instance) { return forward_as_meta(area, std::invoke(Candidate, *static_cast(instance))); }; base_type::insert_or_assign( internal::meta_conv_node{ @@ -280,8 +263,8 @@ class meta_factory: private internal::basic_meta_factory { */ template meta_factory conv() noexcept { - using conv_type = stl::remove_cvref_t; - auto *const op = +[](const meta_ctx &area, const void *instance) { return forward_as_meta(area, static_cast(*static_cast(instance))); }; + using conv_type = std::remove_cvref_t; + auto *const op = +[](const meta_ctx &area, const void *instance) { return forward_as_meta(area, static_cast(*static_cast(instance))); }; base_type::insert_or_assign( internal::meta_conv_node{ @@ -306,16 +289,16 @@ class meta_factory: private internal::basic_meta_factory { */ template meta_factory ctor() noexcept { - using descriptor = meta_function_helper_t; + using descriptor = meta_function_helper_t; static_assert(Policy::template value, "Invalid return type for the given policy"); - static_assert(stl::is_same_v, element_type>, "The function doesn't return an object of the required type"); + static_assert(std::is_same_v, Type>, "The function doesn't return an object of the required type"); base_type::insert_or_assign( internal::meta_ctor_node{ type_id().hash(), descriptor::args_type::size, &meta_arg, - &meta_construct}); + &meta_construct}); return *this; } @@ -334,14 +317,14 @@ class meta_factory: private internal::basic_meta_factory { meta_factory ctor() noexcept { // default constructor is already implicitly generated, no need for redundancy if constexpr(sizeof...(Args) != 0u) { - using descriptor = meta_function_helper_t; + using descriptor = meta_function_helper_t; base_type::insert_or_assign( internal::meta_ctor_node{ type_id().hash(), descriptor::args_type::size, &meta_arg, - &meta_construct}); + &meta_construct}); } return *this; @@ -375,8 +358,8 @@ class meta_factory: private internal::basic_meta_factory { */ template meta_factory data(const id_type id, const char *name = nullptr) noexcept { - if constexpr(stl::is_member_object_pointer_v) { - using data_type = stl::invoke_result_t; + if constexpr(std::is_member_object_pointer_v) { + using data_type = std::invoke_result_t; static_assert(Policy::template value, "Invalid return type for the given policy"); base_type::data( @@ -384,18 +367,16 @@ class meta_factory: private internal::basic_meta_factory { id, name, /* this is never static */ - stl::is_const_v> ? internal::meta_traits::is_const : internal::meta_traits::is_none, + std::is_const_v> ? internal::meta_traits::is_const : internal::meta_traits::is_none, 1u, - 0u, - &meta_arg>>, - &meta_arg>, - &internal::resolve>, - &meta_setter, - &meta_getter}); + &internal::resolve>, + &meta_arg>>, + &meta_setter, + &meta_getter}); } else { - using data_type = stl::remove_pointer_t; + using data_type = std::remove_pointer_t; - if constexpr(stl::is_pointer_v) { + if constexpr(std::is_pointer_v) { static_assert(Policy::template value, "Invalid return type for the given policy"); } else { static_assert(Policy::template value, "Invalid return type for the given policy"); @@ -405,14 +386,12 @@ class meta_factory: private internal::basic_meta_factory { internal::meta_data_node{ id, name, - ((!stl::is_pointer_v || stl::is_const_v) ? internal::meta_traits::is_const : internal::meta_traits::is_none) | internal::meta_traits::is_static, + ((!std::is_pointer_v || std::is_const_v) ? internal::meta_traits::is_const : internal::meta_traits::is_none) | internal::meta_traits::is_static, 1u, - 0u, - &meta_arg>>, - &meta_arg>, - &internal::resolve>, - &meta_setter, - &meta_getter}); + &internal::resolve>, + &meta_arg>>, + &meta_setter, + &meta_getter}); } return *this; @@ -455,10 +434,10 @@ class meta_factory: private internal::basic_meta_factory { */ template meta_factory data(const id_type id, const char *name = nullptr) noexcept { - using getter = meta_function_helper_t; - static_assert(Policy::template value, "Invalid return type for the given policy"); + using descriptor = meta_function_helper_t; + static_assert(Policy::template value, "Invalid return type for the given policy"); - if constexpr(stl::is_same_v) { + if constexpr(std::is_same_v) { base_type::data( internal::meta_data_node{ id, @@ -466,14 +445,12 @@ class meta_factory: private internal::basic_meta_factory { /* this is never static */ internal::meta_traits::is_const, 0u, - getter::args_type::size, + &internal::resolve>, &meta_arg>, - &meta_arg, - &internal::resolve>, - &meta_setter, - &meta_getter}); + &meta_setter, + &meta_getter}); } else { - using setter = meta_function_helper_t; + using args_type = meta_function_helper_t::args_type; base_type::data( internal::meta_data_node{ @@ -481,13 +458,11 @@ class meta_factory: private internal::basic_meta_factory { name, /* this is never static nor const */ internal::meta_traits::is_none, - setter::args_type::size, - getter::args_type::size, - &meta_arg, - &meta_arg, - &internal::resolve>, - &meta_setter, - &meta_getter}); + 1u, + &internal::resolve>, + &meta_arg(args_type::size != 1u), args_type>>>, + &meta_setter, + &meta_getter}); } return *this; @@ -521,7 +496,7 @@ class meta_factory: private internal::basic_meta_factory { */ template meta_factory func(const id_type id, const char *name = nullptr) noexcept { - using descriptor = meta_function_helper_t; + using descriptor = meta_function_helper_t; static_assert(Policy::template value, "Invalid return type for the given policy"); base_type::func( @@ -530,9 +505,9 @@ class meta_factory: private internal::basic_meta_factory { name, (descriptor::is_const ? internal::meta_traits::is_const : internal::meta_traits::is_none) | (descriptor::is_static ? internal::meta_traits::is_static : internal::meta_traits::is_none), descriptor::args_type::size, - &internal::resolve, void, stl::remove_cvref_t>>, + &internal::resolve, void, std::remove_cvref_t>>, &meta_arg, - &meta_invoke}); + &meta_invoke}); return *this; } @@ -549,7 +524,7 @@ class meta_factory: private internal::basic_meta_factory { */ template meta_factory traits(const Value value, const bool unset = false) { - static_assert(stl::is_enum_v, "Invalid enum type"); + static_assert(std::is_enum_v, "Invalid enum type"); base_type::traits(internal::user_to_meta_traits(value), unset); return *this; } @@ -563,7 +538,7 @@ class meta_factory: private internal::basic_meta_factory { */ template meta_factory custom(Args &&...args) { - base_type::custom(internal::meta_custom_node{type_id().hash(), stl::make_shared(stl::forward(args)...)}); + base_type::custom(internal::meta_custom_node{type_id().hash(), std::make_shared(std::forward(args)...)}); return *this; } }; @@ -577,16 +552,17 @@ class meta_factory: private internal::basic_meta_factory { * * The type is also removed from the set of searchable types. * - * @param alias Unique identifier. + * @param id Unique identifier. * @param ctx The context from which to reset meta types. */ -inline void meta_reset(meta_ctx &ctx, const id_type alias) noexcept { - auto &bucket = internal::meta_context::from(ctx).bucket; +inline void meta_reset(meta_ctx &ctx, const id_type id) noexcept { + auto &context = internal::meta_context::from(ctx); - // fast path for unsearchable and overloaded types - if(bucket.erase(alias) == 0u) { - if(const auto it = stl::find_if(bucket.cbegin(), bucket.cend(), [alias](const auto &value) { return value.second->alias == alias; }); it != bucket.cend()) { - bucket.erase(it); + for(auto it = context.bucket.begin(); it != context.bucket.end();) { + if(it->second->id == id) { + it = context.bucket.erase(it); + } else { + ++it; } } } @@ -600,10 +576,10 @@ inline void meta_reset(meta_ctx &ctx, const id_type alias) noexcept { * * The type is also removed from the set of searchable types. * - * @param alias Unique identifier. + * @param id Unique identifier. */ -inline void meta_reset(const id_type alias) noexcept { - meta_reset(locator::value_or(), alias); +inline void meta_reset(const id_type id) noexcept { + meta_reset(locator::value_or(), id); } /** 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 e4f5fd7833..d7e00f0da1 100644 --- a/src/entt/meta/meta.hpp +++ b/src/entt/meta/meta.hpp @@ -1,1901 +1,1949 @@ #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 = std::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{std::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 = std::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{std::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(!std::is_void_v::element_type>>) { + if constexpr(std::is_constructible_v) { + if(const auto &pointer_like = any_cast(value.storage); pointer_like) { + static_cast(other)->emplace::dereference(std::declval()))>(adl_meta_pointer_like::dereference(pointer_like)); + } + } else { + static_cast(other)->emplace::dereference(std::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(std::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(!std::is_array_v && !std::is_void_v>>) { + if(auto *pointer = any_cast(value.storage); pointer) { + static_cast(other)->emplace>>, Type, std::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 = std::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; } - } - [[nodiscard]] const auto &fetch_node() const { - if(node == nullptr) { - ENTT_ASSERT(*this, "Invalid vtable function"); - vtable(internal::meta_traits::is_none, *this, nullptr); + meta_any(const meta_any &other, any elem) + : storage{std::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. + * @tparam Args Types of arguments to use to construct the new instance. + * @param args Parameters to use to construct the instance. + */ + template + explicit meta_any(std::in_place_type_t, Args &&...args) + : meta_any{locator::value_or(), std::in_place_type, std::forward(args)...} {} + + /** + * @brief Constructs a wrapper by directly initializing the new object. + * @tparam Type Type of object to use to initialize the wrapper. + * @tparam Args Types of arguments to use to construct the new instance. + * @param 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, std::in_place_type_t, Args &&...args) + : storage{std::in_place_type, std::forward(args)...}, + ctx{&area}, + vtable{&basic_vtable>} {} + + /** + * @brief Constructs a wrapper taking ownership of the passed object. + * @tparam Type Type of object to use to initialize the wrapper. + * @param value A pointer to an object to take ownership of. + */ + template + explicit meta_any(std::in_place_t, Type *value) + : meta_any{locator::value_or(), std::in_place, value} {} + + /** + * @brief Constructs a wrapper taking ownership of the passed object. + * @tparam Type Type of object to use to initialize the wrapper. + * @param area The context from which to search for meta types. + * @param value A pointer to an object to take ownership of. + */ + template + explicit meta_any(const meta_ctx &area, std::in_place_t, Type *value) + : storage{std::in_place, value}, + ctx{&area}, + vtable{storage ? &basic_vtable : nullptr} { } - ENTT_ASSERT(node != nullptr, "Invalid pointer to node"); - return *node; - } + /** + * @brief Constructs a wrapper from a given value. + * @tparam Type Type of object to use to initialize the wrapper. + * @param value An instance of an object to use to initialize the wrapper. + */ + template + requires (!std::same_as, meta_any>) + meta_any(Type &&value) + : meta_any{locator::value_or(), std::forward(value)} {} + + /** + * @brief Constructs a wrapper from a given value. + * @tparam Type Type of object to use to initialize the wrapper. + * @param area The context from which to search for meta types. + * @param value An instance of an object to use to initialize the wrapper. + */ + template + requires (!std::same_as, meta_any>) + meta_any(const meta_ctx &area, Type &&value) + : meta_any{area, std::in_place_type>, std::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{std::move(other.storage)}, + ctx{&area}, + node{(ctx == other.ctx) ? std::exchange(other.node, nullptr) : nullptr}, + vtable{std::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} { + } - meta_any(const meta_any &other, any elem) - : storage{stl::move(elem)}, - ctx{other.ctx}, - node{other.node}, - vtable{other.vtable} {} + /** + * @brief Move constructor. + * @param other The instance to move from. + */ + meta_any(meta_any &&other) noexcept + : storage{std::move(other.storage)}, + ctx{other.ctx}, + node{std::exchange(other.node, nullptr)}, + vtable{std::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; + } -public: - /*! Default constructor. */ - meta_any() = default; + return *this; + } - /** - * @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 Move assignment operator. + * @param other The instance to move from. + * @return This meta any object. + */ + meta_any &operator=(meta_any &&other) noexcept { + storage = std::move(other.storage); + ctx = other.ctx; + node = std::exchange(other.node, nullptr); + vtable = std::exchange(other.vtable, nullptr); + return *this; + } - /** - * @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 Value assignment operator. + * @tparam Type Type of object to use to initialize the wrapper. + * @param value An instance of an object to use to initialize the wrapper. + * @return This meta any object. + */ + template + requires (!std::same_as, meta_any>) + meta_any &operator=(Type &&value) { + emplace>(std::forward(value)); + return *this; + } - /** - * @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 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 Invokes the underlying function, if possible. + * @tparam Args Types of arguments to use to invoke the function. + * @param id Unique identifier. + * @param args Parameters to use to invoke the function. + * @return A wrapper containing the returned value, if any. + */ + template + meta_any invoke(id_type id, Args &&...args) const; + + /*! @copydoc invoke */ + template + meta_any invoke(id_type id, Args &&...args); + + /** + * @brief Sets the value of a given variable. + * @tparam Type Type of value to assign. + * @param id Unique identifier. + * @param value Parameter to use to set the underlying variable. + * @return True in case of success, false otherwise. + */ + template + bool set(id_type id, Type &&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())); + } - /** - * @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} {} + /*! @copydoc try_cast */ + template + [[nodiscard]] Type *try_cast() { + return ((storage.policy() == any_policy::cref) && !std::is_const_v) ? nullptr : const_cast(std::as_const(*this).try_cast>()); + } - /** - * @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 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]] std::remove_const_t cast() const { + auto *const instance = try_cast>(); + ENTT_ASSERT(instance, "Invalid instance"); + return static_cast(*instance); + } - /** - * @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)} {} + /*! @copydoc cast */ + template + [[nodiscard]] std::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 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 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(!std::is_reference_v || std::is_const_v>) { + if(storage.has_value>()) { + return as_ref(); + } else if(*this) { + if constexpr(std::is_arithmetic_v> || std::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 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} {} + 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()); + } - /** - * @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)} {} + 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 = std::as_const(other).template allow_cast(); from_base) { + return from_base; + } + } + } + } + } - /** - * @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} { - } + return meta_any{meta_ctx_arg, *ctx}; + } - /** - * @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 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(std::is_reference_v && !std::is_const_v>) { + return allow_cast &>() && (storage.policy() != any_policy::cref); + } else { + if(storage.has_value>()) { + return true; + } else if(auto other = std::as_const(*this).allow_cast>(); other) { + if(other.storage.owner()) { + std::swap(*this, other); + } - /*! @brief Default destructor. */ - ~meta_any() = default; + return true; + } - /** - * @brief Copy assignment operator. - * @param other The instance to copy from. - * @return This meta any object. - */ - meta_any &operator=(const meta_any &other) { - if(this != &other) { - ctx = other.ctx; - storage = other.storage; - node = (other.storage && !storage) ? nullptr : other.node; - vtable = (other.storage && !storage) ? nullptr : other.vtable; + return false; + } } - return *this; - } + /*! @copydoc any::emplace */ + template + void emplace(Args &&...args) { + storage.emplace(std::forward(args)...); + auto *prev = std::exchange(vtable, &basic_vtable>); + node = (prev == vtable) ? node : nullptr; + } - /** - * @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; - } + /*! @copydoc any::assign */ + bool assign(const meta_any &other); - /** - * @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; - } + /*! @copydoc any::assign */ + bool assign(meta_any &&other); - /** - * @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; + /*! @copydoc any::reset */ + void reset() { + storage.reset(); + node = nullptr; + vtable = nullptr; + } - /** - * @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 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 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 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 invoke */ - meta_any invoke(id_type id, auto &&...args); + /** + * @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 Sets the value of a given variable. - * @param id Unique identifier. - * @param args Parameters to use to set the underlying variable. - * @return True in case of success, false otherwise. - */ - bool set(id_type id, auto &&...args); + /*! @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 Gets the value of a given variable. - * @param id Unique identifier. - * @param args Parameters to use to set the underlying variable, if any. - * @return A wrapper containing the value of the underlying variable. - */ - [[nodiscard]] meta_any get(id_type id, auto &&...args) const; + /** + * @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 get */ - [[nodiscard]] meta_any get(id_type id, auto &&...args); + /*! @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; + } - /** - * @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 any::operator bool */ + [[nodiscard]] explicit operator bool() const noexcept { + return !(vtable == nullptr); + } - /*! @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>()); - } + /*! @copydoc any::operator== */ + [[nodiscard]] bool operator==(const meta_any &other) const noexcept { + return (ctx == other.ctx) && (!*this == !other) && (storage == other.storage); + } - /** - * @brief Tries to cast an instance to a given type. - * @tparam Type Type to which to cast the instance. - * @return A reference to the contained instance. - */ - template - [[nodiscard]] stl::remove_const_t cast() const { - auto *const instance = try_cast>(); - ENTT_ASSERT(instance, "Invalid instance"); - return static_cast(*instance); - } + /*! @copydoc any::as_ref */ + [[nodiscard]] meta_any as_ref() noexcept { + return meta_any{*this, storage.as_ref()}; + } - /*! @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 any::as_ref */ + [[nodiscard]] meta_any as_ref() const noexcept { + return meta_any{*this, storage.as_ref()}; + } - /** - * @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 Returns the underlying storage. + * @return The underlyig storage. + */ + [[nodiscard]] const any &base() const noexcept { + return storage; + } - /** - * @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 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 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. + * @brief Forwards its argument and avoids copies for lvalue references. + * @tparam Type Type of argument to use to construct the new instance. + * @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. */ template - [[nodiscard]] meta_any allow_cast() const { - if constexpr(!stl::is_reference_v || stl::is_const_v>) { - if(storage.has_value>()) { - return as_ref(); - } else if(*this) { - if constexpr(stl::is_arithmetic_v> || stl::is_enum_v>) { - if(const auto &from = fetch_node(); from.conversion_helper) { - return meta_any{*ctx, static_cast(from.conversion_helper(nullptr, storage.data()))}; - } - } - - if(const auto &from = fetch_node(); from.details != nullptr) { - if(const auto *elem = internal::find_member(from.details->conv, entt::type_hash>::value()); elem != nullptr) { - return elem->conv(*ctx, storage.data()); - } - - for(auto &&curr: from.details->base) { - if(auto other = curr.type(internal::meta_context::from(*ctx)).from_void(*ctx, nullptr, curr.cast(storage.data())); curr.id == entt::type_hash>::value()) { - return other; - } else if(auto from_base = stl::as_const(other).template allow_cast(); from_base) { - return from_base; - } - } - } - } - } - - return meta_any{meta_ctx_arg, *ctx}; + [[nodiscard]] meta_any forward_as_meta(const meta_ctx &ctx, Type &&value) { + return meta_any{ctx, std::in_place_type, std::forward(value)}; } /** - * @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. + * @brief Forwards its argument and avoids copies for lvalue references. + * @tparam Type Type of argument to use to construct the new instance. + * @param value Parameter to use to construct the instance. + * @return A properly initialized and not necessarily owning wrapper. */ template - [[nodiscard]] bool allow_cast() { - if constexpr(stl::is_reference_v && !stl::is_const_v>) { - return allow_cast &>() && (storage.policy() != any_policy::cref); - } else { - if(storage.has_value>()) { - return true; - } else if(auto other = stl::as_const(*this).allow_cast>(); other) { - if(other.storage.owner()) { - stl::swap(*this, other); - } - - return true; - } - - return false; + [[nodiscard]] meta_any forward_as_meta(Type && value) { + return forward_as_meta(locator::value_or(), std::forward(value)); + } + + /*! @brief Opaque pointers to instances of any type. */ + class meta_handle { + template + requires std::same_as, meta_any> + meta_handle(int, Type &value, Args &&...args) + : any{std::forward(args)..., value.as_ref()} {} + + template + meta_handle(char, Type &value, Args &&...args) + : any{std::forward(args)..., std::in_place_type, value} {} + + public: + /*! Default constructor. */ + meta_handle() = default; + + /** + * @brief Creates a handle that points to an unmanaged object. + * @tparam Type Type of object to use to initialize the handle. + * @param ctx The context from which to search for meta types. + * @param value An instance of an object to use to initialize the handle. + */ + template + requires (!std::same_as, meta_handle>) + meta_handle(const meta_ctx &ctx, Type &value) + : meta_handle{0, value, ctx} {} + + /** + * @brief Creates a handle that points to an unmanaged object. + * @tparam Type Type of object to use to initialize the handle. + * @param value An instance of an object to use to initialize the handle. + */ + template + requires (!std::same_as, meta_handle>) + meta_handle(Type &value) + : 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, std::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); } - } - - /*! @copydoc any::emplace */ - template - void emplace(auto &&...args) { - storage.emplace(stl::forward(args)...); - auto *prev = stl::exchange(vtable, &basic_vtable>); - node = (prev == vtable) ? node : nullptr; - } - - /*! @copydoc any::assign */ - bool assign(const meta_any &other); - - /*! @copydoc any::assign */ - bool assign(meta_any &&other); - /*! @copydoc any::reset */ - void reset() { - storage.reset(); - node = nullptr; - vtable = nullptr; - } - - /** - * @brief Returns a sequence container proxy. - * @return A sequence container proxy for the underlying object. - */ - [[nodiscard]] meta_sequence_container as_sequence_container() noexcept { - meta_sequence_container proxy{}; - if(*this) { vtable(internal::meta_traits::is_sequence_container, *this, &proxy); } - return proxy; - } + /** + * @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; + } - /*! @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; - } + 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 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 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()); + } - /*! @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; - } + private: + const internal::meta_custom_node *node{}; + }; /** - * @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. + * @brief Common opaque wrapper for meta objects. + * @tparam Type Underlying meta node type. */ - [[nodiscard]] meta_any operator*() noexcept { - meta_any ret{meta_ctx_arg, *ctx}; - if(*this) { vtable(internal::meta_traits::is_pointer, *this, &ret); } - return ret; - } - - /*! @copydoc operator* */ - [[nodiscard]] meta_any operator*() const noexcept { - meta_any ret{meta_ctx_arg, *ctx}; - if(*this) { vtable(internal::meta_traits::is_pointer, as_ref(), &ret); } - return ret; - } - - /*! @copydoc any::operator bool */ - [[nodiscard]] explicit operator bool() const noexcept { - return !(vtable == nullptr); - } - - /*! @copydoc any::operator== */ - [[nodiscard]] bool operator==(const meta_any &other) const noexcept { - return (ctx == other.ctx) && (!*this == !other) && (storage == other.storage); - } + template + struct meta_object: protected internal::basic_meta_object { + /*! @brief Underlying meta node type. */ + using node_type = Type; + + /*! @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} { + } - /*! @copydoc any::as_ref */ - [[nodiscard]] meta_any as_ref() noexcept { - return meta_any{*this, storage.as_ref()}; - } + /** + * @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); + } - /*! @copydoc any::as_ref */ - [[nodiscard]] meta_any as_ref() const noexcept { - return meta_any{*this, storage.as_ref()}; - } + /** + * @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 Returns the underlying storage. - * @return The underlyig storage. - */ - [[nodiscard]] const any &base() const noexcept { - return storage; - } + /*! @brief Opaque wrapper for data members. */ + struct meta_data: meta_object { + /*! @brief Unsigned integer type. */ + using size_type = internal::meta_data_node::size_type; - /** - * @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; + using meta_object::meta_object; - /** - * @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 Returns the name assigned to a data member, if any. + * @return The name assigned to the data member, if any. + */ + [[nodiscard]] std::string_view name() const noexcept { + return (node_or_assert().name == nullptr) ? std::string_view{} : std::string_view{node_or_assert().name}; + } - /** - * @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 Returns the number of setters available. + * @return The number of setters available. + */ + [[nodiscard]] size_type arity() const noexcept { + return node_or_assert().arity; + } - /** - * @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 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 constructor, deleted on purpose. */ - meta_handle(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 constructor. */ - meta_handle(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. + * @tparam Type Type of value to assign. + * @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, Type &&value) const { + return node_or_assert().set(meta_handle{*ctx, std::forward(instance)}, meta_any{*ctx, std::forward(value)}); + } - /*! @brief Default destructor. */ - ~meta_handle() = default; + /** + * @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, std::forward(instance)}); + } - /** - * @brief Default copy assignment operator, deleted on purpose. - * @return This meta handle. - */ - meta_handle &operator=(const meta_handle &) = delete; + /** + * @brief Returns the type accepted by the i-th setter. + * @param index Index of the setter of which to return the accepted type. + * @return The type accepted by the i-th setter. + */ + [[nodiscard]] inline meta_type arg(size_type index) const noexcept; + + /** + * @brief Returns all meta traits for a given meta object. + * @tparam Type The type to convert the meta traits to. + * @return The registered meta traits, if any. + */ + template + [[nodiscard]] Type traits() const noexcept { + return internal::meta_to_user_traits(node_or_assert().traits); + } - /** - * @brief Default move assignment operator. - * @return This meta handle. - */ - meta_handle &operator=(meta_handle &&) = default; + /** + * @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 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 Opaque wrapper for member functions. */ + struct meta_func: meta_object { + /*! @brief Unsigned integer type. */ + using size_type = internal::meta_func_node::size_type; - /** - * @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; - } + using meta_object::meta_object; -private: - meta_any any{}; -}; + /** + * @brief Returns the name assigned to a member function, if any. + * @return The name assigned to the member function, if any. + */ + [[nodiscard]] std::string_view name() const noexcept { + return (node_or_assert().name == nullptr) ? std::string_view{} : std::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, std::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. + * @tparam Args Types of arguments to use to invoke the function. + * @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, Args &&...args) const { + return invoke(std::forward(instance), std::array{meta_any{*ctx, std::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 { + [[nodiscard]] const auto &fetch_node() const { + return (node == nullptr) ? internal::resolve(internal::meta_context::from(*ctx)) : *node; + } - /** - * @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}; - } + template + [[nodiscard]] auto lookup(meta_any *const args, const internal::meta_type_node::size_type sz, [[maybe_unused]] bool constness, Func next) const { + decltype(next()) candidate = nullptr; + size_type same{}; + bool ambiguous{}; - /** - * @brief Returns the number of arguments of a data member's setter. - * @return The number of arguments accepted by the data member's setter. - */ - [[nodiscard]] size_type set_arity() const noexcept { - return node_or_assert().set_arity; - } + for(auto curr = next(); curr; curr = next()) { + if constexpr(std::is_same_v, internal::meta_func_node>) { + if(constness && !(curr->traits & internal::meta_traits::is_const)) { + continue; + } + } - /** - * @brief Returns the number of arguments of a data member's getter. - * @return The number of arguments accepted by the data member's getter. - */ - [[nodiscard]] size_type get_arity() const noexcept { - return node_or_assert().get_arity; - } + if(curr->arity == sz) { + size_type match{}; + size_type pos{}; - /** - * @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); - } + // NOLINTBEGIN(cppcoreguidelines-pro-bounds-pointer-arithmetic) - waiting for C++20 (and std::span) + for(; pos < sz && args[pos]; ++pos) { + const auto other = curr->arg(*ctx, pos); + const auto type = args[pos].type(); - /** - * @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); - } + 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(std::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; + } + } - /*! @copydoc meta_any::type */ - [[nodiscard]] inline meta_type type() const noexcept; + ambiguous = true; + } + } + } + } - /** - * @brief Sets the value of a given variable. - * @tparam Instance Type of instance to operate on. - * @param instance An instance that fits the underlying type. - * @param args Parameters to use to set the underlying variable. - * @return True in case of success, false otherwise. - */ - template - // NOLINTNEXTLINE(modernize-use-nodiscard) - bool set(Instance &&instance, auto &&...args) const { - return (sizeof...(args) == set_arity()) && node_or_assert().set(meta_handle{*ctx, stl::forward(instance)}, stl::array{meta_any{*ctx, stl::forward(args)}...}.data()); - } + return ambiguous ? nullptr : candidate; + } - /** - * @brief Gets the value of a given variable. - * @tparam Instance Type of instance to operate on. - * @param instance An instance that fits the underlying type. - * @param args Parameters to use to get the underlying variable, if any. - * @return A wrapper containing the value of the underlying variable. - */ - template - [[nodiscard]] meta_any get(Instance &&instance, auto &&...args) const { - return (sizeof...(args) == get_arity()) ? node_or_assert().get(meta_handle{*ctx, stl::forward(instance)}, stl::array{meta_any{*ctx, stl::forward(args)}...}.data()) : meta_any{meta_ctx_arg, *ctx}; - } + public: + /*! @brief Unsigned integer type. */ + using size_type = internal::meta_type_node::size_type; + + /*! @brief Default constructor. */ + meta_type() noexcept = default; + + /** + * @brief Context aware constructor for meta objects. + * @param area The context from which to search for meta types. + * @param curr The underlying node with which to construct the instance. + */ + meta_type(const meta_ctx &area, const internal::meta_type_node &curr) noexcept + : node{&curr}, + ctx{&area} {} + + /** + * @brief Returns the type info object of the underlying type. + * @return The type info object of the underlying type. + */ + [[nodiscard]] const type_info &info() const noexcept { + return *fetch_node().info; + } - /** - * @brief Returns the type of the i-th argument of a data member's setter. - * @param index Index of the argument of which to return the type. - * @return The type of the i-th argument of a data member's setter. - */ - [[nodiscard]] inline meta_type set_arg(size_type index) const noexcept; + /** + * @brief Returns the identifier assigned to a type. + * @return The identifier assigned to the type. + */ + [[nodiscard]] id_type id() const noexcept { + return fetch_node().id; + } - /** - * @brief Returns the type of the i-th argument of a data member's getter. - * @param index Index of the argument of which to return the type. - * @return The type of the i-th argument of a data member's getter. - */ - [[nodiscard]] inline meta_type get_arg(size_type index) const noexcept; + /** + * @brief Returns the name assigned to a type, if any. + * @return The name assigned to the type, if any. + */ + [[nodiscard]] std::string_view name() const noexcept { + return (fetch_node().name == nullptr) ? std::string_view{} : std::string_view{fetch_node().name}; + } - /** - * @brief Returns all meta traits for a given meta object. - * @tparam Type The type to convert the meta traits to. - * @return The registered meta traits, if any. - */ - template - [[nodiscard]] Type traits() const noexcept { - return internal::meta_to_user_traits(node_or_assert().traits); - } + /** + * @brief Returns 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 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 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 Opaque wrapper for member functions. */ -struct meta_func: meta_object { - using meta_object::meta_object; + /** + * @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 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 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 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 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 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 enum or not. + * @return True if the underlying type is an enum, false otherwise. + */ + [[nodiscard]] bool is_enum() const noexcept { + return !!(fetch_node().traits & internal::meta_traits::is_enum); + } - /** - * @brief 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 a class or not. + * @return True if the underlying type is a class, false otherwise. + */ + [[nodiscard]] bool is_class() const noexcept { + return !!(fetch_node().traits & internal::meta_traits::is_class); + } - /** - * @brief 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 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 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 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 Invokes the underlying function, if possible. - * @tparam Instance Type of instance to operate on. - * @param instance An instance that fits the underlying type. - * @param args Parameters to use to invoke the function. - * @return A wrapper containing the returned value, if any. - */ - template - // NOLINTNEXTLINE(modernize-use-nodiscard) - meta_any invoke(Instance &&instance, auto &&...args) const { - return (sizeof...(args) == arity()) ? node_or_assert().invoke(meta_handle{*ctx, stl::forward(instance)}, stl::array{meta_any{*ctx, stl::forward(args)}...}.data()) : meta_any{meta_ctx_arg, *ctx}; - } + /** + * @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::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 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); + } - /*! @copydoc meta_data::custom */ - [[nodiscard]] meta_custom custom() const noexcept { - return {node_or_assert().custom}; - } + /** + * @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 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 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_handle *const args, const auto 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; ++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 + * @tparam Args Types of arguments to use to construct the instance. + * @param args Parameters to use to construct the instance. + * @return A wrapper containing the new instance, if any. + */ + template + [[nodiscard]] meta_any construct(Args &&...args) const { + return construct(std::array{meta_any{*ctx, std::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, std::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) ? std::exchange(curr, curr->next.get()) : nullptr; }); candidate) { + return candidate->invoke(std::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. + * @tparam Args Types of arguments to use to invoke the function. + * @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, Args &&...args) const { + return invoke(id, std::forward(instance), std::array{meta_any{*ctx, std::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. + * @tparam Type Type of value to assign. + * @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, Type &&value) const { + const auto candidate = data(id); + return candidate && candidate.set(std::forward(instance), std::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(std::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().id == other.fetch_node().id); + } - /** - * @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))}; + template + // NOLINTNEXTLINE(modernize-use-nodiscard) + meta_any meta_any::invoke(const id_type id, Args &&...args) const { + return type().invoke(id, *this, std::forward(args)...); } - /** - * @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); + template + meta_any meta_any::invoke(const id_type id, Args &&...args) { + return type().invoke(id, *this, std::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); + template + bool meta_any::set(const id_type id, Type &&value) { + return type().set(id, *this, std::forward(value)); } - /** - * @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); + [[nodiscard]] inline meta_any meta_any::get(const id_type id) const { + return type().get(id, *this); } - /** - * @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) { + 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::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 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{}; - } + 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 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{}; - } + 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 = std::as_const(other).allow_cast(type); from_base) { + return from_base; + } + } + } + } - /** - * @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)); + 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 = std::as_const(*this).allow_cast(type); other) { + if(other.storage.owner()) { + std::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{}; - } + 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 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{}; + return 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{}; + inline bool meta_any::assign(meta_any && other) { + return storage.assign(std::move(other.storage)) || storage.assign(std::as_const(other).allow_cast(type()).storage); } - /** - * @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{}; + [[nodiscard]] inline meta_type meta_data::type() const noexcept { + return meta_type{*ctx, node_or_assert().type(internal::meta_context::from(*ctx))}; } - /** - * @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::arg(const size_type index) const noexcept { + return index < arity() ? node_or_assert().arg(*ctx, index) : meta_type{}; } - /** - * @copybrief construct - * @param args Parameters to use to construct the instance. - * @return A wrapper containing the new instance, if any. - */ - [[nodiscard]] meta_any construct(auto &&...args) const { - if(const auto &ref = fetch_node(); ref.details) { - if(const auto *candidate = lookup(stl::array{meta_handle{*ctx, args}...}.data(), sizeof...(args), false, [first = ref.details->ctor.cbegin(), last = ref.details->ctor.cend()]() mutable { return first == last ? nullptr : &*(first++); }); candidate) { - return candidate->invoke(*ctx, stl::array{meta_any{*ctx, stl::forward(args)}...}.data()); - } - } - - if(const auto &ref = fetch_node(); (sizeof...(args) == 0u) && (ref.default_constructor != nullptr)) { - return ref.default_constructor(*ctx); - } - - return meta_any{meta_ctx_arg, *ctx}; + [[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))}; } - /** - * @copybrief invoke - * @param id Unique identifier. - * @tparam Instance Type of instance to operate on. - * @param instance An instance that fits the underlying type. - * @param args Parameters to use to invoke the function. - * @return A wrapper containing the returned value, if any. - */ - template - // NOLINTNEXTLINE(modernize-use-nodiscard) - meta_any invoke(const id_type id, Instance &&instance, auto &&...args) const { - meta_handle wrapped{*ctx, stl::forward(instance)}; - - if(const auto &ref = fetch_node(); ref.details) { - if(auto *elem = internal::find_member(ref.details->func, id); elem != nullptr) { - if(const auto *candidate = lookup(stl::array{meta_handle{*ctx, args}...}.data(), sizeof...(args), (wrapped->base().policy() == any_policy::cref), [curr = elem]() mutable { return (curr != nullptr) ? stl::exchange(curr, curr->next.get()) : nullptr; }); candidate) { - return candidate->invoke(stl::move(wrapped), stl::array{meta_any{*ctx, stl::forward(args)}...}.data()); - } - } - } + /*! @cond ENTT_INTERNAL */ + class meta_sequence_container::meta_iterator final { + using vtable_type = void(const void *, const std::ptrdiff_t, meta_any *); - for(auto &&curr: base()) { - if(auto elem = curr.second.type().invoke(id, *wrapped.operator->(), stl::forward(args)...); elem) { - return elem; - } + template + static void basic_vtable(const void *value, const std::ptrdiff_t offset, meta_any *other) { + const auto &it = *static_cast(value); + other ? other->emplace(*it) : std::advance(const_cast(it), offset); } - return meta_any{meta_ctx_arg, *ctx}; - } + public: + using value_type = meta_any; + using pointer = input_iterator_pointer; + using reference = value_type; + using difference_type = std::ptrdiff_t; + using iterator_category = std::input_iterator_tag; + using iterator_concept = std::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 args Parameters to use to set the underlying variable. - * @return True in case of success, false otherwise. - */ - template - // NOLINTNEXTLINE(modernize-use-nodiscard) - bool set(const id_type id, Instance &&instance, auto &&...args) const { - const auto candidate = data(id); - return candidate && candidate.set(stl::forward(instance), stl::forward(args)...); - } + 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. - * @param args Parameters to use to set the underlying variable, if any. - * @return A wrapper containing the value of the underlying variable. - */ - template - [[nodiscard]] meta_any get(const id_type id, Instance &&instance, auto &&...args) const { - const auto candidate = data(id); - return candidate ? candidate.get(stl::forward(instance), stl::forward(args)...) : meta_any{meta_ctx_arg, *ctx}; - } + template + meta_iterator(const meta_ctx &area, It 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 &&...args) { - return type().set(id, *this, stl::forward(args)...); -} - -[[nodiscard]] inline meta_any meta_any::get(const id_type id, auto &&...args) const { - return type().get(id, *this, stl::forward(args)...); -} - -[[nodiscard]] inline meta_any meta_any::get(const id_type id, auto &&...args) { - return type().get(id, *this, stl::forward(args)...); -} - -[[nodiscard]] inline meta_any meta_any::allow_cast(const meta_type &type) const { - if(storage.has_value(type.info())) { - return as_ref(); - } else if(*this) { - if(const auto &from = fetch_node(); (from.conversion_helper != nullptr) && (type.is_arithmetic() || type.is_enum())) { - auto other = type.construct(); - const auto value = from.conversion_helper(nullptr, storage.data()); - other.fetch_node().conversion_helper(other.storage.data(), &value); + [[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()); - } + [[nodiscard]] pointer operator->() const { + return operator*(); + } - 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]] explicit operator bool() const noexcept { + return (vtable != nullptr); } - } - return meta_any{meta_ctx_arg, *ctx}; -} + [[nodiscard]] bool operator==(const meta_iterator &other) const noexcept { + return handle == other.handle; + } -[[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]] 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 *, std::pair *); + + template + static void basic_vtable(const void *value, std::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); + } + } - return false; -} + public: + using value_type = std::pair; + using pointer = input_iterator_pointer; + using reference = value_type; + using difference_type = std::ptrdiff_t; + using iterator_category = std::input_iterator_tag; + using iterator_concept = std::forward_iterator_tag; -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); - } + meta_iterator() = default; - return true; -} + template + meta_iterator(const meta_ctx &area, std::bool_constant, It iter) noexcept + : ctx{&area}, + vtable{&basic_vtable}, + handle{iter} {} -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); -} + meta_iterator &operator++() noexcept { + return vtable(handle.data(), nullptr), *this; + } -[[nodiscard]] inline meta_type meta_data::type() const noexcept { - return meta_type{*ctx, node_or_assert().type(internal::meta_context::from(*ctx))}; -} + meta_iterator operator++(int) noexcept { + meta_iterator orig = *this; + vtable(handle.data(), nullptr); + return orig; + } -[[nodiscard]] inline meta_type meta_data::set_arg(const size_type index) const noexcept { - return index < set_arity() ? node_or_assert().set_arg(*ctx, index) : meta_type{}; -} + [[nodiscard]] reference operator*() const { + reference other{{meta_ctx_arg, *ctx}, {meta_ctx_arg, *ctx}}; + vtable(handle.data(), &other); + return other; + } -[[nodiscard]] inline meta_type meta_data::get_arg(const size_type index) const noexcept { - return index < get_arity() ? node_or_assert().get_arg(*ctx, index) : meta_type{}; -} + [[nodiscard]] pointer operator->() const { + return operator*(); + } -[[nodiscard]] inline meta_type meta_func::ret() const noexcept { - return meta_type{*ctx, node_or_assert().ret(internal::meta_context::from(*ctx))}; -} + [[nodiscard]] explicit operator bool() const noexcept { + return (vtable != nullptr); + } -[[nodiscard]] inline meta_type meta_func::arg(const size_type index) const noexcept { - return index < arity() ? node_or_assert().arg(*ctx, index) : meta_type{}; -} + [[nodiscard]] bool operator==(const meta_iterator &other) const noexcept { + return handle == other.handle; + } -[[nodiscard]] inline meta_type meta_base::type() const noexcept { - return meta_type{*ctx, node_or_assert().type(internal::meta_context::from(*ctx))}; -} + private: + const meta_ctx *ctx{}; + vtable_type *vtable{}; + any handle{}; + }; -/*! @cond ENTT_INTERNAL */ -class meta_sequence_container::meta_iterator final { - using vtable_type = void(const void *, const stl::ptrdiff_t, meta_any *); + /*! @endcond */ - 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); + /** + * @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{}; } -public: - using value_type = meta_any; - using pointer = input_iterator_pointer; - using reference = value_type; - using difference_type = stl::ptrdiff_t; - using iterator_category = stl::input_iterator_tag; - using iterator_concept = stl::bidirectional_iterator_tag; - - meta_iterator() = default; - - meta_iterator(const meta_ctx &area, stl::bidirectional_iterator auto iter) noexcept - : ctx{&area}, - vtable{&basic_vtable}, - handle{iter} {} - - meta_iterator &operator++() noexcept { - return vtable(handle.data(), 1, nullptr), *this; + /** + * @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++(int value) noexcept { - meta_iterator orig = *this; - vtable(handle.data(), ++value, nullptr); - return orig; + /** + * @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--() noexcept { - return vtable(handle.data(), -1, nullptr), *this; + /** + * @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)); } - meta_iterator operator--(int value) noexcept { - meta_iterator orig = *this; - vtable(handle.data(), --value, nullptr); - return orig; + /** + * @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]] reference operator*() const { - reference other{meta_ctx_arg, *ctx}; - vtable(handle.data(), 0, &other); - return other; + /** + * @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]] pointer operator->() const { - return operator*(); + /** + * @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]] explicit operator bool() const noexcept { - return (vtable != nullptr); - } + /** + * @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 std::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); + } - [[nodiscard]] bool operator==(const meta_iterator &other) const noexcept { - return handle == other.handle; + 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 8b35546189..5db6a143ae 100644 --- a/src/entt/meta/node.hpp +++ b/src/entt/meta/node.hpp @@ -1,32 +1,36 @@ #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 { /*! @cond ENTT_INTERNAL */ namespace internal { -enum class meta_traits : stl::uint32_t { +enum class meta_traits : std::uint32_t { is_none = 0x0000, is_const = 0x0001, is_static = 0x0002, @@ -45,18 +49,18 @@ enum class meta_traits : stl::uint32_t { }; template -requires stl::is_enum_v +requires std::is_enum_v [[nodiscard]] auto meta_to_user_traits(const meta_traits traits) noexcept { - constexpr auto shift = stl::popcount(static_cast>(meta_traits::_user_defined_traits)); - return Type{static_cast>(static_cast>(traits) >> shift)}; + constexpr auto shift = std::popcount(static_cast>(meta_traits::_user_defined_traits)); + return Type{static_cast>(static_cast>(traits) >> shift)}; } template -requires stl::is_enum_v +requires std::is_enum_v [[nodiscard]] auto user_to_meta_traits(const Type value) noexcept { - constexpr auto shift = stl::popcount(static_cast>(meta_traits::_user_defined_traits)); - const auto traits = static_cast>(static_cast>(value)); - ENTT_ASSERT(traits < ((~static_cast>(meta_traits::_user_defined_traits)) >> shift), "Invalid traits"); + constexpr auto shift = std::popcount(static_cast>(meta_traits::_user_defined_traits)); + const auto traits = static_cast>(static_cast>(value)); + ENTT_ASSERT(traits < ((~static_cast>(meta_traits::_user_defined_traits)) >> shift), "Invalid traits"); return meta_traits{traits << shift}; } @@ -64,7 +68,7 @@ struct meta_type_node; struct meta_custom_node { id_type id{}; - stl::shared_ptr value{}; + std::shared_ptr value{}; }; struct meta_base_node { @@ -79,7 +83,7 @@ struct meta_conv_node { }; struct meta_ctor_node { - using size_type = stl::size_t; + using size_type = std::size_t; id_type id{}; size_type arity{0u}; @@ -88,23 +92,21 @@ struct meta_ctor_node { }; struct meta_data_node { - using size_type = stl::size_t; + using size_type = std::size_t; id_type id{}; const char *name{}; meta_traits traits{meta_traits::is_none}; - size_type set_arity{0u}; - size_type get_arity{0u}; - meta_type (*set_arg)(const meta_ctx &, const size_type) noexcept {}; - meta_type (*get_arg)(const meta_ctx &, const size_type) noexcept {}; + size_type arity{0u}; const meta_type_node &(*type)(const meta_context &) noexcept {}; - bool (*set)(meta_handle, meta_any *const){}; - meta_any (*get)(meta_handle, meta_any *const){}; + meta_type (*arg)(const meta_ctx &, const size_type) noexcept {}; + bool (*set)(meta_handle, meta_any){}; + meta_any (*get)(meta_handle){}; meta_custom_node custom{}; }; struct meta_func_node { - using size_type = stl::size_t; + using size_type = std::size_t; id_type id{}; const char *name{}; @@ -113,12 +115,12 @@ struct meta_func_node { const meta_type_node &(*ret)(const meta_context &) noexcept {}; meta_type (*arg)(const meta_ctx &, const size_type) noexcept {}; meta_any (*invoke)(meta_handle, meta_any *const){}; - stl::unique_ptr next; + std::unique_ptr next; meta_custom_node custom{}; }; struct meta_template_node { - using size_type = stl::size_t; + using size_type = std::size_t; size_type arity{0u}; const meta_type_node &(*resolve)(const meta_context &) noexcept {}; @@ -126,18 +128,18 @@ struct meta_template_node { }; struct meta_type_descriptor { - stl::vector ctor{}; - stl::vector base{}; - stl::vector conv{}; - stl::vector data{}; - stl::vector func{}; + std::vector ctor{}; + std::vector base{}; + std::vector conv{}; + std::vector data{}; + std::vector func{}; }; struct meta_type_node { - using size_type = stl::size_t; + using size_type = std::size_t; const type_info *info{}; - id_type alias{}; + id_type id{}; const char *name{}; meta_traits traits{meta_traits::is_none}; size_type size_of{0u}; @@ -147,7 +149,7 @@ struct meta_type_node { meta_any (*from_void)(const meta_ctx &, void *, const void *){}; meta_template_node templ{}; meta_custom_node custom{}; - stl::unique_ptr details{}; + std::unique_ptr details{}; }; template @@ -161,14 +163,14 @@ template return static_cast(nullptr); } -[[nodiscard]] inline auto *find_overload(meta_func_node *curr, stl::remove_pointer_t *const ref) { +[[nodiscard]] inline auto *find_overload(meta_func_node *curr, std::remove_pointer_t *const ref) { while((curr != nullptr) && (curr->invoke != ref)) { curr = curr->next.get(); } return curr; } template [[nodiscard]] auto *look_for(const meta_context &context, const meta_type_node &node, const id_type id, bool recursive) { - using value_type = stl::remove_reference_t*Member))>::value_type; + using value_type = std::remove_reference_t*Member))>::value_type; if(node.details) { if(auto *member = find_member((node.details.get()->*Member), id); member != nullptr) { @@ -191,9 +193,9 @@ template const meta_type_node &resolve(const meta_context &) noexcept; template -[[nodiscard]] const meta_type_node &meta_arg_node(const meta_context &context, type_list, const stl::size_t index) noexcept { +[[nodiscard]] const meta_type_node &meta_arg_node(const meta_context &context, type_list, const std::size_t index) noexcept { using resolve_type = const meta_type_node &(*)(const meta_context &) noexcept; - constexpr stl::array list{&resolve>...}; + constexpr std::array list{&resolve>...}; ENTT_ASSERT(index < sizeof...(Args), "Out of bounds"); return list[index](context); } @@ -218,47 +220,47 @@ auto setup_node_for() noexcept { &type_id(), type_id().hash(), nullptr, - (stl::is_arithmetic_v ? meta_traits::is_arithmetic : meta_traits::is_none) - | (stl::is_integral_v ? meta_traits::is_integral : meta_traits::is_none) - | (stl::is_signed_v ? meta_traits::is_signed : meta_traits::is_none) - | (stl::is_array_v ? meta_traits::is_array : meta_traits::is_none) - | (stl::is_enum_v ? meta_traits::is_enum : meta_traits::is_none) - | (stl::is_class_v ? meta_traits::is_class : meta_traits::is_none) - | (stl::is_pointer_v ? meta_traits::is_pointer : meta_traits::is_none) + (std::is_arithmetic_v ? meta_traits::is_arithmetic : meta_traits::is_none) + | (std::is_integral_v ? meta_traits::is_integral : meta_traits::is_none) + | (std::is_signed_v ? meta_traits::is_signed : meta_traits::is_none) + | (std::is_array_v ? meta_traits::is_array : meta_traits::is_none) + | (std::is_enum_v ? meta_traits::is_enum : meta_traits::is_none) + | (std::is_class_v ? meta_traits::is_class : meta_traits::is_none) + | (std::is_pointer_v ? meta_traits::is_pointer : meta_traits::is_none) | (is_meta_pointer_like_v ? meta_traits::is_pointer_like : meta_traits::is_none) | (is_complete_v> ? meta_traits::is_sequence_container : meta_traits::is_none) | (is_complete_v> ? meta_traits::is_associative_container : meta_traits::is_none), size_of_v, - &resolve>>}; + &resolve>>}; - if constexpr(stl::is_default_constructible_v) { + if constexpr(std::is_default_constructible_v) { node.default_constructor = +[](const meta_ctx &ctx) { - return meta_any{ctx, stl::in_place_type}; + return meta_any{ctx, std::in_place_type}; }; } - if constexpr(stl::is_arithmetic_v) { + if constexpr(std::is_arithmetic_v) { node.conversion_helper = +[](void *lhs, const void *rhs) { return lhs ? static_cast(*static_cast(lhs) = static_cast(*static_cast(rhs))) : static_cast(*static_cast(rhs)); }; - } else if constexpr(stl::is_enum_v) { + } else if constexpr(std::is_enum_v) { node.conversion_helper = +[](void *lhs, const void *rhs) { - return lhs ? static_cast(*static_cast(lhs) = static_cast(static_cast>(*static_cast(rhs)))) : static_cast(*static_cast(rhs)); + return lhs ? static_cast(*static_cast(lhs) = static_cast(static_cast>(*static_cast(rhs)))) : static_cast(*static_cast(rhs)); }; } - if constexpr(!stl::is_void_v && !stl::is_function_v) { + if constexpr(!std::is_void_v && !std::is_function_v) { node.from_void = +[](const meta_ctx &ctx, void *elem, const void *celem) { if(elem && celem) { // ownership construction request - return meta_any{ctx, stl::in_place, static_cast *>(elem)}; + return meta_any{ctx, std::in_place, static_cast *>(elem)}; } if(elem) { // non-const reference construction request - return meta_any{ctx, stl::in_place_type &>, *static_cast *>(elem)}; + return meta_any{ctx, std::in_place_type &>, *static_cast *>(elem)}; } // const reference construction request - return meta_any{ctx, stl::in_place_type &>, *static_cast *>(celem)}; + return meta_any{ctx, std::in_place_type &>, *static_cast *>(celem)}; }; } @@ -266,17 +268,22 @@ auto setup_node_for() noexcept { node.templ = meta_template_node{ meta_template_traits::args_type::size, &resolve::class_type>, - +[](const meta_context &area, const stl::size_t index) noexcept -> decltype(auto) { return meta_arg_node(area, typename meta_template_traits::args_type{}, index); }}; + +[](const meta_context &area, const std::size_t index) noexcept -> decltype(auto) { return meta_arg_node(area, typename meta_template_traits::args_type{}, index); }}; } return node; } +[[nodiscard]] inline const meta_type_node *try_resolve(const meta_context &context, const type_info &info) noexcept { + const auto it = context.bucket.find(info.hash()); + return (it != context.bucket.end()) ? it->second.get() : nullptr; +} + template [[nodiscard]] const meta_type_node &resolve(const meta_context &context) noexcept { static const meta_type_node node = setup_node_for(); - const auto it = context.bucket.find(node.info->hash()); - return (it == context.bucket.cend()) ? node : *it->second; + const auto *elem = try_resolve(context, *node.info); + return (elem == nullptr) ? node : *elem; } } // namespace internal 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..3d1b8e4681 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 { @@ -71,7 +75,7 @@ struct meta_range_iterator final { } [[nodiscard]] constexpr reference operator[](const difference_type value) const noexcept { - if constexpr(stl::is_same_v) { + if constexpr(stl::is_same_v) { return {it[value].first, Type{*ctx, *it[value].second}}; } else { return {it[value].id, Type{*ctx, it[value]}}; @@ -103,9 +107,50 @@ 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 */ +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 +159,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..5be3659d70 100644 --- a/src/entt/meta/resolve.hpp +++ b/src/entt/meta/resolve.hpp @@ -1,108 +1,104 @@ #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)}; -} - -/** - * @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()}}; -} +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 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 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 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 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()}}; + } - // 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}; + /** + * @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()); } - for(auto &&curr: context.bucket) { - if(curr.second->alias == alias) { - return meta_type{ctx, *curr.second}; + /** + * @brief Returns the meta type associated with a given identifier, if any. + * @param ctx The context from which to search for meta types. + * @param id 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 id) noexcept { + for(auto &&curr: resolve(ctx)) { + if(curr.second.id() == id) { + return 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 id Unique identifier. + * @return The meta type associated with the given identifier, if any. + */ + [[nodiscard]] inline meta_type resolve(const id_type id) noexcept { + return resolve(locator::value_or(), id); + } -/** - * @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 *elem = internal::try_resolve(context, info); + return (elem != nullptr) ? meta_type{ctx, *elem} : meta_type{}; + } -/** - * @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 ea5b01e5ea..461cbfa805 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. @@ -495,6 +507,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..805aea6b84 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 { @@ -26,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>; @@ -113,9 +117,50 @@ 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 */ +ENTT_MODULE_EXPORT_BEGIN + /** * @brief Basic cache for resources of any type. * @tparam Type Type of resources managed by a cache. @@ -381,6 +426,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 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;