Announcement

Collapse
No announcement yet.

Alternative to JOIN$.

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • #21
    Bern,

    Would you give this version a whirl, the test piece seems to be working OK and it is producing a full basic strings complete with an ascii zero embedded in the middle. I have run out of puff for testing but it seems to behave itself so far. The algo is slightly slower as it must retrieve the string length in the speed critical algo but its still clocking up OK.

    The timing on my Haswell E/EP
    Code:
    correctness test for mcat$ = One One Two Two Three Three Four Four Five Five Six Six Seven Seven Eight Eight Nine Nine Ten Ten
    correctness test for join$ = One One Two Two Three Three Four Four Five Five Six Six Seven Seven Eight Eight Nine Nine Ten Ten
    mcat$ = 406 ms
    join$ = 3406 ms
    
    Press any key to exit ....
    This is the "sauce".

    Code:
    ' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
    '                                  Benchmark between mcat$ and join$
    '                                          Build with PBCC 6
    ' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
    
        #COMPILE EXE "bmark.exe"
    
        #include "\basic\include\win32api.inc"
    
    ' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
    
     FUNCTION PBmain as LONG
    
        DIM varr(128) as STRING             ' create string array
    
        varr(0) = "One"+chr$(0)+"One "
        varr(1) = "Two"+chr$(0)+"Two "
        varr(2) = "Three"+chr$(0)+"Three "
        varr(3) = "Four"+chr$(0)+"Four "
        varr(4) = "Five"+chr$(0)+"Five "
        varr(5) = "Six"+chr$(0)+"Six "
        varr(6) = "Seven"+chr$(0)+"Seven "
        varr(7) = "Eight"+chr$(0)+"Eight "
        varr(8) = "Nine"+chr$(0)+"Nine "
        varr(9) = "Ten"+chr$(0)+"Ten "
    
        LOCAL lcnt as DWORD
        LOCAL tcnt as DWORD
    
      ' -------------------------------------
    
        rslt$ = mcat$(10,varr())
        StdOut $CRLF+"correctness test for mcat$ = "+rslt$
    
        rslt$ = join$(varr(),"")
        StdOut "correctness test for join$ = "+rslt$
    
      ' -------------------------------------
    
        lcnt = 1000000
    
        tcnt = GetTickCount()
    
      lbl0:
        rslt$ = mcat$(10,varr())            ' call the multicat function
        ! sub lcnt, 1
        ! jnz lbl0
    
        tcnt = GetTickCount - tcnt
    
        StdOut "mcat$ = "+format$(tcnt)+" ms"
    
      ' -------------------------------------
    
        lcnt = 1000000
    
        tcnt = GetTickCount()
    
      lbl1:
        rslt$ = join$(varr()," ")           ' call the join$ function
        ! sub lcnt, 1
        ! jnz lbl1
    
        tcnt = GetTickCount - tcnt
    
        StdOut "join$ = "+format$(tcnt)+" ms"
    
      ' -------------------------------------
    
        erase varr()                        ' delete the array
    
        StdOut $CRLF+"Press any key to exit ...."
        waitkey$
    
     End FUNCTION
    
    ' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
    
     FUNCTION mcat$(ByVal icnt as DWORD,varr() as STRING)
      ' ----------------------------------------------------
      ' icnt is the number of strings to append to a buffer
      ' varr() is the string array that contains the strings
      ' ----------------------------------------------------
        #REGISTER NONE
    
        LOCAL cloc as DWORD                 ' current location pointer
        LOCAL lcnt as DWORD                 ' loop counter
        LOCAL totl as DWORD                 ' buffer size variable
        LOCAL pstr as DWORD                 ' string pointer for append loop
        LOCAL pbuf as DWORD                 ' buffer pointer
    
      ' -------------------------
      ' calculate the buffer size
      ' -------------------------
        ! mov lcnt, 0                       ' set the loop counter to zero
        ! xor esi, esi                      ' zero esi
        ! mov edi, icnt                     ' load icnt into register to reduce instruction count
    
      lbl0:
        pstr = len(varr(lcnt))
        ! add esi, eax                      ' add each string length to esi
        ! add lcnt, 1                       ' increment the loop counter
        ! cmp lcnt, edi                     ' test lcnt against icnt
        ! jbe lbl0                          ' jump back if below or equal
    
        ! mov totl, esi                     ' store esi (combined string lengths) in totl
      ' -------------------------
    
      ' -----------------------------------------
      ' sequentially append string data to buffer
      ' -----------------------------------------
        buff$ = space$(totl)                ' allocate string space
        pbuf = StrPtr(buff$)                ' get its address
        ! mov cloc, 0                       ' zero the location counter
        ! mov lcnt, 0                       ' set the loop counter to zero
    
      lbl1:
        pstr = StrPtr(varr(lcnt))           ' string address of each array member
    
        ! mov edx, cloc                     ' pass arguments in registers
        ! mov ecx, pstr
        ! mov eax, pbuf
        ! call fcappend                     ' append each string
        ! mov cloc, eax                     ' update cloc
    
        ! add lcnt, 1                       ' increment the loop counter
        ! cmp lcnt, edi                     ' test lcnt against icnt
        ! jbe lbl1                          ' jump back if below or equal
      ' -----------------------------------------
    
        FUNCTION = buff$                    ' return the combined string
    
     End FUNCTION
    
    ' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
    
     FASTPROC fcappend
    
      ' --------------------------------------------------------------
      ' FASTCALL emulation
      ' pass 3 arguments in registers to reduce call overhead
    
      ' eax = pstring     the main buffer to append extra data to.
      ' ecx = buffer      the byte data to append to the main buffer
      ' edx = location    current location pointer
      ' --------------------------------------------------------------
    
        PREFIX "!"
    
        push ebx
        push esi
        push edi
    
        mov ebx, ecx                        ' load the string address
        sub ebx, 4                          ' sub 4 to get stored string length
        mov ebx, [ebx]                      ' write it back to ebx
    
        mov esi, eax                        ' pstring
        mov ecx, ecx                        ' buffer
        add esi, edx                        ' location
        mov edi, edx                        ' update return value variable
        or eax, -1                          ' set eax to -1
        add ebx, 1                          ' correct ebx for following loop
    
      ' -----------
      ' unroll by 2
      ' -----------
      lbl0:
        add eax, 1
        movzx edx, BYTE PTR [ecx+eax]
        mov [esi+eax], dl
        sub ebx, 1
        jz lbl1                             ' exit on written terminator
    
        add eax, 1
        movzx edx, BYTE PTR [ecx+eax]
        mov [esi+eax], dl
        sub ebx, 1
        jnz lbl0                            ' exit on written terminator
    
      lbl1:
        add eax, edi                        ' location
    
        pop edi
        pop esi
        pop ebx
    
        ret
    
        END PREFIX
    
     END FASTPROC
    
    ' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
    Attached Files
    hutch at movsd dot com
    The MASM Forum

    www.masm32.com

    Comment


    • #22
      Steve, initial testing looked good, but when I plugged in to some application code I had and ran with real data, I got GPF/crashes happening. I dumped the data just before the offending call and created a short test code that crashes on my end.

      Strangely enough, I can run your benchmark code on my machine just fine (compile + run), but to do the same with the code below, I have to disable AVG anti-virus as it complains that the code is malware. ???

      Code:
          #COMPILE EXE
      
          #INCLUDE "win32api.inc"
      
      ' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
      
       FUNCTION PBMAIN AS LONG
      
          DIM varr( 0 TO 37) AS LOCAL STRING
      
          LOCAL rslt$
      
          varr(0) = CHR$( 1, 50)
          varr(1) = CHR$( 7, 66, 101, 114, 110, 97, 114, 100)
          varr(2) = CHR$( 32, 68, 52, 49, 68, 56, 67, 68, 57, 56, 70, 48, 48, 66, 50, 48, 52, 69, 57, 56, 48, 48, 57, 57, 56, 69, 67, 70, 56, 52, 50, 55, 69)
          varr(3) = CHR$( 10, 49, 48, 55, 51, 55, 52, 50, 51, 48, 50)
          varr(4) = CHR$( 254)
          varr(5) = CHR$( 2, 55, 54)
          varr(6) = CHR$( 5, 54, 53, 50, 56, 48)
          varr(7) = CHR$( 8, 49, 54, 55, 49, 49, 54, 56, 48)
          varr(8) = CHR$( 5, 54, 53, 53, 51, 53)
          varr(9) = CHR$( 3, 50, 53, 53)
          varr(10) = CHR$( 7, 56, 51, 56, 56, 55, 51, 54)
          varr(11) = CHR$( 8, 49, 50, 54, 51, 50, 50, 53, 54)
          varr(12) = CHR$( 8, 49, 54, 55, 55, 54, 57, 54, 48)
          varr(13) = CHR$( 1, 48)
          varr(14) = CHR$( 8, 49, 54, 55, 49, 49, 57, 51, 53)
          varr(15) = CHR$( 1, 48)
          varr(16) = CHR$( 3, 49, 54, 54)
          varr(17) = CHR$( 3, 53, 52, 56)
          varr(18) = CHR$( 3, 54, 55, 56)
          varr(19) = CHR$( 3, 51, 52, 57)
          varr(20) = CHR$( 2, 51, 54)
          varr(21) = CHR$( 2, 53, 48)
          varr(22) = CHR$( 4, 49, 48, 49, 52)
          varr(23) = CHR$( 4, 49, 55, 56, 53)
          varr(24) = CHR$( 2, 52, 50)
          varr(25) = CHR$( 3, 53, 50, 53)
          varr(26) = CHR$( 3, 57, 57, 51)
          varr(27) = CHR$( 3, 53, 56, 57)
          varr(28) = CHR$( 70, 49, 52, 46, 49, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 55, 8, 49, 52, 46, 49, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 55, 8, 49, 50, 46, 48, 52, 49, 54, 54, 54, 54, 54, 54, 54, 54, 54, 55, 8, 49, 52, _
                                  8, 49, 52, 46, 49, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 55)
          varr(29) = CHR$( 4, 49, 52, 49, 52)
          varr(30) = CHR$( 3, 54, 53, 52)
          varr(31) = CHR$( 148, 80, 114, 111, 106, 101, 99, 116, 9, 49, 9, 45, 49, 9, 49, 54, 46, 50, 53, 8, 78, 111, 116, 101, 115, 9, 50, 9, 45, 49, 9, 51, 48, 46, 56, 55, 53, 8, 79, 119, 110, 101, 114, 9, 51, 9, 45, 49, 9, 49, 51, 46, 56, _
               55, 53, 8, 77, 97, 110, 97, 103, 101, 114, 9, 52, 9, 45, 49, 9, 57, 46, 50, 53, 8, 80, 108, 97, 110, 110, 101, 114, 9, 53, 9, 45, 49, 9, 57, 46, 50, 53, 8, 9, 54, 9, 48, 9, 48, 8, 9, 55, 9, 48, 9, 48, 8, 9, 56, 9, 48, 9, 48, 8, 9, _
               57, 9, 48, 9, 48, 8, 9, 49, 48, 9, 48, 9, 48, 8, 9, 49, 49, 9, 48, 9, 48, 8, 65, 99, 116, 105, 118, 101, 9, 49, 50, 9, 48, 9, 48)
          varr(32) = CHR$( 213, 73, 68, 9, 49, 9, 45, 49, 9, 49, 51, 46, 49, 50, 53, 8, 82, 101, 102, 101, 114, 101, 110, 99, 101, 32, 84, 97, 103, 9, 50, 9, 45, 49, 9, 49, 53, 46, 50, 53, 8, 74, 111, 98, 32, 80, 108, 97, 110, 32, 68, 101, _
              115, 99, 114, 105, 112, 116, 105, 111, 110, 9, 51, 9, 45, 49, 9, 51, 57, 46, 53, 8, 77, 97, 110, 104, 111, 117, 114, 115, 9, 52, 9, 45, 49, 9, 56, 8, 68, 105, 115, 112, 108, 97, 121, 32, 79, 114, 100, 101, 114, 9, 53, 9, _
              45, 49, 9, 49, 51, 46, 51, 55, 53, 8, 65, 114, 99, 104, 105, 118, 101, 100, 9, 54, 9, 45, 49, 9, 56, 8, 65, 46, 70, 46, 69, 46, 9, 55, 9, 48, 9, 48, 8, 69, 113, 117, 105, 112, 109, 101, 110, 116, 9, 56, 9, 45, 49, 9, _
              50, 48, 46, 49, 50, 53, 8, 74, 111, 98, 32, 80, 108, 97, 110, 32, 76, 101, 118, 101, 108, 32, 83, 117, 112, 101, 114, 118, 105, 115, 111, 114, 115, 9, 57, 9, 48, 9, 48, 8, 85, 110, 105, 116, 47, 65, 114, 101, 97, 9, 49, 48, 9, 48, 9, 48)
          varr(33) = CHR$( 255, 202, 2, 0, 0, 83, 117, 109, 109, 97, 114, 121, 32, 84, 97, 115, 107, 32, 79, 112, 101, 110, 47, 67, 108, 111, 115, 101, 9, 49, 9, 45, 49, 9, 50, 46, 56, 55, 53, 8, 73, 68, 9, 50, 9, 45, 49, 9, 49, 48, 46, 49) + _
              CHR$(50,53,8, 84, 97, 115, 107, 32, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 9, 51, 9, 45, 49, 9, 53, 55, 46, 54, 50, 53, 8, 82, 101, 109, 97, 105, 110, 105, 110, 103, 32, 68, 117, 114, 97, 116, 105, 111, 110, 9, 52, 9) + _
              CHR$(48, 9, 48, 8, 79, 114, 105,103,105, 110, 97, 108, 32, 68, 117, 114, 97, 116, 105, 111, 110, 9, 53, 9, 48, 9, 48, 8, 69, 115, 116, 105, 109, 97, 116, 101, 100, 32, 68, 117, 114, 97, 116, 105, 111, 110, 9, 54, 9, 45, 49) + _
              CHR$(9, 56, 8, 37, 32, 67, 111, 109, 112, 108, 101, 116, 101, 9,55,9, 48, 9, 48, 8, 80, 114, 101, 100, 101, 99, 101, 115, 115, 111) + _
              CHR$(114, 115, 9, 56, 9, 48, 9, 48, 8, 83, 117, 99, 99, 101, 115, 115, 111, 114, 115, 9, 57, 9, 48, 9, 48, 8, 82, 101, 115, 111) + _
              CHR$(117, 114, 99, 101, 115, 9, 49, 48, 9, 45, 49, 9, 49, 52, 46,49,50, 53, 8, 84, 121, 112, 101, 9, 49, 49, 9, 45, 49, 9, 56, 8) + _
              CHR$(83, 99, 111, 112, 101, 9, 49, 50, 9, 45, 49, 9, 56, 46, 49, 50, 53, 8, 67, 97, 108, 101, 110, 100, 97, 114, 9, 49, 51, 9, 45, 49, 9, 56) + _
              CHR$(8, 83, 99, 101, 110, 97, 114, 105, 111, 9, 49, 52,9,45, 49, 9, 48, 8, 79, 112, 116, 105, 109, 105, 115, 116, 105, 99, 32) + _
              CHR$(68, 117, 114, 97, 116, 105, 111, 110, 9, 49, 53, 9, 45, 49, 9, 56, 8, 80, 101, 115, 115, 105, 109, 105, 115, 116, 105, 99, 32, 68, 117, 114, 97, 116, 105, 111, 110, 9, 49, 54, 9) + _
              CHR$(45,49,9, 56, 8, 90, 111, 110, 101, 115, 9, 49, 55, 9, 45, 49, 9, 56, 8, 69, 120, 99, 101, 112, 116, 105, 111, 110, 115, 9, 49, 56, 9, 48, 9, 48, 8, 85, 110, 105, 110, 116, 101, 114, 114, 117, 112)
          varr(33) += CHR$(116, 97, 98, 108, 101, 9, 49, 57, 9, 48, 9, 48, 8, 77) + _
              CHR$( 101,116,104, 111, 100, 9, 50, 48, 9, 48, 9, 48, 8, 78, 111, 110, 45, 67, 114, 105, 116, 105, 99, 97, 108, 32, 87, 111, 114, 107, 9, 50, 49, 9, 45, 49, 9, 56, 8, 68, 105, 115, 112, 108, 97, 121, 32) + _
              CHR$(79, 114, 100, 101, 114, 9, 50, 50, 9, 45, 49, 9, 56, 8) + _
              CHR$(69,97,114, 108, 121, 32, 83, 116, 97, 114, 116, 9, 50, 51, 9, 48, 9, 48, 8, 69, 97, 114, 108, 121, 32, 70, 105, 110, 105, 115, 104, 9, 50, 52, 9, 48, 9, 48, 8, 76, 97, 116, 101, 32, 83, 116, 97, 114) + _
              CHR$(116, 9, 50, 53, 9, 48, 9, 48, 8, 76, 97, 116, 101) + _
              CHR$(32,70,105, 110, 105, 115, 104, 9, 50, 54, 9, 48, 9, 48, 8, 70, 114, 101, 101, 32, 70, 108, 111, 97, 116, 9, 50, 55, 9, 48, 9, 48, 8, 84, 111, 116, 97, 108, 32, 70, 108, 111, 97, 116, 9, 50, 56, 9, 48) + _
              CHR$(9, 48, 8, 68, 114, 97, 103, 9, 50, 57, 9, 48, 9, 48) + _
              CHR$(8,80,117, 108, 108, 9, 51, 48, 9, 48, 9, 48, 8, 88, 32, 80, 117, 108, 108, 9, 51, 49, 9, 48, 9, 48, 8, 80, 114, 105, 111, 114, 105, 116, 105, 101, 115, 9, 51, 50, 9, 45, 49, 9, 56, 8, 80, 114, 111, 99) + _
              CHR$(101, 100, 117, 114, 101, 115, 9, 51, 51, 9, 45) + _
              CHR$(49,9,57, 46, 50, 53, 8, 84, 97, 115, 107, 32, 76, 101, 118, 101, 108, 32, 83, 117, 112, 101, 114, 118, 105, 115, 111, 114, 115, 9, 51, 52, 9, 45, 49, 9, 49, 51, 46, 53, 8, 77, 105, 108, 101, 115, 116) + _
              CHR$(111, 110, 101, 115, 9, 51, 53, 9, 45, 49, 9, 50, 53)
          varr(34) = CHR$( 255, 1, 1, 0, 0, 81, 117, 97, 110, 116, 105, 116, 121, 9, 49, 9, 45, 49, 9, 55, 46, 51, 55, 53, 8, 82, 101, 115, 111, 117, 114, 99, 101, 9, 50, 9, 45, 49, 9, 56, 46, 50, 53, 8, 82, 101, 115, 111, 117, 114, 99, 101) + _
              CHR$(32,68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 9, 51, 9, 45, 49, 9, 49, 51, 46, 50, 53, 8, 67, 111, 110, 116, 114, 97, 99, 116, 111, 114, 9, 52, 9, 45, 49, 9, 56, 46, 54) + _
              CHR$(50, 53, 8, 67, 111, 110, 116, 114, 97, 99, 116, 111, 114, 32, 68, 101) + _
              CHR$(115,99, 114, 105, 112, 116, 105, 111, 110, 9, 53, 9, 45, 49, 9, 49, 48, 8, 76) + _
              CHR$(83, 32, 67, 111, 110, 116, 114, 97, 99, 116, 9, 54, 9, 45, 49, 9, 57, 46, 53, 8, 76, 83, 32, 67, 111, 110, 116, 114, 97, 99, 116, 32, 68, 101, 115, 99, 114, 105, 112, 116) + _
              CHR$(105,111, 110, 9, 55, 9, 45, 49, 9, 49, 54, 46, 50, 53, 8, 82, 97, 116, 101) + _
              CHR$(32, 79, 118, 101, 114, 114, 105, 100, 101, 9, 56, 9, 45, 49, 9, 49, 48, 8, 70, 105, 120, 101, 100, 32, 67, 111, 115, 116, 32, 79, 118, 101, 114, 114, 105, 100, 101, 9, 57, 9, 45) + _
              CHR$(49,9, 49, 52, 46, 49, 50, 53, 8, 79, 118, 101, 114, 114, 105, 100, 101, 32) + _
              CHR$(66, 97, 115, 105, 115, 9, 49, 48, 9, 45, 49, 9, 49, 48)
          varr(35) = CHR$( 255, 183, 2, 0, 0, 83, 117, 109, 109, 97, 114, 121, 32, 84, 97, 115, 107, 32, 79, 112, 101, 110, 47, 67, 108, 111, 115, 101, 9, 49, 9, 48, 9, 48, 8, 73, 68, 9, 50, 9, 48, 9, 48, 8, 84, 97, 115, 107, 32, 68, 101) + _
              CHR$(115,99,114, 105, 112, 116, 105, 111, 110, 9, 51, 9, 45, 49, 9, 53, 48, 46, 53, 8, 82, 101, 109, 97) + _
              CHR$(105, 110, 105, 110, 103, 32, 68, 117, 114, 97, 116, 105, 111, 110, 9, 52, 9, 45, 49, 9, 57, 46, 54, 50, 53, 8, 79, 114, 105, 103, 105, 110, 97, 108, 32) + _
              CHR$(68,117,114, 97, 116, 105, 111, 110, 9, 53, 9, 48, 9, 48, 8, 69, 115, 116, 105, 109, 97, 116, 101) + _
              CHR$(100, 32, 68, 117, 114, 97, 116, 105, 111, 110, 9, 54, 9, 48, 9, 48, 8, 37, 32, 67, 111, 109, 112, 108, 101, 116, 101, 9, 55, 9, 45, 49, 9, 56, 46, 50, 53) + _
              CHR$(8,80,114, 101, 100, 101, 99, 101, 115, 115, 111, 114, 115, 9, 56, 9, 48, 9, 48, 8, 83, 117, 99) + _
              CHR$(99, 101, 115, 115, 111, 114, 115, 9, 57, 9, 48, 9, 48, 8, 82, 101, 115, 111, 117, 114, 99, 101, 115, 9, 49, 48, 9, 45, 49, 9, 49, 52, 46, 49, 50, 53, 8, 84) + _
              CHR$(121,112,101, 9, 49, 49, 9, 45, 49, 9, 56, 8, 83, 99, 111, 112, 101, 9, 49, 50, 9, 45, 49, 9, 56) + _
              CHR$(46, 49, 50, 53, 8, 67, 97, 108, 101, 110, 100, 97, 114, 9, 49, 51, 9, 45, 49, 9, 56, 8, 83, 99, 101, 110, 97, 114, 105, 111, 9, 49, 52, 9, 48, 9, 48, 8, 79)
          varr(35) += CHR$(112,116,105, 109, 105, 115, 116, 105, 99, 32, 68, 117, 114, 97, 116, 105, 111, 110, 9, 49, 53, 9) + _
              CHR$(48, 9, 48, 8, 80, 101, 115, 115, 105, 109, 105, 115, 116, 105, 99, 32, 68, 117, 114, 97, 116, 105, 111, 110, 9, 49, 54, 9, 48, 9, 48, 8, 90, 111, 110) + _
              CHR$(101,115,9, 49, 55, 9, 48, 9, 48, 8, 69, 120, 99, 101, 112, 116, 105, 111, 110, 115, 9, 49, 56, 9) + _
              CHR$(48, 9, 48, 8, 85, 110, 105, 110, 116, 101, 114, 114, 117, 112, 116, 97, 98, 108, 101, 9, 49, 57, 9, 48, 9, 48, 8, 77, 101, 116, 104, 111, 100, 9, 50, 48) + _
              CHR$(9,48,9, 48, 8, 78, 111, 110, 45, 67, 114, 105, 116, 105, 99, 97, 108, 32, 87, 111, 114, 107, 9, 50) + _
              CHR$(49, 9, 45, 49, 9, 56, 8, 68, 105, 115, 112, 108, 97, 121, 32, 79, 114, 100, 101, 114, 9, 50, 50, 9, 45, 49, 9, 56, 8, 69, 97, 114, 108, 121, 32, 83, 116) + _
              CHR$(97,114,116, 9, 50, 51, 9, 48, 9, 48, 8, 69, 97, 114, 108, 121, 32, 70, 105, 110, 105, 115, 104, 9) + _
              CHR$(50, 52, 9, 48, 9, 48, 8, 76, 97, 116, 101, 32, 83, 116, 97, 114, 116, 9, 50, 53, 9, 48, 9, 48, 8, 76, 97, 116, 101, 32, 70, 105, 110, 105, 115, 104, 9) + _
              CHR$(50,54,9, 48, 9, 48, 8, 70, 114, 101, 101, 32, 70, 108, 111, 97, 116, 9, 50, 55, 9, 48, 9, 48, 8, 84) + _
              CHR$(111, 116, 97, 108, 32, 70, 108, 111, 97, 116, 9, 50, 56, 9, 48, 9, 48, 8, 68, 114, 97, 103, 9, 50, 57, 9, 48, 9, 48, 8, 80, 117, 108, 108, 9, 51, 48, 9) + _
              CHR$(48,9,48, 8, 88, 32, 80, 117, 108, 108, 9, 51, 49, 9, 48, 9, 48, 8, 80, 114, 105, 111, 114, 105, 116)
          varr(35) += CHR$(105, 101, 115, 9, 51, 50, 9, 45, 49, 9, 56, 8, 80, 114, 111, 99, 101, 100, 117, 114, 101, 115, 9, 51, 51, 9, 48, 9, 48, 8, 84, 97, 115, 107, 32, 76) + _
              CHR$(101,118,101, 108, 32, 83, 117, 112, 101, 114, 118, 105, 115, 111, 114, 115, 9, 51, 52, 9, 48, 9, 48) + _
              CHR$(8, 77, 105, 108, 101, 115, 116, 111, 110, 101, 115, 9, 51, 53, 9, 48, 9, 48)
          varr(36) = CHR$( 255, 145, 1, 0, 0, 80, 114, 101, 100, 101, 99, 101, 115, 115, 111, 114, 9, 49, 9, 45, 49, 9, 57, 46, 56, 55, 53, 8, 83, 117, 99, 99, 101, 115, 115, 111, 114, 9, 50, 9, 45, 49, 9, 56, 46, 55, 53, 8, 84, 121, 112) + _
              CHR$(101,9,51, 9, 45, 49, 9, 53, 46, 53, 8, 68, 114, 105, 118, 105, 110, 103, 9, 52, 9, 45, 49, 9, 54, 46, 54, 50) + _
              CHR$(53, 8, 67, 97, 108, 101, 110, 100, 97, 114, 9, 53, 9, 45, 49, 9, 55, 46, 55, 53, 8, 83, 99, 101, 110, 97, 114, 105, 111, 9, 54, 9, 48, 9, 48) + _
              CHR$(8,68,97, 116, 101, 32, 67, 111, 110, 115, 116, 114, 97, 105, 110, 116, 9, 55, 9, 45, 49, 9, 49, 48, 8, 67) + _
              CHR$(111, 110, 115, 116, 114, 97, 105, 110, 116, 32, 84, 121, 112, 101, 9, 56, 9, 45, 49, 9, 49, 48, 8, 76, 101, 97, 100, 47, 76, 97, 103, 9, 57, 9) + _
              CHR$(45,49,9, 56, 46, 51, 55, 53, 8, 76, 101, 97, 100, 47, 76, 97, 103, 32, 66, 97, 115, 105, 115, 9, 49, 48, 9) + _
              CHR$(45, 49, 9, 49, 50, 46, 49, 50, 53, 8, 82, 101, 109, 97, 105, 110, 105, 110, 103, 32, 68, 117, 114, 97, 116, 105, 111, 110, 9, 49, 49, 9, 45, 49)
          varr(36) += CHR$(9,49,48, 8, 70, 105, 114, 115, 116, 32, 116, 111, 32, 67, 111, 109, 112, 108, 101, 116, 101, 32, 71, 114) + _
              CHR$(111, 117, 112, 9, 49, 50, 9, 45, 49, 9, 49, 48, 8, 69, 97, 114, 108, 121, 32, 83, 116, 97, 114, 116, 9, 49, 51, 9, 45, 49, 9, 49, 51, 46, 53, 8) + _
              CHR$(69,97,114, 108, 121, 32, 70, 105, 110, 105, 115, 104, 9, 49, 52, 9, 45, 49, 9, 49, 51, 46, 53, 8, 76, 97, 116) + _
              CHR$(101, 32, 83, 116, 97, 114, 116, 9, 49, 53, 9, 45, 49, 9, 49, 53, 8, 76, 97, 116, 101, 32, 70, 105, 110, 105, 115, 104, 9, 49, 54, 9, 45, 49) + _
              CHR$(9,49,53, 8, 70, 114, 101, 101, 32, 70, 108, 111, 97, 116, 9, 49, 55, 9, 45, 49, 9, 56, 46, 51, 55, 53, 8, 84) + _
              CHR$(111, 116, 97, 108, 32, 70, 108, 111, 97, 116, 9, 49, 56, 9, 45, 49, 9, 57, 46, 54, 50, 53)
          varr(37) = CHR$( 114, 78, 97, 109, 101, 9, 49, 9, 45, 49, 9, 50, 57, 46, 54, 50, 53, 8, 86, 101, 114, 115, 105, 111, 110, 9, 50, 9, 45, 49, 9, 56, 46, 50, 53, 8, 78, 111, 116, 101, 115, 9, 51, 9, 45, 49, 9, 53, 48, 46, 55, 53, 8,_
      67,97, 116, 101, 103, 111, 114, 121, 9, 52, 9, 45, 49, 9, 57, 46, 54, 50, 53, 8, 87, 104, 101, 110, 32, 84, 111, 32, 85, 115, 101, 9, 53, 9, 45, 49, 9, 50, 49, 46, 51, 55, 53, 8, 65, 117, 100, 105, 101, 110, 99, 101, 9, 54, 9, 45, 49, 9, 49, 56, 46, 53)
      
      
          MSGBOX "varr() ready"
      
          rslt$ = mcat$(38,varr())
          MSGBOX "LEN mcat$ = " + FORMAT$( LEN( rslt$))
      
      
       END FUNCTION
      
      ' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
      
       FUNCTION mcat$(BYVAL icnt AS DWORD,varr() AS STRING)
        ' ----------------------------------------------------
        ' icnt is the number of strings to append to a buffer
        ' varr() is the string array that contains the strings
        ' ----------------------------------------------------
          #REGISTER NONE
      
          LOCAL cloc AS DWORD                 ' current location pointer
          LOCAL lcnt AS DWORD                 ' loop counter
          LOCAL totl AS DWORD                 ' buffer size variable
          LOCAL pstr AS DWORD                 ' string pointer for append loop
          LOCAL pbuf AS DWORD                 ' buffer pointer
          LOCAL sbuff AS STRING
      
        ' -------------------------
        ' calculate the buffer size
        ' -------------------------
          ! mov lcnt, 0                       ' set the loop counter to zero
          ! xor esi, esi                      ' zero esi
          ! mov edi, icnt                     ' load icnt into register to reduce instruction count
      
        lbl0:
          pstr = LEN(varr(lcnt))
          ! add esi, eax                      ' add each string length to esi
          ! add lcnt, 1                       ' increment the loop counter
          ! cmp lcnt, edi                     ' test lcnt against icnt
          ! jbe lbl0                          ' jump back if below or equal
      
          ! mov totl, esi                     ' store esi (combined string lengths) in totl
        ' -------------------------
      
        ' -----------------------------------------
        ' sequentially append string data to buffer
        ' -----------------------------------------
          sbuff = SPACE$(totl)                ' allocate string space
          pbuf = STRPTR(sbuff)                ' get its address
          ! mov cloc, 0                       ' zero the location counter
          ! mov lcnt, 0                       ' set the loop counter to zero
      
        lbl1:
          pstr = STRPTR(varr(lcnt))           ' string address of each array member
      
          ! mov edx, cloc                     ' pass arguments in registers
          ! mov ecx, pstr
          ! mov eax, pbuf
          ! call fcappend                     ' append each string
          ! mov cloc, eax                     ' update cloc
      
          ! add lcnt, 1                       ' increment the loop counter
          ! cmp lcnt, edi                     ' test lcnt against icnt
          ! jbe lbl1                          ' jump back if below or equal
        ' -----------------------------------------
      
          FUNCTION = sbuff                    ' return the combined string
      
       END FUNCTION
      
      ' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
      
       FASTPROC fcappend
      
        ' --------------------------------------------------------------
        ' FASTCALL emulation
        ' pass 3 arguments in registers to reduce call overhead
      
        ' eax = pstring     the main buffer to append extra data to.
        ' ecx = buffer      the byte data to append to the main buffer
        ' edx = location    current location pointer
        ' --------------------------------------------------------------
      
          PREFIX "!"
      
          push ebx
          push esi
          push edi
      
          mov ebx, ecx                        ' load the string address
          sub ebx, 4                          ' sub 4 to get stored string length
          mov ebx, [ebx]                      ' write it back to ebx
      
          mov esi, eax                        ' pstring
          mov ecx, ecx                        ' buffer
          add esi, edx                        ' location
          mov edi, edx                        ' update return value variable
          or eax, -1                          ' set eax to -1
          add ebx, 1                          ' correct ebx for following loop
      
        ' -----------
        ' unroll by 2
        ' -----------
        lbl0:
          add eax, 1
          movzx edx, BYTE PTR [ecx+eax]
          mov [esi+eax], dl
          sub ebx, 1
          jz lbl1                             ' exit on written terminator
      
          add eax, 1
          movzx edx, BYTE PTR [ecx+eax]
          mov [esi+eax], dl
          sub ebx, 1
          jnz lbl0                            ' exit on written terminator
      
        lbl1:
          add eax, edi                        ' location
      
          pop edi
          pop esi
          pop ebx
      
          ret
      
          END PREFIX
      
       END FASTPROC
      
      ' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
      Bernard Ertl
      InterPlan Systems

      Comment


      • #23
        Hi Bern,
        replace both jbe with jb.

        ! jbe 'Jump if below or equal
        ! jb 'Jump if below

        Comment


        • #24
          Bern,

          Try this, I changed a few bits of your code, added a manifest and tested the file with jotti with this result. Do not modify the code on Pierre's suggestion, I have no doubt that Pierre could write his own but he certainly did not write this one.
          Code:
          Lavasoft Ad-Aware
          
          10 Jan 2018
          
          Found nothing
          
          Avast! Antivirus
          
          9 Jan 2018
          
          Found nothing
          
          AVG
          
          9 Jan 2018
          
          Found nothing
          BitDefender Antivirus
          
          10 Jan 2018
          
          Found nothing
          
          ClamAV
          
          9 Jan 2018
          
          Found nothing
          
          Dr. Web
          
          10 Jan 2018
          
          Found nothing
          MicroWorld eScan
          
          10 Jan 2018
          
          Found nothing
          
          ESET
          
          9 Jan 2018
          
          Found nothing
          
          Fortinet
          
          10 Jan 2018
          
          Found nothing
          F-PROT Antivirus
          
          10 Jan 2018
          
          Found nothing
          
          F-Secure Anti-Virus
          
          10 Jan 2018
          
          Found nothing
          
          G DATA
          
          10 Jan 2018
          
          Found nothing
          Ikarus
          
          9 Jan 2018
          
          Found nothing
          
          K7 AV
          
          9 Jan 2018
          
          Found nothing
          
          Kaspersky Anti-Virus
          
          9 Jan 2018
          
          Found nothing
          Sophos
          
          9 Jan 2018
          
          Found nothing
          
          Trend Micro Antivirus
          
          8 Jan 2018
          
          Found nothing
          
          VBA32
          
          9 Jan 2018
          
          Found nothing
          Attached Files
          hutch at movsd dot com
          The MASM Forum

          www.masm32.com

          Comment


          • #25
            Steve, the bern.zip code compiles and runs without error (and with AVG active), but I can't see where you changed any of the code aside from the the addition of the resource/manifest. Was the resource/manifest really the solution to getting the code to work without error? If so, why/how? I would like to be able to put the mcat$()/fcappend() code into a .inc file and incorporate it into other applications, but only if I'm sure that it's not going to cause GPF/crashes and right now I'm a bit puzzled as to why the code was having issues without the resource/manifest (or what I'd have to do for any other applications I want to add mcat$() to).
            Bernard Ertl
            InterPlan Systems

            Comment


            • #26
              Hi Bern,

              The manifest solves the problem with junky AV scanners, if you add a manifest AND version control block then most AV scanners will not flag it as "suspicious" unless there is an actual infection in the file.

              These are the changes I remember.
              Code:
              1. DIM varr(38) AS STRING   ' this is how I allocated the array in the example and what the algo was designed to use.
              2. varr(33) = CHR$( 255, etc .... only this line. I don't use this notation so I was not familiar with it -> varr(36) += CHR$(
              3. rslt$ = mcat$(38,varr()) ' made sure the count matched the DIM statement.
              4. erase varr()  ' personal habit of handling arrays within a single sub/function
              There should be no problem putting the code in another .BAS or .INC file and including it in you own source code, its probably the best way to do it.

              If you have a simple app you can test it with you can make sure the embedded chr$(0) are handled properly.

              Make sure you use the simple form of DIM with a single number and make sure the mcat$ call has the same number. It is generally the case with asm code that you use the simplest form available with what you pass to it and this is part of how it keeps sub/function overhead down when you are chasing performance.

              Let me know if there are any problems with it and I hope it gives you some performance improvement.
              hutch at movsd dot com
              The MASM Forum

              www.masm32.com

              Comment


              • #27
                OK. I tested a bit and the issue with my GPF code was the array dimensioning.

                DIM varr( 0 to 37) AS STRING --> GPF

                DIM varr( 0 to 38) AS STRING --> runs fine

                I'm a bit confused about that as when you call mcat$(), the first parameter is supposed to be a count of the number of elements that you want concatenated from the array, so when I call mcat$( 38, varr()), it should be concatenating array elements 0 through 37. I guess the array needs to be dimensioned at least one element larger than the number of elements you plan to concatenate?

                Edit: Yes, I see it now.
                Code:
                        pstr = LEN(varr(lcnt))
                    ! add esi, eax                      ' add each string length to esi
                    ! add lcnt, 1                       ' increment the loop counter
                    ! cmp lcnt, edi                     ' test lcnt against icnt
                     ! jbe lbl0                          ' jump back if below or equal
                It's checking the string length of the next array element before it checks if the next array element should be concatenated.

                Pierre's solution does fix the issue.
                Bernard Ertl
                InterPlan Systems

                Comment


                • #28
                  >Pierre's solution does fix the issue.
                  Yep, this was intended to overcome this over looping bug...

                  Comment


                  • #29
                    Pierre,

                    Feel free to code your own version of a JOIN$ alternative. We would hate to see you with egg on your face yet again after making another blunder.
                    hutch at movsd dot com
                    The MASM Forum

                    www.masm32.com

                    Comment


                    • #30
                      Hey Bern,
                      About your 04:12pm post, if speed is important then you could
                      save the call to "FASTPROC fcappend" and his "ret" by moving the code inside the main function.
                      Could also save a couple of PUSHs and a couple of POPs for esi and ebx.
                      Plus, eliminating the duplicate five line "Terminator exit" seems not to hurt.
                      Here is what I mean...

                      Pierre

                      Code:
                      #COMPILE EXE '#Win 9.07#
                      #DIM ALL
                      #INCLUDE "Win32Api.inc"
                      '_____________________________________________________________________________
                      
                      FUNCTION PBMAIN AS LONG
                       DIM sString(0 TO 9) AS STRING
                       LOCAL sConcatenate  AS STRING
                      
                       sString(00) = "Bonjour "
                       sString(01) = "Bern, " & $CRLF
                       sString(02) = "Do "
                       sString(03) = "You "
                       sString(04) = "think "
                       sString(05) = "that "
                       sString(06) = "this "
                       sString(07) = "could "
                       sString(08) = "help "
                       sString(09) = "?"
                      
                       sConcatenate = mcat$(10, sString())
                      
                       MessageBox(%HWND_DESKTOP, sConcatenate & $CRLF & $CRLF & "Lenght is" & STR$(LEN(sConcatenate)), "Concatenate", %MB_OK OR %MB_TOPMOST)
                      
                      END FUNCTION
                      '_____________________________________________________________________________
                      
                      FUNCTION mcat$(BYVAL StringCount AS DWORD, sString() AS STRING)
                       '-----------------------------------------------------------
                       ' StringCount is the number of strings to append to a buffer
                       ' sString() is the string array that contains the strings
                       '-----------------------------------------------------------
                       #REGISTER NONE
                      
                       LOCAL pCurrent AS DWORD            'Current location pointer
                       LOCAL index    AS DWORD            'Loop counter
                       LOCAL BuffLen  AS DWORD            'Buffer size variable
                       LOCAL pString  AS DWORD            'String pointer for append loop
                       LOCAL pBuff    AS DWORD            'Buffer pointer
                       LOCAL sBuff    AS STRING
                      
                       '--------------------------
                       ' Calculate the buffer size
                       '--------------------------
                       !mov index, 0                      'Set the loop counter to zero
                       !xor esi, esi                      'Zero esi
                       !mov edi, StringCount              'Load StringCount into register to reduce instruction count
                      
                       StringLenAdder:
                       pString = LEN(sString(index))
                       !add esi, eax                      'Add each string length to esi
                       !add index, 1                      'Increment the loop counter
                       !cmp index, edi                    'Test index against StringCount
                       !jb StringLenAdder                 'Jump back if below
                       '!jbe StringLenAdder               'Jump back if below or equal
                      
                       !mov BuffLen, esi                  'Store esi (combined string lengths) in BuffLen
                      
                       '------------------------------------------
                       ' Sequentially append string data to buffer
                       '------------------------------------------
                       sBuff = SPACE$(BuffLen)            'Allocate string space
                       pBuff = STRPTR(sBuff)              'Get its address
                       !mov pCurrent, 0                   'Zero the location counter
                       !mov index, 0                      'Set the loop counter to zero
                      
                       StringBuild:
                       pString = STRPTR(sString(index))   'String address of each array member
                      
                       !mov edx, pCurrent                 'Pass arguments in registers
                       !mov ecx, pString
                       !mov eax, pBuff
                      
                       ' --------------------------------------------------------------
                       '!push ebx
                       '!push esi
                       !push edi
                      
                       !mov ebx, ecx                      'Load the string address
                       !sub ebx, 4                        'Sub 4 to get stored string length
                       !mov ebx, [ebx]                    'Write it back to ebx
                      
                       !mov esi, eax                      'pStringing
                       !mov ecx, ecx                      'Buffer
                       !add esi, edx                      'Location
                       !mov edi, edx                      'Update return value variable
                       !or eax, -1                        'Set eax to -1
                       !add ebx, 1                        'Correct ebx for following loop
                      
                       Rool:
                       !add eax, 1
                       !movzx edx, BYTE PTR [ecx + eax]
                       !mov [esi + eax], dl
                       !sub ebx, 1
                       '!jz Done                          'Exit on written terminator
                       !jnz Rool
                      
                       '!add eax, 1
                       '!movzx edx, BYTE PTR [ecx+eax]
                       '!mov [esi+eax], dl
                       '!sub ebx, 1
                       '!jnz Rool                         'Exit on written terminator
                      
                       'Done:
                       !add eax, edi                      'Location
                      
                       !pop edi
                       '!pop esi
                       '!pop ebx
                      
                       ' --------------------------------------------------------------
                       !mov pCurrent, eax                 'Update pCurrent
                      
                       !add index, 1                      'Increment the loop counter
                       !cmp index, edi                    'Test index against StringCount
                       !jb StringBuild                    'Jump back if below
                       '!jbe StringBuild                  'Jump back if below or equal
                       ' --------------------------------------------------------------
                      
                       FUNCTION = sBuff                   'Return the combined string
                      
                      END FUNCTION
                      '_____________________________________________________________________________
                      '

                      Comment


                      • #31
                        Originally posted by Pierre Bellisle View Post
                        Hey Bern,
                        About your 04:12pm post,
                        The forum software displays the reader's local time. I don't see any post from Bern at 04:12pm

                        Please use post numbers when referring to an earlier post in a thread. I presume that you are referring to post #22 (which I see as being posted "10 Jan 2018, 07:12 AM").



                        --
                        [URL="http://www.camcopng.com"]CAMCo - Applications Development & ICT Consultancy[/URL][URL="http://www.hostingpng.com"]
                        PNG Domain Hosting[/URL]

                        Comment


                        • #32
                          CleanUp...
                          Last edited by Pierre Bellisle; 13 Jan 2018, 08:59 PM. Reason: Better things to do...

                          Comment


                          • #33
                            Originally posted by Pierre Bellisle View Post
                            I try to never use post number, they are no good when someone is using the ignore list.
                            Your post #22 is my post #11.
                            Still prefer time, Bern have only one post written at xx:12pm.
                            I'm quite sure he can deduct what I'm referring to...
                            Depends where he is. I only see a post from him at xx:12am

                            How about: #post768571 ( i.e. the way the link is embedded in a quote) ?
                            --
                            [URL="http://www.camcopng.com"]CAMCo - Applications Development & ICT Consultancy[/URL][URL="http://www.hostingpng.com"]
                            PNG Domain Hosting[/URL]

                            Comment


                            • #34
                              CleanUp...
                              Last edited by Pierre Bellisle; 13 Jan 2018, 08:59 PM. Reason: Better things to do...

                              Comment


                              • #35
                                Pierre,

                                Something you need to connect here, contributions made by members (I have only been here since 1997) for other members including the many friends I have here are not a competition or a venue of influence peddling. You got your nose out of joint some time ago because I posted a very simple piece of basic code for another member that was simply better thought out that what you had offered. I have occasionally seen you post a reasonable piece of assembler code but as you said some time ago, you are no Paul Dixon. Further, when you try to make comparisons between Paul and myself, it assumes that know as much about assembler coding as both Paul and myself together which is simply nonsense as you don't know as much as either Paul or myself.

                                Now as far as your attention to detail when analysing the piece of code that tried unsuccessfully to modify, you did not read how the array was dimensioned in the first place. You badly thought out modification was due to this sloppy analysis. The first version that suited the task I wanted to use it for worked perfectly and as Bern had a slightly different requirement with embedded nuls, it was no big deal to tweak it to perform the task that he had in mind and it worked perfectly as well.

                                Now if for some rediculous reason you want to compete with me, it won't be kiddie level basic, it will be at the closed source executable level against pure 64 bit Microsoft assembler that is so fast it will make your eyes water.

                                If alternatively you have something to contribute to other members, just do it.
                                hutch at movsd dot com
                                The MASM Forum

                                www.masm32.com

                                Comment


                                • #36
                                  Bern,
                                  Another one that goes almost the same road.
                                  Not ASM yet for pure speed, could be used as a template for experiment...

                                  Code:
                                  sConcatenate = Concatenate(StringCount, VARPTR(DynamicStringArray(0)))
                                  '_____________________________________________________________________________
                                  
                                  FUNCTION Concatenate(BYVAL StringCount AS DWORD, BYVAL pBstrArray AS DWORD POINTER) AS STRING
                                   LOCAL pLenArrayItem AS DWORD POINTER
                                   LOCAL pBstrArrayLen AS DWORD POINTER
                                   LOCAL pOut          AS DWORD
                                   LOCAL BytesNeeded   AS DWORD
                                   LOCAL index         AS DWORD
                                   LOCAL sOut          AS STRING
                                  
                                   'Compute needed string lenght
                                   pBstrArrayLen = pBstrArray                        'Preserve pBstrArray for later
                                   FOR index = 1 TO StringCount                      'For each array item
                                     IF @pBstrArrayLen THEN                          'Check for empty array item
                                       pLenArrayItem = @pBstrArrayLen - 4            'Get pointer to string lenght
                                       BytesNeeded = BytesNeeded + @pLenArrayItem    'Add it to BytesNeeded
                                     END IF
                                     pBstrArrayLen = pBstrArrayLen + 4               'Do next array item
                                   NEXT
                                  
                                   'Build output string
                                   sOut = NUL$(BytesNeeded)                          'Build space once to put the string data
                                   pOut = STRPTR(sOut)                               'Get the pointer
                                  
                                   'Fill output string 
                                   FOR index = 1 TO StringCount                      'For each array item
                                     IF @pBstrArray THEN                             'Check for empty array item
                                       pLenArrayItem = @pBstrArray - 4               'Get pointer to string lenght
                                       CopyMemory(pOut, @pBstrArray, @pLenArrayItem) 'Copy string from array to the output string
                                       pOut = pOut + @pLenArrayItem                  'Move to right position in the output string
                                     END IF
                                     pBstrArray = pBstrArray + 4                     'Do next array item
                                   NEXT
                                   FUNCTION = sOut
                                  
                                  END FUNCTION
                                  '_____________________________________________________________________________
                                  '
                                  Last edited by Pierre Bellisle; 15 Jan 2018, 12:20 PM.

                                  Comment


                                  • #37
                                    Hey Bern,
                                    For the fun of it, here is an adaptation of my, let's say "@pointers", previous code to asm...
                                    Empty string or null character are treated.

                                    Code:
                                    #COMPILE EXE '#Win 9.07#
                                    #DIM ALL
                                    #INCLUDE "Win32Api.inc"
                                    '_____________________________________________________________________________
                                    
                                    FUNCTION PBMAIN AS LONG
                                     DIM sString(0 TO 4) AS STRING
                                     LOCAL sConcatenate  AS STRING
                                    
                                     sString(00) = "Bonjour "
                                     sString(01) = "Bern" & NUL$(3) & $CRLF
                                     sString(02) = "Coding is fun"
                                     sString(03) = ""
                                     sString(04) = "!"
                                    
                                     sConcatenate = ConcatenateAsm(5, VARPTR(sString(0)))
                                     REPLACE $NUL WITH "." IN sConcatenate
                                     MessageBox(%HWND_DESKTOP, sConcatenate & $CRLF & $CRLF & _
                                                "Lenght is" & STR$(LEN(sConcatenate)) & $CRLF & _
                                                "(Chr$(0) are replaced with dots)", "Concatenate", %MB_OK OR %MB_TOPMOST)
                                    END FUNCTION
                                    '_____________________________________________________________________________
                                    
                                    FUNCTION ConcatenateAsm(BYVAL StringCount AS DWORD, BYVAL pBstrArray AS DWORD POINTER)AS STRING
                                     #REGISTER NONE
                                     LOCAL BytesNeeded AS DWORD
                                     LOCAL sOut        AS STRING
                                    
                                     'Set parameters
                                     !xor eax, eax            'Set eax string lenght to zero
                                     !mov ebx, StringCount    'Set ebx with StringCount
                                     !mov esi, pBstrArray     'BSTR pointer to StringArray(0)
                                    
                                     'Compute needed string lenght
                                     CharCountAdder:
                                     !mov ecx, [esi]          'Pointer to first char of StringArray(ebx)
                                     !jecxz BypassNullString  'If pointer is zero then bypass lenght addition
                                     !sub ecx, 4              'Pointer to string lenght of StringArray(ebx)
                                     !add eax, [ecx]          'Add lenght of StringArray(ebx)
                                     BypassNullString:
                                     !add esi, 4              'Pointer to first char of next StringArray(ebx)
                                     !dec ebx                 'Decrement remaining item count to do
                                     !jnz CharCountAdder      'Loop if ebx counter is not zero
                                     !mov BytesNeeded, eax    'Byte needed for the output string
                                    
                                     'Build output string
                                     sOut = NUL$(BytesNeeded) 'Build a BSTR space for the output string data
                                    
                                     'Fill output string
                                     !mov ebx, StringCount    'Set ebx with StringCount
                                     !mov esi, pBstrArray     'BSTR pointer to StringArray(0)
                                     !mov edi, sOut           'Pointer to sOut first character
                                     !cld                     'Clear direction flag (forward)
                                    
                                     OutStringFill:
                                     !mov ecx, [esi]          'Pointer to first char of StringArray(ebx)
                                     !jecxz BypassCopy        'If pointer is zero then bypass string copy
                                     !sub ecx, 4              'Pointer to string lenght of StringArray(ebx)
                                     !mov ecx, [ecx]          'Get string lenght via its pointer
                                     !mov edx, esi            'Backup esi to permit movsb
                                     !mov esi, [esi]          'Address of first char from BSTR
                                     !rep movsb               'Repeat copy ecx bytes from esi to edi.
                                     !mov esi, edx            'Restore esi after movsb is done
                                     BypassCopy:
                                     !add edi, ecx            'Add string lenght to the output string pointer
                                     !add esi, 4              'Pointer to first char of the next StringArray(ebx)
                                     !dec ebx                 'Decrement remaining item count to do
                                     !jnz OutStringFill       'Loop if CharCountAdder is not zero
                                    
                                     FUNCTION = sOut
                                    
                                    END FUNCTION
                                    '_____________________________________________________________________________
                                    '

                                    Comment


                                    • #38
                                      I tried benchmarking Steve's mcat$(), Pierre's ConcatenateAsm() and JOIN$() using a sample of my real data and mcat$() and ConcatenateAsm were pretty comparable in performance, but JOIN$ actually worked almost twice as fast!

                                      When you have the final line in either assembly function as:

                                      FUNCTION = buff$ / sOut

                                      Does PB actually do a string copy of the result string? If so, that could be significant if the result string is large.

                                      Code:
                                          #COMPILE EXE "bmark.exe"
                                          #INCLUDE "win32api.inc"
                                      
                                       FUNCTION PBMAIN AS LONG
                                      
                                          DIM varr( 0 TO 37) AS STRING
                                      
                                          varr(0) = CHR$( 1, 48)
                                      
                                          varr(0) = CHR$( 1, 50)
                                          varr(1) = CHR$( 7, 66, 101, 114, 110, 97, 114, 100)
                                          varr(2) = CHR$( 32, 68, 52, 49, 68, 56, 67, 68, 57, 56, 70, 48, 48, 66, 50, 48, 52, 69, 57, 56, 48, 48, 57, 57, 56, 69, 67, 70, 56, 52, 50, 55, 69)
                                          varr(3) = CHR$( 10, 49, 48, 55, 51, 55, 52, 50, 51, 48, 50)
                                          varr(4) = CHR$( 254)
                                          varr(5) = CHR$( 2, 55, 54)
                                          varr(6) = CHR$( 5, 54, 53, 50, 56, 48)
                                          varr(7) = CHR$( 8, 49, 54, 55, 49, 49, 54, 56, 48)
                                          varr(8) = CHR$( 5, 54, 53, 53, 51, 53)
                                          varr(9) = CHR$( 3, 50, 53, 53)
                                          varr(10) = CHR$( 7, 56, 51, 56, 56, 55, 51, 54)
                                          varr(11) = CHR$( 8, 49, 50, 54, 51, 50, 50, 53, 54)
                                          varr(12) = CHR$( 8, 49, 54, 55, 55, 54, 57, 54, 48)
                                          varr(13) = CHR$( 1, 48)
                                          varr(14) = CHR$( 8, 49, 54, 55, 49, 49, 57, 51, 53)
                                          varr(15) = CHR$( 1, 48)
                                          varr(16) = CHR$( 3, 49, 54, 54)
                                          varr(17) = CHR$( 3, 53, 52, 56)
                                          varr(18) = CHR$( 3, 54, 55, 56)
                                          varr(19) = CHR$( 3, 51, 52, 57)
                                          varr(20) = CHR$( 2, 51, 54)
                                          varr(21) = CHR$( 2, 53, 48)
                                          varr(22) = CHR$( 4, 49, 48, 49, 52)
                                          varr(23) = CHR$( 4, 49, 55, 56, 53)
                                          varr(24) = CHR$( 2, 52, 50)
                                          varr(25) = CHR$( 3, 53, 50, 53)
                                          varr(26) = CHR$( 3, 57, 57, 51)
                                          varr(27) = CHR$( 3, 53, 56, 57)
                                          varr(28) = CHR$( 70, 49, 52, 46, 49, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 55, 8, 49, 52, 46, 49, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 55, 8, 49, 50, 46, 48, 52, 49, 54, 54, 54, 54, 54, 54, 54, 54, 54, 55, 8, 49, 52, _
                                                                  8, 49, 52, 46, 49, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 55)
                                          varr(29) = CHR$( 4, 49, 52, 49, 52)
                                          varr(30) = CHR$( 3, 54, 53, 52)
                                          varr(31) = CHR$( 148, 80, 114, 111, 106, 101, 99, 116, 9, 49, 9, 45, 49, 9, 49, 54, 46, 50, 53, 8, 78, 111, 116, 101, 115, 9, 50, 9, 45, 49, 9, 51, 48, 46, 56, 55, 53, 8, 79, 119, 110, 101, 114, 9, 51, 9, 45, 49, 9, 49, 51, 46, 56, _
                                               55, 53, 8, 77, 97, 110, 97, 103, 101, 114, 9, 52, 9, 45, 49, 9, 57, 46, 50, 53, 8, 80, 108, 97, 110, 110, 101, 114, 9, 53, 9, 45, 49, 9, 57, 46, 50, 53, 8, 9, 54, 9, 48, 9, 48, 8, 9, 55, 9, 48, 9, 48, 8, 9, 56, 9, 48, 9, 48, 8, 9, _
                                               57, 9, 48, 9, 48, 8, 9, 49, 48, 9, 48, 9, 48, 8, 9, 49, 49, 9, 48, 9, 48, 8, 65, 99, 116, 105, 118, 101, 9, 49, 50, 9, 48, 9, 48)
                                          varr(32) = CHR$( 213, 73, 68, 9, 49, 9, 45, 49, 9, 49, 51, 46, 49, 50, 53, 8, 82, 101, 102, 101, 114, 101, 110, 99, 101, 32, 84, 97, 103, 9, 50, 9, 45, 49, 9, 49, 53, 46, 50, 53, 8, 74, 111, 98, 32, 80, 108, 97, 110, 32, 68, 101, _
                                              115, 99, 114, 105, 112, 116, 105, 111, 110, 9, 51, 9, 45, 49, 9, 51, 57, 46, 53, 8, 77, 97, 110, 104, 111, 117, 114, 115, 9, 52, 9, 45, 49, 9, 56, 8, 68, 105, 115, 112, 108, 97, 121, 32, 79, 114, 100, 101, 114, 9, 53, 9, _
                                              45, 49, 9, 49, 51, 46, 51, 55, 53, 8, 65, 114, 99, 104, 105, 118, 101, 100, 9, 54, 9, 45, 49, 9, 56, 8, 65, 46, 70, 46, 69, 46, 9, 55, 9, 48, 9, 48, 8, 69, 113, 117, 105, 112, 109, 101, 110, 116, 9, 56, 9, 45, 49, 9, _
                                              50, 48, 46, 49, 50, 53, 8, 74, 111, 98, 32, 80, 108, 97, 110, 32, 76, 101, 118, 101, 108, 32, 83, 117, 112, 101, 114, 118, 105, 115, 111, 114, 115, 9, 57, 9, 48, 9, 48, 8, 85, 110, 105, 116, 47, 65, 114, 101, 97, 9, 49, 48, 9, 48, 9, 48)
                                          varr(33) = CHR$( 255, 202, 2, 0, 0, 83, 117, 109, 109, 97, 114, 121, 32, 84, 97, 115, 107, 32, 79, 112, 101, 110, 47, 67, 108, 111, 115, 101, 9, 49, 9, 45, 49, 9, 50, 46, 56, 55, 53, 8, 73, 68, 9, 50, 9, 45, 49, 9, 49, 48, 46, 49) + _
                                              CHR$(50,53,8, 84, 97, 115, 107, 32, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 9, 51, 9, 45, 49, 9, 53, 55, 46, 54, 50, 53, 8, 82, 101, 109, 97, 105, 110, 105, 110, 103, 32, 68, 117, 114, 97, 116, 105, 111, 110, 9, 52, 9) + _
                                              CHR$(48, 9, 48, 8, 79, 114, 105,103,105, 110, 97, 108, 32, 68, 117, 114, 97, 116, 105, 111, 110, 9, 53, 9, 48, 9, 48, 8, 69, 115, 116, 105, 109, 97, 116, 101, 100, 32, 68, 117, 114, 97, 116, 105, 111, 110, 9, 54, 9, 45, 49) + _
                                              CHR$(9, 56, 8, 37, 32, 67, 111, 109, 112, 108, 101, 116, 101, 9,55,9, 48, 9, 48, 8, 80, 114, 101, 100, 101, 99, 101, 115, 115, 111) + _
                                              CHR$(114, 115, 9, 56, 9, 48, 9, 48, 8, 83, 117, 99, 99, 101, 115, 115, 111, 114, 115, 9, 57, 9, 48, 9, 48, 8, 82, 101, 115, 111) + _
                                              CHR$(117, 114, 99, 101, 115, 9, 49, 48, 9, 45, 49, 9, 49, 52, 46,49,50, 53, 8, 84, 121, 112, 101, 9, 49, 49, 9, 45, 49, 9, 56, 8) + _
                                              CHR$(83, 99, 111, 112, 101, 9, 49, 50, 9, 45, 49, 9, 56, 46, 49, 50, 53, 8, 67, 97, 108, 101, 110, 100, 97, 114, 9, 49, 51, 9, 45, 49, 9, 56) + _
                                              CHR$(8, 83, 99, 101, 110, 97, 114, 105, 111, 9, 49, 52,9,45, 49, 9, 48, 8, 79, 112, 116, 105, 109, 105, 115, 116, 105, 99, 32) + _
                                              CHR$(68, 117, 114, 97, 116, 105, 111, 110, 9, 49, 53, 9, 45, 49, 9, 56, 8, 80, 101, 115, 115, 105, 109, 105, 115, 116, 105, 99, 32, 68, 117, 114, 97, 116, 105, 111, 110, 9, 49, 54, 9) + _
                                              CHR$(45,49,9, 56, 8, 90, 111, 110, 101, 115, 9, 49, 55, 9, 45, 49, 9, 56, 8, 69, 120, 99, 101, 112, 116, 105, 111, 110, 115, 9, 49, 56, 9, 48, 9, 48, 8, 85, 110, 105, 110, 116, 101, 114, 114, 117, 112)
                                          varr(33) += CHR$(116, 97, 98, 108, 101, 9, 49, 57, 9, 48, 9, 48, 8, 77) + _
                                              CHR$( 101,116,104, 111, 100, 9, 50, 48, 9, 48, 9, 48, 8, 78, 111, 110, 45, 67, 114, 105, 116, 105, 99, 97, 108, 32, 87, 111, 114, 107, 9, 50, 49, 9, 45, 49, 9, 56, 8, 68, 105, 115, 112, 108, 97, 121, 32) + _
                                              CHR$(79, 114, 100, 101, 114, 9, 50, 50, 9, 45, 49, 9, 56, 8) + _
                                              CHR$(69,97,114, 108, 121, 32, 83, 116, 97, 114, 116, 9, 50, 51, 9, 48, 9, 48, 8, 69, 97, 114, 108, 121, 32, 70, 105, 110, 105, 115, 104, 9, 50, 52, 9, 48, 9, 48, 8, 76, 97, 116, 101, 32, 83, 116, 97, 114) + _
                                              CHR$(116, 9, 50, 53, 9, 48, 9, 48, 8, 76, 97, 116, 101) + _
                                              CHR$(32,70,105, 110, 105, 115, 104, 9, 50, 54, 9, 48, 9, 48, 8, 70, 114, 101, 101, 32, 70, 108, 111, 97, 116, 9, 50, 55, 9, 48, 9, 48, 8, 84, 111, 116, 97, 108, 32, 70, 108, 111, 97, 116, 9, 50, 56, 9, 48) + _
                                              CHR$(9, 48, 8, 68, 114, 97, 103, 9, 50, 57, 9, 48, 9, 48) + _
                                              CHR$(8,80,117, 108, 108, 9, 51, 48, 9, 48, 9, 48, 8, 88, 32, 80, 117, 108, 108, 9, 51, 49, 9, 48, 9, 48, 8, 80, 114, 105, 111, 114, 105, 116, 105, 101, 115, 9, 51, 50, 9, 45, 49, 9, 56, 8, 80, 114, 111, 99) + _
                                              CHR$(101, 100, 117, 114, 101, 115, 9, 51, 51, 9, 45) + _
                                              CHR$(49,9,57, 46, 50, 53, 8, 84, 97, 115, 107, 32, 76, 101, 118, 101, 108, 32, 83, 117, 112, 101, 114, 118, 105, 115, 111, 114, 115, 9, 51, 52, 9, 45, 49, 9, 49, 51, 46, 53, 8, 77, 105, 108, 101, 115, 116) + _
                                              CHR$(111, 110, 101, 115, 9, 51, 53, 9, 45, 49, 9, 50, 53)
                                          varr(34) = CHR$( 255, 1, 1, 0, 0, 81, 117, 97, 110, 116, 105, 116, 121, 9, 49, 9, 45, 49, 9, 55, 46, 51, 55, 53, 8, 82, 101, 115, 111, 117, 114, 99, 101, 9, 50, 9, 45, 49, 9, 56, 46, 50, 53, 8, 82, 101, 115, 111, 117, 114, 99, 101) + _
                                              CHR$(32,68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 9, 51, 9, 45, 49, 9, 49, 51, 46, 50, 53, 8, 67, 111, 110, 116, 114, 97, 99, 116, 111, 114, 9, 52, 9, 45, 49, 9, 56, 46, 54) + _
                                              CHR$(50, 53, 8, 67, 111, 110, 116, 114, 97, 99, 116, 111, 114, 32, 68, 101) + _
                                              CHR$(115,99, 114, 105, 112, 116, 105, 111, 110, 9, 53, 9, 45, 49, 9, 49, 48, 8, 76) + _
                                              CHR$(83, 32, 67, 111, 110, 116, 114, 97, 99, 116, 9, 54, 9, 45, 49, 9, 57, 46, 53, 8, 76, 83, 32, 67, 111, 110, 116, 114, 97, 99, 116, 32, 68, 101, 115, 99, 114, 105, 112, 116) + _
                                              CHR$(105,111, 110, 9, 55, 9, 45, 49, 9, 49, 54, 46, 50, 53, 8, 82, 97, 116, 101) + _
                                              CHR$(32, 79, 118, 101, 114, 114, 105, 100, 101, 9, 56, 9, 45, 49, 9, 49, 48, 8, 70, 105, 120, 101, 100, 32, 67, 111, 115, 116, 32, 79, 118, 101, 114, 114, 105, 100, 101, 9, 57, 9, 45) + _
                                              CHR$(49,9, 49, 52, 46, 49, 50, 53, 8, 79, 118, 101, 114, 114, 105, 100, 101, 32) + _
                                              CHR$(66, 97, 115, 105, 115, 9, 49, 48, 9, 45, 49, 9, 49, 48)
                                          varr(35) = CHR$( 255, 183, 2, 0, 0, 83, 117, 109, 109, 97, 114, 121, 32, 84, 97, 115, 107, 32, 79, 112, 101, 110, 47, 67, 108, 111, 115, 101, 9, 49, 9, 48, 9, 48, 8, 73, 68, 9, 50, 9, 48, 9, 48, 8, 84, 97, 115, 107, 32, 68, 101) + _
                                              CHR$(115,99,114, 105, 112, 116, 105, 111, 110, 9, 51, 9, 45, 49, 9, 53, 48, 46, 53, 8, 82, 101, 109, 97) + _
                                              CHR$(105, 110, 105, 110, 103, 32, 68, 117, 114, 97, 116, 105, 111, 110, 9, 52, 9, 45, 49, 9, 57, 46, 54, 50, 53, 8, 79, 114, 105, 103, 105, 110, 97, 108, 32) + _
                                              CHR$(68,117,114, 97, 116, 105, 111, 110, 9, 53, 9, 48, 9, 48, 8, 69, 115, 116, 105, 109, 97, 116, 101) + _
                                              CHR$(100, 32, 68, 117, 114, 97, 116, 105, 111, 110, 9, 54, 9, 48, 9, 48, 8, 37, 32, 67, 111, 109, 112, 108, 101, 116, 101, 9, 55, 9, 45, 49, 9, 56, 46, 50, 53) + _
                                              CHR$(8,80,114, 101, 100, 101, 99, 101, 115, 115, 111, 114, 115, 9, 56, 9, 48, 9, 48, 8, 83, 117, 99) + _
                                              CHR$(99, 101, 115, 115, 111, 114, 115, 9, 57, 9, 48, 9, 48, 8, 82, 101, 115, 111, 117, 114, 99, 101, 115, 9, 49, 48, 9, 45, 49, 9, 49, 52, 46, 49, 50, 53, 8, 84) + _
                                              CHR$(121,112,101, 9, 49, 49, 9, 45, 49, 9, 56, 8, 83, 99, 111, 112, 101, 9, 49, 50, 9, 45, 49, 9, 56) + _
                                              CHR$(46, 49, 50, 53, 8, 67, 97, 108, 101, 110, 100, 97, 114, 9, 49, 51, 9, 45, 49, 9, 56, 8, 83, 99, 101, 110, 97, 114, 105, 111, 9, 49, 52, 9, 48, 9, 48, 8, 79) + _
                                              CHR$(112,116,105, 109, 105, 115, 116, 105, 99, 32, 68, 117, 114, 97, 116, 105, 111, 110, 9, 49, 53, 9) + _
                                              CHR$(48, 9, 48, 8, 80, 101, 115, 115, 105, 109, 105, 115, 116, 105, 99, 32, 68, 117, 114, 97, 116, 105, 111, 110, 9, 49, 54, 9, 48, 9, 48, 8, 90, 111, 110) + _
                                              CHR$(101,115,9, 49, 55, 9, 48, 9, 48, 8, 69, 120, 99, 101, 112, 116, 105, 111, 110, 115, 9, 49, 56, 9) + _
                                              CHR$(48, 9, 48, 8, 85, 110, 105, 110, 116, 101, 114, 114, 117, 112, 116, 97, 98, 108, 101, 9, 49, 57, 9, 48, 9, 48, 8, 77, 101, 116, 104, 111, 100, 9, 50, 48) + _
                                              CHR$(9,48,9, 48, 8, 78, 111, 110, 45, 67, 114, 105, 116, 105, 99, 97, 108, 32, 87, 111, 114, 107, 9, 50) + _
                                              CHR$(49, 9, 45, 49, 9, 56, 8, 68, 105, 115, 112, 108, 97, 121, 32, 79, 114, 100, 101, 114, 9, 50, 50, 9, 45, 49, 9, 56, 8, 69, 97, 114, 108, 121, 32, 83, 116) + _
                                              CHR$(97,114,116, 9, 50, 51, 9, 48, 9, 48, 8, 69, 97, 114, 108, 121, 32, 70, 105, 110, 105, 115, 104, 9) + _
                                              CHR$(50, 52, 9, 48, 9, 48, 8, 76, 97, 116, 101, 32, 83, 116, 97, 114, 116, 9, 50, 53, 9, 48, 9, 48, 8, 76, 97, 116, 101, 32, 70, 105, 110, 105, 115, 104, 9) + _
                                              CHR$(50,54,9, 48, 9, 48, 8, 70, 114, 101, 101, 32, 70, 108, 111, 97, 116, 9, 50, 55, 9, 48, 9, 48, 8, 84) + _
                                              CHR$(111, 116, 97, 108, 32, 70, 108, 111, 97, 116, 9, 50, 56, 9, 48, 9, 48, 8, 68, 114, 97, 103, 9, 50, 57, 9, 48, 9, 48, 8, 80, 117, 108, 108, 9, 51, 48, 9) + _
                                              CHR$(48,9,48, 8, 88, 32, 80, 117, 108, 108, 9, 51, 49, 9, 48, 9, 48, 8, 80, 114, 105, 111, 114, 105, 116)
                                          varr(35) += CHR$(105, 101, 115, 9, 51, 50, 9, 45, 49, 9, 56, 8, 80, 114, 111, 99, 101, 100, 117, 114, 101, 115, 9, 51, 51, 9, 48, 9, 48, 8, 84, 97, 115, 107, 32, 76) + _
                                              CHR$(101,118,101, 108, 32, 83, 117, 112, 101, 114, 118, 105, 115, 111, 114, 115, 9, 51, 52, 9, 48, 9, 48) + _
                                              CHR$(8, 77, 105, 108, 101, 115, 116, 111, 110, 101, 115, 9, 51, 53, 9, 48, 9, 48)
                                          varr(36) = CHR$( 255, 145, 1, 0, 0, 80, 114, 101, 100, 101, 99, 101, 115, 115, 111, 114, 9, 49, 9, 45, 49, 9, 57, 46, 56, 55, 53, 8, 83, 117, 99, 99, 101, 115, 115, 111, 114, 9, 50, 9, 45, 49, 9, 56, 46, 55, 53, 8, 84, 121, 112) + _
                                              CHR$(101,9,51, 9, 45, 49, 9, 53, 46, 53, 8, 68, 114, 105, 118, 105, 110, 103, 9, 52, 9, 45, 49, 9, 54, 46, 54, 50) + _
                                              CHR$(53, 8, 67, 97, 108, 101, 110, 100, 97, 114, 9, 53, 9, 45, 49, 9, 55, 46, 55, 53, 8, 83, 99, 101, 110, 97, 114, 105, 111, 9, 54, 9, 48, 9, 48) + _
                                              CHR$(8,68,97, 116, 101, 32, 67, 111, 110, 115, 116, 114, 97, 105, 110, 116, 9, 55, 9, 45, 49, 9, 49, 48, 8, 67) + _
                                              CHR$(111, 110, 115, 116, 114, 97, 105, 110, 116, 32, 84, 121, 112, 101, 9, 56, 9, 45, 49, 9, 49, 48, 8, 76, 101, 97, 100, 47, 76, 97, 103, 9, 57, 9) + _
                                              CHR$(45,49,9, 56, 46, 51, 55, 53, 8, 76, 101, 97, 100, 47, 76, 97, 103, 32, 66, 97, 115, 105, 115, 9, 49, 48, 9) + _
                                              CHR$(45, 49, 9, 49, 50, 46, 49, 50, 53, 8, 82, 101, 109, 97, 105, 110, 105, 110, 103, 32, 68, 117, 114, 97, 116, 105, 111, 110, 9, 49, 49, 9, 45, 49) + _
                                              CHR$(9,49,48, 8, 70, 105, 114, 115, 116, 32, 116, 111, 32, 67, 111, 109, 112, 108, 101, 116, 101, 32, 71, 114) + _
                                              CHR$(111, 117, 112, 9, 49, 50, 9, 45, 49, 9, 49, 48, 8, 69, 97, 114, 108, 121, 32, 83, 116, 97, 114, 116, 9, 49, 51, 9, 45, 49, 9, 49, 51, 46, 53, 8) + _
                                              CHR$(69,97,114, 108, 121, 32, 70, 105, 110, 105, 115, 104, 9, 49, 52, 9, 45, 49, 9, 49, 51, 46, 53, 8, 76, 97, 116) + _
                                              CHR$(101, 32, 83, 116, 97, 114, 116, 9, 49, 53, 9, 45, 49, 9, 49, 53, 8, 76, 97, 116, 101, 32, 70, 105, 110, 105, 115, 104, 9, 49, 54, 9, 45, 49) + _
                                              CHR$(9,49,53, 8, 70, 114, 101, 101, 32, 70, 108, 111, 97, 116, 9, 49, 55, 9, 45, 49, 9, 56, 46, 51, 55, 53, 8, 84) + _
                                              CHR$(111, 116, 97, 108, 32, 70, 108, 111, 97, 116, 9, 49, 56, 9, 45, 49, 9, 57, 46, 54, 50, 53)
                                          varr(37) = CHR$( 114, 78, 97, 109, 101, 9, 49, 9, 45, 49, 9, 50, 57, 46, 54, 50, 53, 8, 86, 101, 114, 115, 105, 111, 110, 9, 50, 9, 45, 49, 9, 56, 46, 50, 53, 8, 78, 111, 116, 101, 115, 9, 51, 9, 45, 49, 9, 53, 48, 46, 55, 53, 8,_
                                      67,97, 116, 101, 103, 111, 114, 121, 9, 52, 9, 45, 49, 9, 57, 46, 54, 50, 53, 8, 87, 104, 101, 110, 32, 84, 111, 32, 85, 115, 101, 9, 53, 9, 45, 49, 9, 50, 49, 46, 51, 55, 53, 8, 65, 117, 100, 105, 101, 110, 99, 101, 9, 54, 9, 45, 49, 9, 49, 56, 46, 53)
                                      
                                      
                                          LOCAL lcnt AS DWORD
                                          LOCAL tcnt AS DWORD
                                          LOCAL tcnt2 AS DWORD
                                          LOCAL tcnt3 AS DWORD
                                      
                                      
                                          lcnt = 1000000
                                      
                                          tcnt = GetTickCount()
                                      
                                        lbl0:
                                          rslt$ = mcat$(38,varr())
                                          ! sub lcnt, 1
                                          ! jnz lbl0
                                      
                                          tcnt = GetTickCount - tcnt
                                      
                                      
                                        ' -------------------------------------
                                      
                                          lcnt = 1000000
                                      
                                          tcnt2 = GetTickCount()
                                      
                                        lbl1:
                                          rslt2$ = JOIN$(varr(),"")
                                          ! sub lcnt, 1
                                          ! jnz lbl1
                                      
                                          tcnt2 = GetTickCount - tcnt2
                                      
                                      
                                        ' -------------------------------------
                                      
                                          lcnt = 1000000
                                      
                                          tcnt3 = GetTickCount()
                                      
                                        lbl2:
                                          rslt3$ = ConcatenateAsm(38, VARPTR( varr(0)))
                                          ! sub lcnt, 1
                                          ! jnz lbl2
                                      
                                          tcnt3 = GetTickCount - tcnt3
                                      
                                      
                                        ' -------------------------------------
                                      
                                          ERASE varr()                        ' delete the array
                                      
                                          MSGBOX "mcat$ = "+FORMAT$(tcnt)+" ms" + $CRLF + _
                                                 "join$ = "+FORMAT$(tcnt2)+" ms" + $CRLF + _
                                                 "Concat$ = "+FORMAT$(tcnt3)+" ms" + $CRLF + _
                                              "rslt$ = " + FORMAT$( LEN( rslt$)) + " bytes." + $CRLF + _
                                              "rslt2$ = " + FORMAT$( LEN( rslt2$)) + " bytes." + $CRLF + _
                                              "rslt3$ = " + FORMAT$( LEN( rslt3$)) + " bytes." + $CRLF + _
                                              "(rslt$ == rslt2$) = " + FORMAT$( (rslt$ = rslt2$)) + $CRLF + _
                                              "(rslt2$ == rslt3$) = " + FORMAT$( (rslt3$ = rslt2$))
                                      
                                      
                                       END FUNCTION
                                      
                                      ' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
                                      
                                       FUNCTION mcat$(BYVAL icnt AS DWORD,varr() AS STRING)
                                        ' ----------------------------------------------------
                                        ' icnt is the number of strings to append to a buffer
                                        ' varr() is the string array that contains the strings
                                        ' ----------------------------------------------------
                                          #REGISTER NONE
                                      
                                          LOCAL cloc AS DWORD                 ' current location pointer
                                          LOCAL lcnt AS DWORD                 ' loop counter
                                          LOCAL totl AS DWORD                 ' buffer size variable
                                          LOCAL pstr AS DWORD                 ' string pointer for append loop
                                          LOCAL pbuf AS DWORD                 ' buffer pointer
                                      
                                        ' -------------------------
                                        ' calculate the buffer size
                                        ' -------------------------
                                          ! mov lcnt, 0                       ' set the loop counter to zero
                                          ! xor esi, esi                      ' zero esi
                                          ! mov edi, icnt                     ' load icnt into register to reduce instruction count
                                      
                                        lbl0:
                                          pstr = LEN(varr(lcnt))
                                          ! add esi, eax                      ' add each string length to esi
                                          ! add lcnt, 1                       ' increment the loop counter
                                          ! cmp lcnt, edi                     ' test lcnt against icnt
                                          ! jb lbl0                          ' jump back if below 'or equal
                                      
                                          ! mov totl, esi                     ' store esi (combined string lengths) in totl
                                        ' -------------------------
                                      
                                        ' -----------------------------------------
                                        ' sequentially append string data to buffer
                                        ' -----------------------------------------
                                          buff$ = SPACE$(totl)                ' allocate string space
                                          pbuf = STRPTR(buff$)                ' get its address
                                          ! mov cloc, 0                       ' zero the location counter
                                          ! mov lcnt, 0                       ' set the loop counter to zero
                                      
                                        lbl1:
                                          pstr = STRPTR(varr(lcnt))           ' string address of each array member
                                      
                                          ! mov edx, cloc                     ' pass arguments in registers
                                          ! mov ecx, pstr
                                          ! mov eax, pbuf
                                          ! call fcappend                     ' append each string
                                          ! mov cloc, eax                     ' update cloc
                                      
                                          ! add lcnt, 1                       ' increment the loop counter
                                          ! cmp lcnt, edi                     ' test lcnt against icnt
                                          ! jb lbl1                          ' jump back if below or equal
                                        ' -----------------------------------------
                                      
                                          FUNCTION = buff$                    ' return the combined string
                                      
                                       END FUNCTION
                                      
                                      ' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
                                      
                                       FASTPROC fcappend
                                      
                                        ' --------------------------------------------------------------
                                        ' FASTCALL emulation
                                        ' pass 3 arguments in registers to reduce call overhead
                                      
                                        ' eax = pstring     the main buffer to append extra data to.
                                        ' ecx = buffer      the byte data to append to the main buffer
                                        ' edx = location    current location pointer
                                        ' --------------------------------------------------------------
                                      
                                          PREFIX "!"
                                      
                                          push ebx
                                          push esi
                                          push edi
                                      
                                          mov ebx, ecx                        ' load the string address
                                          sub ebx, 4                          ' sub 4 to get stored string length
                                          mov ebx, [ebx]                      ' write it back to ebx
                                      
                                          mov esi, eax                        ' pstring
                                          mov ecx, ecx                        ' buffer
                                          add esi, edx                        ' location
                                          mov edi, edx                        ' update return value variable
                                          or eax, -1                          ' set eax to -1
                                          add ebx, 1                          ' correct ebx for following loop
                                      
                                        ' -----------
                                        ' unroll by 2
                                        ' -----------
                                        lbl0:
                                          add eax, 1
                                          movzx edx, BYTE PTR [ecx+eax]
                                          mov [esi+eax], dl
                                          sub ebx, 1
                                          jz lbl1                             ' exit on written terminator
                                      
                                          add eax, 1
                                          movzx edx, BYTE PTR [ecx+eax]
                                          mov [esi+eax], dl
                                          sub ebx, 1
                                          jnz lbl0                            ' exit on written terminator
                                      
                                        lbl1:
                                          add eax, edi                        ' location
                                      
                                          pop edi
                                          pop esi
                                          pop ebx
                                      
                                          ret
                                      
                                          END PREFIX
                                      
                                       END FASTPROC
                                      
                                      ' ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
                                      
                                      FUNCTION ConcatenateAsm(BYVAL StringCount AS DWORD, BYVAL pBstrArray AS DWORD POINTER)AS STRING
                                       #REGISTER NONE
                                       LOCAL BytesNeeded AS DWORD
                                       LOCAL sOut        AS STRING
                                      
                                       'Set parameters
                                       !xor eax, eax            'Set eax string lenght to zero
                                       !mov ebx, StringCount    'Set ebx with StringCount
                                       !mov esi, pBstrArray     'BSTR pointer to StringArray(0)
                                      
                                       'Compute needed string lenght
                                       CharCountAdder:
                                       !mov ecx, [esi]          'Pointer to first char of StringArray(ebx)
                                       !jecxz BypassNullString  'If pointer is zero then bypass lenght addition
                                       !sub ecx, 4              'Pointer to string lenght of StringArray(ebx)
                                       !add eax, [ecx]          'Add lenght of StringArray(ebx)
                                       BypassNullString:
                                       !add esi, 4              'Pointer to first char of next StringArray(ebx)
                                       !dec ebx                 'Decrement remaining item count to do
                                       !jnz CharCountAdder      'Loop if ebx counter is not zero
                                       !mov BytesNeeded, eax    'Byte needed for the output string
                                      
                                       'Build output string
                                       sOut = NUL$(BytesNeeded) 'Build a BSTR space for the output string data
                                      
                                       'Fill output string
                                       !mov ebx, StringCount    'Set ebx with StringCount
                                       !mov esi, pBstrArray     'BSTR pointer to StringArray(0)
                                       !mov edi, sOut           'Pointer to sOut first character
                                       !cld                     'Clear direction flag (forward)
                                      
                                       OutStringFill:
                                       !mov ecx, [esi]          'Pointer to first char of StringArray(ebx)
                                       !jecxz BypassCopy        'If pointer is zero then bypass string copy
                                       !sub ecx, 4              'Pointer to string lenght of StringArray(ebx)
                                       !mov ecx, [ecx]          'Get string lenght via its pointer
                                       !mov edx, esi            'Backup esi to permit movsb
                                       !mov esi, [esi]          'Address of first char from BSTR
                                       !rep movsb               'Repeat copy ecx bytes from esi to edi.
                                       !mov esi, edx            'Restore esi after movsb is done
                                       BypassCopy:
                                       !add edi, ecx            'Add string lenght to the output string pointer
                                       !add esi, 4              'Pointer to first char of the next StringArray(ebx)
                                       !dec ebx                 'Decrement remaining item count to do
                                       !jnz OutStringFill       'Loop if CharCountAdder is not zero
                                      
                                       FUNCTION = sOut
                                      
                                      END FUNCTION
                                      Bernard Ertl
                                      InterPlan Systems

                                      Comment


                                      • #39
                                        I modified Pierre's ConcatenateAsm() function to a SUB with sOutPut as a byref parameter to build the output string directly into the output string and it did help the performance a bit, but JOIN$ still outperforms using the test data as posted just above. On my machine, my results look like:

                                        mcat$ = 6328 ms
                                        JOIN$ = 3281 ms
                                        Concat$ (FN) = ~6000 ms
                                        Concat$ (SUB) = 5156 ms
                                        Bernard Ertl
                                        InterPlan Systems

                                        Comment


                                        • #40
                                          Bern,

                                          Looks like JOIN$ is the best algo for your computer.

                                          This is what I get on this 3.3 gig Haswell E/EP
                                          Code:
                                          mcat$ = 1703 ms
                                          join$ = 1328 ms
                                          Concat$ = 750 ms
                                          rslt$ = 2814 bytes.
                                          rslt2$ = 2814 bytes.
                                          rslt3$ = 2814 bytes.
                                          (rslt$ == rslt2$) = -1
                                          (rslt2$ == rslt3$) = -1
                                          Pierre's algo is the fastest. You can expect this type of variation from one processor to another. What processor does your computer have, from the timings it looks like an oldie. ?
                                          hutch at movsd dot com
                                          The MASM Forum

                                          www.masm32.com

                                          Comment

                                          Working...
                                          X