mirror of
https://github.com/mutouyun/cpp-ipc.git
synced 2025-12-06 16:56:45 +08:00
Optimize memory_resource & add monotonic_buffer_resource
This commit is contained in:
parent
e83bd8f874
commit
e7a8005f58
@ -15,11 +15,37 @@
|
||||
#include "libipc/imp/export.h"
|
||||
#include "libipc/imp/uninitialized.h"
|
||||
#include "libipc/imp/byte.h"
|
||||
#include "libipc/mem/memory_resource.h"
|
||||
|
||||
namespace ipc {
|
||||
namespace mem {
|
||||
|
||||
/// \brief Helper trait for memory resource.
|
||||
|
||||
template <typename T, typename = void>
|
||||
struct has_allocate : std::false_type {};
|
||||
|
||||
template <typename T>
|
||||
struct has_allocate<T,
|
||||
typename std::enable_if<std::is_convertible<
|
||||
decltype(std::declval<T &>().allocate(std::declval<std::size_t>(),
|
||||
std::declval<std::size_t>())), void *
|
||||
>::value>::type> : std::true_type {};
|
||||
|
||||
template <typename T, typename = void>
|
||||
struct has_deallocate : std::false_type {};
|
||||
|
||||
template <typename T>
|
||||
struct has_deallocate<T,
|
||||
decltype(std::declval<T &>().deallocate(std::declval<void *>(),
|
||||
std::declval<std::size_t>(),
|
||||
std::declval<std::size_t>()))
|
||||
> : std::true_type {};
|
||||
|
||||
template <typename T>
|
||||
using is_memory_resource =
|
||||
std::enable_if_t<has_allocate <T>::value &&
|
||||
has_deallocate<T>::value, bool>;
|
||||
|
||||
/**
|
||||
* \brief An allocator which exhibits different allocation behavior
|
||||
* depending upon the memory resource from which it is constructed.
|
||||
@ -57,7 +83,7 @@ class LIBIPC_EXPORT allocator {
|
||||
holder_mr(MR *p_mr) noexcept
|
||||
: res_(p_mr) {}
|
||||
|
||||
// [MSVC] error C2259: 'pmr::allocator::holder_mr<void *,bool>': cannot instantiate abstract class.
|
||||
// [MSVC] error C2259: 'allocator::holder_mr<void *,bool>': cannot instantiate abstract class.
|
||||
void *alloc(std::size_t s, std::size_t a) const override { return nullptr; }
|
||||
void dealloc(void *p, std::size_t s, std::size_t a) const override {}
|
||||
};
|
||||
@ -67,7 +93,7 @@ class LIBIPC_EXPORT allocator {
|
||||
* \tparam MR memory resource type
|
||||
*/
|
||||
template <typename MR>
|
||||
class holder_mr<MR, verify_memory_resource<MR>> : public holder_mr<MR, void> {
|
||||
class holder_mr<MR, is_memory_resource<MR>> : public holder_mr<MR, void> {
|
||||
using base_t = holder_mr<MR, void>;
|
||||
|
||||
public:
|
||||
@ -89,6 +115,8 @@ class LIBIPC_EXPORT allocator {
|
||||
holder_mr_base & get_holder() noexcept;
|
||||
holder_mr_base const &get_holder() const noexcept;
|
||||
|
||||
void init_default_resource() noexcept;
|
||||
|
||||
public:
|
||||
/// \brief Constructs an `allocator` using the return value of
|
||||
/// `new_delete_resource::get()` as the underlying memory resource.
|
||||
@ -103,13 +131,13 @@ public:
|
||||
|
||||
/// \brief Constructs a allocator from a memory resource pointer.
|
||||
/// \note The lifetime of the pointer must be longer than that of allocator.
|
||||
template <typename T, verify_memory_resource<T> = true>
|
||||
template <typename T, is_memory_resource<T> = true>
|
||||
allocator(T *p_mr) noexcept {
|
||||
if (p_mr == nullptr) {
|
||||
ipc::construct<holder_mr<new_delete_resource>>(holder_.data(), new_delete_resource::get());
|
||||
init_default_resource();
|
||||
return;
|
||||
}
|
||||
ipc::construct<holder_mr<T>>(holder_.data(), p_mr);
|
||||
std::ignore = ipc::construct<holder_mr<T>>(holder_.data(), p_mr);
|
||||
}
|
||||
|
||||
void swap(allocator &other) noexcept;
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
/**
|
||||
* \file libipc/memory_resource.h
|
||||
* \author mutouyun (orz@orzz.org)
|
||||
* \brief Implement memory allocation strategies that can be used by pmr::allocator.
|
||||
* \brief Implement memory allocation strategies that can be used by ipc::mem::allocator.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
@ -9,38 +9,13 @@
|
||||
#include <cstddef> // std::size_t, std::max_align_t
|
||||
|
||||
#include "libipc/imp/export.h"
|
||||
#include "libipc/def.h"
|
||||
#include "libipc/imp/span.h"
|
||||
#include "libipc/imp/byte.h"
|
||||
#include "libipc/mem/allocator.h"
|
||||
|
||||
namespace ipc {
|
||||
namespace mem {
|
||||
|
||||
/// \brief Helper trait for memory resource.
|
||||
|
||||
template <typename T, typename = void>
|
||||
struct has_allocate : std::false_type {};
|
||||
|
||||
template <typename T>
|
||||
struct has_allocate<T,
|
||||
typename std::enable_if<std::is_convertible<
|
||||
decltype(std::declval<T &>().allocate(std::declval<std::size_t>(),
|
||||
std::declval<std::size_t>())), void *
|
||||
>::value>::type> : std::true_type {};
|
||||
|
||||
template <typename T, typename = void>
|
||||
struct has_deallocate : std::false_type {};
|
||||
|
||||
template <typename T>
|
||||
struct has_deallocate<T,
|
||||
decltype(std::declval<T &>().deallocate(std::declval<void *>(),
|
||||
std::declval<std::size_t>(),
|
||||
std::declval<std::size_t>()))
|
||||
> : std::true_type {};
|
||||
|
||||
template <typename T>
|
||||
using verify_memory_resource =
|
||||
std::enable_if_t<has_allocate <T>::value &&
|
||||
has_deallocate<T>::value, bool>;
|
||||
|
||||
/**
|
||||
* \class LIBIPC_EXPORT new_delete_resource
|
||||
* \brief A memory resource that uses the
|
||||
@ -62,5 +37,47 @@ public:
|
||||
void deallocate(void *p, std::size_t bytes, std::size_t alignment = alignof(std::max_align_t)) noexcept;
|
||||
};
|
||||
|
||||
/**
|
||||
* \class LIBIPC_EXPORT monotonic_buffer_resource
|
||||
* \brief A special-purpose memory resource class
|
||||
* that releases the allocated memory only when the resource is destroyed.
|
||||
* \see https://en.cppreference.com/w/cpp/memory/monotonic_buffer_resource
|
||||
*/
|
||||
class LIBIPC_EXPORT monotonic_buffer_resource {
|
||||
|
||||
allocator upstream_;
|
||||
|
||||
struct node {
|
||||
node *next;
|
||||
std::size_t size;
|
||||
} *free_list_;
|
||||
|
||||
ipc::byte * head_;
|
||||
ipc::byte * tail_;
|
||||
std::size_t next_size_;
|
||||
|
||||
ipc::byte * const initial_buffer_;
|
||||
std::size_t const initial_size_;
|
||||
|
||||
public:
|
||||
monotonic_buffer_resource() noexcept;
|
||||
explicit monotonic_buffer_resource(allocator upstream) noexcept;
|
||||
explicit monotonic_buffer_resource(std::size_t initial_size) noexcept;
|
||||
monotonic_buffer_resource(std::size_t initial_size, allocator upstream) noexcept;
|
||||
monotonic_buffer_resource(ipc::span<ipc::byte> buffer) noexcept;
|
||||
monotonic_buffer_resource(ipc::span<ipc::byte> buffer, allocator upstream) noexcept;
|
||||
|
||||
~monotonic_buffer_resource() noexcept;
|
||||
|
||||
monotonic_buffer_resource(monotonic_buffer_resource const &) = delete;
|
||||
monotonic_buffer_resource &operator=(monotonic_buffer_resource const &) = delete;
|
||||
|
||||
allocator upstream_resource() const noexcept;
|
||||
void release() noexcept;
|
||||
|
||||
void *allocate(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;
|
||||
};
|
||||
|
||||
} // namespace mem
|
||||
} // namespace ipc
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
|
||||
#include "libipc/imp/log.h"
|
||||
#include "libipc/mem/allocator.h"
|
||||
#include "libipc/mem/memory_resource.h"
|
||||
|
||||
namespace ipc {
|
||||
namespace mem {
|
||||
@ -15,6 +16,10 @@ allocator::holder_mr_base const &allocator::get_holder() const noexcept {
|
||||
return *reinterpret_cast<holder_mr_base const *>(holder_.data());
|
||||
}
|
||||
|
||||
void allocator::init_default_resource() noexcept {
|
||||
std::ignore = ipc::construct<holder_mr<new_delete_resource>>(holder_.data(), new_delete_resource::get());
|
||||
}
|
||||
|
||||
allocator::allocator() noexcept
|
||||
: allocator(new_delete_resource::get()) {}
|
||||
|
||||
|
||||
140
src/libipc/mem/monotonic_buffer_resource.cpp
Normal file
140
src/libipc/mem/monotonic_buffer_resource.cpp
Normal file
@ -0,0 +1,140 @@
|
||||
|
||||
#include <utility>
|
||||
#include <memory>
|
||||
#include <algorithm>
|
||||
|
||||
#include "libipc/imp/log.h"
|
||||
#include "libipc/imp/aligned.h"
|
||||
#include "libipc/imp/detect_plat.h"
|
||||
#include "libipc/mem/memory_resource.h"
|
||||
|
||||
namespace ipc {
|
||||
namespace mem {
|
||||
namespace {
|
||||
|
||||
template <typename Node>
|
||||
Node *make_node(allocator const &upstream, std::size_t initial_size, std::size_t alignment) noexcept {
|
||||
LIBIPC_LOG();
|
||||
auto sz = ipc::round_up(sizeof(Node), alignment) + initial_size;
|
||||
LIBIPC_TRY {
|
||||
auto *node = static_cast<Node *>(upstream.allocate(sz));
|
||||
if (node == nullptr) {
|
||||
log.error("failed: allocate memory for `monotonic_buffer_resource`'s node.",
|
||||
" bytes = ", initial_size, ", alignment = ", alignment);
|
||||
return nullptr;
|
||||
}
|
||||
node->next = nullptr;
|
||||
node->size = sz;
|
||||
return node;
|
||||
} LIBIPC_CATCH(...) {
|
||||
log.error("failed: allocate memory for `monotonic_buffer_resource`'s node.",
|
||||
" bytes = ", initial_size, ", alignment = ", alignment,
|
||||
"\n\texception: ", ipc::log::exception_string(std::current_exception()));
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
std::size_t next_buffer_size(std::size_t size) noexcept {
|
||||
return size * 3 / 2;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
monotonic_buffer_resource::monotonic_buffer_resource() noexcept
|
||||
: monotonic_buffer_resource(allocator{}) {}
|
||||
|
||||
monotonic_buffer_resource::monotonic_buffer_resource(allocator upstream) noexcept
|
||||
: monotonic_buffer_resource(0, std::move(upstream)) {}
|
||||
|
||||
monotonic_buffer_resource::monotonic_buffer_resource(std::size_t initial_size) noexcept
|
||||
: monotonic_buffer_resource(initial_size, allocator{}) {}
|
||||
|
||||
monotonic_buffer_resource::monotonic_buffer_resource(std::size_t initial_size, allocator upstream) noexcept
|
||||
: upstream_ (std::move(upstream))
|
||||
, free_list_ (nullptr)
|
||||
, head_ (nullptr)
|
||||
, tail_ (nullptr)
|
||||
, next_size_ (initial_size)
|
||||
, initial_buffer_(nullptr)
|
||||
, initial_size_ (initial_size) {}
|
||||
|
||||
monotonic_buffer_resource::monotonic_buffer_resource(ipc::span<ipc::byte> buffer) noexcept
|
||||
: monotonic_buffer_resource(buffer, allocator{}) {}
|
||||
|
||||
monotonic_buffer_resource::monotonic_buffer_resource(ipc::span<ipc::byte> buffer, allocator upstream) noexcept
|
||||
: upstream_ (std::move(upstream))
|
||||
, free_list_ (nullptr)
|
||||
, head_ (buffer.begin())
|
||||
, tail_ (buffer.end())
|
||||
, next_size_ (next_buffer_size(buffer.size()))
|
||||
, initial_buffer_(buffer.begin())
|
||||
, initial_size_ (buffer.size()) {}
|
||||
|
||||
monotonic_buffer_resource::~monotonic_buffer_resource() noexcept {
|
||||
release();
|
||||
}
|
||||
|
||||
allocator monotonic_buffer_resource::upstream_resource() const noexcept {
|
||||
return upstream_;
|
||||
}
|
||||
|
||||
void monotonic_buffer_resource::release() noexcept {
|
||||
LIBIPC_LOG();
|
||||
LIBIPC_TRY {
|
||||
while (free_list_ != nullptr) {
|
||||
auto *next = free_list_->next;
|
||||
upstream_.deallocate(free_list_, free_list_->size);
|
||||
free_list_ = next;
|
||||
}
|
||||
} LIBIPC_CATCH(...) {
|
||||
log.error("failed: deallocate memory for `monotonic_buffer_resource`.",
|
||||
"\n\texception: ", ipc::log::exception_string(std::current_exception()));
|
||||
}
|
||||
// reset to initial state at contruction
|
||||
if ((head_ = initial_buffer_) != nullptr) {
|
||||
tail_ = head_ + initial_size_;
|
||||
next_size_ = next_buffer_size(initial_size_);
|
||||
} else {
|
||||
tail_ = nullptr;
|
||||
next_size_ = initial_size_;
|
||||
}
|
||||
}
|
||||
|
||||
void *monotonic_buffer_resource::allocate(std::size_t bytes, std::size_t alignment) noexcept {
|
||||
LIBIPC_LOG();
|
||||
if (bytes == 0) {
|
||||
log.error("failed: allocate bytes = 0.");
|
||||
return nullptr;
|
||||
}
|
||||
void *p = head_;
|
||||
auto s = static_cast<std::size_t>(tail_ - head_);
|
||||
if (std::align(alignment, bytes, p, s) == nullptr) {
|
||||
next_size_ = (std::max)(next_size_, bytes);
|
||||
auto *node = make_node<monotonic_buffer_resource::node>(upstream_, next_size_, alignment);
|
||||
if (node == nullptr) return nullptr;
|
||||
node->next = free_list_;
|
||||
free_list_ = node;
|
||||
next_size_ = next_buffer_size(next_size_);
|
||||
// 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<ipc::byte *>(p) + s;
|
||||
}
|
||||
head_ = static_cast<ipc::byte *>(p) + bytes;
|
||||
return p;
|
||||
}
|
||||
|
||||
void monotonic_buffer_resource::deallocate(void *p, std::size_t bytes, std::size_t alignment) noexcept {
|
||||
static_cast<void>(p);
|
||||
static_cast<void>(bytes);
|
||||
static_cast<void>(alignment);
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
} // namespace mem
|
||||
} // namespace ipc
|
||||
@ -4,7 +4,12 @@
|
||||
|
||||
#include "test.h"
|
||||
|
||||
#if defined(LIBIPC_CPP_17) && defined(__cpp_lib_memory_resource)
|
||||
# include <memory_resource>
|
||||
#endif
|
||||
|
||||
#include "libipc/mem/allocator.h"
|
||||
#include "libipc/mem/memory_resource.h"
|
||||
|
||||
TEST(allocator, construct) {
|
||||
ipc::mem::allocator alc;
|
||||
@ -32,6 +37,26 @@ public:
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST(allocator, memory_resource_traits) {
|
||||
EXPECT_FALSE(ipc::mem::has_allocate<void>::value);
|
||||
EXPECT_FALSE(ipc::mem::has_allocate<int>::value);
|
||||
EXPECT_FALSE(ipc::mem::has_allocate<std::vector<int>>::value);
|
||||
EXPECT_FALSE(ipc::mem::has_allocate<std::allocator<int>>::value);
|
||||
#if defined(LIBIMP_CPP_17) && defined(__cpp_lib_memory_resource)
|
||||
EXPECT_TRUE (ipc::mem::has_allocate<std::ipc::mem::memory_resource>::value);
|
||||
EXPECT_TRUE (ipc::mem::has_allocate<std::ipc::mem::polymorphic_allocator<int>>::value);
|
||||
#endif
|
||||
|
||||
EXPECT_FALSE(ipc::mem::has_deallocate<void>::value);
|
||||
EXPECT_FALSE(ipc::mem::has_deallocate<int>::value);
|
||||
EXPECT_FALSE(ipc::mem::has_deallocate<std::vector<int>>::value);
|
||||
EXPECT_FALSE(ipc::mem::has_deallocate<std::allocator<int>>::value);
|
||||
#if defined(LIBIMP_CPP_17) && defined(__cpp_lib_memory_resource)
|
||||
EXPECT_TRUE (ipc::mem::has_deallocate<std::ipc::mem::memory_resource>::value);
|
||||
EXPECT_FALSE(ipc::mem::has_deallocate<std::ipc::mem::polymorphic_allocator<int>>::value);
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST(allocator, construct_copy_move) {
|
||||
ipc::mem::new_delete_resource mem_res;
|
||||
dummy_resource dummy_res;
|
||||
|
||||
@ -2,9 +2,6 @@
|
||||
#include "test.h"
|
||||
|
||||
#include <utility>
|
||||
#if defined(LIBIPC_CPP_17) && defined(__cpp_lib_memory_resource)
|
||||
# include <memory_resource>
|
||||
#endif
|
||||
|
||||
#include "libipc/mem/memory_resource.h"
|
||||
|
||||
@ -24,26 +21,6 @@ void *test_mr(T &&mr, std::size_t bytes, std::size_t alignment) {
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST(memory_resource, traits) {
|
||||
EXPECT_FALSE(ipc::mem::has_allocate<void>::value);
|
||||
EXPECT_FALSE(ipc::mem::has_allocate<int>::value);
|
||||
EXPECT_FALSE(ipc::mem::has_allocate<std::vector<int>>::value);
|
||||
EXPECT_FALSE(ipc::mem::has_allocate<std::allocator<int>>::value);
|
||||
#if defined(LIBIMP_CPP_17) && defined(__cpp_lib_memory_resource)
|
||||
EXPECT_TRUE (ipc::mem::has_allocate<std::ipc::mem::memory_resource>::value);
|
||||
EXPECT_TRUE (ipc::mem::has_allocate<std::ipc::mem::polymorphic_allocator<int>>::value);
|
||||
#endif
|
||||
|
||||
EXPECT_FALSE(ipc::mem::has_deallocate<void>::value);
|
||||
EXPECT_FALSE(ipc::mem::has_deallocate<int>::value);
|
||||
EXPECT_FALSE(ipc::mem::has_deallocate<std::vector<int>>::value);
|
||||
EXPECT_FALSE(ipc::mem::has_deallocate<std::allocator<int>>::value);
|
||||
#if defined(LIBIMP_CPP_17) && defined(__cpp_lib_memory_resource)
|
||||
EXPECT_TRUE (ipc::mem::has_deallocate<std::ipc::mem::memory_resource>::value);
|
||||
EXPECT_FALSE(ipc::mem::has_deallocate<std::ipc::mem::polymorphic_allocator<int>>::value);
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST(memory_resource, new_delete_resource) {
|
||||
ipc::mem::new_delete_resource mem_res;
|
||||
|
||||
@ -61,3 +38,128 @@ TEST(memory_resource, new_delete_resource) {
|
||||
EXPECT_NE(test_mr(mem_res, 1, 8), nullptr);
|
||||
EXPECT_NE(test_mr(mem_res, 1, 64), nullptr);
|
||||
}
|
||||
|
||||
TEST(memory_resource, monotonic_buffer_resource_construct) {
|
||||
{ ipc::mem::monotonic_buffer_resource tmp; }
|
||||
ipc::mem::monotonic_buffer_resource{};
|
||||
ipc::mem::monotonic_buffer_resource{ipc::mem::allocator{}};
|
||||
ipc::mem::monotonic_buffer_resource{0};
|
||||
ipc::mem::monotonic_buffer_resource{0, ipc::mem::allocator{}};
|
||||
ipc::mem::monotonic_buffer_resource{ipc::span<ipc::byte>{}};
|
||||
ipc::mem::monotonic_buffer_resource{ipc::span<ipc::byte>{}, ipc::mem::allocator{}};
|
||||
SUCCEED();
|
||||
}
|
||||
|
||||
TEST(memory_resource, monotonic_buffer_resource_no_copy) {
|
||||
EXPECT_FALSE(std::is_copy_constructible<ipc::mem::monotonic_buffer_resource>::value);
|
||||
EXPECT_FALSE(std::is_copy_assignable<ipc::mem::monotonic_buffer_resource>::value);
|
||||
EXPECT_FALSE(std::is_move_constructible<ipc::mem::monotonic_buffer_resource>::value);
|
||||
EXPECT_FALSE(std::is_move_assignable<ipc::mem::monotonic_buffer_resource>::value);
|
||||
}
|
||||
|
||||
TEST(memory_resource, 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;
|
||||
ipc::mem::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(memory_resource, monotonic_buffer_resource_allocate) {
|
||||
dummy_allocator dummy;
|
||||
{
|
||||
ipc::mem::monotonic_buffer_resource tmp{&dummy};
|
||||
ASSERT_EQ(tmp.allocate(0), nullptr);
|
||||
ASSERT_EQ(dummy.allocated, 0);
|
||||
}
|
||||
ASSERT_EQ(dummy.allocated, 0);
|
||||
{
|
||||
ipc::mem::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(memory_resource, monotonic_buffer_resource_allocate_by_buffer) {
|
||||
dummy_allocator dummy;
|
||||
std::array<ipc::byte, 4096> buffer;
|
||||
{
|
||||
ipc::mem::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);
|
||||
}
|
||||
|
||||
TEST(memory_resource, monotonic_buffer_resource_release) {
|
||||
dummy_allocator dummy;
|
||||
{
|
||||
ipc::mem::monotonic_buffer_resource tmp{&dummy};
|
||||
tmp.release();
|
||||
ASSERT_EQ(dummy.allocated, 0);
|
||||
ASSERT_NE(tmp.allocate(1024), nullptr);
|
||||
ASSERT_GE(dummy.allocated, 1024u);
|
||||
ASSERT_LE(dummy.allocated, 1024u * 1.5);
|
||||
tmp.release();
|
||||
ASSERT_EQ(dummy.allocated, 0);
|
||||
ASSERT_NE(tmp.allocate(1024), nullptr);
|
||||
ASSERT_GE(dummy.allocated, 1024u);
|
||||
ASSERT_LE(dummy.allocated, 1024u * 1.5);
|
||||
}
|
||||
ASSERT_EQ(dummy.allocated, 0);
|
||||
std::array<ipc::byte, 4096> buffer;
|
||||
{
|
||||
ipc::mem::monotonic_buffer_resource tmp{buffer, &dummy};
|
||||
auto *p = tmp.allocate(1024);
|
||||
ASSERT_EQ(p, buffer.data());
|
||||
ASSERT_EQ(dummy.allocated, 0);
|
||||
p = tmp.allocate(10240);
|
||||
ASSERT_NE(p, buffer.data());
|
||||
ASSERT_LE(dummy.allocated, 10240u + 1024u);
|
||||
tmp.release();
|
||||
ASSERT_EQ(dummy.allocated, 0);
|
||||
p = tmp.allocate(1024);
|
||||
ASSERT_EQ(p, buffer.data());
|
||||
ASSERT_EQ(dummy.allocated, 0);
|
||||
p = tmp.allocate(10240);
|
||||
ASSERT_NE(p, buffer.data());
|
||||
ASSERT_LE(dummy.allocated, 10240u + 1024u);
|
||||
}
|
||||
ASSERT_EQ(dummy.allocated, 0);
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user