Delphi-PRAXiS
Seite 2 von 3     12 3      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Sonstige Fragen zu Delphi (https://www.delphipraxis.net/19-sonstige-fragen-zu-delphi/)
-   -   Optimallösung gesucht: Little Endian <-> Big Endian (https://www.delphipraxis.net/113353-optimalloesung-gesucht-little-endian-big-endian.html)

FAlter 6. Mai 2008 19:27

Re: Optimallösung gesucht: Little Endian <-> Big Endia
 
Hi,

danke. Ein kleiner Fehler: Es heißt UCS4String statt USC4String (war plötzlich ne rote Wellenlinie da).

Wie ich an deinem Code erkennen kann, werden wirklich Zeiger auf die Zeiger übergeben. Aber jetzt ist die Frage ja nicht mehr nötig. Zumindest, wenn es läuft - werds gleich mal testen.

Mfg
FAlter

[edit] Scheint zu funktionieren - und ich versteh sogar was, ist also nicht zu kompliziert geworden! :D [/edit]

himitsu 6. Mai 2008 19:44

Re: Optimallösung gesucht: Little Endian <-> Big Endia
 
ups: nja, hatte die UCS4String-Version ohne zu testen (um)geschrieben :angel2:

PS: das "SHR 1" ist ein schnelles "div 2"
und es ist nötig, da die OleStr (ole32.dll) die Länge in Byte angibt.

und bei USC4 nicht, da Delphi bei seinen dynamischen Arrays (String, WideString, dynArray und Co.) die Anzahl der Elemente/Chars

PS: in FTypes.pas schau dir mal den Abschnitt "Compiler Intern Data-Types" (ab Zeile 1213) an
http://www.delphipraxis.net/internal...=879295#879295



bei "SwapString(Var S: WideString);" könnte man jetzt noch jeweils 2 Chars via BSWAP zusammen verarbeiten

FAlter 6. Mai 2008 19:57

Re: Optimallösung gesucht: Little Endian <-> Big Endia
 
Hi,

Zitat:

Zitat von himitsu
PS: das "SHR 1" ist ein schnelles "div 2"

Ich weiß. Ich sag ja, ich versteh sie sogar :)

Zitat:

und es ist nötig, da die OleStr (ole32.dll) die Länge in Byte angibt.
Gut zu wissen.

Zitat:

PS: in FTypes.pas schau dir mal den Abschnitt "Compiler Intern Data-Types" (ab Zeile 1213) an
http://www.delphipraxis.net/internal...=879295#879295
Kann ich ja mal machen. :)


Zitat:

bei "SwapString(Var S: WideString);" könnte man jetzt noch jeweils 2 Chars via BSWAP zusammen verarbeiten
Macht BSwap nicht aus 01 02 | 03 04 ein 04 03 | 02 01? Wenn man da zwei 16-Bit-Werte zusammenfasst, sind die doch vertauscht? Ob man damit soviel besser kommt, danach nochmal die beiden tauschen zu müssen (zumal man nicht so ohne weiteres an die Bits 16..31 rankommt, wenns noch im e?x-Register steht)?

Mfg
FAlter

himitsu 6. Mai 2008 20:05

Re: Optimallösung gesucht: Little Endian <-> Big Endia
 
besser kommt man in dem Sinne, daß nun integerweise gearbeitet wird, also mit 2*16 Bit ... wobei die 32 Bit-CPU da doch optimaler arbeitet :angel:
Delphi-Quellcode:
procedure SwapString(Var S: WideString);
asm
  mov eax, [eax]

  test eax, eax
  jz  @exit

  mov ecx, [eax - 4]
  shr ecx, 1

  push ecx
  shr ecx, 1

  jz @onechar

  @loop:

  mov  edx, [eax]
  bswap edx
  rol  edx, 16
  mov  [eax], edx

  add eax, 4
  dec ecx
  jnz @loop

  @onechar:

  pop ecx
  and ecx, $01
  jz  @exit

  mov  dx, [eax]
  xchg dl, dh
  mov  [eax], dx

  @exit:
end;
ach, da ich eh grad etwas zuviel Zeit hatte (blöd, wenn man auf was warten muß :? )
ist aber noch ungetestet

FAlter 6. Mai 2008 20:18

Re: Optimallösung gesucht: Little Endian <-> Big Endia
 
Hi,

stimmt, wenn man es rotieren lässt, hat man die beiden Teile des DWords ja auch wider getauscht, insofern ist ein effizientes Tauschen dann möglich.

Evtl. könnte man das Label @onechar noch drei Anweisungen nach unten verschieben, denn wenn es nur ein Zeichen ist muss nicht nochmal geprüft werden, ob die Anzahl ungerade ist (ein Byte übrig bleibt), das ist dann nämlich eben der Fall.

Mfg
FAlter

[edit] Getestet mit verschobenem @onechar läuft nicht. Was hab ich da nur schon wieder übersehen? :gruebel: [/edit]

nicodex 6. Mai 2008 20:38

Re: Optimallösung gesucht: Little Endian <-> Big Endia
 
Mögliche Assembler-Version für UCS2-Swap:
Delphi-Quellcode:
procedure SwapWords(var AWords; ACount: LongWord); register;
asm
        mov    ecx, edx
        jecxz  @@exit
@@loop: ror    word ptr [eax + ecx * 2 - 2], 8
        loop @@loop
@@exit:
end;

procedure TestSwapWords();
var
  Value: WideString;
begin
  Value :=
    #$4800#$6500#$6C00#$6C00#$6F00#$2C00#$2000 +
    #$5700#$6F00#$7200#$6C00#$6400#$2100;
  SwapWords(Value[1], Length(Value));
  ShowMessage(Value);
end;

FAlter 6. Mai 2008 20:46

Re: Optimallösung gesucht: Little Endian <-> Big Endia
 
Hi,

sieht zwar kurz aus, aber himitsus Version ist schöner, da sie (1.) die Parameter verwendet, wie ich sie mir vorstelle (mit viel weniger Tipparbeit) und (2.) die loop-Anweisung unschön ist. Keine Ahnung, wer die überhaupt eingeführt hat :? jedenfalls ist sie nur dann empfehlenswert, wenn man Speicherplatz sparen will, ansonsten kommt man mit dec und jz besser (zumindest wars früher so, evtl. ist sie heute etwas optimiert worden).

Mfg
FAlter

nicodex 6. Mai 2008 21:25

Re: Optimallösung gesucht: Little Endian <-> Big Endia
 
Dann halt mit WideString und dec/jnz :)
Delphi-Quellcode:
procedure SwapUCS2(var AValue: WideString); register;
asm
        mov    eax, [AValue]
        or     eax, eax
        jz     @@exit         // Empty (nil)
        mov    ecx, [eax - 4] // Relies on internal BSTR knowlegde!
        shr    ecx, 1
//      jz     @@exit         // Should not happen (Empty <> nil)
@@loop: dec    ecx
        ror    word ptr [eax + ecx * 2], 8
        jnz    @@loop
@@exit:
end;

himitsu 6. Mai 2008 21:50

Re: Optimallösung gesucht: Little Endian <-> Big Endia
 
also ohne deine Signatur wär mir langsam was komisch vorgekommen (wo kommt denn das x-Anhänsel her?)

nja, gegen die Assemblerprofies hat man einfach keine Chance :|

dafür bin ich einfach zu sehr gedanklich in der Delphi-/Pascalschiene drin ... übersetze es sozusagen und versuch's dann zu optimieren...
Delphi-Quellcode:
procedure SwapString(Var S: WideString);
asm
  mov  eax, [eax]      // eax := PWideChar(S);
  test eax, eax        // if eax = nil then goto @exit;
  jz   @exit
  mov  ecx, [eax - 4]  // ecx = length(eax) {div 2};
  shr  ecx, 1
  push ecx             // temp := ecx;
  shr  ecx, 1           // ecx := ecx div 2;
  jz   @onechar        // if ecx = 0 then goto @onechar;
  @loop:                // @loop:
  mov  edx, [eax]      // PLongWord(eax)^ := bswap(PLongWord(eax)^) rol 16;
  bswap edx
  rol  edx, 16
  mov  [eax], edx
  add  eax, 4           // inc(eac, 4);
  //dec  ecx           // //dec(ecx);
  //jnz  @loo          // //if ecx <> 0 then goto @loop;
  loop @loop           // dec(ecx); if ecx <> 0 then goto @loop;
  @onechar:             // @onechar:
  pop  ecx             // ecx := temp;
  and  ecx, $01         // ecx := ecx and $01;
  jz   @exit           // if ecx = 0 then goto @exit;
  mov  dx, [eax]       // PWord(eax)^ := xchg(PWord(eax)^);
  xchg dl, dh
  mov  [eax], dx
  @exit:                // @exit:
end;
nja, zumindestens lerntman da auch immer was dazu.
wußte noch garnicht, daß man ROR/ROL nicht nur mit Register verwenden kann ...
schade, daß dieses nicht auch mit BSWAP geht, sonst würde ich brstimmt auch fast so weit runter(klein) kommen ^_^

nicodex 6. Mai 2008 22:38

Re: Optimallösung gesucht: Little Endian <-> Big Endia
 
Wenn man davon ausgeht, dass UCS4String ein array of UCS4Char (dynamisches Array) ist, dann könnte man folgendes 'verbrechen':
Delphi-Quellcode:
procedure SwapUCS4(var AValue: UCS4String); register;
asm
        mov    eax, [AValue]
        or     eax, eax
        jz     @@exit         // Empty (nil)
        mov    ecx, [eax - 4] // Relies on internal DynArray knowlegde!
//      jecxz  @@exit         // Should not happen (Empty <> nil)
//      dec    ecx            // Skip the terminating $00000000
//      jz     @@exit
@@loop: dec    ecx
        mov    edx, [eax + ecx * 4]
        bswap  edx
        mov    [eax + ecx * 4], edx
        jnz    @@loop
@@exit:
end;

procedure TestSwapUCS4;
const
  Hello: array [0..13] of UCS4Char = (
    $48000000, $65000000, $6C000000, $6C000000, $6F000000, $2C000000, $20000000,
    $57000000, $6F000000, $72000000, $6C000000, $64000000, $21000000, $00000000
  );
var
  Value: UCS4String;
begin
  SetLength(Value, Length(Hello));
  Move(Hello[0], Value[0], SizeOf(Hello));
  SwapUCS4(Value);
  ShowMessage(UCS4StringToWideString(Value));
end;
Statt read/BSWAP/write hätte man an auch drei ROR (8/16/8) nehmen können:
Delphi-Quellcode:
procedure SwapUCS4(var AValue: UCS4String); register;
asm
        mov    eax, [AValue]
        or     eax, eax
        jz     @@exit
        sub    eax, 4
        mov    ecx, [eax]
//      dec    ecx // Skip terminating $00000000
//      jz     @@exit
@@loop: add    eax, 4
        dec    ecx
        ror    word ptr [eax], 8
        ror    dword ptr [eax], 16
        ror    word ptr [eax], 8
        jnz    @@loop
@@exit:
end;
ps: das x kommt von nicodex (Vorname) / nicodex (Thema) / nicodex (Land) / nicodex (Neigung) / nicodex (Spiel) :]


Alle Zeitangaben in WEZ +1. Es ist jetzt 11:12 Uhr.
Seite 2 von 3     12 3      

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz