From 1e44d6f84e763c4cd5c741592670cf70f26bc4de Mon Sep 17 00:00:00 2001 From: mutouyun Date: Fri, 14 Dec 2018 18:50:20 +0800 Subject: [PATCH] pimpl small object optimization --- include/def.h | 62 ++++++++++++++++++++++++++++++++++++++-- include/rw_lock.h | 1 + src/ipc.cpp | 16 +++++------ src/platform/shm_win.cpp | 6 ++-- src/shm.cpp | 42 +++++++++++++++------------ test/test_ipc.cpp | 29 +++++++++++-------- test/test_shm.cpp | 2 +- 7 files changed, 114 insertions(+), 44 deletions(-) diff --git a/include/def.h b/include/def.h index ccd30ca..4655e86 100644 --- a/include/def.h +++ b/include/def.h @@ -3,7 +3,8 @@ #include #include #include -#include +#include +#include namespace ipc { @@ -25,8 +26,65 @@ using uint_t = typename uint::type; // constants enum : std::size_t { - error_count = std::numeric_limits::max(), + error_count = (std::numeric_limits::max)(), data_length = 16 }; +// concept helpers + +template +using Requires = std::enable_if_t; + +// pimpl small object optimization helpers + +template +using IsImplComfortable = Requires<(sizeof(T) <= sizeof(T*)), R>; + +template +using IsImplUncomfortable = Requires<(sizeof(T) > sizeof(T*)), R>; + +template +constexpr auto make_impl(P&&... params) -> IsImplComfortable { + T* buf {}; + ::new (&buf) T { std::forward

(params)... }; + return buf; +} + +template +constexpr auto impl(T* const (& p)) -> IsImplComfortable { + return reinterpret_cast(&const_cast(reinterpret_cast(p))); +} + +template +constexpr auto clear_impl(T* p) -> IsImplComfortable { + impl(p)->~T(); +} + +template +constexpr auto make_impl(P&&... params) -> IsImplUncomfortable { + return new T { std::forward

(params)... }; +} + +template +constexpr auto clear_impl(T* p) -> IsImplUncomfortable { + delete p; +} + +template +constexpr auto impl(T* const (& p)) -> IsImplUncomfortable { + return p; +} + +template +struct pimpl { + template + constexpr static T* make(P&&... params) { + return make_impl(std::forward

(params)...); + } + + constexpr void clear() { + clear_impl(static_cast(this)); + } +}; + } // namespace ipc diff --git a/include/rw_lock.h b/include/rw_lock.h index 6c0c20d..aa8351f 100644 --- a/include/rw_lock.h +++ b/include/rw_lock.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include diff --git a/src/ipc.cpp b/src/ipc.cpp index c33abe6..55eab34 100644 --- a/src/ipc.cpp +++ b/src/ipc.cpp @@ -10,6 +10,7 @@ #include #include +#include "def.h" #include "circ_queue.h" #include "rw_lock.h" @@ -151,14 +152,14 @@ std::vector recv(handle_t h) { } while(1); } -class channel::channel_ { +class channel::channel_ : public pimpl { public: handle_t h_ = nullptr; std::string n_; }; channel::channel(void) - : p_(new channel_) { + : p_(p_->make()) { } channel::channel(char const * name) @@ -172,7 +173,7 @@ channel::channel(channel&& rhs) } channel::~channel(void) { - delete p_; + p_->clear(); } void channel::swap(channel& rhs) { @@ -185,11 +186,11 @@ channel& channel::operator=(channel rhs) { } bool channel::valid(void) const { - return (p_ != nullptr) && (p_->h_ != nullptr); + return (impl(p_)->h_ != nullptr); } char const * channel::name(void) const { - return (p_ == nullptr) ? "" : p_->n_.c_str(); + return impl(p_)->n_.c_str(); } channel channel::clone(void) const { @@ -197,15 +198,14 @@ channel channel::clone(void) const { } bool channel::connect(char const * name) { - if (p_ == nullptr) return false; this->disconnect(); - p_->h_ = ipc::connect((p_->n_ = name).c_str()); + impl(p_)->h_ = ipc::connect((impl(p_)->n_ = name).c_str()); return valid(); } void channel::disconnect(void) { if (!valid()) return; - ipc::disconnect(p_->h_); + ipc::disconnect(impl(p_)->h_); } } // namespace ipc diff --git a/src/platform/shm_win.cpp b/src/platform/shm_win.cpp index ee29e53..1f558af 100644 --- a/src/platform/shm_win.cpp +++ b/src/platform/shm_win.cpp @@ -8,10 +8,12 @@ #include #include +#include "def.h" + namespace { template -using IsSame = std::enable_if_t::value, R>; +using IsSame = ipc::Requires::value, R>; template constexpr auto to_tchar(std::string && str) -> IsSame { @@ -19,7 +21,7 @@ constexpr auto to_tchar(std::string && str) -> IsSame -inline auto to_tchar(std::string && str) -> IsSame { +constexpr auto to_tchar(std::string && str) -> IsSame { return std::wstring_convert>{}.from_bytes(std::move(str)); } diff --git a/src/shm.cpp b/src/shm.cpp index eec3b24..695c17b 100644 --- a/src/shm.cpp +++ b/src/shm.cpp @@ -3,18 +3,23 @@ #include #include +#include "def.h" + namespace ipc { namespace shm { -class handle::handle_ { +class handle::handle_ : public pimpl { public: handle* t_ = nullptr; handle_t h_ = nullptr; void* m_ = nullptr; - std::string n_; + std::string n_ {}; std::size_t s_ = 0; + handle_() = default; + handle_(handle* t) : t_{t} {} + ~handle_(void) { t_->close(); t_->release(); @@ -22,8 +27,7 @@ public: }; handle::handle(void) - : p_(new handle_) { - p_->t_ = this; + : p_(p_->make(this)) { } handle::handle(char const * name, std::size_t size) @@ -37,7 +41,7 @@ handle::handle(handle&& rhs) } handle::~handle(void) { - delete p_; + p_->clear(); } void handle::swap(handle& rhs) { @@ -50,45 +54,45 @@ handle& handle::operator=(handle rhs) { } bool handle::valid(void) const { - return (p_ != nullptr) && (p_->h_ != nullptr); + return impl(p_)->h_ != nullptr; } std::size_t handle::size(void) const { - return (p_ == nullptr) ? 0 : p_->s_; + return impl(p_)->s_; } 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) { - if (p_ == nullptr) return false; close(); 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(); } void handle::release(void) { if (!valid()) return; - shm::release(p_->h_, p_->s_); - p_->h_ = nullptr; - p_->s_ = 0; - p_->n_.clear(); + shm::release(impl(p_)->h_, impl(p_)->s_); + impl(p_)->h_ = nullptr; + impl(p_)->s_ = 0; + impl(p_)->n_.clear(); } void* handle::get(void) { if (!valid()) return nullptr; - if (p_->m_ == nullptr) { - return p_->m_ = shm::open(p_->h_); + if (impl(p_)->m_ == nullptr) { + return impl(p_)->m_ = shm::open(impl(p_)->h_); } - else return p_->m_; + else return impl(p_)->m_; } void handle::close(void) { if (!valid()) return; - shm::close(p_->m_); - p_->m_ = nullptr; + shm::close(impl(p_)->m_); + impl(p_)->m_ = nullptr; } } // namespace shm diff --git a/test/test_ipc.cpp b/test/test_ipc.cpp index 595e661..c0eb0f7 100644 --- a/test/test_ipc.cpp +++ b/test/test_ipc.cpp @@ -29,6 +29,7 @@ class Unit : public TestSuite { private slots: void test_rw_lock(); void test_send_recv(); + void test_channel(); } unit__; #include "test_ipc.moc" @@ -44,7 +45,7 @@ struct lc_wrapper : Mutex { void unlock_shared() { Mutex::unlock(); } }; -template +template void benchmark() { std::thread w_trd[W]; std::thread r_trd[R]; @@ -134,20 +135,24 @@ void test_performance() { } void Unit::test_rw_lock() { - test_performance<1, 1>(); - test_performance<4, 4>(); - test_performance<1, 8>(); - test_performance<8, 1>(); +// test_performance<1, 1>(); +// test_performance<4, 4>(); +// test_performance<1, 8>(); +// test_performance<8, 1>(); } void Unit::test_send_recv() { -// auto h = ipc::connect("my-ipc"); -// QVERIFY(h != nullptr); -// char data[] = "hello ipc!"; -// QVERIFY(ipc::send(h, data, sizeof(data))); -// auto got = ipc::recv(h); -// QCOMPARE((char*)got.data(), data); -// ipc::disconnect(h); + auto h = ipc::connect("my-ipc"); + QVERIFY(h != nullptr); + char data[] = "hello ipc!"; + QVERIFY(ipc::send(h, data, sizeof(data))); + auto got = ipc::recv(h); + QCOMPARE((char*)got.data(), data); + ipc::disconnect(h); +} + +void Unit::test_channel() { + ipc::channel cc; } } // internal-linkage diff --git a/test/test_shm.cpp b/test/test_shm.cpp index 57f7bb0..8d096e0 100644 --- a/test/test_shm.cpp +++ b/test/test_shm.cpp @@ -22,7 +22,7 @@ private slots: void test_get(); void test_hello(); void test_mt(); -} /*unit__*/; +} unit__; #include "test_shm.moc"