blob: 8c3a0744e28230d39b8fbf5ea915160181346e6a [file] [log] [blame]
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
**/
#ifndef QUICKSTEP_STORAGE_TUPLE_ID_SEQUENCE_HPP_
#define QUICKSTEP_STORAGE_TUPLE_ID_SEQUENCE_HPP_
#include <cstddef>
#include <limits>
#include <vector>
#include "storage/StorageBlockInfo.hpp"
#include "utility/BitVector.hpp"
#include "utility/Macros.hpp"
#include "glog/logging.h"
namespace quickstep {
/** \addtogroup Storage
* @{
*/
/**
* @brief A sequence of Tuple IDs (implemented as a thin wrapper around
* BitVector), used to communicate information about multiple tuples
* between SubBlocks.
**/
class TupleIdSequence {
public:
/**
* @brief Const-iterator over tuple IDs set in a TupleIdSequence.
**/
class ConstIterator {
public:
ConstIterator()
: bitvector_(nullptr) {
}
inline tuple_id operator*() const {
DEBUG_ASSERT(bitvector_ != nullptr);
DEBUG_ASSERT(current_position_ < bitvector_->size());
return current_position_;
}
inline ConstIterator& operator++() {
DEBUG_ASSERT(bitvector_ != nullptr);
const std::size_t search_pos = current_position_ + 1;
current_position_ = (search_pos < bitvector_->size()) ? bitvector_->firstOne(search_pos)
: bitvector_->size();
return *this;
}
inline ConstIterator& operator--() {
DEBUG_ASSERT(bitvector_ != nullptr);
current_position_ = bitvector_->lastOne(current_position_);
if (current_position_ == bitvector_->size()) {
current_position_ = std::numeric_limits<std::size_t>::max();
}
return *this;
}
ConstIterator operator++(int) {
ConstIterator result(*this);
++(*this);
return result;
}
ConstIterator operator--(int) {
ConstIterator result(*this);
--(*this);
return result;
}
inline bool operator==(const ConstIterator& other) const {
return ((bitvector_ == other.bitvector_)
&& (current_position_ == other.current_position_));
}
inline bool operator!=(const ConstIterator& other) const {
return !(*this == other);
}
private:
friend class TupleIdSequence;
ConstIterator(const BitVector<false> *bitvector,
const std::size_t initial_position)
: bitvector_(bitvector),
current_position_(initial_position) {
}
const BitVector<false> *bitvector_;
std::size_t current_position_;
};
typedef ConstIterator const_iterator;
typedef std::size_t size_type;
/**
* @brief Constructor.
*
* @param length The number of tuple ID slots in this TupleIdSequence.
* Typically TupleStorageSubBlock::getMaxTupleID() + 1.
**/
explicit TupleIdSequence(const tuple_id length)
: internal_bitvector_(length) {
}
/**
* @brief Constructor which initializes a TupleIdSequence from bits set in a
* (possibly longer) BitVector.
*
* @param length The number of tuple ID slots in this TupleIdSequence.
* Typically TupleStorageSubBlock::getMaxTupleID() + 1.
* @param bit_vector A BitVector of at least length bits to initially assign
* from.
**/
TupleIdSequence(const tuple_id length,
const BitVector<false> &bit_vector)
: internal_bitvector_(length) {
internal_bitvector_.assignFromLonger(bit_vector);
}
/**
* @brief Destructor.
**/
~TupleIdSequence() {
}
/**
* @brief Set a particular tuple ID as being on or off in this sequence.
*
* @param tuple The ID to set.
* @param on If true, tuple should be part of this sequence. If false,
* remove tuple from this sequence (if it was present).
**/
inline void set(const tuple_id tuple, const bool on) {
DEBUG_ASSERT(tuple >= 0);
DEBUG_ASSERT(static_cast<std::size_t>(tuple) < internal_bitvector_.size());
internal_bitvector_.setBit(tuple, on);
}
/**
* @brief Set a particular tuple ID as being on or off in this sequence.
*
* @param on If true, tuple should be part of this sequence. If false,
* remove tuple from this sequence (if it was present).
**/
inline void set(const tuple_id tuple) {
DCHECK_GE(tuple, 0);
DCHECK_LT(static_cast<std::size_t>(tuple), internal_bitvector_.size());
internal_bitvector_.setBit(tuple);
}
/**
* @brief Set a range of tuple IDs all at once.
*
* @param first_tuple The first ID to set.
* @param num_tuples The number of consecutive tuple IDs to set.
* @param on If true, tuple IDs in range should be part of this sequence. If
* false, remove tuple IDs in range from this sequence.
**/
inline void setRange(const tuple_id first_tuple,
const tuple_id num_tuples,
const bool on) {
DEBUG_ASSERT(first_tuple >= 0);
if (num_tuples > 0) {
internal_bitvector_.setBitRange(first_tuple, num_tuples, on);
}
}
/**
* @brief Set the value of a word of bits simultaneously.
*
* @param word_id The position of the word whose value should be set.
* @param word_value The word value to set for the bits in the word.
**/
inline void setWord(const std::size_t word_id,
const std::size_t word_value) {
DEBUG_ASSERT(word_id * (sizeof(std::size_t) << 3)
< internal_bitvector_.size());
internal_bitvector_.setBitWord(word_id, word_value);
}
/**
* @brief Determine if a particular tuple ID is part of this sequence.
*
* @param tuple The tuple ID to check.
* @return true if tuple is part of this sequence, false if not.
**/
inline bool get(const tuple_id tuple) const {
DEBUG_ASSERT(tuple >= 0);
DEBUG_ASSERT(static_cast<std::size_t>(tuple) < internal_bitvector_.size());
return internal_bitvector_.getBit(tuple);
}
/**
* @brief Get the value of a word of bits.
*
* @param word_id The position of the word.
* @return The word value at word_id.
**/
inline std::size_t getWord(const std::size_t word_id) const {
DEBUG_ASSERT(word_id * (sizeof(std::size_t) << 3)
< internal_bitvector_.size());
return internal_bitvector_.getBitWord(word_id);
}
/**
* @brief Determine if ANY tuple ID is part of this sequence.
*
* @return true if any tuple ID is part of this sequence, false otherwise.
**/
inline bool empty() const {
return !internal_bitvector_.any();
}
/**
* @brief Get the number of tuple ID slots in this sequence.
*
* @note This gives the number of slots. To get the actual number of tuple
* IDs that are "on" in this sequence, use numTuples().
*
* @return The number of tuple ID slots in this sequence.
**/
inline size_type length() const {
return internal_bitvector_.size();
}
/**
* @brief Get the number of tuple IDs that are actually part of this
* sequence (i.e. set to "on").
*
* @return The number of tuple IDs in this sequence.
**/
inline size_type numTuples() const {
return internal_bitvector_.onesCount();
}
/**
* @brief Get the number of tuple IDs that are actually part of this
* sequence (i.e. set to "on").
*
* @return The number of tuple IDs in this sequence.
**/
inline size_type size() const {
return internal_bitvector_.onesCount();
}
/**
* @brief Get an iterator to the first tuple ID that is actually part of this
* sequence (i.e. set to "on").
*
* @return An iterator pointing to the first tuple ID in this sequence.
**/
inline const_iterator begin() const {
return const_iterator(&internal_bitvector_, internal_bitvector_.firstOne());
}
/**
* @brief Get an iterator one-before-the-beginning of tuple IDs actually in
* this sequence.
* @warning The iterator returned must be incremented to become valid.
*
* @return An iterator one-before-the-beginning of tuple IDs in this
* sequence.
**/
inline const_iterator before_begin() const {
return const_iterator(&internal_bitvector_, std::numeric_limits<std::size_t>::max());
}
/**
* @brief Get an iterator one-past-the-end of tuple IDs actually in this
* sequence.
*
* @return An iterator one-past-the-end of tuple IDs in this sequence.
**/
inline const_iterator end() const {
return const_iterator(&internal_bitvector_, internal_bitvector_.size());
}
/**
* @brief Get the smallest tuple ID in this sequence.
*
* @warning This is only safe to call if empty() is false.
*
* @return The smallest tuple ID in this sequence.
**/
inline tuple_id front() const {
DEBUG_ASSERT(!empty());
return internal_bitvector_.firstOne();
}
/**
* @brief Get the largest tuple ID in this sequence.
*
* @warning This is only safe to call if empty() is false.
*
* @return The largest tuple ID in this sequence.
**/
inline tuple_id back() const {
DEBUG_ASSERT(!empty());
return internal_bitvector_.lastOne();
}
/**
* @brief Invert this tuple ID sequence, switching all matches to non-matches
* and vice-versa.
* @warning If this sequence represents tuples in a TupleStorageSubBlock
* which is not packed (i.e. which has holes in its sequence of
* tuple IDs), then this method can cause non-existent Tuple IDs
* to appear as matches. After inverting, the intersectWith() should
* be called with an existence bitmap to filter out such IDs.
**/
inline void invert() {
internal_bitvector_.flipBits();
}
/**
* @brief Assign this TupleIdSequence to be the same as another
* TupleIdSequence of the same length.
*
* @param other Another TupleIdSequence to copy from.
**/
inline void assignFrom(const TupleIdSequence &other) {
internal_bitvector_.assignFrom(other.internal_bitvector_);
}
/**
* @brief Take the intersection of this TupleIdSequence with another,
* modifying this TupleIdSequence in-place.
* @warning This TupleIdSequence must be the same length as the other, and
* the intersection only has semantic meaning if both
* TupleIdSequences refer to tuples in the same block.
*
* @param other Another TupleIdSequence to intersect with.
**/
inline void intersectWith(const TupleIdSequence &other) {
internal_bitvector_.intersectWith(other.internal_bitvector_);
}
/**
* @brief Take the intersection of this TupleIdSequence with another's
* complement (i.e. set difference), modifying this TupleIdSequence
* in-place.
* @warning This TupleIdSequence must be the same length as the other, and
* the set-difference only has semantic meaning if both
* TupleIdSequences refer to tuples in the same block.
*
* @param other Another TupleIdSequence to intersect with the complement of.
**/
inline void intersectWithComplement(const TupleIdSequence &other) {
DEBUG_ASSERT(length() == other.length());
internal_bitvector_.unsetFrom(other.internal_bitvector_);
}
/**
* @brief Take the union of this TupleIdSequence with another,
* modifying this TupleIdSequence in-place.
* @warning This TupleIdSequence must be the same length as the other, and
* the union only has semantic meaning if both
* TupleIdSequences refer to tuples in the same block.
*
* @param other Another TupleIdSequence to union with.
**/
inline void unionWith(const TupleIdSequence &other) {
internal_bitvector_.unionWith(other.internal_bitvector_);
}
/**
* @brief Get a const reference to this TupleIdSequence's underlying
* BitVector representation.
**/
const BitVector<false>& getInternalBitVector() const {
return internal_bitvector_;
}
private:
BitVector<false> internal_bitvector_;
DISALLOW_COPY_AND_ASSIGN(TupleIdSequence);
};
/**
* @brief An ordered sequence of Tuple IDs used to communicate information about
* multiple tuples between SubBlocks.
*/
typedef std::vector<tuple_id> OrderedTupleIdSequence;
/** @} */
} // namespace quickstep
#endif // QUICKSTEP_STORAGE_TUPLE_ID_SEQUENCE_HPP_