Strukturierter Speicherzugriff

Anfängerfragen zum Programmieren mit PureBasic.
ullmann
Beiträge: 205
Registriert: 28.10.2005 07:21

Strukturierter Speicherzugriff

Beitrag von ullmann »

Hallo,

in einem Array verwalte ich Zeiger auf Speicherbereiche, die alle unterschiedlich groß sein können, je nachdem, wieviele Informationen sie beinhalten.

Solch ein Speicherbereich kann in seiner Größe wachsen oder schrumpfen, denn er beinhaltet unterschiedlich viele Objekte verschiedener Typen.

Der Aufbau wäre z.B. so:

Code: Alles auswählen

Structure Objekt_A
  Eigenschaft_A1.a
  Eigenschaft_A2.a
EndStructure

Structure Objekt_B
  Eigenschaft_B1.a
  Eigenschaft_B2.a
  Eigenschaft_B3.a
EndStructure

Structure C3
  C3_1.a
  C3_2.a
EndStructure

Structure Objekt_C
  Eigenschaft_C1.a
  Eigenschaft_C2.a
  Eigenschaft_C3.C3
  Eigenschaft_C4.a
EndStructure

Define.l X, Y, Z

Aufbau eines Speicherblockes:

Offset    Inhalt                     Größe
--------------------------------------------
 0         X (= Anzahl Objekt_A)      4 Byte
 4         Y (= Anzahl Objekt_B)      4 Byte
 8         Z (= Anzahl Objekt_C)      4 Byte
12        Objekte_A                  X x 2 Byte
..        Objekte_B                  Y x 3 Byte
..        Objekte_C                  Z x 5 Byte
Nun kann ich mit einer Variablen den Offset hoch und runter zählen und nach Lust und Laune die Objekte Byte für Byte Peeken und Poken. Ich denke, dass wird problemlos funktionieren.

Ich hätte aber gern gut strukturierten und gut lesbaren Code. Welche Möglichkeiten gibt es dazu? Kann ich ganze Strukturen peeken und poken? Zum Beispiel erst den Header (also X, Y, Z) als Struktur poken, dann X mal die Variablen vom Typ Objekt_A, dann Y mal die Variablen vom Typ Objekt_B usw.

Danke für Antworten.
Benutzeravatar
STARGÅTE
Kommando SG1
Beiträge: 7031
Registriert: 01.11.2005 13:34
Wohnort: Glienicke
Kontaktdaten:

Re: Strukturierter Speicherzugriff

Beitrag von STARGÅTE »

Ich wurde zusätzlich noch den Offset eines Blocks speichern.
Dann kannst du das so machen (mal vereinfach):

Code: Alles auswählen

Structure Objekt_A
  Eigenschaft_A1.a
  Eigenschaft_A2.f
EndStructure

Structure ObjektBlock_A
	Objekt.Objekt_A[0]
EndStructure

Structure Objekt_B
  Eigenschaft_B1.q
  Eigenschaft_B2.d
  Eigenschaft_B3.s{10}
EndStructure

Structure ObjektBlock_B
	Objekt.Objekt_B[0]
EndStructure


Structure Buffer
	Count_Objekt_A.i
	Count_Objekt_B.i
	*ObjektBlock_A.ObjektBlock_A
	*ObjektBlock_B.ObjektBlock_B
	*Datas[0]
EndStructure

*Buffer.Buffer = AllocateMemory(SizeOf(Buffer)+5*SizeOf(Objekt_A)+7*SizeOf(Objekt_B))
*Buffer\Count_Objekt_A = 5
*Buffer\Count_Objekt_B = 7
*Buffer\ObjektBlock_A = @*Buffer\Datas
*Buffer\ObjektBlock_B = *Buffer\ObjektBlock_A + *Buffer\Count_Objekt_A*SizeOf(Objekt_A)

With *Buffer\ObjektBlock_A\Objekt[4]
	\Eigenschaft_A1 = 100
	\Eigenschaft_A2 = #PI
EndWith
With *Buffer\ObjektBlock_B\Objekt[0]
	\Eigenschaft_B1 = 100000
	\Eigenschaft_B2 = #PI
	\Eigenschaft_B3 = "Hallo Welt"
EndWith

Debug *Buffer\ObjektBlock_A\Objekt[4]\Eigenschaft_A2
Debug *Buffer\ObjektBlock_B\Objekt[0]\Eigenschaft_B1

ShowMemoryViewer(*Buffer, SizeOf(Buffer)+5*SizeOf(Objekt_A)+7*SizeOf(Objekt_B))
EDIT:

Mit Variable.Structure[0] kann man ein "undefiniertes" Array erzeugen das keine Länge hat.
So kannst du dort beliebig durch navigieren.
Im Header des Buffers definierst du ja eh die Anzahl der Blockeinträge.
Zum schnelleren Auslesen brauchst du dann noch die direkten Pointern zu den Blöcken.
Dann kannst du es so elegent auslesen wie ich es da oben zeige.
Die *ObjektBlock Pointer müssen also immer erst zur Leufzeit gesetzt werden.

Alternativ kannst du sie auch weglassen und selbst definieren in einer anderen Struktur.

EDIT2: noch mal Code angepasst.
PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Aktuelles Projekt: Lizard - Skriptsprache für symbolische Berechnungen und mehr
ullmann
Beiträge: 205
Registriert: 28.10.2005 07:21

Re: Strukturierter Speicherzugriff

Beitrag von ullmann »

Vielen Dank Stargate.

Hilft mir schon etwas weiter.

Jedoch soll das Programm im Extremfall 300.000 Simulationsobjekte (= Arrayeinträge) bewältigen, also 300.000 "Buffers" (ich hoffe, dass die Speicherverwaltung das mitmacht, mit Listen in Arrays lief der Speicherverbrauch schon bei 30.000 Simulationsobjekten, jedes mit 2 leeren Listen, auf 800 MB hoch :o, deshalb stelle ich jetzt auf eigene Speicherblöcke um). Jeder Buffer hat 11 Objekttypen. Das wäre ein zusätzlicher Speicherverbrauch für die Objektblockzeiger von 300.000 x 11 x 4 Byte = 12,6 MB. Das klingt nicht viel, aber es sind noch massig viele andere Daten zu speichern. Die Simulation benötigt keinen Zugriff auf einzelne Objekte verschiedener Buffer. Vielmehr wird/werden nur ein oder zwei Buffer komplett und der Reihe nach in Variablen, Arrays und Listen ausgelesen und damit interagiert dieses Simulationsobjekt mit seiner Umwelt (ist ein ganz anderes Array) oder mit dem zweiten ausgelesenen Simulationsobjekt. Dann wird/werden die Variablen, Arrays und Listen des einen oder der beiden Simulationsobjekte wieder der Reihe nach und komplett in den/die Buffer geschrieben und das Programm wendet sich dem nächsten Simulationsobjekt zu.

Ich brauche also nur das sequentielle Lesen und Schreiben aller Daten eines Buffers und das möglichst ohne zusätzliche Objektblockzeiger. Und da bin ich wieder am Grübeln und wäre für Tipps dankbar.
Benutzeravatar
STARGÅTE
Kommando SG1
Beiträge: 7031
Registriert: 01.11.2005 13:34
Wohnort: Glienicke
Kontaktdaten:

Re: Strukturierter Speicherzugriff

Beitrag von STARGÅTE »

Wenn es wirklich um "viele" Datenbrocken geht, dann musst du musst du zwangswiese auf eigene Speicherverwaltung zurückgreifen, jenachdem was du wirklich brauchst.
Das Listen und auch Arrays teilweise viel Speicher schlucken obwohl sie leer sind, ist klar, weil sie ja beide Header haben.

Wenn du nun aber wirklich mit einer eigenen Speicherverwaltung arbeitest, dann kommst du nicht drum herrum Zeiger zu verwenden, nur so kommst du ja an die Daten auch schnell ran.
Wo du diese Zeiger speicherst, und ob überhaupt ist ja egal.

Am wichtigsten bleibt die benutzen dieser [0]-Arrays, weil es ermöglicht ohne Header Arrays zu verwalten, ohne feste Länge

Code: Alles auswählen

Structure LongArray
	l.l[0]
EndStructure

*Buffer.LongArray = AllocateMemory(40)

For n = 0 To 9
	*Buffer\l[n] = n
Next

For n = 0 To 9
	Debug *Buffer\l[n]
Next
PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Aktuelles Projekt: Lizard - Skriptsprache für symbolische Berechnungen und mehr
ullmann
Beiträge: 205
Registriert: 28.10.2005 07:21

Re: Strukturierter Speicherzugriff

Beitrag von ullmann »

Ja,
nochmals vielen Dank.
ullmann
Beiträge: 205
Registriert: 28.10.2005 07:21

Re: Strukturierter Speicherzugriff

Beitrag von ullmann »

Hab nochmal bisschen rumprobiert.

Wenn man einen temporären Zeiger mit überlagerten Typen (Strukturen) dem eigentlichen Speicherblock überlagert, kann man tatsächlich ganz bequem unterschiedliche Strukturen in den Speicherblock schreiben:

Code: Alles auswählen

Structure Objekt_A
  Eigenschaft_A1.a
  Eigenschaft_A2.a
EndStructure

Structure Objekt_B
  Eigenschaft_B1.a
  Eigenschaft_B2.a
  Eigenschaft_B3.a
EndStructure

Structure C3
  C3_1.a
  C3_2.a
EndStructure

Structure Objekt_C
  Eigenschaft_C1.a
  Eigenschaft_C2.a
  Eigenschaft_C3.C3
  Eigenschaft_C4.a
EndStructure

Structure Counters
  Count_A.l
  Count_B.l
  Count_C.l
EndStructure

Structure Flexibler_Zeiger
  StructureUnion
    Counters.Counters
    ObjektA.Objekt_A[0]
    ObjektB.Objekt_B[0]
    ObjektC.Objekt_C[0]
  EndStructureUnion
EndStructure

Structure Simobjekt
  Eigenschaft_SO.a
  *mem_SO
EndStructure

Dim Simobjekte.Simobjekt(3)   ; 3 Simulationsobjekte (Index 0 wird nicht benutzt)

For a = 1 To 3
  
  Simobjekte(a)\Eigenschaft_SO = 1 + Random(8)  ; eine nichtdynamische Eigenschaft des Simulationsobjektes, die direkt im Array gespeichert wird
    
  Simcount_A = Random(2) + 2    ; Anzahl Objekte_A: 2 bis 4     diese dynamischen Eigenschaften müssen in den Speicherblock
  Simcount_B = Random(2) + 2    ; Anzahl Objekte_B: 2 bis 4
  Simcount_C = Random(2) + 2    ; Anzahl Objekte_C: 2 bis 4
  
  Dim Objekte_A.Objekt_A(Simcount_A)   ; Objekte anlegen (Index 0 wird nicht benutzt)
  Dim Objekte_B.Objekt_B(Simcount_B)
  Dim Objekte_C.Objekt_C(Simcount_C)
  
  For i = 1 To Simcount_A                                   ; Objekte A mit Testdaten füllen
    Objekte_A(i)\Eigenschaft_A1 = 11 + Random(8)
    Objekte_A(i)\Eigenschaft_A2 = 11 + Random(8)
  Next i
  
  For i = 1 To Simcount_B                                   ; Objekte B mit Testdaten füllen
    Objekte_B(i)\Eigenschaft_B1 = 21 + Random(8)
    Objekte_B(i)\Eigenschaft_B2 = 21 + Random(8)
    Objekte_B(i)\Eigenschaft_B3 = 21 + Random(8)
  Next i
  
  For i = 1 To Simcount_C                                   ; Objekte C mit Testdaten füllen
    Objekte_C(i)\Eigenschaft_C1      = 31 + Random(8)
    Objekte_C(i)\Eigenschaft_C2      = 31 + Random(8)
    Objekte_C(i)\Eigenschaft_C3\C3_1 = 41 + Random(8)
    Objekte_C(i)\Eigenschaft_C3\C3_2 = 41 + Random(8)
    Objekte_C(i)\Eigenschaft_C4      = 51 + Random(8)
  Next i
  
  Memsize = SizeOf(Counters) + Simcount_A * SizeOf(Objekt_A)  ; Speicherbedarf berechnen
  Memsize + Simcount_B * SizeOf(Objekt_B)
  Memsize + Simcount_C * SizeOf(Objekt_C)
  
  *Speicheranfang = AllocateMemory(Memsize)
  
  If *Speicheranfang
  
    Simobjekte(a)\mem_SO = *Speicheranfang                     ; Speicherblock dem Simulationsobjekt zuweisen
    
    *Tempzeiger.Flexibler_Zeiger = *Speicheranfang                 ; Zähler in Speicherblock schreiben
    *Tempzeiger\Counters\Count_A = Simcount_A
    *Tempzeiger\Counters\Count_B = Simcount_B
    *Tempzeiger\Counters\Count_C = Simcount_C
    
    Offset = SizeOf(Counters)
    
    *Tempzeiger = *Speicheranfang + Offset                     ; Objekte A in Speicherblock schreiben
    For i = 1 To Simcount_A
      *Tempzeiger\ObjektA[i-1] = Objekte_A(i)
    Next i
    
    Offset + Simcount_A * SizeOf(Objekt_A)
    
    *Tempzeiger = *Speicheranfang + Offset                     ; Objekte B in Speicherblock schreiben
    For i = 1 To Simcount_B
      *Tempzeiger\ObjektB[i-1] = Objekte_B(i)
    Next i
    
    Offset + Simcount_B * SizeOf(Objekt_B)
    
    *Tempzeiger = *Speicheranfang + Offset                     ; Objekte C in Speicherblock schreiben
    For i = 1 To Simcount_C
      *Tempzeiger\ObjektC[i-1] = Objekte_C(i)
    Next i
    
  EndIf
      
Next a

For a = 1 To 3
  
  ShowMemoryViewer(Simobjekte(a)\mem_SO, MemorySize(Simobjekte(a)\mem_SO))
    
  If a<3
   MessageRequester("Weiter", "Weiter gehts")
  EndIf 
  
Next a
Das Auslesen schenke ich mir hier. Müsste analog funktionieren. Zumindest die Speicheranzeige (Empfehlung Byteliste und Fenster so breit ziehen, dass alles sichtbar ist) ist korrekt.
Benutzeravatar
STARGÅTE
Kommando SG1
Beiträge: 7031
Registriert: 01.11.2005 13:34
Wohnort: Glienicke
Kontaktdaten:

Re: Strukturierter Speicherzugriff

Beitrag von STARGÅTE »

Jup.
Bleibt nur noch zu sagen, dass Strings innerhalb dieser Blöcke separat geschrieben/gelesen werden müssen, außer du benutzt statische Strings.
PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Aktuelles Projekt: Lizard - Skriptsprache für symbolische Berechnungen und mehr
ullmann
Beiträge: 205
Registriert: 28.10.2005 07:21

Re: Strukturierter Speicherzugriff

Beitrag von ullmann »

Danke Stargate für den Hinweis. Strings in den dynamischen Eigenschaften sind aber nicht geplant. Ich habe aber trotzdem überlegt, ob es mit o.g. Methode funktionieren könnte, kam aber zu keinem Ergebnis. Ich habe es aber nicht ausprobiert, weil ich es nicht brauche.
Gruß
Antworten