AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

Dynamisches Array als Klasse

Ein Thema von delphifan2004 · begonnen am 22. Jan 2014 · letzter Beitrag vom 23. Jan 2014
Antwort Antwort
delphifan2004

Registriert seit: 26. Nov 2004
Ort: Dresden
277 Beiträge
 
Delphi 10.3 Rio
 
#1

Dynamisches Array als Klasse

  Alt 22. Jan 2014, 07:24
Hallo,

Hier habe ich eine Dynamic-Array Klasse erstellt, inspiriert durch meine Veröffentlichung vor längerer Zeit hier in der DP unter dem Titel "Dynamische Arrays auch unter Delphi 3" Damals hatte ich für jeden Arraytyp eine separate Klasse erstellt. Heute ist nur noch eine einzige Klasse davon übrig geblieben als eindimensionales Array. Alle anderen Klassentypen habe ich entfernt. Die vorliegende Klasse TGenericDynArray kann Integer-Typen und Pointer speichern. Mit dem Pointer sollte es möglich sein, auch kompliziertere Datenstrukturen in einem solchen Array zu speichern. Leider finde ich den damaligen Thread nicht mehr, weshalb ich nun einen neuen eröffne. Außerdem weiß ich von Lazarus, das dort dynamische Arrays auch als Klasse(n) definiert sind.

Ich hatte zuerst auch an mehrdimensionale Arrays gedacht, daher auch die auf mehrdimensionale Arrays ausgelegte SetLength() Methode. Da jedoch in heutigen Delphi- und Lazarus Versionen dynamische Arrays beliebiger Dimensionalität eh Standard sind, belasse ich es nun bei dem eindimensionalen Array.

Hier nun die Unit:

Delphi-Quellcode:
unit DynArray;

interface

uses
  Sysutils, Classes;

type
  PByte = ^Byte;
  PShortInt = ^ShortInt;
  PSmallInt = ^SmallInt;
  PWord = ^Word;
  PInteger = ^Integer;
  PLongint = ^Longint;

  //Workaround für 1 Dimensionales Array
  TElementsType = (
    etByte, etShortInt, etSmallInt, etWord, etInteger, etLongint, etPointer
  );

  TGenericDynArray = class(TObject)
  private
    FCount: Longint;
    FDims: Longint;
    FSize: Longint;
    //FItem: Longint;
    FType: TElementsType;
    FArray: TList;
    FVector: TStringList;
    function GetItems(Index: Integer): Longint;
    function GetItemP(Index: Integer): Pointer;
    function GetItemType: TElementsType;
    procedure SetItems(Index: Integer; value: Longint);
    procedure SetItemP(Index: Integer; value: Pointer);
  protected
    constructor Create; //Für spätere Verwendung
  public
    //Dieser Constructor instantiiert das Array Objekt
    constructor CreateArray(Elements: Integer; ElType: TElementsType);
    destructor Destroy; override;
    property Count: Longint read FCount; //Anzahl Elemente -> gesamtes Array
    property Dims: Longint read FDims; //Anzahl Dimensionen
    property Size: Longint read FSize; //Größe eines Elementes
    //die Array Elemente
    property Items[Index: Integer]: Longint read GetItems write SetItems; default; //passt dann auf alle Typen
    //Wenn Pointer, dann passt dieser Item besser
    //Aber der LOngint Item wandelt Longint intern in Pointer
    property ItemP[Index: Integer]: Pointer read GetItemP write SetItemP;
    //Hier kann der Datentyp der Elemente gelesen werden
    //Festgelegt wird er im Konstruktor mit dem 2. Parameter
    property ItemType: TElementsType read GetItemType;
    procedure SetLength(ElCount: Longint);
  end;

  T1DimArray = TGenericDynArray; //Fügt sich besser in die Namenskonvention ein



function NewByte(b: Byte): PByte;
function NewShortint(si: ShortInt): PShortInt;
function NewSmallInt(si: SmallInt): PSmallInt;
function NewWord(w: Word): PWord;
function NewInteger(i: Integer): PInteger;
function NewLongint(i: Longint): PLongint;

procedure DisposeShortint(var P: PShortint);
procedure DisposeByte(var P: PByte);
procedure DisposeSmallint(var P: PSmallint);
procedure DisposeWord(var P: PWord);
procedure DisposeInteger(var P: PInteger);
procedure DisposeLongint(var P: PLongint);

procedure InitArray(var A: TList; n: Integer; eltype: TElementsType);
procedure CutArray(var A: TList; n: Integer);

implementation

{ für Dimensionsänderungen während der Laufzeit konzipiert                    }
{ kann natürlich überall benutzt werden, wo man diese Funktionalität braucht  }
{ Das Array selber ist mit TList realisiert und behält deshalb die Daten, die }
 
procedure InitArray(var A: TList; n: Integer; eltype: TElementsType);
begin
  while A.Count < n do
   case eltype of
    etByte : A.Add(NewByte(0));
    etShortint : A.Add(NewShortint(0));
    etSmallint : A.Add(NewSmallint(0));
    etWord : A.Add(NewWord(0));
    etInteger : A.Add(NewInteger(0));
    etLongint : A.Add(NewLongint(0));
    etPointer : A.Add(nil);
   end;
end;
 
{ für Dimensionsänderungen während der Laufzeit konzipiert                    }
{ Das Array selber ist mit TList realisiert und behält deshalb die Daten, die }
{ nicht abgeschnitten werden, automatisch                                     }
 
procedure CutArray(var A: TList; n: Integer);
begin
  while n < A.Count do A.Delete(A.Count-1);
end;

function NewByte(b: Byte): PByte;
var P: PByte;
begin
  GetMem(P, Sizeof(b));
  P^ := b;
  Result := P;
end;

function NewShortint(si: ShortInt): PShortInt;
var P: PShortint;
begin
  GetMem(P, Sizeof(si));
  P^ := si;
  Result := P;
end;

function NewSmallInt(si: SmallInt): PSmallInt;
var P: PSmallint;
begin
  GetMem(P, Sizeof(si));
  P^:= si;
  Result := P;
end;

function NewWord(w: Word): PWord;
var P: PWord;
begin
  GetMem(P, Sizeof(w));
  P^:= w;
  Result := P;
end;

function NewInteger(i: Integer): PInteger;
var P: PInteger;
begin
  GetMem(P , Sizeof(i));
  P^:= i;
  Result := P;
end;

function NewLongint(i: Longint): PLongint;
var P: PLongint;
begin
  GetMem(P , Sizeof(i));
  P^:= i;
  Result := P;
end;


procedure DisposeShortint(var P: PShortint);
begin
  freemem(P, Sizeof(Shortint));
end;

procedure DisposeByte(var P: PByte);
begin
  freemem(P, Sizeof(Byte));
end;

procedure DisposeSmallint(var P: PSmallint);
begin
  freemem(P, Sizeof(SmallInt));
end;

procedure DisposeWord(var P: PWord);
begin
  freemem(P, Sizeof(Word));
end;

procedure DisposeInteger(var P: PInteger);
begin
  freemem(P, Sizeof(Integer));
end;

procedure DisposeLongint(var P: PLongint);
begin
  freemem(P, Sizeof(Longint));
end;


{ TGenericDynArray }

function TGenericDynArray.GetItems(Index: Integer): Longint;
begin
Result:=0;
  case FType of
    etByte : Result := Byte(FArray.Items[Index]^) and $ff;
    etShortInt : Result := Shortint(FArray.Items[Index]^) and $ff;
    etSmallInt : Result := Smallint(FArray.Items[Index]^) and $ffff;
    etWord : Result := Word(FArray.Items[Index]^) and $ffff;
    etInteger : Result := Integer(FArray.Items[Index]^);
    etLongint : Result := LongInt(FArray.Items[Index]^);
    etPointer : Result := Longint(FArray.Items[Index]);
  end;
end;

function TGenericDynArray.GetItemP(Index: Integer): Pointer;
begin
result:=nil;
  if FType = etPointer then Result := FArray.Items[Index];
end;

function TGenericDynArray.GetItemType: TElementsType;
begin
  Result := FType;
end;

procedure TGenericDynArray.SetItems(Index: Integer; value: Longint);
var
  b: Byte;
begin
  case FType of
    etByte: begin b := value and $ff; FArray.Items[Index] := NewByte(b); end;
    etShortInt: begin FArray.Items[Index] := NewShortint(value and $ff); end;
    etSmallInt: begin FArray.Items[Index] := NewSmallInt(value and $ffff); end;
    etWord: begin FArray.Items[Index] := NewWord(value and $ffff); end;
    etInteger: FArray.Items[Index] := NewInteger(value);
    etLongint: FArray.Items[Index] := NewLongint(value);
    etPointer: FArray.Items[Index] := Pointer(value);
  end;
end;

procedure TGenericDynArray.SetItemP(Index: Integer; value: Pointer);
begin
  SetItems(Index, Longint(value));
end;

constructor TGenericDynArray.Create; //für zukünftige Verwendung
begin //nicht zum Instanziieren
  inherited Create;
  FArray := TList.Create;
end;

constructor TGenericDynArray.CreateArray(Elements: Integer; ElType: TElementsType);
var i: Integer; P: Pointer;
begin
p:=nil;
  inherited Create;
  FArray := TList.Create;
  for i := 0 to Elements-1 do
  case ElType of
    etByte : begin FArray.Add(NewByte(0)); FSize := Sizeof(Byte); end;
    etShortInt: begin FArray.Add(NewShortint(0)); FSize := Sizeof(Shortint); end;
    etSmallInt: begin FArray.Add(NewSmallInt(0)); FSize := Sizeof(Smallint); end;
    etWord : begin FArray.Add(NewWord(0)); FSize := Sizeof(Word); end;
    etInteger : begin FArray.Add(NewInteger(0)); FSize := Sizeof(Integer); end;
    etLongint : begin FArray.Add(NewLongint(0)); FSize := Sizeof(Longint); end;
    etPointer : begin FArray.Add(P); FSize := Sizeof(Pointer); end;
  end;
  FCount := FArray.Count;
  FDims := 1;
end;

destructor TGenericDynArray.Destroy;
begin
  FArray.Free;
  inherited Destroy;
end;

procedure TGenericDynArray.SetLength(ElCount: Longint);
var
  delta,ix,switch: Integer; Dims: array[0..1] of Longint;
begin
  Dims[0] := ElCount; //weil vorher Dims: array of Longint, statt ElCount
  if High(Dims)<2 then //Hier wurde die Anzahl aktueller Dimensionen geprüft
  begin //wer mag, kann auf mehrdimensionale Arrays erweitern
    ix := 0; //wie ursprünglich vorgesehen, doch aus technischen
    delta := Dims[0]-FArray.Count; //Gründen nicht weiter verfolgt.
    if delta < 0 then switch := -1 else //Differenz zwichen neuer und alter Anzahl Array-Elemente
    if delta > 0 then switch := +1 else
    switch := 0; //um übersichtlicheren Code zu erhalten
    case switch of
     -1: if Dims[0]>=0 then while ix > delta do { oder while FArray.Count > delta }
         begin //oder CutArray(FArray, Dims[0]);
           FArray.Delete(FArray.Count-1);
           dec(ix);
         end;
      0: ; //Keine Aktion
     +1: while FArray.Count < Dims[0] do //oder InitArray(FArray, Dims[0], FType);
         begin
           case FType of //wenn neue Länge (Elementanzahl) größer als vorherige
            etByte: FArray.Add(NewByte(0));//dann neue Elemente dazu und mit NULL initialisieren
            etShortint: FArray.Add(NewShortint(0));
            etSmallint: FArray.Add(NewSmallint(0));
            etInteger : FArray.Add(NewInteger (0));
            etLongint : FArray.Add(NewLongint (0));
            etPointer : FArray.Add(nil);
           end; { von case Ftype }
         end; { von case +1 -> while do begin }
    end; { von case }
  end; { von if High(Dims) }
FCount := FArray.Count;
end;


end.
Ihr dürft diese Unit per copy & paste in Eure Projekte zu jedem beliebigen Zweck übernehmen.

Soeben hat mir der User "Delphi Laie" den Link zu jenem Thread wieder beschafft. Leider kann ich dort nichts mehr korrigieren. Ich will jedoch den Link zu jenem Thread wenigstens hier setzen, damit die anderen Überlegungen von eventuellen Interessenten auch gefunden werden.

http://www.delphipraxis.net/38721-dy...elphi-3-a.html

Schließlich sind dynamische Arrays unter Lazarus auch als Klassen(n) implementiert.

Geändert von delphifan2004 (22. Jan 2014 um 11:00 Uhr)
  Mit Zitat antworten Zitat
lowmax_5

Registriert seit: 9. Mai 2003
Ort: Münster, NRW
258 Beiträge
 
Delphi 11 Alexandria
 
#2

AW: Dynamisches Array als Klasse

  Alt 22. Jan 2014, 08:00
Hallo,

der Aufwand dafür ist ja recht gross. Wäre es nicht einfacher TObjectList (unit Contnrs) dafür zu verwenden?
  Mit Zitat antworten Zitat
delphifan2004

Registriert seit: 26. Nov 2004
Ort: Dresden
277 Beiträge
 
Delphi 10.3 Rio
 
#3

AW: Dynamisches Array als Klasse

  Alt 22. Jan 2014, 11:08
Hallo,

der Aufwand dafür ist ja recht gross. Wäre es nicht einfacher TObjectList (unit Contnrs) dafür zu verwenden?
Nein, die gab es unter Delphi 3 noch nicht. Und wenn, wie hätte man das dann mit dieser Objectlist einfacher realisieren können? Das interessiert mich jetzt wirklich.

Die Tlist erhält ja auch keine Objektzeiger, sondern Zeiger auf Variablen des mit ElType vereinbarten Datentyps. Ich hätte höchstens gleich nur Longint oder Pointer zulassen können, da intern der Zeiger in der Liste immer mit 4 Byte Länge gespeichert wird, auch dann, wenn ich nur Byte Werte speichern will. Diese Bytes passen auch in eine Longint Speicherstelle. Ich hätte höchstens statt der TList ein
Array[0..0] of Byte verwenden können, wie in der ersten Version, siehe Link im ersten Beitrag. Dann hätte ich mit Setlength immer die aktuell benötigte Bytezahl festgelegt. Deshalb hatte ich ja in der ersten Version (siehe Link) auch für jeden unterstützten Datentyp eine eigene Klasse.
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.340 Beiträge
 
Delphi 12 Athens
 
#4

AW: Dynamisches Array als Klasse

  Alt 22. Jan 2014, 11:15
Wäre es aber nicht etwas "einfacher", das alte Programm von D3 wenigstens auf D7 upzudaten und dann die nativen dynamischen Arrrays zu verwenden,
also jetzt nochmal mit dem Ersatz für diese Arrays rumzuspielen?
Ein Therapeut entspricht 1024 Gigapeut.
  Mit Zitat antworten Zitat
Bjoerk

Registriert seit: 28. Feb 2011
Ort: Mannheim
1.384 Beiträge
 
Delphi 10.4 Sydney
 
#5

AW: Dynamisches Array als Klasse

  Alt 22. Jan 2014, 13:22
Konnte man unter D3 noch nicht einen Integer auf Pointer casten und umgekehrt? Falls ja kannst du die das ganze New/ Disposezeugs schenken?
  Mit Zitat antworten Zitat
Delphi-Laie

Registriert seit: 25. Nov 2005
1.474 Beiträge
 
Delphi 10.1 Berlin Starter
 
#6

AW: Dynamisches Array als Klasse

  Alt 22. Jan 2014, 19:57
Die Unit scheint sich noch weiter vereinfachen zu lassen: Die case-Unterscheidungen zu den verschiedenen Integertypen ließ ich weg und benutze in jedem Falle nur das für die Pointer, also das, was hinter

etPointer:

steht, lasse ich ausführen. Das funktioniert auch, und zwar für alle Integer-Typen.

Abgeleitete Klassen funktionieren auch für Arrays anderen Typs (auch records), sofern der Speicherbedarf konstant ist. Bei Strings funktioniert es bisher leider nur bei solchen mit konstanter Länge (string[x]).

Geändert von Delphi-Laie (22. Jan 2014 um 20:00 Uhr)
  Mit Zitat antworten Zitat
Delphi-Laie

Registriert seit: 25. Nov 2005
1.474 Beiträge
 
Delphi 10.1 Berlin Starter
 
#7

AW: Dynamisches Array als Klasse

  Alt 22. Jan 2014, 09:14
Leider finde ich den damaligen Thread nicht mehr, weshalb ich nun einen neuen eröffne.
Die forumseigene Suchfunktion tut sich tatsächlich etwas schwer damit, aber Tante google ist mal wieder der Retter in der Not: Dynamische Arrays auch unter Delphi 3.
  Mit Zitat antworten Zitat
delphifan2004

Registriert seit: 26. Nov 2004
Ort: Dresden
277 Beiträge
 
Delphi 10.3 Rio
 
#8

AW: Dynamisches Array als Klasse

  Alt 22. Jan 2014, 10:55
Leider finde ich den damaligen Thread nicht mehr, weshalb ich nun einen neuen eröffne.
Die forumseigene Suchfunktion tut sich tatsächlich etwas schwer damit, aber Tante google ist mal wieder der Retter in der Not: Dynamische Arrays auch unter Delphi 3.
Zu spät! Aber egal, habe soeben den Suchbegriff so unter Google eingegeben und bin fündig geworden. Nun bleibt nur noch eine Verlinkung zu ebendiesem Thread, der ja der Ausgangspunkt aller Überlegungen dazu war.
  Mit Zitat antworten Zitat
Antwort Antwort


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 18:07 Uhr.
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