iis7配置asp.net网站,做品牌折扣微信推广的网站,简单网页设计主题,开发者是什么意思在TVM Object类型系统中最重要的是三个类#xff1a;Object、ObjectPtr、ObjectRef
为什么需要这三个类#xff1f;
设计目的#xff1a;为了能够在不更改python前端的情况下扩展c中的语言对象#xff0c;且能够对任何语言对象序列化。
Object#xff1a;编译器中所有的…在TVM Object类型系统中最重要的是三个类Object、ObjectPtr、ObjectRef
为什么需要这三个类
设计目的为了能够在不更改python前端的情况下扩展c中的语言对象且能够对任何语言对象序列化。
Object编译器中所有的语言对象命名一般以Node结尾都是Object的子类Object的子类保存了一般保存了数据成员变量ObjectPtrObject的子定义智能指针用于进行内存管理ObjectRefObject的引用ObjectRef的子类一般包含操作Object类的函数
代码实现
class TVM_DLL Object {protected:uint32_t type_index_{0};RefCounterType ref_counter_{0};FDeleter deleter_ nullptr;inline void IncRef(); // 增加引用计数inline void DecRef(); // 减少引用计数private:inline int use_count() const; // 返回引用计数
};template typename T
class ObjectPtr {public:// 默认构造函数ObjectPtr() {}ObjectPtr(std::nullptr_t) {}// 拷贝构造会调用构造函数从而增加引用数ObjectPtr(const ObjectPtrT other) : ObjectPtr(other.data_) {}template typename UObjectPtr(const ObjectPtrU other) : ObjectPtr(other.data_) {static_assert(std::is_base_ofT, U::value,can only assign of child class ObjectPtr to parent);}// 移动构造函数不调用构造函数引用数不变ObjectPtr(ObjectPtrT other) : data_(other.data_) { other.data_ nullptr; }template typename YObjectPtr(ObjectPtrY other) : data_(other.data_) {static_assert(std::is_base_ofT, Y::value, can only assign of child class ObjectPtr to parent);other.data_ nullptr;}// 析构函数~ObjectPtr() {if (data_ ! nullptr) {data_-DecRef();data_ nullptr;}// 使用计数int use_count() const { return data_ ! nullptr ? data_-use_count() : 0; }// 访问成员变量T* get() const { return static_castT*(data_); }T* operator-() const { return get(); }T operator*() const { return *get(); }private:Object* data_{nullptr};// 构造函数explicit意味着参数不能进行隐式转换explicit ObjectPtr(Object* data) : data_(data) {if (data ! nullptr) {data_-IncRef();}}
};class ObjectRef {public:const Object* get() const { return data_.get(); }const Object* operator-() const { return get(); }using ContainerType Object;protected:ObjectPtrObject data_;
};ObjectPtr类中有Object*类型的data_成员变量可以通过-操作符和get()函数返回Object*指针。 ObjectRef类中有ObjectPtrObject类型的data_成员变量也可以通过-操作符和get()函数返回Object*指针调用了data_成员变量的get()函数。
我们以StringObj、String类为例来展示功能
class StringObj : public Object {public:const char* data;uint64_t size;static constexpr const uint32_t _type_index TypeIndex::kRuntimeString;static constexpr const char* _type_key runtime.String;TVM_DECLARE_FINAL_OBJECT_INFO(StringObj, Object);private:class FromStd; // 内部类用于从std::string初始化data和size
};class StringObj::FromStd : public StringObj {public:explicit FromStd(std::string other) : data_container{other} {}private:std::string data_container;
};class String : public ObjectRef {public:String() : String(std::string()) {}String(std::string other);String(const char* other): String(std::string(other)) {}String(std::nullptr_t): ObjectRef(nullptr) {}const char* c_str() const { return get()-data; }const char* data() const { return get()-data; }// 类型转换运算符重载operator std::string() const { return std::string{get()-data, size()}; }size_t size() const {const auto* ptr get();return ptr-size;}size_t length() const { return size(); }bool empty() const { return size() 0; }char at(size_t pos) const {...}TVM_DEFINE_NOTNULLABLE_OBJECT_REF_METHODS(String, ObjectRef, StringObj);
};StringObj类中定义了字符串的首字符的指针和字符串的长度定义了类型键和类型索引并使用了TVM_DECLARE_FINAL_OBJECT_INFO宏定义如下
#define TVM_DECLARE_FINAL_OBJECT_INFO(TypeName, ParentType) \static const constexpr bool _type_final true; \static const constexpr int _type_child_slots 0; \TVM_DECLARE_BASE_OBJECT_INFO(TypeName, ParentType)#define TVM_DECLARE_BASE_OBJECT_INFO(TypeName, ParentType) \static_assert(!ParentType::_type_final, ParentObj marked as final); \static uint32_t RuntimeTypeIndex() { \static_assert(TypeName::_type_child_slots 0 || ParentType::_type_child_slots 0 || \TypeName::_type_child_slots ParentType::_type_child_slots, \Need to set _type_child_slots when parent specifies it.); \if (TypeName::_type_index ! ::tvm::runtime::TypeIndex::kDynamic) { \return TypeName::_type_index; \} \return _GetOrAllocRuntimeTypeIndex(); \} \static uint32_t _GetOrAllocRuntimeTypeIndex() { \static uint32_t tindex Object::GetOrAllocRuntimeTypeIndex( \TypeName::_type_key, TypeName::_type_index, ParentType::_GetOrAllocRuntimeTypeIndex(), \TypeName::_type_child_slots, TypeName::_type_child_slots_can_overflow); \return tindex; \}TVM_DECLARE_BASE_OBJECT_INFO宏定义了两个静态变量以及两个静态函数RuntimeTypeIndex()用于获取运行时类型索引在StringObj构造时type_index_成员变量的值通过该函数得到。
tvm::runtime::String类中定义了对StringObj进行操作的函数如size()并使用了TVM_DEFINE_NOTNULLABLE_OBJECT_REF_METHODS宏定义如下
#define TVM_DEFINE_NOTNULLABLE_OBJECT_REF_METHODS(TypeName, ParentType, ObjectName) \explicit TypeName(::tvm::runtime::ObjectPtr::tvm::runtime::Object n) : ParentType(n) {} \TVM_DEFINE_DEFAULT_COPY_MOVE_AND_ASSIGN(TypeName); \const ObjectName* operator-() const { return static_castconst ObjectName*(data_.get()); } \const ObjectName* get() const { return operator-(); } \static constexpr bool _type_is_nullable false; \using ContainerType ObjectName;TVM_DEFINE_NOTNULLABLE_OBJECT_REF_METHODS宏定义了一个构造函数重载了-运算符和get()函数返回值类型不再是Object*而是StringObj*标记该类型是不可为空的定义了容器类型。
构造过程
构造函数String(std::string other);的实现如下
inline String::String(std::string other) {auto ptr make_objectStringObj::FromStd(std::move(other));ptr-size ptr-data_container.size();ptr-data ptr-data_container.data();data_ std::move(ptr);
}可以看到在构造tvm::runtime::String时首先使用分配器由std::string参数创建一个ObjectPtrStringObj::FromStd类型的对象。分配器创建完成后将StringObj::FromStd的data_container的size和data直接赋值给StringObj的size和data然后将ptr移动到tvm::runtime::String的data_。 // include/tvm/runtime/memory.h
template typename T, typename... Args
inline ObjectPtrT make_object(Args... args) {return SimpleObjAllocator().make_objectT(std::forwardArgs(args)...);
}template typename Derived
class ObjAllocatorBase {public:template typename T, typename... Argsinline ObjectPtrT make_object(Args... args) {using Handler typename Derived::template HandlerT;static_assert(std::is_base_ofObject, T::value, make can only be used to create Object);T* ptr Handler::New(static_castDerived*(this), std::forwardArgs(args)...);ptr-type_index_ T::RuntimeTypeIndex();ptr-deleter_ Handler::Deleter();return ObjectPtrT(ptr);}
}使用分配器创建时把std::string移动到了data_container中这时调用了StringObj的构造函数然后设置了StringObj的type_index_和deleter_最后构造通过ObjectPtr(Object* data)并返回了ObjectPtr在构造时增加了Object的引用数。
总结
构造ObjectRef的过程中对Object进行了构造主要使用Object保存数据ObjectPtr用于内存管理ObjectRef表示引用并对数据进行操作。