mirror of
https://github.com/mutouyun/cpp-ipc.git
synced 2025-12-07 01:06:45 +08:00
添加部分有用的小组件
This commit is contained in:
parent
c8058022ba
commit
23b7780485
@ -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_
|
||||||
|
|||||||
35
src/libipc/utility/construct.h
Normal file
35
src/libipc/utility/construct.h
Normal 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_
|
||||||
73
src/libipc/utility/pimpl.h
Normal file
73
src/libipc/utility/pimpl.h
Normal 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
68
test/test_src_utility.cpp
Normal 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();
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user