添加部分有用的小组件

This commit is contained in:
mutouyun 2022-02-27 18:03:30 +08:00
parent c8058022ba
commit 23b7780485
4 changed files with 180 additions and 1 deletions

View File

@ -9,7 +9,10 @@
#include <cstddef> #include <cstddef>
#include <cstdint> #include <cstdint>
#define LIBIPC_NAMESPACE_BEG_ namespace ipc { #if !defined(LIBIPC_NAMESPACE)
# define LIBIPC_NAMESPACE ipc
#endif
#define LIBIPC_NAMESPACE_BEG_ namespace LIBIPC_NAMESPACE {
#define LIBIPC_NAMESPACE_END_ } #define LIBIPC_NAMESPACE_END_ }
LIBIPC_NAMESPACE_BEG_ LIBIPC_NAMESPACE_BEG_

View File

@ -0,0 +1,35 @@
/**
* @file src/construct.h
* @author mutouyun (orz@orzz.org)
* @brief Construct an object from a memory buffer
* @date 2022-02-27
*/
#pragma once
#include <new> // placement-new
#include <type_traits> // std::enable_if_t
#include <utility> // std::forward
#include "libipc/def.h"
LIBIPC_NAMESPACE_BEG_
template <typename T, typename... A>
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)...);
}
template <typename T, typename... A>
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)...};
}
template <typename T>
void *destroy(T *p) noexcept {
p->~T();
return p;
}
LIBIPC_NAMESPACE_END_

View File

@ -0,0 +1,73 @@
/**
* @file src/pimpl.h
* @author mutouyun (orz@orzz.org)
* @brief Pointer To Implementation (pImpl) idiom
* @date 2022-02-27
*/
#pragma once
#include <utility>
#include <type_traits>
#include <cstdint>
#include "libipc/utility/construct.h"
#include "libipc/def.h"
LIBIPC_NAMESPACE_BEG_
namespace pimpl {
template <typename T, typename R = T *>
struct is_comfortable {
enum : bool {
value = (sizeof(T) <= sizeof(R)) && (alignof(T) <= alignof(R))
};
};
template <typename T, typename... A>
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)...);
return buf;
}
template <typename T>
auto get(T * const (& p)) noexcept -> std::enable_if_t<is_comfortable<T>::value, T *> {
return reinterpret_cast<T*>(&const_cast<char &>(reinterpret_cast<char const &>(p)));
}
template <typename T>
auto clear(T *p) noexcept -> std::enable_if_t<is_comfortable<T>::value> {
if (p != nullptr) destroy(get(p));
}
template <typename T, typename... A>
auto make(A &&... args) -> std::enable_if_t<!is_comfortable<T>::value, T *> {
return new T{std::forward<A>(args)...};
}
template <typename T>
auto get(T * const (& p)) noexcept -> std::enable_if_t<!is_comfortable<T>::value, T *> {
return p;
}
template <typename T>
auto clear(T *p) noexcept -> std::enable_if_t<!is_comfortable<T>::value> {
if (p != nullptr) delete p;
}
template <typename T>
class Obj {
public:
template <typename... A>
static T *make(A &&... args) {
return pimpl::make<T>(std::forward<A>(args)...);
}
void clear() noexcept {
pimpl::clear(static_cast<T *>(const_cast<Obj *>(this)));
}
};
} // namespace pimpl
LIBIPC_NAMESPACE_END_

68
test/test_src_utility.cpp Normal file
View File

@ -0,0 +1,68 @@
#include <type_traits> // std::aligned_storage_t
#include <cstdint>
#include "gtest/gtest.h"
#include "libipc/utility/construct.h"
#include "libipc/utility/pimpl.h"
TEST(utility, construct) {
struct Foo {
int a_;
short b_;
char c_;
};
std::aligned_storage_t<sizeof(Foo)> foo;
Foo *pfoo = ipc::construct<Foo>(&foo, 123, short{321}, '1');
EXPECT_EQ(pfoo->a_, 123);
EXPECT_EQ(pfoo->b_, 321);
EXPECT_EQ(pfoo->c_, '1');
struct Bar : Foo {
Bar(int a, short b, char c)
: Foo{a, b, c} {}
};
std::aligned_storage_t<sizeof(Bar)> bar;
Bar *pbar = ipc::construct<Bar>(&bar, 123, short(321), '1');
EXPECT_EQ(pbar->a_, 123);
EXPECT_EQ(pbar->b_, 321);
EXPECT_EQ(pbar->c_, '1');
}
namespace {
struct Foo : ipc::pimpl::Obj<Foo> {
int *pi_;
Foo(int *pi) : pi_(pi) {}
};
struct Bar : ipc::pimpl::Obj<Bar> {
int *pi_;
int *pj_;
Bar(int *pi, int *pj) : pi_(pi), pj_(pj) {}
};
} // namespace
TEST(utility, pimpl_is_comfortable) {
EXPECT_TRUE ((ipc::pimpl::is_comfortable<std::int32_t, std::int64_t>::value));
EXPECT_TRUE ((ipc::pimpl::is_comfortable<std::int64_t, std::int64_t>::value));
EXPECT_FALSE((ipc::pimpl::is_comfortable<std::int64_t, std::int32_t>::value));
EXPECT_TRUE ((ipc::pimpl::is_comfortable<Foo>::value));
EXPECT_FALSE((ipc::pimpl::is_comfortable<Bar>::value));
}
TEST(utility, pimpl_inherit) {
int i = 123;
Foo *pfoo = Foo::make(&i);
EXPECT_EQ(ipc::pimpl::get(pfoo)->pi_, &i);
pfoo->clear();
int j = 321;
Bar *pbar = Bar::make(&i, &j);
EXPECT_EQ(ipc::pimpl::get(pbar)->pi_, &i);
EXPECT_EQ(ipc::pimpl::get(pbar)->pj_, &j);
pbar->clear();
}