BitSet implementation added
This commit is contained in:
@@ -9,6 +9,12 @@ INC += serialize.h
|
||||
INC += bitSet.h
|
||||
INC += byteBuffer.h
|
||||
|
||||
LIBSRCS += bitSet.cpp
|
||||
|
||||
LIBRARY=pvMisc
|
||||
|
||||
pvMisc_LIBS += Com
|
||||
|
||||
include $(TOP)/configure/RULES
|
||||
#----------------------------------------
|
||||
# ADD RULES AFTER THIS LINE
|
||||
|
||||
@@ -0,0 +1,373 @@
|
||||
#include "bitSet.h"
|
||||
|
||||
namespace epics { namespace pvData {
|
||||
|
||||
BitSet::BitSet() : words(0), wordsLength(0), wordsInUse(0) {
|
||||
initWords(BITS_PER_WORD);
|
||||
}
|
||||
|
||||
BitSet::BitSet(epicsUInt32 nbits) : words(0), wordsLength(0), wordsInUse(0) {
|
||||
initWords(nbits);
|
||||
}
|
||||
|
||||
BitSet::~BitSet() {
|
||||
delete words;
|
||||
}
|
||||
|
||||
void BitSet::initWords(epicsUInt32 nbits) {
|
||||
epicsUInt32 length = (nbits <= 0) ? 1 : wordIndex(nbits-1) + 1;
|
||||
if (words) delete words;
|
||||
words = new epicsUInt64[length];
|
||||
bzero(words, sizeof(epicsUInt64)*length);
|
||||
wordsLength = length;
|
||||
}
|
||||
|
||||
void BitSet::recalculateWordsInUse() {
|
||||
// wordsInUse is unsigned
|
||||
if (wordsInUse == 0)
|
||||
return;
|
||||
|
||||
// Traverse the bitset until a used word is found
|
||||
epicsUInt32 i;
|
||||
for (i = wordsInUse-1; i >= 0; i--)
|
||||
if (words[i] != 0)
|
||||
break;
|
||||
|
||||
wordsInUse = i+1; // The new logical size
|
||||
}
|
||||
|
||||
void BitSet::ensureCapacity(epicsUInt32 wordsRequired) {
|
||||
if (wordsLength < wordsRequired) {
|
||||
|
||||
// create and copy
|
||||
epicsUInt64* newwords = new epicsUInt64[wordsRequired];
|
||||
bzero(newwords, sizeof(epicsUInt64)*wordsRequired);
|
||||
memcpy(newwords, words, sizeof(epicsUInt64)*wordsLength);
|
||||
if (words) delete words;
|
||||
words = newwords;
|
||||
wordsLength = wordsRequired;
|
||||
}
|
||||
}
|
||||
|
||||
void BitSet::expandTo(epicsUInt32 wordIndex) {
|
||||
epicsUInt32 wordsRequired = wordIndex+1;
|
||||
if (wordsInUse < wordsRequired) {
|
||||
ensureCapacity(wordsRequired);
|
||||
wordsInUse = wordsRequired;
|
||||
}
|
||||
}
|
||||
|
||||
void BitSet::flip(epicsUInt32 bitIndex) {
|
||||
|
||||
epicsUInt32 wordIdx = wordIndex(bitIndex);
|
||||
expandTo(wordIdx);
|
||||
|
||||
words[wordIdx] ^= (((epicsUInt64)1) << (bitIndex % BITS_PER_WORD));
|
||||
|
||||
recalculateWordsInUse();
|
||||
}
|
||||
|
||||
void BitSet::set(epicsUInt32 bitIndex) {
|
||||
|
||||
epicsUInt32 wordIdx = wordIndex(bitIndex);
|
||||
expandTo(wordIdx);
|
||||
|
||||
words[wordIdx] |= (((epicsUInt64)1) << (bitIndex % BITS_PER_WORD));
|
||||
}
|
||||
|
||||
void BitSet::clear(epicsUInt32 bitIndex) {
|
||||
|
||||
epicsUInt32 wordIdx = wordIndex(bitIndex);
|
||||
if (wordIdx >= wordsInUse)
|
||||
return;
|
||||
|
||||
words[wordIdx] &= ~(((epicsUInt64)1) << (bitIndex % BITS_PER_WORD));
|
||||
|
||||
recalculateWordsInUse();
|
||||
}
|
||||
|
||||
void BitSet::set(epicsUInt32 bitIndex, bool value) {
|
||||
if (value)
|
||||
set(bitIndex);
|
||||
else
|
||||
clear(bitIndex);
|
||||
}
|
||||
|
||||
bool BitSet::get(epicsUInt32 bitIndex) const {
|
||||
epicsUInt32 wordIdx = wordIndex(bitIndex);
|
||||
return ((wordIdx < wordsInUse)
|
||||
&& ((words[wordIdx] & (((epicsUInt64)1) << (bitIndex % BITS_PER_WORD))) != 0));
|
||||
}
|
||||
|
||||
void BitSet::clear() {
|
||||
while (wordsInUse > 0)
|
||||
words[--wordsInUse] = 0;
|
||||
}
|
||||
|
||||
epicsUInt32 BitSet::numberOfTrailingZeros(epicsUInt64 i) {
|
||||
// HD, Figure 5-14
|
||||
epicsUInt32 x, y;
|
||||
if (i == 0) return 64;
|
||||
epicsUInt32 n = 63;
|
||||
y = (epicsUInt32)i; if (y != 0) { n = n -32; x = y; } else x = (epicsUInt32)(i>>32);
|
||||
y = x <<16; if (y != 0) { n = n -16; x = y; }
|
||||
y = x << 8; if (y != 0) { n = n - 8; x = y; }
|
||||
y = x << 4; if (y != 0) { n = n - 4; x = y; }
|
||||
y = x << 2; if (y != 0) { n = n - 2; x = y; }
|
||||
return n - ((x << 1) >> 31);
|
||||
}
|
||||
|
||||
epicsUInt32 BitSet::bitCount(epicsUInt64 i) {
|
||||
// HD, Figure 5-14
|
||||
i = i - ((i >> 1) & 0x5555555555555555LL);
|
||||
i = (i & 0x3333333333333333LL) + ((i >> 2) & 0x3333333333333333LL);
|
||||
i = (i + (i >> 4)) & 0x0f0f0f0f0f0f0f0fLL;
|
||||
i = i + (i >> 8);
|
||||
i = i + (i >> 16);
|
||||
i = i + (i >> 32);
|
||||
return (epicsUInt32)(i & 0x7f);
|
||||
}
|
||||
|
||||
epicsInt32 BitSet::nextSetBit(epicsUInt32 fromIndex) const {
|
||||
|
||||
epicsUInt32 u = wordIndex(fromIndex);
|
||||
if (u >= wordsInUse)
|
||||
return -1;
|
||||
|
||||
epicsUInt64 word = words[u] & (WORD_MASK << (fromIndex % BITS_PER_WORD));
|
||||
|
||||
while (true) {
|
||||
if (word != 0)
|
||||
return (u * BITS_PER_WORD) + numberOfTrailingZeros(word);
|
||||
if (++u == wordsInUse)
|
||||
return -1;
|
||||
word = words[u];
|
||||
}
|
||||
}
|
||||
|
||||
epicsInt32 BitSet::nextClearBit(epicsUInt32 fromIndex) const {
|
||||
// Neither spec nor implementation handle bitsets of maximal length.
|
||||
|
||||
epicsUInt32 u = wordIndex(fromIndex);
|
||||
if (u >= wordsInUse)
|
||||
return fromIndex;
|
||||
|
||||
epicsUInt64 word = ~words[u] & (WORD_MASK << (fromIndex % BITS_PER_WORD));
|
||||
|
||||
while (true) {
|
||||
if (word != 0)
|
||||
return (u * BITS_PER_WORD) + numberOfTrailingZeros(word);
|
||||
if (++u == wordsInUse)
|
||||
return wordsInUse * BITS_PER_WORD;
|
||||
word = ~words[u];
|
||||
}
|
||||
}
|
||||
|
||||
bool BitSet::isEmpty() const {
|
||||
return (wordsInUse == 0);
|
||||
}
|
||||
|
||||
epicsUInt32 BitSet::cardinality() const {
|
||||
epicsUInt32 sum = 0;
|
||||
for (epicsUInt32 i = 0; i < wordsInUse; i++)
|
||||
sum += bitCount(words[i]);
|
||||
return sum;
|
||||
}
|
||||
|
||||
BitSet& BitSet::operator&=(const BitSet& set) {
|
||||
|
||||
while (wordsInUse > set.wordsInUse)
|
||||
words[--wordsInUse] = 0;
|
||||
|
||||
// Perform logical AND on words in common
|
||||
for (epicsUInt32 i = 0; i < wordsInUse; i++)
|
||||
words[i] &= set.words[i];
|
||||
|
||||
recalculateWordsInUse();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
BitSet& BitSet::operator|=(const BitSet& set) {
|
||||
|
||||
epicsUInt32 wordsInCommon;
|
||||
if (wordsInUse < set.wordsInUse) {
|
||||
wordsInCommon = wordsInUse;
|
||||
//ensureCapacity(set.wordsInUse);
|
||||
//wordsInUse = set.wordsInUse;
|
||||
}
|
||||
else
|
||||
wordsInCommon = set.wordsInUse;
|
||||
|
||||
// Perform logical OR on words in common
|
||||
epicsUInt32 i = 0;
|
||||
for (; i < wordsInCommon; i++)
|
||||
words[i] |= set.words[i];
|
||||
|
||||
// TODO what to do if BitSets are not the same size !!!
|
||||
|
||||
// recalculateWordsInUse() is not needed
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
BitSet& BitSet::operator^=(const BitSet& set) {
|
||||
|
||||
epicsUInt32 wordsInCommon;
|
||||
if (wordsInUse < set.wordsInUse) {
|
||||
wordsInCommon = wordsInUse;
|
||||
//ensureCapacity(set.wordsInUse);
|
||||
//wordsInUse = set.wordsInUse;
|
||||
}
|
||||
else
|
||||
wordsInCommon = set.wordsInUse;
|
||||
|
||||
// Perform logical XOR on words in common
|
||||
epicsUInt32 i = 0;
|
||||
for (; i < wordsInCommon; i++)
|
||||
words[i] ^= set.words[i];
|
||||
|
||||
// TODO what to do if BitSets are not the same size !!!
|
||||
|
||||
recalculateWordsInUse();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
BitSet& BitSet::operator-=(const BitSet& set) {
|
||||
|
||||
epicsUInt32 wordsInCommon;
|
||||
if (wordsInUse < set.wordsInUse) {
|
||||
wordsInCommon = wordsInUse;
|
||||
//ensureCapacity(set.wordsInUse);
|
||||
//wordsInUse = set.wordsInUse;
|
||||
}
|
||||
else
|
||||
wordsInCommon = set.wordsInUse;
|
||||
|
||||
// Perform logical (a & !b) on words in common
|
||||
epicsUInt32 i = 0;
|
||||
for (; i < wordsInCommon; i++)
|
||||
words[i] &= ~set.words[i];
|
||||
|
||||
recalculateWordsInUse();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
BitSet& BitSet::operator=(const BitSet &set) {
|
||||
// Check for self-assignment!
|
||||
if (this == &set)
|
||||
return *this;
|
||||
|
||||
// we ensure that words array size is adequate (and not wordsInUse to ensure capacity to the future)
|
||||
if (wordsLength < set.wordsLength)
|
||||
{
|
||||
if (words) delete words;
|
||||
words = new epicsUInt64[set.wordsLength];
|
||||
wordsLength = set.wordsLength;
|
||||
}
|
||||
memcpy(words, set.words, sizeof(epicsUInt64)*set.wordsInUse);
|
||||
wordsInUse = set.wordsInUse;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
void BitSet::or_and(const BitSet& set1, const BitSet& set2) {
|
||||
epicsUInt32 inUse = (set1.wordsInUse < set2.wordsInUse) ? set1.wordsInUse : set2.wordsInUse;
|
||||
|
||||
ensureCapacity(inUse);
|
||||
wordsInUse = inUse;
|
||||
|
||||
// Perform logical AND on words in common
|
||||
for (epicsUInt32 i = 0; i < inUse; i++)
|
||||
words[i] |= (set1.words[i] & set2.words[i]);
|
||||
|
||||
// recalculateWordsInUse()...
|
||||
}
|
||||
|
||||
bool BitSet::operator==(const BitSet &set) const
|
||||
{
|
||||
if (this == &set)
|
||||
return true;
|
||||
|
||||
if (wordsInUse != set.wordsInUse)
|
||||
return false;
|
||||
|
||||
// Check words in use by both BitSets
|
||||
for (epicsUInt32 i = 0; i < wordsInUse; i++)
|
||||
if (words[i] != set.words[i])
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void BitSet::toString(StringBuilder buffer) { toString(buffer, 0); }
|
||||
|
||||
void BitSet::toString(StringBuilder buffer, int indentLevel) const
|
||||
{
|
||||
*buffer += '{';
|
||||
epicsInt32 i = nextSetBit(0);
|
||||
char tmp[30];
|
||||
if (i != -1) {
|
||||
sprintf(tmp,"%d",i); *buffer += tmp;
|
||||
for (i = nextSetBit(i+1); i >= 0; i = nextSetBit(i+1)) {
|
||||
epicsInt32 endOfRun = nextClearBit(i);
|
||||
do { *buffer += ", "; sprintf(tmp,"%d",i); *buffer += tmp; } while (++i < endOfRun);
|
||||
}
|
||||
}
|
||||
*buffer += '}';
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
|
||||
void serialize(ByteBuffer buffer, SerializableControl flusher) {
|
||||
|
||||
final int n = wordsInUse;
|
||||
if (n == 0) {
|
||||
SerializeHelper.writeSize(0, buffer, flusher);
|
||||
return;
|
||||
}
|
||||
int len = 8 * (n-1);
|
||||
for (long x = words[n - 1]; x != 0; x >>>= 8)
|
||||
len++;
|
||||
|
||||
SerializeHelper.writeSize(len, buffer, flusher);
|
||||
flusher.ensureBuffer(len);
|
||||
|
||||
for (int i = 0; i < n - 1; i++)
|
||||
buffer.putLong(words[i]);
|
||||
|
||||
for (long x = words[n - 1]; x != 0; x >>>= 8)
|
||||
buffer.put((byte) (x & 0xff));
|
||||
}
|
||||
|
||||
public void deserialize(ByteBuffer buffer, DeserializableControl control) {
|
||||
|
||||
final int bytes = SerializeHelper.readSize(buffer, control); // in bytes
|
||||
|
||||
wordsInUse = (bytes + 7) / 8;
|
||||
if (wordsInUse > words.length)
|
||||
words = new long[wordsInUse];
|
||||
|
||||
if (wordsInUse == 0)
|
||||
return;
|
||||
|
||||
control.ensureData(bytes);
|
||||
|
||||
int i = 0;
|
||||
final int longs = bytes / 8;
|
||||
while (i < longs)
|
||||
words[i++] = buffer.getLong();
|
||||
|
||||
for (int j = i; j < wordsInUse; j++)
|
||||
words[j] = 0;
|
||||
|
||||
for (int remaining = (bytes - longs * 8), j = 0; j < remaining; j++)
|
||||
words[i] |= (buffer.get() & 0xffL) << (8 * j);
|
||||
|
||||
}
|
||||
*/
|
||||
|
||||
}};
|
||||
+299
-2
@@ -1,10 +1,307 @@
|
||||
/* bitSet.h */
|
||||
#ifndef BITSET_H
|
||||
#define BITSET_H
|
||||
#include <stdexcept>
|
||||
#include <epicsTypes.h>
|
||||
//#include "byteBuffer.h"
|
||||
//#include "serialize.h"
|
||||
namespace epics { namespace pvData {
|
||||
|
||||
class BitSet;
|
||||
// must be defined and implemented
|
||||
// TODO !!!
|
||||
typedef unsigned long long epicsUInt64;
|
||||
typedef std::string * StringBuilder;
|
||||
|
||||
/**
|
||||
* This class implements a vector of bits that grows as needed. Each
|
||||
* component of the bit set has a {@code bool} value. The
|
||||
* bits of a {@code BitSet} are indexed by nonnegative integers.
|
||||
* Individual indexed bits can be examined, set, or cleared. One
|
||||
* {@code BitSet} may be used to modify the contents of another
|
||||
* {@code BitSet} through logical AND, logical inclusive OR, and
|
||||
* logical exclusive OR operations.
|
||||
*
|
||||
* <p>By default, all bits in the set initially have the value
|
||||
* {@code false}.
|
||||
*
|
||||
* <p>Every bit set has a current size, which is the number of bits
|
||||
* of space currently in use by the bit set. Note that the size is
|
||||
* related to the implementation of a bit set, so it may change with
|
||||
* implementation. The length of a bit set relates to logical length
|
||||
* of a bit set and is defined independently of implementation.
|
||||
*
|
||||
* <p>A {@code BitSet} is not safe for multithreaded use without
|
||||
* external synchronization.
|
||||
*
|
||||
* Based on Java implementation.
|
||||
*/
|
||||
class BitSet /*: public Serializable*/ {
|
||||
public:
|
||||
|
||||
/**
|
||||
* Creates a new bit set. All bits are initially {@code false}.
|
||||
*/
|
||||
BitSet();
|
||||
|
||||
/**
|
||||
* Creates a bit set whose initial size is large enough to explicitly
|
||||
* represent bits with indices in the range {@code 0} through
|
||||
* {@code nbits-1}. All bits are initially {@code false}.
|
||||
*
|
||||
* @param nbits the initial size of the bit set
|
||||
*/
|
||||
BitSet(epicsUInt32 nbits);
|
||||
|
||||
/**
|
||||
* Destructor.
|
||||
*/
|
||||
virtual ~BitSet();
|
||||
|
||||
/**
|
||||
* Sets the bit at the specified index to the complement of its
|
||||
* current value.
|
||||
*
|
||||
* @param bitIndex the index of the bit to flip
|
||||
*/
|
||||
void flip(epicsUInt32 bitIndex);
|
||||
|
||||
/**
|
||||
* Sets the bit at the specified index to {@code true}.
|
||||
*
|
||||
* @param bitIndex a bit index
|
||||
*/
|
||||
void set(epicsUInt32 bitIndex);
|
||||
|
||||
/**
|
||||
* Sets the bit specified by the index to {@code false}.
|
||||
*
|
||||
* @param bitIndex the index of the bit to be cleared
|
||||
*/
|
||||
void clear(epicsUInt32 bitIndex);
|
||||
|
||||
/**
|
||||
* Sets the bit at the specified index to the specified value.
|
||||
*
|
||||
* @param bitIndex a bit index
|
||||
* @param value a boolean value to set
|
||||
*/
|
||||
void set(epicsUInt32 bitIndex, bool value);
|
||||
|
||||
/**
|
||||
* Returns the value of the bit with the specified index. The value
|
||||
* is {@code true} if the bit with the index {@code bitIndex}
|
||||
* is currently set in this {@code BitSet}; otherwise, the result
|
||||
* is {@code false}.
|
||||
*
|
||||
* @param bitIndex the bit index
|
||||
* @return the value of the bit with the specified index
|
||||
*/
|
||||
bool get(epicsUInt32 bitIndex) const;
|
||||
|
||||
/**
|
||||
* Sets all of the bits in this BitSet to {@code false}.
|
||||
*/
|
||||
void clear();
|
||||
|
||||
/**
|
||||
* Returns the index of the first bit that is set to {@code true}
|
||||
* that occurs on or after the specified starting index. If no such
|
||||
* bit exists then {@code -1} is returned.
|
||||
*
|
||||
* <p>To iterate over the {@code true} bits in a {@code BitSet},
|
||||
* use the following loop:
|
||||
*
|
||||
* <pre> {@code
|
||||
* for (int i = bs.nextSetBit(0); i >= 0; i = bs.nextSetBit(i+1)) {
|
||||
* // operate on index i here
|
||||
* }}</pre>
|
||||
*
|
||||
* @param fromIndex the index to start checking from (inclusive)
|
||||
* @return the index of the next set bit, or {@code -1} if there
|
||||
* is no such bit
|
||||
*/
|
||||
epicsInt32 nextSetBit(epicsUInt32 fromIndex) const;
|
||||
|
||||
/**
|
||||
* Returns the index of the first bit that is set to {@code false}
|
||||
* that occurs on or after the specified starting index.
|
||||
*
|
||||
* @param fromIndex the index to start checking from (inclusive)
|
||||
* @return the index of the next clear bit
|
||||
*/
|
||||
epicsInt32 nextClearBit(epicsUInt32 fromIndex) const;
|
||||
|
||||
/**
|
||||
* Returns true if this {@code BitSet} contains no bits that are set
|
||||
* to {@code true}.
|
||||
*
|
||||
* @return indicating whether this {@code BitSet} is empty
|
||||
*/
|
||||
bool isEmpty() const;
|
||||
|
||||
/**
|
||||
* Returns the number of bits set to {@code true} in this {@code BitSet}.
|
||||
*
|
||||
* @return the number of bits set to {@code true} in this {@code BitSet}
|
||||
*/
|
||||
epicsUInt32 cardinality() const;
|
||||
|
||||
/**
|
||||
* Performs a logical <b>AND</b> of this target bit set with the
|
||||
* argument bit set. This bit set is modified so that each bit in it
|
||||
* has the value {@code true} if and only if it both initially
|
||||
* had the value {@code true} and the corresponding bit in the
|
||||
* bit set argument also had the value {@code true}.
|
||||
*
|
||||
* @param set a bit set
|
||||
*/
|
||||
BitSet& operator&=(const BitSet& set);
|
||||
|
||||
/**
|
||||
* Performs a logical <b>OR</b> of this bit set with the bit set
|
||||
* argument. This bit set is modified so that a bit in it has the
|
||||
* value {@code true} if and only if it either already had the
|
||||
* value {@code true} or the corresponding bit in the bit set
|
||||
* argument has the value {@code true}.
|
||||
*
|
||||
* @param set a bit set
|
||||
*/
|
||||
BitSet& operator|=(const BitSet& set);
|
||||
|
||||
/**
|
||||
* Performs a logical <b>XOR</b> of this bit set with the bit set
|
||||
* argument. This bit set is modified so that a bit in it has the
|
||||
* value {@code true} if and only if one of the following
|
||||
* statements holds:
|
||||
* <ul>
|
||||
* <li>The bit initially has the value {@code true}, and the
|
||||
* corresponding bit in the argument has the value {@code false}.
|
||||
* <li>The bit initially has the value {@code false}, and the
|
||||
* corresponding bit in the argument has the value {@code true}.
|
||||
* </ul>
|
||||
*
|
||||
* @param set a bit set
|
||||
*/
|
||||
BitSet& operator^=(const BitSet& set);
|
||||
|
||||
/**
|
||||
* Clears all of the bits in this {@code BitSet} whose corresponding
|
||||
* bit is set in the specified {@code BitSet}.
|
||||
*
|
||||
* @param set the {@code BitSet} with which to mask this
|
||||
* {@code BitSet}
|
||||
*/
|
||||
BitSet& operator-=(const BitSet& set);
|
||||
|
||||
/**
|
||||
* Assigment operator.
|
||||
*/
|
||||
BitSet& operator=(const BitSet &set);
|
||||
|
||||
/**
|
||||
* Perform AND operation on <code>set1</code> and <code>set2</code>,
|
||||
* and OR on result and this instance.
|
||||
* @param set1
|
||||
* @param set2
|
||||
*/
|
||||
void or_and(const BitSet& set1, const BitSet& set2);
|
||||
|
||||
/**
|
||||
* Comparison operator.
|
||||
*/
|
||||
bool operator==(const BitSet &set) const;
|
||||
|
||||
void toString(StringBuilder buffer);
|
||||
|
||||
void toString(StringBuilder buffer, int indentLevel) const;
|
||||
|
||||
private:
|
||||
|
||||
/*
|
||||
* BitSets are packed into arrays of "words." Currently a word is
|
||||
* a long, which consists of 64 bits, requiring 6 address bits.
|
||||
* The choice of word size is determined purely by performance concerns.
|
||||
*/
|
||||
static const epicsUInt32 ADDRESS_BITS_PER_WORD = 6;
|
||||
static const epicsUInt32 BITS_PER_WORD = 1 << ADDRESS_BITS_PER_WORD;
|
||||
static const epicsUInt32 BIT_INDEX_MASK = BITS_PER_WORD - 1;
|
||||
|
||||
/** Used to shift left or right for a partial word mask */
|
||||
static const epicsUInt64 WORD_MASK = ~((epicsUInt64)0);
|
||||
|
||||
/** The internal field corresponding to the serialField "bits". */
|
||||
epicsUInt64* words;
|
||||
|
||||
/** The internal field corresponding to the size of words[] array. */
|
||||
epicsUInt32 wordsLength;
|
||||
|
||||
/** The number of words in the logical size of this BitSet. */
|
||||
epicsUInt32 wordsInUse;
|
||||
|
||||
|
||||
private:
|
||||
|
||||
/**
|
||||
* Given a bit index, return word index containing it.
|
||||
*/
|
||||
static inline epicsUInt32 wordIndex(epicsUInt32 bitIndex) {
|
||||
return bitIndex >> ADDRESS_BITS_PER_WORD;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new word array.
|
||||
*/
|
||||
void initWords(epicsUInt32 nbits);
|
||||
|
||||
/**
|
||||
* Sets the field wordsInUse to the logical size in words of the bit set.
|
||||
* WARNING: This method assumes that the number of words actually in use is
|
||||
* less than or equal to the current value of wordsInUse!
|
||||
*/
|
||||
void recalculateWordsInUse();
|
||||
|
||||
/**
|
||||
* Ensures that the BitSet can hold enough words.
|
||||
* @param wordsRequired the minimum acceptable number of words.
|
||||
*/
|
||||
void ensureCapacity(epicsUInt32 wordsRequired);
|
||||
|
||||
/**
|
||||
* Ensures that the BitSet can accommodate a given wordIndex,
|
||||
* temporarily violating the invariants. The caller must
|
||||
* restore the invariants before returning to the user,
|
||||
* possibly using recalculateWordsInUse().
|
||||
* @param wordIndex the index to be accommodated.
|
||||
*/
|
||||
void expandTo(epicsUInt32 wordIndex);
|
||||
|
||||
/**
|
||||
* Returns the number of zero bits following the lowest-order ("rightmost")
|
||||
* one-bit in the two's complement binary representation of the specified
|
||||
* <tt>long</tt> value. Returns 64 if the specified value has no
|
||||
* one-bits in its two's complement representation, in other words if it is
|
||||
* equal to zero.
|
||||
*
|
||||
* @return the number of zero bits following the lowest-order ("rightmost")
|
||||
* one-bit in the two's complement binary representation of the
|
||||
* specified <tt>long</tt> value, or 64 if the value is equal
|
||||
* to zero.
|
||||
*/
|
||||
static epicsUInt32 numberOfTrailingZeros(epicsUInt64 i);
|
||||
|
||||
/**
|
||||
* Returns the number of one-bits in the two's complement binary
|
||||
* representation of the specified <tt>long</tt> value. This function is
|
||||
* sometimes referred to as the <i>population count</i>.
|
||||
*
|
||||
* @return the number of one-bits in the two's complement binary
|
||||
* representation of the specified <tt>long</tt> value.
|
||||
*/
|
||||
static epicsUInt32 bitCount(epicsUInt64 i);
|
||||
|
||||
};
|
||||
|
||||
}}
|
||||
#endif /* BITSET_H */
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -22,6 +22,10 @@ PROD_HOST += testSimpleStructure
|
||||
testSimpleStructure_SRCS += testSimpleStructure.cpp
|
||||
testSimpleStructure_LIBS += pvFactory
|
||||
|
||||
PROD_HOST += testBitSet
|
||||
testBitSet_SRCS += testBitSet.cpp
|
||||
testBitSet_LIBS += pvMisc Com
|
||||
|
||||
include $(TOP)/configure/RULES
|
||||
#----------------------------------------
|
||||
# ADD RULES AFTER THIS LINE
|
||||
|
||||
@@ -0,0 +1,143 @@
|
||||
/* testBitSet.cpp */
|
||||
/* Author: Matej Sekoranja Date: 2010.10.18 */
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include "BitSet.h"
|
||||
|
||||
|
||||
#include <epicsAssert.h>
|
||||
|
||||
using namespace epics::pvData;
|
||||
|
||||
void testGetSetClearFlip() {
|
||||
printf("testGetSetClearFlip... ");
|
||||
|
||||
// empty
|
||||
BitSet* b1 = new BitSet();
|
||||
assert(b1->isEmpty());
|
||||
assert(b1->cardinality() == 0);
|
||||
// to string check
|
||||
std::string str; b1->toString(&str);
|
||||
assert(str == "{}");
|
||||
|
||||
// one
|
||||
b1->set(3);
|
||||
assert(b1->get(3));
|
||||
assert(!b1->isEmpty());
|
||||
assert(b1->cardinality() == 1);
|
||||
// to string check
|
||||
str.clear(); b1->toString(&str);
|
||||
assert(str == "{3}");
|
||||
|
||||
// grow
|
||||
b1->set(66);
|
||||
b1->set(67);
|
||||
b1->set(68);
|
||||
assert(b1->cardinality() == 4);
|
||||
str.clear(); b1->toString(&str);
|
||||
assert(str == "{3, 66, 67, 68}");
|
||||
|
||||
// clear one
|
||||
b1->clear(67);
|
||||
assert(b1->cardinality() == 3);
|
||||
str.clear(); b1->toString(&str);
|
||||
assert(str == "{3, 66, 68}");
|
||||
|
||||
// flip
|
||||
b1->flip(66);
|
||||
b1->flip(130);
|
||||
assert(b1->cardinality() == 3);
|
||||
str.clear(); b1->toString(&str);
|
||||
assert(str == "{3, 68, 130}");
|
||||
|
||||
// flip
|
||||
b1->set(130, false);
|
||||
b1->set(4, true);
|
||||
assert(b1->cardinality() == 3);
|
||||
str.clear(); b1->toString(&str);
|
||||
assert(str == "{3, 4, 68}");
|
||||
|
||||
// clear all
|
||||
b1->clear();
|
||||
assert(b1->isEmpty());
|
||||
assert(b1->cardinality() == 0);
|
||||
str.clear(); b1->toString(&str);
|
||||
assert(str == "{}");
|
||||
|
||||
delete b1;
|
||||
printf("PASSED\n");
|
||||
|
||||
}
|
||||
|
||||
void testOperators() {
|
||||
printf("testOperators... ");
|
||||
|
||||
BitSet b1;
|
||||
assert(b1 == b1);
|
||||
BitSet b2;
|
||||
assert(b1 == b2);
|
||||
|
||||
b1.set(1);
|
||||
assert(!(b1 == b2));
|
||||
|
||||
// different internal length, but the same
|
||||
b2.set(100);
|
||||
b2.set(1);
|
||||
b2.flip(100);
|
||||
assert(b1 == b2);
|
||||
|
||||
// OR test
|
||||
b1.set(65);
|
||||
b1.set(106);
|
||||
b2.set(105);
|
||||
b1 |= b2;
|
||||
std::string str; b1.toString(&str);
|
||||
assert(str == "{1, 65, 105, 106}");
|
||||
|
||||
// AND test
|
||||
b1.set(128);
|
||||
b1 &= b2;
|
||||
assert(b1 == b2);
|
||||
|
||||
// XOR test
|
||||
b1.set(128);
|
||||
b1 ^= b2;
|
||||
assert(b1.cardinality() == 1 && b1.get(128) == true);
|
||||
|
||||
// a AND (NOT b)
|
||||
b2 -= b1;
|
||||
str.clear(); b2.toString(&str);
|
||||
assert(str == "{1, 105}");
|
||||
b1.set(1);
|
||||
b2 -= b1;
|
||||
str.clear(); b2.toString(&str);
|
||||
assert(b2.cardinality() == 1 && b2.get(105) == true);
|
||||
|
||||
// assign
|
||||
b1 = b2;
|
||||
assert(b1 == b2);
|
||||
|
||||
// or_and
|
||||
b1.clear(); b1.set(2);
|
||||
b2.clear(); b2.set(66); b2.set(128);
|
||||
BitSet b3; b3.set(128); b3.set(520);
|
||||
b1.or_and(b2, b3);
|
||||
str.clear(); b1.toString(&str);
|
||||
assert(str == "{2, 128}");
|
||||
|
||||
printf("PASSED\n");
|
||||
|
||||
}
|
||||
|
||||
|
||||
int main(int argc,char *argv[])
|
||||
{
|
||||
testGetSetClearFlip();
|
||||
testOperators();
|
||||
return(0);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user