home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 10 Tools
/
10-Tools.zip
/
tlx501.zip
/
SRC
/
BITVECT.CPP
< prev
next >
Wrap
C/C++ Source or Header
|
1996-07-08
|
22KB
|
676 lines
/****************************************************************************
$Id: bitvect.cpp 501.0 1995/03/07 12:26:08 RON Exp $
Copyright (c) 1991-95 Tarma Software Research. All rights reserved.
Project: Tarma Library for C++ V5.0
Author: Ron van der Wal
Implementation of class TLBitVector.
$Log: bitvect.cpp $
Revision 501.0 1995/03/07 12:26:08 RON
Updated for TLX 5.01
Revision 1.10 1995/01/31 16:30:04 RON
Update for release 012
Added partial support for SunPro C++ compiler
Revision 1.9 1995/01/06 15:57:26 ron
Corrected Revision keyword
Revision 1.8 1994/11/16 15:36:28 ron
Changed several signed/unsigned conflicts
Added module info; rearranged #include directives
Revision 1.7 1994/10/07 17:00:27 ron
Corrected useless value >> 1 code to value >>= 1
Revision 1.6 1994/10/05 18:34:33 ron
Formatting changes
Revision 1.5 1994/09/28 14:13:42 ron
Removed Macintosh-style #include references
Revision 1.4 1994/09/27 20:22:03 ron
Changed path separator from / to \
Revision 1.3 1994/09/26 15:40:04 ron
Changed from size_t to index_t bit indices
Revision 1.2 1994/09/06 14:10:43 ron
Adapted to changes in tlx.h
Revision 1.1 1994/08/16 18:12:54 ron
Initial revision
****************************************************************************/
#include <tlx\501\_build.h>
TLX_MODULE_INFO("$Revision: 501.0 $");
#include <iostream.h>
#include <stdlib.h> // mem... routines
#include <string.h> // mem... routines
#include <tlx\501\bitvect.h>
#include <tlx\501\except.h>
/*---------------------------------------------------------------------------
Implementation notes:
---------------------
Throughout this file, we assume that:
- kMaxAlloc < kMaxSize (kMaxSize = maximum value of size_t type)
- each TLBitVector allocation will be <= kMaxAlloc
and that therefore:
- max(ByteIndex()) will be strictly less than kMaxSize
- max(ByteIndex()) + 1 is still within the 'size_t' range.
We also use the malloc()/free() family of memory allocators to take
advantage of the realloc() facility; operator new()/delete() do not
have a similar renew().
Layout of bits within vector
----------------------------
The BitVector class allocates a vector of bytes (with CHAR_BIT bits/
byte) to store the individual bits. The position of bits as indexed
with the various BitVector member functions is as follows:
+-----------------------++-----------------------++------
|07 06 05 04 03 02 01 00||15 14 13 12 11 10 09 08||23 22 etc.
+-----------------------++-----------------------++------
BitIndex(bit) 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6
ByteIndex(bit) \----------0-----------/\-----------1-----------/\------
---------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------
Implementation helper functions. Return the byte and bit indices of
a given bit in the vector.
---------------------------------------------------------------------------*/
inline size_t BitIndex(size_t bit) { return bit % CHAR_BIT; }
inline size_t ByteIndex(size_t bit) { return bit / CHAR_BIT; }
/*-------------------------------------------------------------------------*/
TLBitVector::TLBitVector(size_t aLimit)
/* Constructor, also doubles as the default constructor. Creates a
bitvector with the given initial bit size.
---------------------------------------------------------------------------*/
{
mVector = 0;
mBitSize =
mVectSize = 0;
Resize(aLimit);
}
/*-------------------------------------------------------------------------*/
TLBitVector::TLBitVector(const char *aVector)
/* Constructor that takes a C-style string to specify the length and
initial values of the bitvector. The new bitvector has a length
equal to strlen(aVector) and has '1' bits in each position, except
where 'aVector' contains '0' characters.
---------------------------------------------------------------------------*/
{
TLX_ASSERT_PTR(aVector);
mVector = 0;
mBitSize =
mVectSize = 0;
Resize(strlen(aVector));
for (size_t i = 0; i < mBitSize; i++)
if (aVector[i] != '0')
Set(i);
}
/*-------------------------------------------------------------------------*/
TLBitVector::TLBitVector(const TLBitVector &bv)
/* Copy constructor. Allocates its own vector.
---------------------------------------------------------------------------*/
{
mBitSize = bv.mBitSize;
// By definition, sizeof(byte_t) == 1
mVector = (byte_t *) malloc(mVectSize = bv.mVectSize);
if (TLX_CHECK_PTR(mVector))
memcpy(mVector, bv.mVector, mVectSize);
else
mBitSize = mVectSize = 0;
}
/*-------------------------------------------------------------------------*/
TLBitVector::~TLBitVector()
/* Destructor. Deletes allocated vector.
---------------------------------------------------------------------------*/
{
if (mVector) free(mVector);
}
/*-------------------------------------------------------------------------*/
size_t TLBitVector::First() const
/* Returns the index of the first '1' bit in the vector. It is an error
to call this function if the vector is empty.
---------------------------------------------------------------------------*/
{
if (IsEmpty())
THROW(TLXEmpty(LOCUS));
// Search byte-wise for the first non-0 byte
byte_t *bptr = mVector;
for (size_t i = 0; i < mVectSize; i++, bptr++) {
if (*bptr) {
// Found byte; now locate first bit
byte_t value = *bptr;
for (size_t bit = 0; bit < 8; bit++) {
if (value & 1)
return i * CHAR_BIT + bit;
value >>= 1;
}
TLX_ASSERT_UNREACHABLE;
}
}
TLX_ASSERT_UNREACHABLE;
return 0;
}
/*-------------------------------------------------------------------------*/
void TLBitVector::Invert()
/* Inverts all bits in the vector.
---------------------------------------------------------------------------*/
{
byte_t *aPtr = mVector;
for (size_t i = mVectSize; i; i--)
*aPtr++ ^= 0xff;
}
/*-------------------------------------------------------------------------*/
void TLBitVector::Invert(size_t bit)
/* Inverts the given bit.
---------------------------------------------------------------------------*/
{
if (!IsValidIndex(bit))
THROW(TLXIndex(LOCUS, (index_t)bit));
mVector[ByteIndex(bit)] ^= (char)(1 << BitIndex(bit));
}
/*-------------------------------------------------------------------------*/
void TLBitVector::Invert(size_t from, size_t to)
/* Inverts all bits in the given range.
---------------------------------------------------------------------------*/
{
if (!IsValidIndex(from))
THROW(TLXIndex(LOCUS, (index_t)from));
if (!IsValidIndex(to))
THROW(TLXIndex(LOCUS, (index_t)to));
if (from > to) return;
size_t i1 = ByteIndex(from);
size_t i2 = ByteIndex(to);
// Invert all but the first and last bytes
if (i2 > i1 + 1) {
byte_t *aPtr = &mVector[i1 + 1];
for (size_t i = i2 - i1 - 1; i; i--)
*aPtr++ ^= 0xff;
}
char lowPattern = (char)(0xff << BitIndex(from));
char highPattern = (char)(0xff >> (CHAR_BIT - BitIndex(to) - 1));
// Invert the first and the last byte(s)
if (i1 == i2)
mVector[i1] ^= (lowPattern & highPattern);
else {
mVector[i1] ^= lowPattern;
mVector[i2] ^= highPattern;
}
}
/*-------------------------------------------------------------------------*/
bool TLBitVector::IsEmpty() const
/* Checks whether the bitvector is empty, i.e. contains no '1' bits.
---------------------------------------------------------------------------*/
{
return Test() == 0;
}
/*-------------------------------------------------------------------------*/
bool TLBitVector::IsValidIndex(size_t aIndex) const
/* Tests whether the given bit index is valid for the bitvector. Returns
nonzero if it is, else zero.
---------------------------------------------------------------------------*/
{
return aIndex < mBitSize;
}
/*-------------------------------------------------------------------------*/
size_t TLBitVector::Last() const
/* Returns the index of the last '1' bit in the vector. It is an error
to call this function if the vector is empty.
---------------------------------------------------------------------------*/
{
if (IsEmpty())
THROW(TLXEmpty(LOCUS));
// Search byte-wise for the last non-0 byte
TLX_ASSERT(mVectSize > 0);
byte_t *bptr = &mVector[mVectSize - 1];
for (size_t i = mVectSize; i; i--, bptr--) {
if (*bptr) {
// Found byte; now locate last bit
byte_t value = *bptr;
for (size_t bit = 0; bit < 8; bit++) {
if (value & 0x80) {
TLX_ASSERT(i > 0);
return (i - 1) * CHAR_BIT + (7 - bit);
}
value <<= 1;
}
TLX_ASSERT_UNREACHABLE;
}
}
TLX_ASSERT_UNREACHABLE;
return 0;
}
/*-------------------------------------------------------------------------*/
TLBitVector &TLBitVector::operator =(const TLBitVector &bv)
/* Overloading of asignment operator to create a new copy of the actual
vector.
---------------------------------------------------------------------------*/
{
if (this != &bv) { // Check for assignment to self
if (mBitSize != bv.mBitSize)
Resize(bv.mBitSize);
memcpy(mVector, bv.mVector, mVectSize);
}
return *this;
}
/*-------------------------------------------------------------------------*/
TLBitVector &TLBitVector::operator &=(const TLBitVector &bv)
/* Performs bitwise AND on the current vector and its argument.
---------------------------------------------------------------------------*/
{
size_t size = tlMin(mVectSize, bv.mVectSize);
// Perform 'and' on the common part
for (size_t i = 0; i < size; i++)
mVector[i] &= bv.mVector[i];
// If the current vector is larger than the other one, set the remaining
// bits to 0 as if the other vector were extended with '0' bits.
if (size < mVectSize)
memset(&mVector[size], 0, mVectSize - size);
return *this;
}
/*-------------------------------------------------------------------------*/
TLBitVector &TLBitVector::operator ^=(const TLBitVector &bv)
/* Performs bitwise XOR on the current vector and its argument.
---------------------------------------------------------------------------*/
{
size_t size = tlMin(mVectSize, bv.mVectSize);
for (size_t i = 0; i < size; i++)
mVector[i] ^= bv.mVector[i];
return *this;
}
/*-------------------------------------------------------------------------*/
TLBitVector &TLBitVector::operator |=(const TLBitVector &bv)
/* Performs bitwise OR on the current vector and its argument.
---------------------------------------------------------------------------*/
{
size_t size = tlMin(mVectSize, bv.mVectSize);
for (size_t i = 0; i < size; i++)
mVector[i] |= bv.mVector[i];
return *this;
}
/*-------------------------------------------------------------------------*/
void TLBitVector::Reset()
/* Sets all bits to 0.
---------------------------------------------------------------------------*/
{
memset(mVector, 0, mVectSize);
}
/*-------------------------------------------------------------------------*/
void TLBitVector::Reset(size_t bit)
/* Sets a single bit to 0.
---------------------------------------------------------------------------*/
{
if (!IsValidIndex(bit))
THROW(TLXIndex(LOCUS, (index_t)bit));
mVector[ByteIndex(bit)] &= (byte_t)(~(1U << BitIndex(bit)));
}
/*-------------------------------------------------------------------------*/
void TLBitVector::Reset(size_t from, size_t to)
/* Sets all bits in a range to 0.
---------------------------------------------------------------------------*/
{
if (!IsValidIndex(from))
THROW(TLXIndex(LOCUS, (index_t)from));
if (!IsValidIndex(to))
THROW(TLXIndex(LOCUS, (index_t)to));
if (from > to) return;
size_t i1 = ByteIndex(from);
size_t i2 = ByteIndex(to);
// Clear ranges of bytes (if any)
if (i2 > i1 + 1) memset(&mVector[i1 + 1], 0, i2 - i1 - 1);
// Clear remaining bits at the low and high ends
char lowPattern = (char)(0xff << BitIndex(from));
char highPattern = (char)(0xff >> (CHAR_BIT - BitIndex(to) - 1));
if (i1 == i2)
mVector[i1] &= (lowPattern | highPattern);
else {
mVector[i1] &= lowPattern;
mVector[i2] &= highPattern;
}
}
/*-------------------------------------------------------------------------*/
void TLBitVector::Resize(size_t aBitSize)
/* Changes the bit size of the vector. This might involve resizing the
underlying byte vector.
---------------------------------------------------------------------------*/
{
if (aBitSize == mBitSize) return;
// Round size up to next multiple of CHAR_BIT
size_t newVectSize = (aBitSize + CHAR_BIT - 1) / CHAR_BIT;
// According to our assumptions (see Implementation Note above), it
// should not be possible for the new byte vector size to be larger
// than the maximum allocation size... But we'll check nevertheless.
TLX_ASSERT(newVectSize <= kMaxAlloc);
if (newVectSize == mVectSize) {
// Byte vector is the right size; just resize the bit vector and
// clear out the new bits in the last byte of the byte vector.
if (aBitSize > mBitSize) {
TLX_ASSERT(ByteIndex(aBitSize-1) == ByteIndex(mBitSize-1));
mVector[ByteIndex(mBitSize-1)] &=
(char)(0xff >> (CHAR_BIT - BitIndex(mBitSize-1) - 1));
} else {
mVector[ByteIndex(aBitSize-1)] &=
(char)(0xff >> (CHAR_BIT - BitIndex(aBitSize-1) - 1));
}
mBitSize = aBitSize;
} else {
// We need to resize the byte vector before we resize the bit vector.
// We take advantage of the following behavior of realloc():
//
// - if the original pointer was 0, it works like malloc()
// - if the new size is 0, it works like free()
byte_t *tmp = (byte_t *) realloc(mVector, newVectSize);
if (tmp == 0 && newVectSize > 0)
THROW(TLXAlloc(LOCUS, newVectSize));
// Vector resized; clear out new bytes and the last bits in
// the newly created copy. If the new vector is larger than
// the old vector, we clear everything from the previous bit
// size upwards; else (new vector smaller) we clear from the
// new bit size onwards. In the latter case, we only have to
// clear out the last byte of the new vector.
if (newVectSize > mVectSize) {
memset(&tmp[mVectSize], 0, newVectSize - mVectSize);
tmp[ByteIndex(mBitSize-1)] &=
(char)(0xff >> (CHAR_BIT - BitIndex(mBitSize-1) - 1));
} else {
// New vector is smaller
tmp[ByteIndex(aBitSize-1)] &=
(char)(0xff >> (CHAR_BIT - BitIndex(aBitSize-1) - 1));
}
mVector = tmp; // It may have moved
mVectSize = newVectSize;
mBitSize = aBitSize;
}
}
/*-------------------------------------------------------------------------*/
void TLBitVector::Set()
/* Sets all bits to 1.
---------------------------------------------------------------------------*/
{
memset(mVector, 0xff, mVectSize);
if (mVectSize * CHAR_BIT > mBitSize) {
mVector[ByteIndex(mBitSize-1)] &=
(char)(0xff >> (CHAR_BIT - BitIndex(mBitSize-1) - 1));
}
}
/*-------------------------------------------------------------------------*/
void TLBitVector::Set(size_t bit)
/* Sets a single bit to 1.
---------------------------------------------------------------------------*/
{
if (!IsValidIndex(bit))
THROW(TLXIndex(LOCUS, (index_t)bit));
mVector[ByteIndex(bit)] |= (char)(1 << BitIndex(bit));
}
/*-------------------------------------------------------------------------*/
void TLBitVector::Set(size_t from, size_t to)
/* Sets all bits in a range to 1.
---------------------------------------------------------------------------*/
{
if (!IsValidIndex(from))
THROW(TLXIndex(LOCUS, (index_t)from));
if (!IsValidIndex(to))
THROW(TLXIndex(LOCUS, (index_t)to));
if (from > to) return;
size_t i1 = ByteIndex(from);
size_t i2 = ByteIndex(to);
if (i2 > i1 + 1)
memset(&mVector[i1 + 1], 0xff, i2 - i1 - 1);
char lowPattern = (char)(0xff << BitIndex(from));
char highPattern = (char)(0xff >> (CHAR_BIT - BitIndex(to) - 1));
if (i1 == i2)
mVector[i1] |= (lowPattern & highPattern);
else {
mVector[i1] |= lowPattern;
mVector[i2] |= highPattern;
}
}
/*---------------------------------------------------------------------------
Helper function that counts bits in a byte by counting the bits in its
nibbles.
---------------------------------------------------------------------------*/
static size_t bit_table[16] = { 0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4 };
inline size_t bit_count(byte_t b)
{ return bit_table[b & 0xf] + bit_table[(b & 0xf0) >> 4]; }
/*-------------------------------------------------------------------------*/
size_t TLBitVector::Test() const
/* Returns number of bits set in the vector.
---------------------------------------------------------------------------*/
{
size_t cnt = 0;
byte_t *aPtr = mVector;
for (size_t aTop = mVectSize; aTop; aTop--, aPtr++)
cnt += bit_count(*aPtr);
return cnt;
}
/*-------------------------------------------------------------------------*/
size_t TLBitVector::Test(size_t bit) const
/* Returns 1 if bit is set, else 0.
---------------------------------------------------------------------------*/
{
if (!IsValidIndex(bit))
THROW(TLXIndex(LOCUS, (index_t)bit));
return (mVector[ByteIndex(bit)] & (1 << BitIndex(bit))) != 0;
}
/*-------------------------------------------------------------------------*/
size_t TLBitVector::Test(size_t from, size_t to) const
/* Returns number of bits set in a range.
---------------------------------------------------------------------------*/
{
if (!IsValidIndex(from))
THROW(TLXIndex(LOCUS, (index_t)from));
if (!IsValidIndex(to))
THROW(TLXIndex(LOCUS, (index_t)to));
if (from > to) return 0;
size_t i1 = ByteIndex(from);
size_t i2 = ByteIndex(to);
size_t cnt = 0;
if (i2 > i1 + 1) {
byte_t *aPtr = &mVector[i1 + 1];
for (size_t i = i2 - i1 - 1; i; i--)
cnt += bit_count(*aPtr);
}
byte_t lowPattern = (byte_t)(0xff << BitIndex(from));
byte_t highPattern = (byte_t)(0xff >> (CHAR_BIT - 1 - BitIndex(to)));
if (i1 == i2)
cnt += bit_count(mVector[i1] & (lowPattern | highPattern));
else {
cnt += bit_count(mVector[i1] & lowPattern);
cnt += bit_count(mVector[i2] & highPattern);
}
return cnt;
}
/*-------------------------------------------------------------------------*/
TLBitVector _TLXFUNC operator ~(const TLBitVector &bv)
/* Creates inverse of bit vector.
---------------------------------------------------------------------------*/
{
TLBitVector result = bv;
result.Invert();
return result;
}
/*-------------------------------------------------------------------------*/
TLBitVector _TLXFUNC operator &(
const TLBitVector &bv1,
const TLBitVector &bv2
)
/* Creates bitwise AND of both vectors.
---------------------------------------------------------------------------*/
{
TLBitVector result = bv1;
return result &= bv2;
}
/*-------------------------------------------------------------------------*/
TLBitVector _TLXFUNC operator ^(
const TLBitVector &bv1,
const TLBitVector &bv2
)
/* Creates bitwise XOR of both vectors.
---------------------------------------------------------------------------*/
{
TLBitVector result = bv1;
return result ^= bv2;
}
/*-------------------------------------------------------------------------*/
TLBitVector _TLXFUNC operator |(
const TLBitVector &bv1,
const TLBitVector &bv2
)
/* Creates bitwise or of both vectors.
---------------------------------------------------------------------------*/
{
TLBitVector result = bv1;
return result |= bv2;
}
/*-------------------------------------------------------------------------*/
bool _TLXFUNC operator ==(const TLBitVector &bv1, const TLBitVector &bv2)
/* Compares BitVectors bitwise, returning one of the following values:
< 0 if the first one is less than the second one
0 if they are equal
> 0 if the first one is greater than the second one
---------------------------------------------------------------------------*/
{
return bv1.mVectSize == bv2.mVectSize &&
memcmp(bv1.mVector, bv2.mVector, bv1.mVectSize) == 0;
}
/*-------------------------------------------------------------------------*/
ostream & _TLXFUNC operator <<(ostream &os, const TLBitVector &bv)
/* Overloading of the stream output operator for bitvectors. The bits are
printed from index 0 to Size() - 1.
---------------------------------------------------------------------------*/
{
for (size_t i = 0; i < bv.mBitSize; i++)
os << bv.Test(i);
return os;
}