Files
2026-07-13 13:35:51 +08:00

329 lines
10 KiB
C++

/**
* Copyright (c) 2019 by Contributors
* @file runtime/object.h
* @brief Defines the Object data structures.
*/
#ifndef DGL_RUNTIME_OBJECT_H_
#define DGL_RUNTIME_OBJECT_H_
#include <dmlc/logging.h>
#include <memory>
#include <string>
#include <type_traits>
#include <vector>
namespace dgl {
namespace runtime {
// forward declaration
class Object;
class ObjectRef;
class NDArray;
/**
* @brief Visitor class to each object attribute.
* The content is going to be called for each field.
*/
class AttrVisitor {
public:
//! \cond Doxygen_Suppress
virtual void Visit(const char* key, double* value) = 0;
virtual void Visit(const char* key, int64_t* value) = 0;
virtual void Visit(const char* key, uint64_t* value) = 0;
virtual void Visit(const char* key, int* value) = 0;
virtual void Visit(const char* key, bool* value) = 0;
virtual void Visit(const char* key, std::string* value) = 0;
virtual void Visit(const char* key, ObjectRef* value) = 0;
virtual void Visit(const char* key, NDArray* value) = 0;
template <
typename ENum,
typename = typename std::enable_if<std::is_enum<ENum>::value>::type>
void Visit(const char* key, ENum* ptr) {
static_assert(
std::is_same<int, typename std::underlying_type<ENum>::type>::value,
"declare enum to be enum int to use visitor");
this->Visit(key, reinterpret_cast<int*>(ptr));
}
//! \endcond
};
/**
* @brief base class of object container.
* All object's internal is stored as std::shared_ptr<Object>
*/
class Object {
public:
/** @brief virtual destructor */
virtual ~Object() {}
/** @return The unique type key of the object */
virtual const char* type_key() const = 0;
/**
* @brief Apply visitor to each field of the Object
* Visitor could mutate the content of the object.
* override if Object contains attribute fields.
* @param visitor The visitor
*/
virtual void VisitAttrs(AttrVisitor* visitor) {}
/** @return the type index of the object */
virtual uint32_t type_index() const = 0;
/**
* @brief Whether this object derives from object with type_index=tid.
* Implemented by DGL_DECLARE_OBJECT_TYPE_INFO
*
* @param tid The type index.
* @return the check result.
*/
virtual bool _DerivedFrom(uint32_t tid) const;
/**
* @brief get a runtime unique type index given a type key
* @param type_key Type key of a type.
* @return the corresponding type index.
*/
static uint32_t TypeKey2Index(const char* type_key);
/**
* @brief get type key from type index.
* @param index The type index
* @return the corresponding type key.
*/
static const char* TypeIndex2Key(uint32_t index);
/**
* @return whether the type is derived from
*/
template <typename T>
inline bool derived_from() const;
/**
* @return whether the object is of type T
* @tparam The type to be checked.
*/
template <typename T>
inline bool is_type() const;
// object ref can see this
friend class ObjectRef;
static constexpr const char* _type_key = "Object";
};
/** @brief base class of all reference object */
class ObjectRef {
public:
/** @brief type indicate the container type */
using ContainerType = Object;
/**
* @brief Comparator
*
* Compare with the two are referencing to the same object (compare by
* address).
*
* @param other Another object ref.
* @return the compare result.
* @sa same_as
*/
inline bool operator==(const ObjectRef& other) const;
/**
* @brief Comparator
*
* Compare with the two are referencing to the same object (compare by
* address).
*
* @param other Another object ref.
* @return the compare result.
*/
inline bool same_as(const ObjectRef& other) const;
/**
* @brief Comparator
*
* The operator overload allows ObjectRef be used in std::map.
*
* @param other Another object ref.
* @return the compare result.
*/
inline bool operator<(const ObjectRef& other) const;
/**
* @brief Comparator
* @param other Another object ref.
* @return the compare result.
* @sa same_as
*/
inline bool operator!=(const ObjectRef& other) const;
/** @return the hash function for ObjectRef */
inline size_t hash() const;
/** @return whether the expression is null */
inline bool defined() const;
/** @return the internal type index of Object */
inline uint32_t type_index() const;
/** @return the internal object pointer */
inline const Object* get() const;
/** @return the internal object pointer */
inline const Object* operator->() const;
/**
* @brief Downcast this object to its actual type.
* This returns nullptr if the object is not of the requested type.
* Example usage:
*
* if (const Banana *banana = obj->as<Banana>()) {
* // This is a Banana!
* }
* @tparam T the target type, must be subtype of Object
*/
template <typename T>
inline const T* as() const;
/** @brief default constructor */
ObjectRef() = default;
explicit ObjectRef(std::shared_ptr<Object> obj) : obj_(obj) {}
/** @brief the internal object, do not touch */
std::shared_ptr<Object> obj_;
};
/**
* @brief helper macro to declare type information in a base object.
*
* This is macro should be used in abstract base class definition
* because it does not define type_key and type_index.
*/
#define DGL_DECLARE_BASE_OBJECT_INFO(TypeName, Parent) \
const bool _DerivedFrom(uint32_t tid) const override { \
static uint32_t tidx = TypeKey2Index(TypeName::_type_key); \
if (tidx == tid) return true; \
return Parent::_DerivedFrom(tid); \
}
/**
* @brief helper macro to declare type information in a terminal class
*
* This is macro should be used in terminal class definition.
*
* For example:
*
* // This class is an abstract class and cannot create instances
* class SomeBaseClass : public Object {
* public:
* static constexpr const char* _type_key = "some_base";
* DGL_DECLARE_BASE_OBJECT_INFO(SomeBaseClass, Object);
* };
*
* // Child class that allows instantiation
* class SomeChildClass : public SomeBaseClass {
* public:
* static constexpr const char* _type_key = "some_child";
* DGL_DECLARE_OBJECT_TYPE_INFO(SomeChildClass, SomeBaseClass);
* };
*/
#define DGL_DECLARE_OBJECT_TYPE_INFO(TypeName, Parent) \
const char* type_key() const final { return TypeName::_type_key; } \
uint32_t type_index() const final { \
static uint32_t tidx = TypeKey2Index(TypeName::_type_key); \
return tidx; \
} \
bool _DerivedFrom(uint32_t tid) const final { \
static uint32_t tidx = TypeKey2Index(TypeName::_type_key); \
if (tidx == tid) return true; \
return Parent::_DerivedFrom(tid); \
}
/** @brief Macro to generate common object reference class method definition */
#define DGL_DEFINE_OBJECT_REF_METHODS(TypeName, BaseTypeName, ObjectName) \
TypeName() {} \
explicit TypeName(std::shared_ptr<runtime::Object> obj) \
: BaseTypeName(obj) {} \
const ObjectName* operator->() const { \
return static_cast<const ObjectName*>(obj_.get()); \
} \
ObjectName* operator->() { return static_cast<ObjectName*>(obj_.get()); } \
std::shared_ptr<ObjectName> sptr() const { \
return CHECK_NOTNULL(std::dynamic_pointer_cast<ObjectName>(obj_)); \
} \
operator bool() const { return this->defined(); } \
using ContainerType = ObjectName
/** @brief Macro to generate object reference class definition */
#define DGL_DEFINE_OBJECT_REF(TypeName, ObjectName) \
class TypeName : public ::dgl::runtime::ObjectRef { \
public: \
DGL_DEFINE_OBJECT_REF_METHODS( \
TypeName, ::dgl::runtime::ObjectRef, ObjectName); \
}
// implementations of inline functions after this
template <typename T>
inline bool Object::is_type() const {
// use static field so query only happens once.
static uint32_t type_id = Object::TypeKey2Index(T::_type_key);
return type_id == this->type_index();
}
template <typename T>
inline bool Object::derived_from() const {
// use static field so query only happens once.
static uint32_t type_id = Object::TypeKey2Index(T::_type_key);
return this->_DerivedFrom(type_id);
}
inline const Object* ObjectRef::get() const { return obj_.get(); }
inline const Object* ObjectRef::operator->() const { return obj_.get(); }
inline bool ObjectRef::defined() const { return obj_.get() != nullptr; }
inline bool ObjectRef::operator==(const ObjectRef& other) const {
return obj_.get() == other.obj_.get();
}
inline bool ObjectRef::same_as(const ObjectRef& other) const {
return obj_.get() == other.obj_.get();
}
inline bool ObjectRef::operator<(const ObjectRef& other) const {
return obj_.get() < other.obj_.get();
}
inline bool ObjectRef::operator!=(const ObjectRef& other) const {
return obj_.get() != other.obj_.get();
}
inline size_t ObjectRef::hash() const {
return std::hash<Object*>()(obj_.get());
}
inline uint32_t ObjectRef::type_index() const {
CHECK(obj_.get() != nullptr) << "null type";
return get()->type_index();
}
template <typename T>
inline const T* ObjectRef::as() const {
const Object* ptr = get();
if (ptr && ptr->is_type<T>()) {
return static_cast<const T*>(ptr);
}
return nullptr;
}
/** @brief The hash function for nodes */
struct ObjectHash {
size_t operator()(const ObjectRef& a) const { return a.hash(); }
};
/** @brief The equal comparator for nodes */
struct ObjectEqual {
bool operator()(const ObjectRef& a, const ObjectRef& b) const {
return a.get() == b.get();
}
};
} // namespace runtime
} // namespace dgl
namespace std {
template <>
struct hash<::dgl::runtime::ObjectRef> {
std::size_t operator()(const ::dgl::runtime::ObjectRef& k) const {
return k.hash();
}
};
} // namespace std
#endif // DGL_RUNTIME_OBJECT_H_