Browse Source

Started refactoring bit vector class.

tempestpy_adaptions
dehnert 12 years ago
parent
commit
171a9fa161
  1. 183
      src/vector/bitvector.h

183
src/vector/bitvector.h

@ -6,26 +6,27 @@
#include <cmath> #include <cmath>
#include "boost/integer/integer_mask.hpp" #include "boost/integer/integer_mask.hpp"
#include <pantheios/pantheios.hpp>
#include <pantheios/inserters/integer.hpp>
#include "src/exceptions/invalid_state.h" #include "src/exceptions/invalid_state.h"
#include "src/exceptions/invalid_argument.h" #include "src/exceptions/invalid_argument.h"
#include "src/exceptions/out_of_range.h" #include "src/exceptions/out_of_range.h"
#include <iostream>
#include <string.h>
#include "log4cplus/logger.h"
#include "log4cplus/loggingmacros.h"
extern log4cplus::Logger logger;
namespace mrmc { namespace mrmc {
namespace vector { namespace vector {
//! A Boolean Array
/*! /*!
A bit vector for boolean fields or quick selection schemas on Matrix entries.
Does NOT perform index bound checks!
* A bit vector that is internally represented by an array of 64-bit values.
*/ */
class BitVector { class BitVector {
public:
class constIndexIterator { class constIndexIterator {
constIndexIterator(uint_fast64_t* bucketPtr, uint_fast64_t* endBucketPtr) : bucketPtr(bucketPtr), endBucketPtr(endBucketPtr), offset(0), currentBitInByte(0) { } constIndexIterator(uint_fast64_t* bucketPtr, uint_fast64_t* endBucketPtr) : bucketPtr(bucketPtr), endBucketPtr(endBucketPtr), offset(0), currentBitInByte(0) { }
constIndexIterator& operator++() { constIndexIterator& operator++() {
@ -50,68 +51,83 @@ class BitVector {
uint_fast8_t currentBitInByte; uint_fast8_t currentBitInByte;
}; };
public:
//! Constructor //! Constructor
/*! /*!
\param initial_length The initial size of the boolean Array. Can be changed later on via BitVector::resize()
* Constructs a bit vector which can hold the given number of bits.
* @param initialLength The number of bits the bit vector should be able to hold.
*/ */
BitVector(uint_fast64_t initial_length) {
bucket_count = initial_length >> 6;
if ((initial_length & mod64mask) != 0) {
++bucket_count;
BitVector(uint_fast64_t initialLength) {
// Check whether the given length is valid.
if (initialLength == 0) {
throw mrmc::exceptions::invalid_argument("Trying to create a bit vector of size 0.");
} }
bucket_array = new uint_fast64_t[bucket_count]();
// init all 0
for (uint_fast64_t i = 0; i < bucket_count; ++i) {
bucket_array[i] = 0;
// Compute the correct number of buckets needed to store the given number of bits
bucket_count = initialLength >> 6;
if ((initialLength & mod64mask) != 0) {
++bucket_count;
} }
// Finally, create the full bucket array. This should initialize the array
// with 0s (notice the parentheses at the end) for standard conforming
// compilers.
bucket_array = new uint_fast64_t[bucket_count]();
} }
//! Copy Constructor //! Copy Constructor
/*! /*!
Copy Constructor. Creates an exact copy of the source bit vector bv. Modification of either bit vector does not affect the other.
@param bv A reference to the bit vector that should be copied from
* Copy Constructor. Performs a deep copy of the given bit vector.
* @param bv A reference to the bit vector to be copied.
*/ */
BitVector(const BitVector &bv) :
bucket_count(bv.bucket_count) {
pantheios::log_DEBUG("BitVector::CopyCTor: Using Copy() Ctor.");
bucket_array = new uint_fast64_t[bucket_count]();
memcpy(bucket_array, bv.bucket_array,
sizeof(uint_fast64_t) * bucket_count);
BitVector(const BitVector &bv) : bucket_count(bv.bucket_count) {
bucket_array = new uint_fast64_t[bucket_count];
memcpy(bucket_array, bv.bucket_array, sizeof(uint_fast64_t) * bucket_count);
} }
//! Destructor
/*!
* Destructor. Frees the underlying bucket array.
*/
~BitVector() { ~BitVector() {
if (bucket_array != NULL) {
if (bucket_array != nullptr) {
delete[] bucket_array; delete[] bucket_array;
} }
} }
void resize(uint_fast64_t new_length) {
uint_fast64_t* tempArray = new uint_fast64_t[new_length]();
/*!
* Resizes the bit vector to hold the given new number of bits.
* @param newLength The new number of bits the bit vector can hold.
*/
void resize(uint_fast64_t newLength) {
uint_fast64_t newBucketCount = newLength >> 6;
if ((newLength & mod64mask) != 0) {
++bucket_count;
}
// Reserve a temporary array for copying.
uint_fast64_t* tempArray = new uint_fast64_t[newBucketCount];
// 64 bit/entries per uint_fast64_t
uint_fast64_t copySize =
(new_length <= (bucket_count << 6)) ?
(new_length >> 6) : (bucket_count);
// Copy over the elements from the old bit vector.
uint_fast64_t copySize = (newBucketCount <= bucket_count) ? newBucketCount : bucket_count;
memcpy(tempArray, bucket_array, sizeof(uint_fast64_t) * copySize); memcpy(tempArray, bucket_array, sizeof(uint_fast64_t) * copySize);
bucket_count = new_length >> 6;
if ((new_length & mod64mask) != 0) {
++bucket_count;
// Initialize missing values in the new bit vector.
for (uint_fast64_t i = copySize; i < bucket_count; ++i) {
bucket_array[i] = 0;
} }
// Dispose of the old bit vector and set the new one.
delete[] bucket_array; delete[] bucket_array;
bucket_array = tempArray; bucket_array = tempArray;
} }
/*!
* Sets the given truth value at the given index.
* @param index The index where to set the truth value.
* @param value The truth value to set.
*/
void set(const uint_fast64_t index, const bool value) { void set(const uint_fast64_t index, const bool value) {
uint_fast64_t bucket = index >> 6; uint_fast64_t bucket = index >> 6;
// Taking the step with mask is crucial as we NEED a 64bit shift, not a 32bit one.
// MSVC: C4334, use 1i64 or cast to __int64.
// result of 32-bit shift implicitly converted to 64 bits (was 64-bit shift intended?)
uint_fast64_t mask = 1;
mask = mask << (index & mod64mask);
uint_fast64_t mask = static_cast<uint_fast64_t>(1) << (index & mod64mask);
if (value) { if (value) {
bucket_array[bucket] |= mask; bucket_array[bucket] |= mask;
} else { } else {
@ -119,21 +135,27 @@ public:
} }
} }
/*!
* Retrieves the truth value at the given index.
* @param index The index from which to retrieve the truth value.
*/
bool get(const uint_fast64_t index) { bool get(const uint_fast64_t index) {
uint_fast64_t bucket = index >> 6; uint_fast64_t bucket = index >> 6;
// Taking the step with mask is crucial as we NEED a 64bit shift, not a 32bit one.
// MSVC: C4334, use 1i64 or cast to __int64.
// result of 32-bit shift implicitly converted to 64 bits (was 64-bit shift intended?)
uint_fast64_t mask = 1;
mask = mask << (index & mod64mask);
uint_fast64_t mask = static_cast<uint_fast64_t>(1) << (index & mod64mask);
return ((bucket_array[bucket] & mask) == mask); return ((bucket_array[bucket] & mask) == mask);
} }
// Operators
/*!
* Performs a logical "and" with the given bit vector. In case the sizes of the bit vectors
* do not match, only the matching portion is considered and the overlapping bits
* are set to 0.
* @param bv A reference to the bit vector to use for the operation.
* @return A bit vector corresponding to the logical "and" of the two bit vectors.
*/
BitVector operator &(BitVector const &bv) { BitVector operator &(BitVector const &bv) {
uint_fast64_t minSize =
(bv.bucket_count < this->bucket_count) ?
bv.bucket_count : this->bucket_count;
uint_fast64_t minSize = (bv.bucket_count < this->bucket_count) ? bv.bucket_count : this->bucket_count;
// Create resulting bit vector and perform the operation on the individual elements.
BitVector result(minSize << 6); BitVector result(minSize << 6);
for (uint_fast64_t i = 0; i < minSize; ++i) { for (uint_fast64_t i = 0; i < minSize; ++i) {
result.bucket_array[i] = this->bucket_array[i] & bv.bucket_array[i]; result.bucket_array[i] = this->bucket_array[i] & bv.bucket_array[i];
@ -141,10 +163,18 @@ public:
return result; return result;
} }
/*!
* Performs a logical "or" with the given bit vector. In case the sizes of the bit vectors
* do not match, only the matching portion is considered and the overlapping bits
* are set to 0.
* @param bv A reference to the bit vector to use for the operation.
* @return A bit vector corresponding to the logical "or" of the two bit vectors.
*/
BitVector operator |(BitVector const &bv) { BitVector operator |(BitVector const &bv) {
uint_fast64_t minSize =
(bv.bucket_count < this->bucket_count) ?
bv.bucket_count : this->bucket_count;
uint_fast64_t minSize = (bv.bucket_count < this->bucket_count) ? bv.bucket_count : this->bucket_count;
// Create resulting bit vector and perform the operation on the individual elements.
BitVector result(minSize << 6); BitVector result(minSize << 6);
for (uint_fast64_t i = 0; i < minSize; ++i) { for (uint_fast64_t i = 0; i < minSize; ++i) {
result.bucket_array[i] = this->bucket_array[i] | bv.bucket_array[i]; result.bucket_array[i] = this->bucket_array[i] | bv.bucket_array[i];
@ -153,10 +183,17 @@ public:
return result; return result;
} }
/*!
* Performs a logical "xor" with the given bit vector. In case the sizes of the bit vectors
* do not match, only the matching portion is considered and the overlapping bits
* are set to 0.
* @param bv A reference to the bit vector to use for the operation.
* @return A bit vector corresponding to the logical "xor" of the two bit vectors.
*/
BitVector operator ^(BitVector const &bv) { BitVector operator ^(BitVector const &bv) {
uint_fast64_t minSize =
(bv.bucket_count < this->bucket_count) ?
bv.bucket_count : this->bucket_count;
uint_fast64_t minSize = (bv.bucket_count < this->bucket_count) ? bv.bucket_count : this->bucket_count;
// Create resulting bit vector and perform the operation on the individual elements.
BitVector result(minSize << 6); BitVector result(minSize << 6);
for (uint_fast64_t i = 0; i < minSize; ++i) { for (uint_fast64_t i = 0; i < minSize; ++i) {
result.bucket_array[i] = this->bucket_array[i] ^ bv.bucket_array[i]; result.bucket_array[i] = this->bucket_array[i] ^ bv.bucket_array[i];
@ -165,7 +202,12 @@ public:
return result; return result;
} }
/*!
* Performs a logical "not" on the bit vector.
* @return A bit vector corresponding to the logical "not" of the bit vector.
*/
BitVector operator ~() { BitVector operator ~() {
// Create resulting bit vector and perform the operation on the individual elements.
BitVector result(this->bucket_count << 6); BitVector result(this->bucket_count << 6);
for (uint_fast64_t i = 0; i < this->bucket_count; ++i) { for (uint_fast64_t i = 0; i < this->bucket_count; ++i) {
result.bucket_array[i] = ~this->bucket_array[i]; result.bucket_array[i] = ~this->bucket_array[i];
@ -174,16 +216,18 @@ public:
return result; return result;
} }
/*!
* Performs a logical "implies" with the given bit vector. In case the sizes of the bit vectors
* do not match, only the matching portion is considered and the overlapping bits
* are set to 0.
* @param bv A reference to the bit vector to use for the operation.
* @return A bit vector corresponding to the logical "xor" of the two bit vectors.
*/
BitVector implies(BitVector& other) { BitVector implies(BitVector& other) {
if (other.getSize() != this->getSize()) {
pantheios::log_ERROR(
"BitVector::implies: Throwing invalid argument exception for connecting bit vectors of different size.");
throw mrmc::exceptions::invalid_argument();
}
// Create resulting bit vector and perform the operation on the individual elements.
BitVector result(this->bucket_count << 6); BitVector result(this->bucket_count << 6);
for (uint_fast64_t i = 0; i < this->bucket_count; ++i) { for (uint_fast64_t i = 0; i < this->bucket_count; ++i) {
result.bucket_array[i] = ~this->bucket_array[i]
| other.bucket_array[i];
result.bucket_array[i] = ~this->bucket_array[i] | other.bucket_array[i];
} }
return result; return result;
@ -196,7 +240,8 @@ public:
uint_fast64_t getNumberOfSetBits() { uint_fast64_t getNumberOfSetBits() {
uint_fast64_t set_bits = 0; uint_fast64_t set_bits = 0;
for (uint_fast64_t i = 0; i < bucket_count; ++i) { for (uint_fast64_t i = 0; i < bucket_count; ++i) {
#ifdef __GNUG__ // check if we are using g++ and use built-in function if available
// Check if we are using g++ or clang++ and, if so, use the built-in function
#if (defined (__GNUG__) || defined(__clang__))
set_bits += __builtin_popcountll(this->bucket_array[i]); set_bits += __builtin_popcountll(this->bucket_array[i]);
#else #else
uint_fast32_t cnt; uint_fast32_t cnt;
@ -210,8 +255,11 @@ public:
return set_bits; return set_bits;
} }
/*!
* Retrieves the number of bits this bit vector can store.
*/
uint_fast64_t getSize() { uint_fast64_t getSize() {
return bucket_count;
return bucket_count << 6;
} }
/*! /*!
@ -223,13 +271,14 @@ public:
} }
private: private:
/*! The number of 64-bit buckets we use as internal storage. */
uint_fast64_t bucket_count; uint_fast64_t bucket_count;
/*! Array containing the boolean bits for each node, 64bits/64nodes per element */
uint_fast64_t* bucket_array;
/*! Array of 64-bit buckets to store the bits. */
uint64_t* bucket_array;
/*! A bit mask that can be used to reduce a modulo operation to a logical "and". */
static const uint_fast64_t mod64mask = (1 << 6) - 1; static const uint_fast64_t mod64mask = (1 << 6) - 1;
}; };
} // namespace vector } // namespace vector

Loading…
Cancel
Save