#ifndef STORM_STORAGE_BITVECTOR_H_ #define STORM_STORAGE_BITVECTOR_H_ #include #include #include #include #include namespace storm { namespace storage { /*! * A bit vector that is internally represented as a vector of 64-bit values. */ class BitVector { public: /*! * A class that enables iterating over the indices of the bit vector whose corresponding bits are set to * true. Note that this is a const iterator, which cannot alter the bit vector. */ class const_iterator : public std::iterator { // Declare the BitVector class as a friend class to access its internal storage. friend class BitVector; public: /*! * Constructs an iterator over the indices of the set bits in the given bit vector, starting and * stopping, respectively, at the given indices. * * @param dataPtr A pointer to the first bucket of the underlying bit vector. * @param startIndex The index where to begin looking for set bits. * @param setOnFirstBit A flag that indicates whether the iterator is to be moved to the index of the * first bit upon construction. * @param endIndex The index at which to abort the iteration process. */ const_iterator(uint64_t const* dataPtr, uint_fast64_t startIndex, uint_fast64_t endIndex, bool setOnFirstBit = true); /*! * Constructs an iterator by copying the given iterator. * * @param other The iterator to copy. */ const_iterator(const_iterator const& other); /*! * Assigns the contents of the given iterator to the current one via copying the former's contents. * * @param other The iterator from which to copy-assign. */ const_iterator& operator=(const_iterator const& other); /*! * Increases the position of the iterator to the position of the next bit that is set to true in the * underlying bit vector. * * @return A reference to this iterator. */ const_iterator& operator++(); /*! * Returns the index of the current bit to which this iterator points. * * @return The index of the current bit to which this iterator points. */ uint_fast64_t operator*() const; /*! * Compares the iterator with another iterator for inequality. * * @param other The iterator with respect to which inequality is checked. * @return True if the two iterators are unequal. */ bool operator!=(const_iterator const& other) const; /*! * Compares the iterator with another iterator for equality. * * @param other The iterator with respect to which equality is checked. * @return True if the two iterators are equal. */ bool operator==(const_iterator const& other) const; private: // The underlying bit vector of this iterator. uint64_t const* dataPtr; // The index of the bit this iterator currently points to. uint_fast64_t currentIndex; // The index of the bit that is past the end of the range of this iterator. uint_fast64_t endIndex; }; /* * Constructs an empty bit vector of length 0. */ BitVector(); /*! * Constructs a bit vector which can hold the given number of bits and initializes all bits with the * provided truth value. * * @param length The number of bits the bit vector should be able to hold. * @param init The initial value of the first |length| bits. */ BitVector(uint_fast64_t length, bool init = false); /*! * Creates a bit vector that has exactly the bits set that are given by the provided input iterator range * [first, last). * * @param The length of the bit vector. * @param first The begin of the iterator range. * @param last The end of the iterator range. */ template BitVector(uint_fast64_t length, InputIterator first, InputIterator last); /*! * Performs a deep copy of the given bit vector. * * @param other A reference to the bit vector to be copied. */ BitVector(BitVector const& other); /*! * Move constructs the bit vector from the given bit vector. * * @param other The bit vector from which to move-construct. */ BitVector(BitVector&& other); /*! * Compares the given bit vector with the current one. * * @param other The bitvector with which to compare the current one. * @return True iff the other bit vector is semantically the same as the current one. */ bool operator==(BitVector const& other); /*! * Compares the given bit vector with the current one. * * @param other The bitvector with which to compare the current one. * @return True iff the other bit vector is semantically not the same as the current one. */ bool operator!=(BitVector const& other); /*! * Assigns the contents of the given bit vector to the current bit vector via a deep copy. * * @param other The bit vector to assign to the current bit vector. * @return A reference to this bit vector after it has been assigned the given bit vector by means of a * deep copy. */ BitVector& operator=(BitVector const& other); /*! * Move assigns the given bit vector to the current bit vector. * * @param other The bit vector whose content is moved to the current bit vector. * @return A reference to this bit vector after the contents of the given bit vector have been moved * into it. */ BitVector& operator=(BitVector&& other); /*! * Retrieves whether the current bit vector is (in some order) smaller than the given one. * * @param other The other bit vector. * @return True iff the current bit vector is smaller than the given one. */ bool operator<(BitVector const& other) const; /*! * 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, bool value = true); /*! * Sets all bits in the given iterator range [first, last). * * @param first The begin of the iterator range. * @param last The element past the last element of the iterator range. */ template void set(InputIterator first, InputIterator last); /*! * Retrieves the truth value of the bit at the given index. Note: this does not check whether the given * index is within bounds. * * @param index The index of the bit to access. * @return True iff the bit at the given index is set. */ bool operator[](uint_fast64_t index) const; /*! * Retrieves the truth value of the bit at the given index and performs a bound check. If the access is * out-of-bounds an OutOfBoundsException is thrown. * * @param index The index of the bit to access. * @return True iff the bit at the given index is set. */ bool get(const uint_fast64_t index) const; /*! * Resizes the bit vector to hold the given new number of bits. If the bit vector becomes smaller this way, * the bits are truncated. Otherwise, the new bits are initialized to the given value. * * @param newLength The new number of bits the bit vector can hold. * @param init The truth value to which to initialize newly created bits. */ void resize(uint_fast64_t newLength, bool init = false); /*! * 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 other 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& other) const; /*! * Performs a logical "and" with the given bit vector and assigns the result to the current 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 other A reference to the bit vector to use for the operation. * @return A reference to the current bit vector corresponding to the logical "and" * of the two bit vectors. */ BitVector& operator&=(BitVector const& other); /*! * 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 other 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& other) const; /*! * Performs a logical "or" with the given bit vector and assigns the result to the current 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 other A reference to the bit vector to use for the operation. * @return A reference to the current bit vector corresponding to the logical "or" * of the two bit vectors. */ BitVector& operator|=(BitVector const& other); /*! * 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 other 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& other) const; /*! * Computes a bit vector that is as long as the number of set bits in the given filter that has bit i is set * iff the i-th set bit of the current bit vector is set in the filter. * * @param filter A reference the bit vector to use as the filter. * @return A bit vector that is as long as the number of set bits in the given filter that has bit i is set * iff the i-th set bit of the current bit vector is set in the filter. */ BitVector operator%(BitVector const& filter) const; /*! * Performs a logical "not" on the bit vector. * * @return A bit vector corresponding to the logical "not" of the bit vector. */ BitVector operator~() const; /*! * Negates all bits in the bit vector. */ void complement(); /*! * 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 other A reference to the bit vector to use for the operation. * @return A bit vector corresponding to the logical "implies" of the two bit vectors. */ BitVector implies(BitVector const& other) const; /*! * Checks whether all bits that are set in the current bit vector are also set in the given bit vector. * * @param other A reference to the bit vector whose bits are (possibly) a superset of the bits of * the current bit vector. * @return True iff all bits that are set in the current bit vector are also set in the given bit * vector. */ bool isSubsetOf(BitVector const& other) const; /*! * Checks whether none of the bits that are set in the current bit vector are also set in the given bit * vector. * * @param other A reference to the bit vector whose bits are (possibly) disjoint from the bits in * the current bit vector. * @return True iff none of the bits that are set in the current bit vector are also set in the * given bit vector. */ bool isDisjointFrom(BitVector const& other) const; /*! * Retrieves whether no bits are set to true in this bit vector. * * @return False iff there is at least one bit set in this vector. */ bool empty() const; /*! * Retrievs whether all bits are set in this bit vector. * * @return True iff all bits in the bit vector are set. */ bool full() const; /*! * Removes all set bits from the bit vector. Calling empty() after this operation will yield true. */ void clear(); /*! * Returns the number of bits that are set to true in this bit vector. * * @return The number of bits that are set to true in this bit vector. */ uint_fast64_t getNumberOfSetBits() const; /*! * Retrieves the number of bits set in this bit vector with an index strictly smaller than the given one. * * @param index The index for which to retrieve the number of set bits with a smaller index. * @return The number of bits set in this bit vector with an index strictly smaller than the given one. */ uint_fast64_t getNumberOfSetBitsBeforeIndex(uint_fast64_t index) const; /*! * Retrieves the number of bits this bit vector can store. * * @return The number of bits this bit vector can hold. */ size_t size() const; /*! * Returns the size of the bit vector in memory measured in bytes. * * @return The size of the bit vector in memory measured in bytes. */ uint_fast64_t getSizeInMemory() const; /*! * Returns an iterator to the indices of the set bits in the bit vector. */ const_iterator begin() const; /*! * Returns an iterator pointing at the element past the bit vector. */ const_iterator end() const; /*! * Calculates a hash value for this bit vector. * * @return The hash value of this bit vector. */ std::size_t hash() const; /* * Retrieves the index of the bit that is the next bit set to true in the bit vector. If there is none, * this function returns the number of bits this vector holds in total. Put differently, if the return * value is equal to a call to size(), then there is no bit set after the specified position. * * @param startingIndex The index at which to start the search for the next bit that is set. The * bit at this index itself is already considered. * @return The index of the next bit that is set after the given index. */ uint_fast64_t getNextSetIndex(uint_fast64_t startingIndex) const; friend std::ostream& operator<<(std::ostream& out, BitVector const& bitVector); private: /*! * Retrieves the index of the next bit that is set to true after (and including) the given starting index. * * @param dataPtr A pointer to the first bucket of the data storage. * @param startingIndex The index where to start the search. * @param endIndex The index at which to stop the search. * @return The index of the bit that is set after the given starting index, but before the given end index * in the given bit vector or endIndex in case the end index was reached. */ static uint_fast64_t getNextSetIndex(uint64_t const* dataPtr, uint_fast64_t startingIndex, uint_fast64_t endIndex); /*! * Truncate the last bucket so that no bits are set starting from bitCount. */ void truncateLastBucket(); // The number of bits that this bit vector can hold. uint_fast64_t bitCount; // The underlying storage of 64-bit buckets for all bits of this bit vector. std::vector bucketVector; // A bit mask that can be used to reduce a modulo 64 operation to a logical "and". static const uint_fast64_t mod64mask = (1 << 6) - 1; }; } // namespace storage } // namespace storm #endif // STORM_STORAGE_BITVECTOR_H_