|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Announcements
Want a new Job?
Chapters
Services
Feature Zones
|
IntroductionThe Bit Array structure provides a compacted arrays of Booleans, with one bit for each Boolean value. A 0 (1) bit corresponds to the Boolean value false (true), respectively. We can look at a stream of bytes as a stream of bits; each byte contains 8 bits, so any n bytes hold n*8 bits. And the operation to manipulate this stream or bits array is so easy, jut read or change the bits' state or make any Boolean operation on the whole bits array, like ‘AND’, ‘OR’, or ‘XOR’.
As each byte contains 8 bits, we need to divide the bit number by 8 to reach the byte that holds the bit. Then, we can seek to the right bit in the reached byte by the remainder of dividing the bit number by 8. So to read or change the bit state, the operations will be like that: // returns bit state 0 or 1 #define GetBit(a, b) ((((BYTE*)a)[(b)>>3] >> ((b)&7)) & 1) // set bit Boolean value to 1 #define SetBit(a, b) (((BYTE*)a)[(b)>>3] |= (1 << ((b)&7))) // set bit Boolean value to 0 #define ResetBit(a, b) (((BYTE*)a)[(b)>>3] &= ~(1 << ((b)&7))) // toggle bit Boolean value #define XOrBit(a, b) (((BYTE*)a)[(b)>>3] ^= (1 << ((b)&7))) // where 'a' is the byte stream pointer, and b is the bit number. Note that to divide by 8, we need only to shift right by 3 (>>3), and to get the remainder of dividing by 8, we need only to AND with 7 (&7). Bits Array Encapsulation:To deal with the bits stream in more sophisticated operations like get ‘1’s count in the bits stream, or get the order of any bit that includes ‘1’ value in the ‘1’s values, or AND all bits stream with another bits stream, it’ll be so hard to do all operation steps each time in the code. So, it is needed to encapsulate all bits stream operations in a class to handle all or most of bits stream functions. So, I did that in a simple class and named it class CBitArray
{
...
}
This class includes some useful functions like: // to get '1' bits count in the stream of bits GetCount() // to get the state of any bit '0' or '1' GetAt() // to set the state of any bit to '1', // with dynamically allocating class internal buffer SetAt() // to reset the state of any bit to '0' ResetAt() // to xor the state of any bit, with dynamically // allocating class internal buffer if needed XOrAt() // to keep the bits stream in a compressed form // to save memory in cases of larg bitmaps Compress() // to decompress bitmap to its normal state buffer Decompress() All boolean operators can be applied with any two int CBitArray::GetCount() { if(m_nCount == -1) { static BYTE bitCount[256] = { 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, 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, 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, 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, 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, 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, 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, 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 }; BYTE by; m_nCount = 0; for(int nByte = 0; nByte < m_nLength; nByte++) if(by = m_pBuffer[nByte]) m_nCount += bitCount The best thing that is done in this class is the indexing of the one's in the bits array, that is done by indexing all one's locations in the bitmap zero based, and keeping these indices in an array, taking in consideration that if number of '1's exceeds a certain value ( #define SEG_COUNT 10240 void CBitArray::Index() { // (^_^) 21/2/2004 hmh if(GetLength() == 0) return; // calculate number of ones that will be include in each index m_nBitSeg = GetCount()/SEG_COUNT + 1; if(m_nIndexes) free(m_nIndexes); // allocate buffe of the indices array m_nIndexes = (int *)malloc(sizeof(int)*(m_nCount/m_nBitSeg+1)); m_nIndexesCount = m_nCount = 0; BYTE by; // loop in the bitmap buffer to index '1's locations for(int nBit, nByte = 0; nByte < m_nLength; nByte++) // copy buffer byte into by and check if it is not 0 if(by = m_pBuffer[nByte]) { // get bit number by multiply by 8 (or left shift by 3) nBit = nByte<<3; while(by) { // if the first bit in the byte is '1' if(by&1) // check if the bit in the head of the index if(m_nCount++ % m_nBitSeg == 0) // add this bit to the indices m_nIndexes[m_nIndexesCount++] = nBit; // shift right to move second bit to the byte head by >>= 1, nBit++; } } } So, at any time after initializing the bitmap, you can get any '1' index bit, or get any bit index using the functions: int CBitArray::GetIndexBit(int nIndex); int CBitArray::GetBitIndex(int nBit); The previous two functions contain a very complicated code, specially CBitArray and STL bitsetThere are a lot of differences betweenCBitArray and STL bitset:
CBitArray Usage// initialize CBitArray object CBitArray a; // set the bit 4578 in the bit array buffer (at byte 4578/8, at bit 4578%8) a.SetAt(4578); // set the bit 323 in the bit array buffer (at byte 323/8, at bit 323%8) a.SetAt(323); // get the count of '1's int nCount = a.GetCount(); // return 2 // xor bit number 323 a.XOrAt(323); // get the count of '1's nCount = a.GetCount(); // return 1 // initialize CBitArray object CBitArray b; // attach buffer which is allocated with some bytes b.Attach(buffer, length); // AND b with a b &= a; // initialize CBitArray object with the value of b CBitArray c = b; // ... // and so on Source code filesBitArray.cpp, BitArray.h, mem.cpp, mem.h Thanks to...I owe a lot to my colleagues for helping me in implementing and testing this code. (JAK)
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||