554 lines
10 KiB
C++
554 lines
10 KiB
C++
/*************************************************************************/
|
|
/* File : XBitArray.h */
|
|
/* Author : Aymeric Bard */
|
|
/* */
|
|
/* Virtools SDK */
|
|
/* Copyright (c) Virtools 2000, All Rights Reserved. */
|
|
/*************************************************************************/
|
|
#ifndef XBITARRAY_H
|
|
#define XBITARRAY_H "$Id:$"
|
|
|
|
#include "XArray.h"
|
|
#include "VxMath.h"
|
|
|
|
/************************************************
|
|
{filename:XBitArray}
|
|
Summary: Set of bit flags.
|
|
|
|
Remarks:
|
|
|
|
o This class define a set of bit flags that may be treated as a virtual array but are stored in an efficient manner.
|
|
o The class has methods to set, clear and return the i-th bit, resize the array, etc.
|
|
************************************************/
|
|
class XBitArray
|
|
{
|
|
public:
|
|
XBitArray(int initialsize = 1) {
|
|
if (initialsize<1) initialsize=1;
|
|
m_Size = (initialsize<<5);
|
|
if (m_Size > 32) { // we allocate only if > 32
|
|
m_Data = Allocate(initialsize);
|
|
Clear();
|
|
} else {
|
|
m_Flags = 0;
|
|
}
|
|
}
|
|
|
|
~XBitArray() {
|
|
if (m_Size > 32)
|
|
Free();
|
|
}
|
|
|
|
// copy Ctor
|
|
XBitArray(const XBitArray& a)
|
|
{
|
|
m_Size = a.m_Size;
|
|
if (m_Size <= 32)
|
|
m_Flags = a.m_Flags;
|
|
else {
|
|
m_Data = Allocate(m_Size>>5);
|
|
memcpy(m_Data,a.m_Data,m_Size>>3);
|
|
}
|
|
}
|
|
|
|
// operator =
|
|
XBitArray& operator = (const XBitArray& a)
|
|
{
|
|
if (this != &a) {
|
|
if (m_Size != a.m_Size) {
|
|
if (m_Size > 32)
|
|
Free();
|
|
|
|
m_Size = a.m_Size;
|
|
if (m_Size > 32) { // we allocate only if > 32
|
|
m_Data = Allocate(m_Size>>5);
|
|
memcpy(m_Data,a.m_Data,m_Size>>3);
|
|
} else {
|
|
m_Flags = a.m_Flags;
|
|
}
|
|
} else {
|
|
if (m_Size>32)
|
|
memcpy(m_Data,a.m_Data,m_Size>>3);
|
|
else
|
|
m_Flags = a.m_Flags;
|
|
|
|
}
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
|
|
// Reallocation if necessary
|
|
void CheckSize(int n)
|
|
{
|
|
while (n >= m_Size) { // m_Size >= 32, always
|
|
|
|
int size = (m_Size>>5);
|
|
XDWORD* temp = Allocate(size+size);
|
|
|
|
// Copy the old bits
|
|
if (m_Size > 32)
|
|
memcpy(temp,m_Data,size*sizeof(XDWORD));
|
|
else
|
|
*temp = m_Flags;
|
|
|
|
// Clear the new bits
|
|
memset(temp+size,0,size*sizeof(XDWORD));
|
|
|
|
if (m_Size > 32) // we free only if we were allocated
|
|
Free();
|
|
|
|
m_Data = temp;
|
|
m_Size += m_Size;
|
|
}
|
|
}
|
|
|
|
void CheckSameSize(XBitArray& a)
|
|
{
|
|
if (m_Size < a.m_Size) {
|
|
if (a.m_Size > 32) {
|
|
int size = a.m_Size>>5;
|
|
int oldsize = m_Size>>5;
|
|
XDWORD* temp = Allocate(size);
|
|
// Copy the old bits
|
|
if (m_Size > 32)
|
|
memcpy(temp,m_Data,oldsize*sizeof(XDWORD));
|
|
else
|
|
*temp = m_Flags;
|
|
|
|
// Clear the new bits
|
|
memset(temp+oldsize,0,(size-oldsize)*sizeof(XDWORD));
|
|
|
|
if (m_Size > 32) // we free only if we were allocated
|
|
Free();
|
|
|
|
m_Data = temp;
|
|
m_Size = a.m_Size;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// Summary: Returns if the n-th bit is set to 1
|
|
int IsSet(int n) {
|
|
if (n >= m_Size)
|
|
return 0; // Out of range
|
|
if (m_Size <= 32)
|
|
return (m_Flags & (1<<n)); // Not allocated
|
|
|
|
return (m_Data[n>>5] & (1<<(n&31))); // Allocated after the first DWORD
|
|
}
|
|
|
|
// Summary: Returns if the n-th bit is set to 1
|
|
int operator [] (int n) {
|
|
return IsSet(n);
|
|
}
|
|
|
|
// Summary: Appends the bitcount first bits of integer v to the array
|
|
void AppendBits(int n,int v,int bitcount)
|
|
{
|
|
int mask = 1;
|
|
bitcount += n;
|
|
for(int i=n;i<bitcount; ++i,mask<<=1) {
|
|
if (mask&v)
|
|
Set(i);
|
|
else
|
|
Unset(i);
|
|
}
|
|
}
|
|
|
|
// Summary: Sets the n-th bit to 1
|
|
void Set(int n) {
|
|
if (n < m_Size) {
|
|
if (m_Size <= 32) { // Only one dword long
|
|
m_Flags |= (1<<n);
|
|
} else { // more than one dword
|
|
m_Data[n>>5] |= 1<<(n&31);
|
|
}
|
|
} else { // we have to reallocate
|
|
CheckSize(n);
|
|
m_Data[n>>5] |= 1<<(n&31);
|
|
}
|
|
}
|
|
|
|
// Summary: Sets the n-th bit to 1 and return 0 if it was set, 1 otherwise
|
|
int TestSet(int n) {
|
|
if(n < m_Size) {
|
|
if (m_Size <= 32) { // Only one dword long
|
|
int mask = 1<<n;
|
|
|
|
if (m_Flags&mask) return 0;
|
|
m_Flags |= mask;
|
|
return 1;
|
|
|
|
} else { // more than one dword
|
|
int pos = n>>5;
|
|
int mask = 1<<(n&31);
|
|
|
|
if (m_Data[pos]&mask) return 0;
|
|
m_Data[pos] |= mask;
|
|
return 1;
|
|
}
|
|
} else { // we have to reallocate
|
|
CheckSize(n);
|
|
m_Data[n>>5] |= 1<<(n&31);
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
// Summary: Sets the n-th bit to 0
|
|
void Unset(int n) {
|
|
if(n < m_Size) {
|
|
if (m_Size <= 32) {
|
|
m_Flags &= ~(1<<n);
|
|
} else {
|
|
m_Data[n>>5] &= ~(1<<(n&31));
|
|
}
|
|
}
|
|
}
|
|
|
|
// Summary: Sets the n-th bit to 0 and return 1 if it was set, 0 otherwise
|
|
int TestUnset(int n) {
|
|
if(n < m_Size) {
|
|
if (m_Size <= 32) {
|
|
int mask = 1<<n;
|
|
if (m_Flags & mask) {
|
|
m_Flags &= ~mask;
|
|
return 1;
|
|
}
|
|
return 0;
|
|
} else {
|
|
int pos = n>>5;
|
|
int mask = 1<<(n&31);
|
|
if (m_Data[pos] & mask) {
|
|
m_Data[pos] &= ~mask;
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
} else return 0;
|
|
}
|
|
|
|
// Summary: Returns the number of bits
|
|
int Size() const {
|
|
return m_Size;
|
|
}
|
|
|
|
// Summary: Resets the array
|
|
void Clear() {
|
|
if (m_Size<=32)
|
|
m_Flags = 0;
|
|
else
|
|
memset(m_Data,0,(m_Size>>3));
|
|
}
|
|
|
|
// Summary: Sets all bits of the array to 1
|
|
// Warning : this functions sets all the allocated bits, not only the
|
|
// used bits
|
|
void Fill() {
|
|
if (m_Size<=32)
|
|
m_Flags = 0xffffffff;
|
|
else
|
|
memset(m_Data,0xff,(m_Size>>3));
|
|
}
|
|
|
|
// Summary: Performs a binary AND with another array
|
|
void And(XBitArray& a)
|
|
{
|
|
if (a.m_Size <= 32) {
|
|
if (m_Size <= 32)
|
|
m_Flags &= a.m_Flags;
|
|
else {
|
|
m_Data[0] &= a.m_Flags;
|
|
|
|
// clear the remaining bytes
|
|
int rsize = m_Size>>5;
|
|
for (int i=1;i<rsize;++i) {
|
|
m_Data[i] = 0;
|
|
}
|
|
}
|
|
} else {
|
|
if (m_Size <= 32)
|
|
m_Flags &= a.m_Data[0];
|
|
else {
|
|
int size = a.m_Size>>5;
|
|
int i = 0;
|
|
for (;i<size;++i) {
|
|
m_Data[i] &= a.m_Data[i];
|
|
}
|
|
// clear the remaining bytes
|
|
int rsize = m_Size>>5;
|
|
for (;i<rsize;++i) {
|
|
m_Data[i] = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Summary: subtract bits from another bitarray
|
|
XBitArray& operator -= (XBitArray& a)
|
|
{
|
|
if (a.m_Size <= 32) {
|
|
if (m_Size <= 32)
|
|
m_Flags &= ~a.m_Flags;
|
|
else {
|
|
m_Data[0] &= ~a.m_Flags;
|
|
}
|
|
} else {
|
|
if (m_Size <= 32)
|
|
m_Flags &= ~a.m_Data[0];
|
|
else {
|
|
int size = a.m_Size>>5;
|
|
int i = 0;
|
|
for (;i<size;++i) {
|
|
m_Data[i] &= ~a.m_Data[i];
|
|
}
|
|
}
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
// Summary: Returns TRUE if at least one common bit is set in two arrays
|
|
BOOL CheckCommon(XBitArray& a)
|
|
{
|
|
if (a.m_Size <= 32) {
|
|
if (m_Size <= 32)
|
|
return (m_Flags & a.m_Flags);
|
|
else
|
|
return (m_Data[0] & a.m_Flags);
|
|
} else {
|
|
if (m_Size <= 32)
|
|
return (m_Flags & a.m_Data[0]);
|
|
else {
|
|
int size = a.m_Size>>5;
|
|
for (int i=0;i<size;++i) {
|
|
if (m_Data[i] & a.m_Data[i])
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
// Summary: Performs a binary OR with another array
|
|
void Or(XBitArray& a)
|
|
{
|
|
CheckSameSize(a);
|
|
|
|
if (a.m_Size <= 32) {
|
|
if (m_Size <= 32)
|
|
m_Flags |= a.m_Flags;
|
|
else
|
|
m_Data[0] |= a.m_Flags;
|
|
} else {
|
|
if (m_Size <= 32)
|
|
m_Flags |= a.m_Data[0];
|
|
else {
|
|
int size = a.m_Size>>5;
|
|
for (int i=0;i<size;++i) {
|
|
m_Data[i] |= a.m_Data[i];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Summary: Performs a binary XOR with another array
|
|
void XOr(XBitArray& a)
|
|
{
|
|
CheckSameSize(a);
|
|
|
|
if (a.m_Size <= 32) {
|
|
if (m_Size <= 32)
|
|
m_Flags ^= a.m_Flags;
|
|
else
|
|
m_Data[0] ^= a.m_Flags;
|
|
} else {
|
|
if (m_Size <= 32)
|
|
m_Flags ^= a.m_Data[0];
|
|
else {
|
|
int size = a.m_Size>>5;
|
|
for (int i=0;i<size;++i) {
|
|
m_Data[i] ^= a.m_Data[i];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Summary: Inverts all bits value in the array
|
|
void Invert()
|
|
{
|
|
if (m_Size <= 32) {
|
|
m_Flags = ~m_Flags;
|
|
} else {
|
|
int size = m_Size>>5;
|
|
for(int i=0;i<size;++i) {
|
|
m_Data[i] = ~m_Data[i];
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// Summary: Returns the number of bits set
|
|
int BitSet()
|
|
{
|
|
int set = 0;
|
|
if (m_Size <= 32) {
|
|
int mask = 1;
|
|
for (int j=0;j<32;++j) {
|
|
if (m_Flags & mask)
|
|
++set;
|
|
mask<<=1;
|
|
}
|
|
} else {
|
|
int size = m_Size>>5;
|
|
for (int i=0;i<size;++i) {
|
|
int mask = 1;
|
|
for(int j=0;j<32;++j) {
|
|
if(m_Data[i]&mask) ++set;
|
|
mask<<=1;
|
|
}
|
|
}
|
|
}
|
|
return set;
|
|
}
|
|
|
|
// Summary: Returns the position of the n-th set(1) bit
|
|
int GetSetBitPosition(int n)
|
|
{
|
|
int set = 0;
|
|
int pos = 0;
|
|
if (m_Size <= 32) {
|
|
int mask = 1;
|
|
for (int j=0; j<32; ++j, ++pos) {
|
|
if (m_Flags & mask) {
|
|
if (set == n)
|
|
return pos;
|
|
++set;
|
|
}
|
|
mask<<=1;
|
|
}
|
|
|
|
} else {
|
|
int size = m_Size>>5;
|
|
for (int i=0;i<size;++i) {
|
|
int mask = 1;
|
|
for (int j=0; j<32; ++j, ++pos) {
|
|
if (m_Data[i] & mask) {
|
|
if (set == n)
|
|
return pos;
|
|
++set;
|
|
}
|
|
mask<<=1;
|
|
}
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
// Summary: Returns the position of the n-th unset(0) bit
|
|
int GetUnsetBitPosition(int n)
|
|
{
|
|
int unset = 0;
|
|
int pos = 0;
|
|
if (m_Size <= 32) {
|
|
int mask = 1;
|
|
for (int j=0; j<32; ++j, ++pos) {
|
|
if (!(m_Flags & mask)) {
|
|
if (unset == n)
|
|
return pos;
|
|
++unset;
|
|
}
|
|
mask<<=1;
|
|
}
|
|
|
|
} else {
|
|
int size = m_Size>>5;
|
|
for (int i=0;i<size;++i) {
|
|
int mask = 1;
|
|
for (int j=0;j<32;++j,++pos) {
|
|
if (!(m_Data[i]&mask)) {
|
|
if (unset == n)
|
|
return pos;
|
|
++unset;
|
|
}
|
|
mask<<=1;
|
|
}
|
|
}
|
|
}
|
|
// We haven't found an unsetted bit yet : we reallocate
|
|
CheckSize(pos);
|
|
return pos;
|
|
}
|
|
|
|
|
|
char * ConvertToString(char * buffer)
|
|
{
|
|
if (buffer)
|
|
{
|
|
int count=0;
|
|
if (m_Size <= 32) {
|
|
for (int j=0;j<32;j++)
|
|
{
|
|
if (m_Flags & (1<<j))
|
|
buffer[count]='1';
|
|
else
|
|
buffer[count]='0';
|
|
count++;
|
|
}
|
|
} else {
|
|
for (int i=0;i<(m_Size>>5);i++)
|
|
{
|
|
for (int j=0;j<32;j++)
|
|
{
|
|
if (m_Data[i] & (1<<j))
|
|
buffer[count]='1';
|
|
else
|
|
buffer[count]='0';
|
|
count++;
|
|
}
|
|
}
|
|
}
|
|
buffer[m_Size]=0;
|
|
}
|
|
return buffer;
|
|
}
|
|
|
|
// Summary: Returns the occupied size in memory in bytes
|
|
int GetMemoryOccupation(BOOL addstatic=FALSE) const {
|
|
if (m_Size<=32)
|
|
return addstatic?sizeof(*this):0;
|
|
else
|
|
return (m_Size>>5)*sizeof(XDWORD)+(addstatic?sizeof(*this):0);
|
|
}
|
|
|
|
private:
|
|
|
|
XDWORD* Allocate(int size)
|
|
{
|
|
return new XDWORD[size];
|
|
}
|
|
|
|
|
|
void Free()
|
|
{
|
|
delete [] m_Data;
|
|
}
|
|
|
|
// the array itself {secret}
|
|
// If the size is inferior strict to 32
|
|
// the data array is not allocated, we
|
|
// just use the sapce of the pointer to store the
|
|
// first bits
|
|
union {
|
|
XDWORD* m_Data;
|
|
XDWORD m_Flags;
|
|
};
|
|
// real size already allocated {secret}
|
|
int m_Size;
|
|
};
|
|
|
|
#endif // BITARRAY_H
|
|
|