|
|
@ -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;
|
|
|
|
};
|
|
|
|
};
|
|
|
|