122 lines
3.0 KiB
Plaintext
122 lines
3.0 KiB
Plaintext
|
|
EnableExplicit
|
|
|
|
#HashMap_InitialPower = 9
|
|
#HashMap_InsertIterations = 100000
|
|
|
|
;{
|
|
|
|
Structure ChainedHashMapBucket
|
|
*BucketData
|
|
*Next.ChainedHashMapBucket
|
|
Hash.q
|
|
EndStructure
|
|
|
|
Structure ChainedHashMap
|
|
EntryCount.i
|
|
Capacity.i
|
|
SizePower.a
|
|
*Buckets.ChainedHashMapBucket[0]
|
|
EndStructure
|
|
|
|
|
|
Prototype CbFree(*Data)
|
|
|
|
Procedure.l MakeBitMask(BitCount.b)
|
|
EnableASM
|
|
MOV eax, $00000001
|
|
MOV cl, BitCount
|
|
SHL eax, cl
|
|
DEC eax
|
|
ProcedureReturn
|
|
DisableASM
|
|
EndProcedure
|
|
|
|
Procedure.i CHM_Create(SizePower.b)
|
|
Protected *CHM.ChainedHashMap = AllocateMemory(SizeOf(ChainedHashMap) + (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 CHM_GetByHash(*CHM.ChainedHashMap, Hash.q)
|
|
If *CHM <> #Null
|
|
Protected *CurrentBucket.ChainedHashMapBucket = *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 CHM_OverwriteByHash(*CHM.ChainedHashMap, *Data, Hash.q, *FreeingCallback.CbFree = #Null)
|
|
If *CHM <> #Null
|
|
Protected *PreviousBucket.ChainedHashMapBucket = #Null
|
|
Protected *CurrentBucket.ChainedHashMapBucket = *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.ChainedHashMapBucket = AllocateMemory(SizeOf(ChainedHashMapBucket))
|
|
|
|
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 CHM_DeleteByHash(*CHM.ChainedHashMap, Hash.q)
|
|
|
|
EndProcedure
|
|
|
|
Procedure CHM_Free(*CHM.ChainedHashMap)
|
|
|
|
EndProcedure
|
|
|
|
Procedure NoopFree(*Data) : EndProcedure
|