Object/Node

Object是所有对象容器的基类。
Node是runtime::Object的别名。

Objecgt子类的对象应该声明以下静态constexpr字段。

  • _type_index

    1. 对象的静态类型索引,并非当前对象的类型索引,旨在被子类作为默认值使用。如果设置为TypeIndex::kDynamic,类型索引将在运行时分配。<br /> 运行时类型索引可以通过ObjectType::TypeIndex()访问。
  • _type_key

    1. type类型的唯一字符串标识符。
  • _type_final

    1. 类型是否为终端类型(在对象系统中没有该类型的子类),该字段由marco TVM_DECLARE_FINAL_OBJECT_INFO自动设置。<br /> 对于终端对象类型T的子类,使用make_object构造它仍然是可以的,但IsInstance检查只会显示对象类型为T(而不是子类)。

以下两个字段是可以被子类化的基类所必需的:

  • _type_child_slots:

    1. 为子类保留的类型索引槽的数量。用于IsInstance中类型检查的运行时优化。<br /> 如果一个对象的type_index在[type_index, type_index + _type_child_slots]的范围内,则可以快速判定该对象为当前对象类的子类,如果不是,则使用回退机制检查全局类型表。<br /> 建议:设置为估计需要的子类数量。
  • _type_child_slots_can_overflow:

    1. 即使子类的数量超过了_type_child_slots,我们是否可以添加额外的子类。将使用一个后备机制来检查全局类型表。<br /> 建议:如果我们知道确切的子代数量,为了优化运行速度,将其设置为false

用于在对象中声明辅助函数的两个宏:

  • TVM_DECLARE_BASE_OBJECT_INFO 用于可以被子类化的对象类.
  • TVM_DECLARE_FINAL_OBJECT_INFO 用于不可以被子类化的对象类。

新的对象可以使用make_object函数来创建,这将自动设置对象的type_index和deleter。

部分源码如下:

  1. class Object {
  2. public:
  3. /*!
  4. * Check if the object is an instance of TargetType.
  5. * \tparam TargetType The target type to be checked.
  6. * \return Whether the target type is true.
  7. */
  8. template<typename TargetType>
  9. inline bool IsInstance() const;
  10. static constexpr const char* _type_key = "Object";
  11. // Default object type properties for sub-classes
  12. static constexpr bool _type_final = false;
  13. static constexpr uint32_t _type_child_slots = 0;
  14. static constexpr bool _type_child_slots_can_overflow = true;
  15. // NOTE: the following field is not type index of Object
  16. // but was intended to be used by sub-classes as default value.
  17. // The type index of Object is TypeIndex::kRoot
  18. static constexpr uint32_t _type_index = TypeIndex::kDynamic;
  19. protected:
  20. // The fields of the base object cell.
  21. /*! \brief Type index(tag) that indicates the type of the object. */
  22. uint32_t type_index_{0};
  23. /*! \brief The internal reference counter */
  24. RefCounterType ref_counter_{0};
  25. /*!
  26. * \brief deleter of this object to enable customized allocation.
  27. * If the deleter is nullptr, no deletion will be performed.
  28. * The creator of the object must always set the deleter field properly.
  29. */
  30. FDeleter deleter_ = nullptr;
  31. private:
  32. /*!
  33. * \return The usage count of the cell.
  34. * \note We use stl style naming to be consistent with known API in shared_ptr.
  35. */
  36. inline int use_count() const;
  37. /*!
  38. * \brief Check of this object is derived from the parent.
  39. * \param parent_tindex The parent type index.
  40. * \return The derivation results.
  41. */
  42. TVM_DLL bool DerivedFrom(uint32_t parent_tindex) const;
  43. };


ObjectPtr

ObjectPtr是Object的自定义智能指针。
它是一个模板类。部分源码如下:

  1. template <typename T>
  2. class ObjectPtr {
  3. ...
  4. public:
  5. /*!
  6. * \return Get the content of the pointer
  7. */
  8. T* get() const {
  9. return static_cast<T*>(data_);
  10. }
  11. /*!
  12. * \return The pointer
  13. */
  14. T* operator->() const {
  15. return get();
  16. }
  17. /*!
  18. * \return The reference
  19. */
  20. T& operator*() const { // NOLINT(*)
  21. return *get();
  22. }
  23. private:
  24. /*! \brief internal pointer field */
  25. Object* data_{nullptr};
  26. ...
  27. }

它唯一的字段是Object data. 一般的,T是Object的子类。它的函数get()可以将data变成T

ObjectRef

ObjectRef是所有对象引用的基类。
部分源码如下:

  1. /*! \brief Base class of all object reference */
  2. class ObjectRef {
  3. public:
  4. /*!
  5. * \brief Comparator
  6. * \param other Another object ref.
  7. * \return the compare result.
  8. */
  9. bool same_as(const ObjectRef& other) const {
  10. return data_ == other.data_;
  11. }
  12. /*! \return whether the expression is null */
  13. bool defined() const {
  14. return data_ != nullptr;//注意,在ObjectPtr中重载了!=,所以这里是没有问题的。
  15. }
  16. /*! \return the internal object pointer */
  17. const Object* get() const {
  18. return data_.get();
  19. }
  20. /*! \return the internal object pointer */
  21. const Object* operator->() const {
  22. return get();
  23. }
  24. /*!
  25. * \brief Try to downcast the internal Object to a
  26. * raw pointer of a corresponding type.
  27. *
  28. * The function will return a nullptr if the cast failed.
  29. *
  30. * if (const Add *add = node_ref.As<Add>()) {
  31. * // This is an add node
  32. * }
  33. * \tparam ObjectType the target type, must be a subtype of Object/
  34. */
  35. template <typename ObjectType>
  36. inline const ObjectType* as() const;
  37. /*! \brief type indicate the container type. */
  38. using ContainerType = Object;
  39. protected:
  40. /*! \brief Internal pointer that backs the reference. */
  41. ObjectPtr<Object> data_;
  42. /*!
  43. * \brief Internal helper function downcast a ref without check.
  44. * \note Only used for internal dev purposes.
  45. * \tparam T The target reference type.
  46. * \return The casted result.
  47. */
  48. template<typename T>
  49. static T DowncastNoCheck(ObjectRef ref) {
  50. return T(std::move(ref.data_));
  51. }
  52. /*!
  53. * \brief Internal helper function get data_ as ObjectPtr of ObjectType.
  54. * \note only used for internal dev purpose.
  55. * \tparam ObjectType The corresponding object type.
  56. * \return the corresponding type.
  57. */
  58. template<typename ObjectType>
  59. static ObjectPtr<ObjectType> GetDataPtr(const ObjectRef& ref) {
  60. return ObjectPtr<ObjectType>(ref.data_.data_);
  61. }
  62. };

该类含有一个字段是ObjectPtr data_;

几个重要函数

  1. // 判断某个Object实例是否是某类的的实例
  2. template<typename TargetType>
  3. inline bool Object::IsInstance() const {
  4. const Object* self = this;
  5. // NOTE: the following code can be optimized by
  6. // compiler dead-code elimination for already known constants.
  7. if (self != nullptr) {
  8. // Everything is a subclass of object.
  9. if (std::is_same<TargetType, Object>::value) return true;
  10. if (TargetType::_type_final) {
  11. // if the target type is a final type
  12. // then we only need to check the equivalence.
  13. return self->type_index_ == TargetType::RuntimeTypeIndex();
  14. } else {
  15. // if target type is a non-leaf type
  16. // Check if type index falls into the range of reserved slots.
  17. uint32_t begin = TargetType::RuntimeTypeIndex();
  18. // The condition will be optimized by constant-folding.
  19. if (TargetType::_type_child_slots != 0) {
  20. uint32_t end = begin + TargetType::_type_child_slots;
  21. if (self->type_index_ >= begin && self->type_index_ < end) return true;
  22. } else {
  23. if (self->type_index_ == begin) return true;
  24. }
  25. if (!TargetType::_type_child_slots_can_overflow) return false;
  26. // Invariance: parent index is always smaller than the child.
  27. if (self->type_index_ < TargetType::RuntimeTypeIndex()) return false;
  28. // The rare slower-path, check type hierachy.
  29. return self->DerivedFrom(TargetType::RuntimeTypeIndex());
  30. }
  31. } else {
  32. return false;
  33. }
  34. }
  35. // 尝试将ObjectRef类对象的内部Object转为指定类型的指针
  36. template <typename ObjectType>
  37. inline const ObjectType* ObjectRef::as() const {
  38. if (data_ != nullptr &&
  39. data_->IsInstance<ObjectType>()) {
  40. return static_cast<ObjectType*>(data_.get());
  41. } else {
  42. return nullptr;
  43. }
  44. }
  45. // 从Object类指针获得其引用类型指针
  46. template <typename RefType, typename ObjType>
  47. inline RefType GetRef(const ObjType* ptr) {
  48. static_assert(std::is_base_of<typename RefType::ContainerType, ObjType>::value,
  49. "Can only cast to the ref of same container type");
  50. return RefType(ObjectPtr<Object>(const_cast<Object*>(static_cast<const Object*>(ptr))));
  51. }
  52. template <typename BaseType, typename ObjType>
  53. inline ObjectPtr<BaseType> GetObjectPtr(ObjType* ptr) {
  54. static_assert(std::is_base_of<BaseType, ObjType>::value,
  55. "Can only cast to the ref of same container type");
  56. return ObjectPtr<BaseType>(static_cast<Object*>(ptr));
  57. }
  58. template <typename SubRef, typename BaseRef>
  59. inline SubRef Downcast(BaseRef ref) {
  60. CHECK(ref->template IsInstance<typename SubRef::ContainerType>())
  61. << "Downcast from " << ref->GetTypeKey() << " to "
  62. << SubRef::ContainerType::_type_key << " failed.";
  63. return SubRef(std::move(ref.data_));
  64. }


Demo

  1. // Create a base object
  2. class ObjBase: public Object {
  3. public:
  4. // object fields
  5. int field0;
  6. // object properties
  7. static constexpr const uint32_t _type_index = TypeIndex::kDynamic;
  8. static constexpr const char _type_key = "test.ObjBase ";
  9. TVM_DECLARE_BASE_OBJECT_INFO(ObjBase , Object);
  10. };
  11. class ObjLeaf : public ObjBase {
  12. public:
  13. // fields
  14. int child_field0;
  15. // object properties
  16. static constexpr const uint32_t _type_index = TypeIndex::kDynamic;
  17. static constexpr const char _type_key = "test.ObjLeaf ";
  18. TVM_DECLARE_BASE_OBJECT_INFO(ObjLeaf , ObjBase);
  19. };
  20. // The following code should be put into a cc file.
  21. TVM_REGISTER_OBJECT_TYPE(ObjBase);
  22. TVM_REGISTER_OBJECT_TYPE(ObjLeaf);
  23. // Usage example.
  24. void TestObjects() {
  25. // create an object
  26. ObjectRef leaf_ref(make_object<ObjLeaf>());
  27. // cast to a specific instance
  28. const ObjLeaf *leaf_ptr = leaf_ref.as<ObjLeaf>();
  29. CHECK(leaf_ptr != nullptr);
  30. // can also cast to the base class.
  31. CHECK(leaf_ref.as<ObjBase>() != nullptr);
  32. }