you just asked to do this with a range of 100 bits. This is what does 100 bits with popcount!
it processes the strings directly into bit arrays, ands them together, then pop counts the result, it takes 56 ms for 200,000 loops including the string conversion not just the popcount time. Overall it's quicker.
Code: Select all
EnableExplicit
DeclareModule BitModule
;BitModule
;Author Idle 17/11/13
;PB 5.42+
;Description
;BitVector ; Sets n number of bits with a given value into a memory stream which automatically grows:
; useful if working with arbitary bitsizes to produce an indexable array or output stream
;BitArray ; set, get or toggle a bit at an index in the array
;useful for membership tests 1 bit per index
;Bloom Filter ;probablistic structure to determine if an item exists in a set.
;useful for membership tests of unbounded data sets
;note can give false positives if a key doesn't exist in the set
;BitTrie ;store and retrieve integer key pair values
;useful as a replacement to a map
;Features
;All data structures can be saved to disk and loaded from file or memory
;bitarray bitvector and bloomfilter include logical operations not, or, xor, and
;v1.3.8
; shiftleft shiftright for bitarray bitvector
;v1.3.7
; fixed bitarray bit order
;v1.3.6
; added get bit count; fixed bug in bittrie reallocation;
;v1.3.5
;NOT, OR, XOR, AND for bitarray bitvector bloomfilter classes
;v1.3.4
;tuned up bloom added more hash functions
;v1.3.3
;improved trie time
;v1.3.2
;Added catch
;v1.3.1
;fixed trie walk
;v1.3
;Added Save and load
;modified Trie to work from file
;V1.2
;Added BitTrie
;v1.1
;changed bitvector get to getbuffer
;added bitvector get(index,bitcount)
Enumeration 1
#OP_OR
#OP_AND
#OP_XOR
EndEnumeration
Interface IBitVector
Set(val,bitcount) ;adds a value to the bitvector stream eg: val=%0101010, bitcount=7
Get(index,bitcount) ;Get bits from the index by number of bits eg index =7, bitcount =3
GetBuffer() ; Returns pointer to the buffer
SetBuffer(*mem,len) ;Set the buffer to use
BinOP(bitvector,OP) ;Perform a binary operation on another bit vector OR XOR AND bitModule::#OP_OR
Not() ;nots the buffer
ShiftLeft() ;shift left number of bits
ShiftRight() ;shift right number of bits
Save(file.s,CompressLevel=9) ;save a compressed bit buffer to file
Load(file.s) ;load a compressed bit buffer from file
Catch(*mem,len) ;catch a saved bit buffer from a datasection
BitSize() ;size of stream in bits
ByteSize() ;size in stream in bytes
BitCount() ;popcount number of bits set
Clear()
Free()
EndInterface
Interface IBitArray
Set(index) ;Set bit at position to 1
ReSet(index) ;Reset bit at position to 0
Toggle(index) ;Toggle value of bit at position
Get(index) ;Check if the bit is set returns > 0 if true
GetBuffer() ; Returns pointer to the buffer
BinOP(bitarray,OP) ;Perform a binary operation on another bit array OR XOR AND bitModule::#OP_OR
BiNOPNew(bitarray,OP) ;Perform a binary operation on another bit array and returns a new bitarray
Not() ;Nots the buffer
ShiftLeft() ;shift left number of bits
ShiftRight() ;shift right number of bits
Save(file.s,CompressLevel=9) ;save compressed bitarray to file
Load(file.s) ;load compressed bitarray from file
Catch(*mem,len) ;catch compressed bitarray from datasection
BitSize() ;size of array in bits
ByteSize() ;size in array in bytes
BitCount()
Clear()
Free()
EndInterface
Interface IBloomFilter
Set(*key,len) ;Set the key ;*key, pointer to the memory string or integer,
Get(*key,len) ;look up a key in the filter
GetBuffer() ; Returns pointer to the buffer
BinOP(bloomfilter,OP) ;Perform a binary operation on another bloom filter OR XOR AND bitModule::#OP_OR
Not() ;Nots the buffer
Save(file.s,CompressLevel=9) ;save compresed bloom to file
Load(file.s) ;load compressed bloom from file
Catch(*mem,len) ;catch compressed bloom from datasection
BitSize()
ByteSize()
BitCount()
Clear()
Free()
EndInterface
Prototype BitTrieCB(value.i,*userdata=0,*userdata1=0)
Interface IBitTrie ;bit Trie
Set(key.i,value=1) ;store a value with the key
Get(key.i) ;get the value with the key
GetBuffer() ;get the pointer to the buffer
Walk(*cb.bitTrieCB,*usrdata=0,*usrdata1=0) ;dumps the trie unordered
Save(file.s,CompressLevel=9) ;save the trie to file
Load(file.s) ;load the trie from file
Catch(*mem,len) ;catch the trie from a data section
ByteCount() ;size of trie
NumItems()
Clear()
Free()
EndInterface
Declare.q Hash_Rs(*mem,len.i)
Declare.q Hash_Sax(*mem,len.i)
Declare.q Hash_Sdbm(*mem,len.i)
Declare.q Hash_Js(*mem,len.i)
Declare.q Hash_Fnv32_1(*mem,len.i)
Declare.q Hash_Fnv32_1a(*mem,len.i)
Declare.q Hash_Adler32(*mem,len.i)
Declare New_BitVector(size=64,*data=0)
Declare New_BitArray(size=64,*data=0)
Declare New_BitTrie(size=64)
Declare New_BloomFilter(Items,NumberOfKeys=4,MaxErrorRate.f=0.999)
EndDeclareModule
Module BitModule
CompilerIf #PB_Compiler_OS = #PB_OS_Windows
ImportC "zlib.lib"
compress2(*dest,*destlen,*source,sourcelen,level)
uncompress(*dest,*destlen,*source,sourcelen)
EndImport
CompilerElse
ImportC "-lz"
compress2(*dest,*destlen,*source,sourcelen,level)
uncompress(*dest,*destlen,*source,sourcelen)
EndImport
CompilerEndIf
Enumeration 1
#obj_bitarray
#obj_bitvector
#obj_bloom
#obj_bittire
EndEnumeration
Structure BitBufInfo
Size.q
Bytesused.q
Position.q
Misc.l
type.l
EndStructure
Structure BitBuffer
*vt
inf.bitbufinfo
*buf
EndStructure
Structure node
inext.l[2]
value.i
EndStructure
Structure BitTrie Extends bitBuffer
avail.i
count.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\type = #obj_bittire
*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=1)
Protected *node.node,idx,a,lp,offset
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
If key <> 0
For a = lp To 0 Step -1
idx = (key >> a) & 1
If *node\inext[idx]
offset = *node\inext[idx]
*node = *this\buf + offset
ElseIf *this\avail > 0
offset = *this\inf\Position
*node\inext[idx] = offset
*node = *this\buf + offset
*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 + offset
offset = *this\inf\Position
*node\inext[idx] = offset ;
*node = *this\buf + offset
*this\avail - SizeOf(node)
*this\inf\Position+SizeOf(node)
*this\inf\Bytesused = *this\inf\Position
EndIf
Next
EndIf
If *node
*node\value = val
*this\count + 1
EndIf
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
If key <> 0
For a = lp To 0 Step -1
idx = (key>>a) & 1
If *node
If *node\inext[idx]
*node = *this\buf + *node\inext[idx]
Else
ProcedureReturn 0
EndIf
Else
ProcedureReturn 0
EndIf
Next
EndIf
If *node
ProcedureReturn *node\value
EndIf
EndProcedure
Procedure BitTrie_Walk(*this.bitTrie,*cb.bitTrieCB,*userdata=0,*userdata1=0)
Protected *node.node,pos
If *cb
While pos < *this\inf\Bytesused
*node = *this\buf +pos
If *node\value
*cb(*node\value,*userdata,*userdata1)
EndIf
pos + SizeOf(node)
Wend
EndIf
EndProcedure
Procedure BitTrie_NumItems(*this.bitTrie)
ProcedureReturn *this\count
EndProcedure
Procedure.q Hash_Rs(*mem,len) ;Rs
Protected hash.l, *pta.Ascii,a.l,b.l
a = 378551
b = 63689
*pta =*mem
For c = 1 To len
hash * a
hash + *pta\a
a * b
*pta+1
Next
ProcedureReturn hash & $FFFFFFFF
EndProcedure
Procedure.q Hash_Sax(*mem,len) ;sax
Protected hash.l, *pta.Ascii
*pta =*mem
For a = 1 To len
hash ! (((hash <<5) + (hash >> 2)) + *pta\a)
*pta+1
Next
ProcedureReturn hash & $FFFFFFFF
EndProcedure
Procedure.q Hash_Sdbm(*mem,len) ;sdbm
Protected hash.l, *pta.Ascii
*pta =*mem
For a = 1 To len
hash = *pta\a + ((hash<<6) + (hash<<16) - hash)
*pta+1
Next
ProcedureReturn hash & $FFFFFFFF
EndProcedure
Procedure.q Hash_Js(*mem,len) ;js
Protected hash.l, *pta.Ascii
hash = 1315423911;
*pta =*mem
For a = 1 To len
hash ! ((hash<<5)+*pta\a) +(hash>>2)
*pta+1
Next
ProcedureReturn hash & $FFFFFFFF
EndProcedure
Procedure.q Hash_Fnv32_1(*mem,len) ;Fnv32-1
Protected p.l,hash.l, *pta.Ascii
p = 16777619
hash = 2166136261
*pta =*mem
For a = 1 To len
hash * p
hash ! *pta\a
*pta+1
Next
ProcedureReturn hash & $FFFFFFFF
EndProcedure
Procedure.q Hash_Fnv32_1a(*mem,len) ;fnv32-1a
Protected p.l,hash.l, *pta.Ascii
p = 16777619
hash = 2166136261
*pta =*mem
For a = 1 To len
hash ! *pta\a
hash * p
*pta+1
Next
ProcedureReturn hash & $FFFFFFFF
EndProcedure
Procedure.q Hash_Adler32(*mem,len) ;adler32
Protected pa.l,pb.l,hash.l, *pta.Ascii
*pta =*mem
For a = 1 To len
pa + *pta\a
pa % 65521
pb + a
pb % 65521
*pta+1
Next
hash = ((pb << 16) | pa)
ProcedureReturn hash & $FFFFFFFF
EndProcedure
Prototype.q hash(*mem,len)
Structure bloom Extends bitbuffer
*hashFn.hash[7]
EndStructure
Procedure New_BloomFilter(Items,NumberOfKeys=4,MaxErrorRate.f=0.999)
Protected *this.bloom
*this = AllocateMemory(SizeOf(bloom))
If NumberOfKeys > 6
NumberOfKeys = 6
EndIf
If *this
*this\vt = ?vt_bloom
*this\inf\Position = (-(NumberOfKeys * (items))) / (Log(1 - Pow((MaxErrorRate),1/NumberOfKeys )))
*this\inf\Size = *this\inf\Position >> 3
*this\inf\BytesUsed = *this\inf\size
*this\inf\misc =NumberOfKeys
*this\inf\type = #obj_bloom
*this\buf = AllocateMemory(*this\inf\size)
*this\hashFn[0] = @Hash_Rs()
*this\hashFn[1] = @Hash_Sax()
*this\hashFn[2] = @Hash_Sdbm()
*this\hashFn[3] = @Hash_Js()
*this\hashFn[4] = @Hash_Fnv32_1()
*this\hashFn[5] = @Hash_Fnv32_1a()
*this\hashFn[6] = @Hash_Adler32()
ProcedureReturn *this
EndIf
EndProcedure
Procedure Bloom_Set(*this.Bloom,*key,len)
Protected hash.q,a.i,*ta.Ascii
For a = 0 To *this\inf\Misc-1
hash = *this\hashFn[a](*key,len)
hash % *this\inf\Position
*ta = *this\buf+(hash>>3)
*ta\a | (1 << (hash & $07))
Next
EndProcedure
Procedure Bloom_Get(*this.Bloom,*Key,len)
Protected hash.q,tret,retrn,a,*ta.Ascii
For a = 0 To *this\inf\Misc-1
hash = *this\hashFn[a](*key,len)
hash % *this\inf\Position
*ta = *this\buf+(hash>>3)
tret = (*ta\a & (1 << (hash & $07)))
If tret = 0
ProcedureReturn 0
Else
retrn + 1
EndIf
Next
If retrn = *this\inf\Misc ;number of keys
ProcedureReturn #True
Else
ProcedureReturn #False
EndIf
EndProcedure
Procedure New_BitArray(sizebytes=64,*data=0)
Protected *bv.bitbuffer
*bv = AllocateMemory(SizeOf(bitbuffer))
If *bv
*bv\vt = ?vt_bitArray
*bv\buf = AllocateMemory(sizebytes)
If *bv\buf
*bv\inf\Size = sizebytes
*bv\inf\BytesUsed = sizebytes
*bv\inf\Position = 0
*bv\inf\type = #obj_bitarray
If *data
CopyMemory(*data,*bv\buf,sizebytes)
*bv\inf\Position = sizebytes * 8
EndIf
ProcedureReturn *bv
EndIf
EndIf
EndProcedure
Procedure BitArray_Set(*this.bitbuffer,index)
Protected *ta.Ascii, *bv.bitbuffer,tsize
Protected bit.a
If ((index) >> 3) >= *this\inf\size
*this\inf\size = index + 64
*this\inf\BytesUsed = *this\inf\size
*this\buf = ReAllocateMemory(*this\buf,*this\inf\Size)
EndIf
If *this\buf
*ta = *this\buf + ((index)>>3)
*ta\a | (1 << (7-(index & $07)))
EndIf
EndProcedure
Procedure BitArray_ReSet(*this.bitbuffer,index)
Protected *ta.Ascii
If ((index) >> 3) >= *this\inf\size
*this\inf\size = index + 64
*this\inf\BytesUsed = *this\inf\size
*this\buf = ReAllocateMemory(*this\buf,*this\inf\size)
EndIf
If *this\buf
*ta = *this\buf + ((index)>>3)
If *ta\a & (1 << (7-(index & $07)))
*ta\a ! (1 << (7-(index & $07)))
EndIf
EndIf
EndProcedure
Procedure BitArray_Toggle(*this.bitbuffer,index)
Protected *ta.Ascii
If ((index) >> 3) >= *this\inf\size
*this\inf\size = index + 64
*this\inf\BytesUsed = *this\inf\size
*this\buf = ReAllocateMemory(*this\buf,*this\inf\size)
EndIf
If *this\buf
*ta = *this\buf + ((index)>>3)
*ta\a ! (1 << (7-(index & $07)))
EndIf
EndProcedure
Procedure BitArray_Get(*this.bitbuffer,index)
Protected *ta.Ascii,idx
If ((index) >> 3) <= *this\inf\size
*ta = *this\buf+(index>>3)
If (*ta\a & (1 << (7-(index & $07))))
ProcedureReturn 1
EndIf
EndIf
EndProcedure
Procedure New_BitVector(sizebytes=64,*data=0)
Protected *bv.bitBuffer
*bv = AllocateMemory(SizeOf(bitbuffer))
If *bv
*bv\vt = ?vt_bitvector
*bv\buf = AllocateMemory(sizebytes)
If *bv\buf
*bv\inf\size = sizebytes
*bv\inf\BytesUsed = 0
*bv\inf\Position = 0
*bv\inf\type = #obj_bitvector
If *data
CopyMemory(*data,*bv\buf,sizebytes)
*bv\inf\Position = sizebytes * 8
*bv\inf\Bytesused = sizebytes
EndIf
ProcedureReturn *bv
EndIf
EndIf
EndProcedure
Procedure BitVector_Set(*this.bitbuffer,val,bitcount)
Protected *ti.quad,tsize
tsize = (*this\inf\Position+bitcount) >> 3
If tsize >= *this\inf\size
*this\inf\size = tsize +64
*this\buf = ReAllocateMemory(*this\buf,*this\inf\size)
EndIf
If *this\buf
*ti = *this\buf + ((*this\inf\Position)>>3)
*ti\q | (val << ( *this\inf\Position & $07))
*this\inf\Position + bitcount
*this\inf\BytesUsed = Round(*this\inf\Position / 8,#PB_Round_Up) ;*this\inf\Position >> 3
EndIf
EndProcedure
Procedure BitVector_Get(*this.bitbuffer,index,bitcount)
Protected mask.q,*ti.quad,shift
mask = $FFFFFFFF
mask >> (32-bitcount)
If *this\buf
*ti = *this\buf + ((index)>>3)
shift = (index & $07)
ProcedureReturn (*ti\q & (mask << shift)) >> shift
EndIf
EndProcedure
Procedure BitBuffer_GetBuffer(*this.bitbuffer)
If *this
ProcedureReturn *this\buf
EndIf
EndProcedure
Procedure BitBuffer_SetBuffer(*this.bitbuffer,*mem,len)
If *this
*this\buf = *mem
*this\inf\Bytesused = len
*this\inf\Size = len
EndIf
EndProcedure
Procedure BitBuffer_BiNOP(*this.bitbuffer,*that.bitbuffer,OP)
Protected *pa.Ascii,*pb.Ascii,a
If *this\inf\Size <= *that\inf\Size
*this\buf = ReAllocateMemory(*this\buf,*that\inf\Size)
*this\inf\Size = *that\inf\Size
*this\inf\Position = *that\inf\Position
*this\inf\Bytesused = *that\inf\Bytesused
*this\inf\Misc = *that\inf\Misc
EndIf
*pa = *this\buf
*pb = *that\buf
For a = 0 To *that\inf\Size-1
Select OP
Case #OP_OR
*pa\a | *pb\a
Case #OP_AND
*pa\a & *pb\a
Case #OP_XOR
*pa\a ! *pb\a
EndSelect
*pa+1
*pb+1
Next
EndProcedure
Procedure BitBuffer_BiNOPNew(*this.bitbuffer,*that.bitbuffer,OP)
Protected *pa.Ascii,*pb.Ascii,*pc.Ascii,a
Protected *result.BitBuffer = New_BitArray(*this\inf\Size)
*pa = *this\buf
*pb = *that\buf
*pc = *result\buf
For a = 0 To *that\inf\Size;-1
Select OP
Case #OP_OR
*pc\a = *pa\a | *pb\a
Case #OP_AND
*pc\a = *pa\a & *pb\a
Case #OP_XOR
*pc\a = *pa\a ! *pb\a
EndSelect
*pa+1
*pb+1
*pc+1
Next
ProcedureReturn *result
EndProcedure
Procedure BitBuffer_Not(*this.bitbuffer)
Protected *pa.Ascii,a
*pa = *this\buf
For a = 0 To *this\inf\Size
*pa\a = ~*pa\a
*pa+1
Next
EndProcedure
Procedure BitBuffer_ShiftLeft(*this.bitbuffer)
Protected *data,length.l
*data = *this\buf
length = *this\inf\Size
!xor eax, eax
!mov ecx, [p.v_length]
!dec ecx
!jc slb_exit
CompilerIf #PB_Compiler_Processor = #PB_Processor_x64
!mov rdx, [p.p_data]
!slb_loop:
!mov ah, [rdx + rcx]
!shl eax, 1
!mov [rdx + rcx], ah
CompilerElse
!mov edx, [p.p_data]
!slb_loop:
!mov ah, [edx + ecx]
!shl eax, 1
!mov [edx + ecx], ah
CompilerEndIf
!shr eax, 9
!sub ecx, 1
!jnc slb_loop
!slb_exit:
!shr eax, 7
ProcedureReturn
EndProcedure
Procedure BitBuffer_ShiftRight(*this.bitbuffer)
Protected *data,length.l
*data = *this\buf
length = *this\inf\Position
!xor eax, eax
!mov ecx, [p.v_length]
!and ecx, ecx
!jz srb_exit
CompilerIf #PB_Compiler_Processor = #PB_Processor_x64
!mov rdx, [p.p_data]
!srb_loop:
!mov ah, [rdx]
!shr eax, 1
!mov [rdx], ah
!inc rdx
CompilerElse
!mov edx, [p.p_data]
!srb_loop:
!mov ah, [edx]
!shr eax, 1
!mov [edx], ah
!inc edx
CompilerEndIf
!shl eax, 9
!dec ecx
!jnz srb_loop
!srb_exit:
!shr eax, 16
!and eax, 1
ProcedureReturn
EndProcedure
CompilerIf SizeOf(Integer) = 4
Procedure _popcountmem(*mem.long,len.l)
Protected result,a,b
!mov eax, [p.v_len]
!and eax, 3
!mov edx, [p.v_len]
!sub edx,eax
!mov [p.v_a],edx
!mov [p.v_b],eax
!xor ecx,ecx
!lwhile:
!cmp ecx, [p.v_a]
!jge lend
!mov eax, [p.p_mem]
!mov eax, [eax + ecx]
!mov edx, eax
!shr edx, 1
!and edx, 0x55555555
!sub eax,edx
!mov edx, eax
!and eax, 0x33333333
!shr edx, 2
!and edx, 0x33333333
!add eax,edx
!mov edx, eax
!shr edx, 4
!add eax,edx
!and eax, 0x0f0f0f0f
!imul eax, 0x01010101
!shr eax, 24
!add [p.v_result],eax
!add ecx,4
!jmp lwhile
!lend:
!mov eax, [p.p_mem]
!mov eax, [eax + ecx]
!mov edx, [p.v_b]
!jmp dword [JT_remain + edx * 4]
!JT_remain dd le,l1,l2,l3,l4
!l1:
!and eax, 0xff
!jmp le
!l2:
!and eax, 0xffff
!jmp le
!l3:
!and eax, 0xffffff
!jmp le
!l4:
!le:
!mov edx, eax
!shr edx, 1
!and edx, 0x55555555
!sub eax,edx
!mov edx, eax
!and eax, 0x33333333
!shr edx, 2
!and edx, 0x33333333
!add eax,edx
!mov edx, eax
!shr edx, 4
!add eax,edx
!and eax, 0x0f0f0f0f
!imul eax, 0x01010101
!shr eax, 24
!add [p.v_result],eax
ProcedureReturn result
EndProcedure
Procedure _popcountmemSSE(*mem,len)
Protected result,a,b
!mov eax, [p.v_len]
!and eax, 3
!mov edx, [p.v_len]
!sub edx,eax
!mov [p.v_a],edx
!mov [p.v_b],eax
!xor ecx,ecx
!lwhile1:
!cmp ecx, [p.v_a]
!jge lend1
!mov eax, [p.p_mem]
!mov eax, [eax + ecx]
!popcnt eax,eax
!add [p.v_result],eax
!add ecx,4
!jmp lwhile1
!lend1:
!mov eax, [p.p_mem]
!mov eax, [eax + ecx]
!mov edx, [p.v_b]
!jmp dword [JT_remain1 + edx * 4]
!JT_remain1 dd lle,ll1,ll2,ll3,ll4
!ll1:
!and eax, 0xff
!jmp lle
!ll2:
!and eax, 0xffff
!jmp lle
!ll3:
!and eax, 0xffffff
!jmp lle
!ll4:
!lle:
!mov edx,eax
!popcnt eax,edx
!add [p.v_result],eax
ProcedureReturn result
EndProcedure
CompilerElse
Procedure _popcountmem(*mem,len)
Protected result,a,b
!mov rax, [p.v_len]
!And rax, 3
!mov rdx, [p.v_len]
!sub rdx,rax
!mov [p.v_a],rdx
!mov [p.v_b],rax
!xor rcx,rcx
!lwhile:
!cmp rcx, [p.v_a]
!jge lend
!mov rax, [p.p_mem]
!mov eax, [rax + rcx]
!mov edx, eax
!shr edx, 1
!and edx, 0x55555555
!sub eax,edx
!mov edx, eax
!and eax, 0x33333333
!shr edx, 2
!and edx, 0x33333333
!add eax,edx
!mov edx, eax
!shr edx, 4
!add eax,edx
!and eax, 0x0f0f0f0f
!imul eax, 0x01010101
!shr eax, 24
!add [p.v_result],eax
!add rcx,4
!jmp lwhile
!lend:
!mov rax, [p.p_mem]
!mov eax, [rax + rcx]
!lea rdx, [JT_remain]
!mov rcx, [p.v_b]
!jmp qword [rdx + rcx * 8]
!JT_remain dq le,l1,l2,l3,l4
!l1:
!and eax, 0xff
!jmp le
!l2:
!and eax, 0xffff
!jmp le
!l3:
!and eax, 0xffffff
!jmp le
!l4:
!le:
!mov edx, eax
!shr edx, 1
!and edx, 0x55555555
!sub eax,edx
!mov edx, eax
!and eax, 0x33333333
!shr edx, 2
!and edx, 0x33333333
!add eax,edx
!mov edx, eax
!shr edx, 4
!add eax,edx
!and eax, 0x0f0f0f0f
!imul eax, 0x01010101
!shr eax, 24
!add [p.v_result],eax
ProcedureReturn result
EndProcedure
Procedure _popcountmemSSE(*mem,len)
Protected result,a,b
!mov rax, [p.v_len]
!and rax, 7
!mov rdx, [p.v_len]
!sub rdx,rax
!mov [p.v_a],rdx
!mov [p.v_b],rax
!xor rcx,rcx
!lwhile1:
!cmp rcx, [p.v_a]
!jge lend1
!mov rax, [p.p_mem]
!mov rax, [rax + rcx]
!popcnt rax,rax
!add [p.v_result],rax
!add rcx,8
!jmp lwhile1
!lend1:
!mov rax, [p.p_mem]
!mov rax, [rax + rcx]
!lea rdx, [JT_remain1]
!mov rcx, [p.v_b]
!jmp qword [rdx + rcx * 8]
!JT_remain1 dq lle,ll1,ll2,ll3,ll4,ll5,ll6,ll7,ll8
!ll1:
!and rax, 0xff
!jmp lle
!ll2:
!and rax, 0xffff
!jmp lle
!ll3:
!and rax, 0xffffff
!jmp lle
!ll4:
!mov rdx,0xffffffff
!and rax, rdx
!jmp lle
!ll5:
!mov rdx, 0xffffffffff
!and rax, rdx
!jmp lle
!ll6:
!mov rdx,0xffffffffffff
!and rax, rdx
!jmp lle
!ll7:
!mov rdx,0xffffffffffffff
!and rax, rdx
!jmp lle
!ll8:
!lle:
!mov rdx,rax
!popcnt rax,rdx
!add [p.v_result],rax
ProcedureReturn result
EndProcedure
CompilerEndIf
Prototype PopCountMem(*mem,len)
Global PopCountMem.PopCountMem
Procedure InitpopCount()
Protected result
!mov eax, 1
!cpuid
!shr ecx, 23
!and ecx, 1
!mov [p.v_result],ecx
If result
popcountmem = @_popcountmemSSE()
Else
popcountmem = @_popcountmem()
EndIf
EndProcedure
Procedure BitBuffer_GetBitCount(*this.bitbuffer) ;popcount
If *this
If Not popcountmem
InitpopCount()
EndIf
ProcedureReturn PopCountMem(*this\buf,*this\inf\Size)
EndIf
EndProcedure
Procedure BitBuffer_GetBitSize(*this.bitbuffer)
If *this
ProcedureReturn *this\inf\BytesUsed * 8
EndIf
EndProcedure
Procedure BitBuffer_GetByteSize(*this.bitbuffer)
If *this
ProcedureReturn *this\inf\BytesUsed
EndIf
EndProcedure
Procedure BitBuffer_SaveToFile(*this.bitbuffer,file.s,CompressLevel=9)
Protected fn,len,*src,*dst,destlen,srclen
fn = OpenFile(#PB_Any,file)
If fn
srclen = *this\inf\BytesUsed+SizeOf(BitBufInfo)
*src = AllocateMemory(srclen)
destlen = srclen * 1.5
*dst = AllocateMemory(destlen)
If *src And *dst ;bit stupid here need to rework structures so don't have to copy before compress
CopyMemory(@*this\inf,*src,SizeOf(BitBufInfo))
CopyMemory(*this\buf,*src+SizeOf(BitBufInfo),*this\inf\BytesUsed)
If compress2(*dst,@destlen,*src,srclen ,CompressLevel) = 0
len = WriteLong(fn,srclen)
len + WriteData(fn,*dst,destlen)
CloseFile(fn)
FreeMemory(*src)
FreeMemory(*dst)
ProcedureReturn len
EndIf
EndIf
EndIf
EndProcedure
Procedure BitBuffer_LoadFile(*this.bitbuffer,file.s)
Protected fn,destlen,srclen,*src,*dst
fn = OpenFile(#PB_Any,file)
If fn
destlen = ReadLong(fn)
*dst = AllocateMemory(destlen)
srclen = Lof(fn)-4
*src = AllocateMemory(srclen)
ReadData(fn,*src,srclen)
If uncompress(*dst,@destlen,*src,srclen) = 0
CopyMemory(*dst,@*this\inf,SizeOf(BitBufInfo))
FreeMemory(*this\buf)
*this\buf = AllocateMemory(*this\inf\size)
CopyMemory(*dst+SizeOf(BitBufInfo),*this\buf,destlen-SizeOf(BitBufInfo))
FreeMemory(*dst)
FreeMemory(*src)
CloseFile(fn)
ProcedureReturn 1
EndIf
EndIf
EndProcedure
Procedure BitBuffer_Catch(*this.bitbuffer,*mem,len)
Protected destlen,srclen,*src,*dst
If *mem
destlen = PeekL(*mem)
*mem+4
*dst = AllocateMemory(destlen)
srclen = len-4
If uncompress(*dst,@destlen,*mem,srclen) = 0
CopyMemory(*dst,@*this\inf,SizeOf(BitBufInfo))
FreeMemory(*this\buf)
*this\buf = AllocateMemory(*this\inf\size)
CopyMemory(*dst+SizeOf(BitBufInfo),*this\buf,destlen-SizeOf(BitBufInfo))
FreeMemory(*dst)
ProcedureReturn 1
EndIf
EndIf
EndProcedure
Procedure BitBuffer_Clear(*this.bitbuffer)
If *this
FillMemory(*this\buf,*this\inf\Bytesused)
*this\inf\Position=0
EndIf
EndProcedure
Procedure BitBuffer_Free(*this.bitbuffer)
If *this
FreeMemory(*this\buf)
FreeMemory(*this)
EndIf
EndProcedure
DataSection
vt_Bitvector:
Data.i @BitVector_Set()
Data.i @BitVector_Get()
Data.i @BitBuffer_GetBuffer()
Data.i @BitBuffer_SetBuffer()
Data.i @BitBuffer_BinOP()
Data.i @BitBuffer_Not()
Data.i @bitBuffer_ShiftLeft()
Data.i @bitbuffer_ShiftRight()
Data.i @BitBuffer_SaveToFile()
Data.i @BitBuffer_LoadFile()
Data.i @BitBuffer_Catch()
Data.i @BitBuffer_GetBitSize()
Data.i @BitBuffer_GetByteSize()
Data.i @BitBuffer_GetBitCount()
Data.i @BitBuffer_Clear()
Data.i @BitBuffer_Free()
EndDataSection
DataSection
vt_BitArray:
Data.i @BitArray_Set()
Data.i @BitArray_ReSet()
Data.i @BitArray_Toggle()
Data.i @BitArray_Get()
Data.i @BitBuffer_GetBuffer()
Data.i @BitBuffer_BinOP()
Data.i @BitBuffer_BiNOPNew()
Data.i @BitBuffer_Not()
Data.i @bitBuffer_ShiftLeft()
Data.i @bitbuffer_ShiftRight()
Data.i @BitBuffer_SaveToFile()
Data.i @BitBuffer_LoadFile()
Data.i @BitBuffer_Catch()
Data.i @BitBuffer_GetBitSize()
Data.i @BitBuffer_GetByteSize()
Data.i @BitBuffer_GetBitCount()
Data.i @BitBuffer_Clear()
Data.i @BitBuffer_Free()
EndDataSection
DataSection
vt_bloom:
Data.i @Bloom_Set()
Data.i @Bloom_Get()
Data.i @BitBuffer_GetBuffer()
Data.i @BitBuffer_BinOP()
Data.i @BitBuffer_Not()
Data.i @BitBuffer_SaveToFile()
Data.i @BitBuffer_LoadFile()
Data.i @BitBuffer_Catch()
Data.i @BitBuffer_GetBitSize()
Data.i @BitBuffer_GetByteSize()
Data.i @BitBuffer_GetBitCount()
Data.i @BitBuffer_Clear()
Data.i @BitBuffer_Free()
EndDataSection
DataSection
vt_BitTrie:
Data.i @BitTrie_Add()
Data.i @BitTrie_Get()
Data.i @BitBuffer_GetBuffer()
Data.i @BitTrie_Walk()
Data.i @BitBuffer_SaveToFile()
Data.i @BitBuffer_LoadFile()
Data.i @BitBuffer_Catch()
Data.i @BitBuffer_GetByteSize()
Data.i @BitTrie_NumItems()
Data.i @BitBuffer_Clear()
Data.i @BitBuffer_Free()
EndDataSection
EndModule
CompilerIf #PB_Compiler_IsMainFile
UseModule BitModule
Procedure.i CreateB(*input,*ba.IBitArray=0)
Protected *inp.Unicode = *input
Protected n.u
Repeat
n = (*inp\u-48) * 10
*inp+2
n + *inp\u-48
*ba\set(n)
*inp+2
If *inp\u <> 0
*inp+2
EndIf
Until *inp\u = 0
EndProcedure
Procedure Count(*input1,*input2)
Static.IBitArray ba1,ba2
If Not ba1
ba1 = New_BitArray()
ba2 = New_BitArray()
EndIf
ba1\Clear()
ba2\Clear()
CreateB(*input1,ba1)
Createb(*input2,ba2)
ba1\BiNOP(ba2,#OP_AND)
ProcedureReturn ba1\BitCount()
EndProcedure
;test code
UseModule BitModule
;bit array class grows as needed
Define.i a,cx,et,st,sz
Define.s s1,s2,out
s1 = "92 00 99 80 65 68 04 01"
s2 = "37 65 04 92 15 98 00 43 02"
cx = count(@s1,@s2)
sz = 200000
st = ElapsedMilliseconds()
For a = 0 To sz
count(@s1,@s2)
Next
et = ElapsedMilliseconds()
out.s = " count " + Str(cx) + " time " + Str(et-st) + " ms"
SetClipboardText(out)
MessageRequester("End",out, #PB_MessageRequester_Ok)
CompilerEndIf