Virtual LinkedLists und Zusatzfunktionen mit PB-Syntax

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
Franky
Beiträge: 1132
Registriert: 29.08.2004 16:31
Wohnort: Münsterland
Kontaktdaten:

Virtual LinkedLists und Zusatzfunktionen mit PB-Syntax

Beitrag von Franky »

Hi Leude :D

Ansätze für weitere LinkedList-Funktionen gibt es ja zur genüge, was mich nur nervte war das verlorengehen der PB-Syntax. die alternativen LinkedLists arbeiteten immer mit Pointern, was ich im Quelltext einfach zu unübersichtlich fand. (bei Liste() sieht man direkt, dass es ne liste is, bei *Liste() kann man´s nur vermuten)

Also hab ich mich ma dran begeben, sowas selbst zu bauen.

Zuersteinmal sei hier einigen Leuten zu danken:
1.)Deeem, der mir half, wenn mein "Wie geht nochma ASM"-Gedächtnis ma wieder versagte
2.)DarkDragon, der mir den Link zu
3.)HellHounds Ansatz für ein Template ( http://www.purebasic-lounge.de/viewtopi ... 8582#38582
zeigte
4.)Mama, Papa, Meinem Agenten und den Regisseuren uswusf

was ist das hier?
Ein BefehlsSatz von Zusatzfunktionen für LinkedLists, die es Erlauben, (fast) die PureBasic-Syntax bei zu behalten (um die Typenangabe kam ich leider net rum, aber das sollte nicht weiter stören)
Befehle:
InitVirtualType(Typ)
Muss für jeden VariablenTyp, der in LinkedLists verwendet werden Soll angegeben werden. Dieses Macro erstellt die gebrauchten Funktionen für den Jeweiligen Typ
VirtualizeList(Liste(),Typ)
Vorbereiten einer Liste für das Virtuelle Verarbeiten
Virtual_SetList(Liste(),Typ,ListenHeader)
Mit Virtual_SetList kann man eine Liste auf jeden beliebigen Speicher zeigen lassen. Der ListenHeader muss die Structur LinkedList haben (siehe Code). Nach dem "umbiegen" des Zeigers kann mit der Liste gearbeitet werden wie immer. Wichtig: Da der Direkte Zeiger auf den Header umgebogen wird, bleiben etwaige altDaten vorhanden (siehe Bsp1.pb).
UnVirtualizeAllLists
Diese Funktion muss am Ende jedes Codes stehen, damit die ListenZeiger wieder auf die Richtige Stelle umgebogen werden, sodass PB die Listen wieder vernünftig entfernen kann
UnvirtualizeList(LinkedList(),Typ)
Macht die Liste wieder zu einer Normalen Liste. Der ListenHeaderZeiger zeigt nun wieder auf den von PB dieser Liste ehemals zugewiesenen Header.
GetListPointer(LinkedList(),Typ)
Sagt, wohin der ListenZeiger zeigt
GetListHeaderPointer(LinkedList(),Typ)
Sagt, wohin der ListenHeaderZeiger zeigt
SplitList(Liste1(),Liste2(),Typ,element)
Zerschneidet Liste1() VOR Element und erstellt aus dem Rest die Liste2
ConnectLists(Liste1(),Liste2(),Typ)
Fügt Liste1 und Liste2 zu Liste1 zusammen

So, hier nun die IncludeDatei:

Code: Alles auswählen

Enumeration  
   #VirtualTypes_s
   #VirtualTypes_b
   #VirtualTypes_c
   #VirtualTypes_w
   #VirtualTypes_l
   #VirtualTypes_d
   #VirtualTypes_q
EndEnumeration   
     
Structure LinkedList
        FirstEl.l
        LastEl.l
        elementSize.l
        Menge.l
        lindex.l
        current_adr.l
EndStructure

Structure LL_Head
             header.l
             current.l
EndStructure

Structure LL_RealAdr
      listadr.l
      headeradr.l
EndStructure 

Structure LL_Element
         nachher.l
         vorher.l
EndStructure
 
Global Virtual_Hold.l
Global NewList _Virtual_ListeHeaders.LL_RealAdr()



Macro InitVirtualType(mpqurkak_Typ)
;
      Procedure  VirtualizeList_#mpqurkak_Typ#(LinkedList.mpqurkak_Typ());Macht eine Normale Liste zur Virtuellen
            !MOV eax,[esp+0] ;ListenHeader in Virtual_Hold lesen
            !MOV dword[v_Virtual_Hold],eax
            AddElement(_Virtual_ListeHeaders())
                    _Virtual_ListeHeaders()\listadr=Virtual_Hold
                    _Virtual_ListeHeaders()\headeradr=PeekL(Virtual_Hold)
            ClearList(LinkedList())
      EndProcedure

      Procedure Virtual_SetList_#mpqurkak_Typ(LinkedList.mpqurkak_Typ(),*mp_adr_hold.linkedlist)      
      Protected *LLHead.LL_Head,*mp_adr_hold2.LinkedList
           !MOV eax,[esp+0];Enthält den Pointer auf die Linkedlist (so wie t_worte bei ner Liste namens Worte())
           !MOV dword[v_Virtual_Hold],eax;Verschiebt´s in nen zwischenhalter
           *LLHead=virtual_hold;Setzt den LLHead auf den Listheader (muss ich nich so viel mit ASM arbeiten)
           
           ;Alten Header sichern
           *mp_adr_hold2=*LLHead\header
           
           ;Richtige Elementgröße angeben
           CompilerIf  Defined(VirtualTypes_#mpqurkak_Typ,#PB_Constant)
                   #Vpqtest_#mpqurkak_Typ=#VirtualTypes_#mpqurkak_Typ
           CompilerElse
                   #vpqtest_#mpqurkak_Typ=-1
           CompilerEndIf
           
           CompilerSelect  #Vpqtest_#mpqurkak_Typ
              CompilerCase #VirtualTypes_b
                       *mp_adr_hold\elementsize=SizeOf(BYTE)+8      
              CompilerCase #VirtualTypes_l
                       *mp_adr_hold\elementsize=SizeOf(LONG)+8      
              CompilerCase #VirtualTypes_s
                       *mp_adr_hold\elementsize=SizeOf(LONG)+8      
              CompilerCase #VirtualTypes_w
                       *mp_adr_hold\elementsize=SizeOf(WORD)+8      
              CompilerCase #VirtualTypes_c
                       *mp_adr_hold\elementsize=SizeOf(Character)+8      
              CompilerCase #VirtualTypes_d
                       *mp_adr_hold\elementsize=SizeOf(Double)+8      
              CompilerCase #VirtualTypes_q
                       *mp_adr_hold\elementsize=SizeOf(quad)+8      
              CompilerDefault
                       *mp_adr_hold\elementsize=SizeOf(mpqurkak_Typ)+8      
            CompilerEndSelect

           ;Alte currentadr sichern
           If *mp_adr_hold2<>0 And MemorySize(*mp_adr_hold2)=SizeOf(LinkedList); gibt ne Alte Liste; Ist also ne Virtual List 
                    *mp_adr_hold2\current_adr=*LLHead\current
           EndIf   
           ;Header neu verlinken          
           *LLHEAD\header=*mp_adr_hold
           *LLHead\current=*mp_adr_hold\current_adr
      EndProcedure
      
      Procedure.l  GetListPointer_#mpqurkak_Typ(LinkedList.mpqurkak_Typ())
               !MOV Eax,[esp+0]               
      EndProcedure
      
      Procedure.l GetListHeaderPointer_#mpqurkak_Typ(LinkedList.mpqurkak_Typ())
               !MOV EBX,[esp+0]
               !MOV EAX,dword[ebx]
               !MOV dword[v_Virtual_Hold],EAX
               ProcedureReturn  Virtual_Hold
      EndProcedure
      
      Procedure RecountList_#mpqurkak_Typ(LinkedList.mpqurkak_Typ())
                FirstElement(LinkedList())
                *Element.LL_Element=@LinkedList()-8
                menge=0
                While *Element<>0
                      *Element=*Element\nachher
                      INC menge
                Wend 
                ProcedureReturn  menge
      EndProcedure
      
      Procedure   SplitList_#mpqurkak_Typ(LinkedList_Anf.mpqurkak_Typ(),LinkedList_End.mpqurkak_Typ(),element.l)
            If element>0 And element<CountList(LinkedList_Anf())
              LastElement(LinkedList_Anf())
              mylast.l=@LinkedList_Anf()-8
              SelectElement(LinkedList_Anf(),element-1)
              *NeuEnde.LL_Element=@LinkedLIst_Anf()-8
              If *NeuEnde\nachher<>0
                    *NeuAnfang.LL_Element=*NeuEnde\nachher
                    *NeuEnde\nachher=0
                    *NeuAnfang\vorher=0
                    *Liste_Alt.LinkedList=GetListHeaderPointer_#mpqurkak_Typ(LinkedList_Anf())
                    *Liste_Alt\lastel=*NeuEnde
                    ClearList(LinkedList_End())
                    *Liste_Neu.LinkedList=GetListHeaderPointer_#mpqurkak_Typ(LinkedList_End())
                    *Liste_Neu\firstel=*NeuAnfang
                    *Liste_Neu\lastel=mylast
                    
                    ResetList(LinkedList_End())
                    ResetList(LinkedList_Anf())
                    *Liste_Alt\menge=ReCountList_#mpqurkak_Typ(LinkedList_Anf())
                    *Liste_Neu\menge=ReCountList_#mpqurkak_Typ(LinkedList_End())                    
              EndIf
             EndIf
      EndProcedure 
      
      Procedure ConnectLists_#mpqurkak_Typ(LinkedList_Anf.mpqurkak_Typ(),LinkedList_End.mpqurkak_Typ())
                  *Liste1.LinkedList=GetListHeaderPointer(LinkedList_Anf(),mpqurkak_Typ)
                  *Liste2.LinkedList=GetListHeaderPointer(LinkedList_End(),mpqurkak_Typ)
                  If *Liste1\firstel=0;Kein Element in Liste 1, wird also nur rüberkopiert
                        *Liste1\firstel=*Liste2\firstel
                        *Liste1\lastel=*Liste2\lastel
                        *Liste1\menge=*Liste2\menge
                        
                        *Liste2\menge=0
                        *Liste2\firstel=0
                        *Liste2\lastel=0
                        ResetList(LinkedList_End())
                        ResetList(LinkedList_Anf())
                  ElseIf *Liste2\firstel<>0;Zweite Liste hat kein Element, also alles Egal
                      *MomLetztElement.LL_Element=*Liste1\lastel
                      *MomErstElement.LL_Element=*Liste2\firstel
                      *Liste1\lastel=*Liste2\lastel
                      *MomLetztElement\nachher=*momerstelement
                      *MomErstElement\vorher=*MomLetztElement
                      *Liste1\menge=*Liste1\menge+*Liste2\menge
                      *Liste2\menge=0
                      *Liste2\firstel=0
                      *Liste2\lastel=0
                      ResetList(LinkedList_End())
                      ResetList(LinkedList_Anf())
                  EndIf
      EndProcedure
      
      Procedure  UnVirtualizeList_#mpqurkak_Typ(LinkedList.mpqurkak_Typ())
                adr.l=GetListPointer(LinkedList(),mpqurkak_Typ)
                ForEach  _Virtual_ListeHeaders()
                     If _Virtual_ListeHeaders()\listadr=adr 
                            PokeL(adr,_Virtual_ListeHeaders()\headeradr)
                            ResetList(LinkedList())
                            Break
                     EndIf
                Next 
      EndProcedure
EndMacro

Macro VirtualizeList(LinkedList,mpqurkak_Typ)
     VirtualizeList_#mpqurkak_Typ(LinkedList)
EndMacro 

Macro UnVirtualizeList(LinkedList,mpqurkak_Typ)
     UnVirtualizeList_#mpqurkak_Typ(LinkedList)
EndMacro 

Macro Virtual_SetList(LinkedList,mpqurkak_Typ,mp_adr_hold)
      Virtual_SetList_#mpqurkak_Typ(LinkedList,mp_adr_hold)
EndMacro 

Procedure UnVirtualizeAllLists();Führt am Ende alles wieder zusammen, damit PB normal den Speicher reinigen kann und 
      ForEach  _Virtual_ListeHeaders()
              PokeL(_Virtual_ListeHeaders()\listadr,_Virtual_ListeHeaders()\headeradr)
      Next
      ClearList(_Virtual_ListeHeaders())
EndProcedure  

 
Macro GetListPointer(LinkedList,Typ)
       GetListPointer_#Typ(LinkedList)
EndMacro

Macro  GetListHeaderPointer(LinkedList,Typ)
        GetListHeaderPointer_#Typ(LinkedList)
EndMacro

Macro SplitList(LinkedList1,LinkedList2,element,Typ)
      SplitList_#Typ(LinkedList1,LinkedList2,element)
EndMacro

Macro ConnectLists(LinkedList1,LinkedList2,Typ)
     ConnectLists_#Typ(LinkedList1,LinkedList2)
EndMacro
Dann Hier ein Beispiel für VirtualizeList

Code: Alles auswählen

IncludeFile  "Virtual_List.pb"

Enumeration 
       #w_Artikel
       #w_Nomen
       #w_Verben
       #w_Adjektive
EndEnumeration  

;Beispiel1: Verschiedene Listen in einem Array 
Global Dim Listen.LinkedList(10)
Global NewList  Worte.s()
InitVirtualType(s)
VirtualizeList(Worte(),s)


Macro LiesWoerter(Art)
  Virtual_SetLIST(Worte(),s,Listen(#w_#ART))
  string.s=""
  Restore ART
  Read string.s
  While String<>"!§$last!$%"
         AddElement(Worte())
               Worte()=String
               Read string 
  Wend
EndMacro 


LiesWoerter(Artikel)
LiesWoerter(Nomen)
LiesWoerter(Verben)
LiesWoerter(Adjektive)
For a=1 To 10
      string.s=""
      For q=#w_Artikel To #w_Adjektive     
             Virtual_SetLIST(Worte(),s,Listen(q))     
             SelectElement(Worte(),Random(CountList(Worte())))
              String=string+Worte()+" "
      Next 
      Debug string.s
Next 
CallDebugger
UnVirtualizeAllLists()

DataSection
Artikel:
Data.s "Ein","Eine","Der","Die","Das","Den","!§$last!$%"
Nomen:
Data.s "Haus","Boot","Baum","Garten","Wolkenkratzer","Hund","Katze","Maus","!§$last!$%"
Verben:
Data.s "ist","war","wird","wurde","!§$last!$%"
Adjektive:
Data.s "schön","blau","groß","genial","unglaublich","unbrauchbar","nervig","sensationsgeil","buggy","!§$last!$%"
EndDataSection
Ein Beispiel für SplitList:

Code: Alles auswählen

IncludeFile  "Virtual_List.pb"

Enumeration 
       #w_Artikel
       #w_Nomen
       #w_Verben
       #w_Adjektive
EndEnumeration  

;Beispiel 3: Eine Liste zerstückeln
Global NewList Artikel.s()
Global NewList Nomen.s()
Global NewList Verben.s()
Global NewList Adjektive.s()
InitVirtualType(s)

Macro LiesWoerter(Art)
  string.s=""
  Restore ART
  Read string.s
  While String<>"!§$last!$%"
         AddElement(artikel())
               Artikel()=String
               Read string 
  Wend
EndMacro 


LiesWoerter(Dinger)
;Alle Begriffe finden sich nun in Worte
ForEach  Artikel()
         Debug  Artikel()
Next          
Debug  "________Artikel________"
;6 Artikel, daher muss Element 7 das erste Element für Nomen() werden
SplitList(Artikel(),Nomen(),6,s)
ForEach Artikel()
        Debug  Artikel()
Next        
Debug "__________Nomen__________"
;Jetzt ist der Rest in Nomen().
;Da es nur 8 Nomen sind, kommt wiederum dieser Rest in Verben
SplitList(Nomen(),Verben(),8,s)
ForEach  Nomen()
    Debug  Nomen()
Next     
Debug "__________Verben__________"
;Jetzt ist der Rest in Verben().
;Da es nur 4 Verben sind, kommt wiederum dieser Rest in Verben
FirstElement(Verben())
SplitList(Verben(),Adjektive(),4,s)
ForEach  Verben()
    Debug  Verben()
Next     
Debug "___________Adjektive_______"
ForEach  Adjektive()
     Debug  Adjektive()
Next 
CallDebugger
UnVirtualizeAllLists()     
DataSection
Dinger:
Data.s "Ein","Eine","Der","Die","Das","Den"
Data.s "Haus","Boot","Baum","Garten","Wolkenkratzer","Hund","Katze","Maus"
Data.s "ist","war","wird","wurde"
Data.s "schön","blau","groß","genial","unglaublich","unbrauchbar","nervig","sensationsgeil","buggy","!§$last!$%"
EndDataSection
Und eins für ConnectList:

Code: Alles auswählen

IncludeFile  "Virtual_List.pb"

Enumeration 
       #w_Artikel
       #w_Nomen
       #w_Verben
       #w_Adjektive
EndEnumeration  

;Beispiel 2: Mehrere Listen zu einer connecten
Global NewList  Worte.s()
Global NewList Nomen.s()
Global NewList Verben.s()
Global NewList Adjektive.s()
Global NewList Artikel.s()
InitVirtualType(s)
;Beispiel 1: Ein Array von Listen


Macro LiesWoerter(Art)
  string.s=""
  Restore ART
  Read string.s
  While String<>"!§$last!$%"
         AddElement(Art())
               Art()=string
               Read string 
  Wend
EndMacro 


LiesWoerter(Artikel)
LiesWoerter(Nomen)
LiesWoerter(Verben)
LiesWoerter(Adjektive)
ClearList(Worte())
ConnectLists(Worte(),Artikel(),s)
ForEach Worte()
       Debug Worte()
Next        
Debug "_______________________"
ConnectLists(Worte(),Nomen(),s)
ForEach Worte()
       Debug Worte()
Next        
Debug "_______________________"
ConnectLists(Worte(),Verben(),s)
ForEach Worte()
       Debug Worte()
Next        
Debug "_______________________"
ConnectLists(Worte(),Adjektive(),s)
Debug  CountList(Worte())
ForEach Worte()
       Debug Worte()
Next        
Debug "_______________________"
CallDebugger

UnVirtualizeAllLists()
DataSection
Artikel:
Data.s "Ein","Eine","Der","Die","Das","Den","!§$last!$%"
Nomen:
Data.s "Haus","Boot","Baum","Garten","Wolkenkratzer","Hund","Katze","Maus","!§$last!$%"
Verben:
Data.s "ist","war","wird","wurde","!§$last!$%"
Adjektive:
Data.s "schön","blau","groß","genial","unglaublich","unbrauchbar","nervig","sensationsgeil","buggy","!§$last!$%"
EndDataSection
Ob die Beispiele jetzt so passend sind, weiß ich nicht. Brauchbar
ist es aber überall, wo man auf komplexere Datenstrukturen trifft.

Feedback Willkommen, Bugreports geduldet :D

Achja, weitere Funktionen für LinkedLists natürlich auch ;)
Falsch zugeordnetes Zitat des Tages: "O'zapft is" - Edward Snowden :)
Hellhound66
Beiträge: 476
Registriert: 23.03.2005 23:19

Beitrag von Hellhound66 »

Boah, das ist ja cool!
Hat also doch jemand eine sinnvolle Anwendung für ein Template-Macro gefunden.
Optimismus ist ein Mangel an Information.
Antworten