Page 2 of 2

Posted: Mon Oct 16, 2006 5:58 pm
by thamarok
AND51 wrote:
What the hell?
First you copy my code and say that I didn't use protected on the variable i?
And it was not about optimization, I made the smallest code for this!
Sorry. I can understand your point of view. Unfortunately, I had the wrong code in my clipboard. I corrected to make you see what I mean.

In my opinion, not the smallest, but the fastest code is the code that can be declared as "optimized". I discovered this, when there was the byte-calc contest in the german forum. It's no problem for me to turn my byte-calc into a one-liner (without : !!). But then the code get slower! Although I dont' work with variables any more. So you can see: Smallest code <> fastest performance
I would suggest: let's kepp the contest alive! :)
Ok, no problem I am not mad at you anymore :)
Good to see you had your explanation, but the next time, please check what you have in the clipboard :wink:

And about one-liners, I always code like that, I just like small sources even how dirty and complex they are, but I have written a little program which turns my one-liners to full PB code, so that you people would understand them easily (especially newcomers).

Let's have peace and concentrate to the upcoming stuff.
Guten abend noch AND51 und nco2k!

Posted: Tue Oct 17, 2006 11:29 am
by wilbert
There's a problem with your swapfields procedure.
Compare the two results. This also proves pointers can be faster (ok, with a little help from asm)

Code: Select all

Procedure.s StringField_SwapFields_Orig(String$, FieldA, FieldB, Separator$=" ") ; by AND51
   If FieldA <> FieldB
      String$+Separator$
      If FieldA > FieldB
         Swap FieldA, FieldB
      EndIf
      Protected FieldA$=StringField(String$, FieldA+1, Separator$), FieldB$=StringField(String$, FieldB+1, Separator$)
      FieldA=FindString(String$, FieldA$, 1)
      FieldB=FindString(String$, FieldB$, 1)
      ProcedureReturn Left(Left(String$, FieldA-1)+FieldB$+Mid(String$, FieldA+Len(FieldA$), FieldB-FIeldA-Len(FieldA$))+FieldA$+Right(String$, Len(String$)-(FieldB+Len(FieldB$))+1), Len(String$)-Len(Separator$))
   Else
      ProcedureReturn String$
   EndIf
EndProcedure

Procedure.s StringField_SwapFields(String.s, FieldA.l, FieldB.l, Separator.s = " ")
 Protected *Orig.l, *Copy.l, PosA.l, PosB.l, LenA.l, LenB.l
 Protected esi.l,ebx.l
 ; esp + 48 contains ptr to the original string
 !mov eax,dword [esp+48]
 !mov dword [p.p_Orig],eax
 ; passed String contains a copy
 !mov eax,dword [p.v_String]
 !mov dword [p.p_Copy],eax
 ; swap fields if required and check if fields > 0 and not equal
 !mov eax,[p.v_FieldA]
 !mov edx,[p.v_FieldB]
 !cmp edx,eax
 !je sf_err
 !jg sf_cont
 !xchg eax,edx
 !mov [p.v_FieldA],eax
 !mov [p.v_FieldB],edx
 !sf_cont:
 !cmp eax,1
 !jl sf_err
 ; store esi and ebx registers
 !mov [p.v_esi],esi
 !mov [p.v_ebx],ebx
 ; scan for both fields
 !mov edx,[p.v_Separator]
 !mov ah,[edx]
 !mov esi,[p.v_String]
 !xor ecx,ecx
 !cld
 !sf_pre_loop:
 !mov edx,esi
 !sf_scan_loop:
 !lodsb
 !and al,al
 !jz sf_end_fnd
 !cmp al,ah
 !jnz sf_scan_loop
 !inc ecx
 !cmp ecx,[p.v_FieldB]
 !jz sf_fldB_fnd
 !cmp ecx,[p.v_FieldA] 
 !jnz sf_pre_loop
 !mov ebx,edx
 !sub ebx,[p.v_String]
 !mov [p.v_PosA],ebx
 !mov ebx,esi
 !sub ebx,edx
 !dec ebx
 !mov [p.v_LenA],ebx
 !jmp sf_pre_loop
 !sf_fldB_fnd:
 !mov ebx,edx
 !sub ebx,[p.v_String]
 !mov [p.v_PosB],ebx
 !mov ebx,esi
 !sub ebx,edx
 !dec ebx
 !mov [p.v_LenB],ebx
 !sf_end_fnd:
 !inc ecx
 !cmp ecx,[p.v_FieldB]
 !jz sf_fldB_fnd
 ; retrieve esi and ebx registers
 !mov esi,[p.v_esi]
 !mov ebx,[p.v_ebx]
 ; check if both fields exist
 !cmp byte [p.v_PosB],0
 !je sf_err
 MoveMemory(*Orig+PosB,*Copy+PosA,LenB)
 MoveMemory(*Orig+PosA,*Copy+PosB+LenB-LenA,LenA)
 MoveMemory(*Orig+PosA+LenA,*Copy+PosA+LenB,PosB-PosA-LenA)
 !sf_err:
 ProcedureReturn String
EndProcedure 

t = GetTickCount_()
s.s = "hai there, this is a test to see if swapping some fields will work for this string."
For i=1 To 100001
 s = StringField_SwapFields_Orig(s,0,3)
Next
Debug s
t = GetTickCount_()-t
Debug t

t = GetTickCount_()
s.s = "hai there, this is a test to see if swapping some fields will work for this string."
For i=1 To 100001
 s = StringField_SwapFields(s,1,4)
Next
Debug s
t = GetTickCount_()-t
Debug t

Posted: Tue Oct 17, 2006 1:39 pm
by AND51
Hello! Thanks for your code!
I'm not able to code with / in ASM... I even don't uinderstand 'mov' :oops:

I corrected my code; there was a bug concerning the first field. I made the last field a field by appending Seperator$. But i also must add Seperator$ before the beginning to make the first field a field.

You know what I mean?

This should work now. Code becomes slower, because not only appending one Seperator$, but embedding the whole String into Seperators$. Second fact, why code got slower is that I used Mid() instead of Left() (neccessary).

Code: Select all

Procedure.s StringField_SwapFields(String$, FieldA, FieldB, Separator$=" ") ; by AND51
	If FieldA <> FieldB
		String$=Separator$+String$+Separator$
		If FieldA > FieldB
			Swap FieldA, FieldB
		EndIf
		Protected FieldA$=StringField(String$, FieldA+1, Separator$), FieldB$=StringField(String$, FieldB+1, Separator$)
		FieldA=FindString(String$, FieldA$, 1)
		FieldB=FindString(String$, FieldB$, 1)
		ProcedureReturn Mid(Left(String$, FieldA-1)+FieldB$+Mid(String$, FieldA+Len(FieldA$), FieldB-FIeldA-Len(FieldA$))+FieldA$+Right(String$, Len(String$)-(FieldB+Len(FieldB$))+1), Len(Separator$)+1, Len(String$)-Len(Separator$)*2)
	Else
		ProcedureReturn String$
	EndIf
EndProcedure

Posted: Tue Oct 17, 2006 2:04 pm
by thamarok
Thank God I came from ASM before coming to PureBasic :wink: .
mov is an instruction which moves data from X to Y.
An example:
The register ax needs to be filled with the value 4, to do this you would make this code:

Code: Select all

MOV ax, 4
Please note that every register has it's own meaning, and setting a number to a register works always as a flag to tell more detail for the processor about the instruction.

Look to the PureBasic FAQ, I think there is a link to a help file with ASM instructions and other stuff.

Posted: Tue Oct 17, 2006 2:54 pm
by AND51
Thank you!

Before your explanation, I only knew that 'mov' is needed in evry program. Seems so.

I'll care about ASM, if I'm in the right mood. Although I think that I'm an advanced coder, :wink:
ASM is still to difficult for me.

Nevertheless, I'll pay attention to your advice, thx!

By the way: You filled 'ax' with '4'. Is 'ax' now a .l, .b or .q ? Moreover, can I continue using 'ax' as 'normal PureBasic variable'? I assume, filling variables that way you did is faster than 'ax=4' for example.

Posted: Tue Oct 17, 2006 3:05 pm
by thamarok
AND51 wrote:Thank you!

Before your explanation, I only knew that 'mov' is needed in evry program. Seems so.

I'll care about ASM, if I'm in the right mood. Although I think that I'm an advanced coder, :wink:
ASM is still to difficult for me.

Nevertheless, I'll pay attention to your advice, thx!

By the way: You filled 'ax' with '4'. Is 'ax' now a .l, .b or .q ? Moreover, can I continue using 'ax' as 'normal PureBasic variable'? I assume, filling variables that way you did is faster than 'ax=4' for example.
In the example above, ax is a register and it can be filled with a byte, word etc.. But you can't use a register in PureBasic as a value, but you can do this:

Code: Select all

Debug a
!MOV [v_a], 4 ; To use a PB variable in ASM, you have to put the v_ prefix.
Debug a
I am not sure if this is faster, you have to make a speed test.
I hope this helps

EDIT: I forgot to tell that you need to define (or mention) every variable you are going to use in inlined ASM or you will get a "undefined symbol" error.

Posted: Tue Oct 17, 2006 3:07 pm
by wilbert
AND51 wrote:This should work now.
Unfortunately it still returns a strange result when I try it with the string I used.
I also included a similar partly asm solution to remove a field.

PureBasic4 code

Code: Select all

Procedure.s StringField_SwapFields_Orig(String$, FieldA, FieldB, Separator$=" ") ; by AND51
   If FieldA <> FieldB
      String$=Separator$+String$+Separator$
      If FieldA > FieldB
         Swap FieldA, FieldB
      EndIf
      Protected FieldA$=StringField(String$, FieldA+1, Separator$), FieldB$=StringField(String$, FieldB+1, Separator$)
      FieldA=FindString(String$, FieldA$, 1)
      FieldB=FindString(String$, FieldB$, 1)
      ProcedureReturn Mid(Left(String$, FieldA-1)+FieldB$+Mid(String$, FieldA+Len(FieldA$), FieldB-FIeldA-Len(FieldA$))+FieldA$+Right(String$, Len(String$)-(FieldB+Len(FieldB$))+1), Len(Separator$)+1, Len(String$)-Len(Separator$)*2)
   Else
      ProcedureReturn String$
   EndIf
EndProcedure

Procedure.s StringField_RemoveField_Orig(String$, Index, Separator$=" ") ; by AND51
   Protected n.l=CountString(String$, Separator$), position.q
   If Index > n
      Index=n
   EndIf
   For n=1 To Index
      position=FindString(String$, Separator$, position+1)
   Next
   ProcedureReturn Left(String$, position)+Right(String$, Len(String$)-(position+Len(StringField(String$, Index+1, Separator$)))-Len(Separator$))
EndProcedure

Procedure.s StringField_SwapFields(String.s, FieldA.l, FieldB.l, Separator.s = " ")
 Protected *Orig.l, *Copy.l, PosA.l, PosB.l, LenA.l, LenB.l
 Protected esi.l,ebx.l
 ; esp + 48 contains ptr to the original string
 !mov eax,dword [esp+48]
 !mov dword [p.p_Orig],eax
 ; passed String contains a copy
 !mov eax,dword [p.v_String]
 !mov dword [p.p_Copy],eax
 ; swap fields if required and check if fields > 0 and not equal
 !mov eax,[p.v_FieldA]
 !mov edx,[p.v_FieldB]
 !cmp edx,eax
 !je sf_err
 !jg sf_cont
 !xchg eax,edx
 !mov [p.v_FieldA],eax
 !mov [p.v_FieldB],edx
 !sf_cont:
 !cmp eax,1
 !jl sf_err
 ; store esi and ebx registers
 !mov [p.v_esi],esi
 !mov [p.v_ebx],ebx
 ; scan for both fields
 !mov edx,[p.v_Separator]
 !mov ah,[edx]
 !mov esi,[p.v_String]
 !xor ecx,ecx
 !cld
 !sf_pre_loop:
 !mov edx,esi
 !sf_scan_loop:
 !lodsb
 !and al,al
 !jz sf_end_fnd
 !cmp al,ah
 !jnz sf_scan_loop
 !inc ecx
 !cmp ecx,[p.v_FieldB]
 !jz sf_fldB_fnd
 !cmp ecx,[p.v_FieldA] 
 !jnz sf_pre_loop
 !mov ebx,edx
 !sub ebx,[p.v_String]
 !mov [p.v_PosA],ebx
 !mov ebx,esi
 !sub ebx,edx
 !dec ebx
 !mov [p.v_LenA],ebx
 !jmp sf_pre_loop
 !sf_fldB_fnd:
 !mov ebx,edx
 !sub ebx,[p.v_String]
 !mov [p.v_PosB],ebx
 !mov ebx,esi
 !sub ebx,edx
 !dec ebx
 !mov [p.v_LenB],ebx
 !sf_end_fnd:
 !inc ecx
 !cmp ecx,[p.v_FieldB]
 !jz sf_fldB_fnd
 ; retrieve esi and ebx registers
 !mov esi,[p.v_esi]
 !mov ebx,[p.v_ebx]
 ; check if both fields exist
 !cmp byte [p.v_PosB],0
 !je sf_err
 MoveMemory(*Orig+PosB,*Copy+PosA,LenB)
 MoveMemory(*Orig+PosA,*Copy+PosB+LenB-LenA,LenA)
 MoveMemory(*Orig+PosA+LenA,*Copy+PosA+LenB,PosB-PosA-LenA)
 !sf_err:
 ProcedureReturn String
EndProcedure 

Procedure.s StringField_RemoveField(String.s, Field.l, Separator.s = " ")
 Protected *Orig.l, *Copy.l, PosF.l, LenF.l, LenS.l
 Protected esi.l,ebx.l
 ; esp + 44 contains ptr to the original string
 !mov eax,dword [esp+44]
 !mov dword [p.p_Orig],eax
 ; passed String contains a copy
 !mov eax,dword [p.v_String]
 !mov dword [p.p_Copy],eax
 ; swap fields if required and check if fields > 0 and not equal
 !mov eax,[p.v_Field]
 !cmp eax,1
 !jl rf_err
 ; store esi and ebx registers
 !mov [p.v_esi],esi
 !mov [p.v_ebx],ebx
 ; scan for field
 !mov edx,[p.v_Separator]
 !mov ah,[edx]
 !mov esi,[p.v_String]
 !xor ecx,ecx
 !cld
 !rf_pre_loop:
 !mov edx,esi
 !rf_scan_loop:
 !lodsb
 !and al,al
 !jz rf_end_fnd
 !cmp al,ah
 !jnz rf_scan_loop
 !inc ecx
 !cmp ecx,[p.v_Field]
 !jnz rf_pre_loop
 !rf_fld_fnd:
 !mov ebx,edx
 !sub ebx,[p.v_String]
 !mov [p.v_PosF],ebx
 !mov ebx,esi
 !sub ebx,edx
 !dec ebx
 !mov [p.v_LenF],ebx
 !cmp dword [p.v_LenS],0
 !jz rf_scan_loop
 !rf_end_fnd:
 !mov ebx,esi
 !sub ebx,[p.v_String]
 !dec ebx
 !mov [p.v_LenS],ebx
 !inc ecx
 !cmp ecx,[p.v_Field]
 !jz rf_fld_fnd
 ; retrieve esi and ebx registers
 !mov esi,[p.v_esi]
 !mov ebx,[p.v_ebx]
 ; check if field length > 0
 !cmp byte [p.v_LenF],0
 !je rf_err
 If LenF = LenS
  PokeB(*Copy,0)
 Else
  MoveMemory(*Orig+PosF+LenF+1,*Copy+PosF,LenS-PosF-LenF)
  PokeB(*Copy+LenS-LenF-1,0)
 EndIf
 !rf_err:
 ProcedureReturn String
EndProcedure 

t = GetTickCount_()
s.s = "hai there, this is a test to see if swapping some fields will work for this string."
For i=1 To 100001
 s = StringField_SwapFields_Orig(s,0,3)
Next
Debug s
t = GetTickCount_()-t
Debug t

t = GetTickCount_()
s.s = "hai there, this is a test to see if swapping some fields will work for this string."
For i=1 To 100001
 s = StringField_SwapFields(s,1,4,".")
Next
Debug s
t = GetTickCount_()-t
Debug t

t = GetTickCount_()
s.s = "hai there, this is a test to see if removing a field will work for this string."
For i=1 To 100001
 s1.s = StringField_RemoveField_Orig(s,13)
Next
Debug s1
t = GetTickCount_()-t
Debug t

t = GetTickCount_()
s.s = "hai there, this is a test to see if removing a field will work for this string."
For i=1 To 100001
 s1.s = StringField_RemoveField(s,14)
Next
Debug s1
t = GetTickCount_()-t
Debug t

Re: Space2

Posted: Thu Oct 19, 2006 3:34 pm
by naw
How about this:

Code: Select all

Procedure.s space2(L,S$)
  ProcedureReturn(ReplaceString(Space(L)," ",S$))
EndProcedure

messageRequester("",space2(10,"PB"))

Re: Space2

Posted: Thu Oct 19, 2006 4:37 pm
by thamarok
naw wrote:How about this:

Code: Select all

Procedure.s space2(L,S$)
  ProcedureReturn(ReplaceString(Space(L)," ",S$))
EndProcedure

messageRequester("",space2(10,"PB"))
naw, you are a genious!
That works, is a bit slow, but cool :wink:

What makes it slow is that PB needs to first create the string with space characters, and then replace all of them with the needed string.

A faster way is what I made which does only add the needed amount of the string.

Posted: Fri Oct 20, 2006 12:48 am
by naw
thamarok thank you :lol: I'm inventive but certainly not a genius but I'll be grinning about the generous compliment all day now...

Re: Space2

Posted: Fri Oct 20, 2006 9:37 am
by AND51
naw wrote:How about this:

Code: Select all

Procedure.s space2(L,S$)
  ProcedureReturn(ReplaceString(Space(L)," ",S$))
EndProcedure

messageRequester("",space2(10,"PB"))
Of course, I had this idea before creating my Procedure. But your Code does not use th advantage: If 'L' is an even number (e. g. 2, 8, 64, 200, ...) and then length of 'S$' is also even, than you can use the "in place"-method, offered by ReplaceString(). See help for more details.

Re: Space2

Posted: Fri Oct 20, 2006 10:33 am
by wilbert
AND51 wrote:than you can use the "in place"-method, offered by ReplaceString().
Sorry, but if you do a speed comparisson you will see that even in that case the solution offered by Naw is faster. The only time your solution is faster is when the fill string consists of spaces only.