2022-04-23 18:30:43 +08:00

74 lines
1.7 KiB
C++

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