A bitset data structure library
Posted: Sun Aug 11, 2024 4:18 am
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
Best regards
StarBootics
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