Profiling reversing item list
;==========================================================================================================================================
; Reverse string list.
;
; Profiling Performance Contest.
;
;   - udfItemListReverse_1
;   - udfItemListReverse_2
;   - udfItemListReverse_3
;
;------------------------------------------------------------------------------------------------------------------------------------------
; (c)Detlev Dalitz.20110119.
;==========================================================================================================================================


; How many different test cases?
intContestCaseMax = 3

; How many loops to run?
intContestLoopMax = 300

; 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
   strItemList = "49 18 77 6 56 221 1 12 111"
   strDelimiter = " "
   Break
Case 2
   strItemList = StrFill ("ZZ YY XX --- CC BB AA --- ", 203)
   strDelimiter = " "
   Break
Case 3
   strItemList = "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"
   strDelimiter = " "
   Break
EndSwitch
#EndSubRoutine
;------------------------------------------------------------------------------------------------------------------------------------------


;------------------------------------------------------------------------------------------------------------------------------------------
#DefineSubRoutine udsRunContestant (intContestant)
Exclusive (@ON)
Switch intContestant
Case 1
   arrContestants[intContestant] = "udfItemListReverse_1"
   intStart = GetTickCount ()
   arrContestResults[intContestant] = udfItemListReverse_1 (strItemList, strDelimiter)
   intStop = GetTickCount ()
   arrContestTicks[intContestant] = arrContestTicks[intContestant] + intStop - intStart
   Break

Case 2
   arrContestants[intContestant] = "udfItemListReverse_2"
   intStart = GetTickCount ()
   arrContestResults[intContestant] = udfItemListReverse_2 (strItemList, strDelimiter)
   intStop = GetTickCount ()
   arrContestTicks[intContestant] = arrContestTicks[intContestant] + intStop - intStart
   Break

Case 3
   arrContestants[intContestant] = "udfItemListReverse_3"
   intStart = GetTickCount ()
   arrContestResults[intContestant] = udfItemListReverse_3 (strItemList, strDelimiter)
   intStop = GetTickCount ()
   arrContestTicks[intContestant] = arrContestTicks[intContestant] + intStop - intStart
   Break

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


;------------------------------------------------------------------------------------------------------------------------------------------
#DefineFunction udfItemListReverse_1 (strItemList, strDelimiter)
strItemListReverse = ""
intCount = ItemCount (strItemList, strDelimiter)
For intElem = intCount To 1 By -1
   strItemListReverse = ItemInsert (ItemExtract (intElem, strItemList, strDelimiter), -1, strItemListReverse, strDelimiter)
Next
Return strItemListReverse
#EndFunction
;------------------------------------------------------------------------------------------------------------------------------------------


;------------------------------------------------------------------------------------------------------------------------------------------
#DefineFunction udfItemListReverse_2 (strItemList, strDelimiter)
strItemListReverse = ""
intCount = ItemCount (strItemList, strDelimiter)
For intElem = intCount To 1 By -1
   strItemListReverse = strItemListReverse : strDelimiter : ItemExtract (intElem, strItemList, strDelimiter)
Next
Return StrSub (strItemListReverse, 2, -1)
#EndFunction
;------------------------------------------------------------------------------------------------------------------------------------------


;------------------------------------------------------------------------------------------------------------------------------------------
#DefineFunction udfItemListReverse_3 (strItemList, strDelimiter)
intCount = ItemCount (strItemList, strDelimiter) - 1
For intElem = intCount To 1 By -1
   strItemList = ItemRemove (intElem, ItemInsert (ItemExtract (intElem, strItemList, strDelimiter), -1, strItemList, strDelimiter), strDelimiter)
Next
Return strItemList
#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 = "
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]))
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 : 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
; Iterations = 300
; Test  Ticks   Pct  Contestant
;    1   1112  32.0  udfItemListReverse_1
;    2    891  25.7  udfItemListReverse_2  <== The Winner
;    3   1469  42.3  udfItemListReverse_3
; DateTime = 2011:01:20:00:12:11
; -------------------------------------------------------
; Performance Contest Result
; Contest Case = 2
; Iterations = 300
; Test  Ticks   Pct  Contestant
;    1   5923  31.1  udfItemListReverse_1
;    2   5608  29.5  udfItemListReverse_2  <== The Winner
;    3   7499  39.4  udfItemListReverse_3
; DateTime = 2011:01:20:00:12:32
; -------------------------------------------------------
; Performance Contest Result
; Contest Case = 3
; Iterations = 300
; Test  Ticks   Pct  Contestant
;    1   2887  31.4  udfItemListReverse_1
;    2   2755  29.9  udfItemListReverse_2  <== The Winner
;    3   3563  38.7  udfItemListReverse_3
; DateTime = 2011:01:20:00:12:43
; -------------------------------------------------------