pimpl small object optimization

This commit is contained in:
mutouyun 2018-12-14 18:50:20 +08:00
parent 69cfad56c3
commit 1e44d6f84e
7 changed files with 114 additions and 44 deletions

View File

@ -3,7 +3,8 @@
#include <cstddef>
#include <cstdint>
#include <limits>
#include <thread>
#include <type_traits>
#include <new>
namespace ipc {
@ -25,8 +26,65 @@ using uint_t = typename uint<N>::type;
// constants
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
};
// 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

View File

@ -1,6 +1,7 @@
#pragma once
#include <atomic>
#include <thread>
#include <limits>
#include <type_traits>

View File

@ -10,6 +10,7 @@
#include <shared_mutex>
#include <mutex>
#include "def.h"
#include "circ_queue.h"
#include "rw_lock.h"
@ -151,14 +152,14 @@ std::vector<byte_t> recv(handle_t h) {
} while(1);
}
class channel::channel_ {
class channel::channel_ : public pimpl<channel_> {
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

View File

@ -8,10 +8,12 @@
#include <codecvt>
#include <utility>
#include "def.h"
namespace {
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>
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>
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));
}

View File

@ -3,18 +3,23 @@
#include <string>
#include <utility>
#include "def.h"
namespace ipc {
namespace shm {
class handle::handle_ {
class handle::handle_ : public pimpl<handle_> {
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

View File

@ -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 <typename Lc, int W, int R, int Loops = 1000000>
template <typename Lc, int W, int R, int Loops = 100000>
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

View File

@ -22,7 +22,7 @@ private slots:
void test_get();
void test_hello();
void test_mt();
} /*unit__*/;
} unit__;
#include "test_shm.moc"