mirror of
https://github.com/mutouyun/cpp-ipc.git
synced 2025-12-06 16:56:45 +08:00
Continue to update holders.
This commit is contained in:
parent
c8010e3a51
commit
a50bc78678
@ -11,7 +11,7 @@
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
#include "libimp/construct.h"
|
||||
#include "libimp/uninitialized.h"
|
||||
#include "libimp/detect_plat.h"
|
||||
#include "libimp/aligned.h"
|
||||
|
||||
|
||||
@ -13,7 +13,7 @@
|
||||
#include <cstddef> // std::nullptr_t
|
||||
|
||||
#include "libimp/def.h"
|
||||
#include "libimp/construct.h"
|
||||
#include "libimp/uninitialized.h"
|
||||
#include "libimp/generic.h"
|
||||
#include "libimp/byte.h"
|
||||
|
||||
|
||||
@ -21,6 +21,12 @@ LIBIMP_NAMESPACE_BEG_
|
||||
template <typename...>
|
||||
using void_t = void;
|
||||
|
||||
/**
|
||||
* \brief A type-list for generic programming.
|
||||
*/
|
||||
template <typename...>
|
||||
struct types {};
|
||||
|
||||
/**
|
||||
* \brief To indicate that the contained object should be constructed in-place.
|
||||
* \see https://en.cppreference.com/w/cpp/utility/in_place
|
||||
|
||||
@ -10,7 +10,7 @@
|
||||
#include <type_traits>
|
||||
#include <cstdint>
|
||||
|
||||
#include "libimp/construct.h"
|
||||
#include "libimp/uninitialized.h"
|
||||
#include "libimp/def.h"
|
||||
|
||||
LIBIMP_NAMESPACE_BEG_
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
/**
|
||||
* \file libimp/construct.h
|
||||
* \file libimp/uninitialized.h
|
||||
* \author mutouyun (orz@orzz.org)
|
||||
* \brief Construct an object from a memory buffer
|
||||
* \brief Uninitialized memory algorithms.
|
||||
* \date 2022-02-27
|
||||
*/
|
||||
#pragma once
|
||||
@ -14,6 +14,7 @@
|
||||
|
||||
#include "libimp/def.h"
|
||||
#include "libimp/detect_plat.h"
|
||||
#include "libimp/horrible_cast.h"
|
||||
|
||||
LIBIMP_NAMESPACE_BEG_
|
||||
|
||||
@ -67,4 +68,42 @@ void *destroy(T (*p)[N]) noexcept {
|
||||
return p;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Destroys a range of objects.
|
||||
* \see https://en.cppreference.com/w/cpp/memory/destroy
|
||||
*/
|
||||
template <typename ForwardIt>
|
||||
void destroy(ForwardIt first, ForwardIt last) noexcept {
|
||||
#if defined(LIBIMP_CPP_17)
|
||||
std::destroy(first, last);
|
||||
#else
|
||||
for (; first != last; ++first) {
|
||||
destroy(std::addressof(*first));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Constructs objects by default-initialization
|
||||
* in an uninitialized area of memory, defined by a start and a count.
|
||||
* \see https://en.cppreference.com/w/cpp/memory/uninitialized_default_construct_n
|
||||
*/
|
||||
template <typename ForwardIt, typename Size>
|
||||
ForwardIt uninitialized_default_construct_n(ForwardIt first, Size n) {
|
||||
#if defined(LIBIMP_CPP_17)
|
||||
return std::uninitialized_default_construct_n(first, n);
|
||||
#else
|
||||
using T = typename std::iterator_traits<ForwardIt>::value_type;
|
||||
ForwardIt current = first;
|
||||
LIBIMP_TRY {
|
||||
for (; n > 0; (void) ++current, --n)
|
||||
::new (horrible_cast<void *>(std::addressof(*current))) T;
|
||||
return current;
|
||||
} LIBIMP_CATCH(...) {
|
||||
destroy(first, current);
|
||||
LIBIMP_THROW(, first);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
LIBIMP_NAMESPACE_END_
|
||||
@ -10,7 +10,7 @@
|
||||
#include <array>
|
||||
|
||||
#include "libimp/export.h"
|
||||
#include "libimp/construct.h"
|
||||
#include "libimp/uninitialized.h"
|
||||
#include "libimp/byte.h"
|
||||
|
||||
#include "libpmr/def.h"
|
||||
|
||||
@ -14,28 +14,33 @@
|
||||
#include <cstddef>
|
||||
|
||||
#include "libimp/export.h"
|
||||
#include "libimp/construct.h"
|
||||
#include "libimp/uninitialized.h"
|
||||
#include "libimp/byte.h"
|
||||
#include "libimp/generic.h"
|
||||
|
||||
#include "libpmr/def.h"
|
||||
#include "libpmr/allocator.h"
|
||||
|
||||
LIBPMR_NAMESPACE_BEG_
|
||||
|
||||
class LIBIMP_EXPORT allocator;
|
||||
|
||||
/**
|
||||
* \class holder_base
|
||||
* \brief Data holder base class.
|
||||
*/
|
||||
class holder_base {
|
||||
|
||||
// non-copyable
|
||||
holder_base(holder_base const &) = delete;
|
||||
holder_base &operator=(holder_base const &) = delete;
|
||||
|
||||
public:
|
||||
holder_base() noexcept = default;
|
||||
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 sizeof_heap() 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;
|
||||
|
||||
@ -55,8 +60,8 @@ 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 sizeof_heap() 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; }
|
||||
void move_to(allocator const &, void *) noexcept override {}
|
||||
@ -81,7 +86,7 @@ public:
|
||||
holder() = default; // uninitialized
|
||||
|
||||
template <typename... A>
|
||||
holder(::LIBIMP::in_place_t, A &&...args) {
|
||||
holder(allocator const &, A &&...args) {
|
||||
::LIBIMP::construct<Value>(value_storage_.data(), std::forward<A>(args)...);
|
||||
}
|
||||
|
||||
@ -97,12 +102,12 @@ public:
|
||||
return sizeof(Value);
|
||||
}
|
||||
|
||||
std::size_t count() const noexcept override {
|
||||
return 1;
|
||||
std::size_t sizeof_heap() const noexcept override {
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::size_t size() const noexcept override {
|
||||
return value_storage_.size();
|
||||
std::size_t count() const noexcept override {
|
||||
return 1;
|
||||
}
|
||||
|
||||
void *get() noexcept override {
|
||||
@ -113,16 +118,16 @@ public:
|
||||
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 move_to(allocator const &alloc, void *p) noexcept override {
|
||||
::LIBIMP::construct<holder>(p, alloc, 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()));
|
||||
void copy_to(allocator const &alloc, void *p) const noexcept(false) override {
|
||||
::LIBIMP::construct<holder>(p, alloc, *static_cast<Value const *>(get()));
|
||||
}
|
||||
|
||||
void destroy(allocator const &) noexcept override {
|
||||
::LIBIMP::destroy<Value>(value_storage_.data());
|
||||
::LIBIMP::destroy(static_cast<Value *>(get()));
|
||||
}
|
||||
};
|
||||
|
||||
@ -134,10 +139,177 @@ public:
|
||||
template <typename Value>
|
||||
class holder<Value, false> : public holder_base {
|
||||
|
||||
Value *value_ptr_ = nullptr;
|
||||
Value *value_ptr_;
|
||||
|
||||
public:
|
||||
holder() = default; // uninitialized
|
||||
holder() noexcept : value_ptr_(nullptr) {}
|
||||
|
||||
template <typename... A>
|
||||
holder(allocator const &alloc, A &&...args) {
|
||||
void *p = alloc.allocate(sizeof(Value), alignof(Value));
|
||||
if (p == nullptr) return;
|
||||
value_ptr_ = ::LIBIMP::construct<Value>(p, std::forward<A>(args)...);
|
||||
}
|
||||
|
||||
bool valid() const noexcept override {
|
||||
return value_ptr_ != nullptr;
|
||||
}
|
||||
|
||||
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 sizeof_heap() const noexcept override {
|
||||
return sizeof(Value);
|
||||
}
|
||||
|
||||
std::size_t count() const noexcept override {
|
||||
return 1;
|
||||
}
|
||||
|
||||
void *get() noexcept override {
|
||||
return value_ptr_;
|
||||
}
|
||||
|
||||
void const *get() const noexcept override {
|
||||
return value_ptr_;
|
||||
}
|
||||
|
||||
void move_to(allocator const &alloc, void *p) noexcept override {
|
||||
if (value_ptr_ == nullptr) {
|
||||
::LIBIMP::construct<holder>(p);
|
||||
return;
|
||||
}
|
||||
::LIBIMP::construct<holder>(p, alloc, std::move(*value_ptr_));
|
||||
}
|
||||
|
||||
void copy_to(allocator const &alloc, void *p) const noexcept(false) override {
|
||||
if (value_ptr_ == nullptr) {
|
||||
::LIBIMP::construct<holder>(p);
|
||||
return;
|
||||
}
|
||||
::LIBIMP::construct<holder>(p, alloc, *value_ptr_);
|
||||
}
|
||||
|
||||
void destroy(allocator const &alloc) noexcept override {
|
||||
alloc.deallocate(::LIBIMP::destroy(value_ptr_), sizeof(Value), alignof(Value));
|
||||
}
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
|
||||
struct holder_info {
|
||||
std::type_info const *type;
|
||||
std::size_t sizeof_type;
|
||||
std::size_t count;
|
||||
void (*copy)(allocator const &, void const *s, void *d);
|
||||
};
|
||||
|
||||
template <typename Value, typename Construct>
|
||||
void *holder_construct(allocator const &alloc, std::size_t n, Construct &&c) {
|
||||
void *p = alloc.allocate(n * sizeof(Value));
|
||||
if (p == nullptr) return nullptr;
|
||||
LIBIMP_TRY {
|
||||
std::forward<Construct>(c)(static_cast<Value *>(p), n);
|
||||
return p;
|
||||
} LIBIMP_CATCH(...) {
|
||||
alloc.deallocate(p, n * sizeof(Value));
|
||||
LIBIMP_THROW(, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
/**
|
||||
* \class template <> holder<void, true>
|
||||
* \brief A holder implementation of some data objects that stores type information on stack memory.
|
||||
*/
|
||||
template <>
|
||||
class holder<void, true> : public holder_base {
|
||||
|
||||
detail::holder_info info_;
|
||||
void *value_ptr_;
|
||||
|
||||
public:
|
||||
holder() noexcept
|
||||
: info_{&typeid(nullptr)}
|
||||
, value_ptr_(nullptr) {}
|
||||
|
||||
/// \brief Constructs a holder with type of `Value`.
|
||||
/// alignof(Value) must be less than or equal to alignof(std::max_align_t).
|
||||
template <typename Value,
|
||||
std::enable_if_t<alignof(Value) <= alignof(std::max_align_t), bool> = true>
|
||||
holder(allocator const &alloc, ::LIBIMP::types<Value>, std::size_t n) : holder() {
|
||||
value_ptr_ = detail::holder_construct<Value>(alloc, n,
|
||||
::LIBIMP::uninitialized_default_construct_n<Value *, std::size_t>);
|
||||
if (value_ptr_ == nullptr) return;
|
||||
info_.type = &typeid(Value);
|
||||
info_.sizeof_type = sizeof(Value);
|
||||
info_.count = n;
|
||||
info_.copy = [](allocator const &alloc, void const *s, void *d) {
|
||||
auto const &src = *static_cast<holder const *>(s);
|
||||
auto & dst = *::LIBIMP::construct<holder>(d);
|
||||
if (!src.valid()) return;
|
||||
dst.value_ptr_ = detail::holder_construct<Value>(alloc, src.count(), [s = src.get()](Value *d, std::size_t n) {
|
||||
std::uninitialized_copy_n(static_cast<Value const *>(s), n, d);
|
||||
});
|
||||
if (dst.value_ptr_ == nullptr) return;
|
||||
dst.info_ = src.info_;
|
||||
};
|
||||
}
|
||||
|
||||
bool valid() const noexcept override {
|
||||
return value_ptr_ != nullptr;
|
||||
}
|
||||
|
||||
std::type_info const &type() const noexcept override {
|
||||
return *info_.type;
|
||||
}
|
||||
|
||||
std::size_t sizeof_type() const noexcept override {
|
||||
return info_.sizeof_type;
|
||||
}
|
||||
|
||||
std::size_t sizeof_heap() const noexcept override {
|
||||
return info_.sizeof_type * info_.count;
|
||||
}
|
||||
|
||||
std::size_t count() const noexcept override {
|
||||
return info_.count;
|
||||
}
|
||||
|
||||
void *get() noexcept override {
|
||||
return value_ptr_;
|
||||
}
|
||||
|
||||
void const *get() const noexcept override {
|
||||
return value_ptr_;
|
||||
}
|
||||
|
||||
void move_to(allocator const &, void *p) noexcept override {
|
||||
auto *des = ::LIBIMP::construct<holder>(p);
|
||||
if (value_ptr_ == nullptr) {
|
||||
return;
|
||||
}
|
||||
std::swap(value_ptr_, des->value_ptr_);
|
||||
std::swap(info_, des->info_);
|
||||
}
|
||||
|
||||
void copy_to(allocator const &alloc, void *p) const noexcept(false) override {
|
||||
auto *des = ::LIBIMP::construct<holder>(p);
|
||||
if (value_ptr_ == nullptr) {
|
||||
return;
|
||||
}
|
||||
info_.copy(alloc, this, des);
|
||||
}
|
||||
|
||||
void destroy(allocator const &alloc) noexcept override {
|
||||
alloc.deallocate(::LIBIMP::destroy(value_ptr_), info_.sizeof_type * info_.count);
|
||||
}
|
||||
};
|
||||
|
||||
LIBPMR_NAMESPACE_END_
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "libimp/construct.h"
|
||||
#include "libimp/uninitialized.h"
|
||||
#include "libimp/pimpl.h"
|
||||
#include "libimp/countof.h"
|
||||
#include "libimp/dataof.h"
|
||||
|
||||
@ -1,7 +1,86 @@
|
||||
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "libpmr/small_storage.h"
|
||||
|
||||
TEST(small_storage, holder_construct) {
|
||||
pmr::holder_null();
|
||||
pmr::holder<int, true>();
|
||||
pmr::holder<int, false>();
|
||||
pmr::holder<void, true>();
|
||||
SUCCEED();
|
||||
}
|
||||
|
||||
TEST(small_storage, holder_copy_move_construct) {
|
||||
EXPECT_FALSE(std::is_copy_constructible<pmr::holder_null>::value);
|
||||
EXPECT_FALSE((std::is_copy_constructible<pmr::holder<int, true>>::value));
|
||||
EXPECT_FALSE((std::is_copy_constructible<pmr::holder<int, false>>::value));
|
||||
EXPECT_FALSE((std::is_copy_constructible<pmr::holder<void, true>>::value));
|
||||
|
||||
EXPECT_FALSE(std::is_copy_assignable<pmr::holder_null>::value);
|
||||
EXPECT_FALSE((std::is_copy_assignable<pmr::holder<int, true>>::value));
|
||||
EXPECT_FALSE((std::is_copy_assignable<pmr::holder<int, false>>::value));
|
||||
EXPECT_FALSE((std::is_copy_assignable<pmr::holder<void, true>>::value));
|
||||
|
||||
EXPECT_FALSE(std::is_move_constructible<pmr::holder_null>::value);
|
||||
EXPECT_FALSE((std::is_move_constructible<pmr::holder<int, true>>::value));
|
||||
EXPECT_FALSE((std::is_move_constructible<pmr::holder<int, false>>::value));
|
||||
EXPECT_FALSE((std::is_move_constructible<pmr::holder<void, true>>::value));
|
||||
|
||||
EXPECT_FALSE(std::is_move_assignable<pmr::holder_null>::value);
|
||||
EXPECT_FALSE((std::is_move_assignable<pmr::holder<int, true>>::value));
|
||||
EXPECT_FALSE((std::is_move_assignable<pmr::holder<int, false>>::value));
|
||||
EXPECT_FALSE((std::is_move_assignable<pmr::holder<void, true>>::value));
|
||||
}
|
||||
|
||||
TEST(small_storage, holder_copy_move) {
|
||||
struct foo {
|
||||
int i;
|
||||
foo(int i) : i(i) {}
|
||||
foo(foo const &rhs) : i(rhs.i) {}
|
||||
foo(foo &&rhs) : i(std::exchange(rhs.i, 0)) {}
|
||||
};
|
||||
|
||||
pmr::allocator alc;
|
||||
pmr::holder<foo, true> h1(alc, 1);
|
||||
pmr::holder<foo, true> h2, h3; // uninitialized
|
||||
h1.copy_to(alc, &h2);
|
||||
EXPECT_EQ(static_cast<foo *>(h1.get())->i, 1);
|
||||
EXPECT_EQ(static_cast<foo *>(h2.get())->i, 1);
|
||||
h1.move_to(alc, &h3);
|
||||
EXPECT_EQ(static_cast<foo *>(h1.get())->i, 0);
|
||||
EXPECT_EQ(static_cast<foo *>(h3.get())->i, 1);
|
||||
h1.destroy(alc);
|
||||
h2.destroy(alc);
|
||||
h3.destroy(alc);
|
||||
|
||||
pmr::holder<foo, false> h4(alc, 1);
|
||||
pmr::holder<foo, false> h5, h6; // uninitialized
|
||||
h4.copy_to(alc, &h5);
|
||||
EXPECT_EQ(static_cast<foo *>(h4.get())->i, 1);
|
||||
EXPECT_EQ(static_cast<foo *>(h5.get())->i, 1);
|
||||
h4.move_to(alc, &h6);
|
||||
EXPECT_EQ(static_cast<foo *>(h4.get())->i, 0);
|
||||
EXPECT_EQ(static_cast<foo *>(h6.get())->i, 1);
|
||||
h4.destroy(alc);
|
||||
h5.destroy(alc);
|
||||
h6.destroy(alc);
|
||||
|
||||
pmr::holder<void, true> h7(alc, ::LIBIMP::types<int>{}, 10);
|
||||
pmr::holder<void, true> h8, h9; // uninitialized
|
||||
h7.copy_to(alc, &h8);
|
||||
EXPECT_EQ(h7.count(), 10);
|
||||
EXPECT_EQ(h8.count(), 10);
|
||||
h7.move_to(alc, &h9);
|
||||
EXPECT_EQ(h7.count(), 0);
|
||||
EXPECT_EQ(h9.count(), 10);
|
||||
h7.destroy(alc);
|
||||
h8.destroy(alc);
|
||||
h9.destroy(alc);
|
||||
}
|
||||
|
||||
TEST(small_storage, construct) {
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user