Code: Select all
IntMap(500) = 32
IntMapString(24632) = "my string"
Code: Select all
IntMap(500) = 32
IntMapString(24632) = "my string"
Code: Select all
trie.BitModule::IBitTrie
trie = BitModule::New_BitTrie(size) ; give it a size to pre allocate x number of nodes, defaults at 64 nodes
trie\Set(key,value)
trie\Get(key)
trie\Free()
Thanks--that does fill the bill syntax-wise, but it is a little heavier than I was hoping for...and I will need a 64-bit version, so the smaller one is not so helpful.idle wrote:you can use a BitTrie to do it
There's a generic one in my bitmodule with comparable performance to a pb map
http://www.purebasic.fr/english/viewtop ... 40&t=57409
to use itor there's a more optimized one for x86 onlyCode: Select all
trie.BitModule::IBitTrie trie = BitModule::New_BitTrie(size) ; give it a size to pre allocate x number of nodes, defaults at 64 nodes trie\Set(key,value) trie\Get(key) trie\Free()
http://www.purebasic.fr/english/viewtop ... 12&t=47436
Code: Select all
EnableExplicit
DeclareModule TrieModule
; Mar 13, 2014: From BitModule, but reduced to minimal Trie features
;TrieModule
;Author Idle 17/11/13
;PB 5.20
;v1.3.4
;Description
;
;BitTrie ;builds a bit Trie key size determines the maximum number of items to add, eg 8=256 entries 16= 65596 entries ...
;stores an integer value with the key
Prototype BitTrieCB(value.i)
Interface IBitTrie ;bit Trie
Set(key,value)
Get(key)
ByteCount()
Free()
EndInterface
Declare New_BitTrie(size=64) ;expected number of items
EndDeclareModule
; ------
; ------
Module TrieModule
Structure BitBufInfo
Size.q
Bytesused.q
Position.q
Misc.l
EndStructure
Structure BitBuffer
*vt
inf.bitbufinfo
*buf
EndStructure
Structure node
inext.i[2]
value.i
EndStructure
Structure BitTrie Extends bitBuffer
avail.i
EndStructure
Procedure New_BitTrie(size=64)
Protected *this.BitTrie
*this = AllocateMemory(SizeOf(bittrie))
*this\vt = ?vt_BitTrie
*this\inf\size = Size*SizeOf(node)
*this\inf\Bytesused = *this\inf\size
*this\inf\Position=SizeOf(node)
;*this\inf\misc = Round(Log(size) / Log(2),#PB_Round_Up) -1 ;not needed v1.3.3
*this\buf = AllocateMemory(*this\inf\Size)
*this\avail = *this\inf\size-SizeOf(node)
ProcedureReturn *this
EndProcedure
; ------
Procedure BitTrie_Add(*this.bittrie,key.i,val.i)
Protected *node.node,idx,a,lp
CompilerIf SizeOf(Integer) = 8
!bsr qword rax , qword [p.v_key]
!mov [p.v_lp] , rax
CompilerElse
!bsr dword eax , dword [p.v_key]
!mov [p.v_lp] , eax
CompilerEndIf
*node = *this\buf
For a = lp To 0 Step -1
idx = (key >> a) & 1
If *node\inext[idx]
tpos = *node\inext[idx]
*node = *this\buf + *node\inext[idx]
ElseIf *this\avail > 0
*node\inext[idx] = *this\inf\Position
tpos =*this\inf\Position
*node = *this\buf +*this\inf\Position
*this\avail - SizeOf(node)
*this\inf\Position+SizeOf(node)
*this\inf\Bytesused = *this\inf\Position
Else
*this\avail = 64*SizeOf(node)
*this\inf\size + *this\avail
*this\buf = ReAllocateMemory(*this\buf,*this\inf\size)
*node = *this\buf+ tpos
*node\inext[idx] = *this\inf\Position
*node = *this\buf +*this\inf\Position
*this\avail - SizeOf(node)
*this\inf\Position+SizeOf(node)
*this\inf\Bytesused = *this\inf\Position
EndIf
Next
*node\value = val
EndProcedure
; ------
Procedure BitTrie_Get(*this.bittrie,key.i)
Protected *node.node,value,a,idx,lp
CompilerIf SizeOf(Integer) = 8
!bsr qword rax , qword [p.v_key]
!mov [p.v_lp] , rax
CompilerElse
!bsr dword eax , dword [p.v_key]
!mov [p.v_lp] , eax
CompilerEndIf
*node = *this\buf
For a = lp To 0 Step -1
idx = (key>>a) & 1
If *node
If *node\inext[idx]
*node = *this\buf + *node\inext[idx]
Else
Break
EndIf
Else
ProcedureReturn 0
EndIf
Next
ProcedureReturn *node\value
EndProcedure
; ------
Procedure BitBuffer_GetByteCount(*this.bitbuffer)
If *this
ProcedureReturn *this\inf\BytesUsed
EndIf
EndProcedure
; ------
Procedure BitBuffer_Free(*this.bitbuffer)
If *this
FreeMemory(*this\buf)
FreeMemory(*this)
EndIf
EndProcedure
; ------
DataSection
vt_BitTrie: ; Interface IBitTrie:
Data.i @BitTrie_Add() ; Set(key,value)
Data.i @BitTrie_Get() ; Get(key)
Data.i @BitBuffer_GetByteCount() ; ByteCount()
Data.i @BitBuffer_Free() ; Free()
EndDataSection
EndModule
;----------------------------------------------------------------------
;-DEMO CODE ---------------------------------------------------------------------
; ---------------------------------------------------------------------
; ---------------------------------------------------------------------
; ---------------------------------------------------------------------
; ---------------------------------------------------------------------
CompilerIf 0
Global.i key, value
Global trie.TrieModule::IBitTrie
Global x.i
For x = 0 To 256
trie = TrieModule::New_BitTrie() ; give it a size to pre allocate x number of nodes, defaults at 64 nodes
For value = 0 To 255 Step 8
key = 8 * value
trie\Set(key,value)
Debug "key="+key+", val=" + trie\Get(key)
Next
Debug "..."
For key = 0 To 2048
If trie\Get(key)
Debug Str(key) + "=" + trie\Get(key)
EndIf
Next
trie\Free()
Next x
CompilerEndIf
CompilerIf 1
;-Timed Test code_____________________________________________________________________
DisableExplicit
Global trie.TrieModule::IBitTrie ;mt.clsTrie = NewTrie(@mt)
;DisableDebugger
Structure pair
a.i
b.i
EndStructure
NewMap a.i()
trie = TrieModule::New_BitTrie()
MessageRequester("INFO", "Filling List and Maps.")
start = ElapsedMilliseconds()
b=46589
For a=1 To 10000
b+1
a(Str(a)) = b
a(Str(b)) = a
Next
stop = ElapsedMilliseconds()
result_trie = stop-start
start = ElapsedMilliseconds()
For a = 1 To 10000
trie\Set(a,b) ; mt\Add(a,b)
trie\Set(b,a) ; mt\Add(b,a)
Next
stop = ElapsedMilliseconds()
result_map = stop-start
MessageRequester("Filling:", "Map: "+Str(result_map)+#CRLF$+"Trie: "+Str(result_Trie))
start = ElapsedMilliseconds()
For b = 1 To 10
For n = 10 To 10000
temp = trie\Get(n) ;mt\LookUp(n)
Next
For n = 46599 To 97799
temp = trie\Get(n) ;mt\LookUp(n)
Next
Next
stop = ElapsedMilliseconds()
result_trie = stop-start
start = ElapsedMilliseconds()
For b = 1 To 10
For n = 10 To 10000
temp = a(Str(n))
Next
For n = 46599 To 97799
temp = a(Str(n))
Next
Next
stop = ElapsedMilliseconds()
result_map = stop-start
MessageRequester("", "Map: "+Str(result_map)+#CRLF$+"Trie: "+Str(result_Trie))
; mt\Free()
trie\Free()
; typical output (with Debugger OFF):
; Map: 563
; Trie: 98
CompilerEndIf
Yes you just need to set the value of the trie with a pointer to some structureIs there an easy way to adapt it to strings and random-sized structures? I have not used PB pointers very much. (I have used them more for data sections and procedures than strings or structures...)
Code: Select all
Structure UserData ;some structure you want to use to store with the trie
i.i
s.s
EndStructure
Global *puserdat.userdata
*puserdat = AllocateMemory(SizeOf(userdata)) ;make a new userdata item
*puserdat\i = a
*puserdat\s = Str(a)
Trie\Set(a,*puserdat) ;set the trie value with the pointer to the data
*puserdat = trie\get(a) ;get a userdata item
If *puserdat
Debug *puserdat\s
EndIf
Code: Select all
EnableExplicit
DeclareModule TrieModule
; Mar 13, 2014: From BitModule, but reduced to minimal Trie features
;TrieModule
;Author Idle 17/11/13
;PB 5.20
;v1.3.4
;Description
;
;BitTrie ;builds a bit Trie key size determines the maximum number of items to add, eg 8=256 entries 16= 65596 entries ...
;stores an integer value with the key
Prototype BitTrieCB(value.i)
Interface IBitTrie ;bit Trie
Set(key,value)
Get(key)
Walk(*cb.bitTrieCB)
ByteCount()
Free()
EndInterface
Declare New_BitTrie(size=64) ;expected number of items
EndDeclareModule
; ------
; ------
Module TrieModule
Structure BitBufInfo
Size.q
Bytesused.q
Position.q
Misc.l
EndStructure
Structure BitBuffer
*vt
inf.bitbufinfo
*buf
EndStructure
Structure node
inext.i[2]
value.i
EndStructure
Structure BitTrie Extends bitBuffer
avail.i
EndStructure
Procedure New_BitTrie(size=64)
Protected *this.BitTrie
*this = AllocateMemory(SizeOf(bittrie))
*this\vt = ?vt_BitTrie
*this\inf\size = Size*SizeOf(node)
*this\inf\Bytesused = *this\inf\size
*this\inf\Position=SizeOf(node)
;*this\inf\misc = Round(Log(size) / Log(2),#PB_Round_Up) -1 ;not needed v1.3.3
*this\buf = AllocateMemory(*this\inf\Size)
*this\avail = *this\inf\size-SizeOf(node)
ProcedureReturn *this
EndProcedure
; ------
Procedure BitTrie_Add(*this.bittrie,key.i,val.i)
Protected *node.node,idx,a,lp
CompilerIf SizeOf(Integer) = 8
!bsr qword rax , qword [p.v_key]
!mov [p.v_lp] , rax
CompilerElse
!bsr dword eax , dword [p.v_key]
!mov [p.v_lp] , eax
CompilerEndIf
*node = *this\buf
For a = lp To 0 Step -1
idx = (key >> a) & 1
EnableExplicit
DeclareModule TrieModule
; Mar 13, 2014: From BitModule, but reduced to minimal Trie features
;TrieModule
;Author Idle 17/11/13
;PB 5.20
;v1.3.4
;Description
;
;BitTrie ;builds a bit Trie key size determines the maximum number of items to add, eg 8=256 entries 16= 65596 entries ...
;stores an integer value with the key
Prototype BitTrieCB(value.i)
Interface IBitTrie ;bit Trie
Set(key,value)
Get(key)
Walk(*cb.bitTrieCB)
ByteCount()
Free()
EndInterface
Declare New_BitTrie(size=64) ;expected number of items
EndDeclareModule
; ------
; ------
Module TrieModule
Structure BitBufInfo
Size.q
Bytesused.q
Position.q
Misc.l
EndStructure
Structure BitBuffer
*vt
inf.bitbufinfo
*buf
EndStructure
Structure node
inext.i[2]
value.i
EndStructure
Structure BitTrie Extends bitBuffer
avail.i
EndStructure
Procedure New_BitTrie(size=64)
Protected *this.BitTrie
*this = AllocateMemory(SizeOf(bittrie))
*this\vt = ?vt_BitTrie
*this\inf\size = Size*SizeOf(node)
*this\inf\Bytesused = *this\inf\size
*this\inf\Position=SizeOf(node)
;*this\inf\misc = Round(Log(size) / Log(2),#PB_Round_Up) -1 ;not needed v1.3.3
*this\buf = AllocateMemory(*this\inf\Size)
*this\avail = *this\inf\size-SizeOf(node)
ProcedureReturn *this
EndProcedure
; ------
Procedure BitTrie_Add(*this.bittrie,key.i,val.i)
Protected *node.node,idx,a,lp
CompilerIf SizeOf(Integer) = 8
!bsr qword rax , qword [p.v_key]
!mov [p.v_lp] , rax
CompilerElse
!bsr dword eax , dword [p.v_key]
!mov [p.v_lp] , eax
CompilerEndIf
*node = *this\buf
For a = lp To 0 Step -1
idx = (key >> a) & 1
If *node\inext[idx]
tpos = *node\inext[idx]
*node = *this\buf + *node\inext[idx]
ElseIf *this\avail > 0
*node\inext[idx] = *this\inf\Position
tpos =*this\inf\Position
*node = *this\buf +*this\inf\Position
*this\avail - SizeOf(node)
*this\inf\Position+SizeOf(node)
*this\inf\Bytesused = *this\inf\Position
Else
*this\avail = 64*SizeOf(node)
*this\inf\size + *this\avail
*this\buf = ReAllocateMemory(*this\buf,*this\inf\size)
*node = *this\buf+ tpos
*node\inext[idx] = *this\inf\Position
*node = *this\buf +*this\inf\Position
*this\avail - SizeOf(node)
*this\inf\Position+SizeOf(node)
*this\inf\Bytesused = *this\inf\Position
EndIf
Next
*node\value = val
EndProcedure
; ------
Procedure BitTrie_Get(*this.bittrie,key.i)
Protected *node.node,value,a,idx,lp
CompilerIf SizeOf(Integer) = 8
!bsr qword rax , qword [p.v_key]
!mov [p.v_lp] , rax
CompilerElse
!bsr dword eax , dword [p.v_key]
!mov [p.v_lp] , eax
CompilerEndIf
*node = *this\buf
For a = lp To 0 Step -1
idx = (key>>a) & 1
If *node
If *node\inext[idx]
*node = *this\buf + *node\inext[idx]
Else
Break
EndIf
Else
ProcedureReturn 0
EndIf
Next
ProcedureReturn *node\value
EndProcedure
; ------
Procedure BitTrie_Walk(*this.bitTrie,*cb.bitTrieCB)
Protected *node.node,*stack.Integer, spos,pos
*stack = AllocateMemory(*this\inf\size)
pos = SizeOf(node)
*node = *this\buf +pos
If *cb
spos = 0
While pos < *this\inf\Bytesused
*node = *this\buf +pos
If *node\value
*cb(*node\value)
EndIf
pos + SizeOf(node)
Wend
EndIf
EndProcedure
Procedure BitBuffer_GetByteCount(*this.bitbuffer)
If *this
ProcedureReturn *this\inf\BytesUsed
EndIf
EndProcedure
; ------
Procedure BitBuffer_Free(*this.bitbuffer)
If *this
FreeMemory(*this\buf)
FreeMemory(*this)
EndIf
EndProcedure
; ------
DataSection
vt_BitTrie: ; Interface IBitTrie:
Data.i @BitTrie_Add() ; Set(key,value)
Data.i @BitTrie_Get() ; Get(key)
Data.i @BitTrie_Walk()
Data.i @BitBuffer_GetByteCount() ; ByteCount()
Data.i @BitBuffer_Free() ; Free()
EndDataSection
EndModule
Structure UserData ;some structure you want to use to store with the trie
i.i
s.s
EndStructure
Procedure cbwalk(*puserdat.userdata) ;use the walk callback to free the userdata
Debug *puserdat\s
FreeMemory(*puserdat)
EndProcedure
Global trie.TrieModule::IBitTrie
Global *puserdat.userdata
Global a
trie = TrieModule::New_BitTrie(2048) ;create the trie with the amount of nodes you want
For a = 1 To 2048
*puserdat = AllocateMemory(SizeOf(userdata)) ;make a new userdata item
*puserdat\i = a ;set it
*puserdat\s = Str(a)
Trie\Set(a,*puserdat) ;add the userdata to the trie
Next
For a = 1 To 2048 Step 8
*puserdat = trie\get(a) ;get a userdata item
If *puserdat
Debug *puserdat\s
EndIf
Next
Debug "=================================="
trie\Walk(@cbwalk()) ;walk the trie to free the userdata
trie\Free() ;free the trie
If *node\inext[idx]
tpos = *node\inext[idx]
*node = *this\buf + *node\inext[idx]
ElseIf *this\avail > 0
*node\inext[idx] = *this\inf\Position
tpos =*this\inf\Position
*node = *this\buf +*this\inf\Position
*this\avail - SizeOf(node)
*this\inf\Position+SizeOf(node)
*this\inf\Bytesused = *this\inf\Position
Else
*this\avail = 64*SizeOf(node)
*this\inf\size + *this\avail
*this\buf = ReAllocateMemory(*this\buf,*this\inf\size)
*node = *this\buf+ tpos
*node\inext[idx] = *this\inf\Position
*node = *this\buf +*this\inf\Position
*this\avail - SizeOf(node)
*this\inf\Position+SizeOf(node)
*this\inf\Bytesused = *this\inf\Position
EndIf
Next
*node\value = val
EndProcedure
; ------
Procedure BitTrie_Get(*this.bittrie,key.i)
Protected *node.node,value,a,idx,lp
CompilerIf SizeOf(Integer) = 8
!bsr qword rax , qword [p.v_key]
!mov [p.v_lp] , rax
CompilerElse
!bsr dword eax , dword [p.v_key]
!mov [p.v_lp] , eax
CompilerEndIf
*node = *this\buf
For a = lp To 0 Step -1
idx = (key>>a) & 1
If *node
If *node\inext[idx]
*node = *this\buf + *node\inext[idx]
Else
Break
EndIf
Else
ProcedureReturn 0
EndIf
Next
ProcedureReturn *node\value
EndProcedure
; ------
Procedure BitTrie_Walk(*this.bitTrie,*cb.bitTrieCB)
Protected *node.node,*stack.Integer, spos,pos
*stack = AllocateMemory(*this\inf\size)
pos = SizeOf(node)
*node = *this\buf +pos
If *cb
spos = 0
While pos < *this\inf\Bytesused
*node = *this\buf +pos
If *node\value
*cb(*node\value)
EndIf
pos + SizeOf(node)
Wend
EndIf
EndProcedure
Procedure BitBuffer_GetByteCount(*this.bitbuffer)
If *this
ProcedureReturn *this\inf\BytesUsed
EndIf
EndProcedure
; ------
Procedure BitBuffer_Free(*this.bitbuffer)
If *this
FreeMemory(*this\buf)
FreeMemory(*this)
EndIf
EndProcedure
; ------
DataSection
vt_BitTrie: ; Interface IBitTrie:
Data.i @BitTrie_Add() ; Set(key,value)
Data.i @BitTrie_Get() ; Get(key)
Data.i @BitTrie_Walk()
Data.i @BitBuffer_GetByteCount() ; ByteCount()
Data.i @BitBuffer_Free() ; Free()
EndDataSection
EndModule
Structure UserData ;some structure you want to use to store with the trie
i.i
s.s
EndStructure
Procedure cbwalk(*puserdat.userdata) ;use the walk callback to free the userdata
Debug *puserdat\s
FreeMemory(*puserdat)
EndProcedure
Global trie.TrieModule::IBitTrie
Global *puserdat.userdata
Global a
trie = TrieModule::New_BitTrie(2048) ;create the trie with the amount of nodes you want
For a = 1 To 2048
*puserdat = AllocateMemory(SizeOf(userdata)) ;make a new userdata item
*puserdat\i = a ;set it
*puserdat\s = Str(a)
Trie\Set(a,*puserdat) ;add the userdata to the trie
Next
For a = 1 To 2048 Step 8
*puserdat = trie\get(a) ;get a userdata item
If *puserdat
Debug *puserdat\s
EndIf
Next
Debug "=================================="
trie\Walk(@cbwalk()) ;walk the trie to free the userdata
trie\Free() ;free the trie