mirror of
https://github.com/mutouyun/cpp-ipc.git
synced 2025-12-07 01:06:45 +08:00
pimpl small object optimization
This commit is contained in:
parent
69cfad56c3
commit
1e44d6f84e
@ -3,7 +3,8 @@
|
|||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
#include <thread>
|
#include <type_traits>
|
||||||
|
#include <new>
|
||||||
|
|
||||||
namespace ipc {
|
namespace ipc {
|
||||||
|
|
||||||
@ -25,8 +26,65 @@ using uint_t = typename uint<N>::type;
|
|||||||
// constants
|
// constants
|
||||||
|
|
||||||
enum : std::size_t {
|
enum : std::size_t {
|
||||||
error_count = std::numeric_limits<std::size_t>::max(),
|
error_count = (std::numeric_limits<std::size_t>::max)(),
|
||||||
data_length = 16
|
data_length = 16
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// concept helpers
|
||||||
|
|
||||||
|
template <bool Cond, typename R>
|
||||||
|
using Requires = std::enable_if_t<Cond, R>;
|
||||||
|
|
||||||
|
// pimpl small object optimization helpers
|
||||||
|
|
||||||
|
template <typename T, typename R = T*>
|
||||||
|
using IsImplComfortable = Requires<(sizeof(T) <= sizeof(T*)), R>;
|
||||||
|
|
||||||
|
template <typename T, typename R = T*>
|
||||||
|
using IsImplUncomfortable = Requires<(sizeof(T) > sizeof(T*)), R>;
|
||||||
|
|
||||||
|
template <typename T, typename... P>
|
||||||
|
constexpr auto make_impl(P&&... params) -> IsImplComfortable<T> {
|
||||||
|
T* buf {};
|
||||||
|
::new (&buf) T { std::forward<P>(params)... };
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
constexpr auto impl(T* const (& p)) -> IsImplComfortable<T> {
|
||||||
|
return reinterpret_cast<T*>(&const_cast<char &>(reinterpret_cast<char const &>(p)));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
constexpr auto clear_impl(T* p) -> IsImplComfortable<T, void> {
|
||||||
|
impl(p)->~T();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename... P>
|
||||||
|
constexpr auto make_impl(P&&... params) -> IsImplUncomfortable<T> {
|
||||||
|
return new T { std::forward<P>(params)... };
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
constexpr auto clear_impl(T* p) -> IsImplUncomfortable<T, void> {
|
||||||
|
delete p;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
constexpr auto impl(T* const (& p)) -> IsImplUncomfortable<T> {
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct pimpl {
|
||||||
|
template <typename... P>
|
||||||
|
constexpr static T* make(P&&... params) {
|
||||||
|
return make_impl<T>(std::forward<P>(params)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr void clear() {
|
||||||
|
clear_impl(static_cast<T*>(this));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace ipc
|
} // namespace ipc
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
|
#include <thread>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
|
||||||
|
|||||||
16
src/ipc.cpp
16
src/ipc.cpp
@ -10,6 +10,7 @@
|
|||||||
#include <shared_mutex>
|
#include <shared_mutex>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
|
||||||
|
#include "def.h"
|
||||||
#include "circ_queue.h"
|
#include "circ_queue.h"
|
||||||
#include "rw_lock.h"
|
#include "rw_lock.h"
|
||||||
|
|
||||||
@ -151,14 +152,14 @@ std::vector<byte_t> recv(handle_t h) {
|
|||||||
} while(1);
|
} while(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
class channel::channel_ {
|
class channel::channel_ : public pimpl<channel_> {
|
||||||
public:
|
public:
|
||||||
handle_t h_ = nullptr;
|
handle_t h_ = nullptr;
|
||||||
std::string n_;
|
std::string n_;
|
||||||
};
|
};
|
||||||
|
|
||||||
channel::channel(void)
|
channel::channel(void)
|
||||||
: p_(new channel_) {
|
: p_(p_->make()) {
|
||||||
}
|
}
|
||||||
|
|
||||||
channel::channel(char const * name)
|
channel::channel(char const * name)
|
||||||
@ -172,7 +173,7 @@ channel::channel(channel&& rhs)
|
|||||||
}
|
}
|
||||||
|
|
||||||
channel::~channel(void) {
|
channel::~channel(void) {
|
||||||
delete p_;
|
p_->clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void channel::swap(channel& rhs) {
|
void channel::swap(channel& rhs) {
|
||||||
@ -185,11 +186,11 @@ channel& channel::operator=(channel rhs) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool channel::valid(void) const {
|
bool channel::valid(void) const {
|
||||||
return (p_ != nullptr) && (p_->h_ != nullptr);
|
return (impl(p_)->h_ != nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
char const * channel::name(void) const {
|
char const * channel::name(void) const {
|
||||||
return (p_ == nullptr) ? "" : p_->n_.c_str();
|
return impl(p_)->n_.c_str();
|
||||||
}
|
}
|
||||||
|
|
||||||
channel channel::clone(void) const {
|
channel channel::clone(void) const {
|
||||||
@ -197,15 +198,14 @@ channel channel::clone(void) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool channel::connect(char const * name) {
|
bool channel::connect(char const * name) {
|
||||||
if (p_ == nullptr) return false;
|
|
||||||
this->disconnect();
|
this->disconnect();
|
||||||
p_->h_ = ipc::connect((p_->n_ = name).c_str());
|
impl(p_)->h_ = ipc::connect((impl(p_)->n_ = name).c_str());
|
||||||
return valid();
|
return valid();
|
||||||
}
|
}
|
||||||
|
|
||||||
void channel::disconnect(void) {
|
void channel::disconnect(void) {
|
||||||
if (!valid()) return;
|
if (!valid()) return;
|
||||||
ipc::disconnect(p_->h_);
|
ipc::disconnect(impl(p_)->h_);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace ipc
|
} // namespace ipc
|
||||||
|
|||||||
@ -8,10 +8,12 @@
|
|||||||
#include <codecvt>
|
#include <codecvt>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
|
#include "def.h"
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
template <typename T, typename S, typename R = S>
|
template <typename T, typename S, typename R = S>
|
||||||
using IsSame = std::enable_if_t<std::is_same<T, typename S::value_type>::value, R>;
|
using IsSame = ipc::Requires<std::is_same<T, typename S::value_type>::value, R>;
|
||||||
|
|
||||||
template <typename T = TCHAR>
|
template <typename T = TCHAR>
|
||||||
constexpr auto to_tchar(std::string && str) -> IsSame<T, std::string, std::string &&> {
|
constexpr auto to_tchar(std::string && str) -> IsSame<T, std::string, std::string &&> {
|
||||||
@ -19,7 +21,7 @@ constexpr auto to_tchar(std::string && str) -> IsSame<T, std::string, std::strin
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename T = TCHAR>
|
template <typename T = TCHAR>
|
||||||
inline auto to_tchar(std::string && str) -> IsSame<T, std::wstring> {
|
constexpr auto to_tchar(std::string && str) -> IsSame<T, std::wstring> {
|
||||||
return std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>>{}.from_bytes(std::move(str));
|
return std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>>{}.from_bytes(std::move(str));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
42
src/shm.cpp
42
src/shm.cpp
@ -3,18 +3,23 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
|
#include "def.h"
|
||||||
|
|
||||||
namespace ipc {
|
namespace ipc {
|
||||||
namespace shm {
|
namespace shm {
|
||||||
|
|
||||||
class handle::handle_ {
|
class handle::handle_ : public pimpl<handle_> {
|
||||||
public:
|
public:
|
||||||
handle* t_ = nullptr;
|
handle* t_ = nullptr;
|
||||||
handle_t h_ = nullptr;
|
handle_t h_ = nullptr;
|
||||||
void* m_ = nullptr;
|
void* m_ = nullptr;
|
||||||
|
|
||||||
std::string n_;
|
std::string n_ {};
|
||||||
std::size_t s_ = 0;
|
std::size_t s_ = 0;
|
||||||
|
|
||||||
|
handle_() = default;
|
||||||
|
handle_(handle* t) : t_{t} {}
|
||||||
|
|
||||||
~handle_(void) {
|
~handle_(void) {
|
||||||
t_->close();
|
t_->close();
|
||||||
t_->release();
|
t_->release();
|
||||||
@ -22,8 +27,7 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
handle::handle(void)
|
handle::handle(void)
|
||||||
: p_(new handle_) {
|
: p_(p_->make(this)) {
|
||||||
p_->t_ = this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
handle::handle(char const * name, std::size_t size)
|
handle::handle(char const * name, std::size_t size)
|
||||||
@ -37,7 +41,7 @@ handle::handle(handle&& rhs)
|
|||||||
}
|
}
|
||||||
|
|
||||||
handle::~handle(void) {
|
handle::~handle(void) {
|
||||||
delete p_;
|
p_->clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void handle::swap(handle& rhs) {
|
void handle::swap(handle& rhs) {
|
||||||
@ -50,45 +54,45 @@ handle& handle::operator=(handle rhs) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool handle::valid(void) const {
|
bool handle::valid(void) const {
|
||||||
return (p_ != nullptr) && (p_->h_ != nullptr);
|
return impl(p_)->h_ != nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::size_t handle::size(void) const {
|
std::size_t handle::size(void) const {
|
||||||
return (p_ == nullptr) ? 0 : p_->s_;
|
return impl(p_)->s_;
|
||||||
}
|
}
|
||||||
|
|
||||||
char const * handle::name(void) const {
|
char const * handle::name(void) const {
|
||||||
return (p_ == nullptr) ? "" : p_->n_.c_str();
|
return impl(p_)->n_.c_str();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool handle::acquire(char const * name, std::size_t size) {
|
bool handle::acquire(char const * name, std::size_t size) {
|
||||||
if (p_ == nullptr) return false;
|
|
||||||
close();
|
close();
|
||||||
release();
|
release();
|
||||||
p_->h_ = shm::acquire((p_->n_ = name).c_str(), p_->s_ = size);
|
impl(p_)->h_ = shm::acquire((impl(p_)->n_ = name).c_str(),
|
||||||
|
impl(p_)->s_ = size);
|
||||||
return valid();
|
return valid();
|
||||||
}
|
}
|
||||||
|
|
||||||
void handle::release(void) {
|
void handle::release(void) {
|
||||||
if (!valid()) return;
|
if (!valid()) return;
|
||||||
shm::release(p_->h_, p_->s_);
|
shm::release(impl(p_)->h_, impl(p_)->s_);
|
||||||
p_->h_ = nullptr;
|
impl(p_)->h_ = nullptr;
|
||||||
p_->s_ = 0;
|
impl(p_)->s_ = 0;
|
||||||
p_->n_.clear();
|
impl(p_)->n_.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void* handle::get(void) {
|
void* handle::get(void) {
|
||||||
if (!valid()) return nullptr;
|
if (!valid()) return nullptr;
|
||||||
if (p_->m_ == nullptr) {
|
if (impl(p_)->m_ == nullptr) {
|
||||||
return p_->m_ = shm::open(p_->h_);
|
return impl(p_)->m_ = shm::open(impl(p_)->h_);
|
||||||
}
|
}
|
||||||
else return p_->m_;
|
else return impl(p_)->m_;
|
||||||
}
|
}
|
||||||
|
|
||||||
void handle::close(void) {
|
void handle::close(void) {
|
||||||
if (!valid()) return;
|
if (!valid()) return;
|
||||||
shm::close(p_->m_);
|
shm::close(impl(p_)->m_);
|
||||||
p_->m_ = nullptr;
|
impl(p_)->m_ = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace shm
|
} // namespace shm
|
||||||
|
|||||||
@ -29,6 +29,7 @@ class Unit : public TestSuite {
|
|||||||
private slots:
|
private slots:
|
||||||
void test_rw_lock();
|
void test_rw_lock();
|
||||||
void test_send_recv();
|
void test_send_recv();
|
||||||
|
void test_channel();
|
||||||
} unit__;
|
} unit__;
|
||||||
|
|
||||||
#include "test_ipc.moc"
|
#include "test_ipc.moc"
|
||||||
@ -44,7 +45,7 @@ struct lc_wrapper : Mutex {
|
|||||||
void unlock_shared() { Mutex::unlock(); }
|
void unlock_shared() { Mutex::unlock(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename Lc, int W, int R, int Loops = 1000000>
|
template <typename Lc, int W, int R, int Loops = 100000>
|
||||||
void benchmark() {
|
void benchmark() {
|
||||||
std::thread w_trd[W];
|
std::thread w_trd[W];
|
||||||
std::thread r_trd[R];
|
std::thread r_trd[R];
|
||||||
@ -134,20 +135,24 @@ void test_performance() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Unit::test_rw_lock() {
|
void Unit::test_rw_lock() {
|
||||||
test_performance<1, 1>();
|
// test_performance<1, 1>();
|
||||||
test_performance<4, 4>();
|
// test_performance<4, 4>();
|
||||||
test_performance<1, 8>();
|
// test_performance<1, 8>();
|
||||||
test_performance<8, 1>();
|
// test_performance<8, 1>();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Unit::test_send_recv() {
|
void Unit::test_send_recv() {
|
||||||
// auto h = ipc::connect("my-ipc");
|
auto h = ipc::connect("my-ipc");
|
||||||
// QVERIFY(h != nullptr);
|
QVERIFY(h != nullptr);
|
||||||
// char data[] = "hello ipc!";
|
char data[] = "hello ipc!";
|
||||||
// QVERIFY(ipc::send(h, data, sizeof(data)));
|
QVERIFY(ipc::send(h, data, sizeof(data)));
|
||||||
// auto got = ipc::recv(h);
|
auto got = ipc::recv(h);
|
||||||
// QCOMPARE((char*)got.data(), data);
|
QCOMPARE((char*)got.data(), data);
|
||||||
// ipc::disconnect(h);
|
ipc::disconnect(h);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Unit::test_channel() {
|
||||||
|
ipc::channel cc;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // internal-linkage
|
} // internal-linkage
|
||||||
|
|||||||
@ -22,7 +22,7 @@ private slots:
|
|||||||
void test_get();
|
void test_get();
|
||||||
void test_hello();
|
void test_hello();
|
||||||
void test_mt();
|
void test_mt();
|
||||||
} /*unit__*/;
|
} unit__;
|
||||||
|
|
||||||
#include "test_shm.moc"
|
#include "test_shm.moc"
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user