Mediapipe Packet
参考:https://google.github.io/mediapipe/
mediapipe采用图架构实现,主要包括:
- Calculator: 独立功能的计算单元,可以理解为图的节点,有多个input/ouput stream
- Graph: 构建,管理Calculator,多个Calculator组合成Graph。
- Packet: Calculator之间通过input/output stream相连,Packet是stream中传输的数据单元。
input/output任意数据类型?
目标:设计上Calculator有多个input/ouput,任何Calculator的input/ouput可以相连。
在java上有Object/instanceof,可以很容易用Object作为数据传递,instanceof确定类型。但c++上有什么实现方式?
1. RTTI dynamic_cast
可以使用dynamic_cast实现类似java的方式。
class Object {
}
class Data : public Object {
}
Object *input;
Data* input_data = dynamic_cast<Data*>(input);
缺点:dynamic_cast必须是类继承层次之间的转换,我们传递的数据必须继承Object,但如果我们想传递vector, shared_ptr这些stl库呢?
2. void* + type
更暴力的方法就是封装一个class直接传void*,但会有很大隐患,类型少的话用用也还勉强可以。
class Data {
void* ptr;
Type type; //typeid(T) 或者 枚举
void Data(ptr, type);
void ~Data {
switch (type) {
delete ptr;
}
};
}
Packet实现
mediapipe中Packet采用封装,template的方法实现
相关代码:
type_util.h,TypeInfo做了1件事,每个type对应了唯一hashcode,而且也能在不支持rtti下实现。
//不支持rtti
class TypeInfo {
size_t HashCode() const { return reinterpret_cast<size_t>(this); }
template<typename T>
static const TypeInfo& Get() {
static TypeInfo* static_type = new TypeInfo;
return *static_type;
}
}
//支持rtti
class TypeInfo {
size_t HashCode() const { return reinterpret_cast<size_t>(this); }
template<typename T>
static const TypeInfo& Get() {
static TypeInfo* static_type = new TypeInfo(typeid(T));
return *static_type;
}
const std::type_info& mInfo;
}
template <typename T>
const TypeInfo& TypeId() {
return TypeInfo::Get<T>();
}
//获取<T>的hashcode
template <typename T>
size_t GetTypeHash() {
return TypeId<T>().HashCode();
}
//
//example,get不同类型的hashcode
//
GetTypeHash<int>, GetTypeHash<vector<int>>
packet.h, packet.cc
Holder用来封装数据T*, 同时父类HolderBase的mTypeId记录类型。
class HolderBase {
size_t GetHolderTypeId();
template<typename T>
void SetHolderTypeId() {
mTypeId = GetTypeHash<T>();
}
template <typename T>
bool HolderIsType() const;
// 判断是否类型T
template <typename T>
Holder<T>* As() {
if (HolderIsType<Holder<T>>() || HolderIsType<ForeignHolder<T>>()) {
return static_cast<Holder<T>* >(this);
}
return nullptr;
}
size_t mTypeId;
};
template<typename T>
class Holder : public HolderBase{
explicit Holder(const T* ptr) : mPtr(ptr) {
SetHolderTypeId<Holder>();
}
T* ptr;
};
//
// example
//
Holder<int32_t> hold1(new int32_t(100));
HolderBase *baseHolder = &hold1;
const int32_t &a = baseHolder->As<int32_t>()->Data();
Packet主要包含HolderBase
class Packet {
template <typename T>
StatusCode ValidateAsType() const;
template <typename T>
const T& Get() const;
std::shared_ptr<HolderBase> mHolder;
}
//
// example
//
Packet b = Adopt<int64_t>(new int64_t);
b.ValidateAsType<int64_t>();
b.Get<int64_t>();
总结
Packet采用模版来实现统一的数据类型,比较关键的核心是通过模版class TypeInfo来实现类型的hashcode,而且同时能兼容非rtti下使用。