[源码] Meidapipe框架分析——Packet

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下使用。

已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页