j'ai un besoin précis d'optimisation: Je dois convertir
une chaine en un table de Bytes.
J'ai écrit cette fonction, qui fonctionne très bien:
' s : une chaine
' szt : la longuue de cette chaine
' t() : le tableau de byte à remplir
Function CvrtStr2ByteArray(ByVal s As String, _
ByVal szt As Long, _
ByRef t() As Byte) As Boolean
Dim i As Long
Dim c As String
For i = 1 To szt
c = Mid$(s, i, 1)
If LenB(c) = 0 Then
t(i - 1) = CByte(0)
Else
t(i - 1) = CByte(Asc(c))
End If
Next i
CvrtStr2ByteArray = True
End Function
Connaitriez vous un moyen de faire cela, mais plus rapidement
que ne le fait cette implémentation naïve.
J'ai ici un vrai besoin d'optimisation, car cette fonction est
un facteur limitant dans un de mes programmes (Rabbit)
Note: la chaine en paramètre peut être très longeur (jusqu'à
plusieurs centaines de K) et j'appelle parfois cette fonction
plusieurs milliers de fois consécutivement.
Si vous aviez un moyen efficace, je suis preneur, sinon je ferais
une dll en C, mais je voulais éviter cela pour ce projet en
particulier.
Pour établir une comparaison, j'ai mesuré les performances de
ma fonction: 10 mesures de 100 appels avec une chaine aléatoire
de 65535 caractères.
Résultat: 37 millisecondes par appel de fonction.
Si on peut faire en dessous de 10 millisecondes, je prends :-)
Sinon, je fais une Dll :-(
--
Jean-marc
Tester mon serveur (VB6) => http://myjmnhome.dyndns.org
"There are only 10 kind of people
those who understand binary and those who don't."
mailto: remove '_no_spam_' ; _no_spam_jean_marc_n2@yahoo.fr
j'ai un besoin précis d'optimisation: Je dois convertir une chaine en un table de Bytes.
J'ai écrit cette fonction, qui fonctionne très bien:
' s : une chaine ' szt : la longuue de cette chaine ' t() : le tableau de byte à remplir Function CvrtStr2ByteArray(ByVal s As String, _ ByVal szt As Long, _ ByRef t() As Byte) As Boolean Dim i As Long Dim c As String
For i = 1 To szt c = Mid$(s, i, 1) If LenB(c) = 0 Then t(i - 1) = CByte(0) Else t(i - 1) = CByte(Asc(c)) End If Next i CvrtStr2ByteArray = True End Function
Connaitriez vous un moyen de faire cela, mais plus rapidement que ne le fait cette implémentation naïve. J'ai ici un vrai besoin d'optimisation, car cette fonction est un facteur limitant dans un de mes programmes (Rabbit) Note: la chaine en paramètre peut être très longeur (jusqu'à plusieurs centaines de K) et j'appelle parfois cette fonction plusieurs milliers de fois consécutivement. Si vous aviez un moyen efficace, je suis preneur, sinon je ferais une dll en C, mais je voulais éviter cela pour ce projet en particulier.
Pour établir une comparaison, j'ai mesuré les performances de ma fonction: 10 mesures de 100 appels avec une chaine aléatoire de 65535 caractères.
Résultat: 37 millisecondes par appel de fonction.
Si on peut faire en dessous de 10 millisecondes, je prends :-) Sinon, je fais une Dll :-(
Y a t-il une contrainte qui t'empêche d'utiliser l'API CopyMemory ?
-- Cordialement,
Jacques.
Bonour Jean-Marc,
Jean-Marc a écrit :
Bonjour chers collègues,
j'ai un besoin précis d'optimisation: Je dois convertir
une chaine en un table de Bytes.
J'ai écrit cette fonction, qui fonctionne très bien:
' s : une chaine
' szt : la longuue de cette chaine
' t() : le tableau de byte à remplir
Function CvrtStr2ByteArray(ByVal s As String, _
ByVal szt As Long, _
ByRef t() As Byte) As Boolean
Dim i As Long
Dim c As String
For i = 1 To szt
c = Mid$(s, i, 1)
If LenB(c) = 0 Then
t(i - 1) = CByte(0)
Else
t(i - 1) = CByte(Asc(c))
End If
Next i
CvrtStr2ByteArray = True
End Function
Connaitriez vous un moyen de faire cela, mais plus rapidement
que ne le fait cette implémentation naïve.
J'ai ici un vrai besoin d'optimisation, car cette fonction est
un facteur limitant dans un de mes programmes (Rabbit)
Note: la chaine en paramètre peut être très longeur (jusqu'à
plusieurs centaines de K) et j'appelle parfois cette fonction
plusieurs milliers de fois consécutivement.
Si vous aviez un moyen efficace, je suis preneur, sinon je ferais
une dll en C, mais je voulais éviter cela pour ce projet en
particulier.
Pour établir une comparaison, j'ai mesuré les performances de
ma fonction: 10 mesures de 100 appels avec une chaine aléatoire
de 65535 caractères.
Résultat: 37 millisecondes par appel de fonction.
Si on peut faire en dessous de 10 millisecondes, je prends :-)
Sinon, je fais une Dll :-(
Y a t-il une contrainte qui t'empêche d'utiliser l'API CopyMemory ?
j'ai un besoin précis d'optimisation: Je dois convertir une chaine en un table de Bytes.
J'ai écrit cette fonction, qui fonctionne très bien:
' s : une chaine ' szt : la longuue de cette chaine ' t() : le tableau de byte à remplir Function CvrtStr2ByteArray(ByVal s As String, _ ByVal szt As Long, _ ByRef t() As Byte) As Boolean Dim i As Long Dim c As String
For i = 1 To szt c = Mid$(s, i, 1) If LenB(c) = 0 Then t(i - 1) = CByte(0) Else t(i - 1) = CByte(Asc(c)) End If Next i CvrtStr2ByteArray = True End Function
Connaitriez vous un moyen de faire cela, mais plus rapidement que ne le fait cette implémentation naïve. J'ai ici un vrai besoin d'optimisation, car cette fonction est un facteur limitant dans un de mes programmes (Rabbit) Note: la chaine en paramètre peut être très longeur (jusqu'à plusieurs centaines de K) et j'appelle parfois cette fonction plusieurs milliers de fois consécutivement. Si vous aviez un moyen efficace, je suis preneur, sinon je ferais une dll en C, mais je voulais éviter cela pour ce projet en particulier.
Pour établir une comparaison, j'ai mesuré les performances de ma fonction: 10 mesures de 100 appels avec une chaine aléatoire de 65535 caractères.
Résultat: 37 millisecondes par appel de fonction.
Si on peut faire en dessous de 10 millisecondes, je prends :-) Sinon, je fais une Dll :-(
Y a t-il une contrainte qui t'empêche d'utiliser l'API CopyMemory ?
-- Cordialement,
Jacques.
Jean-Marc
"Jacques93" a écrit dans le message de news:%
Bonour Jean-Marc, Jean-Marc a écrit : > Bonjour chers collègues,
> ' s : une chaine > ' szt : la longuue de cette chaine > ' t() : le tableau de byte à remplir > Function CvrtStr2ByteArray(ByVal s As String, _ > ByVal szt As Long, _ > ByRef t() As Byte) As Boolean > Dim i As Long > Dim c As String > > For i = 1 To szt > c = Mid$(s, i, 1) > If LenB(c) = 0 Then > t(i - 1) = CByte(0) > Else > t(i - 1) = CByte(Asc(c)) > End If > Next i > CvrtStr2ByteArray = True > End Function
> Pour établir une comparaison, j'ai mesuré les performances de > ma fonction: 10 mesures de 100 appels avec une chaine aléatoire > de 65535 caractères. > > Résultat: 37 millisecondes par appel de fonction. > > Si on peut faire en dessous de 10 millisecondes, je prends :-) > Sinon, je fais une Dll :-(
Hello Jacques,
Y a t-il une contrainte qui t'empêche d'utiliser l'API CopyMemory ?
Non, pas du tout. Comment utiliser CopyMemory dans ce cas? Je connais ceci: CopyMemory ByVal StrPtr(dest), ByVal StrPtr(src), LenB(dest)
Mais comment faire avec mon tableau de Byte? Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (pDst As Any, pSrc As Any, ByVal ByteLen As Long)
-- Jean-marc Tester mon serveur (VB6) => http://myjmnhome.dyndns.org "There are only 10 kind of people those who understand binary and those who don't." mailto: remove '_no_spam_' ;
"Jacques93" <jacques@Nospam> a écrit dans le message de
news:%23cgc4sAUGHA.5172@TK2MSFTNGP12.phx.gbl...
Bonour Jean-Marc,
Jean-Marc a écrit :
> Bonjour chers collègues,
> ' s : une chaine
> ' szt : la longuue de cette chaine
> ' t() : le tableau de byte à remplir
> Function CvrtStr2ByteArray(ByVal s As String, _
> ByVal szt As Long, _
> ByRef t() As Byte) As Boolean
> Dim i As Long
> Dim c As String
>
> For i = 1 To szt
> c = Mid$(s, i, 1)
> If LenB(c) = 0 Then
> t(i - 1) = CByte(0)
> Else
> t(i - 1) = CByte(Asc(c))
> End If
> Next i
> CvrtStr2ByteArray = True
> End Function
> Pour établir une comparaison, j'ai mesuré les performances de
> ma fonction: 10 mesures de 100 appels avec une chaine aléatoire
> de 65535 caractères.
>
> Résultat: 37 millisecondes par appel de fonction.
>
> Si on peut faire en dessous de 10 millisecondes, je prends :-)
> Sinon, je fais une Dll :-(
Hello Jacques,
Y a t-il une contrainte qui t'empêche d'utiliser l'API CopyMemory ?
Non, pas du tout. Comment utiliser CopyMemory dans ce cas?
Je connais ceci:
CopyMemory ByVal StrPtr(dest), ByVal StrPtr(src), LenB(dest)
Mais comment faire avec mon tableau de Byte?
Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (pDst As
Any, pSrc As Any, ByVal ByteLen As Long)
--
Jean-marc
Tester mon serveur (VB6) => http://myjmnhome.dyndns.org
"There are only 10 kind of people
those who understand binary and those who don't."
mailto: remove '_no_spam_' ; _no_spam_jean_marc_n2@yahoo.fr
Bonour Jean-Marc, Jean-Marc a écrit : > Bonjour chers collègues,
> ' s : une chaine > ' szt : la longuue de cette chaine > ' t() : le tableau de byte à remplir > Function CvrtStr2ByteArray(ByVal s As String, _ > ByVal szt As Long, _ > ByRef t() As Byte) As Boolean > Dim i As Long > Dim c As String > > For i = 1 To szt > c = Mid$(s, i, 1) > If LenB(c) = 0 Then > t(i - 1) = CByte(0) > Else > t(i - 1) = CByte(Asc(c)) > End If > Next i > CvrtStr2ByteArray = True > End Function
> Pour établir une comparaison, j'ai mesuré les performances de > ma fonction: 10 mesures de 100 appels avec une chaine aléatoire > de 65535 caractères. > > Résultat: 37 millisecondes par appel de fonction. > > Si on peut faire en dessous de 10 millisecondes, je prends :-) > Sinon, je fais une Dll :-(
Hello Jacques,
Y a t-il une contrainte qui t'empêche d'utiliser l'API CopyMemory ?
Non, pas du tout. Comment utiliser CopyMemory dans ce cas? Je connais ceci: CopyMemory ByVal StrPtr(dest), ByVal StrPtr(src), LenB(dest)
Mais comment faire avec mon tableau de Byte? Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (pDst As Any, pSrc As Any, ByVal ByteLen As Long)
-- Jean-marc Tester mon serveur (VB6) => http://myjmnhome.dyndns.org "There are only 10 kind of people those who understand binary and those who don't." mailto: remove '_no_spam_' ;
Jean-Marc
"Jean-Marc" a écrit dans le message de news:44254536$0$14127$
"Jacques93" a écrit dans le message de news:%
> Y a t-il une contrainte qui t'empêche d'utiliser l'API CopyMemory ?
Arf!!!! J'ai trouvé :-) C'était si simple!! CopyMemory t(0), ByVal StrPtr(s), l
Résultat des courses: C'est si rapide que je ne peux même pas mesurer, mais en tout cas c'est inférieur à 0.1 millisecondes par appel, c'est donc environ 400 fois plus rapide ....
Merci infiniment Jacques, et bon après-midi :-)
-- Jean-marc Tester mon serveur (VB6) => http://myjmnhome.dyndns.org "There are only 10 kind of people those who understand binary and those who don't." mailto: remove '_no_spam_' ;
"Jean-Marc" <NO_SPAM_jean_marc_n2@yahoo.fr> a écrit dans le message de
news:44254536$0$14127$ba620e4c@news.skynet.be...
"Jacques93" <jacques@Nospam> a écrit dans le message de
news:%23cgc4sAUGHA.5172@TK2MSFTNGP12.phx.gbl...
> Y a t-il une contrainte qui t'empêche d'utiliser l'API CopyMemory ?
Arf!!!!
J'ai trouvé :-)
C'était si simple!!
CopyMemory t(0), ByVal StrPtr(s), l
Résultat des courses: C'est si rapide que je ne peux même pas mesurer,
mais
en tout cas c'est inférieur à 0.1 millisecondes par appel, c'est donc
environ
400 fois plus rapide ....
Merci infiniment Jacques, et bon après-midi :-)
--
Jean-marc
Tester mon serveur (VB6) => http://myjmnhome.dyndns.org
"There are only 10 kind of people
those who understand binary and those who don't."
mailto: remove '_no_spam_' ; _no_spam_jean_marc_n2@yahoo.fr
"Jean-Marc" a écrit dans le message de news:44254536$0$14127$
"Jacques93" a écrit dans le message de news:%
> Y a t-il une contrainte qui t'empêche d'utiliser l'API CopyMemory ?
Arf!!!! J'ai trouvé :-) C'était si simple!! CopyMemory t(0), ByVal StrPtr(s), l
Résultat des courses: C'est si rapide que je ne peux même pas mesurer, mais en tout cas c'est inférieur à 0.1 millisecondes par appel, c'est donc environ 400 fois plus rapide ....
Merci infiniment Jacques, et bon après-midi :-)
-- Jean-marc Tester mon serveur (VB6) => http://myjmnhome.dyndns.org "There are only 10 kind of people those who understand binary and those who don't." mailto: remove '_no_spam_' ;
Jean-Marc
J'ai parlé trop vite :-(
Les 2 fonctions ne sont pas équivalentes, mais peut être est du à mon passage de paramètre. Avec copyMemory, je récupère en plus un 0 tous les 2 bytes dans le tableau.
voici pour être plus clair:
tba() est rempli avec ma fonction
for i=0 to 10:print tba(i); " ";:next i 72 84 84 80 47 49 46 48 32 50 48
tbb() est rempli avec copyMemory
for i=0 to 10:print tbb(i); " ";:next i 72 0 84 0 84 0 80 0 47 0 49
Comment faire ?
-- Jean-marc Tester mon serveur (VB6) => http://myjmnhome.dyndns.org "There are only 10 kind of people those who understand binary and those who don't." mailto: remove '_no_spam_' ;
J'ai parlé trop vite :-(
Les 2 fonctions ne sont pas équivalentes, mais peut être est du à mon
passage de paramètre.
Avec copyMemory, je récupère en plus un 0 tous les 2 bytes dans le
tableau.
voici pour être plus clair:
tba() est rempli avec ma fonction
for i=0 to 10:print tba(i); " ";:next i
72 84 84 80 47 49 46 48 32 50 48
tbb() est rempli avec copyMemory
for i=0 to 10:print tbb(i); " ";:next i
72 0 84 0 84 0 80 0 47 0 49
Comment faire ?
--
Jean-marc
Tester mon serveur (VB6) => http://myjmnhome.dyndns.org
"There are only 10 kind of people
those who understand binary and those who don't."
mailto: remove '_no_spam_' ; _no_spam_jean_marc_n2@yahoo.fr
Les 2 fonctions ne sont pas équivalentes, mais peut être est du à mon passage de paramètre. Avec copyMemory, je récupère en plus un 0 tous les 2 bytes dans le tableau.
voici pour être plus clair:
tba() est rempli avec ma fonction
for i=0 to 10:print tba(i); " ";:next i 72 84 84 80 47 49 46 48 32 50 48
tbb() est rempli avec copyMemory
for i=0 to 10:print tbb(i); " ";:next i 72 0 84 0 84 0 80 0 47 0 49
Comment faire ?
-- Jean-marc Tester mon serveur (VB6) => http://myjmnhome.dyndns.org "There are only 10 kind of people those who understand binary and those who don't." mailto: remove '_no_spam_' ;
Picalausa François
Hello,
Si tu copymemory(strconv("a",vbFromUnicode)), tu auras la description de caractère voulue (ANSI plutôt qu'UNICODE). Il ne faut pas oublier que VB stoque en interne les chaines en UNICODE et donc la conversion est nécessaire...
-- Picalausa François
"Jean-Marc" a écrit dans le message de news: 44254eef$0$1161$
J'ai parlé trop vite :-(
Les 2 fonctions ne sont pas équivalentes, mais peut être est du à mon passage de paramètre. Avec copyMemory, je récupère en plus un 0 tous les 2 bytes dans le tableau.
voici pour être plus clair:
tba() est rempli avec ma fonction
for i=0 to 10:print tba(i); " ";:next i 72 84 84 80 47 49 46 48 32 50 48
tbb() est rempli avec copyMemory
for i=0 to 10:print tbb(i); " ";:next i 72 0 84 0 84 0 80 0 47 0 49
Comment faire ?
-- Jean-marc Tester mon serveur (VB6) => http://myjmnhome.dyndns.org "There are only 10 kind of people those who understand binary and those who don't." mailto: remove '_no_spam_' ;
Hello,
Si tu copymemory(strconv("a",vbFromUnicode)), tu auras la description de
caractère voulue (ANSI plutôt qu'UNICODE).
Il ne faut pas oublier que VB stoque en interne les chaines en UNICODE et
donc la conversion est nécessaire...
--
Picalausa François
"Jean-Marc" <NO_SPAM_jean_marc_n2@yahoo.fr> a écrit dans le message de news:
44254eef$0$1161$ba620e4c@news.skynet.be...
J'ai parlé trop vite :-(
Les 2 fonctions ne sont pas équivalentes, mais peut être est du à mon
passage de paramètre.
Avec copyMemory, je récupère en plus un 0 tous les 2 bytes dans le
tableau.
voici pour être plus clair:
tba() est rempli avec ma fonction
for i=0 to 10:print tba(i); " ";:next i
72 84 84 80 47 49 46 48 32 50 48
tbb() est rempli avec copyMemory
for i=0 to 10:print tbb(i); " ";:next i
72 0 84 0 84 0 80 0 47 0 49
Comment faire ?
--
Jean-marc
Tester mon serveur (VB6) => http://myjmnhome.dyndns.org
"There are only 10 kind of people
those who understand binary and those who don't."
mailto: remove '_no_spam_' ; _no_spam_jean_marc_n2@yahoo.fr
Si tu copymemory(strconv("a",vbFromUnicode)), tu auras la description de caractère voulue (ANSI plutôt qu'UNICODE). Il ne faut pas oublier que VB stoque en interne les chaines en UNICODE et donc la conversion est nécessaire...
-- Picalausa François
"Jean-Marc" a écrit dans le message de news: 44254eef$0$1161$
J'ai parlé trop vite :-(
Les 2 fonctions ne sont pas équivalentes, mais peut être est du à mon passage de paramètre. Avec copyMemory, je récupère en plus un 0 tous les 2 bytes dans le tableau.
voici pour être plus clair:
tba() est rempli avec ma fonction
for i=0 to 10:print tba(i); " ";:next i 72 84 84 80 47 49 46 48 32 50 48
tbb() est rempli avec copyMemory
for i=0 to 10:print tbb(i); " ";:next i 72 0 84 0 84 0 80 0 47 0 49
Comment faire ?
-- Jean-marc Tester mon serveur (VB6) => http://myjmnhome.dyndns.org "There are only 10 kind of people those who understand binary and those who don't." mailto: remove '_no_spam_' ;
Picalausa François
Hello,
Il y a une technique très efficace qui consiste à mapper un SAFEARRAY sur ta string... Ceci évite de devoir allouer deux fois la mémoire (donc gain de temps) et de devoir recopier la chaine à chaque modification (ou d'effectuer les modification en double) puisqu'on travaille sur la même zone mémoire...
Reste à répéter : "Même en VB, je n'ai pas peur des pointeurs!" deux ou trois fois... ou pas!
Voici un bout de code illustrant la technique: Option Explicit
Private Type SAFEARRAYBOUND cElements As Long lLbound As Long End Type
Private Type SAFEARRAY cDims As Integer fFeatures As Integer cbElements As Long cLocks As Long pvData As Long End Type
Private Declare Function VarPtrArray _ Lib "msvbvm60.dll" _ Alias "VarPtr" _ ( _ Var() As Any _ ) _ As Long Private Declare Sub CopyMemory _ Lib "kernel32" _ Alias "RtlMoveMemory" _ ( _ ByRef Destination As Any, _ ByRef Source As Any, _ ByVal Length As Long _ )
Private opsa As Long 'pointeur vers la safearray précédente Private opvdata As Long 'pointeur vers les données précédentes Private osb As SAFEARRAYBOUND 'bornes précédentes du tableau
Private Function MapSafeArrrayToString(psa As Long, strText As String) As Boolean Dim sa As SAFEARRAY, vt As Long Dim sab As SAFEARRAYBOUND MapSafeArrrayToString = False
'Vérifie la validité des données en entrée If ((StrPtr(strText) <> 0) And (psa <> 0)) Then 'Vérifie qu'on a bien démappé précédemment If (opsa = 0) Then 'déférence le pointer Call CopyMemory(sa, ByVal psa, LenB(sa))
'Demande une array typée en 1D non lockée If ((sa.fFeatures And FADF_HAVEVARTYPE) And (sa.cDims = 1) And (sa.cLocks = 0)) Then 'Demande de plus que cette array soit typée As Byte ou As Integer CopyMemory vt, ByVal (psa - 4), LenB(vt) If (vt = VT_UI1) Then 'Enregistre les données actuelle du tableau opsa = psa opvdata = sa.pvData Call CopyMemory(osb, ByVal psa + LenB(sa), LenB(osb))
sa.pvData = StrPtr(strText) Call CopyMemory(ByVal psa, sa, LenB(sa))
MapSafeArrrayToString = True End If End If End If End If End Function
Private Function UnmapSafeArray() As Boolean Dim sa As SAFEARRAY, vt As Long Dim sab As SAFEARRAYBOUND UnmapSafeArray = False
'Vérifie la validité des données en entrée If (opsa <> 0) Then 'déférence le pointer Call CopyMemory(sa, ByVal opsa, LenB(sa))
'Restaure les données Call CopyMemory(ByVal opsa + LenB(sa), osb, LenB(osb)) sa.pvData = opvdata Call CopyMemory(ByVal opsa, sa, LenB(sa))
'Oublie tout de ce qui s'est passé opsa = 0 opvdata = 0 osb.cElements = 0 osb.lLbound = 0 End If End Function
Private Function GetPsa(PPSA As Long) As Long Call CopyMemory(GetPsa, ByVal PPSA, LenB(GetPsa)) End Function
Private Sub Form_Load() Dim Blah As String Dim byBlah() As Byte Dim i As Long
ReDim byBlah(0)
Blah = "Hello World!"
'ATTENTION : jusqu'à UnmapSafeArray, il est préférable que 'Blah ne sorte jamais du scope If MapSafeArrrayToString(GetPsa(VarPtrArray(byBlah)), Blah) Then For i = LBound(byBlah) To UBound(byBlah) Debug.Print Chr$(byBlah(i)) Next i
UnmapSafeArray End If End Sub
-- Picalausa François
"Jean-Marc" a écrit dans le message de news: 4425260b$0$11427$
Bonjour chers collègues,
j'ai un besoin précis d'optimisation: Je dois convertir une chaine en un table de Bytes.
J'ai écrit cette fonction, qui fonctionne très bien:
' s : une chaine ' szt : la longuue de cette chaine ' t() : le tableau de byte à remplir Function CvrtStr2ByteArray(ByVal s As String, _ ByVal szt As Long, _ ByRef t() As Byte) As Boolean Dim i As Long Dim c As String
For i = 1 To szt c = Mid$(s, i, 1) If LenB(c) = 0 Then t(i - 1) = CByte(0) Else t(i - 1) = CByte(Asc(c)) End If Next i CvrtStr2ByteArray = True End Function
Connaitriez vous un moyen de faire cela, mais plus rapidement que ne le fait cette implémentation naïve. J'ai ici un vrai besoin d'optimisation, car cette fonction est un facteur limitant dans un de mes programmes (Rabbit) Note: la chaine en paramètre peut être très longeur (jusqu'à plusieurs centaines de K) et j'appelle parfois cette fonction plusieurs milliers de fois consécutivement. Si vous aviez un moyen efficace, je suis preneur, sinon je ferais une dll en C, mais je voulais éviter cela pour ce projet en particulier.
Pour établir une comparaison, j'ai mesuré les performances de ma fonction: 10 mesures de 100 appels avec une chaine aléatoire de 65535 caractères.
Résultat: 37 millisecondes par appel de fonction.
Si on peut faire en dessous de 10 millisecondes, je prends :-) Sinon, je fais une Dll :-(
-- Jean-marc Tester mon serveur (VB6) => http://myjmnhome.dyndns.org "There are only 10 kind of people those who understand binary and those who don't." mailto: remove '_no_spam_' ;
Hello,
Il y a une technique très efficace qui consiste à mapper un SAFEARRAY sur ta
string...
Ceci évite de devoir allouer deux fois la mémoire (donc gain de temps) et de
devoir recopier la chaine à chaque modification (ou d'effectuer les
modification en double) puisqu'on travaille sur la même zone mémoire...
Reste à répéter : "Même en VB, je n'ai pas peur des pointeurs!" deux ou
trois fois... ou pas!
Voici un bout de code illustrant la technique:
Option Explicit
Private Type SAFEARRAYBOUND
cElements As Long
lLbound As Long
End Type
Private Type SAFEARRAY
cDims As Integer
fFeatures As Integer
cbElements As Long
cLocks As Long
pvData As Long
End Type
Private Declare Function VarPtrArray _
Lib "msvbvm60.dll" _
Alias "VarPtr" _
( _
Var() As Any _
) _
As Long
Private Declare Sub CopyMemory _
Lib "kernel32" _
Alias "RtlMoveMemory" _
( _
ByRef Destination As Any, _
ByRef Source As Any, _
ByVal Length As Long _
)
Private opsa As Long 'pointeur vers la safearray précédente
Private opvdata As Long 'pointeur vers les données précédentes
Private osb As SAFEARRAYBOUND 'bornes précédentes du tableau
Private Function MapSafeArrrayToString(psa As Long, strText As String) As
Boolean
Dim sa As SAFEARRAY, vt As Long
Dim sab As SAFEARRAYBOUND
MapSafeArrrayToString = False
'Vérifie la validité des données en entrée
If ((StrPtr(strText) <> 0) And (psa <> 0)) Then
'Vérifie qu'on a bien démappé précédemment
If (opsa = 0) Then
'déférence le pointer
Call CopyMemory(sa, ByVal psa, LenB(sa))
'Demande une array typée en 1D non lockée
If ((sa.fFeatures And FADF_HAVEVARTYPE) And (sa.cDims = 1) And
(sa.cLocks = 0)) Then
'Demande de plus que cette array soit typée As Byte ou As
Integer
CopyMemory vt, ByVal (psa - 4), LenB(vt)
If (vt = VT_UI1) Then
'Enregistre les données actuelle du tableau
opsa = psa
opvdata = sa.pvData
Call CopyMemory(osb, ByVal psa + LenB(sa), LenB(osb))
sa.pvData = StrPtr(strText)
Call CopyMemory(ByVal psa, sa, LenB(sa))
MapSafeArrrayToString = True
End If
End If
End If
End If
End Function
Private Function UnmapSafeArray() As Boolean
Dim sa As SAFEARRAY, vt As Long
Dim sab As SAFEARRAYBOUND
UnmapSafeArray = False
'Vérifie la validité des données en entrée
If (opsa <> 0) Then
'déférence le pointer
Call CopyMemory(sa, ByVal opsa, LenB(sa))
'Restaure les données
Call CopyMemory(ByVal opsa + LenB(sa), osb, LenB(osb))
sa.pvData = opvdata
Call CopyMemory(ByVal opsa, sa, LenB(sa))
'Oublie tout de ce qui s'est passé
opsa = 0
opvdata = 0
osb.cElements = 0
osb.lLbound = 0
End If
End Function
Private Function GetPsa(PPSA As Long) As Long
Call CopyMemory(GetPsa, ByVal PPSA, LenB(GetPsa))
End Function
Private Sub Form_Load()
Dim Blah As String
Dim byBlah() As Byte
Dim i As Long
ReDim byBlah(0)
Blah = "Hello World!"
'ATTENTION : jusqu'à UnmapSafeArray, il est préférable que
'Blah ne sorte jamais du scope
If MapSafeArrrayToString(GetPsa(VarPtrArray(byBlah)), Blah) Then
For i = LBound(byBlah) To UBound(byBlah)
Debug.Print Chr$(byBlah(i))
Next i
UnmapSafeArray
End If
End Sub
--
Picalausa François
"Jean-Marc" <NO_SPAM_jean_marc_n2@yahoo.fr> a écrit dans le message de news:
4425260b$0$11427$ba620e4c@news.skynet.be...
Bonjour chers collègues,
j'ai un besoin précis d'optimisation: Je dois convertir
une chaine en un table de Bytes.
J'ai écrit cette fonction, qui fonctionne très bien:
' s : une chaine
' szt : la longuue de cette chaine
' t() : le tableau de byte à remplir
Function CvrtStr2ByteArray(ByVal s As String, _
ByVal szt As Long, _
ByRef t() As Byte) As Boolean
Dim i As Long
Dim c As String
For i = 1 To szt
c = Mid$(s, i, 1)
If LenB(c) = 0 Then
t(i - 1) = CByte(0)
Else
t(i - 1) = CByte(Asc(c))
End If
Next i
CvrtStr2ByteArray = True
End Function
Connaitriez vous un moyen de faire cela, mais plus rapidement
que ne le fait cette implémentation naïve.
J'ai ici un vrai besoin d'optimisation, car cette fonction est
un facteur limitant dans un de mes programmes (Rabbit)
Note: la chaine en paramètre peut être très longeur (jusqu'à
plusieurs centaines de K) et j'appelle parfois cette fonction
plusieurs milliers de fois consécutivement.
Si vous aviez un moyen efficace, je suis preneur, sinon je ferais
une dll en C, mais je voulais éviter cela pour ce projet en
particulier.
Pour établir une comparaison, j'ai mesuré les performances de
ma fonction: 10 mesures de 100 appels avec une chaine aléatoire
de 65535 caractères.
Résultat: 37 millisecondes par appel de fonction.
Si on peut faire en dessous de 10 millisecondes, je prends :-)
Sinon, je fais une Dll :-(
--
Jean-marc
Tester mon serveur (VB6) => http://myjmnhome.dyndns.org
"There are only 10 kind of people
those who understand binary and those who don't."
mailto: remove '_no_spam_' ; _no_spam_jean_marc_n2@yahoo.fr
Il y a une technique très efficace qui consiste à mapper un SAFEARRAY sur ta string... Ceci évite de devoir allouer deux fois la mémoire (donc gain de temps) et de devoir recopier la chaine à chaque modification (ou d'effectuer les modification en double) puisqu'on travaille sur la même zone mémoire...
Reste à répéter : "Même en VB, je n'ai pas peur des pointeurs!" deux ou trois fois... ou pas!
Voici un bout de code illustrant la technique: Option Explicit
Private Type SAFEARRAYBOUND cElements As Long lLbound As Long End Type
Private Type SAFEARRAY cDims As Integer fFeatures As Integer cbElements As Long cLocks As Long pvData As Long End Type
Private Declare Function VarPtrArray _ Lib "msvbvm60.dll" _ Alias "VarPtr" _ ( _ Var() As Any _ ) _ As Long Private Declare Sub CopyMemory _ Lib "kernel32" _ Alias "RtlMoveMemory" _ ( _ ByRef Destination As Any, _ ByRef Source As Any, _ ByVal Length As Long _ )
Private opsa As Long 'pointeur vers la safearray précédente Private opvdata As Long 'pointeur vers les données précédentes Private osb As SAFEARRAYBOUND 'bornes précédentes du tableau
Private Function MapSafeArrrayToString(psa As Long, strText As String) As Boolean Dim sa As SAFEARRAY, vt As Long Dim sab As SAFEARRAYBOUND MapSafeArrrayToString = False
'Vérifie la validité des données en entrée If ((StrPtr(strText) <> 0) And (psa <> 0)) Then 'Vérifie qu'on a bien démappé précédemment If (opsa = 0) Then 'déférence le pointer Call CopyMemory(sa, ByVal psa, LenB(sa))
'Demande une array typée en 1D non lockée If ((sa.fFeatures And FADF_HAVEVARTYPE) And (sa.cDims = 1) And (sa.cLocks = 0)) Then 'Demande de plus que cette array soit typée As Byte ou As Integer CopyMemory vt, ByVal (psa - 4), LenB(vt) If (vt = VT_UI1) Then 'Enregistre les données actuelle du tableau opsa = psa opvdata = sa.pvData Call CopyMemory(osb, ByVal psa + LenB(sa), LenB(osb))
sa.pvData = StrPtr(strText) Call CopyMemory(ByVal psa, sa, LenB(sa))
MapSafeArrrayToString = True End If End If End If End If End Function
Private Function UnmapSafeArray() As Boolean Dim sa As SAFEARRAY, vt As Long Dim sab As SAFEARRAYBOUND UnmapSafeArray = False
'Vérifie la validité des données en entrée If (opsa <> 0) Then 'déférence le pointer Call CopyMemory(sa, ByVal opsa, LenB(sa))
'Restaure les données Call CopyMemory(ByVal opsa + LenB(sa), osb, LenB(osb)) sa.pvData = opvdata Call CopyMemory(ByVal opsa, sa, LenB(sa))
'Oublie tout de ce qui s'est passé opsa = 0 opvdata = 0 osb.cElements = 0 osb.lLbound = 0 End If End Function
Private Function GetPsa(PPSA As Long) As Long Call CopyMemory(GetPsa, ByVal PPSA, LenB(GetPsa)) End Function
Private Sub Form_Load() Dim Blah As String Dim byBlah() As Byte Dim i As Long
ReDim byBlah(0)
Blah = "Hello World!"
'ATTENTION : jusqu'à UnmapSafeArray, il est préférable que 'Blah ne sorte jamais du scope If MapSafeArrrayToString(GetPsa(VarPtrArray(byBlah)), Blah) Then For i = LBound(byBlah) To UBound(byBlah) Debug.Print Chr$(byBlah(i)) Next i
UnmapSafeArray End If End Sub
-- Picalausa François
"Jean-Marc" a écrit dans le message de news: 4425260b$0$11427$
Bonjour chers collègues,
j'ai un besoin précis d'optimisation: Je dois convertir une chaine en un table de Bytes.
J'ai écrit cette fonction, qui fonctionne très bien:
' s : une chaine ' szt : la longuue de cette chaine ' t() : le tableau de byte à remplir Function CvrtStr2ByteArray(ByVal s As String, _ ByVal szt As Long, _ ByRef t() As Byte) As Boolean Dim i As Long Dim c As String
For i = 1 To szt c = Mid$(s, i, 1) If LenB(c) = 0 Then t(i - 1) = CByte(0) Else t(i - 1) = CByte(Asc(c)) End If Next i CvrtStr2ByteArray = True End Function
Connaitriez vous un moyen de faire cela, mais plus rapidement que ne le fait cette implémentation naïve. J'ai ici un vrai besoin d'optimisation, car cette fonction est un facteur limitant dans un de mes programmes (Rabbit) Note: la chaine en paramètre peut être très longeur (jusqu'à plusieurs centaines de K) et j'appelle parfois cette fonction plusieurs milliers de fois consécutivement. Si vous aviez un moyen efficace, je suis preneur, sinon je ferais une dll en C, mais je voulais éviter cela pour ce projet en particulier.
Pour établir une comparaison, j'ai mesuré les performances de ma fonction: 10 mesures de 100 appels avec une chaine aléatoire de 65535 caractères.
Résultat: 37 millisecondes par appel de fonction.
Si on peut faire en dessous de 10 millisecondes, je prends :-) Sinon, je fais une Dll :-(
-- Jean-marc Tester mon serveur (VB6) => http://myjmnhome.dyndns.org "There are only 10 kind of people those who understand binary and those who don't." mailto: remove '_no_spam_' ;
Jacques93
Jean-Marc a écrit :
J'ai parlé trop vite :-(
Les 2 fonctions ne sont pas équivalentes, mais peut être est du à mon passage de paramètre. Avec copyMemory, je récupère en plus un 0 tous les 2 bytes dans le tableau.
voici pour être plus clair:
tba() est rempli avec ma fonction
for i=0 to 10:print tba(i); " ";:next i 72 84 84 80 47 49 46 48 32 50 48
tbb() est rempli avec copyMemory
for i=0 to 10:print tbb(i); " ";:next i 72 0 84 0 84 0 80 0 47 0 49
Comment faire ?
En faisant :
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" _ (Destination As Any, _ Source As Any, _ ByVal Length As Long)
Function CvrtStr2ByteArray(ByRef s As String, _ ByVal szt As Long, _ ByRef t() As Byte) As Boolean CopyMemory t(0), ByVal s, szt
CvrtStr2ByteArray = True End Function
Pour moi c'est OK.
-- Cordialement,
Jacques.
Jean-Marc a écrit :
J'ai parlé trop vite :-(
Les 2 fonctions ne sont pas équivalentes, mais peut être est du à mon
passage de paramètre.
Avec copyMemory, je récupère en plus un 0 tous les 2 bytes dans le
tableau.
voici pour être plus clair:
tba() est rempli avec ma fonction
for i=0 to 10:print tba(i); " ";:next i
72 84 84 80 47 49 46 48 32 50 48
tbb() est rempli avec copyMemory
for i=0 to 10:print tbb(i); " ";:next i
72 0 84 0 84 0 80 0 47 0 49
Comment faire ?
En faisant :
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" _
(Destination As Any, _
Source As Any, _
ByVal Length As Long)
Function CvrtStr2ByteArray(ByRef s As String, _
ByVal szt As Long, _
ByRef t() As Byte) As Boolean
CopyMemory t(0), ByVal s, szt
Les 2 fonctions ne sont pas équivalentes, mais peut être est du à mon passage de paramètre. Avec copyMemory, je récupère en plus un 0 tous les 2 bytes dans le tableau.
voici pour être plus clair:
tba() est rempli avec ma fonction
for i=0 to 10:print tba(i); " ";:next i 72 84 84 80 47 49 46 48 32 50 48
tbb() est rempli avec copyMemory
for i=0 to 10:print tbb(i); " ";:next i 72 0 84 0 84 0 80 0 47 0 49
Comment faire ?
En faisant :
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" _ (Destination As Any, _ Source As Any, _ ByVal Length As Long)
Function CvrtStr2ByteArray(ByRef s As String, _ ByVal szt As Long, _ ByRef t() As Byte) As Boolean CopyMemory t(0), ByVal s, szt
CvrtStr2ByteArray = True End Function
Pour moi c'est OK.
-- Cordialement,
Jacques.
Jacques93
Bonjour Picalausa François, Picalausa François a écrit :
Hello,
Si tu copymemory(strconv("a",vbFromUnicode)), tu auras la description de caractère voulue (ANSI plutôt qu'UNICODE). Il ne faut pas oublier que VB stoque en interne les chaines en UNICODE et donc la conversion est nécessaire...
Cette conversion n'est elle pas implicite, notamment lors de l'appel aux API ?
Il me semble que c'est lorsque qu'une API renvoie une chaîne Unicode qu'il faut faire une conversion explicite.
Il y a peut être aussi la manière de déclarer les paramètres de l'API qui a son importance :
As Any
ou
As String
-- Cordialement,
Jacques.
Bonjour Picalausa François,
Picalausa François a écrit :
Hello,
Si tu copymemory(strconv("a",vbFromUnicode)), tu auras la description de
caractère voulue (ANSI plutôt qu'UNICODE).
Il ne faut pas oublier que VB stoque en interne les chaines en UNICODE et
donc la conversion est nécessaire...
Cette conversion n'est elle pas implicite, notamment lors de l'appel aux
API ?
Il me semble que c'est lorsque qu'une API renvoie une chaîne Unicode
qu'il faut faire une conversion explicite.
Il y a peut être aussi la manière de déclarer les paramètres de l'API
qui a son importance :
Bonjour Picalausa François, Picalausa François a écrit :
Hello,
Si tu copymemory(strconv("a",vbFromUnicode)), tu auras la description de caractère voulue (ANSI plutôt qu'UNICODE). Il ne faut pas oublier que VB stoque en interne les chaines en UNICODE et donc la conversion est nécessaire...
Cette conversion n'est elle pas implicite, notamment lors de l'appel aux API ?
Il me semble que c'est lorsque qu'une API renvoie une chaîne Unicode qu'il faut faire une conversion explicite.
Il y a peut être aussi la manière de déclarer les paramètres de l'API qui a son importance :
As Any
ou
As String
-- Cordialement,
Jacques.
Picalausa François
"Jacques93" a écrit dans le message de news: %
Bonjour Picalausa François, Picalausa François a écrit :
Hello,
Si tu copymemory(strconv("a",vbFromUnicode)), tu auras la description de caractère voulue (ANSI plutôt qu'UNICODE). Il ne faut pas oublier que VB stoque en interne les chaines en UNICODE et donc la conversion est nécessaire...
Cette conversion n'est elle pas implicite, notamment lors de l'appel aux API ?
Il me semble que c'est lorsque qu'une API renvoie une chaîne Unicode qu'il faut faire une conversion explicite.
Il y a peut être aussi la manière de déclarer les paramètres de l'API qui a son importance :
As Any
ou
As String
Hello,
Tu as tout à fait raison, je m'est trompé sur ce coup... je pensais au passage As Long + StrPtr (qui lui peut poser problème)
-- Picalausa François
"Jacques93" <jacques@Nospam> a écrit dans le message de news:
%23Ih9dpBUGHA.4520@TK2MSFTNGP10.phx.gbl...
Bonjour Picalausa François,
Picalausa François a écrit :
Hello,
Si tu copymemory(strconv("a",vbFromUnicode)), tu auras la description de
caractère voulue (ANSI plutôt qu'UNICODE).
Il ne faut pas oublier que VB stoque en interne les chaines en UNICODE et
donc la conversion est nécessaire...
Cette conversion n'est elle pas implicite, notamment lors de l'appel aux
API ?
Il me semble que c'est lorsque qu'une API renvoie une chaîne Unicode qu'il
faut faire une conversion explicite.
Il y a peut être aussi la manière de déclarer les paramètres de l'API qui
a son importance :
As Any
ou
As String
Hello,
Tu as tout à fait raison, je m'est trompé sur ce coup... je pensais au
passage As Long + StrPtr (qui lui peut poser problème)
Bonjour Picalausa François, Picalausa François a écrit :
Hello,
Si tu copymemory(strconv("a",vbFromUnicode)), tu auras la description de caractère voulue (ANSI plutôt qu'UNICODE). Il ne faut pas oublier que VB stoque en interne les chaines en UNICODE et donc la conversion est nécessaire...
Cette conversion n'est elle pas implicite, notamment lors de l'appel aux API ?
Il me semble que c'est lorsque qu'une API renvoie une chaîne Unicode qu'il faut faire une conversion explicite.
Il y a peut être aussi la manière de déclarer les paramètres de l'API qui a son importance :
As Any
ou
As String
Hello,
Tu as tout à fait raison, je m'est trompé sur ce coup... je pensais au passage As Long + StrPtr (qui lui peut poser problème)
-- Picalausa François
Jacques93
Picalausa François a écrit :
"Jacques93" a écrit dans le message de news: %
Bonjour Picalausa François, Picalausa François a écrit :
Hello,
Si tu copymemory(strconv("a",vbFromUnicode)), tu auras la description de caractère voulue (ANSI plutôt qu'UNICODE). Il ne faut pas oublier que VB stoque en interne les chaines en UNICODE et donc la conversion est nécessaire...
Cette conversion n'est elle pas implicite, notamment lors de l'appel aux API ?
Il me semble que c'est lorsque qu'une API renvoie une chaîne Unicode qu'il faut faire une conversion explicite.
Il y a peut être aussi la manière de déclarer les paramètres de l'API qui a son importance :
As Any
ou
As String
Hello,
Tu as tout à fait raison, je m'est trompé sur ce coup... je pensais au passage As Long + StrPtr (qui lui peut poser problème)
Sieste trop courte ? fais gaffe, en plus on perd une heure cette nuit.
:-D
-- Cordialement,
Jacques.
Picalausa François a écrit :
"Jacques93" <jacques@Nospam> a écrit dans le message de news:
%23Ih9dpBUGHA.4520@TK2MSFTNGP10.phx.gbl...
Bonjour Picalausa François,
Picalausa François a écrit :
Hello,
Si tu copymemory(strconv("a",vbFromUnicode)), tu auras la description de
caractère voulue (ANSI plutôt qu'UNICODE).
Il ne faut pas oublier que VB stoque en interne les chaines en UNICODE et
donc la conversion est nécessaire...
Cette conversion n'est elle pas implicite, notamment lors de l'appel aux
API ?
Il me semble que c'est lorsque qu'une API renvoie une chaîne Unicode qu'il
faut faire une conversion explicite.
Il y a peut être aussi la manière de déclarer les paramètres de l'API qui
a son importance :
As Any
ou
As String
Hello,
Tu as tout à fait raison, je m'est trompé sur ce coup... je pensais au
passage As Long + StrPtr (qui lui peut poser problème)
Sieste trop courte ? fais gaffe, en plus on perd une heure cette nuit.
Bonjour Picalausa François, Picalausa François a écrit :
Hello,
Si tu copymemory(strconv("a",vbFromUnicode)), tu auras la description de caractère voulue (ANSI plutôt qu'UNICODE). Il ne faut pas oublier que VB stoque en interne les chaines en UNICODE et donc la conversion est nécessaire...
Cette conversion n'est elle pas implicite, notamment lors de l'appel aux API ?
Il me semble que c'est lorsque qu'une API renvoie une chaîne Unicode qu'il faut faire une conversion explicite.
Il y a peut être aussi la manière de déclarer les paramètres de l'API qui a son importance :
As Any
ou
As String
Hello,
Tu as tout à fait raison, je m'est trompé sur ce coup... je pensais au passage As Long + StrPtr (qui lui peut poser problème)
Sieste trop courte ? fais gaffe, en plus on perd une heure cette nuit.