With fully incomplete types, `unsafe_cast` is used instead of `try_cast` in `operator [const] T*()`.

Fortune for opaque_handle's current commit: Curse − 凶
master
Avril 3 years ago
parent 4f1481b589
commit 7d55dcf124
Signed by: flanchan
GPG Key ID: 284488987C31F630

@ -15,6 +15,9 @@ struct opaque_bad_cast : $_oe("bad opaque_handle pointer cast");
struct opaque_handle; struct opaque_handle;
struct opaque_handle_impl; struct opaque_handle_impl;
template<typename T>
constexpr inline bool opaque_is_incomplete = !requires { { sizeof(T) }; };
struct opaque_handle_impl { struct opaque_handle_impl {
friend class opaque_handle; friend class opaque_handle;
@ -36,10 +39,14 @@ struct opaque_handle_impl {
template<typename To> template<typename To>
inline constexpr const To* try_cast() const noexcept { return is_type(typeid(To)) ? static_cast<const To*>(as_raw_ptr()) : nullptr; } inline constexpr const To* try_cast() const noexcept { return is_type<To>() ? static_cast<const To*>(as_raw_ptr()) : nullptr; }
template<typename To> template<typename To>
inline constexpr To* try_cast() noexcept { return is_type(typeid(To)) ? static_cast<To*>(as_raw_ptr()) : nullptr; } inline constexpr To* try_cast() noexcept { return is_type<To>() ? static_cast<To*>(as_raw_ptr()) : nullptr; }
template<typename T>
constexpr bool is_type() const noexcept {
if constexpr(requires { { sizeof(T) }; }) return is_type(typeid(T)); else return true;
}
constexpr virtual bool is_type(const std::type_info& a) const noexcept { constexpr virtual bool is_type(const std::type_info& a) const noexcept {
if(const auto* p = get_type_info()) return *p == a; if(const auto* p = get_type_info()) return *p == a;
return false; // Types are uncomparable. return false; // Types are uncomparable.
@ -87,6 +94,7 @@ struct opaque_handle final {
template<typename T, bool Reinterpret=false> template<typename T, bool Reinterpret=false>
constexpr T* unsafe_cast() noexcept { return _impl ? _impl->unsafe_cast<T, Reinterpret>() : nullptr; } constexpr T* unsafe_cast() noexcept { return _impl ? _impl->unsafe_cast<T, Reinterpret>() : nullptr; }
/// WARNING: try_cast<T>(), where T is an incomplete type, will always succeed, which may lead to undefined behaviour. Make sure to account for this
template<typename T> template<typename T>
constexpr const T* try_cast() const noexcept { return _impl ? _impl->try_cast<T>() : nullptr; } constexpr const T* try_cast() const noexcept { return _impl ? _impl->try_cast<T>() : nullptr; }
template<typename T> template<typename T>
@ -138,9 +146,15 @@ struct opaque_handle final {
inline auto operator*() noexcept { return *(try_cast<T>() ?: throw opaque_bad_cast{}); } inline auto operator*() noexcept { return *(try_cast<T>() ?: throw opaque_bad_cast{}); }
*/ */
template<typename T> template<typename T>
constexpr operator T*() noexcept { return try_cast<T>(); } constexpr operator T*() noexcept {
if constexpr(opaque_is_incomplete<T>) return unsafe_cast<T>();
else return try_cast<T>();
}
template<typename T> template<typename T>
constexpr operator const T*() const noexcept { return try_cast<T>(); } constexpr operator const T*() const noexcept {
if constexpr(opaque_is_incomplete<T>) return unsafe_cast<T>();
else return try_cast<T>();
}
private: private:
struct _impl_deref_const { struct _impl_deref_const {
@ -248,7 +262,11 @@ constexpr inline opaque_handle make_opaque_handle(T* data, const HandleF& handle
{ return const_cast<T*>(data); } { return const_cast<T*>(data); }
constexpr opaque_handle_impl* try_clone() const override final constexpr opaque_handle_impl* try_clone() const override final
{ return data ? new object_handler(*this) : nullptr; } { return data ? new object_handler(*this) : nullptr; }
inline constexpr const std::type_info* get_type_info() const noexcept override final { return &typeid(T); } inline constexpr const std::type_info* get_type_info() const noexcept override final {
if constexpr(requires { { sizeof(T) }; })
return &typeid(T);
else return nullptr;
}
T* data; T* data;
const HandleF& handler; const HandleF& handler;
@ -294,7 +312,11 @@ constexpr inline opaque_handle make_opaque_handle(T* data, HandleF&& handler) no
return data ? new object_handler(*this) : nullptr; return data ? new object_handler(*this) : nullptr;
} else return nullptr; } else return nullptr;
} }
inline constexpr const std::type_info* get_type_info() const noexcept override final { return &typeid(T); } inline constexpr const std::type_info* get_type_info() const noexcept override final {
if constexpr(requires { { sizeof(T) }; })
return &typeid(T);
else return nullptr;
}
T* data; T* data;
HandleF handler; HandleF handler;
@ -334,7 +356,11 @@ constexpr inline opaque_handle make_opaque_handle(T* data) noexcept
{ return const_cast<T*>(data); } { return const_cast<T*>(data); }
constexpr opaque_handle_impl* try_clone() const override final constexpr opaque_handle_impl* try_clone() const override final
{ return data ? new object_handler(*this) : nullptr; } { return data ? new object_handler(*this) : nullptr; }
inline constexpr const std::type_info* get_type_info() const noexcept override final { return &typeid(T); } inline constexpr const std::type_info* get_type_info() const noexcept override final {
if constexpr(requires { { sizeof(T) }; })
return &typeid(T);
else return nullptr;
}
T* data; T* data;
}; };

@ -101,6 +101,9 @@ static void use_moh()
// Testing a hypothetical C interface // Testing a hypothetical C interface
extern "C" { extern "C" {
struct c_struct_example; struct c_struct_example;
struct opaque;
void black_box(const opaque* __restrict__){}
c_struct_example* cs_create(const c_struct_example* __restrict__ from); c_struct_example* cs_create(const c_struct_example* __restrict__ from);
void cs_free(c_struct_example* p); void cs_free(c_struct_example* p);
@ -113,6 +116,10 @@ static void use_c_struct()
using type = c_struct_example; using type = c_struct_example;
auto* allocp = cs_create(nullptr); auto* allocp = cs_create(nullptr);
opaque_handle impossible{make_opaque_handle<opaque>(nullptr, [](auto*, auto) noexcept { return static_cast<opaque*>(nullptr); })};
black_box(impossible);
const opaque_handle v{make_opaque_handle<type>(allocp, [](auto* ptr, auto op) noexcept { const opaque_handle v{make_opaque_handle<type>(allocp, [](auto* ptr, auto op) noexcept {
if(ptr) { if(ptr) {
switch(op) { switch(op) {

Loading…
Cancel
Save