Files
AncientCivil/Plugins/Puerts/Source/JsEnv/Private/ContainerWrapper.h
T
2025-02-10 00:44:11 +08:00

418 lines
14 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
* Tencent is pleased to support the open source community by making Puerts available.
* Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
* Puerts is licensed under the BSD 3-Clause License, except for the third-party components listed in the file 'LICENSE' which may
* be subject to their corresponding license terms. This file is subject to the terms and conditions defined in file 'LICENSE',
* which is part of this source code package.
*/
#pragma once
#include <memory>
#include <vector>
#include "CoreMinimal.h"
#include "CoreUObject.h"
#include "V8Utils.h"
#include "ObjectMapper.h"
#include "JSLogger.h"
#include "NamespaceDef.h"
PRAGMA_DISABLE_UNDEFINED_IDENTIFIER_WARNINGS
#pragma warning(push, 0)
#include "libplatform/libplatform.h"
#include "v8.h"
#pragma warning(pop)
PRAGMA_ENABLE_UNDEFINED_IDENTIFIER_WARNINGS
namespace PUERTS_NAMESPACE
{
class FPropertyTranslator;
FORCEINLINE int32 GetSizeWithAlignment(PropertyMacro* InProperty)
{
return Align(InProperty->GetSize(), InProperty->GetMinAlignment());
}
struct FScriptArrayEx
{
FScriptArray Data;
#if ENGINE_MINOR_VERSION < 25 && ENGINE_MAJOR_VERSION < 5
TWeakObjectPtr<PropertyMacro> PropertyPtr;
#else
TWeakFieldPtr<PropertyMacro> PropertyPtr;
#endif
FORCEINLINE FScriptArrayEx(PropertyMacro* InProperty)
{
// UE_LOG(LogTemp, Warning, TEXT("FScriptArrayEx:%p"), this);
PropertyPtr = InProperty;
}
FORCEINLINE ~FScriptArrayEx()
{
// UE_LOG(LogTemp, Warning, TEXT("~FScriptArrayEx:%p"), this);
if (PropertyPtr.IsValid())
{
Empty(&Data, PropertyPtr.Get());
}
else
{
UE_LOG(Puerts, Error, TEXT("~FScriptArrayEx: Property is invalid"));
}
}
FORCEINLINE static uint8* GetData(FScriptArray* ScriptArray, int32 ElementSize, int32 Index)
{
return static_cast<uint8*>(ScriptArray->GetData()) + Index * ElementSize;
}
FORCEINLINE static void Destruct(FScriptArray* ScriptArray, PropertyMacro* Property, int32 Index, int32 Count = 1)
{
const int32 ElementSize = GetSizeWithAlignment(Property);
uint8* Dest = GetData(ScriptArray, ElementSize, Index);
for (int32 i = 0; i < Count; ++i)
{
Property->DestroyValue(Dest);
Dest += ElementSize;
}
}
FORCEINLINE static void Empty(FScriptArray* ScriptArray, PropertyMacro* Property)
{
Destruct(ScriptArray, Property, 0, ScriptArray->Num());
#if ENGINE_MAJOR_VERSION > 4
ScriptArray->Empty(0, GetSizeWithAlignment(Property), __STDCPP_DEFAULT_NEW_ALIGNMENT__);
#else
ScriptArray->Empty(0, GetSizeWithAlignment(Property));
#endif
}
};
struct FScriptSetEx
{
FScriptSet Data;
#if ENGINE_MINOR_VERSION < 25 && ENGINE_MAJOR_VERSION < 5
TWeakObjectPtr<PropertyMacro> PropertyPtr;
#else
TWeakFieldPtr<PropertyMacro> PropertyPtr;
#endif
FORCEINLINE FScriptSetEx(PropertyMacro* InProperty)
{
// UE_LOG(LogTemp, Warning, TEXT("FScriptSetEx:%p"), this);
PropertyPtr = InProperty;
}
FORCEINLINE ~FScriptSetEx()
{
// UE_LOG(LogTemp, Warning, TEXT("~FScriptSetEx:%p"), this);
if (PropertyPtr.IsValid())
{
Empty(&Data, PropertyPtr.Get());
}
else
{
UE_LOG(Puerts, Error, TEXT("~FScriptSetEx: Property is invalid"));
}
}
FORCEINLINE static void Destruct(FScriptSet* ScriptSet, PropertyMacro* Property, int32 Index, int32 Count = 1)
{
auto SetLayout = ScriptSet->GetScriptLayout(Property->GetSize(), Property->GetMinAlignment());
for (int32 i = Index; i < Index + Count; ++i)
{
if (ScriptSet->IsValidIndex(i))
{
void* Data = ScriptSet->GetData(i, SetLayout);
Property->DestroyValue(Data);
}
}
}
FORCEINLINE static void Empty(FScriptSet* ScriptSet, PropertyMacro* Property)
{
auto SetLayout = FScriptSet::GetScriptLayout(Property->GetSize(), Property->GetMinAlignment());
Destruct(ScriptSet, Property, 0, ScriptSet->Num());
ScriptSet->Empty(0, SetLayout);
}
};
FORCEINLINE static int32 GetKeyOffset(const FScriptMapLayout& ScriptMapLayout)
{
#if ENGINE_MINOR_VERSION < 22 && ENGINE_MAJOR_VERSION < 5
return ScriptMapLayout.KeyOffset;
#else
return 0;
#endif
}
struct FScriptMapEx
{
FScriptMap Data;
#if ENGINE_MINOR_VERSION < 25 && ENGINE_MAJOR_VERSION < 5
TWeakObjectPtr<PropertyMacro> KeyPropertyPtr;
TWeakObjectPtr<PropertyMacro> ValuePropertyPtr;
#else
TWeakFieldPtr<PropertyMacro> KeyPropertyPtr;
TWeakFieldPtr<PropertyMacro> ValuePropertyPtr;
#endif
FORCEINLINE FScriptMapEx(PropertyMacro* InKeyProperty, PropertyMacro* InValueProperty)
{
// UE_LOG(LogTemp, Warning, TEXT("FScriptMapEx:%p"), this);
KeyPropertyPtr = InKeyProperty;
ValuePropertyPtr = InValueProperty;
}
FORCEINLINE ~FScriptMapEx()
{
// UE_LOG(LogTemp, Warning, TEXT("~FScriptMapEx:%p"), this);
if (KeyPropertyPtr.IsValid() && ValuePropertyPtr.IsValid())
{
Empty(&Data, KeyPropertyPtr.Get(), ValuePropertyPtr.Get());
}
else
{
UE_LOG(Puerts, Error, TEXT("~FScriptMapEx: Property is invalid"));
}
}
FORCEINLINE static FScriptMapLayout GetScriptLayout(const PropertyMacro* KeyProperty, const PropertyMacro* ValueProperty)
{
return FScriptMap::GetScriptLayout(
KeyProperty->GetSize(), KeyProperty->GetMinAlignment(), ValueProperty->GetSize(), ValueProperty->GetMinAlignment());
}
FORCEINLINE static void Destruct(
FScriptMap* ScriptMap, PropertyMacro* KeyProperty, PropertyMacro* ValueProperty, int32 Index, int32 Count = 1)
{
int32 MaxIndex = ScriptMap->GetMaxIndex();
auto MapLayout = GetScriptLayout(KeyProperty, ValueProperty);
for (int32 i = Index; i < Index + Count; ++i)
{
if (ScriptMap->IsValidIndex(i))
{
uint8* Data = reinterpret_cast<uint8*>(ScriptMap->GetData(i, MapLayout));
void* Key = Data + GetKeyOffset(MapLayout);
void* Value = Data + MapLayout.ValueOffset;
KeyProperty->DestroyValue(Key);
ValueProperty->DestroyValue(Value);
}
}
}
FORCEINLINE static void Empty(FScriptMap* ScriptMap, PropertyMacro* KeyProperty, PropertyMacro* ValueProperty)
{
auto MapLayout = GetScriptLayout(KeyProperty, ValueProperty);
Destruct(ScriptMap, KeyProperty, ValueProperty, 0, ScriptMap->Num());
ScriptMap->Empty(0, MapLayout);
}
};
template <typename T>
struct ContainerExTypeMapper;
template <>
struct ContainerExTypeMapper<FScriptArray>
{
using Type = FScriptArrayEx;
};
template <>
struct ContainerExTypeMapper<FScriptSet>
{
using Type = FScriptSetEx;
};
template <>
struct ContainerExTypeMapper<FScriptMap>
{
using Type = FScriptMapEx;
};
template <typename T>
class FContainerWrapper
{
public:
static void OnGarbageCollectedWithFree(const v8::WeakCallbackInfo<void>& Data)
{
typedef typename ContainerExTypeMapper<T>::Type ET;
ET* Container =
static_cast<ET*>(DataTransfer::MakeAddressWithHighPartOfTwo(Data.GetInternalField(0), Data.GetInternalField(1)));
FV8Utils::IsolateData<IObjectMapper>(Data.GetIsolate())->UnBindContainer(Container);
delete Container;
}
static void OnGarbageCollected(const v8::WeakCallbackInfo<void>& Data)
{
T* Container =
static_cast<T*>(DataTransfer::MakeAddressWithHighPartOfTwo(Data.GetInternalField(0), Data.GetInternalField(1)));
FV8Utils::IsolateData<IObjectMapper>(Data.GetIsolate())->UnBindContainer(Container);
}
static void New(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
FV8Utils::ThrowException(Isolate, "Container Constructor no support yet");
}
// TODO - 用doxygen注释
// 参数:无
// 返回:容器内元素总数
static void Num(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
v8::Isolate* Isolate = Info.GetIsolate();
v8::HandleScope HandleScope(Isolate);
v8::Local<v8::Context> Context = Isolate->GetCurrentContext();
auto Self = FV8Utils::GetPointerFast<T>(Info.Holder());
Info.GetReturnValue().Set(Self->Num());
}
};
class FScriptArrayWrapper : public FContainerWrapper<FScriptArray>
{
public:
static v8::Local<v8::FunctionTemplate> ToFunctionTemplate(v8::Isolate* Isolate);
private:
// 参数:一到多个容器元素
// 返回:无
// 作用:追加新元素到容器
static void Add(const v8::FunctionCallbackInfo<v8::Value>& Info);
// 参数:索引
// 返回:元素(值类型,有内存拷贝)
// 作用:获取索引对应的元素,如果索引越界则抛出异常
static void Get(const v8::FunctionCallbackInfo<v8::Value>& Info);
// 参数:索引
// 返回:元素(引用类型)
// 作用:获取索引对应的元素,如果索引越界则抛出异常
static void GetRef(const v8::FunctionCallbackInfo<v8::Value>& Info);
// 参数1:索引;参数2:元素
// 返回:无
// 作用:设置容器中索引对应的元素值,如果索引越界则抛出异常
static void Set(const v8::FunctionCallbackInfo<v8::Value>& Info);
// 参数:元素
// 返回:bool
// 作用:查询容器是否包含该元素,若是则返回true,否则返回false
static void Contains(const v8::FunctionCallbackInfo<v8::Value>& Info);
// 参数:元素
// 返回:索引
// 作用:返回容器中第一次出现该元素的索引,若元素不存在则返回INDEX_NONE(-1)
static void FindIndex(const v8::FunctionCallbackInfo<v8::Value>& Info);
// 参数:索引
// 返回:无
// 作用:移除索引对应的元素,被移除的位置之后的元素会自动前移,如果索引越界则抛出异常
static void RemoveAt(const v8::FunctionCallbackInfo<v8::Value>& Info);
// 参数:索引
// 返回:bool
// 作用:如果参数是有效索引,返回true,否则返回false
static void IsValidIndex(const v8::FunctionCallbackInfo<v8::Value>& Info);
// 参数:无
// 返回:无
// 作用:清空容器
static void Empty(const v8::FunctionCallbackInfo<v8::Value>& Info);
FORCEINLINE static int32 AddUninitialized(FScriptArray* ScriptArray, int32 ElementSize, int32 Count = 1);
FORCEINLINE static uint8* GetData(FScriptArray* ScriptArray, int32 ElementSize, int32 Index);
FORCEINLINE static void Construct(FScriptArray* ScriptArray, FPropertyTranslator* Inner, int32 Index, int32 Count = 1);
static int32 FindIndexInner(const v8::FunctionCallbackInfo<v8::Value>& Info);
FORCEINLINE static void InternalGet(const v8::FunctionCallbackInfo<v8::Value>& Info, bool PassByPointer);
};
class FScriptSetWrapper : public FContainerWrapper<FScriptSet>
{
public:
static v8::Local<v8::FunctionTemplate> ToFunctionTemplate(v8::Isolate* Isolate);
private:
static void Add(const v8::FunctionCallbackInfo<v8::Value>& Info);
static void Get(const v8::FunctionCallbackInfo<v8::Value>& Info);
static void GetRef(const v8::FunctionCallbackInfo<v8::Value>& Info);
static void Contains(const v8::FunctionCallbackInfo<v8::Value>& Info);
static void FindIndex(const v8::FunctionCallbackInfo<v8::Value>& Info);
static void RemoveAt(const v8::FunctionCallbackInfo<v8::Value>& Info);
static void GetMaxIndex(const v8::FunctionCallbackInfo<v8::Value>& Info);
static void IsValidIndex(const v8::FunctionCallbackInfo<v8::Value>& Info);
static void Empty(const v8::FunctionCallbackInfo<v8::Value>& Info);
FORCEINLINE static int32 FindIndexInner(const v8::FunctionCallbackInfo<v8::Value>& Info);
FORCEINLINE static void InternalGet(const v8::FunctionCallbackInfo<v8::Value>& Info, bool PassByPointer);
};
class FScriptMapWrapper : public FContainerWrapper<FScriptMap>
{
public:
static v8::Local<v8::FunctionTemplate> ToFunctionTemplate(v8::Isolate* Isolate);
private:
static void Add(const v8::FunctionCallbackInfo<v8::Value>& Info);
static void Get(const v8::FunctionCallbackInfo<v8::Value>& Info);
static void GetRef(const v8::FunctionCallbackInfo<v8::Value>& Info);
static void Set(const v8::FunctionCallbackInfo<v8::Value>& Info);
static void Remove(const v8::FunctionCallbackInfo<v8::Value>& Info);
static void GetMaxIndex(const v8::FunctionCallbackInfo<v8::Value>& Info);
static void IsValidIndex(const v8::FunctionCallbackInfo<v8::Value>& Info);
static void GetKey(const v8::FunctionCallbackInfo<v8::Value>& Info);
static void Empty(const v8::FunctionCallbackInfo<v8::Value>& Info);
FORCEINLINE static FScriptMapLayout GetScriptLayout(const PropertyMacro* KeyProperty, const PropertyMacro* ValueProperty);
FORCEINLINE static void InternalGet(const v8::FunctionCallbackInfo<v8::Value>& Info, bool PassByPointer);
};
class FFixSizeArrayWrapper
{
public:
static v8::Local<v8::FunctionTemplate> ToFunctionTemplate(v8::Isolate* Isolate);
private:
static void New(const v8::FunctionCallbackInfo<v8::Value>& Info)
{
}
static void Num(const v8::FunctionCallbackInfo<v8::Value>& Info);
static void Get(const v8::FunctionCallbackInfo<v8::Value>& Info);
static void GetRef(const v8::FunctionCallbackInfo<v8::Value>& Info);
static void Set(const v8::FunctionCallbackInfo<v8::Value>& Info);
FORCEINLINE static void InternalGet(const v8::FunctionCallbackInfo<v8::Value>& Info, bool PassByPointer);
};
} // namespace PUERTS_NAMESPACE