From 00fbb73825f32ea7829b241ca24f6c3e4deef824 Mon Sep 17 00:00:00 2001 From: Ari Vuollet Date: Mon, 28 Apr 2025 21:05:34 +0300 Subject: [PATCH] _wip temporary array thingy --- Source/Engine/Scripting/ManagedCLR/MUtils.h | 172 ++++++++++++++++++ .../Bindings/BindingsGenerator.Cpp.cs | 31 +++- 2 files changed, 194 insertions(+), 9 deletions(-) diff --git a/Source/Engine/Scripting/ManagedCLR/MUtils.h b/Source/Engine/Scripting/ManagedCLR/MUtils.h index f3bc27172..73094230b 100644 --- a/Source/Engine/Scripting/ManagedCLR/MUtils.h +++ b/Source/Engine/Scripting/ManagedCLR/MUtils.h @@ -399,6 +399,72 @@ struct MConverter> namespace MUtils { + template + Array* GetTemporaryArray(); + + template + void ReleaseTemporaryArray(Array* array); + + template + class TemporaryArray + { + public: + Array* _array = nullptr; + + + TemporaryArray() + { + _array = GetTemporaryArray(); + } + + TemporaryArray(TemporaryArray&& other) + { + _array = other._array; + other._array = nullptr; + } + + ~TemporaryArray() + { + if (_array != nullptr) + { + ReleaseTemporaryArray(_array); + _array = nullptr; + } + } + + TemporaryArray& operator=(const TemporaryArray&& other) + { + if (this != &other) + *this = MoveTemp(other); + return *this; + } + + TemporaryArray& operator=(TemporaryArray&& other) + { + if (this != &other) + *this = MoveTemp(other); + return *this; + } + + FORCE_INLINE int32 Count() const + { + return _array->Count(); + } + + FORCE_INLINE void Resize(const int32 size, const bool preserveContents = true) + { + _array->Count(); + } + + operator Array& () { return *_array; }; + + //operator Array() const { return *_array; }; + + //operator const Array&() const { return *_array; }; + + //operator const Array&() const { return _array; }; + }; + // Outputs the full typename for the type of the specified object. extern FLAXENGINE_API const StringAnsi& GetClassFullname(MObject* obj); @@ -468,6 +534,17 @@ namespace MUtils return result; } + template + MArray* ToArray(MArray** result, const Span& data, const MClass* valueClass) + { + if (!valueClass) + return nullptr; + *result = MCore::Array::New(valueClass, data.Length()); + MConverter converter; + converter.ToManagedArray(*result, data); + return *result; + } + /// /// Allocates new managed array of data and copies contents from given native array. /// @@ -480,6 +557,18 @@ namespace MUtils return MUtils::ToArray(Span(data.Get(), data.Count()), valueClass); } + template + FORCE_INLINE MArray* ToArray(MArray** result, const TemporaryArray& data, const MClass* valueClass) + { + return MUtils::ToArray(result, Span(data._array->Get(), data._array->Count()), valueClass); + } + + template + FORCE_INLINE MArray* ToArray(MArray** result, const Array& data, const MClass* valueClass) + { + return MUtils::ToArray(result, Span(data.Get(), data.Count()), valueClass); + } + /// /// Converts the managed array into native array container object. /// @@ -497,6 +586,23 @@ namespace MUtils return result; } + /// + /// Converts the managed array into native array container object. + /// + /// The managed array object. + /// The output array. + template + Array ToArray(Array& result, MArray* arrayObj) + { + const int32 length = arrayObj ? MCore::Array::GetLength(arrayObj) : 0; + result.Clear(); + result.Resize(length); + MConverter converter; + Span resultSpan(result.Get(), length); + converter.ToNativeArray(resultSpan, arrayObj); + return result; + } + /// /// Converts the managed array into native Span. /// @@ -549,6 +655,11 @@ namespace MUtils return ToArray(data, MCore::TypeCache::Byte); } + FORCE_INLINE MArray* ToArray(MArray** result, const Span& data) + { + return ToArray(result, data, MCore::TypeCache::Byte); + } + /// /// Allocates new managed bytes array and copies data from the given unmanaged data container. /// @@ -559,6 +670,11 @@ namespace MUtils return ToArray(Span(data.Get(), data.Count()), MCore::TypeCache::Byte); } + FORCE_INLINE MArray* ToArray(MArray** result, Array& data) + { + return ToArray(result, Span(data.Get(), data.Count()), MCore::TypeCache::Byte); + } + /// /// Allocates new managed strings array and copies data from the given unmanaged data container. /// @@ -569,6 +685,11 @@ namespace MUtils return ToArray(data, MCore::TypeCache::String); } + FORCE_INLINE MArray* ToArray(MArray** result, const Span& data) + { + return ToArray(result, data, MCore::TypeCache::String); + } + /// /// Allocates new managed strings array and copies data from the given unmanaged data container. /// @@ -579,6 +700,57 @@ namespace MUtils return ToArray(Span(data.Get(), data.Count()), MCore::TypeCache::String); } + FORCE_INLINE MArray* ToArray(MArray** result, const Array& data) + { + return ToArray(result, Span(data.Get(), data.Count()), MCore::TypeCache::String); + } + + /// + /// Converts the managed array into native array container object. + /// + /// The managed array object. + /// The output array. + template + TemporaryArray ToArrayTemporary(MArray* arrayObj) + { + TemporaryArray result; + const int32 length = arrayObj ? MCore::Array::GetLength(arrayObj) : 0; + result._array->Resize(length, false); + MConverter converter; + Span resultSpan(result._array->Get(), length); + converter.ToNativeArray(resultSpan, arrayObj); + return result; + } + + template + Array* ManageTemporaryArray(Array* array) + { + static Array result; // TODO: Array of arrays + + if (array == nullptr) + { + // Rent array + return &result; + } + else + { + // Release + return nullptr; + } + } + + template + Array* GetTemporaryArray() + { + return ManageTemporaryArray(nullptr); + } + + template + void ReleaseTemporaryArray(Array* array) + { + ManageTemporaryArray(array); + } + #if USE_NETCORE /// /// Allocates new boolean array and copies data from the given unmanaged data container. The managed runtime is responsible for releasing the returned array data. diff --git a/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Cpp.cs b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Cpp.cs index 2f251932f..01e0db732 100644 --- a/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Cpp.cs +++ b/Source/Tools/Flax.Build/Bindings/BindingsGenerator.Cpp.cs @@ -558,9 +558,9 @@ namespace Flax.Build.Bindings var genericArgs = arrayApiType.MarshalAs.GetFullNameNative(buildData, caller); if (typeInfo.GenericArgs.Count != 1) genericArgs += ", " + typeInfo.GenericArgs[1]; - return "MUtils::ToArray(Array<" + genericArgs + ">({0}), " + GenerateCppGetMClass(buildData, arrayTypeInfo, caller, functionInfo) + ")"; + return "MUtils::ToArray({1}, Array<" + genericArgs + ">({0}), " + GenerateCppGetMClass(buildData, arrayTypeInfo, caller, functionInfo) + ")"; } - return "MUtils::ToArray({0}, " + GenerateCppGetMClass(buildData, arrayTypeInfo, caller, functionInfo) + ")"; + return "MUtils::ToArray({1}, {0}, " + GenerateCppGetMClass(buildData, arrayTypeInfo, caller, functionInfo) + ")"; // } // Span @@ -760,15 +760,23 @@ namespace Flax.Build.Bindings genericArgs += ", " + typeInfo.GenericArgs[1]; type = "MArray*"; - var result = "MUtils::ToArray<" + genericArgs + ">({0})"; + string result; + bool useTemporaryArrays = ((typeInfo.IsRef && typeInfo.IsConst)); + if (/*functionInfo != null ||*/ CppNonPodTypesConvertingGeneration) + result = "MUtils::ToArray<" + genericArgs + ">({0})"; + else if (true || useTemporaryArrays) + result = "MUtils::ToArrayTemporary<" + genericArgs + ">({0})"; + else + result = "MUtils::ToArray<" + genericArgs + ">({1}, {0})"; if (arrayApiType != null && arrayApiType.MarshalAs != null) { + string previousType = $"Array<{genericArgs}>"; // Convert array that uses different type for marshalling genericArgs = typeInfo.GenericArgs[0].GetFullNameNative(buildData, caller); if (typeInfo.GenericArgs.Count != 1) genericArgs += ", " + typeInfo.GenericArgs[1]; - result = $"Array<{genericArgs}>({result})"; + result = $"Array<{genericArgs}>(({previousType}){result})"; } return result; } @@ -1085,6 +1093,8 @@ namespace Flax.Build.Bindings } var useInlinedReturn = true; + if (returnValueType.StartsWith("MArray*") /*&& (functionInfo.ReturnType.IsArray || functionInfo.ReturnType.Type == "Array")*/) + useInlinedReturn = false; for (var i = 0; i < functionInfo.Parameters.Count; i++) { var parameterInfo = functionInfo.Parameters[i]; @@ -1206,7 +1216,7 @@ namespace Flax.Build.Bindings if (useInlinedReturn) callBegin += "return "; else - callBegin += "auto __result = "; + callBegin += returnValueType + " __result; __result = "; } #if USE_NETCORE @@ -1258,7 +1268,7 @@ namespace Flax.Build.Bindings else { // Convert value - param += string.Format(CppParamsWrappersCache[i], name); + param += string.Format(CppParamsWrappersCache[i], name, parameterInfo.Name); } // Special case for output result parameters that needs additional converting from native to managed format (such as non-POD structures or output array parameter) @@ -1322,7 +1332,7 @@ namespace Flax.Build.Bindings } if (!string.IsNullOrEmpty(returnValueConvert)) { - contents.AppendFormat(returnValueConvert, call); + contents.AppendFormat(returnValueConvert, call, "&__result"); } else { @@ -1342,7 +1352,8 @@ namespace Flax.Build.Bindings // Special case for output result parameters that needs additional converting from native to managed format (such as non-POD structures or output array parameter) if (CppParamsThatNeedConversion[i]) { - var value = string.Format(CppParamsThatNeedConversionWrappers[i], parameterInfo.Name + "Temp"); + var parmName = parameterInfo.IsRef || parameterInfo.Type.IsRef ? parameterInfo.Name : "&" + parameterInfo.Name; + var value = string.Format(CppParamsThatNeedConversionWrappers[i], parameterInfo.Name + "Temp", parmName); // MObject* parameters returned by reference need write barrier for GC if (parameterInfo.IsOut) @@ -3048,9 +3059,11 @@ namespace Flax.Build.Bindings var wrapper = CppParamsWrappersCache[i]; header.AppendFormat(" result.{0} = ", fieldInfo.Name); if (string.IsNullOrEmpty(wrapper)) + { header.Append("value." + fieldInfo.Name); + } else - header.AppendFormat(wrapper, "value." + fieldInfo.Name); + header.AppendFormat(wrapper, "value." + fieldInfo.Name, "&result." + fieldInfo.Name); header.Append(';').AppendLine(); } header.Append(" return result;").AppendLine();