Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Algorithmen, Datenstrukturen und Klassendesign (https://www.delphipraxis.net/78-algorithmen-datenstrukturen-und-klassendesign/)
-   -   Delphi Effizienter binär-output eines (word)-streams (https://www.delphipraxis.net/210318-effizienter-binaer-output-eines-word-streams.html)

Sequitar 5. Apr 2022 18:22

Effizienter binär-output eines (word)-streams
 
Ich habe bei einem Algorithmus als output eine liste / einen stream, der werte des typs word (0..65535) enthält.
Jetzt würde ich die liste gerne wieder zu binaer wandeln (chars, bytes) und ausgeben (entweder in einen stream schreiben oder in einem string speichern):
Wie kann ich den output möglichst effizient (d.h. kurz) halten?

Bisher hatte ich folgende Ansätze:

naiv:
Delphi-Quellcode:
Function Tio_stream.OutputCompressedData(data: Tlist<Pword>)
  : Tmemorystream;
Var
  P: Pword;
  Writer: Tbinarywriter;
Begin
  Result := Tmemorystream.Create;
  Writer := Tbinarywriter.Create(Result);
  Try
    For P In Compressed Do
      Writer.Write(P^);
  Finally
    Writer.Free;
  End;
End;

//read

Procedure Tio_stream.GetCompressedData(Const Content: Tmemorystream;
  Out res: Tlist<Pword>);
Var
  Tempdata: Word;
Var
  Tempdataentry: Pword;
Var
  Readindex, Maxread: Word;
  Datasize: Integer;
Begin
//assert(assigned(res));
  Cleardata(res);
  Content.Position := 0;
  Begin
    Readindex := 0;
    Datasize := Sizeof(Word);
    Maxread := Content.Size Div Datasize;
    While Readindex < Maxread Do
    Begin
      Content.Read(Tempdata, Datasize);
      New(Tempdataentry);
      Tempdataentry^ := Tempdata;
      res.Add(Tempdataentry);
      Inc(Readindex);
    End;
  End;
End;
einmal noch als words/chars direkt (bisher das kürzeste):
Delphi-Quellcode:
procedure OutputCompressedData(Compressed: Tlist<Pword>): String;
Var
  Entry: Pword;
  Outchar: Pchar;
Begin
  Setlength(Result, Compressed.Count);
  Outchar := @Result[1];
  For Entry In Compressed Do
  Begin
    Outchar^ := Char(Entry^);
    Inc(Outchar);
  End;
  // Result := Concat(Result, Char(entry^));
End;
Darauf aufbauend hatte ich folgendes versucht (die super klassen tstreamwriter/reader habe ich erst vor kurzem für mich entdeckt)
Delphi-Quellcode:
Function Tlzwio_stringstream.OutputCompressedData
  (Compressed: Tlist<Pword>): String;
Var
  Temp: Tmemorystream;
  Encoding: Tencoding;
Begin
  Try
    Assert(Assigned(Compressed));
    Encoding := Tencoding.Create;
    Encoding.Default;
    // writes values as word to stream
    Temp := Inherited Outputcompresseddata(Compressed);
    Temp.Position := 0;
    With Tstreamreader.Create(Temp, Encoding) Do
    Begin
      Result := ReadLine; // abstract error
      Free;
    End;
  Finally
    Encoding.Free;
    Temp.Free;
  End;
End;
habe aber, wo angegeben, mit dem abstract error (welche klasse überschreibt das denn?) zu tun


Was haltet ihr davon? #Holzweg? Welche - im obigen sinne - effizienten Alternativen (bitstream klasse, sowas könnte ich an anderer stelle auch gebrauchen?)würdet ihr vorschlagen?

danke!

Der schöne Günther 5. Apr 2022 20:01

AW: Effizienter binär-output eines (word)-streams
 
Lustig, vor ein paar Minuten hatte ich eine ganz ähnliche Frage:
https://en.delphipraxis.net/topic/66...re-allocating/

Hier habe ich ein Array von
Delphi-Quellcode:
Word
, und möchte fortan mit einem Array von
Delphi-Quellcode:
Byte
weiterarbeiten. Allerdings ohne nochmal neu Speicher anlegen und Daten hin und her schieben zu müssen, die Daten liegen ja bereits vor.

Bei dir ist es etwas mehr "high-level" und du kontrollierst anscheinend beide Seiten, also den Teil der die Words ausspuckt, und den Teil der die Bytes weiterverarbeiten will, richtig?

BerndS 5. Apr 2022 20:16

AW: Effizienter binär-output eines (word)-streams
 
1. Warum keine TList<Word>
Da kann man dann das array der Liste (TList.
List[0]) in den Stream schreiben.
Laut Wiki kann man TList.Count direkt setzen und dann sollte ein direktes beschreiben von TList.List[0] möglich sein.
2. Was hat ein Word mit strings zu tun? Das array als csv string könnte ich mir vorstellen, aber das meinst du sicher nicht.
3. Wer kümmert sich um die Freigabe von PWord wenn die Liste freigegeben wird?

Sequitar 5. Apr 2022 23:57

AW: Effizienter binär-output eines (word)-streams
 
@BerndS: Die pwords liegen in der liste (data) und werden nach dem Schreibvorgang in den Stream auch von dort korrekt freigegeben.
Was die words mit strings zu tun haben? ich hatte zunächst die idee, dass bei unicode sizeof(char)=sizeof(word), daher kann ich sie ja direkt in einen string schreiben - ich hatte auch bereits damit experimentiert, einen
Delphi-Quellcode:
record
valhi:byte;
vallo:byte;
end;
zu nutzen und ggf (bei kleinen werten) mit dem nächsten halben word zu füllen. Das macht die sache aber auch nicht unbedingt kürzer.

Ich könnte mir so etwas auch auf Bitebene vorstellen, wie im Originalpost angeregt. So etwas geht bestimmt mit Bitmasken oder so - nur spontan wüsste ich jetzt nicht wie ich das umsetzten sollte. Gibts da fertiges? Macht das überhaupt Sinn?

Wie verhält sich das mit der tlist<word>, wenn ich list.list[0] in den stream schreibe? Die einzelnen Einträge sind dann doch immer noch- von der Größe word, egal ob unterhalb der bytegrenze oder nicht? Damit würden die werte 00..FF ja eigentlich immer als 0000..00FF (bzw FF00) abgespeichert. Geht das nicht irgendwie platzsparender? - im moment nutze ich es zb. bei der Ausgabe von dictionary-based Kompressionsalgorithmen (zb. LZW, hier haben die outputs maximal die größe eines words, kleinstenfalls bytegröße)im späteren verlauf würde ich das dann gerne für eine art huffman-baum (-Ausgabe) nutzen wollen.

@Der schöne Günther: mir ist auf den ersten blick nicht ganz klar geworden,inwiefern mir der englische Beitrag von dir hilft? Vieleleicht ist es auch schon zu spät - ich müsste mir das mal bei tageslicht ansehen.:oops:

BerndS 6. Apr 2022 09:48

AW: Effizienter binär-output eines (word)-streams
 
@Sequitar
Es war gestern wohl schon zu spät für mich um dein Problem zu verstehen.
Wenn es so viele Daten sind,das du dir darüber Gedanken machen musst, wäre eine Kompression die beste Lösungen.
Ich verwende dafür eine Kompression der LMD Komponenten um Streams in einer Datenbank im Blob zu speichern und wieder zu laden.

Sinspin 6. Apr 2022 16:03

AW: Effizienter binär-output eines (word)-streams
 
Was du machen kannst ist einen Typen mit mehr als einem Zustand zu verwenden:
Delphi-Quellcode:
type
  TDual = packed record
  case byte of
  0 : (a : word);
  1 : (b: record hi,lo : byte;end);
  end;
Dann hast Du zur gleichen Zeit Zugriff darauf als Word und als Bytes. Das ganze als Array anlegen und nach Möglichkeit blockweise lesen und schreiben. Das spart Zeit beim Zugriff.

Uwe Raabe 6. Apr 2022 18:06

AW: Effizienter binär-output eines (word)-streams
 
Warum das Rad neu erfinden, wenn es doch schon in SysUtils existiert?
Delphi-Quellcode:
{ Type conversion records }

  WordRec = packed record
    case Integer of
      0: (Lo, Hi: Byte);
      1: (Bytes: array [0..1] of Byte);
  end;

  LongRec = packed record
    case Integer of
      0: (Lo, Hi: Word);
      1: (Words: array [0..1] of Word);
      2: (Bytes: array [0..3] of Byte);
  end;

  Int64Rec = packed record
    case Integer of
      0: (Lo, Hi: Cardinal);
      1: (Cardinals: array [0..1] of Cardinal);
      2: (Words: array [0..3] of Word);
      3: (Bytes: array [0..7] of Byte);
  end;

Sinspin 6. Apr 2022 19:10

AW: Effizienter binär-output eines (word)-streams
 
Nur das WordRec keinen Zugriff als Word erlaubt, nur als Bytes. Und dann sinnloserweise auch noch auf zwei Arten.

Uwe Raabe 6. Apr 2022 21:28

AW: Effizienter binär-output eines (word)-streams
 
Zitat:

Zitat von Sinspin (Beitrag 1504350)
Nur das WordRec keinen Zugriff als Word erlaubt, nur als Bytes. Und dann sinnloserweise auch noch auf zwei Arten.

Diese Records sind ja nicht als Typ in einer Typdeklaration gedacht, sondern als Cast auf eine Variable mit Word-Größe. Insofern wäre ein Zugriff auf Word innerhalb WordRec (analog in den anderen records) irgendwie obsolet.
Delphi-Quellcode:
var
  MyCharArray: array[0..15] of WideChar;
begin
  ...
  cntHighUnicode := 0;
  for I := Low(MyCharArray) to High(MyCharArray) do
    if WordRec(MyCharArray[0]).Hi <> 0 then
      Inc(cntHighUnicode);
  ...
end;

Der zugegeben redundante Zugriff auf die Einzelbytes ist wohl eher der Konsistenz mit den anderen record Typen geschuldet.

Sequitar 9. Apr 2022 20:09

AW: Effizienter binär-output eines (word)-streams
 
Hm danke für eure Ideen. Allerdings bin ich mir beim durchlesen nicht mehr sicher, ob ich mein problem richig dargestellt habe.(u.a @BerndS)
Also sagen wir ich habe als output die list<word>, welche ich in den output stream schreiben möchte. Natürlich geht das erst mal intuitiv ungefähr so:
Nur vom prinzip her - ohne auf Schönheit zu achten.

Delphi-Quellcode:
//..
from i:=list.lo to list.hi do
begin
var x:word:=list[i]
stream.write{oder streamwriter().write}(x,wordsize);
end;
dann habe ich am ende einen output stream der groesse list.count*wordsize.
Meine Frage wäre: Geht das kürzer, z.b wenn ich ungefähr weiss, dass die meisten werte werte >high(byte) sein werden? Ich meine, vielleicht geht's ja auch gar nicht.


Gut, was mir jetzt noch einfällt - den könnte ich - zum Beispiel - noch mal durch eine Lauflängen-Kompression schicken (müsste ich mal probieren, ob das was bringt, bei vielen wiederholungen vielleicht), oder durch einen Huffman-Tree oder so ähnlich, damit ich am ende eine art bit-stream habe.

Bevor ich das anfange, wäre ich allerdings an möglichkeiten interessiert, die es mir erlauben, eine Ausgabefolge von word-werten reversibel(!) in eine effizientere Form zu bringen


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

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