AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Algorithmen, Datenstrukturen und Klassendesign Delphi Effizienter binär-output eines (word)-streams
Thema durchsuchen
Ansicht
Themen-Optionen

Effizienter binär-output eines (word)-streams

Offene Frage von "Sequitar"
Ein Thema von Sequitar · begonnen am 5. Apr 2022 · letzter Beitrag vom 11. Apr 2022
Antwort Antwort
Seite 1 von 2  1 2      
Sequitar

Registriert seit: 8. Jan 2016
74 Beiträge
 
Delphi 10.4 Sydney
 
#1

Effizienter binär-output eines (word)-streams

  Alt 5. Apr 2022, 19:22
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!
  Mit Zitat antworten Zitat
Der schöne Günther

Registriert seit: 6. Mär 2013
6.159 Beiträge
 
Delphi 10 Seattle Enterprise
 
#2

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

  Alt 5. Apr 2022, 21:01
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 Word , und möchte fortan mit einem Array von 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?
  Mit Zitat antworten Zitat
BerndS

Registriert seit: 8. Mär 2006
Ort: Jüterbog
491 Beiträge
 
Delphi 12 Athens
 
#3

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

  Alt 5. Apr 2022, 21:16
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?
  Mit Zitat antworten Zitat
Sequitar

Registriert seit: 8. Jan 2016
74 Beiträge
 
Delphi 10.4 Sydney
 
#4

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

  Alt 6. Apr 2022, 00:57
@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.
  Mit Zitat antworten Zitat
BerndS

Registriert seit: 8. Mär 2006
Ort: Jüterbog
491 Beiträge
 
Delphi 12 Athens
 
#5

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

  Alt 6. Apr 2022, 10:48
@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.
  Mit Zitat antworten Zitat
Benutzerbild von Sinspin
Sinspin

Registriert seit: 15. Sep 2008
Ort: Dubai
680 Beiträge
 
Delphi 10.3 Rio
 
#6

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

  Alt 6. Apr 2022, 17:03
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.
Stefan
Nur die Besten sterben jung
A constant is a constant until it change.
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe

Registriert seit: 20. Jan 2006
Ort: Lübbecke
11.453 Beiträge
 
Delphi 12 Athens
 
#7

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

  Alt 6. Apr 2022, 19:06
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;
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat
Benutzerbild von Sinspin
Sinspin

Registriert seit: 15. Sep 2008
Ort: Dubai
680 Beiträge
 
Delphi 10.3 Rio
 
#8

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

  Alt 6. Apr 2022, 20:10
Nur das WordRec keinen Zugriff als Word erlaubt, nur als Bytes. Und dann sinnloserweise auch noch auf zwei Arten.
Stefan
Nur die Besten sterben jung
A constant is a constant until it change.

Geändert von Sinspin ( 6. Apr 2022 um 20:11 Uhr) Grund: tipfehler
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe

Registriert seit: 20. Jan 2006
Ort: Lübbecke
11.453 Beiträge
 
Delphi 12 Athens
 
#9

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

  Alt 6. Apr 2022, 22:28
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.
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat
Sequitar

Registriert seit: 8. Jan 2016
74 Beiträge
 
Delphi 10.4 Sydney
 
#10

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

  Alt 9. Apr 2022, 21:09
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
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 2  1 2      


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 03:10 Uhr.
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