From 5bdd774fa1d8ffbfdc5f5d98eb7f09a1a19f5017 Mon Sep 17 00:00:00 2001 From: Jody Hagins Date: Thu, 28 Aug 2025 19:48:55 -0400 Subject: [PATCH] Have use_allocate_node also check alignment For the segregator, it checks the size of the allocation. However, some allocators (I'm looking at you, memory_pool_collection_allocator) throw if the requested alignment is too big. However, the segregator could have a fallback allocator that supports the larger alignment. If we just made a hard change, this could break existing code. Thus, another parameter can be passed to the threshold constructor that can enable alignment checking. It is a strong type so there should be no inconvenient implicit conversions and in order to get the new behavior, it will have to be explicitly requested. --- include/foonathan/memory/segregator.hpp | 42 ++++++++++++++++++++++--- test/segregator.cpp | 15 +++++++++ 2 files changed, 52 insertions(+), 5 deletions(-) diff --git a/include/foonathan/memory/segregator.hpp b/include/foonathan/memory/segregator.hpp index 101b82a..88e1661 100644 --- a/include/foonathan/memory/segregator.hpp +++ b/include/foonathan/memory/segregator.hpp @@ -17,6 +17,12 @@ namespace foonathan { namespace memory { + enum class ThresholdAlignment : std::size_t + { + None, // No alignment limit + AllocatorMax // Use allocator's max_alignment + }; + /// A \concept{concept_segregatable,Segregatable} that allocates until a maximum size. /// \ingroup adapter template @@ -29,24 +35,39 @@ namespace foonathan /// and the allocator it uses. explicit threshold_segregatable(std::size_t max_size, allocator_type alloc = allocator_type()) - : allocator_type(detail::move(alloc)), max_size_(max_size) + : allocator_type(detail::move(alloc)), + max_size_(max_size), + max_alignment_(static_cast(-1)) + { + } + + /// \effects Creates it by passing the maximum size and alignment it will allocate, + /// and the allocator it uses. + explicit threshold_segregatable(std::size_t max_size, ThresholdAlignment alignment, + allocator_type alloc = allocator_type()) + : allocator_type(detail::move(alloc)), + max_size_(max_size), + max_alignment_(alignment == ThresholdAlignment::AllocatorMax ? + allocator_traits::max_alignment(get_allocator()) : + static_cast(-1)) { } /// \returns `true` if `size` is less then or equal to the maximum size, /// `false` otherwise. /// \note A return value of `true` means that the allocator will be used for the allocation. - bool use_allocate_node(std::size_t size, std::size_t) noexcept + bool use_allocate_node(std::size_t size, std::size_t alignment) noexcept { - return size <= max_size_; + return size <= max_size_ && alignment <= max_alignment_; } /// \returns `true` if `count * size` is less then or equal to the maximum size, /// `false` otherwise. /// \note A return value of `true` means that the allocator will be used for the allocation. - bool use_allocate_array(std::size_t count, std::size_t size, std::size_t) noexcept + bool use_allocate_array(std::size_t count, std::size_t size, + std::size_t alignment) noexcept { - return count * size <= max_size_; + return count * size <= max_size_ && alignment <= max_alignment_; } /// @{ @@ -64,6 +85,7 @@ namespace foonathan private: std::size_t max_size_; + std::size_t max_alignment_; }; /// \returns A \ref threshold_segregatable with the same parameter. @@ -76,6 +98,16 @@ namespace foonathan std::forward(alloc)); } + /// \returns A \ref threshold_segregatable with the same parameter. + template + threshold_segregatable::type> threshold( + std::size_t max_size, ThresholdAlignment alignment, RawAllocator&& alloc) + { + return threshold_segregatable< + typename std::decay::type>(max_size, alignment, + std::forward(alloc)); + } + /// A composable \concept{concept_rawallocator,RawAllocator} that will always fail. /// This is useful for compositioning or as last resort in \ref binary_segregator. /// \ingroup allocator diff --git a/test/segregator.cpp b/test/segregator.cpp index 1d9fffe..7bdc092 100644 --- a/test/segregator.cpp +++ b/test/segregator.cpp @@ -25,6 +25,21 @@ TEST_CASE("threshold_segregatable") REQUIRE(s.use_allocate_array(2u, 4u, 1u)); REQUIRE(!s.use_allocate_array(2u, 8u, 1u)); REQUIRE(!s.use_allocate_array(1u, 9u, 1u)); + REQUIRE(s.use_allocate_array(1u, 1u, 64u)); + + s = segregatable(8u, ThresholdAlignment::AllocatorMax); + REQUIRE(s.use_allocate_node(1u, 1u)); + REQUIRE(s.use_allocate_node(8u, 1u)); + REQUIRE(!s.use_allocate_node(8u, 100u)); + REQUIRE(!s.use_allocate_node(9u, 1u)); + REQUIRE(!s.use_allocate_node(9u, 100u)); + + REQUIRE(s.use_allocate_array(1u, 1u, 1u)); + REQUIRE(s.use_allocate_array(1u, 8u, 1u)); + REQUIRE(s.use_allocate_array(2u, 4u, 1u)); + REQUIRE(!s.use_allocate_array(2u, 8u, 1u)); + REQUIRE(!s.use_allocate_array(1u, 9u, 1u)); + REQUIRE(!s.use_allocate_array(1u, 1u, 64u)); } TEST_CASE("binary_segregator")