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
5fec1f80ff
commit
6b22006897
@ -1,7 +1,7 @@
|
||||
/**
|
||||
* \file libimp/codecvt.h
|
||||
* \author mutouyun (orz@orzz.org)
|
||||
* \brief Character set conversion interface
|
||||
* \brief Character set conversion interface.
|
||||
* \date 2022-08-07
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
/**
|
||||
* \file libimp/countof.h
|
||||
* \author mutouyun (orz@orzz.org)
|
||||
* \brief Returns the size of the given range
|
||||
* \brief Returns the size of the given range.
|
||||
* \date 2022-03-01
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
/**
|
||||
* \file libimp/dataof.h
|
||||
* \author mutouyun (orz@orzz.org)
|
||||
* \brief Returns the data pointer of the given range
|
||||
* \brief Returns the data pointer of the given range.
|
||||
* \date 2023-05-27
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
/**
|
||||
* \file libimp/export.h
|
||||
* \author mutouyun (orz@orzz.org)
|
||||
* \brief Define the symbol export interfaces
|
||||
* \brief Define the symbol export interfaces.
|
||||
* \date 2022-02-27
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
/**
|
||||
* \file libimp/pimpl.h
|
||||
* \author mutouyun (orz@orzz.org)
|
||||
* \brief Pointer To Implementation (pImpl) idiom
|
||||
* \brief Pointer To Implementation (pImpl) idiom.
|
||||
* \date 2022-02-27
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
/**
|
||||
* \file libimp/result.h
|
||||
* \author mutouyun (orz@orzz.org)
|
||||
* \brief Define the return value type with a status code
|
||||
* \brief Define the return value type with a status code.
|
||||
* \date 2022-04-17
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
78
include/libimp/scope_exit.h
Normal file
78
include/libimp/scope_exit.h
Normal file
@ -0,0 +1,78 @@
|
||||
/**
|
||||
* \file libimp/scope_exit.h
|
||||
* \author mutouyun (orz@orzz.org)
|
||||
* \brief Execute guard function when the enclosing scope exits.
|
||||
* \date 2022-03-01
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <utility> // std::forward, std::move
|
||||
#include <functional> // std::function
|
||||
#include <type_traits>
|
||||
|
||||
#include "libimp/def.h"
|
||||
|
||||
LIBIMP_NAMESPACE_BEG_
|
||||
|
||||
template <typename F = std::function<void()>>
|
||||
class scope_exit {
|
||||
F destructor_;
|
||||
mutable bool released_;
|
||||
|
||||
public:
|
||||
template <typename G>
|
||||
explicit scope_exit(G &&destructor) noexcept
|
||||
: destructor_(std::forward<G>(destructor))
|
||||
, released_ (false) {}
|
||||
|
||||
scope_exit(scope_exit &&other) noexcept
|
||||
: destructor_(std::move(other.destructor_))
|
||||
, released_ (std::exchange(other.released_, true)) /*release rhs*/ {}
|
||||
|
||||
scope_exit &operator=(scope_exit &&other) noexcept {
|
||||
destructor_ = std::move(other.destructor_);
|
||||
released_ = std::exchange(other.released_, true);
|
||||
return *this;
|
||||
}
|
||||
|
||||
~scope_exit() noexcept {
|
||||
if (!released_) destructor_();
|
||||
}
|
||||
|
||||
void release() const noexcept {
|
||||
released_ = true;
|
||||
}
|
||||
|
||||
void do_exit() noexcept {
|
||||
if (released_) return;
|
||||
destructor_();
|
||||
released_ = true;
|
||||
}
|
||||
|
||||
void swap(scope_exit &other) noexcept {
|
||||
std::swap(destructor_, other.destructor_);
|
||||
std::swap(released_ , other.released_);
|
||||
}
|
||||
};
|
||||
|
||||
/// \brief Creates a scope_exit object.
|
||||
template <typename F>
|
||||
auto make_scope_exit(F &&destructor) noexcept {
|
||||
return scope_exit<std::decay_t<F>>(std::forward<F>(destructor));
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
|
||||
struct scope_exit_helper {
|
||||
template <typename F>
|
||||
auto operator=(F &&f) const noexcept {
|
||||
return make_scope_exit(std::forward<F>(f));
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
#define LIBIMP_SCOPE_EXIT($val) \
|
||||
auto $val = ::LIBIMP::detail::scope_exit_helper{}
|
||||
|
||||
LIBIMP_NAMESPACE_END_
|
||||
@ -1,7 +1,7 @@
|
||||
/**
|
||||
* \file libimp/span.h
|
||||
* \author mutouyun (orz@orzz.org)
|
||||
* \brief Describes an object that can refer to a contiguous sequence of objects
|
||||
* \brief Describes an object that can refer to a contiguous sequence of objects.
|
||||
* \date 2022-10-16
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
/**
|
||||
* \file libimp/system.h
|
||||
* \author mutouyun (orz@orzz.org)
|
||||
* \brief Isolation and encapsulation of system APIs
|
||||
* \brief Isolation and encapsulation of system APIs.
|
||||
* \date 2022-08-07
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
/**
|
||||
* \file libimp/underlyof.h
|
||||
* \author mutouyun (orz@orzz.org)
|
||||
* \brief Returns the underlying type of the given enum
|
||||
* \brief Returns the underlying type of the given enum.
|
||||
* \date 2022-03-01
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
@ -223,6 +223,39 @@ void *holder_construct(allocator const &alloc, std::size_t n, Construct &&c) {
|
||||
}
|
||||
}
|
||||
|
||||
class holder_info_ptr {
|
||||
allocator const &alloc_;
|
||||
holder_info **pptr_;
|
||||
|
||||
public:
|
||||
holder_info_ptr(allocator const &alloc, holder_info *(&ptr)) noexcept
|
||||
: alloc_(alloc), pptr_(&ptr) {
|
||||
*pptr_ = static_cast<holder_info *>(alloc_.allocate(sizeof(holder_info), alignof(holder_info)));
|
||||
}
|
||||
|
||||
~holder_info_ptr() noexcept {
|
||||
if (pptr_ == nullptr) return;
|
||||
alloc_.deallocate(*pptr_, sizeof(holder_info), alignof(holder_info));
|
||||
*pptr_ = nullptr;
|
||||
}
|
||||
|
||||
explicit operator bool() const noexcept {
|
||||
return (pptr_ != nullptr) && (*pptr_ != nullptr);
|
||||
}
|
||||
|
||||
holder_info *operator->() const noexcept {
|
||||
return *pptr_;
|
||||
}
|
||||
|
||||
holder_info &operator*() noexcept {
|
||||
return **pptr_;
|
||||
}
|
||||
|
||||
void release() noexcept {
|
||||
pptr_ = nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
/**
|
||||
@ -271,6 +304,7 @@ public:
|
||||
}
|
||||
|
||||
std::type_info const &type() const noexcept override {
|
||||
if (!valid()) return typeid(nullptr);
|
||||
return *info_.type;
|
||||
}
|
||||
|
||||
@ -314,4 +348,104 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* \class template <> holder<void, false>
|
||||
* \brief A holder implementation of some data objects that stores type information on heap memory.
|
||||
*/
|
||||
template <>
|
||||
class holder<void, false> : public holder_base {
|
||||
|
||||
detail::holder_info *info_ptr_;
|
||||
void *value_ptr_;
|
||||
|
||||
public:
|
||||
holder() noexcept
|
||||
: info_ptr_ (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() {
|
||||
detail::holder_info_ptr info_p{alloc, info_ptr_};
|
||||
if (!info_p) return;
|
||||
value_ptr_ = detail::holder_construct<Value>(alloc, n,
|
||||
::LIBIMP::uninitialized_default_construct_n<Value *, std::size_t>);
|
||||
if (value_ptr_ == nullptr) return;
|
||||
info_p->type = &typeid(Value);
|
||||
info_p->sizeof_type = sizeof(Value);
|
||||
info_p->count = n;
|
||||
info_p->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;
|
||||
detail::holder_info_ptr info_p{alloc, dst.info_ptr_};
|
||||
if (!info_p) 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;
|
||||
*info_p = *src.info_ptr_;
|
||||
info_p.release();
|
||||
};
|
||||
info_p->dest = [](void *p, std::size_t n) noexcept {
|
||||
::LIBIMP::destroy_n(static_cast<Value *>(p), n);
|
||||
};
|
||||
info_p.release();
|
||||
}
|
||||
|
||||
bool valid() const noexcept override {
|
||||
return (value_ptr_ != nullptr) && (info_ptr_ != nullptr);
|
||||
}
|
||||
|
||||
std::type_info const &type() const noexcept override {
|
||||
if (!valid()) return typeid(nullptr);
|
||||
return *info_ptr_->type;
|
||||
}
|
||||
|
||||
std::size_t sizeof_type() const noexcept override {
|
||||
if (!valid()) return 0;
|
||||
return info_ptr_->sizeof_type;
|
||||
}
|
||||
|
||||
std::size_t sizeof_heap() const noexcept override {
|
||||
if (!valid()) return 0;
|
||||
return info_ptr_->sizeof_type * info_ptr_->count + sizeof(detail::holder_info);
|
||||
}
|
||||
|
||||
std::size_t count() const noexcept override {
|
||||
if (!valid()) return 0;
|
||||
return info_ptr_->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 (!valid()) return;
|
||||
std::swap(value_ptr_, des->value_ptr_);
|
||||
std::swap(info_ptr_ , des->info_ptr_);
|
||||
}
|
||||
|
||||
void copy_to(allocator const &alloc, void *p) const noexcept(false) override {
|
||||
auto *des = ::LIBIMP::construct<holder>(p);
|
||||
if (!valid()) return;
|
||||
info_ptr_->copy(alloc, this, des);
|
||||
}
|
||||
|
||||
void destroy(allocator const &alloc) noexcept override {
|
||||
if (!valid()) return;
|
||||
info_ptr_->dest (value_ptr_, count());
|
||||
alloc.deallocate(value_ptr_, sizeof_heap());
|
||||
alloc.deallocate(info_ptr_ , sizeof(detail::holder_info), alignof(detail::holder_info));
|
||||
}
|
||||
};
|
||||
|
||||
LIBPMR_NAMESPACE_END_
|
||||
|
||||
@ -11,6 +11,7 @@ TEST(small_storage, holder_construct) {
|
||||
pmr::holder<int, true>();
|
||||
pmr::holder<int, false>();
|
||||
pmr::holder<void, true>();
|
||||
pmr::holder<void, false>();
|
||||
SUCCEED();
|
||||
}
|
||||
|
||||
@ -19,21 +20,25 @@ TEST(small_storage, holder_copy_move_construct) {
|
||||
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_constructible<pmr::holder<void, false>>::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_copy_assignable<pmr::holder<void, false>>::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_constructible<pmr::holder<void, false>>::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));
|
||||
EXPECT_FALSE((std::is_move_assignable<pmr::holder<void, false>>::value));
|
||||
}
|
||||
|
||||
TEST(small_storage, holder_copy_move) {
|
||||
@ -46,7 +51,7 @@ TEST(small_storage, holder_copy_move) {
|
||||
|
||||
pmr::allocator alc;
|
||||
pmr::holder<foo, true> h1(alc, 1);
|
||||
pmr::holder<foo, true> h2, h3; // uninitialized
|
||||
pmr::holder<foo, true> h2, h3;
|
||||
h1.copy_to(alc, &h2);
|
||||
EXPECT_EQ(static_cast<foo *>(h1.get())->i, 1);
|
||||
EXPECT_EQ(static_cast<foo *>(h2.get())->i, 1);
|
||||
@ -58,7 +63,7 @@ TEST(small_storage, holder_copy_move) {
|
||||
h3.destroy(alc);
|
||||
|
||||
pmr::holder<foo, false> h4(alc, 1);
|
||||
pmr::holder<foo, false> h5, h6; // uninitialized
|
||||
pmr::holder<foo, false> h5, h6;
|
||||
h4.copy_to(alc, &h5);
|
||||
EXPECT_EQ(static_cast<foo *>(h4.get())->i, 1);
|
||||
EXPECT_EQ(static_cast<foo *>(h5.get())->i, 1);
|
||||
@ -70,7 +75,7 @@ TEST(small_storage, holder_copy_move) {
|
||||
h6.destroy(alc);
|
||||
|
||||
pmr::holder<void, true> h7(alc, ::LIBIMP::types<int>{}, 10);
|
||||
pmr::holder<void, true> h8, h9; // uninitialized
|
||||
pmr::holder<void, true> h8, h9;
|
||||
h7.copy_to(alc, &h8);
|
||||
EXPECT_EQ(h7.count(), 10);
|
||||
EXPECT_EQ(h8.count(), 10);
|
||||
@ -80,6 +85,18 @@ TEST(small_storage, holder_copy_move) {
|
||||
h7.destroy(alc);
|
||||
h8.destroy(alc);
|
||||
h9.destroy(alc);
|
||||
|
||||
pmr::holder<void, false> h10(alc, ::LIBIMP::types<int>{}, 10);
|
||||
pmr::holder<void, false> h11, h12;
|
||||
h10.copy_to(alc, &h11);
|
||||
EXPECT_EQ(h10.count(), 10);
|
||||
EXPECT_EQ(h11.count(), 10);
|
||||
h10.move_to(alc, &h12);
|
||||
EXPECT_EQ(h10.count(), 0);
|
||||
EXPECT_EQ(h12.count(), 10);
|
||||
h10.destroy(alc);
|
||||
h11.destroy(alc);
|
||||
h12.destroy(alc);
|
||||
}
|
||||
|
||||
TEST(small_storage, construct) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user