[Back to STRINGS SWAG index]  [Back to Main SWAG index]  [Original]

{
    The below listed program tests representives of the various methods
available.  The third method does not check for overflow, but is about 3.0
times faster than those presented so far by my bench mark test.
                           Joel Lichtenwalner in Ogden Utah.

RESULTS (TURBO7 USING [Don't laugh] 386DX 25):
  Test concatenation functions
  Testing Pascal's "+" function Performance = 131.100000 Loops per tick
  Testing STRCONT function Performance = 129.466667 Loops per tick
  Testing ATTACH procedure  Performance = 394.900000 Loops per tick
}
{$A+,N+,R-,S+,V-,X+,Y+}
{$M 16384,0,655360}
PROGRAM TEST_CONCAT;  { TESTS VARIOUS METHODS OF CONCATENATING STRINGS }
  USES
    CRT;
  CONST
    ADD_STR     : STRING[22] = 'Test string 1234567890';
    TICKS       = 90;           { LOOP FOR APPROX 5 SECONDS }
  VAR
    CLOCK_TICKS : WORD ABSOLUTE $40:$6C;  { Updated every 58 ms by system }
    TIME_SAVE   : WORD;         { Variable used to keep track of time     }
    LOOPS       : LONGINT;      { Loop control counter                    }
    TARG        : STRING[255];  { Target string, to be added too          }
    COMPUTE     : EXTENDED;

  function strcont(s1,s2:string):string; assembler;
    asm
      push ds
      cld
      lds si,s1         {Load addresses of s1}
      les di,s2         {Load addresses of s2}
      xor ah,ah         {Clear ah & bh}
      xor bh,bh         {     ""      }
      mov al,ds:[si]    {Get the length of first string, copy into al}
      mov bl,es:[di]    {Get the length of second string, copy into bl}
      add ax,bx         {Add length of s1 to length s2}
      cmp ax,255        {Compare}
      ja @toolarge      {Jump to @toolarge if length(s1)+length(s2)>255}
      les di,@result    {Copy location of @result into es:di}
      mov cl,1          {Make sure at least one byte of beginning string}
      xor ch,ch         {is transferred to @result.}
      add cl,ds:[si]    {Add length of string to cl.}
      rep movsb         {Copy first string into @result}
      lds si,s2         {Get address of second string}
      mov cl,ds:[si]    {Get length of second string, copy into cl}
      cmp cl,0          {If second string is blank, skip adding it.}
      je @end           {Jump to end if length of second string is zero.}
      inc si            {Move pointer (si) to start of second string}
      mov al,cl         {Save length of second string in al}
      rep movsb         {Copy second string into @result}
      lds si,@result    {Get location of @result}
      add ds:[si],al    {Add lengths together}
      jmp @end          {Skip to end}
     @toolarge:         {If added strings total larger than 255, this sub}
      les di,@result    {is called.}
      xor al,al         {Make sure al is a zero.}
      mov es:[di],al    {Move a "0" into the beginning of @result, making it}
     @end:              {a null string.}
      pop ds            {Return DS to normal so Pascal doesn't screw up.}
      end;
  PROCEDURE ATTACH(VAR DEST,SOURCE:STRING);
    VAR
      DESTL   : BYTE ABSOLUTE DEST;
      SOURCEL : BYTE ABSOLUTE SOURCE;
    BEGIN
      MOVE(SOURCE[1],DEST[SUCC(DESTL)],SOURCEL);
      INC(DESTL,SOURCEL);
      END;
  BEGIN
    CLRSCR;  WRITELN('Test concatenation functions');
    { -------- FIRST TEST -------- }
    WRITE('Testing Pascal''s "+" function');
    LOOPS := 0;
    TIME_SAVE := CLOCK_TICKS;    { WAIT UNTIL THE CLOCK TURNS OVER }
    REPEAT UNTIL CLOCK_TICKS <> TIME_SAVE;
    TIME_SAVE := CLOCK_TICKS + TICKS;  { Set loop time }
      REPEAT
      TARG := '';
      TARG := TARG + ADD_STR;  {  22 }
      TARG := TARG + ADD_STR;  {  44 }
      TARG := TARG + ADD_STR;  {  66 }
      TARG := TARG + ADD_STR;  {  88 }
      TARG := TARG + ADD_STR;  { 110 }
      TARG := TARG + TARG;     { 220 }
      TARG := TARG + ADD_STR;  { 242 }
      INC(LOOPS);
      UNTIL CLOCK_TICKS = TIME_SAVE;
    COMPUTE := LOOPS;
    COMPUTE := COMPUTE / TICKS;
    WRITELN(' Performance = ',COMPUTE:0:6,' Loops per tick');
    { -------- SECOND TEST -------- }
    WRITE('Testing STRCONT function');
    LOOPS := 0;
    TIME_SAVE := CLOCK_TICKS;    { WAIT UNTIL THE CLOCK TURNS OVER }
    REPEAT UNTIL CLOCK_TICKS <> TIME_SAVE;
    TIME_SAVE := CLOCK_TICKS + TICKS;  { Set loop time }
      REPEAT
      TARG := '';
      TARG := strcont(TARG,ADD_STR);  {  22 }
      TARG := strcont(TARG,ADD_STR);  {  44 }
      TARG := strcont(TARG,ADD_STR);  {  66 }
      TARG := strcont(TARG,ADD_STR);  {  88 }
      TARG := strcont(TARG,ADD_STR);  { 110 }
      TARG := strcont(TARG,TARG);     { 220 }
      TARG := strcont(TARG,ADD_STR);  { 242 }
      INC(LOOPS);
      UNTIL CLOCK_TICKS = TIME_SAVE;
    COMPUTE := LOOPS; COMPUTE := COMPUTE / TICKS;
    WRITELN(' Performance = ',COMPUTE:0:6,' Loops per tick');
    { -------- THIRD TEST -------- }
    WRITE('Testing ATTACH procedure ');
    LOOPS := 0;
    TIME_SAVE := CLOCK_TICKS;    { WAIT UNTIL THE CLOCK TURNS OVER }
    REPEAT UNTIL CLOCK_TICKS <> TIME_SAVE;
    TIME_SAVE := CLOCK_TICKS + TICKS;  { Set loop time }
      REPEAT
      TARG := '';
      ATTACH(TARG,ADD_STR);  {  22 }
      ATTACH(TARG,ADD_STR);  {  44 }
      ATTACH(TARG,ADD_STR);  {  66 }
      ATTACH(TARG,ADD_STR);  {  88 }
      ATTACH(TARG,ADD_STR);  { 110 }
      ATTACH(TARG,TARG);     { 220 }
      ATTACH(TARG,ADD_STR);  { 242 }
      INC(LOOPS);
      UNTIL CLOCK_TICKS = TIME_SAVE;
    COMPUTE := LOOPS; COMPUTE := COMPUTE / TICKS;
    WRITELN(' Performance = ',COMPUTE:0:6,' Loops per tick');
    READLN;
    END.


[Back to STRINGS SWAG index]  [Back to Main SWAG index]  [Original]