Seite 1 von 3
Suche Funktion um Charakter im Memory zu zählen
Verfasst: 22.03.2010 01:07
von hjbremer
Hallo, guten Abend
ich lade eine Textdatei mit ReadData ins Memory und möchte nun wissen wieviele Zeilen diese hat. Nun kann ich natürlich mit Peeks den Memoryinhalt einer Variablen zuordnen und dann mit CountString den Chr 13 zählen. Aber wat fürn Unsinn.
Ich suche also eine Funktion die die Anzahl von einem Charakter im Memory zählt.
Um einen bestimmten Chr zu finden gibt es strchr_(). Nun hab ich darum eine Schleife gebaut und zähle.
Aber gehts nicht noch einfacher ?
Code: Alles auswählen
;Demostring
a.s
a + "12345" + #CRLF$ + "6789" + #CRLF$
a + "12345" + #CRLF$ + "6789" + #CRLF$
;zur Demo String ins Memory
pointer = AllocateMemory(Len(a) + 2): PokeS(pointer, a)
;Demo für suche von chr 13 im Memory
p = strchr_(pointer, 13)
If p: Debug PeekS(p,1)
Debug p - pointer + 1
EndIf
; --------------------------------------------------------
;Schleife für alle chr 13 zählen
p = pointer - 1
Repeat
p = strchr_(p + 1, 13)
If p: anz + 1: EndIf
Until Not p
Debug anz
PS: am besten Einfacher und Schneller
PSPS: die + 2 bei AllocateMemory ist, weil strchr_() einen nullterminierten String erwartet
Re: Suche Funktion um Charakter im Memory zu zählen
Verfasst: 22.03.2010 01:32
von Thorium
Code: Alles auswählen
Procedure CountChar(*Buffer.Character, BufferLength.i, Char.c)
Protected.i i, Count
BufferCharCount = BufferLength / SizeOf(Character)
For i = 1 To BufferLength
If *Buffer\c = Char
Count + 1
EndIf
*Buffer + SizeOf(Character)
Next
ProcedureReturn Count
EndProcedure
;Demostring
a.s
a + "12345" + #CRLF$ + "6789" + #CRLF$
a + "12345" + #CRLF$ + "6789" + #CRLF$
;zur Demo String ins Memory
pointer = AllocateMemory(Len(a)): PokeS(pointer, a)
Debug CountChar(pointer, Len(a), 13)
Bitteschön.
Man könnte die Längenangabe des Puffers auch weglassen, allerdings müsste man dann bei jedem Zeichen prüfen ob Null erreicht wurde, was Performance kostet und da du die Bufferlänge sowieso kennst.
Wenn dus schneller brauchst, muss man mit Assembler rann, dann ist es aber nicht mehr Plattformunabhängig.
Re: Suche Funktion um Charakter im Memory zu zählen
Verfasst: 22.03.2010 01:33
von STARGÅTE
Mir würde nur noch die Structure Variante einfallen:
Code: Alles auswählen
;Demostring
a.s
a + "12345" + #CRLF$ + "6789" + #CRLF$
a + "12345" + #CRLF$ + "6789" + #CRLF$
;zur Demo String ins Memory
*pointer.Character = AllocateMemory(Len(a) + SizeOf(Character)) : PokeS(*pointer, a)
;Demo für suche von chr 13 im Memory
While *pointer\c
If *pointer\c = 13 : anz+1 : EndIf
*pointer+SizeOf(Character)
Wend
Debug anz
EDIT: Zu spääät ^^
Re: Suche Funktion um Charakter im Memory zu zählen
Verfasst: 22.03.2010 16:05
von hjbremer
Habe einen kleinen Vergleich gemacht
Code: Alles auswählen
Structure myFileInfo
name.s
laenge.i
StructureUnion
inhalt.s
zeiger.i
EndStructureUnion
EndStructure
Procedure.i DatenLesen(*dat.myFileInfo)
With *dat
Protected dnr = ReadFile(#PB_Any, \name)
If dnr
\laenge = Lof(dnr)
\inhalt = Space(\laenge)
\laenge = ReadData(dnr, \zeiger, \laenge)
CloseFile(dnr)
Else
MessageRequester(\name,"Konnte diese Datei nicht öffnen!")
End
EndIf
EndWith
EndProcedure
Procedure CountChar1(*Buffer.Character, BufferLength)
; von Thorium
Protected.i i, Count
For i = 1 To BufferLength
If *Buffer\c = 13
Count + 1
EndIf
*Buffer + SizeOf(Character)
Next
ProcedureReturn Count
EndProcedure
Procedure CountChar2(*pointer.Character)
; von Stargate
Protected anz
While *pointer\c
If *pointer\c = 13 : anz + 1 : EndIf
*pointer + SizeOf(Character)
Wend
ProcedureReturn anz
EndProcedure
Procedure CountChar3(pointer)
; von Bremer
Protected p = pointer - SizeOf(Character)
Protected anz
While p
p = strchr_(p + SizeOf(Character), 13)
If p: anz + 1: EndIf
Wend
ProcedureReturn anz
EndProcedure
datei.myFileInfo
datei\name = #PB_Compiler_Home + "Compilers\APIFunctionListing.txt"
DatenLesen(datei)
max = 250
a = GetTickCount_()
For j = 1 To max: anz = CountChar1(datei\zeiger, datei\laenge): Next
thorium = GetTickCount_() - a
i$ = Str(anz) + " thorium " + Str(thorium) + #LF$
a = GetTickCount_()
For j = 1 To max: anz = CountChar2(datei\zeiger): Next
stargate = GetTickCount_() - a
i$ + Str(anz) + " stargate " + Str(stargate) + #LF$
a = GetTickCount_()
For j = 1 To max: anz = CountChar3(datei\zeiger): Next
strchr = GetTickCount_() - a
i$ + Str(anz) + " strchr " + Str(strchr) + #LF$
MessageRequester("", i$)
Geht da noch was ? Eventuell mit ASM
Ich persönlich benötige keine Plattformunabhängigkeit
Re: Suche Funktion um Charakter im Memory zu zählen
Verfasst: 22.03.2010 19:10
von Thorium
Mit Assembler geht da noch ne Menge.
Reichts dir wenn die Prozedur nur ASCII/ANSI verarbeitet oder brauchst du auch Unicode?
Nur ASCII/ANSI ist um einiges einfacher in Assembler. Bei Unicode müsste man bissel rumwurschteln um keine 16bit Operationen zu haben, die saulahm sind.
Und sind deine Strings immer so klein? Wenn sie groß sind kann man auch noch MMX/SSE2 verwenden. Aber bei so kleinen Strings würde das in einem Performanceverlust resultieren.
Also schreib nochmal was genau du brauchst und ich bastel die ne Assemblerprozedur heute abend.
Re: Suche Funktion um Charakter im Memory zu zählen
Verfasst: 22.03.2010 19:43
von hjbremer
Unicode ? neue Pilzsorte, Fernsehsendung, oder ... ?
nein brauch ich nicht, progge nur für mich und Umgebung
Textdateien können ohne Probleme 5 Mb erreichen, darum ja auch in Speicher laden und auswerten.
Danke im voraus
Re: Suche Funktion um Charakter im Memory zu zählen
Verfasst: 23.03.2010 01:41
von Thorium
Bitteschön, ist gut doppelt so schnell wie die anderen. Das ist jetzt simples Assembler, ich werd noch eine mit SSE2 schreiben, das wird aber heute nix mehr.
Code: Alles auswählen
Structure myFileInfo
name.s
laenge.i
StructureUnion
inhalt.s
zeiger.i
EndStructureUnion
EndStructure
Procedure.i DatenLesen(*dat.myFileInfo)
With *dat
Protected dnr = ReadFile(#PB_Any, \name)
If dnr
\laenge = Lof(dnr)
\inhalt = Space(\laenge)
\laenge = ReadData(dnr, \zeiger, \laenge)
CloseFile(dnr)
Else
MessageRequester(\name,"Konnte diese Datei nicht öffnen!")
End
EndIf
EndWith
EndProcedure
Procedure CountChar1(*Buffer.Character, BufferLength)
; von Thorium
Protected.i i, Count
For i = 1 To BufferLength
If *Buffer\c = 13
Count + 1
EndIf
*Buffer + SizeOf(Character)
Next
ProcedureReturn Count
EndProcedure
Procedure CountChar2(*pointer.Character)
; von Stargate
Protected anz
While *pointer\c
If *pointer\c = 13 : anz + 1 : EndIf
*pointer + SizeOf(Character)
Wend
ProcedureReturn anz
EndProcedure
Procedure CountChar3(pointer)
; von Bremer
Protected p = pointer - SizeOf(Character)
Protected anz
While p
p = strchr_(p + SizeOf(Character), 13)
If p: anz + 1: EndIf
Wend
ProcedureReturn anz
EndProcedure
Procedure.i CountCharAsm(*Buffer, BufferLength.i, Char.a)
CompilerSelect #PB_Compiler_Processor
CompilerCase #PB_Processor_x86
!push edi
!cld
!xor edx,edx
!mov ecx,[p.v_BufferLength+4]
!mov edi,[p.p_Buffer+4]
!mov al,[p.v_Char+4]
!align 4
!CountCharAsmLoop:
!repne scasb
!inc edx
!test ecx,ecx
!jne CountCharAsmLoop
!mov bl,[edi]
!cmp bl,al
!je CountCharAsmEnd
!dec edx
!CountCharAsmEnd:
!mov eax, edx
!pop edi
CompilerCase #PB_Processor_x64
!push rdi
!cld
!xor rdx,rdx
!mov rcx,[p.v_BufferLength+8]
!mov rdi,[p.p_Buffer+8]
!mov al,[p.v_Char+8]
!align 8
!CountCharAsmLoop:
!repne scasb
!inc rdx
!test rcx,rcx
!jne CountCharAsmLoop
!mov bl,[rdi]
!cmp bl,al
!je CountCharAsmEnd
!dec rdx
!CountCharAsmEnd:
!mov rax, rdx
!pop rdi
CompilerEndSelect
ProcedureReturn
EndProcedure
datei.myFileInfo
datei\name = #PB_Compiler_Home + "Compilers\APIFunctionListing.txt"
DatenLesen(datei)
max = 500
a = GetTickCount_()
For j = 1 To max: anz = CountChar1(datei\zeiger, datei\laenge): Next
thorium = GetTickCount_() - a
i$ = Str(anz) + " thorium " + Str(thorium) + #LF$
a = GetTickCount_()
For j = 1 To max: anz = CountChar2(datei\zeiger): Next
stargate = GetTickCount_() - a
i$ + Str(anz) + " stargate " + Str(stargate) + #LF$
a = GetTickCount_()
For j = 1 To max: anz = CountChar3(datei\zeiger): Next
strchr = GetTickCount_() - a
i$ + Str(anz) + " strchr " + Str(strchr) + #LF$
a = GetTickCount_()
For j = 1 To max: anz = CountCharAsm(datei\zeiger, datei\laenge, 13): Next
SimpleAsm = GetTickCount_() - a
i$ + Str(anz) + " simples Assembler " + Str(SimpleAsm) + #LF$
MessageRequester("", i$)
Re: Suche Funktion um Charakter im Memory zu zählen
Verfasst: 23.03.2010 21:33
von hjbremer
Boooaah, Wahnsinn, affengeil
Nun noch eine kleine Frage, könnte man sich nicht den Längenparameter sparen und auf Nullstring prüfen?
So in der Art:
CMP byte[ecx], 0 ;überprüfen ob Stringende erreicht
JZ l_ende ;wenn ja, jump nach ende
Da ich aber von ASM so gut wie null Ahnung habe und nie weiß welche Register etc, bekomme ich es nie auf die Reihe.
Oder wird das ganze dann zu langsam ?
Re: Suche Funktion um Charakter im Memory zu zählen
Verfasst: 23.03.2010 22:05
von Thorium
Kann man schon, allerdings kann man dann nicht mehr repne scasb verwenden, das scannt den String solange bis das AL Register gleich dem Byte addressiert durch das EDI Register ist, wobei es bei jedem durchlauf automatisch höher zählt. Außerdem wird repne auch beendet wenn ECX gleich null ist. ECX wird mit jedem durchlauf eins runtergezählt und enthält die Länge des strings. REPNE SCASB ist quasie eine komplette Schleife in sich. Und diese Instruktion gehöhrt zu den wenigen Repetier-Stringbefehlen, welche hochoptimiert sind. Im Klartext baut man die Schleife so auf das die Länge innerhalb der Schleife geprüft wird, wird es merkbar langsamer werden.
Re: Suche Funktion um Charakter im Memory zu zählen
Verfasst: 23.03.2010 23:29
von hjbremer
Aha, also ist es besser so wie es ist, Danke für die Info !