Fast ARRAY and RECORD moves
Posted: Mon Sep 16, 2013 1:29 pm
The auto-increment / auto-decrement versions of SYSTEM.GET and SYSTEM.PUT in v4.5 Astrobe and later allow you to implement very efficient array processing functions. For example, the following are useful general-purpose functions for moving /copying blocks of data:
The main loop of MoveBytes and MoveWords consist of just four instructions. MoveWords is typically four times faster than MoveBytes because it loads/stores four bytes in each instruction and can be used for INTEGER arrays or records that are multiples of four bytes. Move can be used if it is not known if the data is a multiple of four bytes. It uses MoveWords for all except the last (less than four) bytes of data.
An example of their use is a function to shift all the bytes in an array by one position. The normal way to do this would be something like:
However, if maximum performance is a priority, an alternative implementation is:
A test with 1000-byte arrays showed that this second version that uses GET and PUT is about five times faster.
Code: Select all
PROCEDURE* MoveWords*(fromAdr, toAdr, nBytes: INTEGER);
VAR
word, lastAdr: INTEGER;
BEGIN
lastAdr := fromAdr + nBytes;
REPEAT
SYSTEM.GET(fromAdr, word, 4);
SYSTEM.PUT(toAdr, word, 4);
UNTIL fromAdr = lastAdr
END MoveWords;
PROCEDURE* MoveBytes*(fromAdr, toAdr, nBytes: INTEGER);
VAR
byte: BYTE;
lastAdr: INTEGER;
BEGIN
lastAdr := fromAdr + nBytes;
REPEAT
SYSTEM.GET(fromAdr, byte, 1);
SYSTEM.PUT(toAdr, byte, 1);
UNTIL fromAdr = lastAdr
END MoveBytes;
PROCEDURE Move*(fromAdr, toAdr, nBytes: INTEGER);
VAR
nBytes4, nBytes1: INTEGER;
BEGIN
nBytes1 := nBytes MOD 4;
nBytes4 := nBytes - nBytes1;
IF nBytes4 > 0 THEN
MoveWords(fromAdr, toAdr, nBytes4);
END;
IF nBytes1 > 0 THEN
MoveBytes(fromAdr + nBytes4, toAdr + nBytes4, nBytes1);
END
END Move;
An example of their use is a function to shift all the bytes in an array by one position. The normal way to do this would be something like:
Code: Select all
PROCEDURE* ShiftArray(VAR a: ARRAY OF BYTE);
VAR
i: INTEGER;
BEGIN
FOR i := 1 TO LEN(a) - 1 DO a[i-1] := a[i] END
END ShiftArray;
Code: Select all
PROCEDURE ShiftArray(VAR a: ARRAY OF BYTE);
BEGIN
Move(SYSTEM.ADR(a[1]), SYSTEM.ADR(a[0]), LEN(a) - 1)
END ShiftArray;