BitArray class v1.04
Posted: Thu Sep 15, 2011 5:30 am
BitArray.pbi
Code: Select all
;
; BitArray v1.04
;
; memory is dynamically allocated 16 KiB at a time
;
; *b.BitArray_Class = BitArray_New()
;
; *b\Clear()
; *b\Free()
; v = *b\Count()
; v = *b\Get(index)
; *b\Set(index)
; *b\Reset(index)
; v = *b\Toggle(index)
; *b\Walk(*callback [, userInfo])
; *result.BitArray = *b\Intersect(*b2.BitArray)
; *result.BitArray = *b\Union(*b2.BitArray)
; *result.BitArray = *b\Except(*b2.BitArray)
; s.s = *b\GetSize()
;
Structure BitArray_Root
m.l[32768]
EndStructure
Structure BitArray
*vt.l ; offset 0
*b32.BitArray_Root ; offset 4
b18.l[8192] ; offset 8
EndStructure
Declare BitArray_Clear(*this.BitArray)
Declare BitArray_Free(*this.BitArray)
Declare.l BitArray_Count(*this.BitArray)
Declare.l BitArray_Get(*this.BitArray, index.l)
Declare BitArray_Set(*this.BitArray, index.l)
Declare BitArray_Reset(*this.BitArray, index.l)
Declare.l BitArray_Toggle(*this.BitArray, index.l)
Declare BitArray_Walk(*this.BitArray, *callback.l, userInfo.l = 0)
Declare.l BitArray_Intersect(*this.BitArray, *b.BitArray)
Declare.l BitArray_Union(*this.BitArray, *b.BitArray)
Declare.l BitArray_Except(*this.BitArray, *b.BitArray)
Declare.s BitArray_GetMemSize(*this.BitArray)
Interface BitArray_Class
Clear()
Free()
Count.l()
Get.l(index.l)
Set(index.l)
Reset(index.l)
Toggle.l(index.l)
Walk(*callback.l, userInfo.l = 0)
Intersect.l(*b.BitArray)
Union.l(*b.BitArray)
Except.l(*b.BitArray)
GetSize.s()
EndInterface
DataSection:
vt_BitArray:
Data.l @BitArray_Clear()
Data.l @BitArray_Free()
Data.l @BitArray_Count()
Data.l @BitArray_Get()
Data.l @BitArray_Set()
Data.l @BitArray_Reset()
Data.l @BitArray_Toggle()
Data.l @BitArray_Walk()
Data.l @BitArray_Intersect()
Data.l @BitArray_Union()
Data.l @BitArray_Except()
Data.l @BitArray_GetMemSize()
t_BitArrayCount:
Data.l 0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4,1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5
Data.l 1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6
Data.l 1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6
Data.l 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7
Data.l 1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6
Data.l 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7
Data.l 2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7
Data.l 3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8
EndDataSection
Procedure BitArray_New()
Protected *this.BitArray
*this = AllocateMemory(SizeOf(BitArray))
If *this
*this\vt = ?vt_BitArray
EndIf
ProcedureReturn *this
EndProcedure
Procedure BitArray_Clear(*this.BitArray)
Protected i.l, m.l
If *this
If *this\b32
For i = 0 To $7fff
m = *this\b32\m[i]
If m : FreeMemory(m) : EndIf
Next
FreeMemory(*this\b32)
EndIf
FillMemory(*this + 4, SizeOf(BitArray) - 4)
EndIf
EndProcedure
Procedure BitArray_Free(*this.BitArray)
If *this
BitArray_Clear(*this)
FreeMemory(*this)
EndIf
ProcedureReturn 0
EndProcedure
Procedure.l BitArray_CountBlock(source.l, bytes.l)
EnableASM
MOV edx, source
MOV ecx, bytes
!push ebx
!push esi
!lea ebx, [edx + ecx]
!mov esi, edx
!xor eax, eax
!xor edx, edx
!bitarray_count_block_loop:
!mov ecx, [esi]
!mov dl, cl
!add eax, [l_t_bitarraycount + edx*4]
!mov dl, ch
!add eax, [l_t_bitarraycount + edx*4]
!bswap ecx
!mov dl, cl
!add eax, [l_t_bitarraycount + edx*4]
!mov dl, ch
!add eax, [l_t_bitarraycount + edx*4]
!add esi, 4
!cmp esi, ebx
!jb bitarray_count_block_loop
!pop esi
!pop ebx
DisableASM
ProcedureReturn
EndProcedure
Procedure.l BitArray_Count(*this.BitArray)
Protected c.l, i.l, m.l, count.l = 0
If *this
If *this\b32
For i = 0 To $7fff
m = *this\b32\m[i]
If m
c = BitArray_CountBlock(m, $4000)
If c
count + c
Else
FreeMemory(m)
*this\b32\m[i] = 0
EndIf
EndIf
Next
If count = 0
FreeMemory(*this\b32)
*this\b32 = 0
EndIf
EndIf
count + BitArray_CountBlock(@*this\b18, $8000)
EndIf
ProcedureReturn count
EndProcedure
Procedure.l BitArray_Get(*this.BitArray, index.l)
EnableASM
MOV eax, *this
MOV ecx, index
!and eax, eax
!jnz bitarray_get_ok
ProcedureReturn
!bitarray_get_ok:
!lea edx, [eax + 8]
!test ecx, 0xfffc0000
!jz bitarray_get18
!sub edx, 4
!mov eax, [edx]
!and eax, eax
!jz bitarray_get_exit
!mov edx, ecx
!shr edx, 17
!mov eax, [eax + edx*4]
!and eax, eax
!jz bitarray_get_exit
!mov edx, eax
!and ecx, 0x1ffff
!bitarray_get18:
!mov eax, ecx
!shr eax, 5
!and ecx, 31
!bt [edx + eax*4], ecx
!rcl eax, 1
!and eax, 1
!bitarray_get_exit:
DisableASM
ProcedureReturn
EndProcedure
Macro BitArray_AllocMem(n)
!push ecx
!push edx
!push ebp
!mov ebp, esp
!and esp, 0xfffffff0
AllocateMemory(n)
!mov esp, ebp
!pop ebp
!pop edx
!pop ecx
EndMacro
Macro BitArray_MacroOp(op)
EnableASM
MOV eax, *this
MOV ecx, index
!and eax, eax
!jnz bitarray_#op#_ok
ProcedureReturn
!bitarray_#op#_ok:
!lea edx, [eax + 8]
!test ecx, 0xfffc0000
!jz bitarray_#op#18
!sub edx, 4
!mov eax, [edx]
!and eax, eax
!jnz bitarray_#op#_root_ok
BitArray_AllocMem($20000)
!mov [edx], eax
!bitarray_#op#_root_ok:
!mov edx, ecx
!shr edx, 17
!lea edx, [eax + edx*4]
!mov eax, [edx]
!and eax, eax
!jnz bitarray_#op#_sub_ok
BitArray_AllocMem($4000)
!mov [edx], eax
!bitarray_#op#_sub_ok:
!mov edx, eax
!and ecx, 0x1ffff
!bitarray_#op#18:
!mov eax, ecx
!shr eax, 5
!and ecx, 31
DisableASM
EndMacro
Procedure BitArray_Set(*this.BitArray, index.l)
BitArray_MacroOp(set)
!bts [edx + eax*4], ecx
ProcedureReturn
EndProcedure
Procedure BitArray_Reset(*this.BitArray, index.l)
BitArray_MacroOp(reset)
!btr [edx + eax*4], ecx
ProcedureReturn
EndProcedure
Procedure.l BitArray_Toggle(*this.BitArray, index.l)
BitArray_MacroOp(toggle)
!btc [edx + eax*4], ecx
!sbb eax, eax
!inc eax
ProcedureReturn
EndProcedure
Procedure BitArray_Walk(*this.BitArray, *callback.l, userInfo.l = 0)
EnableASM
MOV eax, *this
MOV ecx, *callback
MOV edx, userInfo
!and eax, eax
!jnz ba_walk_ok
ProcedureReturn
!ba_walk_ok:
!push ebx
!push esi
!push edi
!push ebp
!mov edi, edx ; edi = userInfo
!lea edx, [eax + 8] ; edx = *this\b18
!xor ebx, ebx ; ebx = start index
!mov ebp, 0x8000 ; ebp = num bytes
!push edx
!call ba_walk_block
!pop edx
!mov eax, [edx - 4]
!and eax, eax
!jz ba_walk_noroot
!sub esp, 12
!mov [esp], eax
!mov dword [esp + 4], 0x8000 ; block counter
!mov dword [esp + 8], 0 ; start index
!ba_walk_loop:
!mov eax, [esp]
!mov edx, [eax]
!and edx, edx
!jz ba_walk_nosub
!mov ebx, [esp + 8]
!mov ebp, 0x4000
!call ba_walk_block
!ba_walk_nosub:
!add dword [esp], 4
!add dword [esp + 8], 0x20000
!dec dword [esp + 4]
!jnz ba_walk_loop
!add esp, 12
!ba_walk_noroot:
!pop ebp
!pop edi
!pop esi
!pop ebx
ProcedureReturn
; edx = block start
; ebx = start index
; ebp = byte counter
; ecx = callback
; edi = userinfo
!ba_walk_block:
!add ebx, 32
!mov eax, [edx]
!and eax, eax
!jz ba_walk_skip32
!sub ebx, 32
!xor esi, esi
!ba_walk_l32:
!bt eax, esi
!jnc ba_walk_no_call
!push eax
!push ecx
!push edx
!push ebp
!mov ebp, esp
!and esp, 0xfffffff0
!sub esp, 8
!push edi
!push ebx
!call ecx
!mov esp, ebp
!pop ebp
!pop edx
!pop ecx
!pop eax
!ba_walk_no_call:
!inc ebx
!inc esi
!bt esi, 5
!jnc ba_walk_l32
!ba_walk_skip32:
!add edx, 4
!sub ebp, 4
!jnz ba_walk_block
!ret
EndProcedure
Macro BitArray_Logic(operation, opcode)
If *this\b32 And *b\b32
*result\b32 = AllocateMemory($20000)
For i = 0 To $7fff
If *this\b32\m[i] And *b\b32\m[i]
*result\b32\m[i] = AllocateMemory($4000)
EndIf
Next
EndIf
EnableASM
MOV eax, *this
MOV ecx, *b
MOV edx, *result
!push ebx
!mov ebx, 8
!ba_#operation#_loop0:
!movq mm0, [ecx + ebx]
opcode mm0, [eax + ebx]
!movq [edx + ebx], mm0
!add ebx, 8
!cmp ebx, 0x8008
!jb ba_#operation#_loop0
!mov edx, [edx + 4]
!and edx, edx
!jz ba_#operation#_noroot
!mov ecx, [ecx + 4]
!mov eax, [eax + 4]
!xor ebx, ebx
!push esi
!ba_#operation#_loop1:
!push edx
!mov edx, [edx + ebx]
!and edx, edx
!jz ba_#operation#_skip
!push ecx
!push eax
!mov ecx, [ecx + ebx]
!mov eax, [eax + ebx]
!xor esi, esi
!ba_#operation#_loop2:
!movq mm0, [ecx + esi]
opcode mm0, [eax + esi]
!movq [edx + esi], mm0
!add esi, 8
!cmp esi, 0x4000
!jb ba_#operation#_loop2
!pop eax
!pop ecx
!ba_#operation#_skip:
!pop edx
!add ebx, 4
!cmp ebx, 0x20000
!jb ba_#operation#_loop1
!pop esi
!ba_#operation#_noroot:
!pop ebx
!ba_#operation#_exit:
!emms
DisableASM
EndMacro
Procedure.l BitArray_Intersect(*this.BitArray, *b.BitArray)
Protected i.l, *result.BitArray = BitArray_New()
If *this And *b And *result
BitArray_Logic(intersect, pand)
EndIf
ProcedureReturn *result
EndProcedure
Procedure.l BitArray_Union(*this.BitArray, *b.BitArray)
Protected i.l, *result.BitArray = BitArray_New()
If *this And *b And *result
BitArray_Logic(union, pxor)
EndIf
If *result
If *this
If Not *b : CopyMemory(@*this\b18, @*result\b18, $8000) : EndIf
If *this\b32
If Not *result\b32 : *result\b32 = AllocateMemory($20000) : EndIf
For i = 0 To $7fff
If *this\b32\m[i] And Not *result\b32\m[i]
*result\b32\m[i] = AllocateMemory($4000)
CopyMemory(*this\b32\m[i], *result\b32\m[i], $4000)
EndIf
Next
EndIf
EndIf
If *b
If Not *this : CopyMemory(@*b\b18, @*result\b18, $8000) : EndIf
If *b\b32
If Not *result\b32 : *result\b32 = AllocateMemory($20000) : EndIf
For i = 0 To $7fff
If *b\b32\m[i] And Not *result\b32\m[i]
*result\b32\m[i] = AllocateMemory($4000)
CopyMemory(*b\b32\m[i], *result\b32\m[i], $4000)
EndIf
Next
EndIf
EndIf
EndIf
ProcedureReturn *result
EndProcedure
Procedure.l BitArray_Except(*this.BitArray, *b.BitArray)
Protected i.l, *result.BitArray = BitArray_New()
If *this And *b And *result
BitArray_Logic(except, pandn)
EndIf
If *result
If *this
If Not *b : CopyMemory(@*this\b18, @*result\b18, $8000) : EndIf
If *this\b32
If Not *result\b32 : *result\b32 = AllocateMemory($20000) : EndIf
For i = 0 To $7fff
If *this\b32\m[i] And Not *result\b32\m[i]
*result\b32\m[i] = AllocateMemory($4000)
CopyMemory(*this\b32\m[i], *result\b32\m[i], $4000)
EndIf
Next
EndIf
EndIf
EndIf
ProcedureReturn *result
EndProcedure
Procedure.s BitArray_GetMemSize(*this.BitArray)
Protected i.l, sz.s, size.l
If *this
size = SizeOf(BitArray)
If *this\b32
size + $20000
For i = 0 To $7fff
If *this\b32\m[i] : size + $4000 : EndIf
Next
EndIf
If size < 1048576
sz = Str(size/1024) + " KiB"
Else
sz = Str(size/1048576) + " MiB"
EndIf
EndIf
ProcedureReturn sz
EndProcedure