ByteVector - OOP

Share your advanced PureBasic knowledge/code with the community.
User avatar
StarBootics
Addict
Addict
Posts: 984
Joined: Sun Jul 07, 2013 11:35 am
Location: Canada

ByteVector - OOP

Post by StarBootics »

Hello everyone,

A code that I needed for my 3D game project but that could be useful for something else

Code: Select all

; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
; Project name : ByteVector
; File Name : ByteVector - OOP.pb
; File version: 1.1.0
; Programming : OK
; Programmed by : StarBootics
; Date : 13-04-2019
; Last Update : 04-11-2019
; PureBasic code : V5.71 LTS
; Platform : Windows, Linux, MacOS X
; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

DeclareModule ByteVector

  Interface ByteVector

    ElementCount.l()
    GetElement.b(Index.l)
    SetElement(Index.l, Element.b)
    PushBack(Element.b)
    PopBack()
    Clear()
    WriteByteVector(FileID.i)
    ReadByteVector(FileID.i)
    Free()

  EndInterface

  Declare.i New(P_ElementCount.l)

EndDeclareModule

Module ByteVector

  Structure Private_Members

    VirtualTable.i
    ElementCount.l
    DataPointer.i
  
  EndStructure
  
  Macro ReachElement(StartPtr, Index)
    
    (StartPtr + (Index) * SizeOf(Byte))
    
  EndMacro
  
  Macro IsBetween(Value, Lower, Upper)
    
    ((Value) >= (Lower) And (Value) <= (Upper))
    
  EndMacro
  
  Procedure.l ElementCount(*This.Private_Members)

    ProcedureReturn *This\ElementCount
  EndProcedure
  
  Procedure.b GetElement(*This.Private_Members, Index.l)
    
    If IsBetween(Index, 0, *This\ElementCount)
      If *This\DataPointer <> #Null
        Output.b = PeekB(ReachElement(*This\DataPointer, Index))
      EndIf
    Else
      DebuggerError("Byte Vector : Index out of bound !")
    EndIf
    
    ProcedureReturn Output
  EndProcedure
  
  Procedure SetElement(*This.Private_Members, Index.l, Element.b)
    
    If IsBetween(Index, 0, *This\ElementCount)
      If *This\DataPointer <> #Null
        PokeB(ReachElement(*This\DataPointer, Index), Element)
      EndIf
    Else
      DebuggerError("Byte Vector : Index out of bound !")
    EndIf
    
  EndProcedure
  
  Procedure PushBack(*This.Private_Members, Element.b)
    
    If *This\DataPointer <> #Null
      OldMemorySize = MemorySize(*This\DataPointer)
    Else
      OldMemorySize = 0
    EndIf
    
    NewMemory = AllocateMemory(OldMemorySize + SizeOf(Byte))
    
    If *This\DataPointer <> #Null
      CopyMemory(*This\DataPointer, NewMemory, MemorySize(*This\DataPointer))
      PokeB(NewMemory + MemorySize(*This\DataPointer), Element)
    Else
      PokeB(NewMemory, Element)
    EndIf
    
    If *This\DataPointer <> #Null
      FreeMemory(*This\DataPointer)
    EndIf
    
    *This\DataPointer = NewMemory
    *This\ElementCount = MemorySize(*This\DataPointer) / SizeOf(Byte) - 1
    
  EndProcedure
  
  Procedure PopBack(*This.Private_Members)
    
    If *This\DataPointer <> #Null
      NewMemorySize = MemorySize(*This\DataPointer) - SizeOf(Byte)
      If NewMemorySize >= SizeOf(Byte)
        NewMemory = AllocateMemory(NewMemorySize)
        CopyMemory(*This\DataPointer, NewMemory, MemorySize(NewMemory))
        FreeMemory(*This\DataPointer)
        *This\DataPointer = NewMemory
        *This\ElementCount = MemorySize(*This\DataPointer) / SizeOf(Byte) - 1
      Else
        FreeMemory(*This\DataPointer)
        *This\DataPointer = #Null
        *This\ElementCount = -1
      EndIf
      
    EndIf
    
  EndProcedure
  
  Procedure Clear(*This.Private_Members)
    
    If *This\DataPointer <> #Null
      FreeMemory(*This\DataPointer)
      *This\DataPointer = #Null
      *This\ElementCount = -1
    EndIf
    
  EndProcedure
  
  Procedure WriteByteVector(*This.Private_Members, FileID.i)
    
    If *This\DataPointer <> #Null
      WriteLong(FileID, MemorySize(*This\DataPointer) / SizeOf(Byte))
      WriteData(FileID, *This\DataPointer, MemorySize(*This\DataPointer))
    Else
      WriteLong(FileID, 0)
    EndIf
    
  EndProcedure
  
  Procedure ReadByteVector(*This.Private_Members, FileID.i)
    
    ElementCount = ReadLong(FileID)
    
    If ElementCount >= 1
      
      If *This\DataPointer <> #Null
        FreeMemory(*This\DataPointer)
      EndIf
      
      *This\DataPointer = AllocateMemory(ElementCount * SizeOf(Byte))
      ReadData(FileID, *This\DataPointer, MemorySize(*This\DataPointer))
      *This\ElementCount = MemorySize(*This\DataPointer) / SizeOf(Byte) - 1
      
    EndIf

  EndProcedure
  
  Procedure Free(*This.Private_Members)
    
    If *This\DataPointer <> #Null
      FreeMemory(*This\DataPointer)
      *This\DataPointer = #Null
    EndIf
    
    ClearStructure(*This, Private_Members)
    FreeStructure(*This)

  EndProcedure

  Procedure.i New(P_ElementCount.l)

    *This.Private_Members = AllocateStructure(Private_Members)
    *This\VirtualTable = ?START_METHODS
        
    If P_ElementCount >= 1
      *This\DataPointer = AllocateMemory(P_ElementCount * SizeOf(Byte))
      *This\ElementCount = MemorySize(*This\DataPointer) / SizeOf(Byte) - 1
    EndIf
    
    ProcedureReturn *This
  EndProcedure

  DataSection
    START_METHODS:
    Data.i @ElementCount()
    Data.i @GetElement()
    Data.i @SetElement()
    Data.i @PushBack()
    Data.i @PopBack()
    Data.i @Clear()
    Data.i @WriteByteVector()
    Data.i @ReadByteVector()
    Data.i @Free()
    END_METHODS:
  EndDataSection

EndModule

CompilerIf #PB_Compiler_IsMainFile
  
  Debug "-------------------------------------------"
  Debug "Let's create a ByteVector of 5 elements"
  
  Vector1.ByteVector::ByteVector = ByteVector::New(5)
  
  For Index = 0 To Vector1\ElementCount()
    Vector1\SetElement(Index, Index*2)
  Next
  
  Debug "-------------------------------------------"
  Debug "Show the elements"
  
  For Index = 0 To Vector1\ElementCount()
    Debug Vector1\GetElement(Index)
  Next
  
  Debug "-------------------------------------------"
  Debug "Save the Vector in a binary file"
  
  If CreateFile(0, "ByteVector.bin")
    Vector1\WriteByteVector(0)
    CloseFile(0)
  EndIf
  
  Debug "-------------------------------------------"
  Debug "Load from a binary file"
  
  If ReadFile(0, "ByteVector.bin")
    Vector2.ByteVector::ByteVector = ByteVector::New(0)
    Vector2\ReadByteVector(0)
    CloseFile(0)
    DeleteFile("ByteVector.bin") 
  EndIf
  
  Debug "-------------------------------------------"
  Debug "Show the content from the binary file"
  
  For Index = 0 To Vector2\ElementCount()
    Debug Vector2\GetElement(Index)
  Next
  
  Debug "-------------------------------------------"
  Debug "Let's try the PushBack function"
  
  Vector3.ByteVector::ByteVector = ByteVector::New(0)
  
  Vector3\PushBack(25)
  Vector3\PushBack(35)
  Vector3\PushBack(45)
  Vector3\PushBack(55)
  Vector3\PushBack(65)
  
  Debug "-------------------------------------------"
  Debug "Show the content after 5 PushBacks"
  
  For Index = 0 To Vector3\ElementCount()
    Debug Vector3\GetElement(Index)
  Next
  
  Debug "-------------------------------------------"
  Debug "Show the content after 2 PopBacks"
  
  Vector3\PopBack()
  Vector3\PopBack()
  
  For Index = 0 To Vector3\ElementCount()
    Debug Vector3\GetElement(Index)
  Next
  
  Vector1\Free()
  Vector2\Free()
  Vector3\Free()
  
CompilerEndIf

; <<<<<<<<<<<<<<<<<<<<<<<
; <<<<< END OF FILE <<<<<
; <<<<<<<<<<<<<<<<<<<<<<<
Best regards
StarBootics
The Stone Age did not end due to a shortage of stones !
User avatar
Josh
Addict
Addict
Posts: 1183
Joined: Sat Feb 13, 2010 3:45 pm

Re: ByteVector - OOP

Post by Josh »

I'm referring to this posting by you. I think that you have made life difficult by yourself with your code above.

I once tried to get your code to run with lists. This makes the code a lot clearer, shorter and more secure against memory leaks. Only if you really have a lot of vectors (say over 100k) I would organize it with a single global list, because creating a list takes a lot of overhead.

Code: Select all

EnableExplicit

DeclareModule ByteVector

  Interface ByteVector
    Destroy()
    NboElements()
    GetElement(Index)
    SetElement(Element)
    PushBack(Element)
    PopBack()
    Clear()
    WriteByteVector(FileID)
    ReadByteVector(FileID)
  EndInterface

  Declare.i New()

EndDeclareModule

Module ByteVector

  Structure Private_Members
    VirtualTable.i
    List Elements.b()
  EndStructure

  Procedure.i New                      ()
    Protected *This.Private_Members

    *This              = AllocateStructure(Private_Members)
    *This\VirtualTable = ?START_METHODS

    ProcedureReturn *This

  EndProcedure
  Procedure   Destroy                  (*This.Private_Members)

    FreeStructure (*This)

  EndProcedure
  Procedure.i GetNboElements           (*This.Private_Members)

    ProcedureReturn ListSize (*This\Elements())

  EndProcedure
  Procedure.i GetElement               (*This.Private_Members, Index)

    If SelectElement (*This\Elements(), Index-1)
      ProcedureReturn *This\Elements()
    Else
      DebuggerError ("Byte Vector : Index out of bound !")
    EndIf

  EndProcedure
  Procedure   SetElement               (*This.Private_Members, Element)

    LastElement   (*This\Elements())
    AddElement (*This\Elements())
    *This\Elements() = Element

  EndProcedure
  Procedure   PushBack                 (*This.Private_Members, Element)

    LastElement   (*This\Elements())
    AddElement (*This\Elements())
    *This\Elements() = Element

  EndProcedure
  Procedure   PopBack                  (*This.Private_Members)

    LastElement   (*This\Elements())
    DeleteElement (*This\Elements())

  EndProcedure
  Procedure   Clear                    (*This.Private_Members)

    ClearList (*This\Elements())

  EndProcedure
  Procedure   WriteByteVector          (*This.Private_Members, FileID)

    WriteLong(FileID, ListSize (*This\Elements()))
    ForEach *This\Elements()
      WriteByte (FileID, *This\Elements())
    Next

  EndProcedure
  Procedure   ReadByteVector           (*This.Private_Members, FileID)
    Protected nboElements
    Protected i

    nboElements = ReadLong (FileID)
    For i = 1 To nboElements
      AddElement (*This\Elements())
      *This\Elements() = ReadByte (FileID)
    Next

  EndProcedure

  DataSection
    START_METHODS:
    Data.i @Destroy()
    Data.i @GetNboElements()
    Data.i @GetElement()
    Data.i @SetElement()
    Data.i @PushBack()
    Data.i @PopBack()
    Data.i @Clear()
    Data.i @WriteByteVector()
    Data.i @ReadByteVector()
    END_METHODS:
  EndDataSection

EndModule

DisableExplicit


CompilerIf #PB_Compiler_IsMainFile

  Debug "-------------------------------------------"
  Debug "Let's create a ByteVector of 5 elements"
  Vector1.ByteVector::ByteVector = ByteVector::New()
  For Index = 1 To 5
    Vector1\SetElement(Index*2-2)
  Next

  Debug "-------------------------------------------"
  Debug "Show the elements"
  For Index = 1 To Vector1\NboElements()
    Debug Vector1\GetElement(Index)
  Next

  Debug "-------------------------------------------"
  Debug "Save the Vector in a binary file"
  If CreateFile(0, "ByteVector.bin")
    Vector1\WriteByteVector(0)
    CloseFile(0)
  EndIf

  Debug "-------------------------------------------"
  Debug "Load from a binary file"
  If ReadFile(0, "ByteVector.bin")
    Vector2.ByteVector::ByteVector = ByteVector::New()
    Vector2\ReadByteVector(0)
    CloseFile(0)
    DeleteFile("ByteVector.bin")
  EndIf

  Debug "-------------------------------------------"
  Debug "Show the content from the binary file"
  For Index = 1 To Vector2\NboElements()
    Debug Vector2\GetElement(Index)
  Next

  Debug "-------------------------------------------"
  Debug "Let's try the PushBack function"
  Vector3.ByteVector::ByteVector = ByteVector::New()
  Vector3\PushBack(25)
  Vector3\PushBack(35)
  Vector3\PushBack(45)
  Vector3\PushBack(55)
  Vector3\PushBack(65)

  Debug "-------------------------------------------"
  Debug "Show the content after 5 PushBacks"
  For Index = 1 To Vector3\NboElements()
    Debug Vector3\GetElement(Index)
  Next

  Debug "-------------------------------------------"
  Debug "Show the content after 2 PopBacks"
  Vector3\PopBack()
  Vector3\PopBack()

  For Index = 1 To Vector3\NboElements()
    Debug Vector3\GetElement(Index)
  Next

  Vector1\Destroy()
  Vector2\Destroy()
  Vector3\Destroy()

CompilerEndIf
sorry for my bad english
Post Reply