Continue to update holders.

This commit is contained in:
mutouyun 2023-09-03 18:11:12 +08:00
parent 5fec1f80ff
commit 6b22006897
12 changed files with 242 additions and 13 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View 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_

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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_

View File

@ -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) {