/** * \file libimp/pimpl.h * \author mutouyun (orz@orzz.org) * \brief Pointer To Implementation (pImpl) idiom * \date 2022-02-27 */ #pragma once #include #include #include #include "libimp/construct.h" #include "libimp/def.h" LIBIMP_NAMESPACE_BEG_ namespace pimpl { template struct is_comfortable { enum : bool { value = (sizeof(T) <= sizeof(R)) && (alignof(T) <= alignof(R)) }; }; template auto make(A &&... args) -> std::enable_if_t::value, T *> { T *buf {}; // construct an object using memory of a pointer construct(&buf, std::forward(args)...); return buf; } template auto get(T * const (& p)) noexcept -> std::enable_if_t::value, T *> { return reinterpret_cast(&const_cast(reinterpret_cast(p))); } template auto clear(T *p) noexcept -> std::enable_if_t::value> { if (p != nullptr) destroy(get(p)); } template auto make(A &&... args) -> std::enable_if_t::value, T *> { return new T{std::forward(args)...}; } template auto get(T * const (& p)) noexcept -> std::enable_if_t::value, T *> { return p; } template auto clear(T *p) noexcept -> std::enable_if_t::value> { if (p != nullptr) delete p; } template class Obj { public: template static T *make(A &&... args) { return pimpl::make(std::forward(args)...); } void clear() noexcept { pimpl::clear(static_cast(const_cast(this))); } }; } // namespace pimpl LIBIMP_NAMESPACE_END_