Last active
September 15, 2020 21:23
-
-
Save outro56/a81f90f919931908541ccf6b5df59d92 to your computer and use it in GitHub Desktop.
Compilation firewalls: pimpl + fast_pimpl
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef CMUOH_PIMPL_HPP | |
#define CMUOH_PIMPL_HPP | |
#include <memory> | |
#include <cstddef> | |
// See also: https://herbsutter.com/gotw/_100/ | |
// NOTES: | |
// - put all private nonvirtual members (data + functions) into T impl | |
// - when using an impl in a class, all constructors (default/copy/move) and | |
// destructors need to be declare out of line in source file | |
namespace cmuoh { | |
template<typename T, typename PtrType> | |
class pimpl; | |
template<typename T> | |
using unique_ptr_pimpl = pimpl<T, std::unique_ptr<T>>; | |
template<typename T> | |
using shared_ptr_pimpl = pimpl<T, std::shared_ptr<T>>; | |
template<typename T, size_t Size, size_t Alignment = alignof(std::max_align_t)> | |
class fast_pimpl; | |
template<typename T, typename PtrType> | |
class pimpl { | |
public: | |
template<typename ...Args> pimpl(Args&& ...); | |
~pimpl(); | |
const T* operator->() const; | |
const T& operator*() const; | |
T* operator->(); | |
T& operator*(); | |
}; | |
template<typename T> | |
class pimpl<T, std::unique_ptr<T>> { | |
private: | |
std::unique_ptr<T> ptr; | |
public: | |
template<typename ...Args> | |
constexpr pimpl(Args&& ... args) | |
: ptr{ std::make_unique<T>(std::forward<T>(args)...) } | |
{ } | |
constexpr T const & operator*() const noexcept { return *ptr.get(); } | |
constexpr T const * operator->() const noexcept { return &**this; } | |
constexpr T& operator*() noexcept { return *ptr.get(); } | |
constexpr T* operator->() noexcept { return &**this; } | |
}; | |
template<typename T> | |
class pimpl<T, std::shared_ptr<T>> { | |
private: | |
std::shared_ptr<T> ptr; | |
public: | |
template<typename ...Args> | |
constexpr pimpl(Args&& ... args) | |
: ptr{ std::make_shared<T>(std::forward<T>(args)...) } | |
{ } | |
constexpr T const & operator*() const noexcept { return *ptr.get(); } | |
constexpr T const * operator->() const noexcept { return &**this; } | |
constexpr T& operator*() noexcept { return *ptr.get(); } | |
constexpr T* operator->() noexcept { return &**this; } | |
}; | |
template<typename T, size_t Size, size_t Alignment> | |
class fast_pimpl { | |
private: | |
std::aligned_storage_t<Size, Alignment> storage; | |
public: | |
template<typename ...Args> | |
constexpr fast_pimpl(Args&&... args) noexcept { | |
static_assert (sizeof(T) == Size, "fast_pimpl: T doesn't match expected size"); | |
static_assert (alignof(T) <= Alignment, "fast_pimpl: T doesn't match expected alignment"); | |
new (&**this) T { std::forward<T>(args)... }; | |
} | |
constexpr fast_pimpl(fast_pimpl const& o) noexcept { new (&storage) T(*o); } | |
constexpr fast_pimpl(fast_pimpl& o) noexcept { new (&storage) T(*o); } | |
constexpr fast_pimpl(fast_pimpl&& o) noexcept { new (&storage) T(std::move(*o)); } | |
~fast_pimpl() noexcept { reinterpret_cast<T*>(&storage)->~T(); } | |
constexpr T const & operator*() const noexcept { return *reinterpret_cast<T const*>(&storage); } | |
constexpr T const * operator->() const noexcept { return &**this; } | |
constexpr T& operator*() noexcept { return *reinterpret_cast<T*>(&storage); } | |
constexpr T* operator->() noexcept { return &**this; } | |
}; | |
} // namespace "cmuoh" | |
#endif //CMUOH_PIMPL_HPP | |
// /* example */ | |
// struct impl; | |
// int main() { | |
// cmuoh::unique_ptr_pimpl<impl> f; //note: "impl" is forward declared | |
// return 0; | |
// } | |
// struct impl { }; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment