Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bitSet: macros and vector storage #22

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
117 changes: 54 additions & 63 deletions src/misc/bitSet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,39 +11,45 @@
#include <stdio.h>
#include <iostream>

#include <stdexcept>

#define epicsExportSharedSymbols
#include <pv/lock.h>
#include <pv/serializeHelper.h>
#include <pv/bitSet.h>

/*
* 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.
*/
#define ADDRESS_BITS_PER_WORD 6u
#define BITS_PER_WORD (1u << ADDRESS_BITS_PER_WORD)
#define BIT_INDEX_MASK (BITS_PER_WORD - 1u)

/** Used to shift left or right for a partial word mask */
#define WORD_MASK ~((uint64)0)

// index of work containing this bit
#define WORD_INDEX(bitn) ((bitn)>>ADDRESS_BITS_PER_WORD)
// bit offset within word
#define WORD_OFFSET(bitn) ((bitn)&BIT_INDEX_MASK)

namespace epics { namespace pvData {

BitSet::shared_pointer BitSet::create(uint32 nbits)
{
return BitSet::shared_pointer(new BitSet(nbits));
}

BitSet::BitSet() : words(0), wordsLength(0), wordsInUse(0) {
initWords(BITS_PER_WORD);

}

BitSet::BitSet(uint32 nbits) : words(0), wordsLength(0), wordsInUse(0) {
initWords(nbits);
BitSet::BitSet() : words(1,0), wordsInUse(0) {}

}

BitSet::~BitSet() {
delete[] words;
}
BitSet::BitSet(uint32 nbits)
:words((nbits <= 0) ? 1 : WORD_INDEX(nbits-1) + 1, 0)
,wordsInUse(0)
{}

void BitSet::initWords(uint32 nbits) {
uint32 length = (nbits <= 0) ? 1 : wordIndex(nbits-1) + 1;
if (words) delete[] words;
words = new uint64[length];
memset(words, 0, sizeof(uint64)*length);
wordsLength = length;
}
BitSet::~BitSet() {}

void BitSet::recalculateWordsInUse() {
// wordsInUse is unsigned
Expand All @@ -60,16 +66,7 @@ namespace epics { namespace pvData {
}

void BitSet::ensureCapacity(uint32 wordsRequired) {
if (wordsLength < wordsRequired) {

// create and copy
uint64* newwords = new uint64[wordsRequired];
memset(newwords, 0, sizeof(uint64)*wordsRequired);
memcpy(newwords, words, sizeof(uint64)*wordsLength);
if (words) delete[] words;
words = newwords;
wordsLength = wordsRequired;
}
words.resize(wordsRequired, 0);
}

void BitSet::expandTo(uint32 wordIndex) {
Expand All @@ -82,29 +79,29 @@ namespace epics { namespace pvData {

void BitSet::flip(uint32 bitIndex) {

uint32 wordIdx = wordIndex(bitIndex);
uint32 wordIdx = WORD_INDEX(bitIndex);
expandTo(wordIdx);

words[wordIdx] ^= (((uint64)1) << (bitIndex % BITS_PER_WORD));
words[wordIdx] ^= (((uint64)1) << WORD_OFFSET(bitIndex));

recalculateWordsInUse();
}

void BitSet::set(uint32 bitIndex) {

uint32 wordIdx = wordIndex(bitIndex);
uint32 wordIdx = WORD_INDEX(bitIndex);
expandTo(wordIdx);

words[wordIdx] |= (((uint64)1) << (bitIndex % BITS_PER_WORD));
words[wordIdx] |= (((uint64)1) << WORD_OFFSET(bitIndex));
}

void BitSet::clear(uint32 bitIndex) {

uint32 wordIdx = wordIndex(bitIndex);
uint32 wordIdx = WORD_INDEX(bitIndex);
if (wordIdx >= wordsInUse)
return;

words[wordIdx] &= ~(((uint64)1) << (bitIndex % BITS_PER_WORD));
words[wordIdx] &= ~(((uint64)1) << WORD_OFFSET(bitIndex));

recalculateWordsInUse();
}
Expand All @@ -117,9 +114,9 @@ namespace epics { namespace pvData {
}

bool BitSet::get(uint32 bitIndex) const {
uint32 wordIdx = wordIndex(bitIndex);
uint32 wordIdx = WORD_INDEX(bitIndex);
return ((wordIdx < wordsInUse)
&& ((words[wordIdx] & (((uint64)1) << (bitIndex % BITS_PER_WORD))) != 0));
&& ((words[wordIdx] & (((uint64)1) << WORD_OFFSET(bitIndex))) != 0));
}

void BitSet::clear() {
Expand Down Expand Up @@ -153,7 +150,7 @@ namespace epics { namespace pvData {

int32 BitSet::nextSetBit(uint32 fromIndex) const {

uint32 u = wordIndex(fromIndex);
uint32 u = WORD_INDEX(fromIndex);
if (u >= wordsInUse)
return -1;

Expand All @@ -171,7 +168,7 @@ namespace epics { namespace pvData {
int32 BitSet::nextClearBit(uint32 fromIndex) const {
// Neither spec nor implementation handle bitsets of maximal length.

uint32 u = wordIndex(fromIndex);
uint32 u = WORD_INDEX(fromIndex);
if (u >= wordsInUse)
return fromIndex;

Expand All @@ -198,7 +195,7 @@ namespace epics { namespace pvData {
}

uint32 BitSet::size() const {
return wordsLength * BITS_PER_WORD;
return words.size() * BITS_PER_WORD;
}

BitSet& BitSet::operator&=(const BitSet& set) {
Expand Down Expand Up @@ -260,21 +257,19 @@ namespace epics { namespace pvData {

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 uint64[set.wordsLength];
wordsLength = set.wordsLength;
if (this != &set) {
words = set.words;
wordsInUse = set.wordsInUse;
}
memcpy(words, set.words, sizeof(uint64)*set.wordsInUse);
wordsInUse = set.wordsInUse;

return *this;
}

void BitSet::swap(BitSet& set)
{
std::swap(wordsInUse, set.wordsInUse);
words.swap(set.words);
}

void BitSet::or_and(const BitSet& set1, const BitSet& set2) {
uint32 inUse = (set1.wordsInUse < set2.wordsInUse) ? set1.wordsInUse : set2.wordsInUse;

Expand Down Expand Up @@ -335,29 +330,25 @@ namespace epics { namespace pvData {
uint32 bytes = static_cast<uint32>(SerializeHelper::readSize(buffer, control)); // in bytes

wordsInUse = (bytes + 7) / 8;
if (wordsInUse > wordsLength)
{
if (words) delete[] words;
words = new uint64[wordsInUse];
wordsLength = wordsInUse;
}

if (wordsInUse > words.size())
words.resize(wordsInUse);

if (wordsInUse == 0)
return;

control->ensureData(bytes);

uint32 i = 0;
uint32 longs = bytes / 8;
while (i < longs)
words[i++] = buffer->getLong();

for (uint32 j = i; j < wordsInUse; j++)
words[j] = 0;

for (uint32 remaining = (bytes - longs * 8), j = 0; j < remaining; j++)
words[i] |= (buffer->getByte() & 0xffL) << (8 * j);

}

epicsShareExtern std::ostream& operator<<(std::ostream& o, const BitSet& b)
Expand Down
36 changes: 6 additions & 30 deletions src/misc/bitSet.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
#ifndef BITSET_H
#define BITSET_H

#include <stdexcept>
#include <vector>

#include <pv/pvType.h>
#include <pv/serialize.h>
Expand Down Expand Up @@ -211,6 +211,9 @@ namespace epics { namespace pvData {
*/
BitSet& operator=(const BitSet &set);

//! Swap contents
void swap(BitSet& set);

/**
* Perform AND operation on <code>set1</code> and <code>set2</code>,
* and OR on result and this instance.
Expand All @@ -233,42 +236,15 @@ namespace epics { namespace pvData {

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 uint32 ADDRESS_BITS_PER_WORD = 6;
static const uint32 BITS_PER_WORD = 1 << ADDRESS_BITS_PER_WORD;
static const uint32 BIT_INDEX_MASK = BITS_PER_WORD - 1;

/** Used to shift left or right for a partial word mask */
static const uint64 WORD_MASK = ~((uint64)0);

typedef std::vector<uint64> words_t;
/** The internal field corresponding to the serialField "bits". */
uint64* words;

/** The internal field corresponding to the size of words[] array. */
uint32 wordsLength;
words_t words;

/** The number of words in the logical size of this BitSet. */
uint32 wordsInUse;


private:

/**
* Given a bit index, return word index containing it.
*/
static inline uint32 wordIndex(uint32 bitIndex) {
return bitIndex >> ADDRESS_BITS_PER_WORD;
}

/**
* Creates a new word array.
*/
void initWords(uint32 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
Expand Down
3 changes: 2 additions & 1 deletion testApp/misc/testBitSet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ static void testOperators()
testOk1((b1.cardinality() == 2 && b1.get(1) == true && b1.get(256) == true));


testOk1(b1 != b2);
// assign
b1 = b2;
testOk1(b1 == b2);
Expand All @@ -151,7 +152,7 @@ static void testOperators()

MAIN(testBitSet)
{
testPlan(29);
testPlan(30);
testGetSetClearFlip();
testOperators();
return testDone();
Expand Down