Strangely, I see no difference at all, both trim variants complete at around ~100ms, 26ms is file read
If it is the fastest for you, then guess it could be either CLR version differences (compiler optimizations) or the hardware i.e. modern cpu instructions etc.
trim vs getfirstword
trim
getfirstword
Yes. different logic can be used to find those words. I just have to find time for this.
public static string GetFirstWord(string line)
{
int i = 0;
while (i < line.Length && char.IsWhiteSpace(line, i)) { i++; }
int k = i;
while (k < line.Length && !char.IsWhiteSpace(line, k)) { k++; }
return line.Substring(i, k-i);
}
public static string FindFirstWord(string line)
{
line = line.TrimStart();
int k = 0;
while (k < line.Length && !char.IsWhiteSpace(line, k)) { k++; }
return line.Substring(0, k);
}
using:
1. var word = line.TrimStart().Split(null, 2)[0].ToLower();
~ 34-35
2. var word = FindFirstWord(line).ToLower();
~ 22-24
3. var word = GetFirstWord(line).ToLower();
~ 18-23
technically the #3 could be about 2 times faster than #1. but #1 looks more universal and easier to modify if needed.
My machine is not bad… it has very fast hard drive, and it makes the difference, probably.
My guess is that the difference might be more significant if we use longer lines, because the Split method is the weak link and slows things down the most.
even if the compiler would be smart enough to see that only the first array item is used all the time I doubt that it could optimize the Split method code so it doesn’t proceed after the first array item is collected. Strings and array allocations ruin all the performance.
Anyway, if I subtract 25ms for file read from slow hdd out of average 45ms, processing takes ~20+ ms which is very close to what you have. So any further optimization is kinda meaningless
with
public string[] Split (char[]? separator, int count);
you can specify the maximum number of substrings (what I do). It means the algorithm stops after (count-1) split. But the problem is in additional memory allocation for this method. The system has to allocate enough space to place both (all) parts after split.
Guys, side question.
How to prevent the struct members to be printed in the maxscript listener?
(
global miauuStr
struct miauuTestStr
(
defaultLayer = layerManager.getLayer 0,
numMarks = 0,
numMarksArr = #(0,1,2,3,4,5,6,7,8,9),
visState = false,
ok
)
miauuStr = miauuTestStr()
)
oh sure, I forgot about that you explicitly limit the count. Then it is kinda strange that allocation of one extra array takes so much time. Cause I don’t believe that there could be anything else like GC collections happening that would affect the perf
Performance considerations
The Split methods allocate memory for the returned array object and a String object for each array element. If your application requires optimal performance or if managing memory allocation is critical in your application, consider using the IndexOf or IndexOfAny method, and optionally the Compare method, to locate a substring within a string.
If you are splitting a string at a separator character, use the IndexOf or IndexOfAny method to locate a separator character in the string. If you are splitting a string at a separator string, use the IndexOf or IndexOfAny method to locate the first character of the separator string. Then use the Compare method to determine whether the characters after that first character are equal to the remaining characters of the separator string.
In addition, if the same set of characters is used to split strings in multiple Split method calls, consider creating a single array and referencing it in each method call. This significantly reduces the additional overhead of each method call.
can the VS Code be configured in such a way that in case of an error in maxscript, the system will find a line with an error and highlight it in the VS Code editor?
I could only make an app that sends scripts from vscode to selected max instance and not in reverse. Maybe there’s a way to redirect listener output to vscode somehow, but I never digged in that direction.
Moreover I found myself switching back to default max editor most of the time, for any small scripts and prototypes.
AD have added some pre/post listener callbacks to the Listener interface.
But I have no idea, how to check if the output had thrown an error. Parsing listener window could easily freeze max for a long time when lots of data being printed…
tested in 2020
(
global MyClass =
(
local source = "
using Autodesk.Max;
using System;
namespace Jahman
{
public class Test
{
public static IGlobal ip = GlobalInterface.Instance;
public void debugPrint_pre( string str )
{
IListener l = ip.TheListener;
l.EditStream.Wputs(str + \" - pre -\\n\");
l.EditStream.Flush();
l.Dispose();
}
public void debugPrint_post( string str )
{
IListener l = ip.TheListener;
l.EditStream.Wputs(str + \" - post -\\n\");
l.EditStream.Flush();
l.Dispose();
}
public GlobalDelegates.Delegate41 get_delegate_pre()
{
return new GlobalDelegates.Delegate41(debugPrint_pre);
}
public GlobalDelegates.Delegate41 get_delegate_post()
{
return new GlobalDelegates.Delegate41(debugPrint_post);
}
}
}"
compilerParams = dotnetobject "System.CodeDom.Compiler.CompilerParameters"
compilerParams.ReferencedAssemblies.Add "System.dll"
compilerParams.ReferencedAssemblies.Add (getdir #maxroot + "autodesk.max.dll")
compilerParams.GenerateInMemory = on
csharpProvider = dotnetobject "Microsoft.CSharp.CSharpCodeProvider"
compilerResults = csharpProvider.CompileAssemblyFromSource compilerParams #( source )
if (compilerResults.Errors.Count > 0 ) then
(
local errs = stringstream ""
for i = 0 to (compilerResults.Errors.Count-1) do
(
local err = compilerResults.Errors.Item[i]
format "Error:% Line:% Column:% %\n" err.ErrorNumber err.Line err.Column err.ErrorText to:errs
)
format "%\n" errs
return undefined
)
DataPair Assembly:compilerResults.CompiledAssembly Instance:((dotNetClass "System.Activator").CreateInstance (compilerResults.CompiledAssembly.GetType "Jahman.Test"))
)
g.thelistener.MsgOutputCbPrecall = undefined
g.thelistener.MsgOutputCbPostcall = undefined
g.thelistener.MsgOutputCbPrecall = MyClass.instance.get_delegate_pre()
g.thelistener.MsgOutputCbPostcall = MyClass.instance.get_delegate_post()
format "test\n"
)
"test_mxs_error" + 42