2019-01-25 17:15:15 +08:00
|
|
|
/// @file
|
2018-11-16 17:55:37 +08:00
|
|
|
#pragma once
|
|
|
|
|
2019-01-11 18:10:29 +08:00
|
|
|
#include <cstdint>
|
|
|
|
|
2018-11-16 17:55:37 +08:00
|
|
|
namespace utils {
|
|
|
|
|
|
|
|
/// Type information on a C++ type.
|
|
|
|
///
|
|
|
|
/// You should embed this structure as a static constant member `kType` and make
|
|
|
|
/// sure you generate a unique ID for it. Also, if your type has inheritance,
|
|
|
|
/// you may want to add a `virtual utils::TypeInfo GetType();` method to get the
|
|
|
|
/// runtime type.
|
|
|
|
struct TypeInfo {
|
|
|
|
/// Unique ID for the type.
|
|
|
|
uint64_t id;
|
|
|
|
/// Pretty name of the type.
|
2019-01-11 18:10:29 +08:00
|
|
|
const char *name;
|
2019-01-25 17:15:15 +08:00
|
|
|
/// `TypeInfo *` for superclass of this type.
|
|
|
|
/// Multiple inheritance is not supported.
|
|
|
|
const TypeInfo *superclass{nullptr};
|
2018-11-16 17:55:37 +08:00
|
|
|
};
|
|
|
|
|
2021-02-18 22:32:43 +08:00
|
|
|
inline bool operator==(const TypeInfo &a, const TypeInfo &b) { return a.id == b.id; }
|
|
|
|
inline bool operator!=(const TypeInfo &a, const TypeInfo &b) { return a.id != b.id; }
|
|
|
|
inline bool operator<(const TypeInfo &a, const TypeInfo &b) { return a.id < b.id; }
|
|
|
|
inline bool operator<=(const TypeInfo &a, const TypeInfo &b) { return a.id <= b.id; }
|
|
|
|
inline bool operator>(const TypeInfo &a, const TypeInfo &b) { return a.id > b.id; }
|
|
|
|
inline bool operator>=(const TypeInfo &a, const TypeInfo &b) { return a.id >= b.id; }
|
2018-11-16 17:55:37 +08:00
|
|
|
|
2019-01-25 17:15:15 +08:00
|
|
|
/// Return true if `a` is subtype or the same type as `b`.
|
|
|
|
inline bool IsSubtype(const TypeInfo &a, const TypeInfo &b) {
|
|
|
|
if (a == b) return true;
|
|
|
|
const TypeInfo *super_a = a.superclass;
|
|
|
|
while (super_a) {
|
|
|
|
if (*super_a == b) return true;
|
|
|
|
super_a = super_a->superclass;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class T>
|
|
|
|
bool IsSubtype(const T &a, const TypeInfo &b) {
|
|
|
|
return IsSubtype(a.GetTypeInfo(), b);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Downcast `a` to `TDerived` using static_cast.
|
|
|
|
///
|
|
|
|
/// If `a` is `nullptr` or `TBase` is not a subtype of `TDerived`, then a
|
|
|
|
/// `nullptr` is returned.
|
|
|
|
///
|
|
|
|
/// This downcast is ill-formed if TBase is ambiguous, inaccessible, or virtual
|
|
|
|
/// base (or a base of a virtual base) of TDerived.
|
|
|
|
template <class TDerived, class TBase>
|
|
|
|
TDerived *Downcast(TBase *a) {
|
|
|
|
if (!a) return nullptr;
|
|
|
|
if (IsSubtype(*a, TDerived::kType)) return static_cast<TDerived *>(a);
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2018-11-16 17:55:37 +08:00
|
|
|
} // namespace utils
|