From eee15dda027b0081e613eaef7839e1a8f7c20477 Mon Sep 17 00:00:00 2001 From: mutouyun Date: Sun, 17 Sep 2023 16:59:32 +0800 Subject: [PATCH] Add unit tests for `monotonic_buffer_resource`. --- include/libpmr/memory_resource.h | 4 +- src/libpmr/monotonic_buffer_resource.cpp | 13 +- .../test_pmr_monotonic_buffer_resource.cpp | 125 ++++++++++++++++++ 3 files changed, 139 insertions(+), 3 deletions(-) diff --git a/include/libpmr/memory_resource.h b/include/libpmr/memory_resource.h index 8ec6c9e..be30853 100644 --- a/include/libpmr/memory_resource.h +++ b/include/libpmr/memory_resource.h @@ -22,7 +22,8 @@ struct has_allocate : std::false_type {}; template struct has_allocate().allocate(std::declval())), void * + decltype(std::declval().allocate(std::declval(), + std::declval())), void * >::value>::type> : std::true_type {}; template @@ -31,6 +32,7 @@ struct has_deallocate : std::false_type {}; template struct has_deallocate().deallocate(std::declval(), + std::declval(), std::declval())) > : std::true_type {}; diff --git a/src/libpmr/monotonic_buffer_resource.cpp b/src/libpmr/monotonic_buffer_resource.cpp index 195aa86..7f2efdd 100644 --- a/src/libpmr/monotonic_buffer_resource.cpp +++ b/src/libpmr/monotonic_buffer_resource.cpp @@ -17,7 +17,8 @@ Node *make_node(allocator const &upstream, std::size_t initial_size, std::size_t auto sz = ::LIBIMP::round_up(sizeof(Node), alignment) + initial_size; auto *node = static_cast(upstream.allocate(sz)); if (node == nullptr) { - log.error("failed: allocate memory for `monotonic_buffer_resource`."); + log.error("failed: allocate memory for `monotonic_buffer_resource`'s node.", + " bytes = ", initial_size, ", alignment = ", alignment); return nullptr; } node->next = nullptr; @@ -104,7 +105,15 @@ void *monotonic_buffer_resource::allocate(std::size_t bytes, std::size_t alignme node->next = free_list_; free_list_ = node; next_size_ = next_buffer_size(next_size_); - p = reinterpret_cast<::LIBIMP::byte *>(free_list_) + ::LIBIMP::round_up(sizeof(node), alignment); + // try again + s = node->size - sizeof(monotonic_buffer_resource::node); + p = std::align(alignment, bytes, (p = node + 1), s); + if (p == nullptr) { + log.error("failed: allocate memory for `monotonic_buffer_resource`.", + " bytes = ", bytes, ", alignment = ", alignment); + return nullptr; + } + tail_ = static_cast<::LIBIMP::byte *>(p) + s; } head_ = static_cast<::LIBIMP::byte *>(p) + bytes; return p; diff --git a/test/pmr/test_pmr_monotonic_buffer_resource.cpp b/test/pmr/test_pmr_monotonic_buffer_resource.cpp index 1774519..3a14709 100644 --- a/test/pmr/test_pmr_monotonic_buffer_resource.cpp +++ b/test/pmr/test_pmr_monotonic_buffer_resource.cpp @@ -1,4 +1,8 @@ +#include +#include +#include + #include "gtest/gtest.h" #include "libpmr/monotonic_buffer_resource.h" @@ -13,3 +17,124 @@ TEST(monotonic_buffer_resource, construct) { pmr::monotonic_buffer_resource{imp::span{}, pmr::allocator{}}; SUCCEED(); } + +TEST(monotonic_buffer_resource, no_copy) { + EXPECT_FALSE(std::is_copy_constructible::value); + EXPECT_FALSE(std::is_copy_assignable::value); + EXPECT_FALSE(std::is_move_constructible::value); + EXPECT_FALSE(std::is_move_assignable::value); +} + +TEST(monotonic_buffer_resource, upstream_resource) { + struct dummy_allocator { + bool allocated = false; + void *allocate(std::size_t, std::size_t) noexcept { allocated = true; return nullptr; } + void deallocate(void *, std::size_t, std::size_t) noexcept {} + } dummy; + pmr::monotonic_buffer_resource tmp{&dummy}; + ASSERT_EQ(tmp.upstream_resource().allocate(1), nullptr); + ASSERT_TRUE(dummy.allocated); +} + +namespace { + +struct dummy_allocator { + std::size_t allocated = 0; + void *allocate(std::size_t size, std::size_t) noexcept { + allocated += size; + return std::malloc(size); + } + void deallocate(void *p, std::size_t size, std::size_t) noexcept { + allocated -= size; + std::free(p); + } +}; + +} // namespace + +TEST(monotonic_buffer_resource, allocate) { + dummy_allocator dummy; + { + pmr::monotonic_buffer_resource tmp{&dummy}; + ASSERT_EQ(tmp.allocate(0), nullptr); + ASSERT_EQ(dummy.allocated, 0); + } + ASSERT_EQ(dummy.allocated, 0); + { + pmr::monotonic_buffer_resource tmp{&dummy}; + std::size_t sz = 0; + for (std::size_t i = 1; i < 1024; ++i) { + ASSERT_NE(tmp.allocate(i), nullptr); + sz += i; + } + for (std::size_t i = 1; i < 1024; ++i) { + ASSERT_NE(tmp.allocate(1024 - i), nullptr); + sz += 1024 - i; + } + ASSERT_GE(dummy.allocated, sz); + } + ASSERT_EQ(dummy.allocated, 0); +} + +TEST(monotonic_buffer_resource, allocate_by_buffer) { + dummy_allocator dummy; + std::array buffer; + { + pmr::monotonic_buffer_resource tmp{buffer, &dummy}; + for (std::size_t i = 1; i < 64; ++i) { + ASSERT_NE(tmp.allocate(i), nullptr); + } + ASSERT_EQ(dummy.allocated, 0); + std::size_t sz = 0; + for (std::size_t i = 1; i < 64; ++i) { + ASSERT_NE(tmp.allocate(64 - i), nullptr); + sz += 64 - i; + } + ASSERT_GT(dummy.allocated, sz); + } + ASSERT_EQ(dummy.allocated, 0); +} +#include +TEST(monotonic_buffer_resource, release) { + dummy_allocator dummy; + { + pmr::monotonic_buffer_resource tmp{&dummy}; + tmp.release(); + ASSERT_EQ(dummy.allocated, 0); + ASSERT_NE(tmp.allocate(1024), nullptr); + ASSERT_GE(dummy.allocated, 1024); + ASSERT_LE(dummy.allocated, 1024 * 1.5); + tmp.release(); + ASSERT_EQ(dummy.allocated, 0); + ASSERT_NE(tmp.allocate(1024), nullptr); + ASSERT_GE(dummy.allocated, 1024); + ASSERT_LE(dummy.allocated, 1024 * 1.5); + } + ASSERT_EQ(dummy.allocated, 0); + std::array buffer; + { + pmr::monotonic_buffer_resource tmp{buffer, &dummy}; + auto *p = tmp.allocate(1024); + ASSERT_EQ(p, buffer.data()); + p = tmp.allocate(10240); + ASSERT_NE(p, buffer.data()); + ASSERT_LE(dummy.allocated, 10240 + 1024); + tmp.release(); + ASSERT_EQ(dummy.allocated, 0); + p = tmp.allocate(1024); + ASSERT_EQ(p, buffer.data()); + ASSERT_EQ(dummy.allocated, 0); + } + ASSERT_EQ(dummy.allocated, 0); + // { + // std::pmr::monotonic_buffer_resource res{buffer.data(), buffer.size()}; + // std::pmr::polymorphic_allocator tmp{&res}; + // auto *p = tmp.allocate(1024); + // ASSERT_EQ(p, buffer.data()); + // p = tmp.allocate(10240); + // ASSERT_NE(p, buffer.data()); + // res.release(); + // p = tmp.allocate(1024); + // ASSERT_EQ(p, buffer.data()); + // } +}