Optimize default C# stdlib references to prevent using jit-ed features in a game assembly
This commit is contained in:
@@ -655,7 +655,7 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
||||
if (uiControl.Name.StartsWith(previousName))
|
||||
{
|
||||
string newName = controlType.Name + uiControl.Name.Substring(previousName.Length);
|
||||
uiControl.Name = StringUtils.IncrementNameNumber(newName, x => uiControl.Parent.GetChild(x) == null);
|
||||
uiControl.Name = Utilities.Utils.IncrementNameNumber(newName, x => uiControl.Parent.GetChild(x) == null);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -37,6 +37,9 @@ public class Editor : EditorModule
|
||||
{
|
||||
base.Setup(options);
|
||||
|
||||
options.ScriptingAPI.SystemReferences.Add("System.Private.Xml");
|
||||
options.ScriptingAPI.SystemReferences.Add("System.Text.RegularExpressions");
|
||||
|
||||
options.PublicDependencies.Add("Engine");
|
||||
options.PrivateDependencies.Add("pugixml");
|
||||
options.PrivateDependencies.Add("UniversalAnalytics");
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using FlaxEditor.Content;
|
||||
using FlaxEditor.GUI.Docking;
|
||||
|
||||
@@ -472,7 +472,7 @@ namespace FlaxEditor.Surface
|
||||
{
|
||||
Window = window,
|
||||
IsAdd = true,
|
||||
Name = StringUtils.IncrementNameNumber("New parameter", x => OnParameterRenameValidate(null, x)),
|
||||
Name = Utilities.Utils.IncrementNameNumber("New parameter", x => OnParameterRenameValidate(null, x)),
|
||||
Type = type,
|
||||
Index = window.VisjectSurface.Parameters.Count,
|
||||
};
|
||||
|
||||
@@ -153,7 +153,7 @@ namespace FlaxEditor.Actions
|
||||
if (child != actor && child.Name == actor.Name)
|
||||
{
|
||||
var children = parent.Children;
|
||||
actor.Name = StringUtils.IncrementNameNumber(name, x => children.All(y => y.Name != x));
|
||||
actor.Name = Utilities.Utils.IncrementNameNumber(name, x => children.All(y => y.Name != x));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using FlaxEditor.GUI.ContextMenu;
|
||||
using FlaxEditor.GUI.Input;
|
||||
using FlaxEditor.GUI.Tree;
|
||||
@@ -38,6 +39,8 @@ namespace FlaxEditor.Utilities
|
||||
public static class Utils
|
||||
{
|
||||
private static readonly StringBuilder CachedSb = new StringBuilder(256);
|
||||
private static readonly Regex IncNameRegex1 = new Regex("(\\d+)$");
|
||||
private static readonly Regex IncNameRegex2 = new Regex("\\((\\d+)\\)$");
|
||||
|
||||
private static readonly string[] MemorySizePostfixes =
|
||||
{
|
||||
@@ -54,6 +57,92 @@ namespace FlaxEditor.Utilities
|
||||
/// </summary>
|
||||
public static readonly string FlaxEngineAssemblyName = "FlaxEngine.CSharp";
|
||||
|
||||
/// <summary>
|
||||
/// Tries to parse number in the name brackets at the end of the value and then increment it to create a new name.
|
||||
/// Supports numbers at the end without brackets.
|
||||
/// </summary>
|
||||
/// <param name="name">The input name.</param>
|
||||
/// <param name="isValid">Custom function to validate the created name.</param>
|
||||
/// <returns>The new name.</returns>
|
||||
public static string IncrementNameNumber(string name, Func<string, bool> isValid)
|
||||
{
|
||||
// Validate input name
|
||||
if (isValid == null || isValid(name))
|
||||
return name;
|
||||
|
||||
// Temporary data
|
||||
int index;
|
||||
int MaxChecks = 10000;
|
||||
string result;
|
||||
|
||||
// Find '<name><num>' case
|
||||
var match = IncNameRegex1.Match(name);
|
||||
if (match.Success && match.Groups.Count == 2)
|
||||
{
|
||||
// Get result
|
||||
string num = match.Groups[0].Value;
|
||||
|
||||
// Parse value
|
||||
if (int.TryParse(num, out index))
|
||||
{
|
||||
// Get prefix
|
||||
string prefix = name.Substring(0, name.Length - num.Length);
|
||||
|
||||
// Generate name
|
||||
do
|
||||
{
|
||||
result = string.Format("{0}{1}", prefix, ++index);
|
||||
|
||||
if (MaxChecks-- < 0)
|
||||
return name + Guid.NewGuid();
|
||||
} while (!isValid(result));
|
||||
|
||||
if (result.Length > 0)
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
// Find '<name> (<num>)' case
|
||||
match = IncNameRegex2.Match(name);
|
||||
if (match.Success && match.Groups.Count == 2)
|
||||
{
|
||||
// Get result
|
||||
string num = match.Groups[0].Value;
|
||||
num = num.Substring(1, num.Length - 2);
|
||||
|
||||
// Parse value
|
||||
if (int.TryParse(num, out index))
|
||||
{
|
||||
// Get prefix
|
||||
string prefix = name.Substring(0, name.Length - num.Length - 2);
|
||||
|
||||
// Generate name
|
||||
do
|
||||
{
|
||||
result = string.Format("{0}({1})", prefix, ++index);
|
||||
|
||||
if (MaxChecks-- < 0)
|
||||
return name + Guid.NewGuid();
|
||||
} while (!isValid(result));
|
||||
|
||||
if (result.Length > 0)
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
// Generate name
|
||||
index = 0;
|
||||
do
|
||||
{
|
||||
result = string.Format("{0} {1}", name, index++);
|
||||
|
||||
if (MaxChecks-- < 0)
|
||||
return name + Guid.NewGuid();
|
||||
} while (!isValid(result));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Formats the amount of bytes to get a human-readable data size in bytes with abbreviation. Eg. 32 kB
|
||||
/// </summary>
|
||||
|
||||
@@ -422,7 +422,7 @@ namespace FlaxEditor.Viewport
|
||||
var actor = new Camera
|
||||
{
|
||||
StaticFlags = StaticFlags.None,
|
||||
Name = StringUtils.IncrementNameNumber("Camera", x => parent.GetChild(x) == null),
|
||||
Name = Utilities.Utils.IncrementNameNumber("Camera", x => parent.GetChild(x) == null),
|
||||
Transform = ViewTransform,
|
||||
NearPlane = NearPlane,
|
||||
FarPlane = FarPlane,
|
||||
@@ -998,7 +998,7 @@ namespace FlaxEditor.Viewport
|
||||
{
|
||||
actor.Position = PostProcessSpawnedActorLocation(actor, ref hitLocation);
|
||||
var parent = actor.Parent ?? Level.GetScene(0);
|
||||
actor.Name = StringUtils.IncrementNameNumber(actor.Name, x => parent.GetChild(x) == null);
|
||||
actor.Name = Utilities.Utils.IncrementNameNumber(actor.Name, x => parent.GetChild(x) == null);
|
||||
Editor.Instance.SceneEditing.Spawn(actor);
|
||||
Focus();
|
||||
}
|
||||
|
||||
@@ -332,7 +332,7 @@ namespace FlaxEditor.Windows.Assets
|
||||
{
|
||||
Proxy = _proxy,
|
||||
IsAdd = true,
|
||||
Name = StringUtils.IncrementNameNumber("New parameter", x => OnParameterRenameValidate(null, x)),
|
||||
Name = Utilities.Utils.IncrementNameNumber("New parameter", x => OnParameterRenameValidate(null, x)),
|
||||
DefaultValue = TypeUtils.GetDefaultValue(new ScriptType(type)),
|
||||
};
|
||||
_proxy.Window.Undo.AddAction(action);
|
||||
|
||||
@@ -368,7 +368,7 @@ namespace FlaxEditor.Windows.Assets
|
||||
actor.Layer = parentActor.Layer;
|
||||
|
||||
// Rename actor to identify it easily
|
||||
actor.Name = StringUtils.IncrementNameNumber(actor.GetType().Name, x => parentActor.GetChild(x) == null);
|
||||
actor.Name = Utilities.Utils.IncrementNameNumber(actor.GetType().Name, x => parentActor.GetChild(x) == null);
|
||||
}
|
||||
|
||||
// Spawn it
|
||||
|
||||
@@ -269,7 +269,7 @@ namespace FlaxEditor.Windows.Assets
|
||||
{
|
||||
var sprite = new Sprite
|
||||
{
|
||||
Name = StringUtils.IncrementNameNumber("New Sprite", name => Asset.Sprites.All(s => s.Name != name)),
|
||||
Name = Utilities.Utils.IncrementNameNumber("New Sprite", name => Asset.Sprites.All(s => s.Name != name)),
|
||||
Area = new Rectangle(Float2.Zero, Float2.One),
|
||||
};
|
||||
Asset.AddSprite(sprite);
|
||||
|
||||
@@ -529,12 +529,12 @@ namespace FlaxEditor.Windows
|
||||
string destinationName;
|
||||
if (item.IsFolder)
|
||||
{
|
||||
destinationName = StringUtils.IncrementNameNumber(item.ShortName, x => !Directory.Exists(StringUtils.CombinePaths(sourceFolder, x)));
|
||||
destinationName = Utilities.Utils.IncrementNameNumber(item.ShortName, x => !Directory.Exists(StringUtils.CombinePaths(sourceFolder, x)));
|
||||
}
|
||||
else
|
||||
{
|
||||
string extension = Path.GetExtension(sourcePath);
|
||||
destinationName = StringUtils.IncrementNameNumber(item.ShortName, x => !File.Exists(StringUtils.CombinePaths(sourceFolder, x + extension))) + extension;
|
||||
destinationName = Utilities.Utils.IncrementNameNumber(item.ShortName, x => !File.Exists(StringUtils.CombinePaths(sourceFolder, x + extension))) + extension;
|
||||
}
|
||||
|
||||
return StringUtils.CombinePaths(sourceFolder, destinationName);
|
||||
|
||||
@@ -168,7 +168,7 @@ namespace FlaxEditor.Windows
|
||||
actor.Transform = parentActor.Transform;
|
||||
|
||||
// Rename actor to identify it easily
|
||||
actor.Name = StringUtils.IncrementNameNumber(type.Name, x => parentActor.GetChild(x) == null);
|
||||
actor.Name = Utilities.Utils.IncrementNameNumber(type.Name, x => parentActor.GetChild(x) == null);
|
||||
}
|
||||
|
||||
// Spawn it
|
||||
|
||||
@@ -18,59 +18,6 @@ namespace FlaxEngine.Interop
|
||||
/// </summary>
|
||||
internal static class Invoker
|
||||
{
|
||||
internal delegate IntPtr MarshalAndInvokeDelegate(object delegateContext, ManagedHandle instancePtr, IntPtr paramPtr);
|
||||
|
||||
internal delegate IntPtr InvokeThunkDelegate(object delegateContext, ManagedHandle instancePtr, IntPtr* paramPtrs);
|
||||
|
||||
/// <summary>
|
||||
/// Casts managed pointer to unmanaged pointer.
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
internal static T* ToPointer<T>(IntPtr ptr) where T : unmanaged
|
||||
{
|
||||
return (T*)ptr.ToPointer();
|
||||
}
|
||||
|
||||
internal static MethodInfo ToPointerMethod = typeof(Invoker).GetMethod(nameof(Invoker.ToPointer), BindingFlags.Static | BindingFlags.NonPublic);
|
||||
|
||||
/// <summary>
|
||||
/// Creates a delegate for invoker to pass parameters as references.
|
||||
/// </summary>
|
||||
internal static Delegate CreateDelegateFromMethod(MethodInfo method, bool passParametersByRef = true)
|
||||
{
|
||||
Type[] methodParameters;
|
||||
if (method.IsStatic)
|
||||
methodParameters = method.GetParameterTypes();
|
||||
else
|
||||
methodParameters = method.GetParameters().Select(x => x.ParameterType).Prepend(method.DeclaringType).ToArray();
|
||||
|
||||
// Pass delegate parameters by reference
|
||||
Type[] delegateParameters = methodParameters.Select(x => x.IsPointer ? typeof(IntPtr) : x).Select(x => passParametersByRef && !x.IsByRef ? x.MakeByRefType() : x).ToArray();
|
||||
if (!method.IsStatic && passParametersByRef)
|
||||
delegateParameters[0] = method.DeclaringType;
|
||||
|
||||
// Convert unmanaged pointer parameters to IntPtr
|
||||
ParameterExpression[] parameterExpressions = delegateParameters.Select(Expression.Parameter).ToArray();
|
||||
Expression[] callExpressions = new Expression[methodParameters.Length];
|
||||
for (int i = 0; i < methodParameters.Length; i++)
|
||||
{
|
||||
Type parameterType = methodParameters[i];
|
||||
if (parameterType.IsPointer)
|
||||
callExpressions[i] = Expression.Call(null, ToPointerMethod.MakeGenericMethod(parameterType.GetElementType()), parameterExpressions[i]);
|
||||
else
|
||||
callExpressions[i] = parameterExpressions[i];
|
||||
}
|
||||
|
||||
// Create and compile the delegate
|
||||
MethodCallExpression callDelegExp;
|
||||
if (method.IsStatic)
|
||||
callDelegExp = Expression.Call(null, method, callExpressions.ToArray());
|
||||
else
|
||||
callDelegExp = Expression.Call(parameterExpressions[0], method, callExpressions.Skip(1).ToArray());
|
||||
Type delegateType = DelegateHelpers.MakeNewCustomDelegate(delegateParameters.Append(method.ReturnType).ToArray());
|
||||
return Expression.Lambda(delegateType, callDelegExp, parameterExpressions).Compile();
|
||||
}
|
||||
|
||||
internal static IntPtr MarshalReturnValue<TRet>(ref TRet returnValue)
|
||||
{
|
||||
if (returnValue == null)
|
||||
@@ -186,6 +133,60 @@ namespace FlaxEngine.Interop
|
||||
return ManagedHandle.ToIntPtr(returnObject, GCHandleType.Weak);
|
||||
}
|
||||
|
||||
#if !USE_AOT
|
||||
internal delegate IntPtr MarshalAndInvokeDelegate(object delegateContext, ManagedHandle instancePtr, IntPtr paramPtr);
|
||||
|
||||
internal delegate IntPtr InvokeThunkDelegate(object delegateContext, ManagedHandle instancePtr, IntPtr* paramPtrs);
|
||||
|
||||
/// <summary>
|
||||
/// Casts managed pointer to unmanaged pointer.
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
internal static T* ToPointer<T>(IntPtr ptr) where T : unmanaged
|
||||
{
|
||||
return (T*)ptr.ToPointer();
|
||||
}
|
||||
|
||||
internal static MethodInfo ToPointerMethod = typeof(Invoker).GetMethod(nameof(Invoker.ToPointer), BindingFlags.Static | BindingFlags.NonPublic);
|
||||
|
||||
/// <summary>
|
||||
/// Creates a delegate for invoker to pass parameters as references.
|
||||
/// </summary>
|
||||
internal static Delegate CreateDelegateFromMethod(MethodInfo method, bool passParametersByRef = true)
|
||||
{
|
||||
Type[] methodParameters;
|
||||
if (method.IsStatic)
|
||||
methodParameters = method.GetParameterTypes();
|
||||
else
|
||||
methodParameters = method.GetParameters().Select(x => x.ParameterType).Prepend(method.DeclaringType).ToArray();
|
||||
|
||||
// Pass delegate parameters by reference
|
||||
Type[] delegateParameters = methodParameters.Select(x => x.IsPointer ? typeof(IntPtr) : x).Select(x => passParametersByRef && !x.IsByRef ? x.MakeByRefType() : x).ToArray();
|
||||
if (!method.IsStatic && passParametersByRef)
|
||||
delegateParameters[0] = method.DeclaringType;
|
||||
|
||||
// Convert unmanaged pointer parameters to IntPtr
|
||||
ParameterExpression[] parameterExpressions = delegateParameters.Select(Expression.Parameter).ToArray();
|
||||
Expression[] callExpressions = new Expression[methodParameters.Length];
|
||||
for (int i = 0; i < methodParameters.Length; i++)
|
||||
{
|
||||
Type parameterType = methodParameters[i];
|
||||
if (parameterType.IsPointer)
|
||||
callExpressions[i] = Expression.Call(null, ToPointerMethod.MakeGenericMethod(parameterType.GetElementType()), parameterExpressions[i]);
|
||||
else
|
||||
callExpressions[i] = parameterExpressions[i];
|
||||
}
|
||||
|
||||
// Create and compile the delegate
|
||||
MethodCallExpression callDelegExp;
|
||||
if (method.IsStatic)
|
||||
callDelegExp = Expression.Call(null, method, callExpressions.ToArray());
|
||||
else
|
||||
callDelegExp = Expression.Call(parameterExpressions[0], method, callExpressions.Skip(1).ToArray());
|
||||
Type delegateType = DelegateHelpers.MakeNewCustomDelegate(delegateParameters.Append(method.ReturnType).ToArray());
|
||||
return Expression.Lambda(delegateType, callDelegExp, parameterExpressions).Compile();
|
||||
}
|
||||
|
||||
internal static class InvokerNoRet0<TInstance>
|
||||
{
|
||||
internal delegate void InvokerDelegate(object instance);
|
||||
@@ -1285,6 +1286,7 @@ namespace FlaxEngine.Interop
|
||||
return MarshalReturnValueThunk(ref ret);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -651,6 +651,7 @@ namespace FlaxEngine.Interop
|
||||
internal static IntPtr InvokeMethod(ManagedHandle instanceHandle, ManagedHandle methodHandle, IntPtr paramPtr, IntPtr exceptionPtr)
|
||||
{
|
||||
MethodHolder methodHolder = Unsafe.As<MethodHolder>(methodHandle.Target);
|
||||
#if !USE_AOT
|
||||
if (methodHolder.TryGetDelegate(out var methodDelegate, out var methodDelegateContext))
|
||||
{
|
||||
// Fast path, invoke the method with minimal allocations
|
||||
@@ -668,6 +669,7 @@ namespace FlaxEngine.Interop
|
||||
return returnValue;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
// Slow path, method parameters needs to be stored in heap
|
||||
object returnObject;
|
||||
@@ -715,8 +717,12 @@ namespace FlaxEngine.Interop
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
internal static IntPtr GetMethodUnmanagedFunctionPointer(ManagedHandle methodHandle)
|
||||
internal static IntPtr GetThunk(ManagedHandle methodHandle)
|
||||
{
|
||||
#if USE_AOT
|
||||
Debug.LogError("GetThunk is not supported in C# AOT mode");
|
||||
return IntPtr.Zero;
|
||||
#else
|
||||
MethodHolder methodHolder = Unsafe.As<MethodHolder>(methodHandle.Target);
|
||||
|
||||
// Wrap the method call, this is needed to get the object instance from ManagedHandle and to pass the exception back to native side
|
||||
@@ -733,8 +739,8 @@ namespace FlaxEngine.Interop
|
||||
{
|
||||
cachedDelegates[functionPtr] = methodDelegate;
|
||||
}
|
||||
|
||||
return functionPtr;
|
||||
#endif
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
|
||||
@@ -6,7 +6,9 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
#if !USE_AOT
|
||||
using System.Linq.Expressions;
|
||||
#endif
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.Loader;
|
||||
@@ -789,8 +791,10 @@ namespace FlaxEngine.Interop
|
||||
internal Type[] parameterTypes;
|
||||
internal MethodInfo method;
|
||||
internal Type returnType;
|
||||
#if !USE_AOT
|
||||
private Invoker.MarshalAndInvokeDelegate invokeDelegate;
|
||||
private object delegInvoke;
|
||||
#endif
|
||||
|
||||
internal MethodHolder(MethodInfo method)
|
||||
{
|
||||
@@ -799,6 +803,7 @@ namespace FlaxEngine.Interop
|
||||
parameterTypes = method.GetParameterTypes();
|
||||
}
|
||||
|
||||
#if !USE_AOT
|
||||
internal bool TryGetDelegate(out Invoker.MarshalAndInvokeDelegate outDeleg, out object outDelegInvoke)
|
||||
{
|
||||
if (invokeDelegate == null)
|
||||
@@ -836,6 +841,7 @@ namespace FlaxEngine.Interop
|
||||
outDelegInvoke = delegInvoke;
|
||||
return outDeleg != null;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
internal static ManagedHandle GetMethodGCHandle(MethodInfo method)
|
||||
@@ -1001,6 +1007,11 @@ namespace FlaxEngine.Interop
|
||||
|
||||
private static class DelegateHelpers
|
||||
{
|
||||
#if USE_AOT
|
||||
internal static void InitMethods()
|
||||
{
|
||||
}
|
||||
#else
|
||||
private static Func<Type[], Type> MakeNewCustomDelegateFunc;
|
||||
#if FLAX_EDITOR
|
||||
private static Func<Type[], Type> MakeNewCustomDelegateFuncCollectible;
|
||||
@@ -1039,8 +1050,10 @@ namespace FlaxEngine.Interop
|
||||
#endif
|
||||
return MakeNewCustomDelegateFunc(parameters);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if !USE_AOT
|
||||
/// <summary>
|
||||
/// Wrapper class for invoking function pointers from unmanaged code.
|
||||
/// </summary>
|
||||
@@ -1178,6 +1191,7 @@ namespace FlaxEngine.Interop
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1273,8 +1273,8 @@ void* MMethod::GetThunk()
|
||||
{
|
||||
if (!_cachedThunk)
|
||||
{
|
||||
static void* GetMethodUnmanagedFunctionPointerPtr = GetStaticMethodPointer(TEXT("GetMethodUnmanagedFunctionPointer"));
|
||||
_cachedThunk = CallStaticMethod<void*, void*>(GetMethodUnmanagedFunctionPointerPtr, _handle);
|
||||
static void* GetThunkPtr = GetStaticMethodPointer(TEXT("GetThunk"));
|
||||
_cachedThunk = CallStaticMethod<void*, void*>(GetThunkPtr, _handle);
|
||||
}
|
||||
return _cachedThunk;
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace FlaxEngine
|
||||
{
|
||||
@@ -260,94 +259,5 @@ namespace FlaxEngine
|
||||
{
|
||||
return s.Replace("\n", "").Replace("\r", "");
|
||||
}
|
||||
|
||||
private static readonly Regex IncNameRegex1 = new Regex("(\\d+)$");
|
||||
private static readonly Regex IncNameRegex2 = new Regex("\\((\\d+)\\)$");
|
||||
|
||||
/// <summary>
|
||||
/// Tries to parse number in the name brackets at the end of the value and then increment it to create a new name.
|
||||
/// Supports numbers at the end without brackets.
|
||||
/// </summary>
|
||||
/// <param name="name">The input name.</param>
|
||||
/// <param name="isValid">Custom function to validate the created name.</param>
|
||||
/// <returns>The new name.</returns>
|
||||
public static string IncrementNameNumber(string name, Func<string, bool> isValid)
|
||||
{
|
||||
// Validate input name
|
||||
if (isValid == null || isValid(name))
|
||||
return name;
|
||||
|
||||
// Temporary data
|
||||
int index;
|
||||
int MaxChecks = 10000;
|
||||
string result;
|
||||
|
||||
// Find '<name><num>' case
|
||||
var match = IncNameRegex1.Match(name);
|
||||
if (match.Success && match.Groups.Count == 2)
|
||||
{
|
||||
// Get result
|
||||
string num = match.Groups[0].Value;
|
||||
|
||||
// Parse value
|
||||
if (int.TryParse(num, out index))
|
||||
{
|
||||
// Get prefix
|
||||
string prefix = name.Substring(0, name.Length - num.Length);
|
||||
|
||||
// Generate name
|
||||
do
|
||||
{
|
||||
result = string.Format("{0}{1}", prefix, ++index);
|
||||
|
||||
if (MaxChecks-- < 0)
|
||||
return name + Guid.NewGuid();
|
||||
} while (!isValid(result));
|
||||
|
||||
if (result.Length > 0)
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
// Find '<name> (<num>)' case
|
||||
match = IncNameRegex2.Match(name);
|
||||
if (match.Success && match.Groups.Count == 2)
|
||||
{
|
||||
// Get result
|
||||
string num = match.Groups[0].Value;
|
||||
num = num.Substring(1, num.Length - 2);
|
||||
|
||||
// Parse value
|
||||
if (int.TryParse(num, out index))
|
||||
{
|
||||
// Get prefix
|
||||
string prefix = name.Substring(0, name.Length - num.Length - 2);
|
||||
|
||||
// Generate name
|
||||
do
|
||||
{
|
||||
result = string.Format("{0}({1})", prefix, ++index);
|
||||
|
||||
if (MaxChecks-- < 0)
|
||||
return name + Guid.NewGuid();
|
||||
} while (!isValid(result));
|
||||
|
||||
if (result.Length > 0)
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
// Generate name
|
||||
index = 0;
|
||||
do
|
||||
{
|
||||
result = string.Format("{0} {1}", name, index++);
|
||||
|
||||
if (MaxChecks-- < 0)
|
||||
return name + Guid.NewGuid();
|
||||
} while (!isValid(result));
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -234,7 +234,7 @@ namespace Flax.Build.NativeCpp
|
||||
"System.ObjectModel",
|
||||
"System.Private.CoreLib",
|
||||
"System.Private.Uri",
|
||||
"System.Private.Xml",
|
||||
//"System.Private.Xml",
|
||||
|
||||
"System.Reflection",
|
||||
"System.Runtime",
|
||||
@@ -245,11 +245,11 @@ namespace Flax.Build.NativeCpp
|
||||
"System.Security.Cryptography",
|
||||
"System.Security.Cryptography.Algorithms",
|
||||
"System.Security.Cryptography.Primitives",
|
||||
"System.Text.RegularExpressions",
|
||||
//"System.Text.RegularExpressions",
|
||||
"System.Threading.Tasks.Parallel",
|
||||
"System.Xml",
|
||||
//"System.Xml",
|
||||
|
||||
"System.Reflection.Metadata",
|
||||
//"System.Reflection.Metadata",
|
||||
"netstandard",
|
||||
},
|
||||
SystemAnalyzers = new HashSet<string>
|
||||
|
||||
Reference in New Issue
Block a user