Skip to content

Instantly share code, notes, and snippets.

@outro56
Last active September 15, 2020 21:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save outro56/a81f90f919931908541ccf6b5df59d92 to your computer and use it in GitHub Desktop.
Save outro56/a81f90f919931908541ccf6b5df59d92 to your computer and use it in GitHub Desktop.
Compilation firewalls: pimpl + fast_pimpl
#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