mirror of
https://github.com/mutouyun/cpp-ipc.git
synced 2025-12-06 16:56:45 +08:00
upd: [pmr] optimize allocator implementation
This commit is contained in:
parent
774a3c9af7
commit
cd545653c4
@ -77,18 +77,15 @@ private:
|
||||
};
|
||||
|
||||
data *init(index_t circ_size) noexcept {
|
||||
if (!data_allocator_) {
|
||||
return nullptr;
|
||||
}
|
||||
void *data_ptr = nullptr;
|
||||
LIBIMP_TRY {
|
||||
data_ptr = data_allocator_.alloc(data::size_of(circ_size));
|
||||
data_ptr = data_allocator_.allocate(data::size_of(circ_size));
|
||||
if (data_ptr == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
return ::LIBIMP::construct<data>(data_ptr, circ_size);
|
||||
} LIBIMP_CATCH(...) {
|
||||
data_allocator_.dealloc(data_ptr, data::size_of(circ_size));
|
||||
data_allocator_.deallocate(data_ptr, data::size_of(circ_size));
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
@ -128,7 +125,7 @@ public:
|
||||
if (valid()) {
|
||||
auto sz = data_->byte_size();
|
||||
(void)::LIBIMP::destroy<data>(data_);
|
||||
data_allocator_.dealloc(data_, sz);
|
||||
data_allocator_.deallocate(data_, sz);
|
||||
}
|
||||
}
|
||||
|
||||
@ -148,7 +145,7 @@ public:
|
||||
: data_model(default_circle_buffer_size) {}
|
||||
|
||||
bool valid() const noexcept {
|
||||
return (data_ != nullptr) && data_allocator_.valid();
|
||||
return data_ != nullptr;
|
||||
}
|
||||
|
||||
explicit operator bool() const noexcept {
|
||||
|
||||
@ -64,7 +64,7 @@ public:
|
||||
using value_type = T;
|
||||
|
||||
template <typename... A>
|
||||
element(A &&... args)
|
||||
element(A &&...args)
|
||||
noexcept(noexcept(T{std::forward<A>(args)...}))
|
||||
: f_ct_{state::invalid_value}
|
||||
, data_{std::forward<A>(args)...} {}
|
||||
|
||||
@ -44,8 +44,7 @@ class byte {
|
||||
std::uint8_t bits_;
|
||||
|
||||
public:
|
||||
constexpr byte() noexcept
|
||||
: byte(0) {}
|
||||
byte() noexcept = default;
|
||||
|
||||
template <typename T, typename = detail::is_integral<T>>
|
||||
constexpr byte(T v) noexcept
|
||||
|
||||
@ -23,7 +23,7 @@ LIBIMP_NAMESPACE_BEG_
|
||||
*/
|
||||
|
||||
template <typename T, typename... A>
|
||||
auto construct(void *p, A &&... args)
|
||||
auto construct(void *p, A &&...args)
|
||||
-> std::enable_if_t<::std::is_constructible<T, A...>::value, T *> {
|
||||
#if defined(LIBIMP_CPP_20)
|
||||
return std::construct_at(static_cast<T *>(p), std::forward<A>(args)...);
|
||||
@ -33,7 +33,7 @@ auto construct(void *p, A &&... args)
|
||||
}
|
||||
|
||||
template <typename T, typename... A>
|
||||
auto construct(void *p, A &&... args)
|
||||
auto construct(void *p, A &&...args)
|
||||
-> std::enable_if_t<!::std::is_constructible<T, A...>::value, T *> {
|
||||
return ::new (p) T{std::forward<A>(args)...};
|
||||
}
|
||||
|
||||
@ -122,7 +122,7 @@ public:
|
||||
, level_limit_(level_limit) {}
|
||||
|
||||
template <typename... A>
|
||||
grip const &operator()(log::level l, A &&... args) const noexcept {
|
||||
grip const &operator()(log::level l, A &&...args) const noexcept {
|
||||
if (underlyof(l) < underlyof(level_limit_)) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
@ -24,7 +24,7 @@ struct is_comfortable {
|
||||
};
|
||||
|
||||
template <typename T, typename... A>
|
||||
auto make(A &&... args) -> std::enable_if_t<is_comfortable<T>::value, T *> {
|
||||
auto make(A &&...args) -> std::enable_if_t<is_comfortable<T>::value, T *> {
|
||||
T *buf {};
|
||||
// construct an object using memory of a pointer
|
||||
construct<T>(&buf, std::forward<A>(args)...);
|
||||
@ -42,7 +42,7 @@ auto clear(T *p) noexcept -> std::enable_if_t<is_comfortable<T>::value> {
|
||||
}
|
||||
|
||||
template <typename T, typename... A>
|
||||
auto make(A &&... args) -> std::enable_if_t<!is_comfortable<T>::value, T *> {
|
||||
auto make(A &&...args) -> std::enable_if_t<!is_comfortable<T>::value, T *> {
|
||||
return new T{std::forward<A>(args)...};
|
||||
}
|
||||
|
||||
@ -60,7 +60,7 @@ template <typename T>
|
||||
class Obj {
|
||||
public:
|
||||
template <typename... A>
|
||||
static T *make(A &&... args) {
|
||||
static T *make(A &&...args) {
|
||||
return pimpl::make<T>(std::forward<A>(args)...);
|
||||
}
|
||||
|
||||
|
||||
@ -142,7 +142,7 @@ public:
|
||||
typename = not_match<result, A...>,
|
||||
typename = decltype(type_traits_t::init_code(std::declval<storage_t &>()
|
||||
, std::declval<A>()...))>
|
||||
result(A &&... args) noexcept {
|
||||
result(A &&...args) noexcept {
|
||||
type_traits_t::init_code(code_, std::forward<A>(args)...);
|
||||
}
|
||||
|
||||
@ -171,7 +171,7 @@ public:
|
||||
typename = not_match<result, A...>,
|
||||
typename = decltype(type_traits_t::init_code(std::declval<storage_t &>()
|
||||
, std::declval<A>()...))>
|
||||
result(A &&... args) noexcept {
|
||||
result(A &&...args) noexcept {
|
||||
type_traits_t::init_code(code_, std::forward<A>(args)...);
|
||||
}
|
||||
|
||||
|
||||
@ -32,63 +32,54 @@ LIBPMR_NAMESPACE_BEG_
|
||||
*/
|
||||
class LIBIMP_EXPORT allocator {
|
||||
|
||||
class holder_base {
|
||||
class holder_mr_base {
|
||||
public:
|
||||
virtual ~holder_base() noexcept = default;
|
||||
virtual void *alloc(std::size_t) = 0;
|
||||
virtual void dealloc(void *, std::size_t) = 0;
|
||||
virtual bool valid() const noexcept = 0;
|
||||
virtual ~holder_mr_base() noexcept = default;
|
||||
virtual void *alloc(std::size_t, std::size_t) const = 0;
|
||||
virtual void dealloc(void *, std::size_t, std::size_t) const = 0;
|
||||
};
|
||||
|
||||
class holder_null : public holder_base {
|
||||
public:
|
||||
void *alloc(std::size_t) override { return nullptr; }
|
||||
void dealloc(void *, std::size_t) override {}
|
||||
bool valid() const noexcept override { return false; }
|
||||
};
|
||||
|
||||
template <typename MemRes, typename = bool>
|
||||
class holder_memory_resource;
|
||||
|
||||
/**
|
||||
* \brief A memory resource pointer holder class for type erasure.
|
||||
* \tparam MR memory resource type
|
||||
*/
|
||||
template <typename MR>
|
||||
class holder_memory_resource<MR, verify_memory_resource<MR>> : public holder_base {
|
||||
MR *p_mem_res_;
|
||||
|
||||
public:
|
||||
holder_memory_resource(MR *p_mr) noexcept
|
||||
: p_mem_res_(p_mr) {}
|
||||
|
||||
void *alloc(std::size_t s) override {
|
||||
return p_mem_res_->allocate(s);
|
||||
}
|
||||
|
||||
void dealloc(void *p, std::size_t s) override {
|
||||
p_mem_res_->deallocate(p, s);
|
||||
}
|
||||
|
||||
bool valid() const noexcept override {
|
||||
return p_mem_res_ != nullptr;
|
||||
}
|
||||
};
|
||||
template <typename MR, typename = bool>
|
||||
class holder_mr;
|
||||
|
||||
/**
|
||||
* \brief An empty holding class used to calculate a reasonable memory size for the holder.
|
||||
* \tparam MR cannot be converted to the type of memory resource
|
||||
*/
|
||||
template <typename MR, typename U>
|
||||
class holder_memory_resource : public holder_null {
|
||||
MR *p_dummy_;
|
||||
class holder_mr : public holder_mr_base {
|
||||
protected:
|
||||
MR *res_;
|
||||
|
||||
public:
|
||||
holder_mr(MR *p_mr) noexcept
|
||||
: res_(p_mr) {}
|
||||
};
|
||||
|
||||
using void_holder_type = holder_memory_resource<void>;
|
||||
alignas(void_holder_type) std::array<::LIBIMP::byte, sizeof(void_holder_type)> holder_;
|
||||
/**
|
||||
* \brief A memory resource pointer holder class for type erasure.
|
||||
* \tparam MR memory resource type
|
||||
*/
|
||||
template <typename MR>
|
||||
class holder_mr<MR, verify_memory_resource<MR>> : public holder_mr<MR, void> {
|
||||
public:
|
||||
holder_mr(MR *p_mr) noexcept
|
||||
: holder_mr<MR, void>{p_mr} {}
|
||||
|
||||
holder_base & get_holder() noexcept;
|
||||
holder_base const &get_holder() const noexcept;
|
||||
void *alloc(std::size_t s, std::size_t a) const override {
|
||||
return res_->allocate(s, a);
|
||||
}
|
||||
|
||||
void dealloc(void *p, std::size_t s, std::size_t a) const override {
|
||||
res_->deallocate(p, s, a);
|
||||
}
|
||||
};
|
||||
|
||||
using void_holder_t = holder_mr<void *>;
|
||||
alignas(void_holder_t) std::array<::LIBIMP::byte, sizeof(void_holder_t)> holder_;
|
||||
|
||||
holder_mr_base & get_holder() noexcept;
|
||||
holder_mr_base const &get_holder() const noexcept;
|
||||
|
||||
public:
|
||||
allocator() noexcept;
|
||||
@ -97,24 +88,25 @@ public:
|
||||
allocator(allocator const &other) noexcept = default;
|
||||
allocator &operator=(allocator const &other) & noexcept = default;
|
||||
|
||||
allocator(allocator &&other) noexcept;
|
||||
allocator &operator=(allocator &&other) & noexcept;
|
||||
allocator(allocator &&other) noexcept = default;
|
||||
allocator &operator=(allocator &&other) & noexcept = default;
|
||||
|
||||
/// \brief Constructs a allocator from a memory resource pointer
|
||||
/// The lifetime of the pointer must be longer than that of allocator.
|
||||
template <typename T, verify_memory_resource<T> = true>
|
||||
allocator(T *p_mr) : allocator() {
|
||||
if (p_mr == nullptr) return;
|
||||
::LIBIMP::construct<holder_memory_resource<T>>(holder_.data(), p_mr);
|
||||
allocator(T *p_mr) noexcept {
|
||||
if (p_mr == nullptr) {
|
||||
::LIBIMP::construct<holder_mr<new_delete_resource>>(holder_.data(), new_delete_resource::get());
|
||||
return;
|
||||
}
|
||||
::LIBIMP::construct<holder_mr<T>>(holder_.data(), p_mr);
|
||||
}
|
||||
|
||||
void swap(allocator &other) noexcept;
|
||||
bool valid() const noexcept;
|
||||
explicit operator bool() const noexcept;
|
||||
|
||||
/// \brief Allocate/deallocate memory.
|
||||
void *alloc(std::size_t s);
|
||||
void dealloc(void *p, std::size_t s);
|
||||
void *allocate(std::size_t s, std::size_t = alignof(std::max_align_t)) const;
|
||||
void deallocate(void *p, std::size_t s, std::size_t = alignof(std::max_align_t)) const;
|
||||
};
|
||||
|
||||
LIBPMR_NAMESPACE_END_
|
||||
|
||||
122
include/libpmr/holder_base.h
Normal file
122
include/libpmr/holder_base.h
Normal file
@ -0,0 +1,122 @@
|
||||
/**
|
||||
* \file libpmr/small_storage.h
|
||||
* \author mutouyun (orz@orzz.org)
|
||||
* \brief Unified SSO (Small Size Optimization) holder base.
|
||||
* \date 2023-09-02
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <type_traits>
|
||||
#include <array>
|
||||
#include <typeinfo>
|
||||
#include <utility>
|
||||
#include <cstddef>
|
||||
|
||||
#include "libimp/export.h"
|
||||
#include "libimp/construct.h"
|
||||
#include "libimp/byte.h"
|
||||
#include "libimp/generic.h"
|
||||
|
||||
#include "libpmr/def.h"
|
||||
|
||||
LIBPMR_NAMESPACE_BEG_
|
||||
|
||||
class LIBIMP_EXPORT allocator;
|
||||
|
||||
/**
|
||||
* \class holder_base
|
||||
* \brief Data holder base class.
|
||||
*/
|
||||
class holder_base {
|
||||
public:
|
||||
virtual ~holder_base() noexcept = default;
|
||||
virtual bool valid() const noexcept = 0;
|
||||
virtual std::type_info const &type() const noexcept = 0;
|
||||
virtual std::size_t sizeof_type() const noexcept = 0;
|
||||
virtual std::size_t count() const noexcept = 0;
|
||||
virtual std::size_t size () const noexcept = 0;
|
||||
virtual void *get() noexcept = 0;
|
||||
virtual void const *get() const noexcept = 0;
|
||||
virtual void move_to(allocator const &, void *) noexcept = 0;
|
||||
virtual void copy_to(allocator const &, void *) const noexcept(false) = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* \class holder_null
|
||||
* \brief A holder implementation that does not hold any data objects.
|
||||
*/
|
||||
class holder_null : public holder_base {
|
||||
public:
|
||||
bool valid() const noexcept override { return false; }
|
||||
std::type_info const &type() const noexcept override { return typeid(nullptr);}
|
||||
std::size_t sizeof_type() const noexcept override { return 0; }
|
||||
std::size_t count() const noexcept override { return 0; }
|
||||
std::size_t size () const noexcept override { return 0; }
|
||||
void *get() noexcept override { return nullptr; }
|
||||
void const *get() const noexcept override { return nullptr; }
|
||||
|
||||
/// \brief The passed destination pointer is never null,
|
||||
/// and the memory to which it points is uninitialized.
|
||||
void move_to(allocator const &, void *) noexcept override {}
|
||||
void copy_to(allocator const &, void *) const noexcept(false) override {}
|
||||
};
|
||||
|
||||
template <typename Value, bool/*is on stack*/>
|
||||
class holder;
|
||||
|
||||
/**
|
||||
* \class template <typename Value> holder<Value, true>
|
||||
* \brief A holder implementation that holds a data object if type `Value` on stack memory.
|
||||
* \tparam Value The storage type of the holder.
|
||||
*/
|
||||
template <typename Value>
|
||||
class holder<Value, true> : public holder_base {
|
||||
|
||||
alignas(alignof(Value)) std::array<::LIBIMP::byte, sizeof(Value)> value_storage_;
|
||||
|
||||
public:
|
||||
holder() = default; // uninitialized
|
||||
|
||||
template <typename... A>
|
||||
holder(::LIBIMP::in_place_t, A &&...args) {
|
||||
::LIBIMP::construct<Value>(value_storage_.data(), std::forward<A>(args)...);
|
||||
}
|
||||
|
||||
bool valid() const noexcept override {
|
||||
return true;
|
||||
}
|
||||
|
||||
std::type_info const &type() const noexcept override {
|
||||
return typeid(Value);
|
||||
}
|
||||
|
||||
std::size_t sizeof_type() const noexcept override {
|
||||
return sizeof(Value);
|
||||
}
|
||||
|
||||
std::size_t count() const noexcept override {
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::size_t size() const noexcept override {
|
||||
return value_storage_.size();
|
||||
}
|
||||
|
||||
void *get() noexcept override {
|
||||
return value_storage_.data();
|
||||
}
|
||||
|
||||
void const *get() const noexcept override {
|
||||
return value_storage_.data();
|
||||
}
|
||||
|
||||
void move_to(allocator const &, void *p) noexcept override {
|
||||
::LIBIMP::construct<holder>(p, ::LIBIMP::in_place, std::move(*static_cast<Value *>(get())));
|
||||
}
|
||||
|
||||
void copy_to(allocator const &, void *p) const noexcept(false) override {
|
||||
::LIBIMP::construct<holder>(p, ::LIBIMP::in_place, *static_cast<Value *>(get()));
|
||||
}
|
||||
};
|
||||
|
||||
LIBPMR_NAMESPACE_END_
|
||||
35
include/libpmr/small_storage.h
Normal file
35
include/libpmr/small_storage.h
Normal file
@ -0,0 +1,35 @@
|
||||
/**
|
||||
* \file libpmr/small_storage.h
|
||||
* \author mutouyun (orz@orzz.org)
|
||||
* \brief Unified SSO (Small Size Optimization).
|
||||
* \date 2023-09-02
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <type_traits>
|
||||
#include <array>
|
||||
#include <typeinfo>
|
||||
#include <utility>
|
||||
#include <memory>
|
||||
#include <cstddef>
|
||||
|
||||
#include "libimp/export.h"
|
||||
#include "libimp/construct.h"
|
||||
#include "libimp/byte.h"
|
||||
#include "libimp/generic.h"
|
||||
|
||||
#include "libpmr/def.h"
|
||||
#include "libpmr/holder_base.h"
|
||||
|
||||
LIBPMR_NAMESPACE_BEG_
|
||||
|
||||
/**
|
||||
* \class template <typename Value> holder<Value, false>
|
||||
* \brief A holder implementation that holds a data object if type `Value` on heap memory.
|
||||
* \tparam Value The storage type of the holder.
|
||||
*/
|
||||
template <typename Value>
|
||||
class holder<Value, false> : public holder_base {
|
||||
};
|
||||
|
||||
LIBPMR_NAMESPACE_END_
|
||||
@ -5,54 +5,31 @@
|
||||
|
||||
LIBPMR_NAMESPACE_BEG_
|
||||
|
||||
allocator::holder_base &allocator::get_holder() noexcept {
|
||||
return *reinterpret_cast<holder_base *>(holder_.data());
|
||||
allocator::holder_mr_base &allocator::get_holder() noexcept {
|
||||
return *reinterpret_cast<holder_mr_base *>(holder_.data());
|
||||
}
|
||||
|
||||
allocator::holder_base const &allocator::get_holder() const noexcept {
|
||||
return *reinterpret_cast<holder_base const *>(holder_.data());
|
||||
allocator::holder_mr_base const &allocator::get_holder() const noexcept {
|
||||
return *reinterpret_cast<holder_mr_base const *>(holder_.data());
|
||||
}
|
||||
|
||||
allocator::allocator() noexcept {
|
||||
::LIBIMP::construct<holder_null>(holder_.data());
|
||||
}
|
||||
allocator::allocator() noexcept
|
||||
: allocator(new_delete_resource::get()) {}
|
||||
|
||||
allocator::~allocator() noexcept {
|
||||
::LIBIMP::destroy(&get_holder());
|
||||
}
|
||||
|
||||
allocator::allocator(allocator &&other) noexcept
|
||||
: allocator(other) /*copy*/ {
|
||||
::LIBIMP::construct<holder_null>(other.holder_.data());
|
||||
}
|
||||
|
||||
allocator &allocator::operator=(allocator &&other) & noexcept {
|
||||
if (this == &other) return *this;
|
||||
this->holder_ = other.holder_;
|
||||
::LIBIMP::construct<holder_null>(other.holder_.data());
|
||||
return *this;
|
||||
}
|
||||
|
||||
void allocator::swap(allocator &other) noexcept {
|
||||
std::swap(this->holder_, other.holder_);
|
||||
}
|
||||
|
||||
bool allocator::valid() const noexcept {
|
||||
return get_holder().valid();
|
||||
void *allocator::allocate(std::size_t s, std::size_t a) const {
|
||||
return get_holder().alloc(s, a);
|
||||
}
|
||||
|
||||
allocator::operator bool() const noexcept {
|
||||
return valid();
|
||||
}
|
||||
|
||||
void *allocator::alloc(std::size_t s) {
|
||||
if (!valid()) return nullptr;
|
||||
return get_holder().alloc(s);
|
||||
}
|
||||
|
||||
void allocator::dealloc(void *p, std::size_t s) {
|
||||
if (!valid()) return;
|
||||
get_holder().dealloc(p, s);
|
||||
void allocator::deallocate(void *p, std::size_t s, std::size_t a) const {
|
||||
get_holder().dealloc(p, s, a);
|
||||
}
|
||||
|
||||
LIBPMR_NAMESPACE_END_
|
||||
|
||||
@ -8,71 +8,71 @@
|
||||
|
||||
TEST(allocator, construct) {
|
||||
pmr::allocator alc;
|
||||
EXPECT_FALSE(alc.valid());
|
||||
EXPECT_FALSE(alc);
|
||||
SUCCEED();
|
||||
}
|
||||
|
||||
TEST(allocator, construct_with_memory_resource) {
|
||||
pmr::new_delete_resource mem_res;
|
||||
pmr::allocator alc {&mem_res};
|
||||
EXPECT_TRUE(alc.valid());
|
||||
EXPECT_TRUE(alc);
|
||||
|
||||
auto p = alc.alloc(128);
|
||||
TEST(allocator, construct_value_initialization) {
|
||||
pmr::allocator alc{};
|
||||
auto p = alc.allocate(128);
|
||||
EXPECT_NE(p, nullptr);
|
||||
EXPECT_NO_THROW(alc.dealloc(p, 128));
|
||||
EXPECT_NO_THROW(alc.deallocate(p, 128));
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
class dummy_resource {
|
||||
public:
|
||||
void *allocate(std::size_t, std::size_t = 0) noexcept {
|
||||
return nullptr;
|
||||
}
|
||||
void deallocate(void *, std::size_t, std::size_t = 0) noexcept {
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST(allocator, construct_copy_move) {
|
||||
pmr::new_delete_resource mem_res;
|
||||
dummy_resource dummy_res;
|
||||
pmr::allocator alc1{&mem_res}, alc2{&dummy_res};
|
||||
auto p = alc1.allocate(128);
|
||||
ASSERT_NE(p, nullptr);
|
||||
ASSERT_NO_THROW(alc1.deallocate(p, 128));
|
||||
ASSERT_EQ(alc2.allocate(128), nullptr);
|
||||
|
||||
pmr::allocator alc1 {&mem_res}, alc2;
|
||||
EXPECT_TRUE (alc1.valid());
|
||||
EXPECT_TRUE (alc1);
|
||||
EXPECT_FALSE(alc2.valid());
|
||||
EXPECT_FALSE(alc2);
|
||||
pmr::allocator alc3{alc1}, alc4{alc2}, alc5{std::move(alc1)};
|
||||
|
||||
pmr::allocator alc3 {alc1}, alc4{alc2}, alc5 {std::move(alc1)};
|
||||
EXPECT_TRUE (alc3.valid());
|
||||
EXPECT_TRUE (alc3);
|
||||
EXPECT_FALSE(alc4.valid());
|
||||
EXPECT_FALSE(alc4);
|
||||
EXPECT_TRUE (alc5.valid());
|
||||
EXPECT_TRUE (alc5);
|
||||
EXPECT_FALSE(alc1.valid());
|
||||
EXPECT_FALSE(alc1);
|
||||
p = alc3.allocate(128);
|
||||
ASSERT_NE(p, nullptr);
|
||||
ASSERT_NO_THROW(alc3.deallocate(p, 128));
|
||||
|
||||
ASSERT_EQ(alc4.allocate(128), nullptr);
|
||||
|
||||
p = alc5.allocate(128);
|
||||
ASSERT_NE(p, nullptr);
|
||||
ASSERT_NO_THROW(alc5.deallocate(p, 128));
|
||||
}
|
||||
|
||||
TEST(allocator, swap) {
|
||||
pmr::new_delete_resource mem_res;
|
||||
|
||||
pmr::allocator alc1 {&mem_res}, alc2;
|
||||
EXPECT_TRUE (alc1.valid());
|
||||
EXPECT_TRUE (alc1);
|
||||
EXPECT_FALSE(alc2.valid());
|
||||
EXPECT_FALSE(alc2);
|
||||
|
||||
dummy_resource dummy_res;
|
||||
pmr::allocator alc1{&mem_res}, alc2{&dummy_res};
|
||||
alc1.swap(alc2);
|
||||
EXPECT_FALSE(alc1.valid());
|
||||
EXPECT_FALSE(alc1);
|
||||
EXPECT_TRUE (alc2.valid());
|
||||
EXPECT_TRUE (alc2);
|
||||
auto p = alc2.allocate(128);
|
||||
ASSERT_NE(p, nullptr);
|
||||
ASSERT_NO_THROW(alc2.deallocate(p, 128));
|
||||
ASSERT_EQ(alc1.allocate(128), nullptr);
|
||||
}
|
||||
|
||||
TEST(allocator, invalid_alloc_free) {
|
||||
pmr::new_delete_resource mem_res;
|
||||
pmr::allocator alc1;
|
||||
EXPECT_EQ(alc1.allocate(0), nullptr);
|
||||
EXPECT_NO_THROW(alc1.deallocate(nullptr, 128));
|
||||
EXPECT_NO_THROW(alc1.deallocate(nullptr, 0));
|
||||
EXPECT_NO_THROW(alc1.deallocate(&alc1, 0));
|
||||
}
|
||||
|
||||
pmr::allocator alc1 {&mem_res}, alc2;
|
||||
EXPECT_EQ(alc1.alloc(0), nullptr);
|
||||
EXPECT_NO_THROW(alc1.dealloc(nullptr, 128));
|
||||
EXPECT_NO_THROW(alc1.dealloc(nullptr, 0));
|
||||
EXPECT_NO_THROW(alc1.dealloc(&alc1, 0));
|
||||
|
||||
EXPECT_EQ(alc2.alloc(0), nullptr);
|
||||
EXPECT_NO_THROW(alc2.dealloc(nullptr, 128));
|
||||
EXPECT_NO_THROW(alc2.dealloc(nullptr, 0));
|
||||
EXPECT_NO_THROW(alc2.dealloc(&alc1, 0));
|
||||
|
||||
EXPECT_EQ(alc2.alloc(1024), nullptr);
|
||||
EXPECT_NO_THROW(alc2.dealloc(&alc1, sizeof(alc1)));
|
||||
}
|
||||
TEST(allocator, sizeof) {
|
||||
EXPECT_EQ(sizeof(pmr::allocator), sizeof(void *) * 2);
|
||||
}
|
||||
|
||||
7
test/pmr/test_pmr_small_storage.cpp
Normal file
7
test/pmr/test_pmr_small_storage.cpp
Normal file
@ -0,0 +1,7 @@
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "libpmr/small_storage.h"
|
||||
|
||||
TEST(small_storage, construct) {
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user