xo-reflect: allow TypeDescr without .native_typeinfo

This commit is contained in:
Roland Conybeare 2024-06-18 14:05:51 -04:00
commit 7243939916
5 changed files with 83 additions and 13 deletions

View file

@ -27,7 +27,7 @@ or equivalently
$ git clone git@github.com:Rconybea/xo-reflect.git $ git clone git@github.com:Rconybea/xo-reflect.git
``` ```
### build + install xo-reflect ### build + install `xo-reflect`
``` ```
$ xo-build --configure --build --install xo-reflect $ xo-build --configure --build --install xo-reflect
``` ```

View file

@ -227,6 +227,15 @@ namespace xo {
return retval_td; return retval_td;
} }
/** given address @p src_address of a value with type described by @p src,
* return typed pointer of type @tparam T, provided that @p src_td
* actually describes @tparam T. Otherwise returns nullptr
**/
template <typename T>
static T * recover_native(TypeDescr src_td, void * src_address) {
return TaggedPtr(src_td, src_address).recover_native<T>();
}
/* Use: /* Use:
* T * xyz = ...; * T * xyz = ...;
* TaggedPtr xyz_tp = Reflect::make_tp(xyz); * TaggedPtr xyz_tp = Reflect::make_tp(xyz);

View file

@ -68,7 +68,7 @@ namespace xo {
* to refer to a T-instance; otherwise nullptr * to refer to a T-instance; otherwise nullptr
*/ */
template<typename T> template<typename T>
T * recover_native() const { return this->td_->recover_native<T>(this->address_); } T * recover_native() const { return this->td_->recover_native2<T>(this->td_, this->address_); }
uint32_t n_child() const { uint32_t n_child() const {
return this->td_->n_child(this->address_); return this->td_->n_child(this->address_);

View file

@ -149,28 +149,66 @@ namespace xo {
static void print_reflected_types(std::ostream & os); static void print_reflected_types(std::ostream & os);
TypeId id() const { return id_; } TypeId id() const { return id_; }
std::type_info const * typeinfo() const { return typeinfo_; } std::type_info const * native_typeinfo() const { return native_typeinfo_; }
std::string_view const & canonical_name() const { return canonical_name_; } std::string_view const & canonical_name() const { return canonical_name_; }
std::string_view const & short_name() const { return short_name_; } std::string_view const & short_name() const { return short_name_; }
bool complete_flag() const { return complete_flag_; } bool complete_flag() const { return complete_flag_; }
TypeDescrExtra * tdextra() const { return tdextra_.get(); } TypeDescrExtra * tdextra() const { return tdextra_.get(); }
Metatype metatype() const { return tdextra_->metatype(); } Metatype metatype() const { return tdextra_->metatype(); }
/* true iff the type represented by *this is the same as the type T. /* true iff the type represented by *this is the same as the type
* represented by T.
* *
* Warning: comparing typeinfo address can give false negatives. * Warning: comparing typeinfo address can give false negatives.
* suspect this is caused by problems coalescing linker symbols * suspect this is caused by problems coalescing linker symbols
* in the clang toolchain. * in the clang toolchain.
*/ */
template<typename T> template<typename T>
[[deprecated]]
bool is_native() const { bool is_native() const {
return ((this->typeinfo() == &typeid(T)) if (this->native_typeinfo()) {
|| (this->typeinfo()->hash_code() == typeid(T).hash_code()) /* reminder: typeid(T).name() is 'interesting' but not intended
|| (this->typeinfo()->name() == typeid(T).name())); * to be human-readable. It's not how compiler labels
* a type for a human reader
*/
return ((this->native_typeinfo() == &typeid(T))
|| (this->native_typeinfo()->hash_code() == typeid(T).hash_code())
|| (this->native_typeinfo()->name() == typeid(T).name()));
} else {
/** if this type was established via Reflect::require<T1>(),
* then .canonical_name is computed by type_name<T>()
*
* (see demangle.hh in xo-refcnt, which post-processes __PRETTY_FUNCTION__
* or __FUNCSIG__)
*
* To manually construct an equivalent type,
* it's necessary to:
* 1. construct a unique and unambiguous canonical name for the type
* 2. be aware that type will only be recognized as equivalent to
* a natively-reflected type if canonical name matches exactly.
**/
/** FOR NOW: give up. **/
throw std::runtime_error("TypeDescrBase::is_native: not implemented for manually-constructed TypeDescr objects. Prefer is_native2()");
}
} /*is_native*/ } /*is_native*/
/* safe downcast -- like dynamic_cast<>, but does not require a source type */ /** safe downcast -- like dynamic_cast<>, but does not require a source type.
*
* TODO: need variation on this to correctly-handle function types,
* since for exampple cast from void* -> void (*)() is not allowed
*
* WARNING: relies on deprecated is_native<T>(). Application code should prefer any of:
* 1. recover_native2(src_td, src_address)
* 2. Reflect::recover_native<T>(src_td, src_address)
* 3. TaggedPtr(src_td,src_address).recover_native<T>()
* instead of src_td->recover_native<T>()
*
* (note: awkwardness here is that we don't have access to {Reflect.hpp, TaggedPtr.hpp}
* from this .hpp file, since TypeDescr.hpp is included by those headers)
**/
template<typename T> template<typename T>
[[deprecated]]
T * recover_native(void * address) const { T * recover_native(void * address) const {
if (this->is_native<T>()) { if (this->is_native<T>()) {
return reinterpret_cast<T *>(address); return reinterpret_cast<T *>(address);
@ -179,6 +217,22 @@ namespace xo {
} }
} /*recover_native*/ } /*recover_native*/
/** safe downcast -- like dynamic_cast<>, but does not require a source type.
*
* Application code should prefer TaggedPtr::recover_native<T>()
*
* TODO: need variation on this to correctly-handle function types,
* since for exampple cast from void* -> void (*)() is not allowed
**/
template<typename T>
T * recover_native2(TypeDescr address_td, void * address) const {
if (this == address_td) {
return reinterpret_cast<T *>(address);
} else {
return nullptr;
}
} /*recover_native2*/
bool is_pointer() const { return this->tdextra_->is_pointer(); } bool is_pointer() const { return this->tdextra_->is_pointer(); }
bool is_vector() const { return this->tdextra_->is_vector(); } bool is_vector() const { return this->tdextra_->is_vector(); }
bool is_struct() const { return this->tdextra_->is_struct(); } bool is_struct() const { return this->tdextra_->is_struct(); }
@ -255,7 +309,9 @@ namespace xo {
* - s_type_table_map[TypeInfoRef(x->typeinfo())] = x * - s_type_table_map[TypeInfoRef(x->typeinfo())] = x
*/ */
/* hashmap of all TypeDescr instances, indexed by . singleton */ /* hashmap of all native TypeDescr instances, indexed by typeinfo.
* singleton.
*/
static std::unordered_map<TypeInfoRef, std::unique_ptr<TypeDescrBase>> s_type_table_map; static std::unordered_map<TypeInfoRef, std::unique_ptr<TypeDescrBase>> s_type_table_map;
/* hashmap of (presumed) duplicate TypeInfoRef values. /* hashmap of (presumed) duplicate TypeInfoRef values.
* This happens with clang sometimes when the same type is referenced * This happens with clang sometimes when the same type is referenced
@ -269,8 +325,13 @@ namespace xo {
private: private:
/* unique id# for this type */ /* unique id# for this type */
TypeId id_; TypeId id_;
/* typeinfo for type T */ /** typeinfo for type T, if available. nullptr otherwise.
std::type_info const * typeinfo_ = nullptr; *
* 1. Always available for type-descriptions constructed via Reflect::require<T>.
* 2. Always missing for manually-constructed TypeDescr instances, for example
* see Lambda.cpp in xo-expression.
**/
std::type_info const * native_typeinfo_ = nullptr;
/* canonical name for this type (see demangle.hpp for type_name<T>()) /* canonical name for this type (see demangle.hpp for type_name<T>())
* e.g. * e.g.
* xo::option::Px2 * xo::option::Px2

View file

@ -124,11 +124,11 @@ namespace xo {
} /*namespace*/ } /*namespace*/
TypeDescrBase::TypeDescrBase(TypeId id, TypeDescrBase::TypeDescrBase(TypeId id,
std::type_info const * tinfo, std::type_info const * native_tinfo,
std::string_view canonical_name, std::string_view canonical_name,
std::unique_ptr<TypeDescrExtra> tdextra) std::unique_ptr<TypeDescrExtra> tdextra)
: id_{std::move(id)}, : id_{std::move(id)},
typeinfo_{tinfo}, native_typeinfo_{native_tinfo},
canonical_name_{std::move(canonical_name)}, canonical_name_{std::move(canonical_name)},
short_name_{unqualified_name(canonical_name_)}, short_name_{unqualified_name(canonical_name_)},
tdextra_{std::move(tdextra)} tdextra_{std::move(tdextra)}