[ Shejn @ 10.09.2010. 06:57 ] @
Dobar dan,
imam problem sa brzinom izvrsavanja koda, pa bih zamolio ako neko moze da me posavetuje.

Opis problema
Potrebno je konvertovati relativno veliki niz unsigned char( ~ 200k) u CString. Kada je niz mali ~1000, funkcija radi dobro, ali kako raste niz tako se i funkcija usporava .. i to, cini mi se eksponencijalno.

Kod
U pitanju je jedna funkcija, koja manje-vise izgleda ovako:
Code:
CString convert(unsigned char const* in_buff, unsigned int in_len) 
{
      CString retValue(' ', in_len);

      while(in_len--)
      {
             retValue += *(in_buff++); //ovaj deo je problem
      }

      return retValue; 

}



Pitanje
Da li ova funkcija moze da se ubrza?


Hvala
[ X Files @ 10.09.2010. 07:43 ] @
Nemam na ovoj masini instaliran VC (a i odavno ne koristim MFC), pa ne znam koliko cu ti biti od pomoci. Ipak, da pokusam dok ti se ne jave MFC majstori :)

Na osnovu nekog iskustva, ovo u petlji:
Code:

retValue += *(in_buff++); //ovaj deo je problem

... ne valja, jer pretpostavljam da se svaki put interno alocira "privremeni objekat" za sabiranje, koji je svaki put sve veci i veci, pa otuda i pomenuto "eksponencijalno" usporenje, sto je na 200K podataka vec ozbiljno.

Ako vec ne postoji direktno konvertovanje iz "unsigned char*" u CString (sto zaljucujem jer pitas :d) onda pokusaj neku akrobaciju sa:
1. ALOKACIJA: CString.GetBuffer(velicina_buffera)
2. KOPIRANJE iz unsigned char*: memcpy() ili CopyMemory() // pokusaj i sa strncpy, mada mislim da ona radi samo sa "char*"
3. OSLOBADJANJE: CString.ReleaseBuffer(velicina_buffera)

Ipak, još jednom razmisli o finalnom dizajnu te funkcije, tj. da li da funkcija vraca CString ili pokazivac na CString, s obzirom da se radi o 200K podataka.


EDIT: Ili modifikuj postojeci kod tako da koristi AppendChar(), mozda bude razlike.

[Ovu poruku je menjao X Files dana 10.09.2010. u 09:02 GMT+1]
[ Shejn @ 10.09.2010. 08:13 ] @
Hvala na brzom odgovoru.

Mozda gresim, ali zar nije memorija alocirana na pocetku sa: CString retValue(' ', in_len) ?

.. retValue ce na kraju biti duzine in_len.
[ X Files @ 10.09.2010. 08:27 ] @
Kad bolje pogledam, pitam se da li ono inicijalno alociranje "CString retValue(' ', in_len);" uopste ima smisla, jer dodavanje (+=) svakako mora da vodi racuna o realokaciji.

Sto se tice operacije += za dodavanje novog znaka, mislim da se svaki put interno alocira ceo prethodni sadrzaj da bi izvrsilo dodavanje, pa se to vraca u objekat.
[ Mali Misha @ 10.09.2010. 08:34 ] @
Prema ovome bi trebalo da CString čak ima konstruktor koji preuzima unsigned char*.

http://msdn.microsoft.com/ja-jp/library/ms928949.aspx

Da li si probao ovako:
Code:
CString convert(unsigned char const* in_buff, unsigned int in_len) 
{ return CString(in_buff); }

Rekao bih da ovo očekuje string sa null-om na kraju.
[ deerbeer @ 10.09.2010. 08:34 ] @
Ja koristim uvek GetBuffer , Copy .., ReleaseBuffer i nisam imao nikad problema ...
To je u principu standardno resenje u MFC-u za ovakve stvari ..
[ Shejn @ 10.09.2010. 08:50 ] @
@deerbeer
da li bi mogao da postavis neki primer .. posto kazes da si vec ovako nesto radio?

Hvala.
[ deerbeer @ 10.09.2010. 09:17 ] @
Pa ovako nesto probaj :
Code:

CStringA retValue;
unsigned char* msg=(unsigned char*)retValue.GetBuffer();
memcpy(msg,in_buff, in_len) ; 
retValue.ReleaseBuffer() ; 


Eh , da probaj i primer sto je postavio @Mali Misha trebao bi da radi : (zaboravih da postoji taj konstruktor :)
s tim sto bi niz trebao da bude null-terminated
[ Mihajlo Cvetanović @ 10.09.2010. 09:33 ] @
Dodatak na post Malog Mishe, postoji i konstruktor koji uzima i pointer na bafer i dužinu bafera, pa bafer ne mora da bude NUL terminisan.

Code:
CString convert(unsigned char const* in_buff, unsigned int in_len) 
{
  return CString((char*)in_buff, in_len);
}


Ovo je najefikasniji i najbrži način.
[ Nedeljko @ 10.09.2010. 09:42 ] @
@deerbeer

Kod mene tvoj program puca, ali se to eliminiše konstruktorom

CStringA retValue(' ', in_len);

Međutim, šta ako njemu treba CString, a ne CStringA (pitanje je tako i postavljeno). Tada ovo sa memcpy ne pije vodu jer se dobijaju kineska slova.

Ovo je univerzalno

Code:
CString convert(unsigned char const* in_buff, unsigned int in_len) 
    CString retValue(' ', in_len);
    TCHAR *buff = retValue.GetBuffer(); 

    for (int i = 0; i < in_len; ++i) {
        buff[i] = in_buff[i];
    }

    retValue.ReleaseBuffer();
    return retValue;
}


Što se tiče predloga Malog Miše, on radi ako u baferu posle in_len znakova dolayi nula (terminator). No, u tom slučaju mu ne bi trebao in_len.
[ Nedeljko @ 10.09.2010. 09:44 ] @
Citat:
Shejn: Kada je niz mali ~1000, funkcija radi dobro, ali kako raste niz tako se i funkcija usporava .. i to, cini mi se eksponencijalno.


Kvadratno. Da je eksponencijalno, ne bi ti dočekao kraj ni za 100 znakova.
[ Nedeljko @ 10.09.2010. 09:45 ] @
Citat:
Mihajlo Cvetanović: Dodatak na post Malog Mishe, postoji i konstruktor koji uzima i pointer na bafer i dužinu bafera, pa bafer ne mora da bude NUL terminisan.

Code:
CString convert(unsigned char const* in_buff, unsigned int in_len) 
{
  return CString((char*)in_buff, in_len);
}


Ovo je najefikasniji i najbrži način.


E, da, ovo je najbolje.
[ deerbeer @ 10.09.2010. 09:52 ] @
Citat:

Međutim, šta ako njemu treba CString, a ne CStringA (pitanje je tako i postavljeno). Tada ovo sa memcpy ne pije vodu jer se dobijaju kineska slova.

Tacno , ali ako mu je ANSI bild u konfiguraciji a nije napomenuo onda je CString = CStringA
[ Shejn @ 10.09.2010. 09:54 ] @
Citat:
Nedeljko:

Ovo je univerzalno

Code:
CString convert(unsigned char const* in_buff, unsigned int in_len) 
    CString retValue(' ', in_len);
    TCHAR *buff = retValue.GetBuffer(); 

    for (int i = 0; i < in_len; ++i) {
        buff[i] = in_buff[i];
    }

    retValue.ReleaseBuffer();
    return retValue;
}



ovo mi se nakako najbolje uklapa .. jedino sto moram staviti i velicinu buffera kod alociranja
Code:

    TCHAR *buff = retValue.GetBuffer(in_len); 


bez toga mi prijavljuje gresku
error C2660: 'GetBuffer' : function does not take 0 parameters
[ Mihajlo Cvetanović @ 10.09.2010. 10:12 ] @
Nema potrebe to da radiš, nema potrebe da funkcija ima više od jedne linije koda. Već sam napisao, ali možda ti je promaklo. Ovo je najbrži i najefikasniji kod:
Code:
CString convert(unsigned char const* in_buff, unsigned int in_len) 
{
  return CString((char*)in_buff, in_len);
}

[ Nedeljko @ 10.09.2010. 12:07 ] @
Da. Najbolje je ovo što Mihajlo Cvetanović kaže.
[ Shejn @ 13.09.2010. 08:24 ] @
Hvala puno na pomoci, savetima i predlozima.
Prihvacen je predlog koji je dao Mihajlo Cvetanović.


Izvinjavam sto nisam odmah odgovorio ..