cosmetic: indenting
This commit is contained in:
parent
47f86347a4
commit
8231420c5e
1 changed files with 203 additions and 194 deletions
|
|
@ -98,204 +98,213 @@ namespace std {
|
|||
} /*namespace std*/
|
||||
|
||||
namespace xo {
|
||||
namespace reflect {
|
||||
inline bool operator==(TypeInfoRef x, TypeInfoRef y) { return TypeInfoRef::is_equal(x, y); }
|
||||
inline bool operator!=(TypeInfoRef x, TypeInfoRef y) { return !TypeInfoRef::is_equal(x, y); }
|
||||
namespace reflect {
|
||||
inline bool operator==(TypeInfoRef x, TypeInfoRef y) { return TypeInfoRef::is_equal(x, y); }
|
||||
inline bool operator!=(TypeInfoRef x, TypeInfoRef y) { return !TypeInfoRef::is_equal(x, y); }
|
||||
|
||||
#ifdef NOT_IN_USE
|
||||
namespace detail {
|
||||
class HashTypeInfoRef {
|
||||
public:
|
||||
std::size_t operator()(TypeInfoRef x) const noexcept { return x.hash_code(); }
|
||||
}; /*HashTypeInfoRef*/
|
||||
namespace detail {
|
||||
class HashTypeInfoRef {
|
||||
public:
|
||||
std::size_t operator()(TypeInfoRef x) const noexcept { return x.hash_code(); }
|
||||
}; /*HashTypeInfoRef*/
|
||||
|
||||
class EqualTypeInfoRef {
|
||||
public:
|
||||
bool operator()(TypeInfoRef x, TypeInfoRef y) const noexcept { return TypeInfoRef::is_equal(x, y); }
|
||||
}; /*EqualTypeInfoRef*/
|
||||
} /*namespace detail*/
|
||||
class EqualTypeInfoRef {
|
||||
public:
|
||||
bool operator()(TypeInfoRef x, TypeInfoRef y) const noexcept { return TypeInfoRef::is_equal(x, y); }
|
||||
}; /*EqualTypeInfoRef*/
|
||||
} /*namespace detail*/
|
||||
#endif
|
||||
|
||||
class TypeDescrExtra;
|
||||
class TypeDescrExtra;
|
||||
|
||||
/* run-time description for a native c++ type */
|
||||
class TypeDescrBase {
|
||||
public:
|
||||
/* type-description objects for a type T is unique,
|
||||
* --> can always use its address
|
||||
*/
|
||||
TypeDescrBase(TypeDescrBase const & x) = delete;
|
||||
/* run-time description for a native c++ type */
|
||||
class TypeDescrBase {
|
||||
public:
|
||||
/* type-description objects for a type T is unique,
|
||||
* --> can always use its address
|
||||
*/
|
||||
TypeDescrBase(TypeDescrBase const & x) = delete;
|
||||
|
||||
/* test whether a type has been reflected.
|
||||
* introducing this for unit testing
|
||||
*/
|
||||
static bool is_reflected(std::type_info const * tinfo) {
|
||||
return (s_type_table_map.find(TypeInfoRef(tinfo))
|
||||
!= s_type_table_map.end());
|
||||
} /*is_reflected*/
|
||||
/* test whether a type has been reflected.
|
||||
* introducing this for unit testing
|
||||
*/
|
||||
static bool is_reflected(std::type_info const * tinfo) {
|
||||
return (s_type_table_map.find(TypeInfoRef(tinfo))
|
||||
!= s_type_table_map.end());
|
||||
} /*is_reflected*/
|
||||
|
||||
/* NOTE:
|
||||
* implementation here will be defeated if std::type_info
|
||||
* objects violate ODR. This occurs with clang + 2-level namespaces,
|
||||
* so important to linke with --flat_namespace defined.
|
||||
* See FAQ
|
||||
* [Build Issues|Q2 - dynamic_cast<Foo<*>> fails]
|
||||
*/
|
||||
static TypeDescrW require(std::type_info const * tinfo,
|
||||
std::string_view canonical_name,
|
||||
std::unique_ptr<TypeDescrExtra> tdextra);
|
||||
/* NOTE:
|
||||
* implementation here will be defeated if std::type_info
|
||||
* objects violate ODR. This occurs with clang + 2-level namespaces,
|
||||
* so important to linke with --flat_namespace defined.
|
||||
* See FAQ
|
||||
* [Build Issues|Q2 - dynamic_cast<Foo<*>> fails]
|
||||
*/
|
||||
static TypeDescrW require(std::type_info const * tinfo,
|
||||
std::string_view canonical_name,
|
||||
std::unique_ptr<TypeDescrExtra> tdextra);
|
||||
|
||||
/* print table of reflected types to os */
|
||||
static void print_reflected_types(std::ostream & os);
|
||||
/* print table of reflected types to os */
|
||||
static void print_reflected_types(std::ostream & os);
|
||||
|
||||
TypeId id() const { return id_; }
|
||||
std::type_info const * typeinfo() const { return typeinfo_; }
|
||||
std::string_view const & canonical_name() const { return canonical_name_; }
|
||||
std::string_view const & short_name() const { return short_name_; }
|
||||
bool complete_flag() const { return complete_flag_; }
|
||||
TypeDescrExtra * tdextra() const { return tdextra_.get(); }
|
||||
Metatype metatype() const { return tdextra_->metatype(); }
|
||||
TypeId id() const { return id_; }
|
||||
std::type_info const * typeinfo() const { return typeinfo_; }
|
||||
std::string_view const & canonical_name() const { return canonical_name_; }
|
||||
std::string_view const & short_name() const { return short_name_; }
|
||||
bool complete_flag() const { return complete_flag_; }
|
||||
TypeDescrExtra * tdextra() const { return tdextra_.get(); }
|
||||
Metatype metatype() const { return tdextra_->metatype(); }
|
||||
|
||||
/* true iff the type represented by *this is the same as the type T.
|
||||
*
|
||||
* Warning: comparing typeinfo address can give false negatives.
|
||||
* suspect this is caused by problems coalescing linker symbols
|
||||
* in the clang toolchain.
|
||||
*/
|
||||
template<typename T>
|
||||
bool is_native() const {
|
||||
return ((this->typeinfo() == &typeid(T))
|
||||
|| (this->typeinfo()->hash_code() == typeid(T).hash_code())
|
||||
|| (this->typeinfo()->name() == typeid(T).name()));
|
||||
} /*is_native*/
|
||||
/* true iff the type represented by *this is the same as the type T.
|
||||
*
|
||||
* Warning: comparing typeinfo address can give false negatives.
|
||||
* suspect this is caused by problems coalescing linker symbols
|
||||
* in the clang toolchain.
|
||||
*/
|
||||
template<typename T>
|
||||
bool is_native() const {
|
||||
return ((this->typeinfo() == &typeid(T))
|
||||
|| (this->typeinfo()->hash_code() == typeid(T).hash_code())
|
||||
|| (this->typeinfo()->name() == typeid(T).name()));
|
||||
} /*is_native*/
|
||||
|
||||
/* safe downcast -- like dynamic_cast<>, but does not require a source type */
|
||||
template<typename T>
|
||||
T * recover_native(void * address) const {
|
||||
if (this->is_native<T>()) {
|
||||
return reinterpret_cast<T *>(address);
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
} /*recover_native*/
|
||||
/* safe downcast -- like dynamic_cast<>, but does not require a source type */
|
||||
template<typename T>
|
||||
T * recover_native(void * address) const {
|
||||
if (this->is_native<T>()) {
|
||||
return reinterpret_cast<T *>(address);
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
} /*recover_native*/
|
||||
|
||||
bool is_vector() const { return this->tdextra_->is_vector(); }
|
||||
bool is_struct() const { return this->tdextra_->is_struct(); }
|
||||
bool is_vector() const { return this->tdextra_->is_vector(); }
|
||||
bool is_struct() const { return this->tdextra_->is_struct(); }
|
||||
|
||||
/* given a T-instance object, return tagged pointer with T replaced
|
||||
* by the most-derived-subtype of T to which *object belongs.
|
||||
* This works only for descendants of reflect::SelfTagging
|
||||
*/
|
||||
TaggedPtr most_derived_self_tp(void * object) const;
|
||||
/* given a T-instance object, return tagged pointer with T replaced
|
||||
* by the most-derived-subtype of T to which *object belongs.
|
||||
* This works only for descendants of reflect::SelfTagging
|
||||
*/
|
||||
TaggedPtr most_derived_self_tp(void * object) const;
|
||||
|
||||
/* if generalized vector (std::vector<T>, std::array<T,N>, ..):
|
||||
* .n_child() reports #of elements
|
||||
* if struct/class:
|
||||
* .n_child() reports #of instance variables (that have been reflected)
|
||||
*/
|
||||
uint32_t n_child(void * object) const { return this->tdextra_->n_child(object); }
|
||||
TaggedPtr child_tp(uint32_t i, void * object) const;
|
||||
/* if generalized vector (std::vector<T>, std::array<T,N>, ..):
|
||||
* .n_child() reports #of elements
|
||||
* if struct/class:
|
||||
* .n_child() reports #of instance variables (that have been reflected)
|
||||
*/
|
||||
uint32_t n_child(void * object) const { return this->tdextra_->n_child(object); }
|
||||
TaggedPtr child_tp(uint32_t i, void * object) const;
|
||||
|
||||
/* require:
|
||||
* - .is_struct() = true
|
||||
* - i in [0 .. .n_child() - 1]
|
||||
*/
|
||||
std::string const & struct_member_name(uint32_t i) const {
|
||||
return this->tdextra_->struct_member_name(i);
|
||||
}
|
||||
/* fetch runtime description for i'th reflected instance variable.
|
||||
*
|
||||
* require:
|
||||
* - .is_struct() = true
|
||||
* - i in [0 .. .n_child() - 1]
|
||||
*/
|
||||
StructMember const & struct_member(uint32_t i) const {
|
||||
StructMember const * sm = this->tdextra_->struct_member(i);
|
||||
/* require:
|
||||
* - .is_struct() = true
|
||||
* - i in [0 .. .n_child() - 1]
|
||||
*/
|
||||
std::string const & struct_member_name(uint32_t i) const {
|
||||
return this->tdextra_->struct_member_name(i);
|
||||
}
|
||||
/* fetch runtime description for i'th reflected instance variable.
|
||||
*
|
||||
* require:
|
||||
* - .is_struct() = true
|
||||
* - i in [0 .. .n_child() - 1]
|
||||
*/
|
||||
StructMember const & struct_member(uint32_t i) const {
|
||||
StructMember const * sm = this->tdextra_->struct_member(i);
|
||||
|
||||
assert(sm);
|
||||
return *sm;
|
||||
} /*struct_member*/
|
||||
assert(sm);
|
||||
return *sm;
|
||||
} /*struct_member*/
|
||||
|
||||
void display(std::ostream & os) const;
|
||||
std::string display_string() const;
|
||||
void display(std::ostream & os) const;
|
||||
std::string display_string() const;
|
||||
|
||||
/* mark this TypeDescr complete;
|
||||
* returns the value of .complete_flag from _before_
|
||||
* this call
|
||||
*/
|
||||
bool mark_complete();
|
||||
/* mark this TypeDescr complete;
|
||||
* returns the value of .complete_flag from _before_
|
||||
* this call
|
||||
*/
|
||||
bool mark_complete();
|
||||
|
||||
/* call this once to attach extended type information to a type-description
|
||||
* (e.g. description of struct members for a record type)
|
||||
*/
|
||||
void assign_tdextra(std::unique_ptr<TypeDescrExtra> tdx);
|
||||
/* call this once to attach extended type information to a type-description
|
||||
* (e.g. description of struct members for a record type)
|
||||
*/
|
||||
void assign_tdextra(std::unique_ptr<TypeDescrExtra> tdx);
|
||||
|
||||
private:
|
||||
TypeDescrBase(TypeId id,
|
||||
std::type_info const * tinfo,
|
||||
std::string_view canonical_name,
|
||||
std::unique_ptr<TypeDescrExtra> tdextra);
|
||||
private:
|
||||
TypeDescrBase(TypeId id,
|
||||
std::type_info const * tinfo,
|
||||
std::string_view canonical_name,
|
||||
std::unique_ptr<TypeDescrExtra> tdextra);
|
||||
|
||||
private:
|
||||
/* invariant:
|
||||
* - for all TypeDescrImpl instances x:
|
||||
* - s_type_table_v[x->id()] = x
|
||||
* - s_type_table_map[TypeInfoRef(x->typeinfo())] = x
|
||||
*/
|
||||
private:
|
||||
/* invariant:
|
||||
* - for all TypeDescrImpl instances x:
|
||||
* - s_type_table_v[x->id()] = x
|
||||
* - s_type_table_map[TypeInfoRef(x->typeinfo())] = x
|
||||
*/
|
||||
|
||||
/* hashmap of all TypeDescr instances, indexed by . singleton */
|
||||
static std::unordered_map<TypeInfoRef, std::unique_ptr<TypeDescrBase>> s_type_table_map;
|
||||
/* hashmap of (presumed) duplicate TypeInfoRef values.
|
||||
* This happens with clang sometimes when the same type is referenced
|
||||
* from multiple modules (i.e. shared libs).
|
||||
*/
|
||||
static std::unordered_map<TypeInfoRef, TypeDescrBase *> s_coalesced_type_table_map;
|
||||
/* hashmap of all TypeDescr instances, indexed by . singleton */
|
||||
static std::unordered_map<TypeInfoRef, std::unique_ptr<TypeDescrBase>> s_type_table_map;
|
||||
/* hashmap of (presumed) duplicate TypeInfoRef values.
|
||||
* This happens with clang sometimes when the same type is referenced
|
||||
* from multiple modules (i.e. shared libs).
|
||||
*/
|
||||
static std::unordered_map<TypeInfoRef, TypeDescrBase *> s_coalesced_type_table_map;
|
||||
|
||||
/* vector of all TypeDescr instances. singleton. */
|
||||
static std::vector<TypeDescrBase *> s_type_table_v;
|
||||
/* vector of all TypeDescr instances. singleton. */
|
||||
static std::vector<TypeDescrBase *> s_type_table_v;
|
||||
|
||||
private:
|
||||
/* unique id# for this type */
|
||||
TypeId id_;
|
||||
/* typeinfo for type T */
|
||||
std::type_info const * typeinfo_ = nullptr;
|
||||
/* canonical name for this type (see demangle.hpp for type_name<T>())
|
||||
* e.g.
|
||||
* xo::option::Px2
|
||||
*/
|
||||
std::string_view canonical_name_;
|
||||
/* suffix of .canonical_name, just after last ':'
|
||||
* e.g.
|
||||
* Px2
|
||||
*/
|
||||
std::string_view short_name_;
|
||||
/* set to true once final value for .tdextra is established
|
||||
* intially all TypeDescr objects will use AtomicTdx for .tdextra
|
||||
* Reflect::require() upgrades .tdextra for particular types.
|
||||
* When that procedure makes a decision for a type T,
|
||||
* .complete_flag will be set to true for the corresponding TypeDescrBase instance
|
||||
*/
|
||||
bool complete_flag_ = false;
|
||||
/* additional type information that either:
|
||||
* (a) isn't universal across all types,
|
||||
* e.g. dereferencing instance of a pointer type
|
||||
* (b) can't be captured with template-fu,
|
||||
* e.g. struct member names
|
||||
*
|
||||
* generally .tdextra will be populated some time after TypeDescrBase's ctor exits.
|
||||
* This is necessary because of (b) above, also because of possibility of recursive
|
||||
* types.
|
||||
*/
|
||||
std::unique_ptr<TypeDescrExtra> tdextra_;
|
||||
}; /*TypeDescrBase*/
|
||||
private:
|
||||
/* unique id# for this type */
|
||||
TypeId id_;
|
||||
/* typeinfo for type T */
|
||||
std::type_info const * typeinfo_ = nullptr;
|
||||
/* canonical name for this type (see demangle.hpp for type_name<T>())
|
||||
* e.g.
|
||||
* xo::option::Px2
|
||||
*/
|
||||
std::string_view canonical_name_;
|
||||
/* suffix of .canonical_name, just after last ':'
|
||||
* e.g.
|
||||
* Px2
|
||||
*/
|
||||
std::string_view short_name_;
|
||||
/* set to true once final value for .tdextra is established
|
||||
* intially all TypeDescr objects will use AtomicTdx for .tdextra
|
||||
* Reflect::require() upgrades .tdextra for particular types.
|
||||
* When that procedure makes a decision for a type T,
|
||||
* .complete_flag will be set to true for the corresponding TypeDescrBase instance
|
||||
*/
|
||||
bool complete_flag_ = false;
|
||||
/* additional type information that either:
|
||||
* (a) isn't universal across all types,
|
||||
* e.g. dereferencing instance of a pointer type
|
||||
* (b) can't be captured with template-fu,
|
||||
* e.g. struct member names
|
||||
*
|
||||
* generally .tdextra will be populated some time after TypeDescrBase's ctor exits.
|
||||
* This is necessary because of (b) above, also because of possibility of recursive
|
||||
* types.
|
||||
*/
|
||||
std::unique_ptr<TypeDescrExtra> tdextra_;
|
||||
}; /*TypeDescrBase*/
|
||||
|
||||
inline std::ostream &
|
||||
operator<<(std::ostream & os, TypeDescrBase const & x) {
|
||||
x.display(os);
|
||||
return os;
|
||||
} /*operator<<*/
|
||||
inline std::ostream &
|
||||
operator<<(std::ostream & os, TypeDescrBase const & x) {
|
||||
x.display(os);
|
||||
return os;
|
||||
} /*operator<<*/
|
||||
|
||||
} /*namespace reflect*/
|
||||
/* tag to drive overload resolution */
|
||||
struct reflected_types_printer {};
|
||||
|
||||
inline std::ostream &
|
||||
operator<<(std::ostream & os, reflected_types_printer) {
|
||||
TypeDescrBase::print_reflected_types(os);
|
||||
return os;
|
||||
}
|
||||
|
||||
} /*namespace reflect*/
|
||||
} /*namespace xo*/
|
||||
|
||||
/* end TypeDescr.hpp */
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue