A bitset data structure library

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

A bitset data structure library

Post by StarBootics »

Hello everyone,

I have search the forum about Bitsets and there is some examples but they seems to have a fixed amount of bits for the bitset. So I have created a library that allow to have an arbitrary numbers of bits.

EDIT 1 : Little update to V1.1.0
EDIT 2 : Little update to V1.2.0

Code: Select all

; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
; Project name : A bitset data structure library
; File name : Bitset.pb
; File Version : 1.2.0
; Programmation : OK
; Programmed by : StarBootics
; Creation Date : August 10th, 2024
; Last update : August 15th, 2024
; Coded for PureBasic : V6.11 LTS
; Platform : Windows, Linux, MacOS X
; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
; Updates
;
; V1.0.0 - Initial release
; V1.1.0 - FlipBit and FlipBits methods added.
;        - If statement simplification
;        - If statement added to test for Null
;          memory pointers.
; V1.2.0 - Performance improvements
;        - Invalid memory access correction
;        - ClearBits method added
;        - Use of "End" keyword removed
;
; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
;
; This tiny library is the equivalent of the C++
; std::bitset data structure.
;
; It's a more compact way to store TRUE or FALSE
; values than using an Array of integers.
;
; One use case can be Mesh/SubMesh rendering
; flags. If the bit is set then the SubMesh is
; being rendered, not rendered otherwise. Mesh
; with optionnal SubMesh.
;
; Another use case is to determine if an Entity
; has or not a component in an ECS.
; ECS -> EntityComponentSystem
;
; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
;
; The Index param for the SetBit/ClearBit/GetBit
; methods determine the bit you want to work with.
;
; The Size / NewSize params means the number of 
; bits that you need.
;
; A Bitset can be cloned (Use the Clone method)
;
; Two Bitset can be compared (Use the Compare
; method)
;
; Note about the Compare method : The return value
; will be FALSE if the bitsets have different 
; sizes or the bits are different and will return 
; TRUE otherwise.
;
; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
; This is free and unencumbered software released into the public domain.
; 
; Anyone is free to copy, modify, publish, use, compile, sell, or
; distribute this software, either in source code form or as a compiled
; binary, for any purpose, commercial or non-commercial, and by any
; means.
; 
; In jurisdictions that recognize copyright laws, the author or authors
; of this software dedicate any and all copyright interest in the
; software to the public domain. We make this dedication for the benefit
; of the public at large and to the detriment of our heirs and
; successors. We intend this dedication to be an overt act of
; relinquishment in perpetuity of all present and future rights to this
; software under copyright law.
; 
; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
; EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
; MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
; IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
; OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
; ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
; OTHER DEALINGS IN THE SOFTWARE.
; 
; For more information, please refer to <http://unlicense.org/>
; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

DeclareModule Bitset
  
  Interface Bitset
    
    SetBit(Index.i)
    ClearBit(Index.i)
    GetBit.i(Index.i)
    FlipBit(Index.i)
    FlipBits()
    ClearBits()
    Resize.i(NewSize.i)
    Clone.i(*Source)
    Compare.i(*Other)
    Size.i()
    Free()
    
  EndInterface
  
  Declare.i New(Size.i)
  
EndDeclareModule

Module Bitset
  
  DisableDebugger
  
  #BITSET_UNICODE_BITS = 8 * SizeOf(Unicode)
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< Structure declaration <<<<<

  Structure Private_Members
    
    VirtualTable.i
    *BitArray
    Size.i
    
  EndStructure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Helper Macros <<<<<
  
  Macro ReachElement(StartPtr, Index)
    
    (StartPtr + (Index) * SizeOf(Unicode))
    
  EndMacro
  
  Macro IsBetween(Value, Lower, Upper)
    
    ((Value) >= (Lower) And (Value) < (Upper))
    
  EndMacro
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The SetBit method <<<<<
  
  Procedure SetBit(*This.Private_Members, Index.i)
    
    If IsBetween(Index, 0, *This\Size) And *This\BitArray <> #Null
      *Cursor.Unicode = ReachElement(*This\BitArray, Index / #BITSET_UNICODE_BITS)
      *Cursor\u | (1 << (Index % #BITSET_UNICODE_BITS))
    EndIf
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The ClearBit method <<<<<
  
  Procedure ClearBit(*This.Private_Members, Index.i)
    
    If IsBetween(Index, 0, *This\Size) And *This\BitArray <> #Null
      *Cursor.Unicode = ReachElement(*This\BitArray, Index / #BITSET_UNICODE_BITS)
      *Cursor\u & ~(1 << (Index % #BITSET_UNICODE_BITS))
    EndIf
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The GetBit method <<<<<
  
  Procedure.i GetBit(*This.Private_Members, Index.i)
    
    If IsBetween(Index, 0, *This\Size) And *This\BitArray <> #Null
      *Cursor.Unicode = ReachElement(*This\BitArray, Index / #BITSET_UNICODE_BITS)
      ProcedureReturn Bool((*Cursor\u & (1 << (Index % #BITSET_UNICODE_BITS))))
    EndIf
    
    ProcedureReturn 0
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The FlipBit method <<<<<
  
  Procedure FlipBit(*This.Private_Members, Index.i)
    
    If IsBetween(Index, 0, *This\Size) And *This\BitArray <> #Null
      *Cursor.Unicode = ReachElement(*This\BitArray, Index / #BITSET_UNICODE_BITS)
      *Cursor\u ! (1 << (Index % #BITSET_UNICODE_BITS))
    EndIf
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The FlipBits method <<<<<
  
  Procedure FlipBits(*This.Private_Members)
    
    If *This\BitArray <> #Null
      
      For Index = 0 To *This\Size / #BITSET_UNICODE_BITS
        *Cursor.Unicode = ReachElement(*This\BitArray, Index)
        *Cursor\u = ~ *Cursor\u
      Next
      
    EndIf
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The ClearBits method <<<<<
  
  Procedure ClearBits(*This.Private_Members)
    
    If *This\BitArray <> #Null
      FillMemory(*This\BitArray, MemorySize(*This\BitArray), 0, #PB_Unicode)
    EndIf
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Resize method <<<<<
  
  Procedure.i Resize(*This.Private_Members, NewSize.i)
    
    OldSize.i = *This\Size
    
    If NewSize < 1
      NewSize = 1
    EndIf
    
    *This\Size = NewSize
    
    *NewBitArray = ReAllocateMemory(*This\BitArray, (NewSize / #BITSET_UNICODE_BITS + 1) * SizeOf(Unicode))
    
    If *NewBitArray = #Null
      ProcedureReturn 0
    EndIf
    
    *This\BitArray = *NewBitArray
    
    ProcedureReturn 1
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Clone method <<<<<
  
  Procedure.i Clone(*This.Private_Members, *Source.Private_Members)
    
    If *This\Size <> *Source\Size
      If Resize(*This, *Source\Size) = 0
        ProcedureReturn 0
      EndIf
    EndIf
    
    If *This\BitArray <> #Null And *Source\BitArray <> #Null
      CopyMemory(*Source\BitArray, *This\BitArray, MemorySize(*Source\BitArray))
      ProcedureReturn 1
    EndIf
    
    ProcedureReturn 0
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Compare method <<<<<
  
  Procedure.i Compare(*This.Private_Members, *Other.Private_Members)
   
    If *This\Size <> *Other\Size
      ProcedureReturn #False
    EndIf
    
    If *This\BitArray <> #Null And *Other\BitArray <> #Null
      ProcedureReturn CompareMemory(*This\BitArray, *Other\BitArray, MemorySize(*This\BitArray))
    EndIf
    
    ProcedureReturn #False
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Size method <<<<<
  
  Procedure.i Size(*This.Private_Members)
    
    ProcedureReturn *This\Size
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Destructor <<<<<

  Procedure Free(*This.Private_Members)
    
    If *This\BitArray <> #Null
      FreeMemory(*This\BitArray)
    EndIf
    
    FreeStructure(*This)
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Constructor <<<<<

  Procedure.i New(Size.i)
    
    *This.Private_Members = AllocateStructure(Private_Members)
    *This\VirtualTable = ?START_METHODS
    
    If Size < 1
      Size = 1
    EndIf
    
    *This\Size = Size
    
    *This\BitArray = AllocateMemory((Size / #BITSET_UNICODE_BITS + 1) * SizeOf(Unicode))
    
    If *This\BitArray = #Null
      FreeStructure(*This)
      ProcedureReturn #Null
    EndIf
    
    ProcedureReturn *This
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Virtual Table Entries <<<<<

  DataSection
    START_METHODS:
    Data.i @SetBit()
    Data.i @ClearBit()
    Data.i @GetBit()
    Data.i @FlipBit()
    Data.i @FlipBits()
    Data.i @ClearBits()
    Data.i @Resize()
    Data.i @Clone()
    Data.i @Compare()
    Data.i @Size()
    Data.i @Free()
    END_METHODS:
  EndDataSection

  EnableDebugger
  
EndModule

CompilerIf #PB_Compiler_IsMainFile
  
  MyBitset.Bitset::Bitset = BitSet::New(64)
  MyClonedBitset.Bitset::Bitset = BitSet::New(8)
  
  MyBitset\SetBit(0)
  MyBitset\SetBit(2)
  MyBitset\SetBit(4)
  MyBitset\SetBit(5)
  MyBitset\SetBit(63)
  
  For Index = 0 To MyBitset\Size() - 1
    Debug MyBitset\GetBit(Index)
  Next
  
  Debug ""
  Debug "----------------------------"
  Debug ""
  
  MyBitset\ClearBit(4)
  
  For Index = 0 To MyBitset\Size() - 1
    Debug MyBitset\GetBit(Index)
  Next
  
  Debug ""
  Debug "----------------------------"
  Debug ""
  
  MyClonedBitset\Clone(MyBitset)
  
  For Index = 0 To MyClonedBitset\Size() - 1
    Debug MyClonedBitset\GetBit(Index)
  Next
  
  Debug ""
  Debug "----------------------------"
  Debug ""
  
  Debug MyClonedBitset\Compare(MyBitset)
  
  Debug ""
  Debug "----------------------------"
  Debug ""
  
  MyClonedBitset\FlipBits()
  
  For Index = 0 To MyClonedBitset\Size() - 1
    Debug MyClonedBitset\GetBit(Index)
  Next
  
  Debug ""
  Debug "----------------------------"
  Debug ""
  
  Debug MyClonedBitset\Compare(MyBitset)
  
  Debug ""
  Debug "----------------------------"
  Debug ""
  
  MyClonedBitset\ClearBits()
  
  For Index = 0 To MyClonedBitset\Size() - 1
    Debug MyClonedBitset\GetBit(Index)
  Next
  
  MyBitset\Free()
  MyClonedBitset\Free()
  
CompilerEndIf

; <<<<<<<<<<<<<<<<<<<<<<<
; <<<<< END OF FILE <<<<<
; <<<<<<<<<<<<<<<<<<<<<<<

Best regards
StarBootics
Last edited by StarBootics on Thu Aug 15, 2024 9:59 am, edited 9 times in total.
The Stone Age did not end due to a shortage of stones !
User avatar
jacdelad
Addict
Addict
Posts: 2001
Joined: Wed Feb 03, 2021 12:46 pm
Location: Riesa

Re: A bitset data structure library

Post by jacdelad »

Thanks StarBootics! Maybe you want to add a "FlipBit" function?
Good morning, that's a nice tnetennba!

PureBasic 6.21/Windows 11 x64/Ryzen 7900X/32GB RAM/3TB SSD
Synology DS1821+/DX517, 130.9TB+50.8TB+2TB SSD
User avatar
StarBootics
Addict
Addict
Posts: 1006
Joined: Sun Jul 07, 2013 11:35 am
Location: Canada

Re: A bitset data structure library

Post by StarBootics »

jacdelad wrote: Wed Aug 14, 2024 3:22 pm Thanks StarBootics! Maybe you want to add a "FlipBit" function?
DONE ! FlipBit and FlipBits methods added.

I have updated the code in my first post in this topic. Now another way of writing OOP library in PureBasic.

EDIT 1 : Little update to version 1.1.0

Code: Select all

; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
; Project name : A bitset data structure library
; File name : Bitset.pb
; File Version : 1.1.0
; Programmation : OK
; Programmed by : StarBootics
; Creation Date : August 14th, 2024
; Last update : August 15th, 2024
; Coded for PureBasic : V6.11 LTS
; Platform : Windows, Linux, MacOS X
; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
; Updates
;
; V1.0.0 - Initial release
; V1.1.0 - Performance improvements
;        - ClearBits method added
;        - Use of "End" keyword removed
;
; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
;
; This tiny library is the equivalent of the C++
; std::bitset data structure.
;
; It's a more compact way to store TRUE or FALSE
; values than using an Array of integers.
;
; One use case can be Mesh/SubMesh rendering
; flags. If the bit is set then the SubMesh is
; being rendered, not rendered otherwise. Mesh
; with optionnal SubMesh.
;
; Another use case is to determine if an Entity
; has or not a component in an ECS.
; ECS -> EntityComponentSystem
;
; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
;
; The Index param for the SetBit/ClearBit/GetBit
; methods determine the bit you want to work with.
;
; The Size / NewSize params means the number of 
; bits that you need.
;
; A Bitset can be cloned (Use the Clone method)
;
; Two Bitset can be compared (Use the Compare
; method)
;
; Note about the Compare method : The return value
; will be FALSE if the bitsets have different 
; sizes or the bits are different and will return 
; TRUE otherwise.
;
; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
; This is free and unencumbered software released into the public domain.
; 
; Anyone is free to copy, modify, publish, use, compile, sell, or
; distribute this software, either in source code form or as a compiled
; binary, for any purpose, commercial or non-commercial, and by any
; means.
; 
; In jurisdictions that recognize copyright laws, the author or authors
; of this software dedicate any and all copyright interest in the
; software to the public domain. We make this dedication for the benefit
; of the public at large and to the detriment of our heirs and
; successors. We intend this dedication to be an overt act of
; relinquishment in perpetuity of all present and future rights to this
; software under copyright law.
; 
; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
; EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
; MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
; IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
; OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
; ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
; OTHER DEALINGS IN THE SOFTWARE.
; 
; For more information, please refer to <http://unlicense.org/>
; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

DeclareModule Bitset
  
  Structure Bitset
    *BitArray
    Size.i
    *vt.BitsetVirtualTable
  EndStructure
  
  Prototype Proto_Bitset_SetBit(*This.Bitset, Index.i)
  Prototype Proto_Bitset_ClearBit(*This.Bitset, Index.i)
  Prototype.i Proto_Bitset_GetBit(*This.Bitset, Index.i)
  Prototype Proto_Bitset_FlipBit(*This.Bitset, Index.i)
  Prototype Proto_Bitset_FlipBits(*This.Bitset)
  Prototype Proto_Bitset_ClearBits(*This.Bitset)
  Prototype.i Proto_Bitset_Resize(*This.Bitset, NewSize.i)
  Prototype.i Proto_Bitset_Clone(*This.Bitset, *Source.Bitset)
  Prototype.i Proto_Bitset_Compare(*This.Bitset, *Other.Bitset)
  Prototype.i Proto_Bitset_Size(*This.Bitset)
  Prototype Proto_Bitset_Wipeout(*This.Bitset)
  Prototype Proto_Bitset_Destructor(*to_be_destroyed)
  
  Structure BitsetVirtualTable
    SetBit.Proto_Bitset_SetBit
    ClearBit.Proto_Bitset_ClearBit
    GetBit.Proto_Bitset_GetBit
    FlipBit.Proto_Bitset_FlipBit
    FlipBits.Proto_Bitset_FlipBits
    ClearBits.Proto_Bitset_FlipBits
    Resize.Proto_Bitset_Resize
    Clone.Proto_Bitset_Clone
    Compare.Proto_Bitset_Compare
    Size.Proto_Bitset_Size
    Wipeout.Proto_Bitset_Wipeout
    Destructor.Proto_Bitset_Destructor
  EndStructure
  
  Declare Destructor(*to_be_destroyed)
  Declare Init(*This.Bitset, Size.i)
  Declare.i New(Size.i)
  
EndDeclareModule

Module Bitset
  
  DisableDebugger
  
  #BITSET_UNICODE_BITS = 8 * SizeOf(Unicode)
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Helper Macros <<<<<
  
  Macro ReachElement(StartPtr, Index)
    
    (StartPtr + (Index) * SizeOf(Unicode))
    
  EndMacro
  
  Macro IsBetween(Value, Lower, Upper)
    
    ((Value) >= (Lower) And (Value) < (Upper))
    
  EndMacro
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The SetBit method <<<<<
  
  Procedure Bitset_SetBit(*This.Bitset, Index.i)
    
    If IsBetween(Index, 0, *This\Size) And *This\BitArray <> #Null
      *Cursor.Unicode = ReachElement(*This\BitArray, Index / #BITSET_UNICODE_BITS)
      *Cursor\u | (1 << (Index % #BITSET_UNICODE_BITS))
    EndIf
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The ClearBit method <<<<<
  
  Procedure Bitset_ClearBit(*This.Bitset, Index.i)
    
    If IsBetween(Index, 0, *This\Size) And *This\BitArray <> #Null
      *Cursor.Unicode = ReachElement(*This\BitArray, Index / #BITSET_UNICODE_BITS)
      *Cursor\u & ~(1 << (Index % #BITSET_UNICODE_BITS))
    EndIf
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The GetBit method <<<<<
  
  Procedure.i Bitset_GetBit(*This.Bitset, Index.i)
    
    If IsBetween(Index, 0, *This\Size) And *This\BitArray <> #Null
      *Cursor.Unicode = ReachElement(*This\BitArray, Index / #BITSET_UNICODE_BITS)
      ProcedureReturn Bool((*Cursor\u & (1 << (Index % #BITSET_UNICODE_BITS))))
    EndIf
    
    ProcedureReturn 0
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The FlipBit method <<<<<
  
  Procedure Bitset_FlipBit(*This.Bitset, Index.i)
    
    If IsBetween(Index, 0, *This\Size) And *This\BitArray <> #Null
      *Cursor.Unicode = ReachElement(*This\BitArray, Index / #BITSET_UNICODE_BITS)
      *Cursor\u ! (1 << (Index % #BITSET_UNICODE_BITS))
    EndIf
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The FlipBits method <<<<<
  
  Procedure Bitset_FlipBits(*This.Bitset)
    
    If *This\BitArray <> #Null
      
      For Index = 0 To *This\Size / #BITSET_UNICODE_BITS
        *Cursor.Unicode = ReachElement(*This\BitArray, Index)
        *Cursor\u = ~ *Cursor\u
      Next
      
    EndIf
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The ClearBits method <<<<<
  
  Procedure Bitset_ClearBits(*This.Bitset)
    
    If *This\BitArray <> #Null
      FillMemory(*This\BitArray, MemorySize(*This\BitArray), 0, #PB_Unicode)
    EndIf
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Resize method <<<<<
  
  Procedure.i Bitset_Resize(*This.Bitset, NewSize.i)
    
    OldSize.i = *This\Size
    
    If NewSize < 1
      NewSize = 1
    EndIf
    
    *This\Size = NewSize
    
    *NewBitArray = ReAllocateMemory(*This\BitArray, (NewSize / #BITSET_UNICODE_BITS + 1) * SizeOf(Unicode))
    
    If *NewBitArray = #Null
      ProcedureReturn 0
    EndIf
    
    *This\BitArray = *NewBitArray
    
    ProcedureReturn 1
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Clone method <<<<<
  
  Procedure.i Bitset_Clone(*This.Bitset, *Source.Bitset)
    
    If *This\Size <> *Source\Size
      If Bitset_Resize(*This, *Source\Size) = 0
        ProcedureReturn 0
      EndIf
    EndIf
    
    If *This\BitArray <> #Null And *Source\BitArray <> #Null
      CopyMemory(*Source\BitArray, *This\BitArray, MemorySize(*Source\BitArray))
      ProcedureReturn 1
    EndIf
    
    ProcedureReturn 0
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Compare method <<<<<
  
  Procedure.i Bitset_Compare(*This.Bitset, *Other.Bitset)
    
    If *This\Size <> *Other\Size
      ProcedureReturn #False
    EndIf
    
    If *This\BitArray <> #Null And *Other\BitArray <> #Null
      ProcedureReturn CompareMemory(*This\BitArray, *Other\BitArray, MemorySize(*This\BitArray))
    EndIf
    
    ProcedureReturn #False
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Size method <<<<<
  
  Procedure.i Bitset_Size(*This.Bitset)
    
    ProcedureReturn *This\Size
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Wipeout method <<<<<
  
  Procedure Bitset_Wipeout(*This.Bitset)
    
    If *This\BitArray <> #Null
      FreeMemory(*This\BitArray)
    EndIf
    
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Destructor <<<<<
  
  Procedure Destructor(*to_be_destroyed)
    
    *This.Bitset = *to_be_destroyed
    Bitset_Wipeout(*This)
    FreeStructure(*to_be_destroyed)
    
  EndProcedure
  
  Global BitsetVirtualTable.BitsetVirtualTable
  
  BitsetVirtualTable\SetBit = @Bitset_SetBit()
  BitsetVirtualTable\ClearBit = @Bitset_ClearBit()
  BitsetVirtualTable\GetBit = @Bitset_GetBit()
  BitsetVirtualTable\FlipBit = @Bitset_FlipBit()
  BitsetVirtualTable\FlipBits = @Bitset_FlipBits()
  BitsetVirtualTable\ClearBits = @Bitset_ClearBits()
  BitsetVirtualTable\Resize = @Bitset_Resize()
  BitsetVirtualTable\Clone = @Bitset_Clone()
  BitsetVirtualTable\Compare = @Bitset_Compare()
  BitsetVirtualTable\Size = @Bitset_Size()
  BitsetVirtualTable\Wipeout = @Bitset_Wipeout()
  BitsetVirtualTable\Destructor = @Destructor()
  
  ; <<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Init <<<<<
  
  Procedure.i Init(*This.Bitset, Size.i)
    
    *This\vt = @BitsetVirtualTable
    
    If Size < 1
      Size = 1
    EndIf
    
    *This\Size = Size
    
    *This\BitArray = AllocateMemory((Size / #BITSET_UNICODE_BITS + 1) * SizeOf(Unicode))
    
    If *This\BitArray = #Null
      ProcedureReturn 0
    EndIf
    
    ProcedureReturn 1
  EndProcedure
  
  ; <<<<<<<<<<<<<<<<<<<<<<<<<<<
  ; <<<<< The Constructor <<<<<
  
  Procedure.i New(Size.i)
    
    *This.Bitset = AllocateStructure(Bitset)
    
    If *This = #Null
      ProcedureReturn #Null
    EndIf
    
    If Init(*This, Size)
      ProcedureReturn *This
    Else
      FreeStructure(*This)
    EndIf
    
    ProcedureReturn #Null
  EndProcedure
  
  EnableDebugger
  
EndModule

CompilerIf #PB_Compiler_IsMainFile
  
  BitSet::Init(MyBitset.Bitset::Bitset, 16)
  BitSet::Init(MyClonedBitset.Bitset::Bitset, 8)
  
  MyBitset\vt\SetBit(MyBitset, 0)
  MyBitset\vt\SetBit(MyBitset, 2)
  MyBitset\vt\SetBit(MyBitset, 4)
  MyBitset\vt\SetBit(MyBitset, 5)
  
  For Index = 0 To MyBitset\vt\Size(MyBitset) - 1
    Debug MyBitset\vt\GetBit(MyBitset, Index)
  Next
  
  Debug ""
  Debug "----------------------------"
  Debug ""
  
  MyBitset\vt\ClearBit(MyBitset, 4)
  
  For Index = 0 To MyBitset\vt\Size(MyBitset) - 1
    Debug MyBitset\vt\GetBit(MyBitset, Index)
  Next
  
  Debug ""
  Debug "----------------------------"
  Debug ""
  
  MyClonedBitset\vt\Clone(MyClonedBitset, MyBitset)
  
  For Index = 0 To MyClonedBitset\vt\Size(MyClonedBitset) - 1
    Debug MyClonedBitset\vt\GetBit(MyClonedBitset, Index)
  Next
  
  Debug ""
  Debug "----------------------------"
  Debug ""
  
  Debug MyClonedBitset\vt\Compare(MyClonedBitset, MyBitset)
  
  Debug ""
  Debug "----------------------------"
  Debug ""
  
  MyClonedBitset\vt\FlipBits(MyClonedBitset)
  
  For Index = 0 To MyClonedBitset\vt\Size(MyClonedBitset) - 1
    Debug MyClonedBitset\vt\GetBit(MyClonedBitset, Index)
  Next
  
  Debug ""
  Debug "----------------------------"
  Debug ""
  
  Debug MyClonedBitset\vt\Compare(MyClonedBitset, MyBitset)
  
  MyBitset\vt\Wipeout(MyBitset)
  MyClonedBitset\vt\Wipeout(MyClonedBitset)
  
CompilerEndIf

; <<<<<<<<<<<<<<<<<<<<<<<
; <<<<< END OF FILE <<<<<
; <<<<<<<<<<<<<<<<<<<<<<<
Best regards
StarBootics
Last edited by StarBootics on Thu Aug 15, 2024 10:08 am, edited 4 times in total.
The Stone Age did not end due to a shortage of stones !
User avatar
STARGÅTE
Addict
Addict
Posts: 2228
Joined: Thu Jan 10, 2008 1:30 pm
Location: Germany, Glienicke
Contact:

Re: A bitset data structure library

Post by STARGÅTE »

Dear StarBootics,

your code doesn't work here (PB 6.11 x64, Windows 10).
I receive an IMA in the example code at "MyBitset\ClearBit(4)", also the loop before is not executed because MyBitset\Size() is 0.

Otherwise I have a few suggestions for improvement:
  • In FlipBit() you don't need two cases for bit flipping, just use the XOR-operator: 1 ! 1 = 0 , 0 ! 1 = 1

    Code: Select all

    *Cursor\u ! (1 << (Index % #BITSET_UNICODE_BITS))
  • In FlipBits() you iterate through all single bits an flip them. Also here, it is must easier (and faster) to use the NOT-operator and flip the whole unicode.

    Code: Select all

    *Cursor\u = ~ *Cursor\u
  • Using the keyword End in a procedure is a bad idea! Better you return 0 to indicate that a procedure didn't work properly.
  • In Clone() you iterate through all unicodes. Instead, you can use CopyMemory for the whole BitArray.
  • Similar in Compare() you can use CompareMemory() for both BitArrays
PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Lizard - Script language for symbolic calculations and moreTypeface - Sprite-based font include/module
User avatar
StarBootics
Addict
Addict
Posts: 1006
Joined: Sun Jul 07, 2013 11:35 am
Location: Canada

Re: A bitset data structure library

Post by StarBootics »

Hello everyone,

Error reported and Suggestions by STARGÅTE are either corrected or implemented.

Best regards
StarBootics
The Stone Age did not end due to a shortage of stones !
User avatar
jacdelad
Addict
Addict
Posts: 2001
Joined: Wed Feb 03, 2021 12:46 pm
Location: Riesa

Re: A bitset data structure library

Post by jacdelad »

Cool, thanks!
Good morning, that's a nice tnetennba!

PureBasic 6.21/Windows 11 x64/Ryzen 7900X/32GB RAM/3TB SSD
Synology DS1821+/DX517, 130.9TB+50.8TB+2TB SSD
Post Reply