Files
YASS-13-TEMP/core/commons/HashMap/_ChainedHashMap.pbi
T

132 lines
3.2 KiB
Plaintext

DeclareModule ChainedHashMap
EnableExplicit
#InitialPower = 9
#InsertIterations = 100000
Structure Bucket
*BucketData
*Next.Bucket
Hash.q
EndStructure
Structure HashMap
EntryCount.i
Capacity.i
SizePower.a
*Buckets.Bucket[0]
EndStructure
Prototype CbFree(*Data)
Declare.i Create(SizePower.b)
Declare.i GetByHash(*CHM.HashMap, Hash.q)
Declare.b OverwriteByHash(*CHM.HashMap, *Data, Hash.q, *FreeingCallback.CbFree = #Null)
Declare DeleteByHash(*CHM.HashMap, Hash.q)
Declare Free(*CHM.HashMap)
Declare NoopFree(*Data)
EndDeclareModule
Module ChainedHashMap
EnableExplicit
Procedure.l MakeBitMask(BitCount.b)
EnableASM
MOV eax, $00000001
MOV cl, BitCount
SHL eax, cl
DEC eax
ProcedureReturn
DisableASM
EndProcedure
Procedure.i Create(SizePower.b)
Protected *CHM.HashMap = AllocateMemory(SizeOf(HashMap) + (SizeOf(Integer) * (MakeBitMask(SizePower) + 1)))
If *CHM <> #Null
*CHM\EntryCount = 0
*CHM\SizePower = SizePower
Protected iBucket
For iBucket = 0 To MakeBitMask(SizePower)
*CHM\Buckets[iBucket] = #Null
Next
EndIf
ProcedureReturn *CHM
EndProcedure
Procedure.i GetByHash(*CHM.HashMap, Hash.q)
If *CHM <> #Null
Protected *CurrentBucket.Bucket = *CHM\Buckets[(Hash & MakeBitMask(*CHM\SizePower))]
While *CurrentBucket <> #Null
If *CurrentBucket\Hash = Hash
ProcedureReturn *CurrentBucket\BucketData
EndIf
*CurrentBucket = *CurrentBucket\Next
Wend
EndIf
ProcedureReturn #Null
EndProcedure
Procedure.b OverwriteByHash(*CHM.HashMap, *Data, Hash.q, *FreeingCallback.CbFree = #Null)
If *CHM <> #Null
Protected *PreviousBucket.Bucket = #Null
Protected *CurrentBucket.Bucket = *CHM\Buckets[(Hash & MakeBitMask(*CHM\SizePower))]
; We iterate over the bucket chain until we find a collision or an in-between.
While *CurrentBucket <> #Null
If *CurrentBucket\Hash >= Hash
Break
EndIf
*PreviousBucket = *CurrentBucket
*CurrentBucket = *CurrentBucket\Next
Wend
If *CurrentBucket = #Null Or *CurrentBucket\Hash <> Hash
; We either reached the end of the list, or no buckets was in the current slot.
; Or, we have an in-between, or we are at the start of the list.
Protected *NewBucket.Bucket = AllocateMemory(SizeOf(Bucket))
If *NewBucket <> #Null
*NewBucket\Next = *CurrentBucket
*NewBucket\BucketData = *Data
*NewBucket\Hash = Hash
If *PreviousBucket <> #Null
; In-between, or we are at the start of the List.
*PreviousBucket\Next = *NewBucket
Else
; Start of the list.
*CHM\Buckets[(Hash & MakeBitMask(*CHM\SizePower))] = *NewBucket
EndIf
*CHM\EntryCount = *CHM\EntryCount + 1
ProcedureReturn #True
EndIf
ElseIf *FreeingCallback <> #Null
; Handling collision.
CallFunctionFast(*FreeingCallback, *CurrentBucket\BucketData)
*CurrentBucket\BucketData = *Data
ProcedureReturn #True
EndIf
; Implied else: Handling collision while forbidden to overwrite => doing nothing.
EndIf
ProcedureReturn #False
EndProcedure
Procedure DeleteByHash(*CHM.HashMap, Hash.q)
EndProcedure
Procedure Free(*CHM.HashMap)
EndProcedure
Procedure NoopFree(*Data) : EndProcedure
EndModule