diff options
Diffstat (limited to 'deps/include/entt/core/memory.hpp')
| -rw-r--r-- | deps/include/entt/core/memory.hpp | 244 |
1 files changed, 244 insertions, 0 deletions
diff --git a/deps/include/entt/core/memory.hpp b/deps/include/entt/core/memory.hpp new file mode 100644 index 0000000..58fda45 --- /dev/null +++ b/deps/include/entt/core/memory.hpp @@ -0,0 +1,244 @@ +#ifndef ENTT_CORE_MEMORY_HPP
+#define ENTT_CORE_MEMORY_HPP
+
+#include <cstddef>
+#include <memory>
+#include <tuple>
+#include <type_traits>
+#include <utility>
+#include "../config/config.h"
+
+namespace entt {
+
+/**
+ * @brief Unwraps fancy pointers, does nothing otherwise (waiting for C++20).
+ * @tparam Type Pointer type.
+ * @param ptr Fancy or raw pointer.
+ * @return A raw pointer that represents the address of the original pointer.
+ */
+template<typename Type>
+[[nodiscard]] constexpr auto to_address(Type &&ptr) noexcept {
+ if constexpr(std::is_pointer_v<std::decay_t<Type>>) {
+ return ptr;
+ } else {
+ return to_address(std::forward<Type>(ptr).operator->());
+ }
+}
+
+/**
+ * @brief Utility function to design allocation-aware containers.
+ * @tparam Allocator Type of allocator.
+ * @param lhs A valid allocator.
+ * @param rhs Another valid allocator.
+ */
+template<typename Allocator>
+constexpr void propagate_on_container_copy_assignment([[maybe_unused]] Allocator &lhs, [[maybe_unused]] Allocator &rhs) noexcept {
+ if constexpr(std::allocator_traits<Allocator>::propagate_on_container_copy_assignment::value) {
+ lhs = rhs;
+ }
+}
+
+/**
+ * @brief Utility function to design allocation-aware containers.
+ * @tparam Allocator Type of allocator.
+ * @param lhs A valid allocator.
+ * @param rhs Another valid allocator.
+ */
+template<typename Allocator>
+constexpr void propagate_on_container_move_assignment([[maybe_unused]] Allocator &lhs, [[maybe_unused]] Allocator &rhs) noexcept {
+ if constexpr(std::allocator_traits<Allocator>::propagate_on_container_move_assignment::value) {
+ lhs = std::move(rhs);
+ }
+}
+
+/**
+ * @brief Utility function to design allocation-aware containers.
+ * @tparam Allocator Type of allocator.
+ * @param lhs A valid allocator.
+ * @param rhs Another valid allocator.
+ */
+template<typename Allocator>
+constexpr void propagate_on_container_swap([[maybe_unused]] Allocator &lhs, [[maybe_unused]] Allocator &rhs) noexcept {
+ if constexpr(std::allocator_traits<Allocator>::propagate_on_container_swap::value) {
+ using std::swap;
+ swap(lhs, rhs);
+ } else {
+ ENTT_ASSERT_CONSTEXPR(lhs == rhs, "Cannot swap the containers");
+ }
+}
+
+/**
+ * @brief Deleter for allocator-aware unique pointers (waiting for C++20).
+ * @tparam Allocator Type of allocator used to manage memory and elements.
+ */
+template<typename Allocator>
+struct allocation_deleter: private Allocator {
+ /*! @brief Allocator type. */
+ using allocator_type = Allocator;
+ /*! @brief Pointer type. */
+ using pointer = typename std::allocator_traits<Allocator>::pointer;
+
+ /**
+ * @brief Inherited constructors.
+ * @param alloc The allocator to use.
+ */
+ constexpr allocation_deleter(const allocator_type &alloc) noexcept(std::is_nothrow_copy_constructible_v<allocator_type>)
+ : Allocator{alloc} {}
+
+ /**
+ * @brief Destroys the pointed object and deallocates its memory.
+ * @param ptr A valid pointer to an object of the given type.
+ */
+ constexpr void operator()(pointer ptr) noexcept(std::is_nothrow_destructible_v<typename allocator_type::value_type>) {
+ using alloc_traits = std::allocator_traits<Allocator>;
+ alloc_traits::destroy(*this, to_address(ptr));
+ alloc_traits::deallocate(*this, ptr, 1u);
+ }
+};
+
+/**
+ * @brief Allows `std::unique_ptr` to use allocators (waiting for C++20).
+ * @tparam Type Type of object to allocate for and to construct.
+ * @tparam Allocator Type of allocator used to manage memory and elements.
+ * @tparam Args Types of arguments to use to construct the object.
+ * @param allocator The allocator to use.
+ * @param args Parameters to use to construct the object.
+ * @return A properly initialized unique pointer with a custom deleter.
+ */
+template<typename Type, typename Allocator, typename... Args>
+ENTT_CONSTEXPR auto allocate_unique(Allocator &allocator, Args &&...args) {
+ static_assert(!std::is_array_v<Type>, "Array types are not supported");
+
+ using alloc_traits = typename std::allocator_traits<Allocator>::template rebind_traits<Type>;
+ using allocator_type = typename alloc_traits::allocator_type;
+
+ allocator_type alloc{allocator};
+ auto ptr = alloc_traits::allocate(alloc, 1u);
+
+ ENTT_TRY {
+ alloc_traits::construct(alloc, to_address(ptr), std::forward<Args>(args)...);
+ }
+ ENTT_CATCH {
+ alloc_traits::deallocate(alloc, ptr, 1u);
+ ENTT_THROW;
+ }
+
+ return std::unique_ptr<Type, allocation_deleter<allocator_type>>{ptr, alloc};
+}
+
+/*! @cond TURN_OFF_DOXYGEN */
+namespace internal {
+
+template<typename Type>
+struct uses_allocator_construction {
+ template<typename Allocator, typename... Params>
+ static constexpr auto args([[maybe_unused]] const Allocator &allocator, Params &&...params) noexcept {
+ if constexpr(!std::uses_allocator_v<Type, Allocator> && std::is_constructible_v<Type, Params...>) {
+ return std::forward_as_tuple(std::forward<Params>(params)...);
+ } else {
+ static_assert(std::uses_allocator_v<Type, Allocator>, "Ill-formed request");
+
+ if constexpr(std::is_constructible_v<Type, std::allocator_arg_t, const Allocator &, Params...>) {
+ return std::tuple<std::allocator_arg_t, const Allocator &, Params &&...>{std::allocator_arg, allocator, std::forward<Params>(params)...};
+ } else {
+ static_assert(std::is_constructible_v<Type, Params..., const Allocator &>, "Ill-formed request");
+ return std::forward_as_tuple(std::forward<Params>(params)..., allocator);
+ }
+ }
+ }
+};
+
+template<typename Type, typename Other>
+struct uses_allocator_construction<std::pair<Type, Other>> {
+ using type = std::pair<Type, Other>;
+
+ template<typename Allocator, typename First, typename Second>
+ static constexpr auto args(const Allocator &allocator, std::piecewise_construct_t, First &&first, Second &&second) noexcept {
+ return std::make_tuple(
+ std::piecewise_construct,
+ std::apply([&allocator](auto &&...curr) { return uses_allocator_construction<Type>::args(allocator, std::forward<decltype(curr)>(curr)...); }, std::forward<First>(first)),
+ std::apply([&allocator](auto &&...curr) { return uses_allocator_construction<Other>::args(allocator, std::forward<decltype(curr)>(curr)...); }, std::forward<Second>(second)));
+ }
+
+ template<typename Allocator>
+ static constexpr auto args(const Allocator &allocator) noexcept {
+ return uses_allocator_construction<type>::args(allocator, std::piecewise_construct, std::tuple<>{}, std::tuple<>{});
+ }
+
+ template<typename Allocator, typename First, typename Second>
+ static constexpr auto args(const Allocator &allocator, First &&first, Second &&second) noexcept {
+ return uses_allocator_construction<type>::args(allocator, std::piecewise_construct, std::forward_as_tuple(std::forward<First>(first)), std::forward_as_tuple(std::forward<Second>(second)));
+ }
+
+ template<typename Allocator, typename First, typename Second>
+ static constexpr auto args(const Allocator &allocator, const std::pair<First, Second> &value) noexcept {
+ return uses_allocator_construction<type>::args(allocator, std::piecewise_construct, std::forward_as_tuple(value.first), std::forward_as_tuple(value.second));
+ }
+
+ template<typename Allocator, typename First, typename Second>
+ static constexpr auto args(const Allocator &allocator, std::pair<First, Second> &&value) noexcept {
+ return uses_allocator_construction<type>::args(allocator, std::piecewise_construct, std::forward_as_tuple(std::move(value.first)), std::forward_as_tuple(std::move(value.second)));
+ }
+};
+
+} // namespace internal
+/*! @endcond */
+
+/**
+ * @brief Uses-allocator construction utility (waiting for C++20).
+ *
+ * Primarily intended for internal use. Prepares the argument list needed to
+ * create an object of a given type by means of uses-allocator construction.
+ *
+ * @tparam Type Type to return arguments for.
+ * @tparam Allocator Type of allocator used to manage memory and elements.
+ * @tparam Args Types of arguments to use to construct the object.
+ * @param allocator The allocator to use.
+ * @param args Parameters to use to construct the object.
+ * @return The arguments needed to create an object of the given type.
+ */
+template<typename Type, typename Allocator, typename... Args>
+constexpr auto uses_allocator_construction_args(const Allocator &allocator, Args &&...args) noexcept {
+ return internal::uses_allocator_construction<Type>::args(allocator, std::forward<Args>(args)...);
+}
+
+/**
+ * @brief Uses-allocator construction utility (waiting for C++20).
+ *
+ * Primarily intended for internal use. Creates an object of a given type by
+ * means of uses-allocator construction.
+ *
+ * @tparam Type Type of object to create.
+ * @tparam Allocator Type of allocator used to manage memory and elements.
+ * @tparam Args Types of arguments to use to construct the object.
+ * @param allocator The allocator to use.
+ * @param args Parameters to use to construct the object.
+ * @return A newly created object of the given type.
+ */
+template<typename Type, typename Allocator, typename... Args>
+constexpr Type make_obj_using_allocator(const Allocator &allocator, Args &&...args) {
+ return std::make_from_tuple<Type>(internal::uses_allocator_construction<Type>::args(allocator, std::forward<Args>(args)...));
+}
+
+/**
+ * @brief Uses-allocator construction utility (waiting for C++20).
+ *
+ * Primarily intended for internal use. Creates an object of a given type by
+ * means of uses-allocator construction at an uninitialized memory location.
+ *
+ * @tparam Type Type of object to create.
+ * @tparam Allocator Type of allocator used to manage memory and elements.
+ * @tparam Args Types of arguments to use to construct the object.
+ * @param value Memory location in which to place the object.
+ * @param allocator The allocator to use.
+ * @param args Parameters to use to construct the object.
+ * @return A pointer to the newly created object of the given type.
+ */
+template<typename Type, typename Allocator, typename... Args>
+constexpr Type *uninitialized_construct_using_allocator(Type *value, const Allocator &allocator, Args &&...args) {
+ return std::apply([value](auto &&...curr) { return ::new(value) Type(std::forward<decltype(curr)>(curr)...); }, internal::uses_allocator_construction<Type>::args(allocator, std::forward<Args>(args)...));
+}
+
+} // namespace entt
+
+#endif
|
