Profiling reversing an array
;==========================================================================================================================================
; Reverse Array.
;
; Profiling Performance Contest.
;
;   - udfArrayReverse_1
;   - udfArrayReverse_2
;   - udfArrayReverse_3
;
;------------------------------------------------------------------------------------------------------------------------------------------
; (c)Detlev Dalitz.20110121.20130211.
;==========================================================================================================================================


; How many different test cases?
intContestCaseMax = 3

; How many loops to run?
intContestLoopMax = 20

; What group of contestants to examine?
intContestantMin = 1
intContestantMax = 3

; Display preview of test case results?
blnDisplayPreview = @TRUE
;blnDisplayPreview = @FALSE

; Display contest status in windows title?
blnDisplayStatus = @TRUE
;blnDisplayStatus = @FALSE

GoSub DEFINE_CONTEST_FUNCTIONS


;==========================================================================================================================================
GoSub DEFINE_FUNCTIONS

; Run the contest once and display the results for verifying.
; Then press CANCEL to abort or OK to run complete contest.
If blnDisplayPreview
   For intContestCase = 1 To intContestCaseMax
      udsPrepareTestCase (intContestCase)
      udsPrepareCounters ()
      For intContestant = intContestantMin To intContestantMax
         udsRunContestant (intContestant)
      Next
      If @CANCEL == udfArrayDumpToItemList (arrContestResults, intContestantMin, intContestantMax, @LF) Then Goto CANCEL
   Next
EndIf

; Run complete contest.
WinShow ("")
strContestResult = ""

Switch blnDisplayStatus
Case @TRUE
   For intContestCase = 1 To intContestCaseMax
      udsPrepareTestCase (intContestCase)
      udsPrepareCounters ()
      For intContestLoop = 1 To intContestLoopMax
         For intContestant = intContestantMin To intContestantMax
            WinTitle ("", "Profiling|Case=" : intContestCaseMax : "." : intContestCase : "|Contestant=" : intContestantMax : "." : intContestant : "|Loop=" : intContestLoopMax : "." : intContestLoop)
            udsRunContestant (intContestant)
         Next
      Next
      strContestResult = strContestResult : @LF : udsResultPerTestCase ()
   Next
   Break
Case @FALSE
   For intContestCase = 1 To intContestCaseMax
      udsPrepareTestCase (intContestCase)
      udsPrepareCounters ()
      For intContestLoop = 1 To intContestLoopMax
         For intContestant = intContestantMin To intContestantMax
            udsRunContestant (intContestant)
         Next
      Next
      strContestResult = strContestResult : @LF : udsResultPerTestCase ()
   Next
   Break
EndSwitch

strContestResult = strContestResult : @LF : strPre : StrFill ("-", intLenSum)
strContestResult = StrSub (strContestResult, 2, -1)

Message (strMsgTitle, strContestResult)
ClipPut (StrReplace (strContestResult, @LF, @CRLF))

:CANCEL
Exit
;==========================================================================================================================================



;==========================================================================================================================================
:DEFINE_CONTEST_FUNCTIONS
;==========================================================================================================================================

;------------------------------------------------------------------------------------------------------------------------------------------
#DefineSubRoutine udsPrepareTestCase (intContestCase)
Switch intContestCase
Case 1
   arrTest%intContestCase% = Arrayize (StrFill ("1 11 111 18 77 6 56 221 1 12 111 13 123 1234 12345 1 99999 9773 755 2009 02 01 ", 20000), " ")
   intElems%intContestCase% = ArrInfo (arrTest%intContestCase%, 1) ; 5571 array elements.
   Break
Case 2
   arrTest%intContestCase% = Arrayize (StrFill ("ZZ YY XX --- CC BB AA --- ", 2000), " ")
   intElems%intContestCase% = ArrInfo (arrTest%intContestCase%, 1) ; 616 array elements.
   Break
Case 3
   arrTest%intContestCase% = Arrayize (StrFill ("a r e w e n o t d r a w n o n w a r d t o n e w e r a ", 162), " ")
   intElems%intContestCase% = ArrInfo (arrTest%intContestCase%, 1) ; 82 array elements.
   Break
EndSwitch
#EndSubRoutine
;------------------------------------------------------------------------------------------------------------------------------------------


;------------------------------------------------------------------------------------------------------------------------------------------
#DefineSubRoutine udsRunContestant (intContestant)
Exclusive (@ON)
Switch intContestant
Case 1
   arrContestants[intContestant] = "udfArrayReverse_1"
   intStart = GetTickCount ()
   arrResult%intContestant% = udfArrayReverse_1 (arrTest%intContestCase%)
   intStop = GetTickCount ()
   arrContestTicks[intContestant] = arrContestTicks[intContestant] + intStop - intStart
   arrContestResults[intContestant] = udfArrayJoin (arrResult%intContestant%, " ")
   intLen%intContestant% = StrLen (arrContestResults[intContestant])
   Break

Case 2
   arrContestants[intContestant] = "udfArrayReverse_2"
   intStart = GetTickCount ()
   arrResult%intContestant% = udfArrayReverse_2 (arrTest%intContestCase%)
   intStop = GetTickCount ()
   arrContestTicks[intContestant] = arrContestTicks[intContestant] + intStop - intStart
   arrContestResults[intContestant] = udfArrayJoin (arrResult%intContestant%, " ")
   intLen%intContestant% = StrLen (arrContestResults[intContestant])
   Break

Case 3
   arrContestants[intContestant] = "udfArrayReverse_3"
   intStart = GetTickCount ()
   arrResult%intContestant% = udfArrayReverse_3 (arrTest%intContestCase%)
   intStop = GetTickCount ()
   arrContestTicks[intContestant] = arrContestTicks[intContestant] + intStop - intStart
   arrContestResults[intContestant] = udfArrayJoin (arrResult%intContestant%, " ")
   intLen%intContestant% = StrLen (arrContestResults[intContestant])
   Break

EndSwitch
Exclusive (@OFF)
#EndSubRoutine
;------------------------------------------------------------------------------------------------------------------------------------------


;------------------------------------------------------------------------------------------------------------------------------------------
#DefineFunction udfArrayReverse_1 (arrArray)
objSC = CreateObject ("MSScriptControl.ScriptControl")
objSC.AllowUI = @FALSE
Switch @TRUE
Case VarType (arrArray) == 256 ; WinBatch Array.
Case ObjectTypeGet (arrArray) == "ARRAY|VARIANT" ; Variant Array.
   objSC.Language = "JScript"
   objSC.AddCode(: "function VB2JSArray(objVBArray){var a;try{a=new VBArray(objVBArray).toArray();}catch(e){a=new Array(objVBArray);}return a;}")
   objSC.AddCode(: 'function JS2VBArray(objJSArray){var dict=new ActiveXObject("Scripting.Dictionary");for(var i=0;i<objJSArray.length;i++){dict.add(i,objJSArray[i]);}return dict.Items();}')
   objSC.AddCode(: "function ArrayReverse(objVBArray){return JS2VBArray(VB2JSArray(objVBArray).reverse());}")
   arrArray = objSC.Run(: "ArrayReverse", arrArray)
   Break
Case @TRUE
   objSC.Language = "VBScript"
   objSC.AddCode(: "Dim a()")
   arrArray = objSC.Eval(: "a")
EndSwitch
Return arrArray
;..........................................................................................................................................
; This UDF "udfArrayReverse" returns a zero-based Dim-1 variant array that contains all elements from the given array in reversed order
; (makes the last element first, and the first element last).
;
; Parameter:
; arrArray ... A one-dimensional array. Array type can be WinBatch Array or Variant Array.
;..........................................................................................................................................
; Alternative codeline, see above:
; objSC.AddCode(: "function VB2JSArray(objVBArray){return new VBArray(objVBArray).toArray();}") ; Possibly in some circumstances not so safe to use.
;..........................................................................................................................................
; (c)Detlev Dalitz.20100121.
; Jim Dippner.20080221: changed VB2JSArray.
; David Wang.20060704: created VB2JSArray, JS2VBArray.
;..........................................................................................................................................
#EndFunction
;------------------------------------------------------------------------------------------------------------------------------------------


;------------------------------------------------------------------------------------------------------------------------------------------
#DefineFunction udfArrayReverse_2 (arrArray) ; WinBatch array.
If ArrInfo (arrArray, 0) != 1 Then Return arrArray ; Only Dim-1 array allowed.
intLast = ArrInfo (arrArray, 1)
If intLast == 0 Then Return ArrDimension (0)
arrRev = ArrDimension (intLast)
intLast = intLast - 1
For intElem = 0 To intLast
   arrRev[intLast - intElem] = arrArray[intElem]
Next
Return arrRev
;..........................................................................................................................................
; This UDF "udfArrayReverse" returns a zero-based Dim-1 WinBatch array that contains all elements from the given Dim-1 WinBatch array in reversed order
; (c)Detlev Dalitz.20100121.
;..........................................................................................................................................
#EndFunction
;------------------------------------------------------------------------------------------------------------------------------------------


;------------------------------------------------------------------------------------------------------------------------------------------
#DefineFunction udfArrayReverse_3 (arrArray) ; WinBatch array.
If ArrInfo (arrArray, 0) != 1 Then Return arrArray ; Only Dim-1 array allowed.
intLast = ArrInfo (arrArray, 1)
If intLast == 0 Then Return ArrDimension (0)
intMid = intLast / 2
For intLeft = 1 To intMid
   intRight = intLast - intLeft
   anyTemp = arrArray[intLeft - 1]
   arrArray[intLeft - 1] = arrArray[intRight]
   arrArray[intRight] = anyTemp
Next
Return arrArray
;..........................................................................................................................................
; This UDF "udfArrayReverse1" returns a zero-based Dim-1 WinBatch array that contains all elements from the given Dim-1 WinBatch array in reversed order
; (c)Detlev Dalitz.20100121.
;..........................................................................................................................................
#EndFunction
;------------------------------------------------------------------------------------------------------------------------------------------


;------------------------------------------------------------------------------------------------------------------------------------------
#DefineFunction udfArrayJoin (arrArray, strDelimiter)
objJSC = CreateObject ("MSScriptControl.ScriptControl")
objJSC.Language = "JScript"
objJSC.AllowUI = @FALSE
Switch @TRUE
Case 256 == VarType (arrArray) ; WinBatch Array.
Case ObjectTypeGet (arrArray) == "ARRAY|VARIANT" ; Variant Array
   objJSC.AddCode(: "function VB2JSArray(objVBArray){var a;try{a=new VBArray(objVBArray).toArray();}catch(e){a=new Array(objVBArray);}return a;}")
   objJSC.AddCode(: "function ArrayJoin(objVBArray,strDelimiter){return VB2JSArray(objVBArray).join(strDelimiter);}")
   strJoined = objJSC.Run(: "ArrayJoin", arrArray, strDelimiter)
   Break
Case @TRUE
   strJoined = ""
EndSwitch
Return strJoined
;..........................................................................................................................................
; This UDF "udfArrayJoin" joins all elements of an array into a string.
; The elements will be separated by the specified delimiter string.
;
; Parameter:
; arrArray ....... A one-dimensional array of strings to be searched. Array type can be WinBatch Array or Variant Array.
; strDelimiter ... A single character or a string. The elements will be separated by this delimiter.
;..........................................................................................................................................
; (c)Detlev Dalitz.20100121.
; Jim Dippner.20080221: changed VB2JSArray.
; David Wang.20060704: created VB2JSArray.
;..........................................................................................................................................
#EndFunction
;------------------------------------------------------------------------------------------------------------------------------------------

;==========================================================================================================================================
Return ; from GoSub DEFINE_CONTEST_FUNCTIONS
;==========================================================================================================================================



;==========================================================================================================================================
:DEFINE_FUNCTIONS
;==========================================================================================================================================

;------------------------------------------------------------------------------------------------------------------------------------------
#DefineFunction udfArrayDumpToItemList (arrArray, intFirst, intLast, strDelimiter)
If !ArrInfo (arrArray, -1) Then Return "*ARRAY_IS_INVALID*" ; No Array, return invalid itemlist, i. e. empty string "".
If ArrInfo (arrArray, 0) != 1 Then Return "*ARRAY_IS_NOT_DIM_1*" ; Array is not a dim-1 array, return invalid itemlist, i. e. empty string "".
intElements = ArrInfo (arrArray, 1)
If intElements == 0 Then Return "*ARRAY_HAS_NO_ELEMENTS*" ; Array has no element.
intFirst = Min (Max (intFirst, 0), intElements - 1)
intLast = Min (Max (intLast, 0), intElements - 1)
strItemList = ""
intFixSize = StrLen (intLast)
For intI = intFirst To intLast
   If !!VarType (arrArray [intI])
      If arrArray [intI] == ""
         strItemList = ItemInsert (StrFixLeft (intI, "0", intFixSize) : "|" : "*ARRAY_ELEMENT_IS_EMPTY_STRING*", -1, strItemList, strDelimiter)
      Else
         arrArray [intI] = StrReplace (StrReplace (StrReplace (StrReplace (arrArray [intI], @CRLF, "@CRLF"), @CR, "@CR"), @LF, "@LF"), @TAB, "@TAB") ; Make WB style.
         arrArray [intI] = StrSub (arrArray [intI], 1, 200) ; Special truncation just for the small buffer of AskItemList.
         strItemList = ItemInsert (StrFixLeft (intI, "0", intFixSize) : "|" : arrArray [intI], -1, strItemList, strDelimiter)
      EndIf
   Else
      strItemList = ItemInsert (StrFixLeft (intI, "0", intFixSize) : "|" : "*ARRAY_ELEMENT_IS_UNDEFINED*", -1, strItemList, strDelimiter)
   EndIf
Next
IntControl (28, 1, 0, 0, 0)
IntControl (63, 050, 200, 950, 800)
Return AskItemlist ("Profiling|Preview Contestant Result", strItemList, strDelimiter, @UNSORTED, @SINGLE) ; This returns a Unicode string of VarType=128.
:CANCEL
Return @CANCEL
;..........................................................................................................................................
; This UDF "udfArrayDumpToItemList" reads a dim-1 array and returns an itemlist of all array cell items within an AskItemList dialog..
;
; Return values:
; "*ARRAY_IS_INVALID*"              ... Invalid array resp. this is no array.
; "*ARRAY_IS_NOT_DIM_1*"            ... Array is not a dim-1 array.
; "*ARRAY_HAS_NO_ELEMENTS*"         ... Array has no element.
; "*ARRAY_ELEMENT_IS_EMPTY_STRING*" ... Array element has vartype STRING but is empty.
; "*ARRAY_ELEMENT_IS UNDEFINED*"    ... Array element has undefined VarType.
; value                             ... Current value of the array element.
;
; Example: strItemList = udfArrayDumpToItemList (arrArray, 0, 19, @TAB)
;
; Detlev Dalitz.20090515.20100122.20101222.
;..........................................................................................................................................
#EndFunction
;------------------------------------------------------------------------------------------------------------------------------------------


;------------------------------------------------------------------------------------------------------------------------------------------
#DefineSubRoutine udsPrepareCounters ()
arrContestants = ArrDimension (1 + intContestantMax)    ; Array index 0 not used.
arrContestResults = ArrDimension (1 + intContestantMax) ; Array index 0 not used.
arrContestTicks = ArrDimension (1 + intContestantMax)   ; Array index 0 used for the sum.
arrContestPct = ArrDimension (1 + intContestantMax)     ; Array index 0 not used.
ArrInitialize (arrContestants, "")
ArrInitialize (arrContestResults, "")
ArrInitialize (arrContestTicks, 0)
ArrInitialize (arrContestPct, 0.0)
#EndSubRoutine
;------------------------------------------------------------------------------------------------------------------------------------------


;------------------------------------------------------------------------------------------------------------------------------------------
#DefineSubRoutine udsResultPerTestCase ()
Decimals (1)
For intContestant = intContestantMin To intContestantMax
   arrContestTicks[0] = arrContestTicks[0] + arrContestTicks[intContestant]
Next
intContestTicksMin = arrContestTicks[0]
For intContestant = intContestantMin To intContestantMax
   intContestTicksMin = Min (intContestTicksMin, arrContestTicks[intContestant])
Next
If arrContestTicks[0] < 1 Then arrContestTicks[0] = 1 ; To prevent dividing by zero.
For intContestant = intContestantMin To intContestantMax
   arrContestPct[intContestant] = 100.0 * arrContestTicks[intContestant] / arrContestTicks[0]
Next

; Format output.
strMsgTitle = "Performance Contest Result"
strTest = "Test"
strTicks = "Ticks"
strPct = "Pct"
strContestant = "Contestant"
strCase = "Contest Case = "
strElems = "Array elements = "
strIter = "Iterations = "
strSep = "  "
strPre = "; "
strWinner = "<== The Winner"
strDT = "DateTime = "
intLenTest = Max (StrLen (strTest), StrLen (intContestantMax))
intLenTicks = StrLen (strTicks)
intLenPct = StrLen (strPct)
intLenContestant = StrLen (strContestant)
intLenSep = StrLen (strSep)
intLenWinner = StrLen (strWinner)
For intContestant = intContestantMin To intContestantMax
   intLenTicks = Max (intLenTicks, StrLen (arrContestTicks[intContestant]))
   intLenPct = Max (intLenPct, StrLen (arrContestPct[intContestant]))
   intLenContestant = Max (intLenContestant, StrLen (arrContestants[intContestant]))
   intElems = intElems%intContestCase%
Next
intLenSum = intLenTest + intLenTicks + intLenPct + intLenContestant + intLenWinner + 4 * intLenSep
strTest = StrFixLeft (strTest, " ", intLenTest)
strTicks = StrFixLeft (strTicks, " ", intLenTicks)
strPct = StrFixLeft (strPct, " ", intLenPct)
strResult = strPre : StrFill ("-", intLenSum) : @LF : strPre : strMsgTitle
strResult = strResult : @LF : strPre : strCase : intContestCase
strResult = strResult : @LF : strPre : strElems : intElems%intContestCase%
strResult = strResult : @LF : strPre : strIter : intContestLoopMax
strResult = strResult : @LF : strPre : strTest : strSep : strTicks : strSep : strPct : strSep : strContestant
For intContestant = intContestantMin To intContestantMax
   strTest = StrFixLeft (intContestant, " ", intLenTest)
   strTicks = StrFixLeft (arrContestTicks[intContestant], " ", intLenTicks)
   strPct = StrFixLeft (arrContestPct[intContestant], " ", intLenPct)
   strContestant = StrFix (arrContestants[intContestant], " ", intLenContestant)
   If arrContestTicks[intContestant] == intContestTicksMin Then strContestant = strContestant : strSep : strWinner
   strResult = strResult : @LF : strPre : strTest : strSep : strTicks : strSep : strPct : strSep : strContestant
Next
Return strResult : @LF : strPre : strDT : TimeYmdHms ()
#EndSubRoutine
;------------------------------------------------------------------------------------------------------------------------------------------

;==========================================================================================================================================
Return ; from GoSub DEFINE_FUNCTIONS
;==========================================================================================================================================

; ----------------------------------------------------
; Performance Contest Result
; Contest Case = 1
; Array elements = 5571
; Iterations = 20
; Test  Ticks   Pct  Contestant
;    1   6454   5.8  udfArrayReverse_1  <== The Winner
;    2  46253  41.9  udfArrayReverse_2
;    3  57799  52.3  udfArrayReverse_3
; DateTime = 2011:01:22:00:34:22
; ----------------------------------------------------
; Performance Contest Result
; Contest Case = 2
; Array elements = 616
; Iterations = 20
; Test  Ticks   Pct  Contestant
;    1   3216  10.9  udfArrayReverse_1  <== The Winner
;    2  11404  38.7  udfArrayReverse_2
;    3  14811  50.3  udfArrayReverse_3
; DateTime = 2011:01:22:00:35:10
; ----------------------------------------------------
; Performance Contest Result
; Contest Case = 3
; Array elements = 82
; Iterations = 20
; Test  Ticks   Pct  Contestant
;    1   2845  43.2  udfArrayReverse_1
;    2   1781  27.1  udfArrayReverse_2  <== The Winner ???
;    3   1955  29.7  udfArrayReverse_3
; DateTime = 2011:01:22:00:35:36
; ----------------------------------------------------


; ----------------------------------------------------
; WinBatch 2012C
; ----------------------------------------------------
; Performance Contest Result
; Contest Case = 1
; Array elements = 5571
; Iterations = 20
; Test  Ticks   Pct  Contestant
;    1   3077   4.9  udfArrayReverse_1  <== The Winner
;    2  26405  41.7  udfArrayReverse_2
;    3  33847  53.4  udfArrayReverse_3
; DateTime = 2013:02:12:20:18:23
; ----------------------------------------------------
; Performance Contest Result
; Contest Case = 2
; Array elements = 616
; Iterations = 20
; Test  Ticks   Pct  Contestant
;    1    405   6.7  udfArrayReverse_1  <== The Winner
;    2   2610  43.4  udfArrayReverse_2
;    3   3005  49.9  udfArrayReverse_3
; DateTime = 2013:02:12:20:18:30
; ----------------------------------------------------
; Performance Contest Result
; Contest Case = 3
; Array elements = 82
; Iterations = 20
; Test  Ticks   Pct  Contestant
;    1    202  20.8  udfArrayReverse_1  <== The Winner
;    2    378  39.0  udfArrayReverse_2
;    3    390  40.2  udfArrayReverse_3
; DateTime = 2013:02:12:20:18:31
; ----------------------------------------------------