Object - Manager Include

Hier könnt Ihr gute, von Euch geschriebene Codes posten. Sie müssen auf jeden Fall funktionieren und sollten möglichst effizient, elegant und beispielhaft oder einfach nur cool sein.
Benutzeravatar
cxAlex
Beiträge: 2111
Registriert: 26.06.2008 10:42

Object - Manager Include

Beitrag von cxAlex »

Hier mal ein kleines Object - Manager Include das ich gestern schnell zusammengeproggt habe.

Der Object - Manager funktioniert exakt wie der PB - ObjectManager:
http://www.purearea.net/pb/german/manua ... jects.html

d.H. er bietet Statische und Dynamische Indexierung, Automatische Deinitialsierung und ist leicht zu benutzen und verstehen.

Für was brauche ich das?
Nun, mit diesem Code könnt ihr allen euren Includes ein einfaches Managemant verpassen, wie es sämtliche PB Funktionen haben. (Window, Gadget, Image, Sprite, ....) . Unter anderem auch nützlich bei der Erstellung von DLLs, UserLibrarys usw. um "PB - Like" managed Funktionen zu bieten.

Am Ende des Includes steht ein kleines Beispiel um die Funktion des Managers zu demonstrieren:

Code: Alles auswählen

; ------------------------------------------------------------------------------------
; Include: Object - Manager
; Autor: Alexander Aigner
; minimale PB - Version: 4.3
; ------------------------------------------------------------------------------------

EnableExplicit

Prototype _OM_Init(cId.i, *Entry)

Structure _OM_Entry  ; OM - Eintrag
  isInit.i        ; Entry - ist Initialisiert
  *Data         ; Entry - Daten
EndStructure

Structure _OM_Entry_Holder
  Holder._OM_Entry[0]
EndStructure

Structure _OM_Inits  ; (De)Initialisierung - Aufrufe
  ; Init._OM_Init       ; Initialisierung für jedes Entry
  DeInit._OM_Init     ; DeInitialisierung für jedes Entry
EndStructure

Structure _OM_Data   ; OM - Informationen
  Count.i             ; Akteller Entry
  RealEntryCount.i    ; Wirkliche Anzahl der Entrys
  BlockSize.i          ; Größe eines Entrys
  BlockCount.i          ; Anzahl der Entry - Blöcke
  Pt._OM_Inits          ; Prototypes
  *Entry._OM_Entry_Holder ; Entrys
EndStructure

Enumeration -1
  #OM_Any
  #OM_StandardBlockSize = 25
EndEnumeration

Declare OM_Init(*DeInit._OM_Init, BlockSize.i = #OM_StandardBlockSize)
Declare OM_DeInit(*OM._OM_Data)
Declare OM_SetEntry(*OM._OM_Data, Id.i, *EntryData)
Declare OM_GetEntry(*OM._OM_Data, Id.i)
Declare OM_DeleteEntry(*OM._OM_Data, Id.i)
Declare OM_IsEntry(*OM._OM_Data, Id.i)
Declare OM_ParseAllEntrys(*OM._OM_Data, *Pt._OM_Init)
Declare OM_GetEntryCount(*OM._OM_Data)
Declare OM_GetSize(*OM._OM_Data)
; ------------------------------------------------------------------------------------
; Internal
; ------------------------------------------------------------------------------------

Macro Mem_Alloc(_mem)
  AllocateMemory(_mem)
EndMacro

Macro Mem_ReAlloc(_mem, _size)
  ReAllocateMemory(_mem, _size)
EndMacro

Macro Mem_Free(_mem)
  FreeMemory(_mem)
EndMacro

Procedure OM_Init(*DeInit._OM_Init, BlockSize.i = #OM_StandardBlockSize) ; Neuen Objekt - Manager erstellen
  Protected currentEntry
  Define *OM._OM_Data = Mem_Alloc(SizeOf(_OM_Data))
  With *OM
    \Pt\DeInit = *DeInit
    \BlockSize = BlockSize
    \BlockCount = 1
    \Count = 0
    \Entry = Mem_Alloc(\BlockSize*\BlockCount*SizeOf(_OM_Entry))
  EndWith
  ProcedureReturn *OM
EndProcedure

Procedure OM_DeInit(*OM._OM_Data) ; Objektmanager komplett freigeben
  Protected currentId
  With *OM
    OM_ParseAllEntrys(*OM, \Pt\DeInit) ; Alle Entrys Freigeben
    Mem_Free(\Entry) ; EntryIndex freigeben
    Mem_Free(*OM) ; ObjektManager Struktur freigeben
  EndWith
EndProcedure

Procedure OM_SetEntry(*OM._OM_Data, Id.i, *EntryData)
  Protected currentId, RtVar
  With *OM
    If Id = #OM_Any ; Id ermitteln
      \Count + 1
      currentId = \Count
    ElseIf Id>\Count
      \Count = Id
      currentId = \Count
    Else
      currentId = Id
    EndIf
    
    While currentId> = \BlockSize*\BlockCount ; Muss der Bereich vergrößert werden?
      \BlockCount + 1
      \Entry = Mem_ReAlloc(\Entry, \BlockSize*\BlockCount*SizeOf(_OM_Entry))
    Wend
    
    If \Entry\Holder[currentId]\isInit
      If Not OM_GetEntry(*OM, currentID) <> *EntryData ; Wenn alte Speicheradresse <> neuer Speicheradresse
        \Pt\DeInit(currentId, OM_GetEntry(*OM, currentID)) ; Alte Daten deinitialisieren
      EndIf
    Else
      \RealEntryCount + 1 ; Wenn neuer Entry : Anzahl erhöhen
    EndIf



    
    \Entry\Holder[currentId]\Data = *EntryData ; Daten schreiben
    \Entry\Holder[currentId]\isInit = #True ; Initialisiert = #True
    
    If Id = #OM_Any ; Rückgabewert festlegen
      RtVar = currentId
    Else
      RtVar = *EntryData;\Entry\Holder[currentId]\Data
    EndIf
  EndWith
  ProcedureReturn RtVar
EndProcedure

Procedure OM_GetEntry(*OM._OM_Data, Id.i) ; Entry holen
  Protected RtVar
  With *OM
    If OM_IsEntry(*OM, Id)
      RtVar = \Entry\Holder[Id]\Data
    EndIf
  EndWith
  ProcedureReturn RtVar
EndProcedure

Procedure OM_DeleteEntry(*OM._OM_Data, Id.i) ; Entry löschen
  Protected RtVar
  With *OM
    If OM_IsEntry(*OM, Id)
      \Pt\DeInit(Id, OM_GetEntry(*OM, Id)) ; Deinitialisieren
      \Entry\Holder[Id]\isInit = #False
      \RealEntryCount-1
      If \Count = Id ; zu löschendes Element = Letztes Element: Count kann dekrementiert werden
        \Count-1
      EndIf
    EndIf
  EndWith
  ProcedureReturn RtVar
EndProcedure

Procedure OM_IsEntry(*OM._OM_Data, Id.i) ; Prüfen: ist Entry gültig?
  Protected RtVar
  With *OM
    If Id> = \BlockSize*\BlockCount
      RtVar = #False
    Else
      If \Entry\Holder[Id]\isInit
        RtVar = #True
      Else
        RtVar = #False
      EndIf
    EndIf
  EndWith
  ProcedureReturn RtVar
EndProcedure

Procedure OM_ParseAllEntrys(*OM._OM_Data, *Pt._OM_Init) ; Alle Entrys an Procedure senden
  Protected currentId, EntryCount
  With *OM
    For currentId = 0 To \Count
      If OM_IsEntry(*OM, currentId)
        *Pt(currentId, OM_GetEntry(*OM, currentId))
        EntryCount+1
        If EntryCount >= \RealEntryCount
          Break
        EndIf
      EndIf
    Next
  EndWith
EndProcedure

Procedure OM_GetEntryCount(*OM._OM_Data) ; Anzahl der Entrys ermitteln
  Protected RtVar
  With *OM
    RtVar = \RealEntryCount
  EndWith
  ProcedureReturn RtVar
EndProcedure

Procedure OM_GetSize(*OM._OM_Data) ; Speichergröße des Managers ermitteln
  Protected RtVar
  With *OM
    RtVar = SizeOf(_OM_Data)+\BlockCount*\BlockSize*SizeOf(_OM_Entry)
  EndWith
  ProcedureReturn RtVar
EndProcedure

DisableExplicit






; ------------------------------------------------------------------------------------
; Beispiel:
; ------------------------------------------------------------------------------------

; Beispiel - Struktur
Structure MyImage
  x.i
  y.i
  width.i
  height.i
  oID.i
  *RawData
EndStructure

; Deininitializer - callback
Procedure FreeMyImage(ImgId, *Img.MyImage)
  Debug "Lösche: Id: " + Str(ImgId) + " Data: " + Str(*Img)
  Mem_Free(*Img\RawData)
  Mem_Free(*Img)
EndProcedure

; Neues Image machen
Procedure NewMyImage(x.i, y.i, width.i, height.i)
  *Img.MyImage = Mem_Alloc(SizeOf(MyImage))
  *Img\x = x
  *Img\y = y
  *Img\width = width
  *Img\height = height
  *Img\oID = Random(1000000)
  *Img\RawData = Mem_Alloc(1000)
  ProcedureReturn *Img
EndProcedure

; Object - Manager Initialisieren
Global ImageManager = OM_Init(@FreeMyImage())

Procedure ImageInfo(ImgId)
  If OM_isEntry(ImageManager, ImgId)
    *Image.MyImage = OM_GetEntry(ImageManager, ImgId)
    Debug "X: " + Str(*Image\x)
    Debug "Y: " + Str(*Image\y)
    Debug "Width: " + Str(*Image\Width)
    Debug "Height: " + Str(*Image\Height)
    Debug "OS - ID: " + Str(*Image\oID)
  Else
    Debug "ImgID nicht gültig!"
  EndIf
EndProcedure

; Images erstellen
*NewImage.MyImage = NewMyImage(12, 45, 800, 600)
*NewImage2.MyImage = NewMyImage(0, 12, 600, 825)

; Mit Any in den Object-Manager laden
Img1 = OM_SetEntry(ImageManager, #OM_Any, *NewImage)

; Feste ID
OM_SetEntry(ImageManager, 45, *NewImage2)
; Probe
ImageInfo(Img1)
ImageInfo(45)

ImageInfo(46) ; müsste Fehler geben

OM_DeInit(ImageManager) ; Alle Elemente Freigeben
Zuletzt geändert von cxAlex am 02.01.2009 14:09, insgesamt 1-mal geändert.
Projekte: IO.pbi, vcpu
Pausierte Projekte: Easy Network Manager, µC Emulator
Aufgegebene Projekte: ECluster

Bild

PB 5.1 x64/x86; OS: Win7 x64/Ubuntu 10.x x86
Andesdaf
Moderator
Beiträge: 2671
Registriert: 15.06.2008 18:22
Wohnort: Dresden

Beitrag von Andesdaf »

schön und praktisch :allright:
Win11 x64 | PB 6.20
Benutzeravatar
cxAlex
Beiträge: 2111
Registriert: 26.06.2008 10:42

Beitrag von cxAlex »

Kleines Update

Nun mit einer Optimizer-Procedure um den Manager zu optimieren (falls z.B. sehr hohe IDs gewählt wurden). Wie immer ein Beispiel am Schluss:

Code: Alles auswählen

; ------------------------------------------------------------------------------------
; Include: Object - Manager
; Autor: Alexaner Aigner
; minimale PB - Version: 4.3
; ------------------------------------------------------------------------------------

EnableExplicit

Prototype _OM_Init(cId.i, *Entry)
Prototype _OM_OptimizeManager(oldID, newID, *Entry)

Structure _OM_Entry  ; OM - Eintrag
  isInit.i        ; Entry - ist Initialisiert
  *Data         ; Entry - Daten
EndStructure

Structure _OM_Entry_Holder
  Holder._OM_Entry[0]
EndStructure

Structure _OM_Inits  ; (De)Initialisierung - Aufrufe
  ; Init._OM_Init       ; Initialisierung für jedes Entry
  DeInit._OM_Init     ; DeInitialisierung für jedes Entry
EndStructure

Structure _OM_Data   ; OM - Informationen
  Count.i             ; Akteller Entry
  RealEntryCount.i    ; Wirkliche Anzahl der Entrys
  BlockSize.i          ; Größe eines Entrys
  BlockCount.i          ; Anzahl der Entry - Blöcke
  Pt._OM_Inits          ; Prototypes
  *Entry._OM_Entry_Holder ; Entrys
EndStructure

Enumeration -1
  #OM_Any
  #OM_StandardBlockSize = 25
EndEnumeration

Declare OM_Init(*DeInit._OM_Init, BlockSize.i = #OM_StandardBlockSize)
Declare OM_DeInit(*OM._OM_Data)
Declare OM_SetEntry(*OM._OM_Data, Id.i, *EntryData)
Declare OM_GetEntry(*OM._OM_Data, Id.i)
Declare OM_DeleteEntry(*OM._OM_Data, Id.i)
Declare OM_IsEntry(*OM._OM_Data, Id.i)
Declare OM_ParseAllEntrys(*OM._OM_Data, *Pt._OM_Init)
Declare OM_GetEntryCount(*OM._OM_Data)
Declare OM_GetSize(*OM._OM_Data)
Declare OM_OptimizeManager(*OM._OM_Data, *Pt._OM_OptimizeManager)
; ------------------------------------------------------------------------------------
; Internal
; ------------------------------------------------------------------------------------

Macro Mem_Alloc(_mem)
  AllocateMemory(_mem)
EndMacro

Macro Mem_ReAlloc(_mem, _size)
  ReAllocateMemory(_mem, _size)
EndMacro

Macro Mem_Free(_mem)
  FreeMemory(_mem)
EndMacro

Procedure OM_Init(*DeInit._OM_Init, BlockSize.i = #OM_StandardBlockSize) ; Neuen Objekt - Manager erstellen
  Protected currentEntry
  Define *OM._OM_Data = Mem_Alloc(SizeOf(_OM_Data))
  With *OM
    \Pt\DeInit = *DeInit
    \BlockSize = BlockSize
    \BlockCount = 1
    \Count = 0
    \Entry = Mem_Alloc(\BlockSize*\BlockCount*SizeOf(_OM_Entry))
  EndWith
  ProcedureReturn *OM
EndProcedure

Procedure OM_DeInit(*OM._OM_Data) ; Objektmanager komplett freigeben
  Protected currentId
  With *OM
    OM_ParseAllEntrys(*OM, \Pt\DeInit) ; Alle Entrys Freigeben
    Mem_Free(\Entry) ; EntryIndex freigeben
    Mem_Free(*OM) ; ObjektManager Struktur freigeben
  EndWith
EndProcedure

Procedure OM_OptimizeManager(*OM._OM_Data, *Pt._OM_OptimizeManager) ; Optimiert den Object Manager
  Protected *tOM._OM_Data = OM_Init(*OM\Pt\DeInit, *OM\BlockSize)
  Protected currentId, newId, *EntryData
  With *OM
    For currentId = 0 To \Count
      If OM_IsEntry(*OM, currentId)
        *EntryData = OM_GetEntry(*OM, currentId)
        newId = OM_SetEntry(*tOM, #OM_Any, *EntryData)
        *Pt(currentId, newId, *EntryData)
      EndIf
    Next
    Mem_Free(\Entry)
    \Entry = *tOM\Entry
    \Count = *tOM\Count
    \RealEntryCount = *tOM\RealEntryCount
    \BlockCount = *tOM\BlockCount
    Mem_Free(*tOM)
  EndWith
EndProcedure

Procedure OM_SetEntry(*OM._OM_Data, Id.i, *EntryData)
  Protected currentId, RtVar
  With *OM
    If Id = #OM_Any ; Id ermitteln
      \Count + 1
      currentId = \Count
    ElseIf Id>\Count
      \Count = Id
      currentId = \Count
    Else
      currentId = Id
    EndIf
    
    While currentId> = \BlockSize*\BlockCount ; Muss der Bereich vergrößert werden?
      \BlockCount + 1
      \Entry = Mem_ReAlloc(\Entry, \BlockSize*\BlockCount*SizeOf(_OM_Entry))
    Wend
    
    If \Entry\Holder[currentId]\isInit
      If Not OM_GetEntry(*OM, currentID)<>*EntryData ; Wenn alte Speicheradresse <> neuer Speicheradresse
        \Pt\DeInit(currentId, OM_GetEntry(*OM, currentID)) ; Alte Daten deinitialisieren
      EndIf
    Else
      \RealEntryCount + 1 ; Wenn neuer Entry : Anzahl erhöhen
    EndIf
    
    \Entry\Holder[currentId]\Data = *EntryData ; Daten schreiben
    \Entry\Holder[currentId]\isInit = #True ; Initialisiert = #True
    
    If Id = #OM_Any ; Rückgabewert festlegen
      RtVar = currentId
    Else
      RtVar = *EntryData;\Entry\Holder[currentId]\Data
    EndIf
  EndWith
  ProcedureReturn RtVar
EndProcedure

Procedure OM_GetEntry(*OM._OM_Data, Id.i) ; Entry holen
  Protected RtVar
  With *OM
    If OM_IsEntry(*OM, Id)
      RtVar = \Entry\Holder[Id]\Data
    EndIf
  EndWith
  ProcedureReturn RtVar
EndProcedure

Procedure OM_DeleteEntry(*OM._OM_Data, Id.i) ; Entry löschen
  Protected RtVar
  With *OM
    If OM_IsEntry(*OM, Id)
      \Pt\DeInit(Id, OM_GetEntry(*OM, Id)) ; Deinitialisieren
      \Entry\Holder[Id]\isInit = #False
      \RealEntryCount-1
      If \Count = Id ; zu löschendes Element = Letztes Element: Count kann dekrementiert werden
        \Count-1
      EndIf
    EndIf
  EndWith
  ProcedureReturn RtVar
EndProcedure

Procedure OM_IsEntry(*OM._OM_Data, Id.i) ; Prüfen: ist Entry gültig?
  Protected RtVar
  With *OM
    If Id> = \BlockSize*\BlockCount
      RtVar = #False
    Else
      If \Entry\Holder[Id]\isInit
        RtVar = #True
      Else
        RtVar = #False
      EndIf
    EndIf
  EndWith
  ProcedureReturn RtVar
EndProcedure

Procedure OM_ParseAllEntrys(*OM._OM_Data, *Pt._OM_Init) ; Alle Entrys an Procedure senden
  Protected currentId, EntryCount
  With *OM
    For currentId = 0 To \Count
      If OM_IsEntry(*OM, currentId)
        *Pt(currentId, OM_GetEntry(*OM, currentId))
        EntryCount + 1
        If EntryCount> = \RealEntryCount
          Break
        EndIf
      EndIf
    Next
  EndWith
EndProcedure

Procedure OM_GetEntryCount(*OM._OM_Data) ; Anzahl der Entrys ermitteln
  Protected RtVar
  With *OM
    RtVar = \RealEntryCount
  EndWith
  ProcedureReturn RtVar
EndProcedure

Procedure OM_GetSize(*OM._OM_Data) ; Speichergröße des Managers ermitteln
  Protected RtVar
  With *OM
    RtVar = SizeOf(_OM_Data) + \BlockCount*\BlockSize*SizeOf(_OM_Entry)
  EndWith
  ProcedureReturn RtVar
EndProcedure

DisableExplicit

; ------------------------------------------------------------------------------------
; Beispiel:
; ------------------------------------------------------------------------------------

; Beispiel - Struktur
Structure MyImage
  x.i
  y.i
  width.i
  height.i
  oID.i
  *RawData
EndStructure

; Deininitializer - callback
Procedure FreeMyImage(ImgId, *Img.MyImage)
  Debug "Lösche: Id: " + Str(ImgId) + " Data: " + Str(*Img)
  Mem_Free(*Img\RawData)
  Mem_Free(*Img)
EndProcedure

Procedure MyImageManagerOptimizerCallBack(oldId, newId, *tData)
  Debug "Alte Id: " + Str(oldId) + " Neue Id: " + Str(newId)
EndProcedure

; Neues Image machen
Procedure NewMyImage(x.i, y.i, width.i, height.i)
  *Img.MyImage = Mem_Alloc(SizeOf(MyImage))
  *Img\x = x
  *Img\y = y
  *Img\width = width
  *Img\height = height
  *Img\oID = Random(1000000)
  *Img\RawData = Mem_Alloc(1000)
  ProcedureReturn *Img
EndProcedure

; Object - Manager Initialisieren
Global ImageManager = OM_Init(@FreeMyImage())

Procedure ImageInfo(ImgId)
  If OM_isEntry(ImageManager, ImgId)
    *Image.MyImage = OM_GetEntry(ImageManager, ImgId)
    Debug "X: " + Str(*Image\x)
    Debug "Y: " + Str(*Image\y)
    Debug "Width: " + Str(*Image\Width)
    Debug "Height: " + Str(*Image\Height)
    Debug "OS - ID: " + Str(*Image\oID)
  Else
    Debug "ImgID nicht gültig!"
  EndIf
EndProcedure

; Images erstellen
*NewImage.MyImage = NewMyImage(12, 45, 800, 600)
*NewImage2.MyImage = NewMyImage(0, 12, 600, 825)

; Mit Any in den Object-Manager laden
Img1 = OM_SetEntry(ImageManager, #OM_Any, *NewImage)

; Feste ID
OM_SetEntry(ImageManager, 8000, *NewImage2)
; Probe
ImageInfo(Img1)
ImageInfo(8000)

ImageInfo(46) ; müsste Fehler geben

Debug "Größe alter Manager: " + Str(OM_GetSize(ImageManager)) + " Bytes"
OM_OptimizeManager(ImageManager, @MyImageManagerOptimizerCallBack())
Debug "Größe optimierter Manager: " + Str(OM_GetSize(ImageManager)) + " Bytes"


OM_DeInit(ImageManager) ; Alle Elemente Freigeben
Projekte: IO.pbi, vcpu
Pausierte Projekte: Easy Network Manager, µC Emulator
Aufgegebene Projekte: ECluster

Bild

PB 5.1 x64/x86; OS: Win7 x64/Ubuntu 10.x x86
Antworten