.. _cast: ======================================= C++ ABI 和类型工厂基础结构 ======================================= ---- Cast ---- 当 C++ 与 Daslang 交互时,将遵循 `cast` ABI。 * 值类型在特定的内存布局中与 `vec4f` 相互转换 * 引用类型的地址与 `vec4f` 相互转换 预计 vec4f * 可以通过简单的指针强制转换被修剪为 by 值类型,因为在某些情况下,Daslang 解释器将通过 v_ldu 内部函数访问预转换数据:: template TT get_data ( vec4f * dasData ) { // 默认版本 return cast::to(v_ldu((float *)dasData)); } int32_t get_data ( vec4f * dasData ) { // 合法优化的版本 return * (int32_t *) dasData; } ABI 基础设施是通过 C++ 强制转换模板实现的,该模板有两个主要功能: * 将 ``from`` C++ 转换为 Daslang * 从 Daslang 强制转换 ``to`` C++ ``from`` 函数需要一个 Daslang 类型作为输入,并输出一个 vec4f。 ``to`` 函数需要一个 vec4f,并输出一个 Daslang 类型。 让我们回顾一下以下示例:: template <> struct cast { static __forceinline int32_t to ( vec4f x ) { return v_extract_xi(v_cast_vec4i(x)); } static __forceinline vec4f from ( int32_t x ) { return v_cast_vec4f(v_splatsi(x)); } }; 它实现了 int32_t 的 ABI,它使用多平台内联函数在 vec4f 的开头打包了一个 int32_t 值。 让我们回顾另一个示例,该示例实现引用类型的默认打包:: template struct cast { static __forceinline TT & to ( vec4f a ) { return *(TT *) v_extract_ptr(v_cast_vec4i((a))); } static __forceinline vec4f from ( const TT & p ) { return v_cast_vec4f(v_splats_ptr((const void *)&p)); } }; 在这里,指向数据的指针使用多平台内部函数打包在 vec4f 中。 ------------ 类型工厂 ------------ 当 C++ 类型公开给 Daslang 时,将采用类型工厂基础结构。 要公开任何自定义C++类型,请使用 ``MAKE_TYPE_FACTORY`` 宏,或者 ``MAKE_EXTERNAL_TYPE_FACTORY`` 和 ``IMPLEMENT_EXTERNAL_TYPE_FACTORY`` 宏对: MAKE_TYPE_FACTORY(clock, das::Time) 上面的示例告诉 Daslang,C++ 类型`das::Time`将公开给名称为`clock`的 Daslang。 让我们看看 ``MAKE_TYPE_FACTORY`` 宏的实现:: #define MAKE_TYPE_FACTORY(TYPE,CTYPE) \ namespace das { \ template <> \ struct typeFactory { \ static TypeDeclPtr make(const ModuleLibrary & library ) { \ return makeHandleType(library,#TYPE); \ } \ }; \ template <> \ struct typeName { \ constexpr static const char * name() { return #TYPE; } \ }; \ }; 在上面的示例中发生的情况是,两个模板化策略公开给 C++。 ``typeName`` 策略有一个静态函数 ``name``,它返回类型的字符串名称。 ``typeFactory`` 策略创建一个指向 Daslang 的智能指针 `das::TypeDecl` 类型,它对应于 C++ 类型。 它期望在提供的 ModuleLibrary 中的某个位置找到类型(参阅 :ref:`Modules `)。 ------------ 类型别名 ------------ 自定义类型工厂是创建别名的首选方法:: struct Point3 { float x, y, z; }; template <> struct typeFactory { static TypeDeclPtr make(const ModuleLibrary &) { auto t = make_smart(Type::tFloat3); t->alias = "Point3"; t->aotAlias = true; return t; } }; template <> struct typeName { constexpr static const char * name() { return "Point3"; } }; 在上面的示例中,C++ 应用程序已经具有`Point3`类型,这与 Daslang 的 float3 非常相似。 最好公开对 Point3 进行作的 C++ 函数,因此该实现会创建一个名为 `Point3` 的别名,该别名对应于 das Type::tFloat3。 有时,需要一个 ``typeFactory`` 的自定义实现,以便以更原生的方式将 C++ 暴露给 Daslang 类型。让我们回顾一下以下示例:: struct SampleVariant { int32_t _variant; union { int32_t i_value; float f_value; char * s_value; }; }; template <> struct typeFactory { static TypeDeclPtr make(const ModuleLibrary & library ) { auto vtype = make_smart(Type::tVariant); vtype->alias = "SampleVariant"; vtype->aotAlias = true; vtype->addVariant("i_value", typeFactory::make(library)); vtype->addVariant("f_value", typeFactory::make(library)); vtype->addVariant("s_value", typeFactory::make(library)); // optional validation DAS_ASSERT(sizeof(SampleVariant) == vtype->getSizeOf()); DAS_ASSERT(alignof(SampleVariant) == vtype->getAlignOf()); DAS_ASSERT(offsetof(SampleVariant, i_value) == vtype->getVariantFieldOffset(0)); DAS_ASSERT(offsetof(SampleVariant, f_value) == vtype->getVariantFieldOffset(1)); DAS_ASSERT(offsetof(SampleVariant, s_value) == vtype->getVariantFieldOffset(2)); return vtype; } }; 此处,C++ 类型 `SomeVariant` 与 Daslang 变体类型及其内存布局匹配。 上面的代码公开了一个 C++ 类型别名,并创建了一个对应的 TypeDecl。