One of the advantages of PowerBASIC is its flexibility in programming
style. PowerBASIC has a very powerful set of string manipulation functions
but the operating system still mainly uses zero terminated strings so in
some instances, it is more economical to work in zero terminated strings.
In other instances, some people who are more familiar with this format
still like to work this way and of course, sometimes there is an advantage
in using this format.
Below is a test application that has a set of zero terminated string
functions written in assembler. The are not as easy to use as the basic
dynamic strings but they are useful in many instances. Where possible,
they have used DWORD size instructions to get the speed up to an
acceptable level.
Zero terminated strings have the disadvantage that they must be scanned to
get their length so an algorithm written by Agner Fog has been used
because of its speed advantage over classic byte scanners.
There is also an example of how to copy a numeric array using a DWORD
memory copy routine written in assembler. Rather than some messy looped
assignment process, this routine uses the direct address of the first
member of each array and copies the correct number of bytes from the
source address to the destination address.
For having written two other test pieces, one using 4 32 bit registers and
the second using 4 64 bit MMX registers, the "rep movsd" method has not
been improved on so the memory copy routine is in the smart end of the
market in terms of speed.
Note that you cannot use this technique on a dynamic string array as they
are not stored sequentially in memory.
A small piece of pure PowerBASIC for your pleasure.
Regards,
[email protected]
style. PowerBASIC has a very powerful set of string manipulation functions
but the operating system still mainly uses zero terminated strings so in
some instances, it is more economical to work in zero terminated strings.
In other instances, some people who are more familiar with this format
still like to work this way and of course, sometimes there is an advantage
in using this format.
Below is a test application that has a set of zero terminated string
functions written in assembler. The are not as easy to use as the basic
dynamic strings but they are useful in many instances. Where possible,
they have used DWORD size instructions to get the speed up to an
acceptable level.
Zero terminated strings have the disadvantage that they must be scanned to
get their length so an algorithm written by Agner Fog has been used
because of its speed advantage over classic byte scanners.
There is also an example of how to copy a numeric array using a DWORD
memory copy routine written in assembler. Rather than some messy looped
assignment process, this routine uses the direct address of the first
member of each array and copies the correct number of bytes from the
source address to the destination address.
For having written two other test pieces, one using 4 32 bit registers and
the second using 4 64 bit MMX registers, the "rep movsd" method has not
been improved on so the memory copy routine is in the smart end of the
market in terms of speed.
Note that you cannot use this technique on a dynamic string array as they
are not stored sequentially in memory.
A small piece of pure PowerBASIC for your pleasure.
Regards,
[email protected]
Code:
' ######################################################################### #COMPILE EXE ' ---------------------------- ' Function / Sub declarations ' ---------------------------- DECLARE FUNCTION MessageBox LIB "user32.dll" ALIAS "MessageBoxA" _ (ByVal DWORD,ByVal DWORD,ByVal DWORD,ByVal DWORD) as LONG DECLARE FUNCTION szLen(ByVal lpszString as LONG) as LONG DECLARE SUB MemCopyD(ByVal src as LONG, _ ByVal dst as LONG, _ ByVal ln as LONG) DECLARE SUB szCatStr(ByVal lpszSource as LONG, _ ByVal lpszAdd as LONG) DECLARE SUB szLeft(ByVal lpszSource as LONG, _ ByVal lpszTarget as LONG, _ ByVal ln as LONG) DECLARE SUB szMid(ByVal lpszSource as LONG, _ ByVal lpszTarget as LONG, _ ByVal stPos as LONG, _ ByVal ln as LONG) DECLARE SUB szRight(ByVal lpszSource as LONG, _ ByVal lpszTarget as LONG, _ ByVal ln as LONG) DECLARE SUB szRevStr(ByVal lpszSource as LONG,ByVal lpszTarget as LONG) ' ######################################################################### FUNCTION WinMain(ByVal Instance as LONG, _ ByVal hPrevInstance as LONG, _ lpszCmdLine as ASCIIZ PTR, _ ByVal nCmdShow as LONG) AS LONG LOCAL lpAr1 as LONG LOCAL lpAr2 as LONG LOCAL szText as ASCIIZ * 64 LOCAL szAdd as ASCIIZ * 20 LOCAL sztTl as ASCIIZ * 16 LOCAL szBuffer as ASCIIZ * 64 LOCAL szMidStr as ASCIIZ * 8 LOCAL szRightStr as ASCIIZ * 8 LOCAL szExtra as ASCIIZ * 128 szText = "Hi there folks ! " szAdd = "Message Box Test" sztTl = "Message Box" ' -------------------- ' sz string functions ' -------------------- szLeft VarPtr(szAdd),VarPtr(szBuffer),11 szCatStr VarPtr(szText),VarPtr(szBuffer) szMid VarPtr(szText),VarPtr(szMidStr),8,6 szCatStr VarPtr(szText),VarPtr(szMidStr) szRight VarPtr(szAdd),VarPtr(szRightStr),5 szCatStr VarPtr(szText),VarPtr(szRightStr) szRevStr VarPtr(szText),VarPtr(szExtra) MessageBox 0,VarPtr(szExtra),VarPtr(sztTl),0 ' ----------- ' Array copy ' ----------- redim aLong&(1 to 10000) redim aNext&(1 to 10000) lpAr1 = VarPtr(aLong&(1)) lpAr2 = VarPtr(aNext&(1)) aLong&(5678) = 1234 MemCopyD lpAr1,lpAr2,40000 Result$ = str$(aNext&(5678)) MessageBox 0,StrPtr(Result$),VarPtr(sztTl),0 FUNCTION = 0 END FUNCTION ' ######################################################################### SUB szCatStr(ByVal lpszSource as LONG, ByVal lpszAdd as LONG) #REGISTER NONE LOCAL ln1 as DWORD ln1 = szLen(lpszSource) ! mov esi, lpszAdd ! mov edi, lpszSource ! add edi, ln1 csSt: ! mov al, [esi] ! inc esi ! mov [edi], al ! inc edi ! test al, al ; test for zero ! jne csSt END SUB ' ########################################################################### FUNCTION szLen(ByVal lpszString as LONG) as LONG #REGISTER NONE LOCAL retval as LONG ! mov eax,lpszString ; get pointer to string ! lea edx,[eax+3] ; pointer+3 used in the end lnSt: ! mov ebx,[eax] ; read first 4 bytes ! add eax,4 ; increment pointer ! lea ecx,[ebx-&H01010101] ; subtract 1 from each byte ! not ebx ; invert all bytes ! and ecx,ebx ; and these two ! and ecx,&H80808080 ! jz lnSt ; no zero bytes, continue loop ! test ecx,&H00008080 ; test first two bytes ! jnz lnOut ! shr ecx,16 ; not in the first 2 bytes ! add eax,2 lnOut: ! shl cl,1 ; use carry flag to avoid branch ! sbb eax,edx ; compute length ! mov FUNCTION, eax END FUNCTION ' ########################################################################### SUB MemCopyD(ByVal src as LONG, _ ByVal dst as LONG, _ ByVal ln as LONG) #REGISTER NONE ! cld ! mov esi, src ! mov edi, dst ! mov ecx, ln ! shr ecx, 2 ! rep movsd ! mov ecx, ln ! and ecx, 3 ! rep movsb END SUB ' ########################################################################### SUB szLeft(ByVal lpszSource as LONG, _ ByVal lpszTarget as LONG, _ ByVal ln as LONG) #REGISTER NONE ! cld ! mov esi, lpszSource ! mov edi, lpszTarget ! mov ecx, ln ! shr ecx, 2 ! rep movsd ! mov ecx, ln ! and ecx, 3 ! rep movsb ! mov al, 0 ! mov [edi], al END SUB ' ########################################################################### SUB szMid(ByVal lpszSource as LONG, _ ByVal lpszTarget as LONG, _ ByVal stPos as LONG, _ ByVal ln as LONG) #REGISTER NONE ! cld ! mov esi, lpszSource ! mov edi, lpszTarget ! add esi, stPos ! mov ecx, ln ! shr ecx, 2 ! rep movsd ! mov ecx, ln ! and ecx, 3 ! rep movsb ! mov al, 0 ! mov [edi], al END SUB ' ########################################################################### SUB szRight(ByVal lpszSource as LONG, _ ByVal lpszTarget as LONG, _ ByVal ln as LONG) #REGISTER NONE LOCAL ln1 as DWORD ln1 = szLen(lpszSource) ! cld ! mov esi, lpszSource ! add esi, ln1 ! sub esi, ln ! mov edi, lpszTarget ! mov ecx, ln ! shr ecx, 2 ! rep movsd ! mov ecx, ln ! and ecx, 3 ! rep movsb ! mov al, 0 ! mov [edi], al END SUB ' ########################################################################### SUB szRevStr(ByVal lpszSource as LONG,ByVal lpszTarget as LONG) #REGISTER NONE LOCAL ln as LONG ln = szLen(lpszSource) ! mov esi, lpszSource ! mov edx, esi ; put in edx for comparison ! dec edx ! add esi, ln ; add len to source address ! dec esi ! mov edi, lpszTarget rsSt: ! mov al, [esi] ! dec esi ! mov [edi], al ! inc edi ! cmp esi, edx ! jne rsSt ! mov al, 0 ! mov [edi], al ; write terminator END SUB ' ###########################################################################