Yes. different logic can be used to find those words. I just have to find time for this.
Fast search through text file
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?
Few minutes ago I wrote a script which, after I select the line number in Maxscript listener(where the error occur) will go to the line in the currently opened script.
local g = (dotNetClass "Autodesk.Max.GlobalInterface").Instance
local mxse = g.TheMxsEditorInterface
local editorHandle = mxse.EditorGetMainHWND
local currentlyOpenTab = mxse.EditorGetEditHWND
local SCI_GOTOLINE = 2024
local SCI_GETLINEENDPOSITION = 2136
local SCI_SETSEL = 2160
local SCI_POSITIONFROMLINE = 2167
local windowsSendMessage = windows.SendMessage
if (selText = (getListenerSelText())) != "" do
(
_lineIdx = selText as integer
windowsSendMessage currentlyOpenTab SCI_GOTOLINE _lineIdx 0
nStart = SendCommandToScintilla SCI_POSITIONFROMLINE (_lineIdx - 1) 0
nEnd = SendCommandToScintilla SCI_GETLINEENDPOSITION (_lineIdx - 1) 0
windowsSendMessage currentlyOpenTab SCI_SETSEL nStart nEnd
)
Still canāt run it while the Maxscript listener is in focus, but clicking in the viewport and executing the script does the job.
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
I am doing something wrong, but I canāt figure out what.
Here is part of the code:
string re_with = (\"with\\\\\");
var spaces = new char[]{' ',' '};
using (System.IO.StringReader sr = new System.IO.StringReader(doc))
{
string line;
int line_index = 0;
string word;
while ((line = sr.ReadLine()) != null)
{
line_index++;
word = line.TrimStart(spaces);
int len = word.IndexOfAny( spaces );
word = word.Substring( 0, len < 0 ? word.Length : len ).ToLower();
if ( re_with == word )
{
_defWithArr.Add(line);
_defWithLineNumArr.Add(line_index);
}
The if statement is always false. When I collect all word
there is āwithā inside the collection, but all If statements are always false.
Update
Fixed. It has to be string re_with = (\"with\");