slua unreal分析(四)LuaArray&LuaMap
相关文章:之前介绍的UObject,UStruct传递都是单个元素传递,slua也支持array和map的容器传递。
LuaArray
UE中数组类型为TArray,把TArray从UE传到lua,会用一个LuaArray类把TArray包装起来,LuaArray也提供了迭代接口供lua使用数组常用操作。
TArray传到Lua时有两种创建LuaArray方式,一种会把TArray复制一份,Lua中对LuaArray操作不会影响C++TArray,另一种是把TArray引用传到Lua。Lua对LuaArray的添加和删除会影响C++的TArray。
复制一份
当TArray作为函数的返回值时,会复制一份,相关代码如下:
构造函数接受两个参数,分别为数组元素的UProperty,和源array数据。
LuaArray::LuaArray(UProperty* p, FScriptArray* buf)
: inner(p)
, prop(nullptr)
, propObj(nullptr)
{
array = new FScriptArray();
clone(array, p, buf);
}
void LuaArray::clone(FScriptArray* destArray, UProperty* p, const FScriptArray* srcArray) {
// blueprint stack will destroy the TArray
// so deep-copy construct FScriptArray
// it's very expensive
if(!srcArray || srcArray->Num()==0)
return;
FScriptArrayHelper helper = FScriptArrayHelper::CreateHelperFormInnerProperty(p,destArray);
helper.AddValues(srcArray->Num());
uint8* dest = helper.GetRawPtr(;
uint8* src = (uint8*)srcArray->GetData();
for(int n=0;n<srcArray->Num();n++) {
p->CopySingleValue(dest,src);
dest+=p->ElementSize;
src+=p->ElementSize;
}
}源array类型为FScriptArray,可以认为是一个数组,通过遍历FScriptArray可以把元素逐个复制到luaarray的array属性中。因为我们已经知道了数组内元素的UProperty类型,因此可用对应的CopySingleValue方法利用反射机制来拷贝元素。
传递引用
把UObject上的TArray属性进行传递时,会使用传递引用的方式。LuaArray构造函数中,并没有创建新的FScriptArray,而是把Tarray的指针赋给了array,因此Lua中操作的就是TArray本身,对LuaArray的add和remove操作都会影响到实际的TArray。
LuaArray::LuaArray(UArrayProperty* p, UObject* obj)
: inner(p->Inner)
, prop(p)
, propObj(obj)
{
array = prop->ContainerPtrToValuePtr<FScriptArray>(obj);
}
数组迭代
LuaArray实现了基本的add,remove,迭代等功能,前面的相对简单,主要介绍下迭代功能。
Lua中,可以通过for in pairs语法遍历LuaArray中的元素:
for i,v in pairs(arr) do
print(&#34;arr item&#34;,i,v)
endslua提供了LuaArray::Enumerator类作为迭代器,LuaArray::Enumerable作为迭代函数,来实现pairs功能,迭代函数内容如下:
int LuaArray::Enumerable(lua_State* L) {
CheckUD(LuaArray::Enumerator, L, 1);
auto arr = UD->arr;
if (arr->isValidIndex(UD->index)) {
auto element = arr->inner;
auto es = element->ElementSize;
auto parms = ((uint8*)arr->array->GetData()) + UD->index * es;
LuaObject::push(L, UD->index);
LuaObject::push(L, element, parms);
UD->index += 1;
return 2;
}
return 0;
}UD就是Enumerator,index为当前遍历到的下标,根据下标和数组,直接去ScriptArray对应的内存偏移取元素指针,返回给lua。
LuaArray与GC
LuaArray会对内部的元素产生引用,UEGC会看到这些引用,当LuaArray销毁,这些引用也会消失。因为LuaArray继承自FGCObject,内部实现了AddReferencedObjects()函数,每次UE执行GC时,都会调用这个函数。函数内部通过之前介绍的LuaReference方法,模拟一遍UE的引用添加逻辑。
LuaMap
LuaMap与LuaArray的实现思想基本相同,也实现了Map的add,remove等常用功能,最大的区别可能是LuaMap底层数据为ScriptMap散列表,这也使LuaMap在一些处理上要小心对待。
如下图所示,ScriptArray和ScriptMap都存储了3个元素,容器中也都留有空位。对于ScriptArray,做clone、迭代等操作时只要遍历前三个位置即可,也不需要判断前三个位置元素是否有效,因为它们肯定是有效的。而ScriptMap由于是散列表,因此clone、迭代时必须把整个容器都遍历一遍,还有判断当前元素是否有效,过滤掉空的槽位。
页:
[1]