Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   Einem Set einen Enum zuweisen? (https://www.delphipraxis.net/193660-einem-set-einen-enum-zuweisen.html)

Glados 27. Aug 2017 08:30

Einem Set einen Enum zuweisen?
 
Gegeben ist ein Enum und ein Set davon:
Delphi-Quellcode:
 TDataEnum = (tdHouse, tdCar);
 TDataSet = set of TDataEnum;
Nun habe ich in einer Funktion eine Variable (im Kopf, als Parameter) vom Typ
Delphi-Quellcode:
TDataSet
Ich prüfe, ob das Set leer ist mit
Delphi-Quellcode:
if aDataSet = []
und danach füge ich Standardwerte hinzu.
Aktuell so
Delphi-Quellcode:
aDataSet := [tdHouse, tdCar];
Hier habe ich nun doppelten Code. Einmal bei der Zuweisung in der Funktion in einmal in der Deklaration ganz oben.

Kann man aDataSet nicht irgendwie die Hauptdeklaration (TDataEnum = ...) zuweisen, um das zu vermeiden?

DeddyH 27. Aug 2017 08:35

AW: Einem Set einen Enum zuweisen?
 
Ich habe das jetzt 4 mal gelesen, aber immer noch nicht verstanden. Willst Du Deinem Funktionsargument einen Standardwert zuweisen, oder worum geht es genau?

jaenicke 27. Aug 2017 08:38

AW: Einem Set einen Enum zuweisen?
 
Nein, du hast in der Deklaration ja nur die möglichen Werte definiert.

Du kannst aber eine Konstante vom Typ TDataSet für alle möglichen Werte anlegen und diese dann im Code verwenden.

Nebenbei:
TDataSet war nur ein Beispiel, oder? Den Typ gibt es ja schon in Delphi.

Glados 27. Aug 2017 08:59

AW: Einem Set einen Enum zuweisen?
 
TDataSet war nur ein Beispiel.
Ich habe das jetzt mit der Konstante umgesetzt.
Jetzt habe ich zwar auch quasi doppelten Code, dafür aber nur einmal und das in derselben Unit an derselben Stelle statt wild verstreut.

Danke.

Uwe Raabe 27. Aug 2017 09:12

AW: Einem Set einen Enum zuweisen?
 
Um Fehler bei späteren Erweiterungen zu vermeiden, mache ich das in der Regel so:

Delphi-Quellcode:
type
  TDataEnum = (tdHouse, tdCar);
  TDataSet = set of TDataEnum;

const
  cDataSetAll: TDataSet = [Low(TDataEnum)..High(TDataEnum)];

Glados 27. Aug 2017 09:14

AW: Einem Set einen Enum zuweisen?
 
Das ist noch besser. Ich hatte es bis gerade eben noch so (was wohl nicht gut ist)
Delphi-Quellcode:
type
  TDataEnum = (tdHouse, tdCar);
  TDataSet = set of TDataEnum;

const
  cDataSetAll: TDataSet = [tdHouse, tdCar];

himitsu 27. Aug 2017 09:46

AW: Einem Set einen Enum zuweisen?
 
Delphi-Quellcode:
TDataSet = set of (tdHouse, tdCar);


Du hast eine Definition für einen ENUM (eine Liste mit verschiedenen Namen/Werten), aber ein ENUM kann immer nur einen dieser Werte speichern.
Und du hast eine Definition für ein SET, dass mehrere ENUMS speichern kann.

Es ist zwar auch möglich ENUM und SET zusammen zu definieren, aber es ist so nicht möglich eine Variable für nur einen ENUM zu deklarieren, da DU nicht an den eingebetteten ENUM-Typen ran kommst.


PS: Delphi-Referenz durchsuchenTDataSet

[EDIT]
Jetzt hab ich's auch falsch verstanden.


Delphi-Quellcode:
aDataSet := TDataSet(-1);
hier sind nun alle deine ENUMs gesetzt und auch der freie Speicher, da das SET ja auf die Größe des nächstgrößeren Datentypen für die Speicherung "aufgerundet" wurde (Byte, Word, LongWord oder UInt64).

Glados 27. Aug 2017 09:58

AW: Einem Set einen Enum zuweisen?
 
Zitat:

PS: Delphi-Referenz durchsuchenTDataSet
Zitat:

TDataSet war nur ein Beispiel.
Ich habe es so gelößt wie Uwe vorgeschlagen hat
Delphi-Quellcode:
type
  TDataEnum = (tdHouse, tdCar);
  TDataSet = set of TDataEnum;

const
  cDataSetAll: TDataSet = [Low(TDataEnum)..High(TDataEnum)];
Zitat:

hier sind nun alle deine ENUMs gesetzt und auch der freie Speicher,
Alles was den Speicher angeht, ist mir ehrlich gesagt herzlich egal.
Ob das jetzt 1 Byte oder 1 KByte mehr verbraucht oder weniger: wir sind in 2017 und nicht mehr in 198X.
Bei Unterschieden von 100MB mehr oder weniger könnte ich das noch verstehen, aber nicht im Bereich von Byte zu maximal Kbyte.

Uwe Raabe 27. Aug 2017 10:37

AW: Einem Set einen Enum zuweisen?
 
Zitat:

Zitat von himitsu (Beitrag 1379581)
Delphi-Quellcode:
aDataSet := TDataSet(-1);

[dcc32 Fehler] Unit208.pas(38): E2089 Ungültige Typumwandlung

himitsu 27. Aug 2017 11:48

AW: Einem Set einen Enum zuweisen?
 
Hmmmm, war mir sicher, dass es sorum auch mal ging.

Delphi-Quellcode:
type
  TDataEnum = (tdHouse, tdCar);
  TDataSet = set of TDataEnum;

procedure TForm9.FormCreate(Sender: TObject);
var
  aDataSet: TDataSet;
begin
  Byte(aDataSet) := $FF; // Byte(-1)
end;

procedure TForm9.FormCreate(Sender: TObject);
var
  aDataSet: TDataSet;
  iDataSet: ShortInt absolute aDataSet;
begin
  iDataSet := -1;
  if tdHouse in aDataSet then
    Beep;
end;

Glados 27. Aug 2017 11:49

AW: Einem Set einen Enum zuweisen?
 
Jetzt werden aber Spezialitäten hier ausgepackt :P

Uwe Raabe 27. Aug 2017 11:54

AW: Einem Set einen Enum zuweisen?
 
Zitat:

Zitat von himitsu (Beitrag 1379606)
Hmmmm, war mir sicher, dass es sorum auch mal ging.

Auch nicht wirklich:

Delphi-Quellcode:
var
  cnt: Integer;
  dataSet: TDataSet;
  enum: TDataEnum;
begin
  Byte(dataSet) := $FF;
  cnt := 0;
  for enum in dataSet do begin
    Inc(cnt);
  end;
  Assert(cnt = 2, 'Klappt nicht!');
end;

himitsu 27. Aug 2017 12:51

AW: Einem Set einen Enum zuweisen?
 
Delphi-Quellcode:
Assert(cnt = SizeOf(enum) * 8, 'Klappt doch!');
:stupid:

jaenicke 27. Aug 2017 13:24

AW: Einem Set einen Enum zuweisen?
 
Zitat:

Zitat von Glados (Beitrag 1379576)
Das ist noch besser. Ich hatte es bis gerade eben noch so (was wohl nicht gut ist)
Delphi-Quellcode:
const
  cDataSetAll: TDataSet = [tdHouse, tdCar];

Im Sinne von All ist die von Uwe vorgeschlagene Variante besser. Meistens benutze ich aber eher funktionelle Bezeichnungen bei diesen Konstanten um auszudrücken was ich mit dem Setzen dieser Werte bewirke.
Aber auch das ist natürlich nicht immer sinnvoll.

Beide Varianten haben je nach Kontext ihre Vorteile.

Rollo62 28. Aug 2017 06:54

AW: Einem Set einen Enum zuweisen?
 
Zitat:

aDataSet := TDataSet(-1); hier sind nun alle deine ENUMs gesetzt und auch der freie Speicher, da das SET ja auf die Größe des nächstgrößeren Datentypen für die Speicherung "aufgerundet" wurde (Byte, Word, LongWord oder UInt64).
Nur mal zur Klärung was "set of" eigentlich ist:
Ich würde das als Bitfeld bezeichen, aber naja, Pascal eben ...
Oder sehe ich das falsch ?

Zitat:

Mengentypen

Eine Menge setzt sich aus mehreren Werten desselben ordinalen Typs zusammen. Die Werte haben keine feste Reihenfolge. Wenn ein Wert in einer Menge doppelt vorkommt, hat jedes Vorkommen dieselbe Bedeutung.

Der Bereich eines Mengentyps ist die Potenzmenge eines bestimmten Ordinaltyps, der als Basistyp bezeichnet wird. Die möglichen Werte eines Mengentyps sind Teilmengen des Basistyps, einschließlich der leeren Menge. Der Basistyp darf aus maximal 256 Werten bestehen. Die Ordinalpositionen der Werte müssen zwischen 0 und 255 liegen. Alle Konstruktionen der Form:
Das steht so im DocWiki, kann es denn jetzt größer als 8-Bit werden, oder nicht ?

Rollo

Uwe Raabe 28. Aug 2017 08:43

AW: Einem Set einen Enum zuweisen?
 
Zitat:

Zitat von Rollo62 (Beitrag 1379662)
Das steht so im DocWiki, kann es denn jetzt größer als 8-Bit werden, oder nicht ?

Na klar, steht da doch! Bis 256 Elemente sind erlaubt, solange deren Ordinalwerte im Bereich 0..255 liegen. Der Speicherbereich eines Set wird dann eben zwischen 1 und 32 Byte angepasst.

Rollo62 28. Aug 2017 08:58

AW: Einem Set einen Enum zuweisen?
 
Meine Frage war ja wie sich 256 Werte intern speichern, reicht da EIN Bit aus,
also wird die Info als Bitfeld gespeichert ?
Oder wird das als Array angelegt ?

Delphi-Quellcode:
type
   enum (eins=1, zwei=2, ende=256);

//1.) Wird das irgendwie bitmässig gespeichert im set ?

$01 = eins
$02 = zwei
$04 = drei
$08 = vier
...
$80 = acht
$80000000...00000 // 256-Bit ?

// So funktioniert es wohl nicht, sondern (ich vermute)
// 2.) eher wie ein Byte-Array (oder Integer-Array)

byteArr : array[0..255];
byteArr[0]  = eins
byteArr[1]  = zwei
byteArr[255] = ende

// 1.) Im ersten Fall würde es intern als BIT gespeichert (wäre Speichereffizient),
// 2.) im zweiten Fall als BYTE (wäre Speicher-Verschwendung, aber simpler zu implementieren)
Ich habe mir die Interna nicht angesehen, deshalb die blöde Frage.
Das es bis 32-Bit wächst steht da ja nicht explizit.
Meine Vermutung wäre 2.).

himitsu 28. Aug 2017 09:45

AW: Einem Set einen Enum zuweisen?
 
Das mit den 0-255 hast du falsch verstanden.

1-Byte wäre es, wenn es sich auf ENUMs bezieht, aber die können bis 64 Bit groß werden (0-255=Byte, 256-65.535=Word, ...=LargeWord und auch abhängig von
Delphi-Quellcode:
{$MinEnumSize x}
), bei Verwendung des IN-Operators kann man davon aber nur 0-255 abfragen.

Der Compiler nutzt für SETs aber beim IN einen Assemblerbefehl, der nur eine Bit-Adressierung mit einem Byte unterstützt, weswegen SETs auf 256 Bits (Werte/ENUMs) unterstützt werden, also bis zu 32 Bytes.

Das ist auch der Grund, warum man bei WideChar kein IN verwenden kann, obwohl man das im Compiler auch hätte bugfixen können. (selber eine Prüfung implementieren, bzw. bei der Prüfung das unterde Byte des Index über den schon verwendeten ASM-Befehl und die höheren Byte als Speicheroffest i*32, vorallem da dieser ASM-Befehl nicht gerade schnell ist und man das mit einem ByteOffest+Shift+AND hätte womöglich schneller prüfen können)


Code:
Unit6.pas.29: Exclude(A, 'b');
004AB648 8065E4FB        and byte ptr [ebp-$1c],$fb

Unit6.pas.30: Include(A, 'b');
004AB64C 804DE404         or byte ptr [ebp-$1c],$04

Unit6.pas.31: if 'b' in a then ;
004AB650 F645E404         test byte ptr [ebp-$1c],$04
004AB654 7407             jz $004AB656
https://en.wikipedia.org/wiki/TEST_(x86_instruction)

Rollo62 28. Aug 2017 10:08

AW: Einem Set einen Enum zuweisen?
 
Aha, dankesehr himitsu.

Wieder was dazugelernt :thumb:

Ich benutzte sets eigentlich recht sparsam, deswegen habe ich mir das auch noch nicht näher angesehen.
Und weil die Doku das irgendwie nicht klar beschreibt (oder ich hatte es nur noch nicht gefunden).

Rollo

Uwe Raabe 28. Aug 2017 11:38

AW: Einem Set einen Enum zuweisen?
 
Zitat:

Zitat von Rollo62 (Beitrag 1379700)
Und weil die Doku das irgendwie nicht klar beschreibt (oder ich hatte es nur noch nicht gefunden).

http://docwiki.embarcadero.com/RADSt...i)#Mengentypen

Zitat:

Eine Menge ist ein Array von Bits. Jedes Bit zeigt an, ob ein Element in der Menge enthalten ist oder nicht. Da die maximale Anzahl der Elemente einer Menge 256 beträgt, belegt eine Menge nie mehr als 32 Byte.
Zitat:

Der Compiler speichert Mengen nach Möglichkeit in CPU-Registern. Eine Menge bleibt jedoch immer im Speicher, wenn sie größer als der plattformabhängige Integertyp ist oder im Quelltext des Programms auf die Adresse der Menge zugegriffen wird.

himitsu 28. Aug 2017 11:44

AW: Einem Set einen Enum zuweisen?
 
Nur beim IN-Operator ist ein SET das manchmal kein Bit-Array,
aber nur, wenn das SET direkt beim IN definiert wird, also ohne das SET als Variable/Konstante, dann optimiert der Compiler den Code ähnlich einem CASE-Statement und löst es mathematisch (INC, DEC und CMP).

Codehunter 28. Aug 2017 13:45

AW: Einem Set einen Enum zuweisen?
 
Ähm... Was macht ihr denn hier? Ist ja wie Einstein und Oppenheimer beim Kaffeekränzchen :-)

Zitat:

Zitat von Glados (Beitrag 1379554)
Hier habe ich nun doppelten Code. Einmal bei der Zuweisung in der Funktion in einmal in der Deklaration ganz oben.

Kann man aDataSet nicht irgendwie die Hauptdeklaration (TDataEnum = ...) zuweisen, um das zu vermeiden?

Ich glaube die Frage war doch, ob es sich hier um redundanten Code handelt. Aus meiner bescheidenen Sicht: Nein, das sieht nur so aus, weil hier zufällig Deklaration und Prozeduraufruf die selben zwei Werte enthalten. Man kann das zwar mit den bisher diskutierten Verfahren "umgehen", aber dass der Code dadurch leserlicher wird wage ich zu bezweifeln :-)


Alle Zeitangaben in WEZ +1. Es ist jetzt 10:28 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