diff --git a/include/libimp/detect_plat.h b/include/libimp/detect_plat.h index a38dac2..26e8c18 100644 --- a/include/libimp/detect_plat.h +++ b/include/libimp/detect_plat.h @@ -42,6 +42,7 @@ # define LIBIMP_CC_MSVC_2015 1900 # define LIBIMP_CC_MSVC_2017 1910 # define LIBIMP_CC_MSVC_2019 1920 +# define LIBIMP_CC_MSVC_2022 1930 #elif defined(__GNUC__) # define LIBIMP_CC_GNUC __GNUC__ # if defined(__clang__) diff --git a/include/libpmr/new.h b/include/libpmr/new.h index bcf0c8c..46e3b93 100644 --- a/include/libpmr/new.h +++ b/include/libpmr/new.h @@ -25,7 +25,7 @@ LIBPMR_NAMESPACE_BEG_ class LIBIMP_EXPORT block_collector { public: virtual ~block_collector() noexcept = default; - virtual void deallocate(void *p) noexcept = 0; + virtual void recycle(void *p, std::size_t bytes, std::size_t alignment) noexcept = 0; }; using get_block_collector_t = block_collector *(*)() noexcept; @@ -60,15 +60,41 @@ constexpr inline std::size_t regular_sizeof() noexcept { return regular_sizeof_impl(regular_head_size + sizeof(T)); } +/// \brief Use block pools to handle memory less than 64K. +template +class block_resource_base : public block_pool { +public: + void *allocate(std::size_t /*bytes*/, std::size_t /*alignment*/) noexcept { + return block_pool::allocate(); + } + + void deallocate(void *p, std::size_t /*bytes*/, std::size_t /*alignment*/) noexcept { + block_pool::deallocate(p); + } +}; + +/// \brief Use `new`/`delete` to handle memory larger than 64K. +template +class block_resource_base : public new_delete_resource { +public: + void *allocate(std::size_t bytes, std::size_t alignment) noexcept { + return new_delete_resource::allocate(regular_head_size + bytes, alignment); + } + + void deallocate(void *p, std::size_t bytes, std::size_t alignment) noexcept { + new_delete_resource::deallocate(p, regular_head_size + bytes, alignment); + } +}; + /// \brief Defines block pool memory resource based on block pool. template -class block_pool_resource : public block_pool +class block_pool_resource : public block_resource_base , public block_collector { - using base_t = block_pool; + using base_t = block_resource_base; - void deallocate(void *p) noexcept override { - base_t::deallocate(p); + void recycle(void *p, std::size_t bytes, std::size_t alignment) noexcept override { + base_t::deallocate(p, bytes, alignment); } public: @@ -77,22 +103,20 @@ public: return &instance; } - using base_t::base_t; - - void *allocate(std::size_t /*bytes*/, std::size_t /*alignment*/ = alignof(std::max_align_t)) noexcept { - void *p = base_t::allocate(); + void *allocate(std::size_t bytes, std::size_t alignment = alignof(std::max_align_t)) noexcept { + void *p = base_t::allocate(bytes, alignment); *static_cast(p) = get; return static_cast<::LIBIMP::byte *>(p) + regular_head_size; } - void deallocate(void *p, std::size_t /*bytes*/, std::size_t /*alignment*/ = alignof(std::max_align_t)) noexcept { + void deallocate(void *p, std::size_t bytes, std::size_t alignment = alignof(std::max_align_t)) noexcept { p = static_cast<::LIBIMP::byte *>(p) - regular_head_size; auto g = *static_cast(p); if (g == get) { - base_t::deallocate(p); + base_t::deallocate(p, bytes, alignment); return; } - g()->deallocate(p); + g()->recycle(p, bytes, alignment); } }; @@ -115,9 +139,6 @@ struct regular_resource { } }; -template -struct regular_resource : new_delete_resource {}; - /// \brief Creates an object based on the specified type and parameters with block pool resource. /// \note This function is thread-safe. template @@ -136,11 +157,11 @@ void delete$(T *p) noexcept { ::LIBIMP::destroy(p); auto *res = regular_resource()>::get(); if (res == nullptr) return; -#if defined(LIBIMP_CC_MSVC_2015) +#if (LIBIMP_CC_MSVC > LIBIMP_CC_MSVC_2015) + res->deallocate(p, sizeof(T), alignof(T)); +#else // `alignof` of vs2015 requires that type must be able to be instantiated. res->deallocate(p, sizeof(T)); -#else - res->deallocate(p, sizeof(T), alignof(T)); #endif } diff --git a/test/pmr/test_pmr_new.cpp b/test/pmr/test_pmr_new.cpp index 5a2ba3e..dc8f569 100644 --- a/test/pmr/test_pmr_new.cpp +++ b/test/pmr/test_pmr_new.cpp @@ -93,6 +93,14 @@ private: int value_; }; +class Derived64K : public Derived { +public: + using Derived::Derived; + +private: + std::array padding_; +}; + } // namespace TEST(pmr_new, delete$poly) { @@ -110,6 +118,21 @@ TEST(pmr_new, delete$poly) { ASSERT_EQ(construct_count__, 0); } +TEST(pmr_new, delete$poly64k) { + Base *p = pmr::new$(-1); + ASSERT_NE(p, nullptr); + ASSERT_EQ(p->get(), -1); + ASSERT_EQ(construct_count__, -1); + pmr::delete$(p); + ASSERT_EQ(construct_count__, 0); + + Base *q = pmr::new$((std::numeric_limits::max)()); + ASSERT_EQ(q->get(), (std::numeric_limits::max)()); + ASSERT_EQ(construct_count__, (std::numeric_limits::max)()); + pmr::delete$(q); + ASSERT_EQ(construct_count__, 0); +} + TEST(pmr_new, delete$null) { Base *p = nullptr; pmr::delete$(p);