bm.h
Go to the documentation of this file.
#ifndef BM__H__INCLUDED__
#define BM__H__INCLUDED__
/*
Copyright(c) 2002-2019 Anatoliy Kuznetsov(anatoliy_kuznetsov at yahoo.com)
Licensed 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.
For more information please visit: http://bitmagic.io
*/
/*! \file bm.h
\brief Compressed bit-vector bvector<> container, set algebraic methods, traversal iterators
*/
// define BM_NO_STL if you use BM in "STL free" environment and want
// to disable any references to STL headers
#ifndef BM_NO_STL
# include <iterator>
# include <initializer_list>
# include <stdexcept>
#endif
#include <limits.h>
#ifdef _MSC_VER
#pragma warning( push )
#pragma warning( disable : 4311 4312 4127)
#endif
#include "bmdef.h"
#include "bmconst.h"
#include "bmsimd.h"
#include "bmfwd.h"
# define BM_DECLARE_TEMP_BLOCK(x) bm::bit_block_t x;
#include "bmfunc.h"
#include "encoding.h"
#include "bmalloc.h"
#include "bmblocks.h"
#include "bmbuffer.h"
#include "bmdef.h"
#include "bmrs.h"
extern "C"
{
#ifdef BM64ADDR
typedef int (*bit_visitor_callback_type)(void* handle_ptr, bm::id64_t bit_idx);
#else
/**
Callback type to visit (callback style) bits in bit-vector(s)
@param handle_ptr - custom pointer to callback specific data
@param bit_idx - number/index of visited bit
@return negative return code is recognised as a request to interrupt visiting
@ingroup bvector
*/
typedef int (*bit_visitor_callback_type)(void* handle_ptr, bm::id_t bit_idx);
#endif
}
namespace bm
{
/** @defgroup bmagic BitMagic Library
BitMagic C++ Library
For more information please visit: http://bitmagic.io
*/
/** @defgroup bvector bvector<> container
The Main bvector<> Group
bvector<> template: front end of the BitMagic library.
@ingroup bmagic
*/
/** @defgroup bvit bvector<> iterators
Iterators for compressed bit-vector traversal
@ingroup bvector
*/
#ifdef BM64ADDR
typedef bm::id64_t bvector_size_type;
#else
typedef bm::id_t bvector_size_type;
#endif
/*!
@brief Bitvector
Bit-vector container with runtime compression of bits
@ingroup bvector
*/
template<class Alloc>
class bvector
{
public:
typedef Alloc allocator_type;
typedef typename allocator_type::allocator_pool_type allocator_pool_type;
typedef blocks_manager<Alloc> blocks_manager_type;
typedef typename blocks_manager_type::block_idx_type block_idx_type;
typedef bvector_size_type size_type;
/** Statistical information about bitset's memory allocation details. */
struct statistics : public bv_statistics
{};
/*!
\brief Optimization mode
Every next level means additional checks (better compression vs time)
\sa optimize
*/
enum optmode
{
opt_none = 0, ///< no optimization
opt_free_0 = 1, ///< Free unused 0 blocks
opt_free_01 = 2, ///< Free unused 0 and 1 blocks
opt_compress = 3 ///< compress blocks when possible (GAP/prefix sum)
};
/**
@brief Class reference implements an object for bit assignment.
Since C++ does not provide with build-in bit type supporting l-value
operations we have to emulate it.
@ingroup bvector
*/
class reference
{
public:
reference(bvector<Alloc>& bv, size_type position) BMNOEXCEPT
: bv_(bv),
position_(position)
{}
reference(const reference& ref) BMNOEXCEPT
: bv_(ref.bv_),
position_(ref.position_)
{
bv_.set(position_, ref.bv_.get_bit(position_));
}
operator bool() const BMNOEXCEPT
{
return bv_.get_bit(position_);
}
const reference& operator=(const reference& ref) const
{
bv_.set(position_, (bool)ref);
return *this;
}
const reference& operator=(bool value) const BMNOEXCEPT
{
bv_.set(position_, value);
return *this;
}
bool operator==(const reference& ref) const BMNOEXCEPT
{
return bool(*this) == bool(ref);
}
/*! Bitwise AND. Performs operation: bit = bit AND value */
const reference& operator&=(bool value) const
{
bv_.set_bit_and(position_, value);
return *this;
}
/*! Bitwise OR. Performs operation: bit = bit OR value */
const reference& operator|=(bool value) const
{
if (value != bv_.get_bit(position_))
{
bv_.set_bit(position_);
}
return *this;
}
/*! Bitwise exclusive-OR (XOR). Performs operation: bit = bit XOR value */
const reference& operator^=(bool value) const
{
bv_.set(position_, value != bv_.get_bit(position_));
return *this;
}
/*! Logical Not operator */
bool operator!() const BMNOEXCEPT
{
return !bv_.get_bit(position_);
}
/*! Bit Not operator */
bool operator~() const BMNOEXCEPT
{
return !bv_.get_bit(position_);
}
/*! Negates the bit value */
reference& flip()
{
bv_.flip(position_);
return *this;
}
private:
bvector<Alloc>& bv_; //!< Reference variable on the parent.
size_type position_; //!< Position in the parent bitvector.
};
typedef bool const_reference;
/*!
@brief Base class for all iterators.
@ingroup bvit
*/
class iterator_base
{
friend class bvector;
public:
iterator_base() BMNOEXCEPT
: bv_(0), position_(bm::id_max), block_(0), block_type_(0),
block_idx_(0)
{}
bool operator==(const iterator_base& it) const BMNOEXCEPT
{
return (position_ == it.position_) && (bv_ == it.bv_);
}
bool operator!=(const iterator_base& it) const BMNOEXCEPT
{
return ! operator==(it);
}
bool operator < (const iterator_base& it) const BMNOEXCEPT
{
return position_ < it.position_;
}
bool operator <= (const iterator_base& it) const BMNOEXCEPT
{
return position_ <= it.position_;
}
bool operator > (const iterator_base& it) const BMNOEXCEPT
{
return position_ > it.position_;
}
bool operator >= (const iterator_base& it) const BMNOEXCEPT
{
return position_ >= it.position_;
}
/**
\fn bool bm::bvector::iterator_base::valid() const
\brief Checks if iterator is still valid. Analog of != 0 comparison for pointers.
\returns true if iterator is valid.
*/
bool valid() const BMNOEXCEPT { return position_ != bm::id_max; }
/**
\fn bool bm::bvector::iterator_base::invalidate()
\brief Turns iterator into an invalid state.
*/
void invalidate() BMNOEXCEPT
{ position_ = bm::id_max; block_type_ = ~0u;}
/** \brief Compare FSMs for testing purposes
\internal
*/
bool compare_state(const iterator_base& ib) const BMNOEXCEPT
{
if (this->bv_ != ib.bv_) return false;
if (this->position_ != ib.position_) return false;
if (this->block_ != ib.block_) return false;
if (this->block_type_ != ib.block_type_) return false;
if (this->block_idx_ != ib.block_idx_) return false;
const block_descr& bd = this->bdescr_;
const block_descr& ib_db = ib.bdescr_;
if (this->block_type_ == 0) // bit block
{
if (bd.bit_.ptr != ib_db.bit_.ptr) return false;
if (bd.bit_.idx != ib_db.bit_.idx) return false;
if (bd.bit_.cnt != ib_db.bit_.cnt) return false;
if (bd.bit_.pos != ib_db.bit_.pos) return false;
for (unsigned i = 0; i < bd.bit_.cnt; ++i)
{
if (bd.bit_.bits[i] != ib_db.bit_.bits[i]) return false;
}
}
else // GAP block
{
if (bd.gap_.ptr != ib_db.gap_.ptr) return false;
if (bd.gap_.gap_len != ib_db.gap_.gap_len) return false;
}
return true;
}
public:
/** Bit-block descriptor
@internal
*/
struct bitblock_descr
{
const bm::word_t* ptr; //!< Word pointer.
unsigned char bits[set_bitscan_wave_size*32]; //!< bit list
unsigned short idx; //!< Current position in the bit list
unsigned short cnt; //!< Number of ON bits
size_type pos; //!< Last bit position decode before
};
/** Information about current DGAP block.
@internal
*/
struct dgap_descr
{
const gap_word_t* ptr; //!< Word pointer.
gap_word_t gap_len; //!< Current dgap length.
};
protected:
bm::bvector<Alloc>* bv_; //!< Pointer on parent bitvector
size_type position_; //!< Bit position (bit idx)
const bm::word_t* block_; //!< Block pointer.(NULL-invalid)
unsigned block_type_; //!< Type of block. 0-Bit, 1-GAP
block_idx_type block_idx_; //!< Block index
/*! Block type dependent information for current block. */
union block_descr
{
bitblock_descr bit_; //!< BitBlock related info.
dgap_descr gap_; //!< DGAP block related info.
} bdescr_;
};
/*!
@brief Output iterator iterator designed to set "ON" bits based on
input sequence of integers (bit indeces).
STL container can be converted to bvector using this iterator
Insert iterator guarantees the vector will be dynamically resized
(set_bit does not do that).
@note
If you have many bits to set it is a good idea to use output iterator
instead of explicitly calling set, because iterator may implement
some performance specific tricks to make sure bulk insert is fast.
@sa bulk_insert_iterator
@ingroup bvit
*/
class insert_iterator
{
friend class bulk_insert_iterator;
public:
#ifndef BM_NO_STL
typedef std::output_iterator_tag iterator_category;
#endif
typedef bm::bvector<Alloc> bvector_type;
typedef size_type value_type;
typedef void difference_type;
typedef void pointer;
typedef void reference;
insert_iterator() BMNOEXCEPT : bvect_(0), max_bit_(0) {}
insert_iterator(bvector<Alloc>& bvect) BMNOEXCEPT
: bvect_(&bvect),
max_bit_(bvect.size())
{
bvect_->init();
}
insert_iterator(const insert_iterator& iit)
: bvect_(iit.bvect_),
max_bit_(iit.max_bit_)
{
}
insert_iterator& operator=(const insert_iterator& ii)
{
bvect_ = ii.bvect_; max_bit_ = ii.max_bit_;
return *this;
}
insert_iterator& operator=(size_type n)
{
BM_ASSERT(n < bm::id_max);
BM_ASSERT_THROW(n < bm::id_max, BM_ERR_RANGE);
if (n >= max_bit_)
{
max_bit_ = n;
if (n >= bvect_->size())
{
size_type new_size = (n == bm::id_max) ? bm::id_max : n + 1;
bvect_->resize(new_size);
}
}
bvect_->set_bit_no_check(n);
return *this;
}
/*! Returns *this without doing anything (no-op) */
insert_iterator& operator*() { return *this; }
/*! Returns *this. This iterator does not move (no-op) */
insert_iterator& operator++() { return *this; }
/*! Returns *this. This iterator does not move (no-op)*/
insert_iterator& operator++(int) { return *this; }
bvector_type* get_bvector() const { return bvect_; }
protected:
bvector_type* bvect_;
size_type max_bit_;
};
/*!
@brief Output iterator iterator designed to set "ON" bits based on
input sequence of integers.
STL container can be converted to bvector using this iterator
Insert iterator guarantees the vector will be dynamically resized
(set_bit does not do that).
The difference from the canonical insert iterator, is that
bulk insert implements internal buffering, which needs
to flushed (or flushed automatically when goes out of scope).
Buffering creates a delayed effect, which needs to be
taken into account.
@sa insert_iterator
@ingroup bvit
*/
class bulk_insert_iterator
{
public:
#ifndef BM_NO_STL
typedef std::output_iterator_tag iterator_category;
#endif
typedef bm::bvector<Alloc> bvector_type;
typedef bvector_type::size_type size_type;
typedef bvector_type::size_type value_type;
typedef void difference_type;
typedef void pointer;
typedef void reference;
bulk_insert_iterator() BMNOEXCEPT
: bvect_(0), buf_(0), buf_size_(0), sorted_(BM_UNKNOWN) {}
~bulk_insert_iterator()
{
flush();
if (buf_)
bvect_->blockman_.get_allocator().free_bit_block((bm::word_t*)buf_);
}
bulk_insert_iterator(bvector<Alloc>& bvect,
bm::sort_order so = BM_UNKNOWN) BMNOEXCEPT
: bvect_(&bvect), sorted_(so)
{
bvect_->init();
buf_ = (value_type*) bvect_->blockman_.get_allocator().alloc_bit_block();
buf_size_ = 0;
}
bulk_insert_iterator(const bulk_insert_iterator& iit)
: bvect_(iit.bvect_)
{
buf_ = bvect_->blockman_.get_allocator().alloc_bit_block();
buf_size_ = iit.buf_size_;
sorted_ = iit.sorted_;
::memcpy(buf_, iit.buf_, buf_size_ * sizeof(*buf_));
}
bulk_insert_iterator(const insert_iterator& iit)
: bvect_(iit.get_bvector())
{
buf_ = (value_type*) bvect_->blockman_.get_allocator().alloc_bit_block();
buf_size_ = 0;
sorted_ = BM_UNKNOWN;
}
bulk_insert_iterator(bulk_insert_iterator&& iit) BMNOEXCEPT
: bvect_(iit.bvect_)
{
buf_ = iit.buf_; iit.buf_ = 0;
buf_size_ = iit.buf_size_;
sorted_ = iit.sorted_;
}
bulk_insert_iterator& operator=(const bulk_insert_iterator& ii)
{
bvect_ = ii.bvect_;
if (!buf_)
buf_ = bvect_->allocate_tempblock();
buf_size_ = ii.buf_size_;
::memcpy(buf_, ii.buf_, buf_size_ * sizeof(*buf_));
sorted_ = ii.sorted_;
return *this;
}
bulk_insert_iterator& operator=(bulk_insert_iterator&& ii) BMNOEXCEPT
{
bvect_ = ii.bvect_;
if (buf_)
bvect_->free_tempblock(buf_);
buf_ = ii.buf_; ii.buf_ = 0;
buf_size_ = ii.buf_size_;
sorted_ = ii.sorted_;
return *this;
}
bulk_insert_iterator& operator=(size_type n)
{
BM_ASSERT(n < bm::id_max);
BM_ASSERT_THROW(n < bm::id_max, BM_ERR_RANGE);
if (buf_size_ == buf_size_max())
{
bvect_->import(buf_, buf_size_, sorted_);
buf_size_ = 0;
}
buf_[buf_size_++] = n;
return *this;
}
/*! Returns *this without doing anything (no-op) */
bulk_insert_iterator& operator*() { return *this; }
/*! Returns *this. This iterator does not move (no-op) */
bulk_insert_iterator& operator++() { return *this; }
/*! Returns *this. This iterator does not move (no-op)*/
bulk_insert_iterator& operator++(int) { return *this; }
/*! Flush the internal buffer into target bvector */
void flush()
{
BM_ASSERT(bvect_);
if (buf_size_)
{
bvect_->import(buf_, buf_size_, sorted_);
buf_size_ = 0;
}
bvect_->sync_size();
}
bvector_type* get_bvector() const BMNOEXCEPT { return bvect_; }
protected:
static
size_type buf_size_max() BMNOEXCEPT
{
#ifdef BM64ADDR
return bm::set_block_size / 2;
#else
return bm::set_block_size;
#endif
}
protected:
bvector_type* bvect_; ///< target bvector
size_type* buf_; ///< bulk insert buffer
size_type buf_size_; ///< current buffer size
bm::sort_order sorted_; ///< sort order hint
};
/*! @brief Constant iterator designed to enumerate "ON" bits
@ingroup bvit
*/
class enumerator : public iterator_base
{
public:
#ifndef BM_NO_STL
typedef std::input_iterator_tag iterator_category;
#endif
typedef size_type value_type;
typedef unsigned difference_type;
typedef unsigned* pointer;
typedef unsigned& reference;
public:
enumerator() BMNOEXCEPT : iterator_base()
{}
/*! @brief Construct enumerator associated with a vector.
Important: This construction creates unpositioned iterator with status
valid() == false. It can be re-positioned using go_first() or go_to().
@sa go_to
*/
enumerator(const bvector<Alloc>* bv) BMNOEXCEPT
: iterator_base()
{
this->bv_ = const_cast<bvector<Alloc>*>(bv);
}
/*! @brief Construct enumerator for bit vector
@param bv bit-vector reference
@param pos bit position in the vector
if position is 0, it finds the next 1 or becomes not valid
(en.valid() == false)
*/
enumerator(const bvector<Alloc>& bv, size_type pos = 0) BMNOEXCEPT
: iterator_base()
{
this->bv_ = const_cast<bvector<Alloc>*>(&bv);
go_to(pos);
}
/*! @brief Construct enumerator for bit vector
@param bv bit-vector pointer
@param pos bit position in the vector
if position is 0, it finds the next 1 or becomes not valid
(en.valid() == false)
*/
enumerator(const bvector<Alloc>* bv, size_type pos) BMNOEXCEPT
: iterator_base()
{
this->bv_ = const_cast<bvector<Alloc>*>(bv);
this->go_to(pos);
}
/*! \brief Get current position (value) */
size_type operator*() const BMNOEXCEPT { return this->position_; }
/*! \brief Get current position (value) */
size_type value() const BMNOEXCEPT { return this->position_; }
/*! \brief Advance enumerator forward to the next available bit */
enumerator& operator++() BMNOEXCEPT { this->go_up(); return *this; }
/*! \brief Advance enumerator forward to the next available bit.
Possibly do NOT use this operator it is slower than the pre-fix increment.
*/
enumerator operator++(int) BMNOEXCEPT
{
enumerator tmp = *this;
this->go_up();
return tmp;
}
/*! \brief Position enumerator to the first available bit */
void go_first() BMNOEXCEPT;
/*! advance iterator forward by one
@return true if advance was successfull and the enumerator is valid
*/
bool advance() BMNOEXCEPT { return this->go_up(); }
/*! \brief Advance enumerator to the next available bit */
bool go_up() BMNOEXCEPT;
/*!
@brief Skip to specified relative rank
@param rank - number of ON bits to go for (must be: > 0)
@return true if skip was successfull and enumerator is valid
*/
bool skip_to_rank(size_type rank) BMNOEXCEPT
{
BM_ASSERT(rank);
--rank;
if (!rank)
return this->valid();
return skip(rank);
}
/*!
@brief Skip specified number of bits from enumeration
@param rank - number of ON bits to skip
@return true if skip was successfull and enumerator is valid
*/
bool skip(size_type rank) BMNOEXCEPT;
/*!
@brief go to a specific position in the bit-vector (or next)
*/
bool go_to(size_type pos) BMNOEXCEPT;
private:
typedef typename iterator_base::block_descr block_descr_type;
static bool decode_wave(block_descr_type* bdescr) BMNOEXCEPT;
bool decode_bit_group(block_descr_type* bdescr) BMNOEXCEPT;
bool decode_bit_group(block_descr_type* bdescr,
size_type& rank) BMNOEXCEPT;
bool search_in_bitblock() BMNOEXCEPT;
bool search_in_gapblock() BMNOEXCEPT;
bool search_in_blocks() BMNOEXCEPT;
};
/*!
@brief Constant iterator designed to enumerate "ON" bits
counted_enumerator keeps bitcount, ie number of ON bits starting
from the position 0 in the bit string up to the currently enumerated bit
When increment operator called current position is increased by 1.
@ingroup bvit
*/
class counted_enumerator : public enumerator
{
public:
#ifndef BM_NO_STL
typedef std::input_iterator_tag iterator_category;
#endif
counted_enumerator() BMNOEXCEPT : bit_count_(0){}
counted_enumerator(const enumerator& en) BMNOEXCEPT : enumerator(en)
{
bit_count_ = this->valid(); // 0 || 1
}
counted_enumerator& operator=(const enumerator& en) BMNOEXCEPT
{
enumerator* me = this;
*me = en;
if (this->valid())
this->bit_count_ = 1;
return *this;
}
counted_enumerator& operator++() BMNOEXCEPT
{
this->go_up();
this->bit_count_ += this->valid();
return *this;
}
counted_enumerator operator++(int)
{
counted_enumerator tmp(*this);
this->go_up();
this->bit_count_ += this->valid();
return tmp;
}
/*! @brief Number of bits ON starting from the .
Method returns number of ON bits fromn the bit 0 to the current bit
For the first bit in bitvector it is 1, for the second 2
*/
size_type count() const BMNOEXCEPT { return bit_count_; }
private:
/*! Function closed for usage */
counted_enumerator& go_to(size_type pos);
private:
size_type bit_count_;
};
/*!
Resource guard for bvector<>::set_allocator_pool()
@ingroup bvector
@internal
*/
typedef
bm::alloc_pool_guard<allocator_pool_type, bvector<Alloc> > mem_pool_guard;
friend class iterator_base;
friend class enumerator;
template<class BV> friend class aggregator;
template<class BV> friend class operation_deserializer;
template<class BV, class DEC> friend class deserializer;
public:
/*! @brief memory allocation policy
Defualt memory allocation policy uses BM_BIT, and standard
GAP levels tune-ups
*/
struct allocation_policy
{
bm::strategy strat;
const gap_word_t* glevel_len;
allocation_policy(bm::strategy s=BM_BIT,
const gap_word_t* glevels = bm::gap_len_table<true>::_len) BMNOEXCEPT
: strat(s), glevel_len(glevels)
{}
};
typedef rs_index<allocator_type> blocks_count;
typedef rs_index<allocator_type> rs_index_type;
public:
/*! @name Construction, initialization, assignment */
//@{
/*!
\brief Constructs bvector class
\param strat - operation mode strategy,
BM_BIT - default strategy, bvector use plain bitset
blocks, (performance oriented strategy).
BM_GAP - memory effitent strategy, bvector allocates
blocks as array of intervals(gaps) and convert blocks
into plain bitsets only when enthropy grows.
\param glevel_len
- pointer on C-style array keeping GAP block sizes.
bm::gap_len_table<true>::_len - default value set
(use bm::gap_len_table_min<true>::_len for very sparse vectors)
(use bm::gap_len_table_nl<true>::_len non-linear GAP growth)
\param bv_size
- bvector size (number of bits addressable by bvector), bm::id_max means
"no limits" (recommended).
bit vector allocates this space dynamically on demand.
\param alloc - alllocator for this instance
\sa bm::gap_len_table bm::gap_len_table_min set_new_blocks_strat
*/
bvector(strategy strat = BM_BIT,
const gap_word_t* glevel_len = bm::gap_len_table<true>::_len,
size_type bv_size = bm::id_max,
const Alloc& alloc = Alloc())
: blockman_(glevel_len, bv_size, alloc),
new_blocks_strat_(strat),
size_(bv_size)
{}
/*!
\brief Constructs bvector class
*/
bvector(size_type bv_size,
strategy strat = BM_BIT,
const gap_word_t* glevel_len = bm::gap_len_table<true>::_len,
const Alloc& alloc = Alloc())
: blockman_(glevel_len, bv_size, alloc),
new_blocks_strat_(strat),
size_(bv_size)
{}
/*!
\brief Copy constructor
*/
bvector(const bvector<Alloc>& bvect)
: blockman_(bvect.blockman_),
new_blocks_strat_(bvect.new_blocks_strat_),
size_(bvect.size_)
{}
/*!
\brief Copy constructor for range copy [left..right]
\sa copy_range
*/
bvector(const bvector<Alloc>& bvect, size_type left, size_type right)
: blockman_(bvect.blockman_.glevel_len_, bvect.blockman_.max_bits_, bvect.blockman_.alloc_),
new_blocks_strat_(bvect.new_blocks_strat_),
size_(bvect.size_)
{
if (!bvect.blockman_.is_init())
return;
if (left > right)
bm::xor_swap(left, right);
copy_range_no_check(bvect, left, right);
}
/*!
\brief Copy-constructor for mutable/immutable initialization
*/
bvector(const bvector<Alloc>& bvect, bm::finalization is_final)
: blockman_(bvect.blockman_.glevel_len_, bvect.blockman_.max_bits_, bvect.blockman_.alloc_),
new_blocks_strat_(bvect.new_blocks_strat_),
size_(bvect.size_)
{
if (!bvect.blockman_.is_init())
return;
if (is_final == bm::finalization::READONLY)
blockman_.copy_to_arena(bvect.blockman_);
else
blockman_.copy(bvect.blockman_);
}
~bvector() BMNOEXCEPT {}
/*!
\brief Explicit post-construction initialization.
Must be caled to make sure safe use of *_no_check() methods
*/
void init();
/*!
\brief Explicit post-construction initialization.
Must be caled right after construction strickly before any modificating calls
to make sure safe use of *_no_check() methods.
This init can do pre-allocation of top level structures.
@param top_size - request to do pre-allocation of the top level of a sparse bit-vector tree
(can be up to 256 for 32-bit mode)
@param alloc_subs - if true also allocates second level structures
*/
void init(unsigned top_size, bool alloc_subs);
/*!
\brief Copy assignment operator
*/
bvector& operator=(const bvector<Alloc>& bvect)
{
this->copy(bvect, bm::finalization::UNDEFINED);
return *this;
}
#ifndef BM_NO_CXX11
/*!
\brief Move constructor
*/
bvector(bvector<Alloc>&& bvect) BMNOEXCEPT
{
blockman_.move_from(bvect.blockman_);
size_ = bvect.size_;
new_blocks_strat_ = bvect.new_blocks_strat_;
}
/*!
\brief Brace constructor
*/
bvector(std::initializer_list<size_type> il)
: blockman_(bm::gap_len_table<true>::_len, bm::id_max, Alloc()),
new_blocks_strat_(BM_BIT),
size_(bm::id_max)
{
init();
std::initializer_list<size_type>::const_iterator it_start = il.begin();
std::initializer_list<size_type>::const_iterator it_end = il.end();
for (; it_start < it_end; ++it_start)
this->set_bit_no_check(*it_start);
}
/*!
\brief Move assignment operator
*/
bvector& operator=(bvector<Alloc>&& bvect) BMNOEXCEPT
{
this->move_from(bvect);
return *this;
}
#endif
/*!
\brief Copy bvector from the argument bvector
\param bvect - bit-vector to copy from
\param is_final - BM_READONLY - copies as immutable, BM_READWRITE - copies as mutable
even if the argument bvect is read-only vector,
BM_UNDEFINED - follow the argument type as is
*/
void copy(const bvector<Alloc>& bvect, bm::finalization is_final);
/*!
\brief Move bvector content from another bvector
*/
void move_from(bvector<Alloc>& bvect) BMNOEXCEPT;
/*! \brief Exchanges content of bv and this bvector.
*/
void swap(bvector<Alloc>& bvect) BMNOEXCEPT;
/*! \brief Merge/move content from another vector
Merge performs a logical OR operation, but the source vector
is not immutable. Source content gets destroyed (memory moved)
to create a union of two vectors.
Merge operation can be more efficient than OR if argument is
a temporary vector.
@param bvect - [in, out] - source vector (NOT immutable)
*/
void merge(bm::bvector<Alloc>& bvect);
//@}
reference operator[](size_type n)
{
if (n >= size_)
{
size_type new_size = (n == bm::id_max) ? bm::id_max : n + 1;
resize(new_size);
}
return reference(*this, n);
}
bool operator[](size_type n) const BMNOEXCEPT
{
BM_ASSERT(n < size_);
return get_bit(n);
}
void operator &= (const bvector<Alloc>& bv) { bit_and(bv); }
void operator ^= (const bvector<Alloc>& bv) { bit_xor(bv); }
void operator |= (const bvector<Alloc>& bv) { bit_or(bv); }
void operator -= (const bvector<Alloc>& bv) { bit_sub(bv); }
bool operator < (const bvector<Alloc>& bv) const { return compare(bv)<0; }
bool operator <= (const bvector<Alloc>& bv) const { return compare(bv)<=0; }
bool operator > (const bvector<Alloc>& bv) const { return compare(bv)>0; }
bool operator >= (const bvector<Alloc>& bv) const { return compare(bv) >= 0; }
bool operator == (const bvector<Alloc>& bv) const BMNOEXCEPT { return equal(bv); }
bool operator != (const bvector<Alloc>& bv) const BMNOEXCEPT { return !equal(bv); }
bvector<Alloc> operator~() const { return bvector<Alloc>(*this).invert(); }
Alloc get_allocator() const
{ return blockman_.get_allocator(); }
/// Set allocator pool for local (non-th readed)
/// memory cyclic(lots of alloc-free ops) opertations
///
void set_allocator_pool(allocator_pool_type* pool_ptr) BMNOEXCEPT
{ blockman_.get_allocator().set_pool(pool_ptr); }
/// Get curent allocator pool (if set)
/// @return pointer to the current pool or NULL
allocator_pool_type* get_allocator_pool() BMNOEXCEPT
{ return blockman_.get_allocator().get_pool(); }
// --------------------------------------------------------------------
/*! @name Read-only / immutable vector methods */
//@{
/// Turn current vector to read-only (immutable vector).
/// After calling this method any modification (non-const methods) will cause undefined behavior
/// (likely crash or assert)
///
/// \sa is_ro
void freeze();
/// Returns true if vector is read-only
bool is_ro() const BMNOEXCEPT { return blockman_.arena_; }
//@}
// --------------------------------------------------------------------
/*! @name Bit access/modification methods */
//@{
/*!
\brief Sets bit n.
\param n - index of the bit to be set.
\param val - new bit value
\return TRUE if bit was changed
*/
bool set_bit(size_type n, bool val = true);
/*!
\brief Sets bit n using bit AND with the provided value.
\param n - index of the bit to be set.
\param val - new bit value
\return TRUE if bit was changed
*/
bool set_bit_and(size_type n, bool val = true);
/*!
\brief Increment the specified element
Bit increment rules:
0 + 1 = 1 (no carry over)
1 + 1 = 0 (with carry over returned)
\param n - index of the bit to be set
\return TRUE if carry over created (1+1)
*/
bool inc(size_type n);
/*!
\brief Sets bit n only if current value equals the condition
\param n - index of the bit to be set.
\param val - new bit value
\param condition - expected current value
\return TRUE if bit was changed
*/
bool set_bit_conditional(size_type n, bool val, bool condition);
/*!
\brief Sets bit n if val is true, clears bit n if val is false
\param n - index of the bit to be set
\param val - new bit value
\return *this
*/
bvector<Alloc>& set(size_type n, bool val = true);
/*!
\brief Sets every bit in this bitset to 1.
\return *this
*/
bvector<Alloc>& set();
/*!
\brief Set list of bits in this bitset to 1.
Method implements optimized bulk setting of multiple bits at once.
The best results are achieved when the imput comes sorted.
This is equivalent of OR (Set Union), argument set as an array.
@param ids - pointer on array of indexes to set
@param ids_size - size of the input (ids)
@param so - sort order (use BM_SORTED for faster load)
@sa keep, clear
*/
void set(const size_type* ids, size_type ids_size,
bm::sort_order so=bm::BM_UNKNOWN);
/*!
\brief Keep list of bits in this bitset, others are cleared
This is equivalent of AND (Set Intersect), argument set as an array.
@param ids - pointer on array of indexes to set
@param ids_size - size of the input (ids)
@param so - sort order (use BM_SORTED for faster load)
@sa set, clear
*/
void keep(const size_type* ids, size_type ids_size,
bm::sort_order so=bm::BM_UNKNOWN);
/*!
\brief clear list of bits in this bitset
This is equivalent of AND NOT (Set Substract), argument set as an array.
@param ids - pointer on array of indexes to set
@param ids_size - size of the input (ids)
@param so - sort order (use BM_SORTED for faster load)
@sa set, keep
*/
void clear(const size_type* ids, size_type ids_size,
bm::sort_order so=bm::BM_UNKNOWN);
/*!
\brief swap values of bits
@param idx1 - index of bit to swap with
@param idx2 - index of bit to swap with
*/
void swap(size_type idx1, size_type idx2);
/*!
\brief Set bit without checking preconditions (size, etc)
Fast set bit method, without safety net.
Make sure you call bvector<>::init() before setting bits with this
function.
\param n - bit number
*/
void set_bit_no_check(size_type n);
/**
\brief Set specified bit without checking preconditions (size, etc)
*/
bool set_bit_no_check(size_type n, bool val);
/*!
\brief Sets all bits in the specified closed interval [left,right]
Interval must be inside the bvector's size.
This method DOES NOT resize vector.
\param left - interval start
\param right - interval end (closed interval)
\param value - value to set interval in
\return *this
@sa clear_range
*/
bvector<Alloc>& set_range(size_type left,
size_type right,
bool value = true);
/*!
\brief Sets all bits to zero in the specified closed interval [left,right]
Interval must be inside the bvector's size.
This method DOES NOT resize vector.
\param left - interval start
\param right - interval end (closed interval)
@sa set_range
*/
void clear_range(size_type left, size_type right)
{ set_range(left, right, false); }
/*!
\brief Sets all bits to zero outside of the closed interval [left,right]
Expected result: 00000...0[left, right]0....0000
\param left - interval start
\param right - interval end (closed interval)
@sa set_range
*/
void keep_range(size_type left, size_type right);
/*!
\brief Copy all bits in the specified closed interval [left,right]
\param bvect - source bit-vector
\param left - interval start
\param right - interval end (closed interval)
*/
void copy_range(const bvector<Alloc>& bvect,
size_type left,
size_type right);
/*!
\brief Clears bit n.
\param n - bit's index to be cleaned.
\return true if bit was cleared
*/
bool clear_bit(size_type n) { return set_bit(n, false); }
/*!
\brief Clears bit n without precondiion checks
\param n - bit's index to be cleaned.
*/
void clear_bit_no_check(size_type n);
/*!
\brief Clears every bit in the bitvector.
\param free_mem if "true" (default) bvector frees the memory,
otherwise sets blocks to 0.
*/
void clear(bool free_mem = true) BMNOEXCEPT;
/*!
\brief Clears every bit in the bitvector.
\return *this;
*/
bvector<Alloc>& reset() BMNOEXCEPT { clear(true); return *this; }
/*!
\brief Flips bit n
\return *this
*/
bvector<Alloc>& flip(size_type n) { this->inc(n); return *this; }
/*!
\brief Flips all bits
\return *this
@sa invert
*/
bvector<Alloc>& flip() { return invert(); }
//@}
// --------------------------------------------------------------------
/*! Function erturns insert iterator for this bitvector */
insert_iterator inserter() { return insert_iterator(*this); }
// --------------------------------------------------------------------
/*! @name Size and capacity
By default bvector is dynamically sized, manual control methods
available
*/
//@{
/** \brief Returns bvector's capacity (number of bits it can store) */
//size_type capacity() const { return blockman_.capacity(); }
/*! \brief return current size of the vector (bits) */
size_type size() const BMNOEXCEPT { return size_; }
/*!
\brief Change size of the bvector
\param new_size - new size in bits
*/
void resize(size_type new_size);
//@}
// --------------------------------------------------------------------
/*! @name Population counting, ranks, ranges and intervals
*/
//@{
/*!
\brief population count (count of ON bits)
\sa count_range
\return Total number of bits ON
*/
size_type count() const BMNOEXCEPT;
/*! \brief Computes bitcount values for all bvector blocks
\param arr - pointer on array of block bit counts
\return Index of the last block counted.
This number +1 gives you number of arr elements initialized during the
function call.
*/
block_idx_type count_blocks(unsigned* arr) const BMNOEXCEPT;
/*!
\brief Returns count of 1 bits in the given range [left..right]
Uses rank-select index to accelerate the search
\param left - index of first bit start counting from
\param right - index of last bit
\param rs_idx - block count structure to accelerate search
\sa build_rs_index
\return population count in the diapason
*/
size_type count_range(size_type left,
size_type right,
const rs_index_type& rs_idx) const BMNOEXCEPT;
/*!
\brief Returns count of 1 bits in the given range [left..right]
\param left - index of first bit start counting from
\param right - index of last bit
\return population count in the diapason
@sa count_range_no_check
*/
size_type count_range(size_type left, size_type right) const BMNOEXCEPT;
/*!
Returns count of 1 bits in the given range [left..right]
Function expects that caller guarantees that left < right
@sa count_range
*/
size_type count_range_no_check(size_type left, size_type right) const BMNOEXCEPT;
/*!
Returns count of 1 bits in the given range [left..right]
Function expects that caller guarantees that left < right
@sa count_range
*/
size_type count_range_no_check(size_type left,
size_type right,
const rs_index_type& rs_idx) const BMNOEXCEPT;
/*!
\brief Returns true if all bits in the range are 1s (saturated interval)
Function uses closed interval [left, right]
\param left - index of first bit start checking
\param right - index of last bit
\return true if all bits are 1, false otherwise
@sa any_range, count_range
*/
bool is_all_one_range(size_type left, size_type right) const BMNOEXCEPT;
/*!
\brief Returns true if any bits in the range are 1s (non-empty interval)
Function uses closed interval [left, right]
\param left - index of first bit start checking
\param right - index of last bit
\return true if at least 1 bits is set
@sa is_all_one_range, count_range
*/
bool any_range(size_type left, size_type right) const BMNOEXCEPT;
/*! \brief compute running total of all blocks in bit vector (rank-select index)
\param rs_idx - [out] pointer to index / count structure
\param bv_blocks - [out] list of block ids in the vector (internal, optional)
Function will fill full array of running totals
\sa count_to, select, find_rank
*/
void build_rs_index(rs_index_type* rs_idx, bvector<Alloc>* bv_blocks=0) const;
/*!
\brief Returns count of 1 bits (population) in [0..right] range.
This operation is also known as rank of bit N.
\param n - index of bit to rank
\param rs_idx - rank-select to accelerate search
should be prepared using build_rs_index
\return population count in the range [0..n]
\sa build_rs_index
\sa count_to_test, select, rank, rank_corrected
*/
size_type count_to(size_type n,
const rs_index_type& rs_idx) const BMNOEXCEPT;
/*!
\brief Returns rank of specified bit position (same as count_to())
\param n - index of bit to rank
\param rs_idx - rank-select index
\return population count in the range [0..n]
\sa build_rs_index
\sa count_to_test, select, rank, rank_corrected
*/
size_type rank(size_type n,
const rs_index_type& rs_idx) const BMNOEXCEPT
{ return count_to(n, rs_idx); }
/*!
\brief Returns rank corrceted by the requested border value (as -1)
This is rank function (bit-count) minus value of bit 'n'
if bit-n is true function returns rank()-1 if false returns rank()
faster than rank() + test().
\param n - index of bit to rank
\param rs_idx - rank-select index
\return population count in the range [0..n] corrected as -1 by the value of n
\sa build_rs_index
\sa count_to_test, select, rank
*/
size_type rank_corrected(size_type n,
const rs_index_type& rs_idx) const BMNOEXCEPT;
/*!
\brief popcount in [0..right] range if test(right) == true
This is conditional rank operation, which is faster than test()
plus count_to()
\param n - index of bit to test and rank
\param rs_idx - rank-select index
(block count structure to accelerate search)
should be prepared using build_rs_index()
\return population count in the diapason or 0 if right bit test failed
\sa build_rs_index
\sa count_to
*/
size_type
count_to_test(size_type n,
const rs_index_type& rs_idx) const BMNOEXCEPT;
/*! Recalculate bitcount (deprecated)
*/
size_type recalc_count() BMNOEXCEPT { return count(); }
/*!
Disables count cache. (deprecated).
*/
void forget_count() BMNOEXCEPT {}
//@}
// --------------------------------------------------------------------
/*! @name Bit access (read-only) */
//@{
/*!
\brief returns true if bit n is set and false is bit n is 0.
\param n - Index of the bit to check.
\return Bit value (1 or 0)
*/
bool get_bit(size_type n) const BMNOEXCEPT;
/*!
\brief returns true if bit n is set and false is bit n is 0.
\param n - Index of the bit to check.
\return Bit value (1 or 0)
*/
bool test(size_type n) const BMNOEXCEPT { return get_bit(n); }
//@}
// --------------------------------------------------------------------
/*! @name bit-shift and insert operations */
//@{
/*!
\brief Shift right by 1 bit, fill with zero return carry out
\return Carry over bit value (1 or 0)
*/
bool shift_right();
/*!
\brief Shift left by 1 bit, fill with zero return carry out
\return Carry over bit value (1 or 0)
*/
bool shift_left();
/*!
\brief Insert bit into specified position
All the vector content after insert position is shifted right.
\param n - index of the bit to insert
\param value - insert value
\return Carry over bit value (1 or 0)
*/
bool insert(size_type n, bool value);
/*!
\brief Erase bit in the specified position
All the vector content after erase position is shifted left.
\param n - index of the bit to insert
*/
void erase(size_type n);
//@}
// --------------------------------------------------------------------
/*! @name Check for empty-ness of container */
//@{
/*!
\brief Returns true if any bits in this bitset are set, and otherwise returns false.
\return true if any bit is set
*/
bool any() const BMNOEXCEPT;
/*!
\brief Returns true if no bits are set, otherwise returns false.
*/
bool none() const BMNOEXCEPT { return !any(); }
/**
\brief Returns true if the set is empty (no bits are set, otherwise returns false)
Please note that this is NOT a size check, it is an empty SET check (absense of 1s)
*/
bool empty() const BMNOEXCEPT { return !any(); }
//@}
// --------------------------------------------------------------------
/*! @name Scan and find bits and indexes */
//@{
/*!
\fn bool bvector::find(bm::id_t& pos) const
\brief Finds index of first 1 bit
\param pos - [out] index of the found 1 bit
\return true if search returned result
\sa get_first, get_next, extract_next, find_reverse, find_first_mismatch
*/
bool find(size_type& pos) const BMNOEXCEPT;
/*!
\fn bool bvector::find(bm::id_t from, bm::id_t& pos) const
\brief Find index of 1 bit starting from position
\param from - position to start search from, please note that if bit at from position
is set then it will be found, function uses closed interval [from...
\param pos - [out] index of the found 1 bit
\return true if search returned result
\sa get_first, get_next, extract_next, find_reverse, find_first_mismatch
*/
bool find(size_type from, size_type& pos) const BMNOEXCEPT;
/*!
\fn bm::id_t bvector::get_first() const
\brief find first 1 bit in vector.
Function may return 0 and this requires an extra check if bit 0 is
actually set or bit-vector is empty
\return Index of the first 1 bit, may return 0
\sa get_next, find, extract_next, find_reverse
*/
size_type get_first() const BMNOEXCEPT { return check_or_next(0); }
/*!
\fn bm::id_t bvector::get_next(bm::id_t prev) const
\brief Finds the number of the next bit ON.
\param prev - Index of the previously found bit.
\return Index of the next bit which is ON or 0 if not found.
\sa get_first, find, extract_next, find_reverse
*/
size_type get_next(size_type prev) const BMNOEXCEPT
{ return (++prev == bm::id_max) ? 0 : check_or_next(prev); }
/*!
\fn bm::id_t bvector::extract_next(bm::id_t prev)
\brief Finds the number of the next bit ON and sets it to 0.
\param prev - Index of the previously found bit.
\return Index of the next bit which is ON or 0 if not found.
\sa get_first, get_next, find_reverse
*/
size_type extract_next(size_type prev)
{
return (++prev == bm::id_max) ? 0 : check_or_next_extract(prev);
}
/*!
\brief Finds last index of 1 bit
\param pos - [out] index of the last found 1 bit
\return true if search returned result
\sa get_first, get_next, extract_next,
\sa find, find_first_mismatch, find_range
*/
bool find_reverse(size_type& pos) const BMNOEXCEPT;
/*!
\brief Reverse finds next(prev) index of 1 bit
\param from - index to search from
\param pos - [out] found position index
(undefined if method returns false)
\return true if search returned result
\sa get_first, get_next, extract_next,
\sa find, find_first_mismatch, find_range
*/
bool find_reverse(size_type from, size_type& pos) const BMNOEXCEPT;
/*!
\brief Finds dynamic range of bit-vector [first, last]
\param first - index of the first found 1 bit
\param last - index of the last found 1 bit
\return true if search returned result
\sa get_first, get_next, extract_next, find, find_reverse
*/
bool find_range(size_type& first, size_type& last) const BMNOEXCEPT;
/*!
\brief Find bit-vector position for the specified rank(bitcount)
Rank based search, counts number of 1s from specified position until
finds the ranked position relative to start from position.
In other words: range population count between from and pos == rank.
\param rank - rank to find (bitcount)
\param from - start positioon for rank search
\param pos - position with speciefied rank (relative to from position)
\return true if requested rank was found
*/
bool find_rank(size_type rank, size_type from,
size_type& pos) const BMNOEXCEPT;
/*!
\brief Find bit-vector position for the specified rank(bitcount)
Rank based search, counts number of 1s from specified position until
finds the ranked position relative to start from position.
In other words: range population count between from and pos == rank.
\param rank - rank to find (bitcount)
\param from - start positioon for rank search
\param pos - position with speciefied rank (relative to from position)
\param rs_idx - rank-select index to accelarate search
(should be prepared using build_rs_index)
\sa build_rs_index, select
\return true if requested rank was found
*/
bool find_rank(size_type rank, size_type from, size_type& pos,
const rs_index_type& rs_idx) const BMNOEXCEPT;
/*!
\brief select bit-vector position for the specified rank(bitcount)
Rank based search, counts number of 1s from specified position until
finds the ranked position relative to start from position.
Uses
In other words: range population count between from and pos == rank.
\param rank - rank to find (bitcount)
\param pos - position with speciefied rank (relative to from position) [out]
\param rs_idx - block count structure to accelerate rank search
\sa running_count_blocks, find_rank
\return true if requested rank was found
*/
bool select(size_type rank, size_type& pos,
const rs_index_type& rs_idx) const BMNOEXCEPT;
//@}
// --------------------------------------------------------------------
/*! @name Algebra of Sets operations */
//@{
/*!
\brief 3-operand OR : this := bv1 OR bv2
\param bv1 - Argument vector 1
\param bv2 - Argument vector 2
\param opt_mode - optimization compression
(when it is performed on the fly it is faster than a separate
call to optimize()
@sa optimize, bit_or
*/
bm::bvector<Alloc>& bit_or(const bm::bvector<Alloc>& bv1,
const bm::bvector<Alloc>& bv2,
typename bm::bvector<Alloc>::optmode opt_mode=opt_none);
/*!
\brief 3-operand XOR : this := bv1 XOR bv2
\param bv1 - Argument vector 1
\param bv2 - Argument vector 2
\param opt_mode - optimization compression
(when it is performed on the fly it is faster than a separate
call to optimize()
@sa optimize, bit_xor
*/
bm::bvector<Alloc>& bit_xor(const bm::bvector<Alloc>& bv1,
const bm::bvector<Alloc>& bv2,
typename bm::bvector<Alloc>::optmode opt_mode=opt_none);
/*!
\brief 3-operand AND : this := bv1 AND bv2
\param bv1 - Argument vector 1
\param bv2 - Argument vector 2
\param opt_mode - optimization compression
(when it is performed on the fly it is faster than a separate
call to optimize()
@sa optimize, bit_and
*/
bm::bvector<Alloc>& bit_and(const bm::bvector<Alloc>& bv1,
const bm::bvector<Alloc>& bv2,
typename bm::bvector<Alloc>::optmode opt_mode=opt_none);
/*!
\brief 3-operand AND where result is ORed into the terget vector : this |= bv1 AND bv2
TARGET := TARGET OR (BV1 AND BV2)
\param bv1 - Argument vector 1
\param bv2 - Argument vector 2
\param opt_mode - optimization compression
(when it is performed on the fly it is faster than a separate
call to optimize()
@sa optimize, bit_and
*/
bm::bvector<Alloc>& bit_or_and(const bm::bvector<Alloc>& bv1,
const bm::bvector<Alloc>& bv2,
typename bm::bvector<Alloc>::optmode opt_mode=opt_none);
/*!
\brief 3-operand SUB : this := bv1 MINUS bv2
SUBtraction is also known as AND NOT
\param bv1 - Argument vector 1
\param bv2 - Argument vector 2
\param opt_mode - optimization compression
(when it is performed on the fly it is faster than a separate
call to optimize()
@sa optimize, bit_sub
*/
bm::bvector<Alloc>& bit_sub(const bm::bvector<Alloc>& bv1,
const bm::bvector<Alloc>& bv2,
typename bm::bvector<Alloc>::optmode opt_mode=opt_none);
/*!
\brief 2 operand logical OR
\param bv - Argument vector.
*/
bm::bvector<Alloc>& bit_or(const bm::bvector<Alloc>& bv)
{
BM_ASSERT(!is_ro());
combine_operation_or(bv);
return *this;
}
/*!
\brief 2 operand logical AND
\param bv - argument vector
\param opt_mode - set an immediate optimization
*/
bm::bvector<Alloc>& bit_and(const bm::bvector<Alloc>& bv,
optmode opt_mode = opt_none)
{
BM_ASSERT(!is_ro());
combine_operation_and(bv, opt_mode);
return *this;
}
/*!
\brief 2 operand logical XOR
\param bv - argument vector.
*/
bm::bvector<Alloc>& bit_xor(const bm::bvector<Alloc>& bv)
{
BM_ASSERT(!is_ro());
combine_operation_xor(bv);
return *this;
}
/*!
\brief 2 operand logical SUB(AND NOT). Also known as MINUS.
\param bv - argument vector.
*/
bm::bvector<Alloc>& bit_sub(const bm::bvector<Alloc>& bv)
{
BM_ASSERT(!is_ro());
combine_operation_sub(bv);
return *this;
}
/*!
\brief Invert/NEG all bits
It should be noted, invert is affected by size()
if size is set - it only inverts [0..size-1] bits
*/
bvector<Alloc>& invert();
/*! \brief perform a set-algebra operation by operation code
*/
void combine_operation(const bm::bvector<Alloc>& bvect,
bm::operation opcode);
/*! \brief perform a set-algebra operation OR
*/
void combine_operation_or(const bm::bvector<Alloc>& bvect);
/*! \brief perform a set-algebra operation AND
*/
void combine_operation_and(const bm::bvector<Alloc>& bvect,
optmode opt_mode);
/*! \brief perform a set-algebra operation MINUS (AND NOT)
*/
void combine_operation_sub(const bm::bvector<Alloc>& bvect);
/*! \brief perform a set-algebra operation XOR
*/
void combine_operation_xor(const bm::bvector<Alloc>& bvect);
// @}
// --------------------------------------------------------------------
/*! @name Iterator-traversal methods */
//@{
/**
\brief Returns enumerator pointing on the first non-zero bit.
*/
enumerator first() const { return get_enumerator(0); }
/**
\fn bvector::enumerator bvector::end() const
\brief Returns enumerator pointing on the next bit after the last.
*/
enumerator end() const
{ return typename bvector<Alloc>::enumerator(this); }
/**
\brief Returns enumerator pointing on specified or the next available bit.
*/
enumerator get_enumerator(size_type pos) const
{ return typename bvector<Alloc>::enumerator(this, pos); }
//@}
// --------------------------------------------------------------------
/*! @name Memory management and compression */
//@{
/*!
@brief Calculates bitvector statistics.
@param st - pointer on statistics structure to be filled in.
Function fills statistics structure containing information about how
this vector uses memory and estimation of max. amount of memory
bvector needs to serialize itself.
@sa statistics
*/
void calc_stat(struct bm::bvector<Alloc>::statistics* st) const BMNOEXCEPT;
/*!
\brief Sets new blocks allocation strategy.
\param strat - Strategy code 0 - bitblocks allocation only.
1 - Blocks mutation mode (adaptive algorithm)
*/
void set_new_blocks_strat(strategy strat) { new_blocks_strat_ = strat; }
/*!
\brief Returns blocks allocation strategy.
\return - Strategy code 0 - bitblocks allocation only.
1 - Blocks mutation mode (adaptive algorithm)
\sa set_new_blocks_strat
*/
strategy get_new_blocks_strat() const BMNOEXCEPT
{ return new_blocks_strat_; }
/*!
\brief Optimize memory bitvector's memory allocation.
Function analyze all blocks in the bitvector, compresses blocks
with a regular structure, frees some memory. This function is recommended
after a bulk modification of the bitvector using set_bit, clear_bit or
logical operations.
Optionally function can calculate vector post optimization statistics
@param temp_block - externally allocated temp buffer for optimization
BM_DECLARE_TEMP_BLOCK(tb)
if NULL - it will allocated (and de-allocated upon exit)
@param opt_mode - optimization level
@param stat - statistics of memory consumption and serialization
stat can also be computed by calc_stat() but it would require an extra pass
@sa optmode, optimize_gap_size, calc_stat
*/
void optimize(bm::word_t* temp_block = 0,
optmode opt_mode = opt_compress,
statistics* stat = 0);
/*!
Run partial vector optimization for the area [left..right] (specified in bit coordinates)
@param left - bit index to optimize from (approximate, rounded up to a nearest block)
@param right - bit index to optimize to
Please note that left and right define range in bit coordinates but later rounded to blocks
@param temp_block - external scratch memory (MUST be pre-allocated)
@param opt_mode - optimization level
@sa optimize
*/
void optimize_range(
size_type left, size_type right,
bm::word_t* temp_block,
optmode opt_mode = opt_compress);
/*!
\brief Optimize sizes of GAP blocks
This method runs an analysis to find optimal GAP levels for the
specific vector. Current GAP compression algorithm uses several fixed
GAP sizes. By default bvector uses some reasonable preset.
*/
void optimize_gap_size();
/*!
@brief Sets new GAP lengths table. All GAP blocks will be reallocated
to match the new scheme.
@param glevel_len - pointer on C-style array keeping GAP block sizes.
*/
void set_gap_levels(const gap_word_t* glevel_len);
/**
Return true if bvector is initialized at all
@internal
*/
bool is_init() const BMNOEXCEPT { return blockman_.is_init(); }
/**
Calculate blocks digest vector (for diagnostics purposes)
1 is added if NB is a real, allocated block
@param bv_blocks - [out] bvector of blocks statistics
@internal
*/
void fill_alloc_digest(bvector<Alloc>& bv_blocks) const;
//@}
// --------------------------------------------------------------------
/*! @name Comparison */
//@{
/*!
\brief Lexicographical comparison with a bitvector.
Function compares current bitvector with the provided argument
bit by bit and returns -1 if this bitvector less than the argument,
1 - greater, 0 - equal
@return 0 if this == arg, -1 if this < arg, 1 if this > arg
@sa find_first_mismatch
*/
int compare(const bvector<Alloc>& bvect) const BMNOEXCEPT;
/*!
\brief Equal comparison with an agr bit-vector
@return true if vectors are identical
*/
bool equal(const bvector<Alloc>& bvect) const BMNOEXCEPT
{
size_type pos;
bool found = find_first_mismatch(bvect, pos);
return !found;
}
/*!
\brief Find index of first bit different between this and the agr vector
@param bvect - argumnet vector to compare with
@param pos - [out] position of the first difference
@param search_to - search limiter [0..to] to avoid overscan
(default: unlimited to the vectors end)
@return true if didfference found, false - both vectors are equivalent
@sa compare
*/
bool find_first_mismatch(const bvector<Alloc>& bvect,
size_type& pos,
size_type search_to = bm::id_max
) const BMNOEXCEPT;
//@}
// --------------------------------------------------------------------
/*! @name Open internals */
//@{
/*!
@internal
*/
void combine_operation_with_block(block_idx_type nb,
const bm::word_t* arg_blk,
bool arg_gap,
bm::operation opcode);
/**
\brief get access to memory manager (internal)
Use only if you are BitMagic library
@internal
*/
const blocks_manager_type& get_blocks_manager() const BMNOEXCEPT
{ return blockman_; }
/**
\brief get access to memory manager (internal)
Use only if you are BitMagic library
@internal
*/
blocks_manager_type& get_blocks_manager() BMNOEXCEPT
{ return blockman_; }
/**
Import integers (set bits). (Fast, no checks).
@internal
*/
void import(const size_type* ids, size_type ids_size,
bm::sort_order sorted_idx);
/**
Import sorted integers (set bits). (Fast, no checks).
@internal
*/
void import_sorted(const size_type* ids,
const size_type ids_size, bool opt_flag);
/**
\brief Set range without validity/bounds checking
*/
void set_range_no_check(size_type left,
size_type right);
/**
\brief Clear range without validity/bounds checking
*/
void clear_range_no_check(size_type left,
size_type right);
//@}
static void throw_bad_alloc();
protected:
/**
Syncronize size if it got extended due to bulk import
@internal
*/
void sync_size();
void import_block(const size_type* ids,
block_idx_type nblock, size_type start, size_type stop);
size_type check_or_next(size_type prev) const BMNOEXCEPT;
/// set bit in GAP block with GAP block length control
bool gap_block_set(bm::gap_word_t* gap_blk,
bool val, block_idx_type nblock, unsigned nbit);
/// set bit in GAP block with GAP block length control
void gap_block_set_no_ret(bm::gap_word_t* gap_blk,
bool val, block_idx_type nblock,
unsigned nbit);
/// check if specified bit is 1, and set it to 0
/// if specified bit is 0, scan for the next 1 and returns it
/// if no 1 found returns 0
size_type check_or_next_extract(size_type prev);
/**
\brief AND specified bit without checking preconditions (size, etc)
*/
bool and_bit_no_check(size_type n, bool val);
bool set_bit_conditional_impl(size_type n, bool val, bool condition);
void combine_operation_with_block(block_idx_type nb,
bool gap,
bm::word_t* blk,
const bm::word_t* arg_blk,
bool arg_gap,
bm::operation opcode);
/**
@return true if block optimization may be needed
*/
bool combine_operation_block_or(unsigned i,
unsigned j,
const bm::word_t* arg_blk1,
const bm::word_t* arg_blk2);
bool combine_operation_block_xor(unsigned i,
unsigned j,
const bm::word_t* arg_blk1,
const bm::word_t* arg_blk2);
bool combine_operation_block_and(unsigned i,
unsigned j,
const bm::word_t* arg_blk1,
const bm::word_t* arg_blk2);
bool combine_operation_block_and_or(unsigned i,
unsigned j,
const bm::word_t* arg_blk1,
const bm::word_t* arg_blk2);
bool combine_operation_block_sub(unsigned i,
unsigned j,
const bm::word_t* arg_blk1,
const bm::word_t* arg_blk2);
void combine_operation_block_or(unsigned i,
unsigned j,
bm::word_t* blk,
const bm::word_t* arg_blk);
void combine_operation_block_xor(unsigned i,
unsigned j,
bm::word_t* blk,
const bm::word_t* arg_blk);
void combine_operation_block_and(unsigned i,
unsigned j,
bm::word_t* blk,
const bm::word_t* arg_blk);
void combine_operation_block_sub(unsigned i,
unsigned j,
bm::word_t* blk,
const bm::word_t* arg_blk);
void copy_range_no_check(const bvector<Alloc>& bvect,
size_type left,
size_type right);
private:
/**
\brief Clear outside the range without validity/bounds checking
*/
void keep_range_no_check(size_type left,
size_type right);
/**
Compute rank in bit-block using rank-select index
*/
static
size_type block_count_to(const bm::word_t* block,
block_idx_type nb,
unsigned nbit_right,
const rs_index_type& rs_idx) BMNOEXCEPT;
/**
Compute rank in GAP block using rank-select index
@param test_set - request to test nbit_right before computing count
(returns 0 if not set)
*/
static
size_type gap_count_to(const bm::gap_word_t* gap_block,
block_idx_type nb,
unsigned nbit_right,
const rs_index_type& rs_idx,
bool test_set = false) BMNOEXCEPT;
/**
Return value of first bit in the block
*/
bool test_first_block_bit(block_idx_type nb) const BMNOEXCEPT;
private:
blocks_manager_type blockman_; //!< bitblocks manager
strategy new_blocks_strat_; //!< block allocation strategy
size_type size_; //!< size in bits
};
//---------------------------------------------------------------------
template<class Alloc>
inline bvector<Alloc> operator& (const bvector<Alloc>& bv1,
const bvector<Alloc>& bv2)
{
bvector<Alloc> ret;
ret.bit_and(bv1, bv2, bvector<Alloc>::opt_none);
return ret;
}
//---------------------------------------------------------------------
template<class Alloc>
inline bvector<Alloc> operator| (const bvector<Alloc>& bv1,
const bvector<Alloc>& bv2)
{
bvector<Alloc> ret;
ret.bit_or(bv1, bv2, bvector<Alloc>::opt_none);
return ret;
}
//---------------------------------------------------------------------
template<class Alloc>
inline bvector<Alloc> operator^ (const bvector<Alloc>& bv1,
const bvector<Alloc>& bv2)
{
bvector<Alloc> ret;
ret.bit_xor(bv1, bv2, bvector<Alloc>::opt_none);
return ret;
}
//---------------------------------------------------------------------
template<class Alloc>
inline bvector<Alloc> operator- (const bvector<Alloc>& bv1,
const bvector<Alloc>& bv2)
{
bvector<Alloc> ret;
ret.bit_sub(bv1, bv2, bvector<Alloc>::opt_none);
return ret;
}
// -----------------------------------------------------------------------
template<typename Alloc>
void bvector<Alloc>::init()
{
BM_ASSERT(!is_ro());
blockman_.init_tree();
}
// -----------------------------------------------------------------------
template<typename Alloc>
void bvector<Alloc>::init(unsigned top_size, bool alloc_subs)
{
BM_ASSERT(!is_ro());
if (!blockman_.is_init())
blockman_.init_tree(top_size);
if (alloc_subs)
for (unsigned nb = 0; nb < top_size; ++nb)
blockman_.alloc_top_subblock(nb);
}
// -----------------------------------------------------------------------
template<typename Alloc>
void bvector<Alloc>::copy(const bvector<Alloc>& bvect, bm::finalization is_final)
{
if (this != &bvect)
{
blockman_.deinit_tree();
switch (is_final)
{
case bm::finalization::UNDEFINED:
if (bvect.is_ro())
{
blockman_.copy_to_arena(bvect.blockman_);
size_ = bvect.size();
}
else
{
blockman_.copy(bvect.blockman_);
resize(bvect.size());
}
break;
case bm::finalization::READONLY:
blockman_.copy_to_arena(bvect.blockman_);
size_ = bvect.size();
break;
case bm::finalization::READWRITE:
blockman_.copy(bvect.blockman_);
resize(bvect.size());
break;
default:
BM_ASSERT(0);
break;
} // switch
}
}
// -----------------------------------------------------------------------
template<typename Alloc>
void bvector<Alloc>::move_from(bvector<Alloc>& bvect) BMNOEXCEPT
{
if (this != &bvect)
{
blockman_.move_from(bvect.blockman_);
size_ = bvect.size_;
new_blocks_strat_ = bvect.new_blocks_strat_;
}
}
//---------------------------------------------------------------------
template<class Alloc>
void bvector<Alloc>::keep_range(size_type left, size_type right)
{
BM_ASSERT(!is_ro());
if (!blockman_.is_init())
return; // nothing to do
if (right < left)
bm::xor_swap(left, right);
keep_range_no_check(left, right);
}
// -----------------------------------------------------------------------
template<typename Alloc>
bvector<Alloc>& bvector<Alloc>::set_range(size_type left,
size_type right,
bool value)
{
BM_ASSERT(!is_ro());
if (!blockman_.is_init() && !value)
return *this; // nothing to do
if (right < left)
return set_range(right, left, value);
BM_ASSERT_THROW(right < bm::id_max, BM_ERR_RANGE);
if (right >= size_) // this vect shorter than the arg.
{
size_type new_size = (right == bm::id_max) ? bm::id_max : right + 1;
resize(new_size);
}
BM_ASSERT(left <= right);
BM_ASSERT(left < size_);
if (value)
set_range_no_check(left, right);
else
clear_range_no_check(left, right);
return *this;
}
// -----------------------------------------------------------------------
template<typename Alloc>
typename bvector<Alloc>::size_type bvector<Alloc>::count() const BMNOEXCEPT
{
if (!blockman_.is_init())
return 0;
word_t*** blk_root = blockman_.top_blocks_root();
BM_ASSERT(blk_root);
size_type cnt = 0;
unsigned top_blocks = blockman_.top_block_size();
for (unsigned i = 0; i < top_blocks; ++i)
{
bm::word_t** blk_blk = blk_root[i];
if (!blk_blk)
{
++i;
bool found = bm::find_not_null_ptr(blk_root, i, top_blocks, &i);
if (!found)
break;
blk_blk = blk_root[i];
BM_ASSERT(blk_blk);
if (!blk_blk)
break;
}
if ((bm::word_t*)blk_blk == FULL_BLOCK_FAKE_ADDR)
{
cnt += bm::gap_max_bits * bm::set_sub_array_size;
continue;
}
unsigned j = 0;
do
{
if (blk_blk[j])
cnt += blockman_.block_bitcount(blk_blk[j]);
if (blk_blk[j+1])
cnt += blockman_.block_bitcount(blk_blk[j+1]);
if (blk_blk[j+2])
cnt += blockman_.block_bitcount(blk_blk[j+2]);
if (blk_blk[j+3])
cnt += blockman_.block_bitcount(blk_blk[j+3]);
j += 4;
} while (j < bm::set_sub_array_size);
} // for i
return cnt;
}
// -----------------------------------------------------------------------
template<typename Alloc>
bool bvector<Alloc>::any() const BMNOEXCEPT
{
word_t*** blk_root = blockman_.top_blocks_root();
if (!blk_root)
return false;
typename blocks_manager_type::block_any_func func(blockman_);
return for_each_nzblock_if(blk_root, blockman_.top_block_size(), func);
}
// -----------------------------------------------------------------------
template<typename Alloc>
void bvector<Alloc>::resize(size_type new_size)
{
BM_ASSERT(!is_ro());
if (size_ == new_size) return; // nothing to do
if (size_ < new_size) // size grows
{
if (!blockman_.is_init())
blockman_.init_tree();
blockman_.reserve(new_size);
size_ = new_size;
}
else // shrink
{
set_range(new_size, size_ - 1, false); // clear the tail
size_ = new_size;
}
}
// -----------------------------------------------------------------------
template<typename Alloc>
void bvector<Alloc>::sync_size()
{
BM_ASSERT(!is_ro());
if (size_ >= bm::id_max)
return;
bvector<Alloc>::size_type last;
bool found = find_reverse(last);
if (found && last >= size_)
resize(last+1);
}
// -----------------------------------------------------------------------
template<typename Alloc>
void bvector<Alloc>::build_rs_index(rs_index_type* rs_idx,
bvector<Alloc>* bv_blocks) const
{
BM_ASSERT(rs_idx);
if (bv_blocks)
{
bv_blocks->clear();
bv_blocks->init();
}
unsigned bcount[bm::set_sub_array_size];
bm::id64_t sub_count[bm::set_sub_array_size];
rs_idx->init();
if (!blockman_.is_init())
return;
// resize the RS index to fit the vector
//
size_type last_bit;
bool found = find_reverse(last_bit);
if (!found)
return;
block_idx_type nb = (last_bit >> bm::set_block_shift);
unsigned i0, j0;
bm::get_block_coord(nb, i0, j0);
unsigned real_top_blocks = blockman_.find_real_top_blocks();
unsigned max_top_blocks = blockman_.find_max_top_blocks();
if (nb < (max_top_blocks * bm::set_sub_array_size))
nb = (max_top_blocks * bm::set_sub_array_size);
rs_idx->set_total(nb + 1);
rs_idx->resize(nb + 1);
rs_idx->resize_effective_super_blocks(real_top_blocks);
// index construction
//
BM_ASSERT(max_top_blocks <= blockman_.top_block_size());
bm::word_t*** blk_root = blockman_.top_blocks_root();
for (unsigned i = 0; i < max_top_blocks; ++i)
{
bm::word_t** blk_blk = blk_root[i];
if (!blk_blk)
{
rs_idx->set_null_super_block(i);
continue;
}
if ((bm::word_t*)blk_blk == FULL_BLOCK_FAKE_ADDR)
{
rs_idx->set_full_super_block(i);
if (bv_blocks)
{
size_type nb_from = i * bm::set_sub_array_size;
size_type nb_to = nb_from + bm::set_sub_array_size - 1;
bv_blocks->set_range_no_check(nb_from, nb_to);
}
continue;
}
unsigned j = 0;
do
{
const bm::word_t* block = blk_blk[j];
if (!block)
{
bcount[j] = 0; sub_count[j] = 0;
continue;
}
unsigned local_first, local_second, local_third;
bm::id64_t aux0, aux1; // aux infomation to encode
if (BM_IS_GAP(block))
{
const bm::gap_word_t* const gap_block = BMGAP_PTR(block);
local_first =
bm::gap_bit_count_to(gap_block, (gap_word_t)bm::rs3_border0);
local_second =
bm::gap_bit_count_range(gap_block,
bm::gap_word_t(bm::rs3_border0+1),
bm::rs3_border1);
local_third =
bm::gap_bit_count_range(gap_block,
bm::gap_word_t(bm::rs3_border1+1),
bm::gap_word_t(bm::gap_max_bits-1));
// for GAP block calculate borderline positions in GAP
// and value (0|1), save to AUX
//
unsigned is_set;
aux0 = bm::gap_bfind(gap_block, rs3_border0+1, &is_set);
aux0 <<= 1;
if (is_set) aux0 |= 1;
aux1 = bm::gap_bfind(gap_block, rs3_border1+1, &is_set);
aux1 <<= 1;
if (is_set) aux1 |= 1;
}
else
{
block = BLOCK_ADDR_SAN(block); // TODO: optimize FULL
local_first =
bm::bit_block_calc_count_to(block, bm::rs3_border0);
local_second =
bm::bit_block_calc_count_range(block,
bm::rs3_border0+1,
bm::rs3_border1);
local_third =
bm::bit_block_calc_count_range(block,
bm::rs3_border1+1,
bm::gap_max_bits-1);
// compute inetrmediate points
aux0 = bm::bit_block_calc_count_to(block, bm::rs3_border0_1);
aux1 = bm::bit_block_calc_count_to(block, bm::rs3_border1_1);
}
unsigned cnt = local_first + local_second + local_third;
BM_ASSERT(cnt == blockman_.block_bitcount(block));
bcount[j] = cnt;
if (bv_blocks && cnt)
bv_blocks->set_bit_no_check(i * bm::set_sub_array_size + j);
BM_ASSERT(cnt >= local_first + local_second);
sub_count[j] = bm::id64_t(local_first | (local_second << 16)) |
(aux0 << 32) | (aux1 << 48);
} while (++j < bm::set_sub_array_size);
rs_idx->register_super_block(i, &bcount[0], &sub_count[0]);
} // for i
}
// -----------------------------------------------------------------------
template<typename Alloc>
typename bvector<Alloc>::block_idx_type
bvector<Alloc>::count_blocks(unsigned* arr) const BMNOEXCEPT
{
bm::word_t*** blk_root = blockman_.top_blocks_root();
if (blk_root == 0)
return 0;
typename blocks_manager_type::block_count_arr_func func(blockman_, &(arr[0]));
bm::for_each_nzblock(blk_root, blockman_.top_block_size(), func);
return func.last_block();
}
// -----------------------------------------------------------------------
#define BM_BORDER_TEST(blk, idx) bool(blk[idx >> bm::set_word_shift] & (1u << (idx & bm::set_word_mask)))
#if (defined(BMSSE42OPT) || defined(BMAVX2OPT) || defined(BMAVX512OPT) || \
defined(BMWASMSIMDOPT) || defined(BMNEONOPT))
template<typename Alloc>
typename bvector<Alloc>::size_type
bvector<Alloc>::block_count_to(const bm::word_t* block,
block_idx_type nb,
unsigned nbit_right,
const rs_index_type& rs_idx) BMNOEXCEPT
{
BM_ASSERT(IS_VALID_ADDR(block));
size_type c;
bm::id64_t sub = rs_idx.sub_count(nb);
unsigned sub_cnt = unsigned(sub);
unsigned first = sub_cnt & 0xFFFF;
unsigned second = sub_cnt >> 16;
BM_ASSERT(first == bm::bit_block_calc_count_to(block, rs3_border0));
BM_ASSERT(second == bm::bit_block_calc_count_range(block, rs3_border0+1, rs3_border1));
{
unsigned cnt, aux0(bm::gap_word_t(sub >> 32)); (void)cnt; (void)aux0;
BM_ASSERT(aux0 == (cnt =bm::bit_block_calc_count_to(block, bm::rs3_border0_1)));
unsigned cnt1, aux1(bm::gap_word_t(sub >> 48)); (void)aux1; (void) cnt1;
BM_ASSERT(aux1 == (cnt1 =bm::bit_block_calc_count_to(block, bm::rs3_border1_1)));
}
#if defined(BM64_SSE4) || defined(BM64_AVX2) || defined(BM64_AVX512)
const unsigned cutoff_bias = rs3_half_span/8;
#else
const unsigned cutoff_bias = 0;
#endif
unsigned sub_range = rs_idx.find_sub_range(nbit_right);
// evaluate 3 sub-block intervals (and sub-intervals)
// |--------[0]-----*-----[1]----*-----|
switch(sub_range) // sub-range rank calc
{
case 0:
// |--x-----[0]-----------[1]----------|
if (nbit_right <= rs3_border0/2 + cutoff_bias)
{
c = bm::bit_block_calc_count_range<true, false>(block, 0, nbit_right);
}
else
{
// |--------[x]-----------[1]----------|
if (nbit_right == rs3_border0)
{
c = first;
}
else
{
// |------x-[0]-----------[1]----------|
c = bm::bit_block_calc_count_range(block, nbit_right+1,
rs3_border0);
c = first - c;
}
}
break;
case 1:
{
// |--------[0]-x---------[1]----------|
if (nbit_right <= rs3_border0_1 + cutoff_bias)
{
c =
bm::bit_block_calc_count_range<true, false>(block,
bm::rs3_border0,
nbit_right);
c += first - BM_BORDER_TEST(block, bm::rs3_border0);
}
else
{
unsigned bc_second_range = first + second;
// |--------[0]-----------[x]----------|
if (nbit_right == rs3_border1)
{
c = bc_second_range;
}
else // sub-range processing
{
// |--------[0]--------x--[1]----------|
BM_ASSERT(nbit_right > bm::rs3_border0_1);
unsigned d1 = nbit_right - bm::rs3_border0_1;
unsigned d2 = rs3_border1 - nbit_right;
if (d2 < d1)
{
// |--------[0]----|----x-[1]----------|
c = bm::bit_block_calc_count_range(block,
nbit_right+1,
rs3_border1);
c = bc_second_range - c;
}
else
{
// |--------[0]----|-x----[1]----------|
c = bm::bit_block_calc_count_range<true, false>(
block,
bm::rs3_border0_1,
nbit_right);
unsigned aux0 = bm::gap_word_t(sub >> 32);
c += aux0;
c -= BM_BORDER_TEST(block, bm::rs3_border0_1);
}
}
}
}
break;
case 2:
{
// |--------[0]-----------[1]-x---*----|
if (nbit_right <= rs3_border1_1)
{
unsigned d1 = nbit_right - bm::rs3_border1;
unsigned d2 = (rs3_border1_1 + cutoff_bias) - nbit_right;
if (d1 < d2) // |--------[0]-----------[1]-x---*----|
{
c = bm::bit_block_calc_count_range<true, false>(block,
bm::rs3_border1,
nbit_right);
c += first + second; //bc_second_range;
c -= BM_BORDER_TEST(block, bm::rs3_border1);
}
else // |--------[0]-----------[1]---x-*----|
{
if (nbit_right == rs3_border1_1)
{
unsigned aux1 = bm::gap_word_t(sub >> 48);
c = aux1;
}
else
{
c = bm::bit_block_calc_count_range(block,
nbit_right+1,
rs3_border1_1);
unsigned aux1 = bm::gap_word_t(sub >> 48);
c = aux1 - c;
}
}
}
else
{
// |--------[0]-----------[1]----------x
if (nbit_right == bm::gap_max_bits-1)
{
c = rs_idx.count(nb);
}
else // sub-range processing
{
// |--------[0]-----------[1]-------x--|
BM_ASSERT(nbit_right > bm::rs3_border1_1);
unsigned d1 = nbit_right - bm::rs3_border1_1;
unsigned d2 = bm::gap_max_bits - nbit_right;
if (d2 < d1)
{
// |--------[0]----------[1]----*---x-|
c = bm::bit_block_calc_count_range(block,
nbit_right+1,
bm::gap_max_bits-1);
size_type cnt = rs_idx.count(nb);
c = cnt - c;
}
else
{
// |--------[0]----------[1]----*-x---|
c = bm::bit_block_calc_count_range<true, false>(block,
bm::rs3_border1_1,
nbit_right);
unsigned aux1 = bm::gap_word_t(sub >> 48);
c += aux1;
c -= BM_BORDER_TEST(block, bm::rs3_border1_1);
}
}
}
}
break;
default:
BM_ASSERT(0);
c = 0;
} // switch
BM_ASSERT(c == bm::bit_block_calc_count_to(block, nbit_right));
return c;
}
#else // non-SIMD version
template<typename Alloc>
typename bvector<Alloc>::size_type
bvector<Alloc>::block_count_to(const bm::word_t* block,
block_idx_type nb,
unsigned nbit_right,
const rs_index_type& rs_idx) BMNOEXCEPT
{
BM_ASSERT(block);
bm::id64_t sub = rs_idx.sub_count(nb);
unsigned sub_cnt = unsigned(sub);
unsigned first = sub_cnt & 0xFFFF;
unsigned second = sub_cnt >> 16;
BM_ASSERT(first == bm::bit_block_calc_count_to(block, rs3_border0));
BM_ASSERT(second == bm::bit_block_calc_count_range(block, rs3_border0+1, rs3_border1));
{
unsigned cnt, aux0(bm::gap_word_t(sub >> 32)); (void)cnt; (void)aux0;
BM_ASSERT(aux0 == (cnt =bm::bit_block_calc_count_to(block, bm::rs3_border0_1)));
unsigned cnt1, aux1(bm::gap_word_t(sub >> 48)); (void)aux1; (void) cnt1;
BM_ASSERT(aux1 == (cnt1 =bm::bit_block_calc_count_to(block, bm::rs3_border1_1)));
}
size_type c=0;
unsigned sub_choice =
bm::get_nibble(bm::rs_intervals<true>::_c._lut, nbit_right);
switch(sub_choice)
{
case 0:
c = bm::bit_block_calc_count_range<true, false>(block, 0, nbit_right);
break;
case 1:
c = first;
break;
case 2:
c = bm::bit_block_calc_count_range(block, nbit_right+1, rs3_border0);
c = first - c;
break;
case 3:
c = bm::bit_block_calc_count_range<true, false>(block,
bm::rs3_border0,
nbit_right);
c += first - BM_BORDER_TEST(block, bm::rs3_border0);
break;
case 4:
c = first + second;
break;
case 5:
c = bm::bit_block_calc_count_range(block, nbit_right+1, rs3_border1);
c = first + second - c;
break;
case 6:
c = bm::bit_block_calc_count_range<true, false>(
block,
bm::rs3_border0_1,
nbit_right);
c += bm::gap_word_t(sub >> 32); // aux0
c -= BM_BORDER_TEST(block, bm::rs3_border0_1);
break;
case 7:
c = bm::bit_block_calc_count_range<true, false>(block,
bm::rs3_border1,
nbit_right);
c += first + second; //bc_second_range;
c -= BM_BORDER_TEST(block, bm::rs3_border1);
break;
case 8:
c = bm::gap_word_t(sub >> 48); // aux1;
break;
case 9:
c = bm::bit_block_calc_count_range(block,
nbit_right+1,
rs3_border1_1);
c = bm::gap_word_t(sub >> 48) - c; // aux1 - c
break;
case 10:
c = rs_idx.count(nb);
break;
case 11:
c = bm::bit_block_calc_count_range(block,
nbit_right+1,
bm::gap_max_bits-1);
c = rs_idx.count(nb) - c;
break;
case 12:
c = bm::bit_block_calc_count_range<true, false>(block,
bm::rs3_border1_1,
nbit_right);
c += bm::gap_word_t(sub >> 48); // aux1;
c -= BM_BORDER_TEST(block, bm::rs3_border1_1);
break;
default:
BM_ASSERT(0);
} // switch
BM_ASSERT(c == bm::bit_block_calc_count_to(block, nbit_right));
return c;
}
#endif
#undef BM_BORDER_TEST
// -----------------------------------------------------------------------
template<typename Alloc>
typename bvector<Alloc>::size_type
bvector<Alloc>::gap_count_to(const bm::gap_word_t* gap_block,
block_idx_type nb,
unsigned nbit_right,
const rs_index_type& rs_idx,
bool test_set) BMNOEXCEPT
{
BM_ASSERT(gap_block);
size_type c;
if (test_set)
{
bool is_set = bm::gap_test_unr(gap_block, (gap_word_t)nbit_right);
if (!is_set)
return 0;
}
/*
{
unsigned len = bm::gap_length(gap_block);
if (len < 64)
{
c = bm::gap_bit_count_to(gap_block, (gap_word_t)nbit_right);
return c;
}
}
*/
bm::id64_t sub = rs_idx.sub_count(nb);
if (!sub)
{
c = 0;
BM_ASSERT(c == bm::gap_bit_count_to(gap_block, (gap_word_t)nbit_right));
return c;
}
unsigned sub_cnt = unsigned(sub);
unsigned first = bm::gap_word_t(sub_cnt);
unsigned second = (sub_cnt >> 16);
BM_ASSERT(first == bm::gap_bit_count_to(gap_block,(gap_word_t)rs3_border0));
BM_ASSERT(second == bm::gap_bit_count_range(gap_block, rs3_border0+1, rs3_border1));
// evaluate 3 sub-block intervals
// |--------[0]-----------[1]----------|
const unsigned cutoff_bias = rs3_half_span/8;
unsigned sub_range = rs_idx.find_sub_range(nbit_right);
switch(sub_range) // sub-range rank calc
{
case 0:
// |--x-----[0]-----------[1]----------|
if (nbit_right <= (rs3_border0/2 + cutoff_bias))
{
c = bm::gap_bit_count_to(gap_block,(gap_word_t)nbit_right);
}
else
{
// |--------[x]-----------[1]----------|
if (nbit_right == rs3_border0)
{
c = first;
}
else
{
// |------x-[0]-----------[1]----------|
c =
bm::gap_bit_count_range(gap_block, nbit_right+1, rs3_border0);
c = first - c;
}
}
break;
case 1:
// |--------[0]-x---------[1]----------|
if (nbit_right <= (rs3_border0 + rs3_half_span + cutoff_bias))
{
unsigned aux0 = bm::gap_word_t(sub >> 32);
c = bm::gap_bit_count_range_hint(gap_block,
rs3_border0+1, nbit_right, aux0);
c += first;
}
else
{
// |--------[0]-----------[x]----------|
if (nbit_right == rs3_border1)
{
c = first + second;
}
else
{
// |--------[0]--------x--[1]----------|
c =
bm::gap_bit_count_range(gap_block, nbit_right+1, rs3_border1);
c = first + second - c;
}
}
break;
case 2:
{
// |--------[0]-----------[1]-x--------|
if (nbit_right <= (rs3_border1 + rs3_half_span + cutoff_bias))
{
unsigned aux1 = bm::gap_word_t(sub >> 48);
c = bm::gap_bit_count_range_hint(gap_block,
rs3_border1 + 1, nbit_right, aux1);
c += first + second; // += bc_second_range
}
else
{
// |--------[0]-----------[1]----------x
if (nbit_right == bm::gap_max_bits-1)
{
c = rs_idx.count(nb);
}
else
{
// |--------[0]-----------[1]-------x--|
c = bm::gap_bit_count_range<bm::gap_word_t, true> (gap_block,
nbit_right+1, bm::gap_max_bits-1);
size_type cnt = rs_idx.count(nb);
c = cnt - c;
}
}
}
break;
default:
BM_ASSERT(0);
c = 0;
} // switch
BM_ASSERT(c == bm::gap_bit_count_to(gap_block, (gap_word_t)nbit_right));
return c;
}
// -----------------------------------------------------------------------
template<typename Alloc>
typename bvector<Alloc>::size_type
bvector<Alloc>::count_to(size_type right,
const rs_index_type& rs_idx) const BMNOEXCEPT
{
BM_ASSERT(right < bm::id_max);
if (!blockman_.is_init())
return 0;
unsigned nb_right = unsigned(right >> bm::set_block_shift);
// running count of all blocks before target
//
size_type cnt;
if (nb_right >= rs_idx.get_total())
{
cnt = rs_idx.count();
return cnt;
}
cnt = nb_right ? rs_idx.rcount(nb_right-1) : 0;
unsigned i, j;
bm::get_block_coord(nb_right, i, j);
const bm::word_t* block = blockman_.get_block_ptr(i, j);
if (block)
{
size_type c;
unsigned nbit_right = unsigned(right & bm::set_block_mask);
if (BM_IS_GAP(block))
{
const bm::gap_word_t* gap_block = BMGAP_PTR(block);
c = this->gap_count_to(gap_block, nb_right, nbit_right, rs_idx);
}
else
{
if (block == FULL_BLOCK_FAKE_ADDR) // TODO: misses REAL full sometimes
{
return cnt + nbit_right + 1;
}
else // real bit-block
{
c = this->block_count_to(block, nb_right, nbit_right, rs_idx);
}
}
cnt += c;
}
return cnt;
}
// -----------------------------------------------------------------------
template<typename Alloc>
typename bvector<Alloc>::size_type
bvector<Alloc>::count_to_test(size_type right,
const rs_index_type& rs_idx) const BMNOEXCEPT
{
BM_ASSERT(right < bm::id_max);
if (!blockman_.is_init())
return 0;
unsigned nb_right = unsigned(right >> bm::set_block_shift);
unsigned i, j;
bm::get_block_coord(nb_right, i, j);
const bm::word_t* block = blockman_.get_block_ptr(i, j);
if (!block)
return 0;
unsigned nbit_right = unsigned(right & bm::set_block_mask);
size_type cnt = nbit_right + 1; // default for FULL BLOCK
if (BM_IS_GAP(block))
{
bm::gap_word_t *gap_blk = BMGAP_PTR(block);
cnt = gap_count_to(gap_blk, nb_right, nbit_right, rs_idx, true);
if (!cnt)
return cnt;
BM_ASSERT(cnt == bm::gap_bit_count_to(gap_blk, (gap_word_t)nbit_right));
/*
if (bm::gap_test_unr(gap_blk, (gap_word_t)nbit_right))
{
cnt = gap_count_to(gap_blk, nb_right, nbit_right, rs_idx);
BM_ASSERT(cnt == bm::gap_bit_count_to(gap_blk, (gap_word_t)nbit_right));
}
else
return 0;
*/
}
else
{
if (block != FULL_BLOCK_FAKE_ADDR)
{
unsigned w = block[nbit_right >> bm::set_word_shift]; // nword
if (w &= (1u << (nbit_right & bm::set_word_mask)))
{
cnt = block_count_to(block, nb_right, nbit_right, rs_idx);
BM_ASSERT(cnt == bm::bit_block_calc_count_to(block, nbit_right));
}
else
return 0;
}
}
cnt += nb_right ? rs_idx.rcount(nb_right - 1) : 0;
return cnt;
}
// -----------------------------------------------------------------------
template<typename Alloc>
typename bvector<Alloc>::size_type
bvector<Alloc>::rank_corrected(size_type right,
const rs_index_type& rs_idx) const BMNOEXCEPT
{
BM_ASSERT(right < bm::id_max);
if (!blockman_.is_init())
return 0;
unsigned nblock_right = unsigned(right >> bm::set_block_shift);
unsigned nbit_right = unsigned(right & bm::set_block_mask);
size_type cnt = nblock_right ? rs_idx.rcount(nblock_right - 1) : 0;
unsigned i, j;
bm::get_block_coord(nblock_right, i, j);
const bm::word_t* block = blockman_.get_block_ptr(i, j);
if (!block)
return cnt;
bool gap = BM_IS_GAP(block);
if (gap)
{
cnt += bm::gap_bit_count_to<bm::gap_word_t, true>(
BMGAP_PTR(block), (gap_word_t)nbit_right);
}
else
{
if (block == FULL_BLOCK_FAKE_ADDR)
cnt += nbit_right;
else
{
cnt += block_count_to(block, nblock_right, nbit_right, rs_idx);
unsigned w = block[nbit_right >> bm::set_word_shift] &
(1u << (nbit_right & bm::set_word_mask));
cnt -= bool(w); // rank correction
}
}
return cnt;
}
// -----------------------------------------------------------------------
template<typename Alloc>
typename bvector<Alloc>::size_type
bvector<Alloc>::count_range(size_type left, size_type right) const BMNOEXCEPT
{
BM_ASSERT(left < bm::id_max && right < bm::id_max);
if (!blockman_.is_init())
return 0;
if (left > right)
bm::xor_swap(left, right);
if (right == bm::id_max)
--right;
return count_range_no_check(left, right);
}
// -----------------------------------------------------------------------
template<typename Alloc>
typename bvector<Alloc>::size_type
bvector<Alloc>::count_range_no_check(size_type left, size_type right) const BMNOEXCEPT
{
size_type cnt = 0;
// calculate logical number of start and destination blocks
block_idx_type nblock_left = (left >> bm::set_block_shift);
block_idx_type nblock_right = (right >> bm::set_block_shift);
unsigned i0, j0;
bm::get_block_coord(nblock_left, i0, j0);
const bm::word_t* block = blockman_.get_block(i0, j0);
bool left_gap = BM_IS_GAP(block);
unsigned nbit_left = unsigned(left & bm::set_block_mask);
unsigned nbit_right = unsigned(right & bm::set_block_mask);
unsigned r =
(nblock_left == nblock_right) ? nbit_right : (bm::bits_in_block-1);
typename blocks_manager_type::block_count_func func(blockman_);
if (block)
{
if ((nbit_left == 0) && (r == (bm::bits_in_block-1))) // whole block
{
func(block);
cnt += func.count();
}
else
{
if (left_gap)
{
cnt += bm::gap_bit_count_range(BMGAP_PTR(block),
(gap_word_t)nbit_left,
(gap_word_t)r);
}
else
{
cnt += bm::bit_block_calc_count_range(block, nbit_left, r);
}
}
}
if (nblock_left == nblock_right) // in one block
return cnt;
// process all full mid-blocks
{
func.reset();
word_t*** blk_root = blockman_.top_blocks_root();
block_idx_type top_blocks_size = blockman_.top_block_size();
bm::for_each_nzblock_range(blk_root, top_blocks_size,
nblock_left+1, nblock_right-1, func);
cnt += func.count();
}
bm::get_block_coord(nblock_right, i0, j0);
block = blockman_.get_block(i0, j0);
bool right_gap = BM_IS_GAP(block);
if (block)
{
if (right_gap)
{
cnt +=
bm::gap_bit_count_to(BMGAP_PTR(block), (gap_word_t)nbit_right);
}
else
{
cnt += bm::bit_block_calc_count_range(block, 0, nbit_right);
}
}
return cnt;
}
// -----------------------------------------------------------------------
template<typename Alloc>
bool bvector<Alloc>::is_all_one_range(size_type left,
size_type right) const BMNOEXCEPT
{
if (!blockman_.is_init())
return false; // nothing to do
if (right < left)
bm::xor_swap(left, right);
if (right == bm::id_max)
--right;
if (left == right)
return test(left);
BM_ASSERT(left < bm::id_max && right < bm::id_max);
block_idx_type nblock_left = (left >> bm::set_block_shift);
block_idx_type nblock_right = (right >> bm::set_block_shift);
unsigned i0, j0;
bm::get_block_coord(nblock_left, i0, j0);
const bm::word_t* block = blockman_.get_block(i0, j0);
if (nblock_left == nblock_right) // hit in the same block
{
unsigned nbit_left = unsigned(left & bm::set_block_mask);
unsigned nbit_right = unsigned(right & bm::set_block_mask);
return bm::block_is_all_one_range(block, nbit_left, nbit_right);
}
// process entry point block
{
unsigned nbit_left = unsigned(left & bm::set_block_mask);
bool all_one = bm::block_is_all_one_range(block,
nbit_left, (bm::gap_max_bits-1));
if (!all_one)
return all_one;
++nblock_left;
}
// process tail block
{
bm::get_block_coord(nblock_right, i0, j0);
block = blockman_.get_block(i0, j0);
unsigned nbit_right = unsigned(right & bm::set_block_mask);
bool all_one = bm::block_is_all_one_range(block, 0, nbit_right);
if (!all_one)
return all_one;
--nblock_right;
}
// check all blocks in the middle
//
if (nblock_left <= nblock_right)
{
unsigned i_from, j_from, i_to, j_to;
bm::get_block_coord(nblock_left, i_from, j_from);
bm::get_block_coord(nblock_right, i_to, j_to);
bm::word_t*** blk_root = blockman_.top_blocks_root();
for (unsigned i = i_from; i <= i_to; ++i)
{
bm::word_t** blk_blk = blk_root[i];
if (!blk_blk)
return false;
if ((bm::word_t*)blk_blk == FULL_BLOCK_FAKE_ADDR)
continue;
unsigned j = (i == i_from) ? j_from : 0;
unsigned j_limit = (i == i_to) ? j_to+1 : bm::set_sub_array_size;
do
{
bool all_one = bm::check_block_one(blk_blk[j], true);
if (!all_one)
return all_one;
} while (++j < j_limit);
} // for i
}
return true;
}
// -----------------------------------------------------------------------
template<typename Alloc>
bool bvector<Alloc>::any_range(size_type left, size_type right) const BMNOEXCEPT
{
BM_ASSERT(left < bm::id_max && right < bm::id_max);
if (!blockman_.is_init())
return false; // nothing to do
if (right < left)
bm::xor_swap(left, right);
if (right == bm::id_max)
--right;
if (left == right)
return test(left);
block_idx_type nblock_left = (left >> bm::set_block_shift);
block_idx_type nblock_right = (right >> bm::set_block_shift);
unsigned i0, j0;
bm::get_block_coord(nblock_left, i0, j0);
const bm::word_t* block = blockman_.get_block(i0, j0);
if (nblock_left == nblock_right) // hit in the same block
{
unsigned nbit_left = unsigned(left & bm::set_block_mask);
unsigned nbit_right = unsigned(right & bm::set_block_mask);
return bm::block_any_range(block, nbit_left, nbit_right);
}
// process entry point block
{
unsigned nbit_left = unsigned(left & bm::set_block_mask);
bool any_one = bm::block_any_range(block,
nbit_left, (bm::gap_max_bits-1));
if (any_one)
return any_one;
++nblock_left;
}
// process tail block
{
bm::get_block_coord(nblock_right, i0, j0);
block = blockman_.get_block(i0, j0);
unsigned nbit_right = unsigned(right & bm::set_block_mask);
bool any_one = bm::block_any_range(block, 0, nbit_right);
if (any_one)
return any_one;
--nblock_right;
}
// check all blocks in the middle
//
if (nblock_left <= nblock_right)
{
unsigned i_from, j_from, i_to, j_to;
bm::get_block_coord(nblock_left, i_from, j_from);
bm::get_block_coord(nblock_right, i_to, j_to);
bm::word_t*** blk_root = blockman_.top_blocks_root();
{
block_idx_type top_size = blockman_.top_block_size();
if (i_from >= top_size)
return false;
if (i_to >= top_size)
{
i_to = unsigned(top_size-1);
j_to = bm::set_sub_array_size-1;
}
}
for (unsigned i = i_from; i <= i_to; ++i)
{
bm::word_t** blk_blk = blk_root[i];
if (!blk_blk)
continue;
if ((bm::word_t*)blk_blk == FULL_BLOCK_FAKE_ADDR)
return true;
unsigned j = (i == i_from) ? j_from : 0;
unsigned j_limit = (i == i_to) ? j_to+1 : bm::set_sub_array_size;
do
{
bool any_one = bm::block_any(blk_blk[j]);
if (any_one)
return any_one;
} while (++j < j_limit);
} // for i
}
return false;
}
// -----------------------------------------------------------------------
template<typename Alloc>
typename bvector<Alloc>::size_type
bvector<Alloc>::count_range(size_type left,
size_type right,
const rs_index_type& rs_idx) const BMNOEXCEPT
{
if (left > right)
bm::xor_swap(left, right);
BM_ASSERT_THROW(right < bm::id_max, BM_ERR_RANGE);
return count_range_no_check(left, right, rs_idx);
}
// -----------------------------------------------------------------------
template<typename Alloc>
typename bvector<Alloc>::size_type
bvector<Alloc>::count_range_no_check(size_type left,
size_type right,
const rs_index_type& rs_idx) const BMNOEXCEPT
{
BM_ASSERT(left <= right);
if (left == right)
return this->test(left);
size_type cnt_l, cnt_r;
if (left)
cnt_l = this->count_to(left-1, rs_idx);
else
cnt_l = left; // == 0
cnt_r = this->count_to(right, rs_idx);
BM_ASSERT(cnt_r >= cnt_l);
return cnt_r - cnt_l;
}
// -----------------------------------------------------------------------
template<typename Alloc>
bvector<Alloc>& bvector<Alloc>::invert()
{
BM_ASSERT(!is_ro());
if (!size_)
return *this; // cannot invert a set of power 0
unsigned top_blocks = blockman_.reserve_top_blocks(bm::set_top_array_size);
bm::word_t*** blk_root = blockman_.top_blocks_root();
for (unsigned i = 0; i < top_blocks; ++i)
{
bm::word_t** blk_blk = blk_root[i];
if (!blk_blk)
{
blk_root[i] = (bm::word_t**)FULL_BLOCK_FAKE_ADDR;
continue;
}
if (blk_blk == (bm::word_t**)FULL_BLOCK_FAKE_ADDR)
{
blk_root[i] = 0;
continue;
}
unsigned j = 0; bm::word_t* blk;
do
{
blk = blk_blk[j];
if (!blk)
blockman_.set_block_ptr(i, j, FULL_BLOCK_FAKE_ADDR);
else
if (IS_FULL_BLOCK(blk))
blockman_.set_block_ptr(i, j, 0);
else
{
if (BM_IS_GAP(blk))
bm::gap_invert(BMGAP_PTR(blk));
else
bm::bit_invert((wordop_t*)blk);
}
} while (++j < bm::set_sub_array_size);
} // for i
if (size_ == bm::id_max)
set_bit_no_check(bm::id_max, false);
else
clear_range_no_check(size_, bm::id_max);
return *this;
}
// -----------------------------------------------------------------------
template<typename Alloc>
bool bvector<Alloc>::get_bit(size_type n) const BMNOEXCEPT
{
BM_ASSERT(n < size_);
BM_ASSERT_THROW((n < size_), BM_ERR_RANGE);
// calculate logical block number
unsigned nb = unsigned(n >> bm::set_block_shift);
unsigned i, j;
bm::get_block_coord(nb, i, j);
if (!blockman_.top_blocks_ || i >= blockman_.top_block_size_)
return false;
const bm::word_t* const* blk_blk = blockman_.top_blocks_[i];
if ((bm::word_t*)blk_blk == FULL_BLOCK_FAKE_ADDR)
return true;
if (!blk_blk) return false;
if (const bm::word_t* block = blk_blk[j])
{
if (block == FULL_BLOCK_FAKE_ADDR)
return true;
unsigned nbit = unsigned(n & bm::set_block_mask);
if (BM_IS_GAP(block))
return bm::gap_test_unr(BMGAP_PTR(block), nbit);
return block[nbit >> bm::set_word_shift] &
(1u << (nbit & bm::set_word_mask));
}
return false;
}
// -----------------------------------------------------------------------
template<typename Alloc>
void bvector<Alloc>::optimize(bm::word_t* temp_block,
optmode opt_mode,
statistics* stat)
{
BM_ASSERT(!is_ro());
if (!blockman_.is_init())
{
if (stat)
calc_stat(stat);
return;
}
if (!temp_block)
temp_block = blockman_.check_allocate_tempblock();
if (stat)
{
stat->reset();
::memcpy(stat->gap_levels,
blockman_.glen(), sizeof(gap_word_t) * bm::gap_levels);
stat->max_serialize_mem = (unsigned)sizeof(bm::id_t) * 4;
}
blockman_.optimize_tree(temp_block, opt_mode, stat);
if (stat)
{
blockman_.stat_correction(stat);
stat->memory_used += (unsigned)(sizeof(*this) - sizeof(blockman_));
}
// don't need to keep temp block if we optimizing memory usage
blockman_.free_temp_block();
}
// -----------------------------------------------------------------------
template<typename Alloc>
void bvector<Alloc>::optimize_range(
size_type left,
size_type right,
bm::word_t* temp_block,
optmode opt_mode)
{
BM_ASSERT(!is_ro());
BM_ASSERT(left <= right);
BM_ASSERT(temp_block);
block_idx_type nblock_left = (left >> bm::set_block_shift);
block_idx_type nblock_right = (right >> bm::set_block_shift);
for (; nblock_left <= nblock_right; ++nblock_left)
{
unsigned i0, j0;
bm::get_block_coord(nblock_left, i0, j0);
if (i0 >= blockman_.top_block_size())
break;
bm::word_t* block = blockman_.get_block_ptr(i0, j0);
if (block)
blockman_.optimize_block(i0, j0, block, temp_block, opt_mode, 0);
} // for
}
// -----------------------------------------------------------------------
template<typename Alloc>
void bvector<Alloc>::optimize_gap_size()
{
#if 0
if (!blockman_.is_init())
return;
struct bvector<Alloc>::statistics st;
calc_stat(&st);
if (!st.gap_blocks)
return;
gap_word_t opt_glen[bm::gap_levels];
::memcpy(opt_glen, st.gap_levels, bm::gap_levels * sizeof(*opt_glen));
improve_gap_levels(st.gap_length,
st.gap_length + st.gap_blocks,
opt_glen);
set_gap_levels(opt_glen);
#endif
}
// -----------------------------------------------------------------------
template<typename Alloc>
void bvector<Alloc>::set_gap_levels(const gap_word_t* glevel_len)
{
BM_ASSERT(!is_ro());
if (blockman_.is_init())
{
word_t*** blk_root = blockman_.top_blocks_root();
typename
blocks_manager_type::gap_level_func gl_func(blockman_, glevel_len);
for_each_nzblock(blk_root, blockman_.top_block_size(),gl_func);
}
blockman_.set_glen(glevel_len);
}
// -----------------------------------------------------------------------
template<typename Alloc>
int bvector<Alloc>::compare(const bvector<Alloc>& bv) const BMNOEXCEPT
{
int res;
unsigned top_blocks = blockman_.top_block_size();
unsigned bvect_top_blocks = bv.blockman_.top_block_size();
if (bvect_top_blocks > top_blocks) top_blocks = bvect_top_blocks;
for (unsigned i = 0; i < top_blocks; ++i)
{
const bm::word_t* const* blk_blk = blockman_.get_topblock(i);
const bm::word_t* const* arg_blk_blk = bv.blockman_.get_topblock(i);
if (blk_blk == arg_blk_blk)
continue;
for (unsigned j = 0; j < bm::set_sub_array_size; ++j)
{
const bm::word_t* arg_blk; const bm::word_t* blk;
if ((bm::word_t*)arg_blk_blk == FULL_BLOCK_FAKE_ADDR)
arg_blk = FULL_BLOCK_REAL_ADDR;
else
{
arg_blk = arg_blk_blk ? arg_blk_blk[j] : 0;
if (arg_blk == FULL_BLOCK_FAKE_ADDR)
arg_blk = FULL_BLOCK_REAL_ADDR;
}
if ((bm::word_t*)blk_blk == FULL_BLOCK_FAKE_ADDR)
blk = FULL_BLOCK_REAL_ADDR;
else
{
blk = blk_blk ? blk_blk[j] : 0;
if (blk == FULL_BLOCK_FAKE_ADDR)
blk = FULL_BLOCK_REAL_ADDR;
}
if (blk == arg_blk) continue;
// If one block is zero we check if the other one has at least
// one bit ON
if (!blk || !arg_blk)
{
const bm::word_t* pblk; bool is_gap;
if (blk)
{
pblk = blk;
res = 1;
is_gap = BM_IS_GAP(blk);
}
else
{
pblk = arg_blk;
res = -1;
is_gap = BM_IS_GAP(arg_blk);
}
if (is_gap)
{
if (!bm::gap_is_all_zero(BMGAP_PTR(pblk)))
return res;
}
else
{
if (!bm::bit_is_all_zero(pblk))
return res;
}
continue;
}
bool arg_gap = BM_IS_GAP(arg_blk);
bool gap = BM_IS_GAP(blk);
if (arg_gap != gap)
{
BM_DECLARE_TEMP_BLOCK(temp_blk)
bm::wordop_t* blk1; bm::wordop_t* blk2;
if (gap)
{
bm::gap_convert_to_bitset((bm::word_t*)temp_blk,
BMGAP_PTR(blk));
blk1 = (bm::wordop_t*)temp_blk;
blk2 = (bm::wordop_t*)arg_blk;
}
else
{
bm::gap_convert_to_bitset((bm::word_t*)temp_blk,
BMGAP_PTR(arg_blk));
blk1 = (bm::wordop_t*)blk;
blk2 = (bm::wordop_t*)temp_blk;
}
res = bm::bitcmp(blk1, blk2, bm::set_block_size_op);
}
else
{
if (gap)
{
res = bm::gapcmp(BMGAP_PTR(blk), BMGAP_PTR(arg_blk));
}
else
{
res = bm::bitcmp((bm::wordop_t*)blk,
(bm::wordop_t*)arg_blk,
bm::set_block_size_op);
}
}
if (res != 0)
return res;
} // for j
} // for i
return 0;
}
// -----------------------------------------------------------------------
template<typename Alloc>
bool bvector<Alloc>::find_first_mismatch(
const bvector<Alloc>& bvect, size_type& pos,
size_type search_to) const BMNOEXCEPT
{
unsigned top_blocks = blockman_.top_block_size();
bm::word_t*** top_root = blockman_.top_blocks_root();
if (!top_blocks || !top_root)
{
return bvect.find(pos);
}
bm::word_t*** arg_top_root = bvect.blockman_.top_blocks_root();
unsigned i_to, j_to;
{
unsigned bvect_top_blocks = bvect.blockman_.top_block_size();
if (!bvect_top_blocks || !arg_top_root)
{
bool f = this->find(pos);
if (f)
{
if (pos > search_to)
return false;
}
return f;
}
if (bvect_top_blocks > top_blocks)
top_blocks = bvect_top_blocks;
block_idx_type nb_to = (search_to >> bm::set_block_shift);
bm::get_block_coord(nb_to, i_to, j_to);
}
if (i_to < top_blocks)
top_blocks = i_to+1;
for (unsigned i = 0; i < top_blocks; ++i)
{
const bm::word_t* const* blk_blk = blockman_.get_topblock(i);
const bm::word_t* const* arg_blk_blk = bvect.blockman_.get_topblock(i);
if (blk_blk == arg_blk_blk)
{
/* TODO: fix buffer overrread here
unsigned arg_top_blocks = bvect.blockman_.top_block_size_;
if (top_blocks < arg_top_blocks)
arg_top_blocks = top_blocks;
if (i_to < arg_top_blocks)
arg_top_blocks = i_to+1;
// look ahead for top level mismatch
for (++i; i < arg_top_blocks; ++i)
{
if (top_root[i] != arg_top_root[i])
{
blk_blk = blockman_.get_topblock(i);
arg_blk_blk = bvect.blockman_.get_topblock(i);
BM_ASSERT(blk_blk != arg_blk_blk);
goto find_sub_block;
}
}
*/
continue;
}
//find_sub_block:
unsigned j = 0;
do
{
const bm::word_t* arg_blk; const bm::word_t* blk;
arg_blk = ((bm::word_t*)arg_blk_blk == FULL_BLOCK_FAKE_ADDR) ?
FULL_BLOCK_REAL_ADDR :
arg_blk_blk ? (BLOCK_ADDR_SAN(arg_blk_blk[j])) : 0;
blk = ((bm::word_t*)blk_blk == FULL_BLOCK_FAKE_ADDR) ?
FULL_BLOCK_REAL_ADDR :
(blk_blk ? (BLOCK_ADDR_SAN(blk_blk[j])) : 0);
if (blk == arg_blk)
continue;
unsigned block_pos;
bool found = bm::block_find_first_diff(blk, arg_blk, &block_pos);
if (found)
{
pos =
(size_type(i) * bm::set_sub_array_size * bm::gap_max_bits) +
(size_type(j) * bm::gap_max_bits) + block_pos;
if (pos > search_to)
return false;
return true;
}
if (i == i_to)
{
if (j >= j_to)
return false;
}
} while (++j < bm::set_sub_array_size);
} // for i
return false;
}
// -----------------------------------------------------------------------
template<typename Alloc>
void bvector<Alloc>::swap(bvector<Alloc>& bvect) BMNOEXCEPT
{
if (this != &bvect)
{
blockman_.swap(bvect.blockman_);
bm::xor_swap(size_,bvect.size_);
}
}
// -----------------------------------------------------------------------
template<typename Alloc>
void bvector<Alloc>::calc_stat(
struct bvector<Alloc>::statistics* st) const BMNOEXCEPT
{
BM_ASSERT(st);
st->reset();
::memcpy(st->gap_levels,
blockman_.glen(), sizeof(gap_word_t) * bm::gap_levels);
st->max_serialize_mem = unsigned(sizeof(bm::id_t) * 4);
unsigned top_size = blockman_.top_block_size();
size_t blocks_mem = sizeof(blockman_);
blocks_mem +=
(blockman_.temp_block_ ? sizeof(bm::word_t) * bm::set_block_size : 0);
blocks_mem += sizeof(bm::word_t**) * top_size;
bm::word_t*** blk_root = blockman_.top_blocks_root();
if (blk_root)
{
for (unsigned i = 0; i < top_size; ++i)
{
const bm::word_t* const* blk_blk = blk_root[i];
if (!blk_blk)
{
++i;
bool found = bm::find_not_null_ptr(blk_root, i, top_size, &i);
if (!found)
break;
blk_blk = blk_root[i];
BM_ASSERT(blk_blk);
if (!blk_blk)
break;
}
if ((bm::word_t*)blk_blk == FULL_BLOCK_FAKE_ADDR)
continue;
st->ptr_sub_blocks++;
for (unsigned j = 0; j < bm::set_sub_array_size; ++j)
{
const bm::word_t* blk = blk_blk[j];
if (IS_VALID_ADDR(blk))
{
if (BM_IS_GAP(blk))
{
const bm::gap_word_t* gap_blk = BMGAP_PTR(blk);
unsigned cap;
unsigned len = gap_length(gap_blk);
cap = is_ro() ? len
: bm::gap_capacity(gap_blk, blockman_.glen());
unsigned level = bm::gap_level(gap_blk);
st->add_gap_block(cap, len, level);
}
else // bit block
st->add_bit_block();
}
} // for j
} // for i
size_t full_null_size = blockman_.calc_serialization_null_full();
st->max_serialize_mem += full_null_size;
} // if blk_root
size_t safe_inc = st->max_serialize_mem / 10; // 10% increment
if (!safe_inc) safe_inc = 256;
st->max_serialize_mem += safe_inc;
// Calc size of different odd and temporary things.
st->memory_used += unsigned(sizeof(*this) - sizeof(blockman_));
blocks_mem += st->ptr_sub_blocks * (sizeof(void*) * bm::set_sub_array_size);
st->memory_used += blocks_mem;
if (is_ro())
st->memory_used += sizeof(typename blocks_manager_type::arena);
st->bv_count = 1;
}
// -----------------------------------------------------------------------
template<typename Alloc>
void bvector<Alloc>::fill_alloc_digest(bvector<Alloc>& bv_blocks) const
{
bv_blocks.init();
unsigned top_size = blockman_.top_block_size();
bm::word_t*** blk_root = blockman_.top_blocks_root();
if (blk_root)
{
for (unsigned i = 0; i < top_size; ++i)
{
const bm::word_t* const* blk_blk = blk_root[i];
if (!blk_blk || ((bm::word_t*)blk_blk == FULL_BLOCK_FAKE_ADDR))
continue;
for (unsigned j = 0; j < bm::set_sub_array_size; ++j)
{
const bm::word_t* blk = blk_blk[j];
if (IS_VALID_ADDR(blk))
{
size_type nb = i * bm::set_sub_array_size + j;
bv_blocks.set_bit_no_check(nb);
}
} // for j
} // for i
} // if blk_root
}
// -----------------------------------------------------------------------
template<class Alloc>
void bvector<Alloc>::set(const size_type* ids,
size_type ids_size, bm::sort_order so)
{
BM_ASSERT(!is_ro());
if (!ids || !ids_size)
return; // nothing to do
if (!blockman_.is_init())
blockman_.init_tree();
import(ids, ids_size, so);
sync_size();
}
// -----------------------------------------------------------------------
template<class Alloc>
void bvector<Alloc>::keep(const size_type* ids, size_type ids_size,
bm::sort_order so)
{
BM_ASSERT(!is_ro());
if (!ids || !ids_size || !blockman_.is_init())
{
clear();
return;
}
bvector<Alloc> bv_tmp; // TODO: better optimize for SORTED case (avoid temp)
bv_tmp.import(ids, ids_size, so);
size_type last;
bool found = bv_tmp.find_reverse(last);
if (found)
{
bv_tmp.resize(last+1);
bit_and(bv_tmp);
}
else
{
BM_ASSERT(0);
clear();
}
}
// -----------------------------------------------------------------------
template<class Alloc>
void bvector<Alloc>::clear(bool free_mem) BMNOEXCEPT
{
if (is_ro())
{
BM_ASSERT(free_mem);
blockman_.destroy_arena();
}
else
blockman_.set_all_zero(free_mem);
}
// -----------------------------------------------------------------------
template<class Alloc>
void bvector<Alloc>::clear(const size_type* ids,
size_type ids_size, bm::sort_order so)
{
BM_ASSERT(!is_ro());
if (!ids || !ids_size || !blockman_.is_init())
{
return;
}
bvector<Alloc> bv_tmp; // TODO: better optimize for SORTED case (avoid temp)
bv_tmp.import(ids, ids_size, so);
size_type last;
bool found = bv_tmp.find_reverse(last);
if (found)
{
bv_tmp.resize(last+1);
bit_sub(bv_tmp);
}
else
{
BM_ASSERT(0);
}
}
// -----------------------------------------------------------------------
template<class Alloc>
bvector<Alloc>& bvector<Alloc>::set()
{
BM_ASSERT(!is_ro());
set_range(0, size_ - 1, true);
return *this;
}
// -----------------------------------------------------------------------
template<class Alloc>
bvector<Alloc>& bvector<Alloc>::set(size_type n, bool val)
{
BM_ASSERT(!is_ro());
set_bit(n, val);
return *this;
}
// -----------------------------------------------------------------------
template<class Alloc>
bool bvector<Alloc>::set_bit_conditional(size_type n, bool val, bool condition)
{
if (val == condition) return false;
if (n >= size_)
{
size_type new_size = (n == bm::id_max) ? bm::id_max : n + 1;
resize(new_size);
}
return set_bit_conditional_impl(n, val, condition);
}
// -----------------------------------------------------------------------
template<class Alloc>
bool bvector<Alloc>::set_bit_and(size_type n, bool val)
{
BM_ASSERT(!is_ro());
BM_ASSERT(n < size_);
BM_ASSERT_THROW(n < size_, BM_ERR_RANGE);
if (!blockman_.is_init())
blockman_.init_tree();
return and_bit_no_check(n, val);
}
// -----------------------------------------------------------------------
template<class Alloc>
bool bvector<Alloc>::set_bit(size_type n, bool val)
{
BM_ASSERT(!is_ro());
BM_ASSERT_THROW(n < bm::id_max, BM_ERR_RANGE);
if (!blockman_.is_init())
blockman_.init_tree();
if (n >= size_)
{
size_type new_size = (n == bm::id_max) ? bm::id_max : n + 1;
resize(new_size);
}
return set_bit_no_check(n, val);
}
// -----------------------------------------------------------------------
template<class Alloc>
void bvector<Alloc>::import(const size_type* ids, size_type size_in,
bm::sort_order sorted_idx)
{
BM_ASSERT(!is_ro());
if (!size_in)
return;
size_type n, start(0), stop(size_in);
block_idx_type nblock;
n = ids[start];
nblock = (n >> bm::set_block_shift);
switch(sorted_idx)
{
case BM_SORTED:
{
block_idx_type nblock_end = (ids[size_in-1] >> bm::set_block_shift);
if (nblock == nblock_end) // special case: one block import
{
import_block(ids, nblock, 0, stop);
return;
}
// multi-block import, do top block space reservation
unsigned i, j;
bm::get_block_coord(nblock_end, i, j);
blockman_.reserve_top_blocks(i+1);
}
break;
default:
break;
} // switch
do
{
n = ids[start];
nblock = (n >> bm::set_block_shift);
#ifdef BM64ADDR
stop = bm::idx_arr_block_lookup_u64(ids, size_in, nblock, start);
#else
stop = bm::idx_arr_block_lookup_u32(ids, size_in, nblock, start);
#endif
BM_ASSERT(start < stop);
import_block(ids, nblock, start, stop);
start = stop;
} while (start < size_in);
}
// -----------------------------------------------------------------------
template<class Alloc>
void bvector<Alloc>::import_sorted(const size_type* ids,
const size_type size_in,
bool opt_flag)
{
BM_ASSERT(size_in);
BM_ASSERT(ids[0] < bm::id_max); // limit is 2^31-1 (for 32-bit mode)
BM_ASSERT(ids[size_in-1] < bm::id_max);
size_type n, start(0), stop = size_in;
block_idx_type nblock, nblock_end;
n = ids[start];
nblock = (n >> bm::set_block_shift);
nblock_end = (ids[size_in-1] >> bm::set_block_shift);
if (nblock == nblock_end) // special (but frequent)case: one block import
{
import_block(ids, nblock, 0, stop);
unsigned nbit = unsigned(ids[size_in-1] & bm::set_block_mask);
if (opt_flag && nbit == 65535) // last bit in block
{
unsigned i, j;
bm::get_block_coord(nblock, i, j);
blockman_.optimize_bit_block(i, j, opt_compress);
}
}
else
{
do
{
// TODO: use one-sided binary search to find the block limits
#ifdef BM64ADDR
stop = bm::idx_arr_block_lookup_u64(ids, size_in, nblock, start);
#else
stop = bm::idx_arr_block_lookup_u32(ids, size_in, nblock, start);
#endif
BM_ASSERT(start < stop);
import_block(ids, nblock, start, stop);
start = stop;
nblock = (ids[stop] >> bm::set_block_shift);
} while (start < size_in);
if (opt_flag) // multi-block sorted import, lets optimize
{
n = ids[start];
nblock = (n >> bm::set_block_shift);
nblock_end = (ids[size_in-1] >> bm::set_block_shift);
unsigned nbit = unsigned(ids[size_in-1] & bm::set_block_mask);
nblock_end += bool(nbit == 65535);
do
{
unsigned i, j;
bm::get_block_coord(nblock++, i, j);
blockman_.optimize_bit_block(i, j, opt_compress);
} while (nblock < nblock_end);
}
}
}
// -----------------------------------------------------------------------
template<class Alloc>
void bvector<Alloc>::import_block(const size_type* ids,
block_idx_type nblock,
size_type start,
size_type stop)
{
BM_ASSERT(stop > start);
int block_type;
bm::word_t* blk =
blockman_.check_allocate_block(nblock, 1, 0, &block_type,
true/*allow NULL ret*/);
if (!IS_FULL_BLOCK(blk))
{
if (BM_IS_GAP(blk))
{
if (stop-start == 1)
{
unsigned nbit = unsigned(ids[0] & bm::set_block_mask);
gap_block_set_no_ret(BMGAP_PTR(blk), true, nblock, nbit);
return;
}
blk = blockman_.deoptimize_block(nblock); // TODO: try to avoid
}
#ifdef BM64ADDR
bm::set_block_bits_u64(blk, ids, start, stop);
#else
bm::set_block_bits_u32(blk, ids, start, stop);
#endif
if (new_blocks_strat_ == BM_GAP) // optimization required
{
BM_DECLARE_TEMP_BLOCK(temp_blk);
unsigned i0, j0;
bm::get_block_coord(nblock, i0, j0);
blockman_.optimize_block(i0, j0, blk, temp_blk, opt_compress, 0);
}
if (nblock == bm::set_total_blocks-1)
blk[bm::set_block_size-1] &= ~(1u<<31); // clear the "impossible" last just in case
}
}
// -----------------------------------------------------------------------
template<class Alloc>
void bvector<Alloc>::swap(size_type idx1, size_type idx2)
{
BM_ASSERT(!is_ro());
BM_ASSERT_THROW(idx1 < bm::id_max, BM_ERR_RANGE);
BM_ASSERT_THROW(idx2 < bm::id_max, BM_ERR_RANGE);
block_idx_type nb1 = (idx1 >> bm::set_block_shift);
block_idx_type nb2 = (idx2 >> bm::set_block_shift);
bm::word_t* block1, *block2;
unsigned nbit1, nbit2;
nbit1 = unsigned(idx1 & bm::set_block_mask);
nbit2 = unsigned(idx2 & bm::set_block_mask);
if (nb1 == nb2) // same block hit
{
unsigned i0, j0;
bm::get_block_coord(nb1, i0, j0);
block1 = blockman_.get_block_ptr(i0, j0);
if (!block1 || (block1==FULL_BLOCK_FAKE_ADDR)) // nothing to do?
return;
if (BM_IS_GAP(block1))
{
bm::gap_word_t* gblk = BMGAP_PTR(block1);
bool b1 = bm::gap_test_unr(gblk, nbit1);
bool b2 = bm::gap_test_unr(gblk, nbit2);
if (b1 != b2)
{
this->gap_block_set_no_ret(gblk, b2, nb1, nbit1);
block2 = blockman_.get_block_ptr(i0, j0);
if (block1 == block2) // same block
this->gap_block_set_no_ret(gblk, b1, nb1, nbit2);
else
set_bit_no_check(idx2, b1);
}
return;
}
unsigned nword1 = unsigned(nbit1 >> bm::set_word_shift);
unsigned nword2 = unsigned(nbit2 >> bm::set_word_shift);
nbit1 &= bm::set_word_mask; nbit2 &= bm::set_word_mask;
bool b1 = block1[nword1] & (1u << nbit1);
bool b2 = block1[nword2] & (1u << nbit2);
if (b1 != b2)
{
nbit1 = 1u << nbit1; nbit2 = 1u << nbit2;
auto w = block1[nword1];
(b2) ? w |= nbit1 : w &= ~nbit1;
block1[nword1] = w;
w = block1[nword2];
(b1) ? w |= nbit2 : w &= ~nbit2;
block1[nword2] = w;
}
return;
} // if (same block)
{
unsigned i0, j0;
bm::get_block_coord(nb1, i0, j0);
block1 = blockman_.get_block_ptr(i0, j0);
bm::get_block_coord(nb2, i0, j0);
block2 = blockman_.get_block_ptr(i0, j0);
}
if (block1 == block2) // nothing to do
return;
bm::gap_word_t *gblk1{0}, *gblk2{0};
unsigned cpos1{ 0 }, cpos2{ 0 };
bool b1, b2, b1real, b2real;
if (!block1)
{
b1 = false; b1real = false;
}
else
if (block1 == FULL_BLOCK_FAKE_ADDR)
{
b1 = true; b1real = false;
}
else
{
b1real = true;
nbit1 = unsigned(idx1 & bm::set_block_mask);
if (BM_IS_GAP(block1))
{
gblk1 = BMGAP_PTR(block1);
unsigned is_set;
cpos1 = bm::gap_bfind(gblk1, nbit1, &is_set);
b1 = is_set;
}
else // bit block
{
unsigned nword1 = unsigned(nbit1 >> bm::set_word_shift);
b1 = block1[nword1] & (1u << (nbit1 & bm::set_word_mask));
}
}
if (!block2)
{
b2 = false; b2real = false;
}
else
if (block2 == FULL_BLOCK_FAKE_ADDR)
{
b2 = true; b2real = false;
}
else
{
b2real = true;
nbit2 = unsigned(idx2 & bm::set_block_mask);
if (BM_IS_GAP(block2))
{
gblk2 = BMGAP_PTR(block2);
unsigned is_set;
cpos2 = bm::gap_bfind(gblk2, nbit2, &is_set);
b2 = is_set;
}
else // bit block
{
unsigned nword2 = unsigned(nbit2 >> bm::set_word_shift);
b2 = block2[nword2] & (1u << (nbit2 & bm::set_word_mask));
}
}
if (b1 == b2)
return;
if (b1real)
{
if (BM_IS_GAP(block1))
{
unsigned new_len, old_len;
unsigned is_set = b1;
old_len = bm::gap_length(gblk1)-1;
new_len = bm::gap_set_value_cpos(b2, gblk1, nbit1, &is_set, cpos1);
if (old_len < new_len)
{
unsigned threshold = bm::gap_limit(gblk1, blockman_.glen());
if (new_len > threshold)
blockman_.extend_gap_block(nb1, gblk1);
}
}
else // bit block
{
unsigned nword1 = unsigned(nbit1 >> bm::set_word_shift);
nbit1 = 1u << (nbit1 & bm::set_word_mask);
auto w = block1[nword1];
(b2) ? w |= nbit1 : w &= ~nbit1;
block1[nword1] = w;
}
}
else // block
{
set_bit_no_check(idx1, b2);
}
if (b2real)
{
if (BM_IS_GAP(block2))
{
unsigned new_len, old_len;
unsigned is_set = b2;
old_len = bm::gap_length(gblk2)-1;
new_len = bm::gap_set_value_cpos(b1, gblk2, nbit2, &is_set, cpos2);
if (old_len < new_len)
{
unsigned threshold = bm::gap_limit(gblk2, blockman_.glen());
if (new_len > threshold)
blockman_.extend_gap_block(nb2, gblk2);
}
}
else // bit block
{
unsigned nword2 = unsigned(nbit2 >> bm::set_word_shift);
nbit2 = 1u << (nbit2 & bm::set_word_mask);
auto w = block2[nword2];
(b1) ? w |= nbit2 : w &= ~nbit2;
block2[nword2] = w;
}
}
else
{
set_bit_no_check(idx2, b1);
}
}
// -----------------------------------------------------------------------
template<class Alloc>
bool bvector<Alloc>::set_bit_no_check(size_type n, bool val)
{
BM_ASSERT(!is_ro());
BM_ASSERT_THROW(n < bm::id_max, BM_ERR_RANGE);
// calculate logical block number
block_idx_type nblock = (n >> bm::set_block_shift);
int block_type;
bm::word_t* blk =
blockman_.check_allocate_block(nblock,
val,
get_new_blocks_strat(),
&block_type);
if (!IS_VALID_ADDR(blk))
return false;
// calculate word number in block and bit
unsigned nbit = unsigned(n & bm::set_block_mask);
if (block_type) // gap
{
return gap_block_set(BMGAP_PTR(blk), val, nblock, nbit);
}
else // bit block
{
unsigned nword = unsigned(nbit >> bm::set_word_shift);
nbit &= bm::set_word_mask;
bm::word_t* word = blk + nword;
bm::word_t mask = (((bm::word_t)1) << nbit);
if (val)
{
val = ~(*word & mask);
*word |= mask; // set bit
return val;
}
else
{
val = ~(*word & mask);
*word &= ~mask; // clear bit
return val;
}
}
}
// -----------------------------------------------------------------------
template<class Alloc>
void bvector<Alloc>::set_bit_no_check(size_type n)
{
BM_ASSERT(!is_ro());
BM_ASSERT_THROW(n < bm::id_max, BM_ERR_RANGE);
const bool val = true; // set bit
block_idx_type nblock = (n >> bm::set_block_shift);
unsigned nbit = unsigned(n & bm::set_block_mask);
int block_type;
bm::word_t* blk =
blockman_.check_allocate_block(nblock,
val,
get_new_blocks_strat(),
&block_type);
if (!IS_VALID_ADDR(blk))
return;
if (block_type) // gap block
{
this->gap_block_set_no_ret(BMGAP_PTR(blk), val, nblock, nbit);
}
else // bit block
{
unsigned nword = nbit >> bm::set_word_shift;
nbit &= bm::set_word_mask;
blk[nword] |= (1u << nbit); // set bit
}
}
// -----------------------------------------------------------------------
template<class Alloc>
void bvector<Alloc>::clear_bit_no_check(size_type n)
{
BM_ASSERT(!is_ro());
BM_ASSERT_THROW(n < bm::id_max, BM_ERR_RANGE);
const bool val = false; // clear bit
block_idx_type nblock = (n >> bm::set_block_shift);
int block_type;
bm::word_t* blk =
blockman_.check_allocate_block(nblock,
val,
get_new_blocks_strat(),
&block_type);
if (!blk)
return;
unsigned nbit = unsigned(n & bm::set_block_mask);
if (block_type) // gap
{
this->gap_block_set_no_ret(BMGAP_PTR(blk), val, nblock, nbit);
}
else // bit block
{
unsigned nword = unsigned(nbit >> bm::set_word_shift);
nbit &= bm::set_word_mask;
blk[nword] &= ~(1u << nbit); // clear bit
}
}
// -----------------------------------------------------------------------
template<class Alloc>
bool bvector<Alloc>::gap_block_set(bm::gap_word_t* gap_blk,
bool val, block_idx_type nblock,
unsigned nbit)
{
unsigned is_set, new_len, old_len;
old_len = bm::gap_length(gap_blk)-1;
new_len = bm::gap_set_value(val, gap_blk, nbit, &is_set);
if (old_len < new_len)
{
unsigned threshold = bm::gap_limit(gap_blk, blockman_.glen());
if (new_len > threshold)
blockman_.extend_gap_block(nblock, gap_blk);
}
return is_set;
}
// -----------------------------------------------------------------------
template<class Alloc>
void bvector<Alloc>::gap_block_set_no_ret(bm::gap_word_t* gap_blk,
bool val, block_idx_type nblock, unsigned nbit)
{
unsigned new_len, old_len;
old_len = bm::gap_length(gap_blk)-1;
new_len = bm::gap_set_value(val, gap_blk, nbit);
if (old_len < new_len)
{
unsigned threshold = bm::gap_limit(gap_blk, blockman_.glen());
if (new_len > threshold)
blockman_.extend_gap_block(nblock, gap_blk);
}
}
// -----------------------------------------------------------------------
template<class Alloc>
bool bvector<Alloc>::inc(size_type n)
{
BM_ASSERT(!is_ro());
// calculate logical block number
block_idx_type nblock = (n >> bm::set_block_shift);
bm::word_t* blk =
blockman_.check_allocate_block(nblock,
get_new_blocks_strat());
BM_ASSERT(IS_VALID_ADDR(blk));
unsigned nbit = unsigned(n & bm::set_block_mask);
unsigned is_set;
if (BM_IS_GAP(blk))
{
bm::gap_word_t* gap_blk = BMGAP_PTR(blk);
is_set = (bm::gap_test_unr(gap_blk, nbit) != 0);
this->gap_block_set(gap_blk, !is_set, nblock, nbit); // flip
}
else // bit block
{
unsigned nword = unsigned(nbit >> bm::set_word_shift);
nbit &= bm::set_word_mask;
bm::word_t* word = blk + nword;
const bm::word_t mask = (((bm::word_t)1) << nbit);
is_set = ((*word) & mask);
*word ^= mask; // flip the bit
}
return is_set;
}
// -----------------------------------------------------------------------
template<class Alloc>
bool bvector<Alloc>::set_bit_conditional_impl(size_type n,
bool val,
bool condition)
{
// calculate logical block number
block_idx_type nblock = (n >> bm::set_block_shift);
int block_type;
bm::word_t* blk =
blockman_.check_allocate_block(nblock,
val,
get_new_blocks_strat(),
&block_type);
if (!IS_VALID_ADDR(blk))
return false;
// calculate word number in block and bit
unsigned nbit = unsigned(n & bm::set_block_mask);
if (block_type == 1) // gap
{
bm::gap_word_t* gap_blk = BMGAP_PTR(blk);
unsigned is_set = gap_block_set(gap_blk, val, nblock, nbit);
return is_set;
}
else // bit block
{
unsigned nword = unsigned(nbit >> bm::set_word_shift);
nbit &= bm::set_word_mask;
bm::word_t* word = blk + nword;
bm::word_t mask = (((bm::word_t)1) << nbit);
bool is_set = ((*word) & mask) != 0;
if (is_set != condition)
return false;
if (is_set != val) // need to change bit
{
if (val) // set bit
*word |= mask;
else // clear bit
*word &= ~mask;
return true;
}
}
return false;
}
// -----------------------------------------------------------------------
template<class Alloc>
bool bvector<Alloc>::and_bit_no_check(size_type n, bool val)
{
BM_ASSERT(!is_ro());
// calculate logical block number
block_idx_type nblock = (n >> bm::set_block_shift);
int block_type;
bm::word_t* blk =
blockman_.check_allocate_block(nblock,
val,
get_new_blocks_strat(),
&block_type);
if (!IS_VALID_ADDR(blk))
return false;
// calculate word number in block and bit
unsigned nbit = unsigned(n & bm::set_block_mask);
if (block_type == 1) // gap
{
bm::gap_word_t* gap_blk = BMGAP_PTR(blk);
bool old_val = (bm::gap_test_unr(gap_blk, nbit) != 0);
bool new_val = val & old_val;
if (new_val != old_val)
{
unsigned is_set = gap_block_set(gap_blk, val, nblock, nbit);
BM_ASSERT(is_set);
return is_set;
}
}
else // bit block
{
unsigned nword = unsigned(nbit >> bm::set_word_shift);
nbit &= bm::set_word_mask;
bm::word_t* word = blk + nword;
bm::word_t mask = (((bm::word_t)1) << nbit);
bool is_set = ((*word) & mask) != 0;
bool new_val = is_set & val;
if (new_val != val) // need to change bit
{
if (new_val) // set bit
{
*word |= mask;
}
else // clear bit
{
*word &= ~mask;
}
return true;
}
}
return false;
}
//---------------------------------------------------------------------
template<class Alloc>
bool bvector<Alloc>::find(size_type from, size_type& pos) const BMNOEXCEPT
{
if (from == bm::id_max)
return false;
if (!from)
{
return find(pos);
}
pos = check_or_next(from);
return (pos != 0);
}
//---------------------------------------------------------------------
template<class Alloc>
bool bvector<Alloc>::find_reverse(size_type& pos) const BMNOEXCEPT
{
bool found;
unsigned top_blocks = blockman_.top_block_size();
if (!top_blocks)
return false;
for (unsigned i = top_blocks-1; true; --i)
{
const bm::word_t* const* blk_blk = blockman_.get_topblock(i);
if (blk_blk)
{
if ((bm::word_t*)blk_blk == FULL_BLOCK_FAKE_ADDR)
blk_blk = FULL_SUB_BLOCK_REAL_ADDR;
for (unsigned short j = bm::set_sub_array_size-1; true; --j)
{
const bm::word_t* blk = blk_blk[j];
if (blk)
{
unsigned block_pos;
if (blk == FULL_BLOCK_FAKE_ADDR)
{
block_pos = bm::gap_max_bits-1;
found = true;
}
else
{
bool is_gap = BM_IS_GAP(blk);
found = is_gap ? bm::gap_find_last(BMGAP_PTR(blk), &block_pos)
: bm::bit_find_last(blk, &block_pos);
}
if (found)
{
block_idx_type base_idx =
block_idx_type(i) * bm::set_sub_array_size *
bm::gap_max_bits;
base_idx += j * bm::gap_max_bits;
pos = base_idx + block_pos;
return found;
}
}
if (j == 0)
break;
} // for j
} // if blk_blk
if (i == 0)
break;
} // for i
return false;
}
//---------------------------------------------------------------------
template<class Alloc>
bool bvector<Alloc>::find_reverse(size_type from, size_type& pos) const BMNOEXCEPT
{
bool found;
if (!blockman_.is_init())
return false; // nothing to do
if (!from)
{
pos = from;
return this->test(from);
}
block_idx_type nb = (from >> bm::set_block_shift);
unsigned i0, j0;
bm::get_block_coord(nb, i0, j0);
const bm::word_t* block = blockman_.get_block_ptr(i0, j0);
if (block)
{
size_type base_idx;
unsigned found_nbit;
unsigned nbit = unsigned(from & bm::set_block_mask);
found = bm::block_find_reverse(block, nbit, &found_nbit);
if (found)
{
base_idx = bm::get_block_start<size_type>(i0, j0);
pos = base_idx + found_nbit;
return found;
}
}
if (nb)
--nb;
else
return false;
bm::get_block_coord(nb, i0, j0);
const bm::word_t* const* blk_blk = blockman_.get_topblock(i0);
if (blk_blk)
{
if ((bm::word_t*)blk_blk == FULL_BLOCK_FAKE_ADDR)
blk_blk = FULL_SUB_BLOCK_REAL_ADDR;
for (unsigned j = j0; true; --j)
{
const bm::word_t* blk = blk_blk[j];
if (blk)
{
unsigned block_pos;
if (blk == FULL_BLOCK_FAKE_ADDR)
{
block_pos = bm::gap_max_bits-1;
found = true;
}
else
{
bool is_gap = BM_IS_GAP(blk);
found = is_gap ? bm::gap_find_last(BMGAP_PTR(blk), &block_pos)
: bm::bit_find_last(blk, &block_pos);
}
if (found)
{
block_idx_type base_idx =
block_idx_type(i0) * bm::set_sub_array_size *
bm::gap_max_bits;
base_idx += j * bm::gap_max_bits;
pos = base_idx + block_pos;
return found;
}
}
if (!j)
break;
} // for j
}
if (i0)
--i0;
else
return false;
for (unsigned i = i0; true; --i)
{
blk_blk = blockman_.get_topblock(i);
if (blk_blk)
{
if ((bm::word_t*)blk_blk == FULL_BLOCK_FAKE_ADDR)
blk_blk = FULL_SUB_BLOCK_REAL_ADDR;
for (unsigned short j = bm::set_sub_array_size-1; true; --j)
{
const bm::word_t* blk = blk_blk[j];
if (blk)
{
unsigned block_pos;
if (blk == FULL_BLOCK_FAKE_ADDR)
{
block_pos = bm::gap_max_bits-1;
found = true;
}
else
{
bool is_gap = BM_IS_GAP(blk);
found = is_gap ? bm::gap_find_last(BMGAP_PTR(blk), &block_pos)
: bm::bit_find_last(blk, &block_pos);
}
if (found)
{
block_idx_type base_idx =
block_idx_type(i) * bm::set_sub_array_size *
bm::gap_max_bits;
base_idx += j * bm::gap_max_bits;
pos = base_idx + block_pos;
return found;
}
}
if (!j)
break;
} // for j
}
if (i == 0)
break;
} // for i
return false;
}
//---------------------------------------------------------------------
template<class Alloc>
bool bvector<Alloc>::find(size_type& pos) const BMNOEXCEPT
{
bool found;
unsigned top_blocks = blockman_.top_block_size();
for (unsigned i = 0; i < top_blocks; ++i)
{
const bm::word_t* const* blk_blk = blockman_.get_topblock(i);
if (blk_blk)
{
if ((bm::word_t*)blk_blk == FULL_BLOCK_FAKE_ADDR)
blk_blk = FULL_SUB_BLOCK_REAL_ADDR;
for (unsigned j = 0; j < bm::set_sub_array_size; ++j)
{
const bm::word_t* blk = blk_blk[j];
if (blk)
{
unsigned block_pos;
if (blk == FULL_BLOCK_FAKE_ADDR)
{
found = true; block_pos = 0;
}
else
{
bool is_gap = BM_IS_GAP(blk);
found = (is_gap) ? bm::gap_find_first(BMGAP_PTR(blk), &block_pos)
: bm::bit_find_first(blk, &block_pos);
}
if (found)
{
size_type base_idx = block_idx_type(i) * bm::bits_in_array;
base_idx += j * bm::gap_max_bits;
pos = base_idx + block_pos;
return found;
}
}
} // for j
} // if blk_blk
} // for i
return false;
}
//---------------------------------------------------------------------
template<class Alloc>
bool bvector<Alloc>::find_range(size_type& in_first,
size_type& in_last) const BMNOEXCEPT
{
bool found = find(in_first);
if (found)
{
found = find_reverse(in_last);
BM_ASSERT(found);
BM_ASSERT(in_first <= in_last);
}
else
{
in_first = in_last = 0; // zero the output just in case
}
return found;
}
//---------------------------------------------------------------------
template<class Alloc>
bool bvector<Alloc>::find_rank(size_type rank_in,
size_type from,
size_type& pos) const BMNOEXCEPT
{
BM_ASSERT_THROW(from < bm::id_max, BM_ERR_RANGE);
bool ret = false;
if (!rank_in || !blockman_.is_init())
return ret;
block_idx_type nb = (from >> bm::set_block_shift);
bm::gap_word_t nbit = bm::gap_word_t(from & bm::set_block_mask);
unsigned bit_pos = 0;
for (; nb < bm::set_total_blocks; ++nb)
{
int no_more_blocks;
const bm::word_t* block = blockman_.get_block(nb, &no_more_blocks);
if (block)
{
if (!nbit && (rank_in > bm::gap_max_bits)) // requested rank cannot be in this block
{
unsigned cnt = blockman_.block_bitcount(block);
BM_ASSERT(cnt < rank_in);
rank_in -= cnt;
continue;
}
else
{
rank_in = bm::block_find_rank(block, rank_in, nbit, bit_pos);
if (!rank_in) // target found
{
pos = bit_pos + (nb * bm::set_block_size * 32);
return true;
}
}
}
else
{
// TODO: better next block search
if (no_more_blocks)
break;
}
nbit ^= nbit; // zero start bit after first scanned block
} // for nb
return ret;
}
//---------------------------------------------------------------------
template<class Alloc>
bool bvector<Alloc>::find_rank(size_type rank_in,
size_type from,
size_type& pos,
const rs_index_type& rs_idx) const BMNOEXCEPT
{
BM_ASSERT_THROW(from < bm::id_max, BM_ERR_RANGE);
bool ret = false;
if (!rank_in ||
!blockman_.is_init() ||
(rs_idx.count() < rank_in))
return ret;
block_idx_type nb;
if (from)
nb = (from >> bm::set_block_shift);
else
{
nb = rs_idx.find(rank_in);
BM_ASSERT(rs_idx.rcount(nb) >= rank_in);
if (nb)
rank_in -= rs_idx.rcount(nb-1);
}
bm::gap_word_t nbit = bm::gap_word_t(from & bm::set_block_mask);
unsigned bit_pos = 0;
for (; nb < rs_idx.get_total(); ++nb)
{
int no_more_blocks;
const bm::word_t* block = blockman_.get_block(nb, &no_more_blocks);
if (block)
{
if (!nbit) // check if the whole block can be skipped
{
unsigned block_bc = rs_idx.count(nb);
if (rank_in <= block_bc) // target block
{
nbit = rs_idx.select_sub_range(nb, rank_in);
rank_in = bm::block_find_rank(block, rank_in, nbit, bit_pos);
BM_ASSERT(rank_in == 0);
pos = bit_pos + (nb * bm::set_block_size * 32);
return true;
}
rank_in -= block_bc;
continue;
}
rank_in = bm::block_find_rank(block, rank_in, nbit, bit_pos);
if (!rank_in) // target found
{
pos = bit_pos + (nb * bm::set_block_size * 32);
return true;
}
}
else
{
// TODO: better next block search
if (no_more_blocks)
break;
}
nbit ^= nbit; // zero start bit after first scanned block
} // for nb
return ret;
}
//---------------------------------------------------------------------
template<class Alloc>
bool bvector<Alloc>::select(size_type rank_in, size_type& pos,
const rs_index_type& rs_idx) const BMNOEXCEPT
{
bool ret = false;
if (!rank_in ||
!blockman_.is_init() ||
(rs_idx.count() < rank_in))
return ret;
block_idx_type nb;
bm::gap_word_t sub_range_from;
bool found = rs_idx.find(&rank_in, &nb, &sub_range_from);
if (!found)
return found;
unsigned i, j;
bm::get_block_coord(nb, i, j);
const bm::word_t* block = blockman_.get_block_ptr(i, j);
BM_ASSERT(block);
BM_ASSERT(rank_in <= rs_idx.count(nb));
unsigned bit_pos = 0;
if (block == FULL_BLOCK_FAKE_ADDR)
{
BM_ASSERT(rank_in <= bm::gap_max_bits);
bit_pos = sub_range_from + unsigned(rank_in) - 1;
}
else
{
rank_in = bm::block_find_rank(block, rank_in, sub_range_from, bit_pos);
BM_ASSERT(rank_in == 0);
}
pos = bit_pos + (nb * bm::set_block_size * 32);
return true;
}
//---------------------------------------------------------------------
template<class Alloc>
typename bvector<Alloc>::size_type
bvector<Alloc>::check_or_next(size_type prev) const BMNOEXCEPT
{
if (!blockman_.is_init())
return 0;
// calculate logical block number
block_idx_type nb = (prev >> bm::set_block_shift);
unsigned i, j;
bm::get_block_coord(nb, i, j);
const bm::word_t* block = blockman_.get_block_ptr(i, j);
if (block)
{
unsigned block_pos;
bool found = false;
// calculate word number in block and bit
unsigned nbit = unsigned(prev & bm::set_block_mask);
if (BM_IS_GAP(block))
{
if (bm::gap_block_find(BMGAP_PTR(block), nbit, &block_pos))
{
prev = (size_type(nb) * bm::gap_max_bits) + block_pos;
return prev;
}
}
else
{
if (block == FULL_BLOCK_FAKE_ADDR)
return prev;
found = bm::bit_block_find(block, nbit, &block_pos);
if (found)
{
prev = (size_type(nb) * bm::gap_max_bits) + block_pos;
return prev;
}
}
}
++j;
block_idx_type top_blocks = blockman_.top_block_size();
for (; i < top_blocks; ++i)
{
const bm::word_t* const* blk_blk = blockman_.get_topblock(i);
if (blk_blk)
{
if ((bm::word_t*)blk_blk == FULL_BLOCK_FAKE_ADDR)
blk_blk = FULL_SUB_BLOCK_REAL_ADDR;
for (; j < bm::set_sub_array_size; ++j)
{
const bm::word_t* blk = blk_blk[j];
if (blk)
{
bool found;
unsigned block_pos;
if (blk == FULL_BLOCK_FAKE_ADDR)
{
found = true; block_pos = 0;
}
else
{
bool is_gap = BM_IS_GAP(blk);
found = (is_gap) ? bm::gap_find_first(BMGAP_PTR(blk), &block_pos)
: bm::bit_find_first(blk, &block_pos);
}
if (found)
{
size_type base_idx = size_type(i) * bm::bits_in_array;
base_idx += j * bm::gap_max_bits;
prev = base_idx + block_pos;
return prev;
}
}
} // for j
}
j = 0;
} // for i
return 0;
}
//---------------------------------------------------------------------
template<class Alloc>
typename bvector<Alloc>::size_type
bvector<Alloc>::check_or_next_extract(size_type prev)
{
BM_ASSERT(!is_ro());
if (!blockman_.is_init())
return 0;
// TODO: optimization
size_type pos = this->check_or_next(prev);
if (pos >= prev)
this->clear_bit_no_check(pos);
return pos;
}
//---------------------------------------------------------------------
template<class Alloc>
bool bvector<Alloc>::shift_right()
{
BM_ASSERT(!is_ro());
return insert(0, false);
}
//---------------------------------------------------------------------
template<class Alloc>
bool bvector<Alloc>::shift_left()
{
BM_ASSERT(!is_ro());
bool b = this->test(0);
this->erase(0);
return b;
}
//---------------------------------------------------------------------
template<class Alloc>
bool bvector<Alloc>::insert(size_type n, bool value)
{
BM_ASSERT(!is_ro());
BM_ASSERT_THROW(n < bm::id_max, BM_ERR_RANGE);
if (size_ < bm::id_max)
++size_;
if (!blockman_.is_init())
{
if (value)
set(n);
return 0;
}
// calculate logical block number
block_idx_type nb = (n >> bm::set_block_shift);
int block_type;
bm::word_t carry_over = 0;
// 1: process target block insertion
if (value || n)
{
unsigned i, j;
bm::get_block_coord(nb, i, j);
bm::word_t* block = blockman_.get_block_ptr(i, j);
const unsigned nbit = unsigned(n & bm::set_block_mask);
if (!block)
{
if (value)
{
block = blockman_.check_allocate_block(nb, get_new_blocks_strat());
goto insert_bit_check;
}
}
else
{
insert_bit_check:
if (BM_IS_GAP(block))
{
unsigned new_block_len;
bm::gap_word_t* gap_blk = BMGAP_PTR(block);
carry_over = bm::gap_insert(gap_blk, nbit, value, &new_block_len);
unsigned threshold = bm::gap_limit(gap_blk, blockman_.glen());
if (new_block_len > threshold)
blockman_.extend_gap_block(nb, gap_blk);
}
else
{
if (IS_FULL_BLOCK(block))
{
if (!value)
{
block = blockman_.deoptimize_block(nb);
goto insert_bit;
}
carry_over = 1;
}
else // BIT block
{
insert_bit:
BM_ASSERT(IS_VALID_ADDR(block));
carry_over = bm::bit_block_insert(block, nbit, value);
}
}
}
++nb;
}
// 2: shift right everything else
//
unsigned i0, j0;
bm::get_block_coord(nb, i0, j0);
unsigned top_blocks = blockman_.top_block_size();
bm::word_t*** blk_root = blockman_.top_blocks_root();
bm::word_t** blk_blk;
bm::word_t* block;
for (unsigned i = i0; i < bm::set_top_array_size; ++i)
{
if (i >= top_blocks)
{
if (!carry_over)
break;
blk_blk = 0;
}
else
blk_blk = blk_root[i];
if (!blk_blk) // top level group of blocks missing - can skip it
{
if (carry_over)
{
// carry over: needs block-list extension and a block
block_idx_type nblock = (block_idx_type(i) * bm::set_sub_array_size) + 0;
if (nblock > nb)
{
block =
blockman_.check_allocate_block(nblock, 0, 0, &block_type, false);
block[0] |= carry_over; // block is brand new (0000)
// reset all control vars (blocks tree may have re-allocated)
blk_root = blockman_.top_blocks_root();
blk_blk = blk_root[i];
top_blocks = blockman_.top_block_size();
carry_over = 0;
}
}
continue;
}
if ((bm::word_t*)blk_blk == FULL_BLOCK_FAKE_ADDR)
{
if (carry_over)
continue;
blk_blk = blockman_.check_alloc_top_subblock(i);
}
unsigned j = j0;
do
{
block_idx_type nblock = (block_idx_type(i) * bm::set_sub_array_size) + j;
block = blk_blk[j];
if (!block)
{
if (carry_over)
{
size_type nbit = nblock * bm::gap_max_bits;
set_bit_no_check(nbit);
carry_over = 0; block = 0;
}
// no CO: tight loop scan for the next available block (if any)
for (++j; j < bm::set_sub_array_size; ++j)
{
if (0 != (block = blk_blk[j]))
{
nblock = (i * bm::set_sub_array_size) + j;
break;
}
} // for j
if (!block) // no more blocks in this j-dimention
continue;
}
if (IS_FULL_BLOCK(block))
{
// 1 in 1 out, block is still all 0xFFFF..
// 0 into 1 -> carry in 0, carry out 1
if (!carry_over)
{
block = blockman_.deoptimize_block(nblock);
block[0] <<= (carry_over = 1);
}
continue;
}
if (BM_IS_GAP(block))
{
if (nblock == bm::set_total_blocks-1) // last block
{
// process as a bit-block (for simplicity)
block = blockman_.deoptimize_block(nblock);
}
else // use gap-block shift here
{
unsigned new_block_len;
bm::gap_word_t* gap_blk = BMGAP_PTR(block);
carry_over = bm::gap_shift_r1(gap_blk, carry_over, &new_block_len);
unsigned threshold = bm::gap_limit(gap_blk, blockman_.glen());
if (new_block_len > threshold)
blockman_.extend_gap_block(nblock, gap_blk);
continue;
}
}
// bit-block
{
bm::word_t acc;
carry_over = bm::bit_block_shift_r1_unr(block, &acc, carry_over);
BM_ASSERT(carry_over <= 1);
if (nblock == bm::set_total_blocks-1) // last possible block
{
carry_over = block[bm::set_block_size-1] & (1u<<31);
block[bm::set_block_size-1] &= ~(1u<<31); // clear the 1-bit tail
if (!acc) // block shifted out: release memory
blockman_.zero_block(nblock);
break;
}
if (!acc)
blockman_.zero_block(nblock);
}
} while (++j < bm::set_sub_array_size);
j0 = 0;
} // for i
return carry_over;
}
//---------------------------------------------------------------------
template<class Alloc>
void bvector<Alloc>::erase(size_type n)
{
BM_ASSERT(!is_ro());
BM_ASSERT_THROW(n < bm::id_max, BM_ERR_RANGE);
if (!blockman_.is_init())
return ;
// calculate logical block number
block_idx_type nb = (n >> bm::set_block_shift);
if (!n ) // regular shift-left by 1 bit
{}
else // process target block bit erase
{
unsigned i, j;
bm::get_block_coord(nb, i, j);
bm::word_t* block = blockman_.get_block_ptr(i, j);
bool carry_over = test_first_block_bit(nb+1);
if (!block)
{
if (carry_over)
{
block = blockman_.check_allocate_block(nb, BM_BIT);
block[bm::set_block_size-1] = (1u << 31u);
}
}
else
{
if (BM_IS_GAP(block) || IS_FULL_BLOCK(block))
block = blockman_.deoptimize_block(nb);
BM_ASSERT(IS_VALID_ADDR(block));
unsigned nbit = unsigned(n & bm::set_block_mask);
bm::bit_block_erase(block, nbit, carry_over);
}
++nb;
}
// left shifting of all other blocks
//
unsigned i0, j0;
bm::get_block_coord(nb, i0, j0);
unsigned top_blocks = blockman_.top_block_size();
bm::word_t*** blk_root = blockman_.top_blocks_root();
bm::word_t** blk_blk;
bm::word_t* block;
for (unsigned i = i0; i < bm::set_top_array_size; ++i)
{
if (i >= top_blocks)
break;
else
blk_blk = blk_root[i];
if (!blk_blk) // top level group of blocks missing
{
bool found = bm::find_not_null_ptr(blk_root, i+1, top_blocks, &i);
if (!found)
break;
--i;
continue;
}
if ((bm::word_t*)blk_blk == FULL_BLOCK_FAKE_ADDR)
{
bool carry_over = 0;
if (i + 1 < bm::set_top_array_size)
{
size_type co_idx = (block_idx_type(i)+1) * bm::gap_max_bits * bm::set_sub_array_size;
carry_over = this->test(co_idx);
if (carry_over)
continue; // nothing to do (1 in)
else
blk_blk = blockman_.check_alloc_top_subblock(i);
}
else
{
blk_blk = blockman_.check_alloc_top_subblock(i);
}
}
unsigned j = j0;
do
{
block_idx_type nblock = (block_idx_type(i) * bm::set_sub_array_size) + j;
bool carry_over = 0; // test_first_block_bit(nblock+1); // look ahead for CO
block = blk_blk[j];
if (!block)
{
// no CO: tight loop scan for the next available block (if any)
bool no_blocks = (j == 0);
for (++j; j < bm::set_sub_array_size; ++j)
{
if (0 != (block = blk_blk[j]))
{
nblock = (block_idx_type(i) * bm::set_sub_array_size) + j;
break;
}
} // for j
if (!block) // no more blocks in this j-dimention ?
{
if (j == bm::set_sub_array_size && no_blocks)
{
blockman_.zero_block(i, j-1); // free the top level
}
continue;
}
}
BM_ASSERT(block);
if (IS_FULL_BLOCK(block))
{
carry_over = test_first_block_bit(nblock+1); // look ahead for CO
// 1 in 1 out, block is still all 0xFFFF..
// 0 into 1 -> carry in 0, carry out 1
if (!carry_over)
{
block = blockman_.deoptimize_block(nblock);
block[bm::set_block_size-1] >>= 1;
}
carry_over = 1;
}
else
if (BM_IS_GAP(block))
{
carry_over = test_first_block_bit(nblock+1); // look ahead for CO
unsigned new_block_len;
bm::gap_word_t* gap_blk = BMGAP_PTR(block);
carry_over = bm::gap_shift_l1(gap_blk, carry_over, &new_block_len);
unsigned threshold = bm::gap_limit(gap_blk, blockman_.glen());
if (new_block_len > threshold)
blockman_.extend_gap_block(nblock, gap_blk);
else
{
if (bm::gap_is_all_zero(gap_blk))
blockman_.zero_block(i, j);
}
}
else // bit-block
{
bm::word_t acc;
carry_over = bm::bit_block_shift_l1_unr(block, &acc, carry_over);
if (!acc)
blockman_.zero_block(i, j);
}
if (carry_over && nblock)
{
set_bit_no_check((nblock-1) * bm::gap_max_bits + bm::gap_max_bits-1);
}
} while (++j < bm::set_sub_array_size);
j0 = 0;
} // for i
}
//---------------------------------------------------------------------
template<class Alloc>
bool bvector<Alloc>::test_first_block_bit(block_idx_type nb) const BMNOEXCEPT
{
if (nb >= bm::set_total_blocks) // last possible block
return false;
return test(nb * bm::gap_max_bits);
}
//---------------------------------------------------------------------
template<class Alloc>
void bvector<Alloc>::merge(bm::bvector<Alloc>& bv)
{
BM_ASSERT(!is_ro());
if (!bv.blockman_.is_init()) // nothing to OR
return;
if (bv.is_ro()) // argument is immutable, just use OR
{
this->bit_or(bv);
return;
}
unsigned top_blocks = blockman_.top_block_size();
if (size_ < bv.size_) // this vect shorter than the arg.
{
size_ = bv.size_;
}
unsigned arg_top_blocks = bv.blockman_.top_block_size();
top_blocks = blockman_.reserve_top_blocks(arg_top_blocks);
bm::word_t*** blk_root = blockman_.top_blocks_root();
bm::word_t*** blk_root_arg = bv.blockman_.top_blocks_root();
for (unsigned i = 0; i < top_blocks; ++i)
{
bm::word_t** blk_blk = blk_root[i];
bm::word_t** blk_blk_arg = (i < arg_top_blocks) ? blk_root_arg[i] : 0;
if (blk_blk == blk_blk_arg || !blk_blk_arg) // nothing to do (0 OR 0 == 0)
continue;
if (!blk_blk && blk_blk_arg) // top block transfer
{
BM_ASSERT(i < arg_top_blocks);
blk_root[i] = blk_root_arg[i];
blk_root_arg[i] = 0;
continue;
}
if ((bm::word_t*)blk_blk == FULL_BLOCK_FAKE_ADDR)
continue;
if ((bm::word_t*)blk_blk_arg == FULL_BLOCK_FAKE_ADDR)
{
blockman_.deallocate_top_subblock(i);
blk_root[i] = (bm::word_t**)FULL_BLOCK_FAKE_ADDR;
continue;
}
unsigned j = 0;
bm::word_t* blk;
bm::word_t* arg_blk;
do
{
blk = blk_blk[j]; arg_blk = blk_blk_arg[j];
if (blk != arg_blk)
{
if (!blk && arg_blk) // block transfer
{
blockman_.set_block_ptr(i, j, arg_blk);
bv.blockman_.set_block_ptr(i, j, 0);
}
else // need full OR
{
combine_operation_block_or(i, j, blk, arg_blk);
}
}
} while (++j < bm::set_sub_array_size);
} // for i
}
//---------------------------------------------------------------------
template<class Alloc>
void bvector<Alloc>::combine_operation_with_block(block_idx_type nb,
const bm::word_t* arg_blk,
bool arg_gap,
bm::operation opcode)
{
unsigned i0, j0;
bm::get_block_coord(nb, i0, j0);
bm::word_t* blk = blockman_.get_block_ptr(i0, j0);
bool gap = BM_IS_GAP(blk);
combine_operation_with_block(nb, gap, blk, arg_blk, arg_gap, opcode);
}
//---------------------------------------------------------------------
template<class Alloc>
bm::bvector<Alloc>&
bvector<Alloc>::bit_or(const bm::bvector<Alloc>& bv1,
const bm::bvector<Alloc>& bv2,
typename bm::bvector<Alloc>::optmode opt_mode)
{
BM_ASSERT(!is_ro());
if (blockman_.is_init())
blockman_.deinit_tree();
if (&bv1 == &bv2)
{
this->bit_or(bv2);
return *this;
}
if (this == &bv1)
{
this->bit_or(bv2);
return *this;
}
if (this == &bv2)
{
this->bit_or(bv1);
return *this;
}
const blocks_manager_type& bman1 = bv1.get_blocks_manager();
const blocks_manager_type& bman2 = bv2.get_blocks_manager();
unsigned top_blocks1 = bman1.top_block_size();
unsigned top_blocks2 = bman2.top_block_size();
unsigned top_blocks = (top_blocks2 > top_blocks1) ? top_blocks2 : top_blocks1;
top_blocks = blockman_.reserve_top_blocks(top_blocks);
size_ = bv1.size_;
if (size_ < bv2.size_)
size_ = bv2.size_;
bm::word_t*** blk_root_arg1 = bv1.blockman_.top_blocks_root();
if (!blk_root_arg1)
{
this->bit_or(bv2);
return *this;
}
bm::word_t*** blk_root_arg2 = bv2.blockman_.top_blocks_root();
if (!blk_root_arg2)
{
this->bit_or(bv1);
return *this;
}
for (unsigned i = 0; i < top_blocks; ++i)
{
bm::word_t** blk_blk_arg1 = (i < top_blocks1) ? blk_root_arg1[i] : 0;
bm::word_t** blk_blk_arg2 = (i < top_blocks2) ? blk_root_arg2[i] : 0;
if (blk_blk_arg1 == blk_blk_arg2)
{
BM_ASSERT(!blk_blk_arg1 || (bm::word_t*)blk_blk_arg1 == FULL_BLOCK_FAKE_ADDR);
bm::word_t*** blk_root = blockman_.top_blocks_root();
blk_root[i] = blk_blk_arg1;
continue;
}
if ((bm::word_t*)blk_blk_arg1 == FULL_BLOCK_FAKE_ADDR ||
(bm::word_t*)blk_blk_arg2 == FULL_BLOCK_FAKE_ADDR)
{
bm::word_t*** blk_root = blockman_.top_blocks_root();
blk_root[i] = (bm::word_t**)FULL_BLOCK_FAKE_ADDR;
continue;
}
bm::word_t** blk_blk = blockman_.alloc_top_subblock(i);
bool any_blocks = false;
unsigned j = 0;
do
{
const bm::word_t* arg_blk1 = blk_blk_arg1 ? blk_blk_arg1[j] : 0;
const bm::word_t* arg_blk2 = blk_blk_arg2 ? blk_blk_arg2[j] : 0;
if (arg_blk1 == arg_blk2 && !arg_blk1)
continue;
bool need_opt = combine_operation_block_or(i, j, arg_blk1, arg_blk2);
if (need_opt && opt_mode == opt_compress)
blockman_.optimize_bit_block(i, j, opt_mode);
any_blocks |= bool(blk_blk[j]);
} while (++j < bm::set_sub_array_size);
if (!any_blocks)
blockman_.free_top_subblock(i);
} // for i
if (opt_mode != opt_none)
blockman_.free_temp_block();
return *this;
}
//---------------------------------------------------------------------
template<class Alloc>
bm::bvector<Alloc>&
bvector<Alloc>::bit_xor(const bm::bvector<Alloc>& bv1,
const bm::bvector<Alloc>& bv2,
typename bm::bvector<Alloc>::optmode opt_mode)
{
BM_ASSERT(!is_ro());
if (blockman_.is_init())
blockman_.deinit_tree();
if (&bv1 == &bv2)
return *this; // nothing to do empty result
if (this == &bv1)
{
this->bit_xor(bv2);
return *this;
}
if (this == &bv2)
{
this->bit_xor(bv1);
return *this;
}
const blocks_manager_type& bman1 = bv1.get_blocks_manager();
if (!bman1.is_init())
{
*this = bv2;
return *this;
}
const blocks_manager_type& bman2 = bv2.get_blocks_manager();
if (!bman2.is_init())
{
*this = bv1;
return *this;
}
unsigned top_blocks1 = bman1.top_block_size();
unsigned top_blocks2 = bman2.top_block_size();
unsigned top_blocks = (top_blocks2 > top_blocks1) ? top_blocks2 : top_blocks1;
top_blocks = blockman_.reserve_top_blocks(top_blocks);
size_ = bv1.size_;
if (size_ < bv2.size_)
size_ = bv2.size_;
bm::word_t*** blk_root_arg1 = bv1.blockman_.top_blocks_root();
bm::word_t*** blk_root_arg2 = bv2.blockman_.top_blocks_root();
for (unsigned i = 0; i < top_blocks; ++i)
{
bm::word_t** blk_blk_arg1 = (i < top_blocks1) ? blk_root_arg1[i] : 0;
bm::word_t** blk_blk_arg2 = (i < top_blocks2) ? blk_root_arg2[i] : 0;
if (blk_blk_arg1 == blk_blk_arg2)
{
if (!blk_blk_arg1)
continue;
BM_ASSERT((bm::word_t*)blk_blk_arg1 == FULL_BLOCK_FAKE_ADDR);
blockman_.deallocate_top_subblock(i);
continue;
}
if ((bm::word_t*)blk_blk_arg1 == FULL_BLOCK_FAKE_ADDR)
{
if (!blk_blk_arg2)
{
set_full_sb:
bm::word_t*** blk_root= blockman_.top_blocks_root();
blk_root[i] = (bm::word_t**)FULL_BLOCK_FAKE_ADDR;
continue;
}
blk_blk_arg1 = FULL_SUB_BLOCK_REAL_ADDR;
}
if ((bm::word_t*)blk_blk_arg2 == FULL_BLOCK_FAKE_ADDR)
{
if (!blk_blk_arg1)
goto set_full_sb;
blk_blk_arg2 = FULL_SUB_BLOCK_REAL_ADDR;
}
bm::word_t** blk_blk = blockman_.alloc_top_subblock(i);
bool any_blocks = false;
unsigned j = 0;
do
{
const bm::word_t* arg_blk1; const bm::word_t* arg_blk2;
arg_blk1 = blk_blk_arg1 ? blk_blk_arg1[j] : 0;
arg_blk2 = blk_blk_arg2 ? blk_blk_arg2[j] : 0;
if ((arg_blk1 == arg_blk2) &&
(!arg_blk1 || arg_blk1 == FULL_BLOCK_FAKE_ADDR))
continue; // 0 ^ 0 == 0 , 1 ^ 1 == 0 (nothing to do)
bool need_opt = combine_operation_block_xor(i, j, arg_blk1, arg_blk2);
if (need_opt && opt_mode == opt_compress)
blockman_.optimize_bit_block(i, j, opt_mode);
any_blocks |= bool(blk_blk[j]);
} while (++j < bm::set_sub_array_size);
if (!any_blocks)
blockman_.free_top_subblock(i);
} // for i
if (opt_mode != opt_none)
blockman_.free_temp_block();
return *this;
}
//---------------------------------------------------------------------
template<class Alloc>
bm::bvector<Alloc>&
bvector<Alloc>::bit_and(const bm::bvector<Alloc>& bv1,
const bm::bvector<Alloc>& bv2,
typename bm::bvector<Alloc>::optmode opt_mode)
{
BM_ASSERT(!is_ro());
if (&bv1 == &bv2)
{
*this = bv1;
return *this;
}
if (this == &bv1)
{
this->bit_and(bv2);
return *this;
}
if (this == &bv2)
{
this->bit_and(bv1);
return *this;
}
if (blockman_.is_init())
blockman_.deinit_tree();
const blocks_manager_type& bman1 = bv1.get_blocks_manager();
const blocks_manager_type& bman2 = bv2.get_blocks_manager();
if (!bman1.is_init() || !bman2.is_init())
return *this;
unsigned top_blocks1 = bman1.top_block_size();
unsigned top_blocks2 = bman2.top_block_size();
unsigned top_blocks = (top_blocks2 > top_blocks1) ? top_blocks2 : top_blocks1;
top_blocks = blockman_.reserve_top_blocks(top_blocks);
size_ = bv1.size_;
if (size_ < bv2.size_)
size_ = bv2.size_;
bm::word_t*** blk_root_arg1 = bv1.blockman_.top_blocks_root();
bm::word_t*** blk_root_arg2 = bv2.blockman_.top_blocks_root();
for (unsigned i = 0; i < top_blocks; ++i)
{
bm::word_t** blk_blk_arg1 = (i < top_blocks1) ? blk_root_arg1[i] : 0;
bm::word_t** blk_blk_arg2 = (i < top_blocks2) ? blk_root_arg2[i] : 0;
if (blk_blk_arg1 == blk_blk_arg2)
{
if (!blk_blk_arg1)
continue; // 0 & 0 == 0
if ((bm::word_t*)blk_blk_arg1 == FULL_BLOCK_FAKE_ADDR)
{
bm::word_t*** blk_root = blockman_.top_blocks_root();
blk_root[i] = (bm::word_t**)FULL_BLOCK_FAKE_ADDR;
continue;
}
}
if ((bm::word_t*)blk_blk_arg1 == FULL_BLOCK_FAKE_ADDR)
blk_blk_arg1 = FULL_SUB_BLOCK_REAL_ADDR;
if ((bm::word_t*)blk_blk_arg2 == FULL_BLOCK_FAKE_ADDR)
blk_blk_arg2 = FULL_SUB_BLOCK_REAL_ADDR;
bm::word_t** blk_blk = blockman_.alloc_top_subblock(i);
bool any_blocks = false;
unsigned j = 0;
do
{
const bm::word_t* arg_blk1; const bm::word_t* arg_blk2;
arg_blk1 = blk_blk_arg1 ? blk_blk_arg1[j] : 0;
arg_blk2 = blk_blk_arg2 ? blk_blk_arg2[j] : 0;
if ((arg_blk1 == arg_blk2) && !arg_blk1)
continue; // 0 & 0 == 0
bool need_opt = combine_operation_block_and(i, j, arg_blk1, arg_blk2);
if (need_opt && opt_mode == opt_compress)
blockman_.optimize_bit_block(i, j, opt_mode);
any_blocks |= bool(blk_blk[j]);
} while (++j < bm::set_sub_array_size);
if (!any_blocks)
blockman_.free_top_subblock(i);
} // for i
if (opt_mode != opt_none)
blockman_.free_temp_block();
return *this;
}
//---------------------------------------------------------------------
template<class Alloc>
bm::bvector<Alloc>&
bvector<Alloc>::bit_or_and(const bm::bvector<Alloc>& bv1,
const bm::bvector<Alloc>& bv2,
typename bm::bvector<Alloc>::optmode opt_mode)
{
BM_ASSERT(!is_ro());
if (&bv1 == &bv2)
{
this->bit_or(bv1);
return *this;
}
if (this == &bv1)
{
this->bit_and(bv2);
return *this;
}
if (this == &bv2)
{
this->bit_and(bv1);
return *this;
}
const blocks_manager_type& bman1 = bv1.get_blocks_manager();
const blocks_manager_type& bman2 = bv2.get_blocks_manager();
if (!bman1.is_init() || !bman2.is_init())
return *this;
unsigned top_blocks1 = bman1.top_block_size();
unsigned top_blocks2 = bman2.top_block_size();
unsigned top_blocks = (top_blocks2 > top_blocks1) ? top_blocks2 : top_blocks1;
top_blocks = blockman_.reserve_top_blocks(top_blocks);
size_type new_size = bv1.size_;
if (new_size < bv2.size_)
new_size = bv2.size_;
if (size_ < new_size)
size_ = new_size;
bm::word_t*** blk_root_arg1 = bv1.blockman_.top_blocks_root();
bm::word_t*** blk_root_arg2 = bv2.blockman_.top_blocks_root();
for (unsigned i = 0; i < top_blocks; ++i)
{
bm::word_t** blk_blk_arg1 = (i < top_blocks1) ? blk_root_arg1[i] : 0;
bm::word_t** blk_blk_arg2 = (i < top_blocks2) ? blk_root_arg2[i] : 0;
if (blk_blk_arg1 == blk_blk_arg2)
{
if (!blk_blk_arg1)
continue; // 0 & 0 == 0
if ((bm::word_t*)blk_blk_arg1 == FULL_BLOCK_FAKE_ADDR)
{
bm::word_t*** blk_root = blockman_.top_blocks_root();
if (blk_root[i])
blockman_.deallocate_top_subblock(i);
BM_ASSERT(!blk_root[i]);
blk_root[i] = (bm::word_t**)FULL_BLOCK_FAKE_ADDR;
continue;
}
}
if ((bm::word_t*)blk_blk_arg1 == FULL_BLOCK_FAKE_ADDR)
blk_blk_arg1 = FULL_SUB_BLOCK_REAL_ADDR;
if ((bm::word_t*)blk_blk_arg2 == FULL_BLOCK_FAKE_ADDR)
blk_blk_arg2 = FULL_SUB_BLOCK_REAL_ADDR;
bm::word_t** blk_blk = blockman_.check_alloc_top_subblock(i);
bool any_blocks = false;
for (unsigned j = 0; j < bm::set_sub_array_size; ++j)
{
if (blk_blk[j] == FULL_BLOCK_FAKE_ADDR) // saturated: nothing to do
{
any_blocks = true;
continue;
}
const bm::word_t* arg_blk1; const bm::word_t* arg_blk2;
arg_blk1 = blk_blk_arg1 ? blk_blk_arg1[j] : 0;
arg_blk2 = blk_blk_arg2 ? blk_blk_arg2[j] : 0;
if ((arg_blk1 == arg_blk2) && !arg_blk1)
continue; // 0 & 0 == 0
bool need_opt;
if (!blk_blk[j]) // nothing to OR
{
need_opt =
combine_operation_block_and(i, j, arg_blk1, arg_blk2);
}
else
{
need_opt =
combine_operation_block_and_or(i, j, arg_blk1, arg_blk2);
}
if (need_opt && opt_mode == opt_compress)
blockman_.optimize_bit_block(i, j, opt_mode);
any_blocks |= bool(blk_blk[j]);
} // for j
if (!any_blocks)
blockman_.free_top_subblock(i);
} // for i
if (opt_mode != opt_none)
blockman_.free_temp_block();
return *this;
}
//---------------------------------------------------------------------
template<class Alloc>
bm::bvector<Alloc>&
bvector<Alloc>::bit_sub(const bm::bvector<Alloc>& bv1,
const bm::bvector<Alloc>& bv2,
typename bm::bvector<Alloc>::optmode opt_mode)
{
BM_ASSERT(!is_ro());
if (blockman_.is_init())
blockman_.deinit_tree();
if (&bv1 == &bv2)
return *this; // nothing to do empty result
if (this == &bv1)
{
this->bit_sub(bv2);
return *this;
}
if (this == &bv2)
{
this->bit_sub(bv1);
return *this;
}
const blocks_manager_type& bman1 = bv1.get_blocks_manager();
const blocks_manager_type& bman2 = bv2.get_blocks_manager();
if (!bman1.is_init())
{
return *this;
}
if (!bman2.is_init())
{
this->bit_or(bv1);
return *this;
}
unsigned top_blocks1 = bman1.top_block_size();
unsigned top_blocks2 = bman2.top_block_size();
unsigned top_blocks = (top_blocks2 > top_blocks1) ? top_blocks2 : top_blocks1;
top_blocks = blockman_.reserve_top_blocks(top_blocks);
size_ = bv1.size_;
if (size_ < bv2.size_)
size_ = bv2.size_;
bm::word_t*** blk_root_arg1 = bv1.blockman_.top_blocks_root();
bm::word_t*** blk_root_arg2 = bv2.blockman_.top_blocks_root();
for (unsigned i = 0; i < top_blocks; ++i)
{
bm::word_t** blk_blk_arg1 = (i < top_blocks1) ? blk_root_arg1[i] : 0;
bm::word_t** blk_blk_arg2 = (i < top_blocks2) ? blk_root_arg2[i] : 0;
if (blk_blk_arg1 == blk_blk_arg2)
continue; // 0 AND NOT 0 == 0
if ((bm::word_t*)blk_blk_arg2 == FULL_BLOCK_FAKE_ADDR)
continue;
if ((bm::word_t*)blk_blk_arg1 == FULL_BLOCK_FAKE_ADDR)
blk_blk_arg1 = FULL_SUB_BLOCK_REAL_ADDR;
bm::word_t** blk_blk = blockman_.alloc_top_subblock(i);
bool any_blocks = false;
unsigned j = 0;
do
{
const bm::word_t* arg_blk1 = blk_blk_arg1 ? blk_blk_arg1[j] : 0;
const bm::word_t* arg_blk2 = blk_blk_arg2 ? blk_blk_arg2[j] : 0;
if ((arg_blk1 == arg_blk2) && !arg_blk1)
continue; // 0 & ~0 == 0
bool need_opt = combine_operation_block_sub(i, j, arg_blk1, arg_blk2);
if (need_opt && opt_mode == opt_compress)
blockman_.optimize_bit_block(i, j, opt_mode);
any_blocks |= bool(blk_blk[j]);
} while (++j < bm::set_sub_array_size);
if (!any_blocks)
blockman_.free_top_subblock(i);
} // for i
if (opt_mode != opt_none)
blockman_.free_temp_block();
return *this;
}
//---------------------------------------------------------------------
#define BM_OR_OP(x) \
{ \
blk = blk_blk[j+x]; arg_blk = blk_blk_arg[j+x]; \
if (blk != arg_blk) \
combine_operation_block_or(i, j+x, blk, arg_blk); \
}
template<class Alloc>
void bvector<Alloc>::combine_operation_or(const bm::bvector<Alloc>& bv)
{
if (!bv.blockman_.is_init())
return;
unsigned top_blocks = blockman_.top_block_size();
if (size_ < bv.size_)
size_ = bv.size_;
unsigned arg_top_blocks = bv.blockman_.top_block_size();
top_blocks = blockman_.reserve_top_blocks(arg_top_blocks);
bm::word_t*** blk_root = blockman_.top_blocks_root();
bm::word_t*** blk_root_arg = bv.blockman_.top_blocks_root();
for (unsigned i = 0; i < top_blocks; ++i)
{
bm::word_t** blk_blk = blk_root[i];
bm::word_t** blk_blk_arg = (i < arg_top_blocks) ? blk_root_arg[i] : 0;
if (blk_blk == blk_blk_arg || !blk_blk_arg) // nothing to do (0 OR 0 == 0)
continue;
if ((bm::word_t*)blk_blk == FULL_BLOCK_FAKE_ADDR)
continue;
if ((bm::word_t*)blk_blk_arg == FULL_BLOCK_FAKE_ADDR)
{
blockman_.deallocate_top_subblock(i);
blk_root[i] = (bm::word_t**)FULL_BLOCK_FAKE_ADDR;
continue;
}
if (!blk_blk)
blk_blk = blockman_.alloc_top_subblock(i);
unsigned j = 0;
bm::word_t* blk;
const bm::word_t* arg_blk;
do
{
#if defined(BM64_AVX2) || defined(BM64_AVX512)
if (!avx2_test_all_eq_wave2(blk_blk + j, blk_blk_arg + j))
{
BM_OR_OP(0)
BM_OR_OP(1)
BM_OR_OP(2)
BM_OR_OP(3)
}
j += 4;
#elif defined(BM64_SSE4)
if (!sse42_test_all_eq_wave2(blk_blk + j, blk_blk_arg + j))
{
BM_OR_OP(0)
BM_OR_OP(1)
}
j += 2;
#else
BM_OR_OP(0)
++j;
#endif
} while (j < bm::set_sub_array_size);
} // for i
}
#undef BM_OR_OP
//---------------------------------------------------------------------
#define BM_XOR_OP(x) \
{ \
blk = blk_blk[j+x]; arg_blk = blk_blk_arg[j+x]; \
combine_operation_block_xor(i, j+x, blk, arg_blk); \
}
template<class Alloc>
void bvector<Alloc>::combine_operation_xor(const bm::bvector<Alloc>& bv)
{
if (!bv.blockman_.is_init())
return;
if (!blockman_.is_init())
{
*this = bv;
return;
}
unsigned top_blocks = blockman_.top_block_size();
if (size_ < bv.size_) // this vect shorter than the arg.
{
size_ = bv.size_;
}
unsigned arg_top_blocks = bv.blockman_.top_block_size();
top_blocks = blockman_.reserve_top_blocks(arg_top_blocks);
bm::word_t*** blk_root = blockman_.top_blocks_root();
bm::word_t*** blk_root_arg = bv.blockman_.top_blocks_root();
for (unsigned i = 0; i < top_blocks; ++i)
{
bm::word_t** blk_blk_arg = (i < arg_top_blocks) ? blk_root_arg[i] : 0;
if (!blk_blk_arg)
continue;
bm::word_t** blk_blk = blk_root[i];
if (blk_blk == blk_blk_arg) // nothing to do (any XOR 0 == 0)
{
if ((bm::word_t*)blk_blk == FULL_BLOCK_FAKE_ADDR)
blk_root[i] = 0;
continue;
}
if ((bm::word_t*)blk_blk == FULL_BLOCK_FAKE_ADDR)
{
if (!blk_blk_arg)
continue;
blk_blk = blockman_.check_alloc_top_subblock(i);
}
if ((bm::word_t*)blk_blk_arg == FULL_BLOCK_FAKE_ADDR)
{
if (!blk_blk)
{
blk_root[i] = (bm::word_t**) FULL_BLOCK_FAKE_ADDR;
continue;
}
blk_blk_arg = FULL_SUB_BLOCK_REAL_ADDR;
}
if (!blk_blk)
blk_blk = blockman_.alloc_top_subblock(i);
unsigned j = 0;
bm::word_t* blk;
const bm::word_t* arg_blk;
do
{
#if defined(BM64_AVX2) || defined(BM64_AVX512)
if (!avx2_test_all_zero_wave2(blk_blk + j, blk_blk_arg + j))
{
BM_XOR_OP(0)
BM_XOR_OP(1)
BM_XOR_OP(2)
BM_XOR_OP(3)
}
j += 4;
#elif defined(BM64_SSE4)
if (!sse42_test_all_zero_wave2(blk_blk + j, blk_blk_arg + j))
{
BM_XOR_OP(0)
BM_XOR_OP(1)
}
j += 2;
#else
BM_XOR_OP(0)
++j;
#endif
} while (j < bm::set_sub_array_size);
} // for i
}
#undef BM_XOR_OP
//---------------------------------------------------------------------
#define BM_AND_OP(x) if (0 != (blk = blk_blk[j+x])) \
{ \
if (0 != (arg_blk = blk_blk_arg[j+x])) \
{ \
combine_operation_block_and(i, j+x, blk, arg_blk); \
if (opt_mode == opt_compress) \
blockman_.optimize_bit_block(i, j+x, opt_mode); \
} \
else \
blockman_.zero_block(i, j+x); \
}
template<class Alloc>
void bvector<Alloc>::combine_operation_and(const bm::bvector<Alloc>& bv,
typename bm::bvector<Alloc>::optmode opt_mode)
{
if (!blockman_.is_init())
return; // nothing to do, already empty
if (!bv.blockman_.is_init())
{
clear(true);
return;
}
unsigned top_blocks = blockman_.top_block_size();
if (size_ < bv.size_) // this vect shorter than the arg.
size_ = bv.size_;
unsigned arg_top_blocks = bv.blockman_.top_block_size();
top_blocks = blockman_.reserve_top_blocks(arg_top_blocks);
bm::word_t*** blk_root = blockman_.top_blocks_root();
bm::word_t*** blk_root_arg = bv.blockman_.top_blocks_root();
for (unsigned i = 0; i < top_blocks; ++i)
{
bm::word_t** blk_blk = blk_root[i];
if (!blk_blk) // nothing to do (0 AND 1 == 0)
continue;
bm::word_t** blk_blk_arg = (i < arg_top_blocks) ? blk_root_arg[i] : 0;
if (!blk_blk_arg) // free a whole group of blocks
{
if ((bm::word_t*)blk_blk == FULL_BLOCK_FAKE_ADDR)
{
blk_root[i] = 0;
}
else
{
for (unsigned j = 0; j < bm::set_sub_array_size; ++j)
blockman_.zero_block(i, j);
blockman_.deallocate_top_subblock(i);
}
continue;
}
if ((bm::word_t*)blk_blk_arg == FULL_BLOCK_FAKE_ADDR)
continue; // any & 1 == any
if ((bm::word_t*)blk_blk == FULL_BLOCK_FAKE_ADDR)
blk_blk = blockman_.check_alloc_top_subblock(i);
unsigned j = 0;
bm::word_t* blk;
const bm::word_t* arg_blk;
do
{
#if defined(BM64_AVX2) || defined(BM64_AVX512)
if (!avx2_test_all_zero_wave(blk_blk + j))
{
BM_AND_OP(0)
BM_AND_OP(1)
BM_AND_OP(2)
BM_AND_OP(3)
}
j += 4;
#elif defined(BM64_SSE4)
if (!sse42_test_all_zero_wave(blk_blk + j))
{
BM_AND_OP(0)
BM_AND_OP(1)
}
j += 2;
#else
BM_AND_OP(0)
++j;
#endif
} while (j < bm::set_sub_array_size);
} // for i
}
#undef BM_AND_OP
//---------------------------------------------------------------------
#define BM_SUB_OP(x) \
if ((0 != (blk = blk_blk[j+x])) && (0 != (arg_blk = blk_blk_arg[j+x]))) \
combine_operation_block_sub(i, j+x, blk, arg_blk);
template<class Alloc>
void bvector<Alloc>::combine_operation_sub(const bm::bvector<Alloc>& bv)
{
if (!blockman_.is_init() || !bv.blockman_.is_init())
return;
unsigned top_blocks = blockman_.top_block_size();
if (size_ < bv.size_) // this vect shorter than the arg.
size_ = bv.size_;
unsigned arg_top_blocks = bv.blockman_.top_block_size();
top_blocks = blockman_.reserve_top_blocks(arg_top_blocks);
bm::word_t*** blk_root = blockman_.top_blocks_root();
bm::word_t*** blk_root_arg = bv.blockman_.top_blocks_root();
for (unsigned i = 0; i < top_blocks; ++i)
{
bm::word_t** blk_blk = blk_root[i];
bm::word_t** blk_blk_arg = (i < arg_top_blocks) ? blk_root_arg[i] : 0;
if (!blk_blk || !blk_blk_arg) // nothing to do (0 AND NOT 1 == 0)
continue;
if ((bm::word_t*)blk_blk_arg == FULL_BLOCK_FAKE_ADDR) // zero result
{
blockman_.deallocate_top_subblock(i);
continue;
}
if ((bm::word_t*)blk_blk == FULL_BLOCK_FAKE_ADDR)
blk_blk = blockman_.check_alloc_top_subblock(i);
bm::word_t* blk;
const bm::word_t* arg_blk;
unsigned j = 0;
do
{
#if defined(BM64_AVX2) || defined(BM64_AVX512)
if (!avx2_test_all_zero_wave(blk_blk + j))
{
BM_SUB_OP(0)
BM_SUB_OP(1)
BM_SUB_OP(2)
BM_SUB_OP(3)
}
j += 4;
#elif defined(BM64_SSE4)
if (!sse42_test_all_zero_wave(blk_blk + j))
{
BM_SUB_OP(0)
BM_SUB_OP(1)
}
j += 2;
#else
BM_SUB_OP(0)
++j;
#endif
} while (j < bm::set_sub_array_size);
} // for i
}
#undef BM_SUB_OP
//---------------------------------------------------------------------
template<class Alloc>
void bvector<Alloc>::combine_operation(
const bm::bvector<Alloc>& bv,
bm::operation opcode)
{
if (!blockman_.is_init())
{
if (opcode == BM_AND || opcode == BM_SUB)
return;
blockman_.init_tree();
}
unsigned top_blocks = blockman_.top_block_size();
unsigned arg_top_blocks = bv.blockman_.top_block_size();
if (arg_top_blocks > top_blocks)
top_blocks = blockman_.reserve_top_blocks(arg_top_blocks);
if (size_ < bv.size_) // this vect shorter than the arg.
{
size_ = bv.size_;
// stretch our capacity
blockman_.reserve_top_blocks(arg_top_blocks);
top_blocks = blockman_.top_block_size();
}
else
if (size_ > bv.size_) // this vector larger
{
if (opcode == BM_AND) // clear the tail with zeros
{
set_range(bv.size_, size_ - 1, false);
if (arg_top_blocks < top_blocks)
{
// not to scan blocks we already swiped
top_blocks = arg_top_blocks;
}
}
}
bm::word_t*** blk_root = blockman_.top_blocks_root();
unsigned block_idx = 0; (void) block_idx;
unsigned i, j;
// calculate effective top size to avoid overscan
top_blocks = blockman_.top_block_size();
if (top_blocks < bv.blockman_.top_block_size())
{
if (opcode != BM_AND)
{
top_blocks = bv.blockman_.top_block_size();
}
}
for (i = 0; i < top_blocks; ++i)
{
bm::word_t** blk_blk = blk_root[i];
if (blk_blk == 0) // not allocated
{
if (opcode == BM_AND) // 0 AND anything == 0
{
block_idx += bm::set_sub_array_size;
continue;
}
const bm::word_t* const* bvbb = bv.blockman_.get_topblock(i);
if (bvbb == 0) // skip it because 0 OP 0 == 0
{
block_idx += bm::set_sub_array_size;
continue;
}
// 0 - self, non-zero argument
block_idx_type r = i * bm::set_sub_array_size;
for (j = 0; j < bm::set_sub_array_size; ++j)
{
const bm::word_t* arg_blk = bv.blockman_.get_block(i, j);
if (arg_blk )
combine_operation_with_block(r + j,
0, 0,
arg_blk, BM_IS_GAP(arg_blk),
opcode);
} // for j
continue;
}
if (opcode == BM_AND)
{
block_idx_type r = i * bm::set_sub_array_size;
for (j = 0; j < bm::set_sub_array_size; ++j)
{
bm::word_t* blk = blk_blk[j];
if (blk)
{
const bm::word_t* arg_blk = bv.blockman_.get_block(i, j);
if (arg_blk)
combine_operation_with_block(r + j,
BM_IS_GAP(blk), blk,
arg_blk, BM_IS_GAP(arg_blk),
opcode);
else
blockman_.zero_block(i, j);
}
} // for j
}
else // OR, SUB, XOR
{
block_idx_type r = i * bm::set_sub_array_size;
for (j = 0; j < bm::set_sub_array_size; ++j)
{
bm::word_t* blk = blk_blk[j];
const bm::word_t* arg_blk = bv.blockman_.get_block(i, j);
if (arg_blk || blk)
combine_operation_with_block(r + j, BM_IS_GAP(blk), blk,
arg_blk, BM_IS_GAP(arg_blk),
opcode);
} // for j
}
} // for i
}
//---------------------------------------------------------------------
template<class Alloc>
bool bvector<Alloc>::combine_operation_block_or(unsigned i,
unsigned j,
const bm::word_t* arg_blk1,
const bm::word_t* arg_blk2)
{
bm::gap_word_t tmp_buf[bm::gap_equiv_len * 3]; // temporary result
if (!arg_blk1)
{
blockman_.clone_assign_block(i, j, arg_blk2);
return 0;
}
if (!arg_blk2)
{
blockman_.clone_assign_block(i, j, arg_blk1);
return 0;
}
if ((arg_blk1==FULL_BLOCK_FAKE_ADDR) || (arg_blk2==FULL_BLOCK_FAKE_ADDR))
{
blockman_.set_block_ptr(i, j, FULL_BLOCK_FAKE_ADDR);
return 0;
}
bool is_gap1 = BM_IS_GAP(arg_blk1);
bool is_gap2 = BM_IS_GAP(arg_blk2);
if (is_gap1 | is_gap2) // at least one GAP
{
if (is_gap1 & is_gap2) // both GAPS
{
unsigned res_len;
bm::gap_operation_or(BMGAP_PTR(arg_blk1),
BMGAP_PTR(arg_blk2),
tmp_buf, res_len);
blockman_.clone_gap_block(i, j, tmp_buf, res_len);
return 0;
}
// one GAP one bit block
const bm::word_t* arg_block;
const bm::gap_word_t* arg_gap;
if (is_gap1) // arg1 is GAP -> clone arg2(bit)
{
arg_block = arg_blk2;
arg_gap = BMGAP_PTR(arg_blk1);
}
else // arg2 is GAP
{
arg_block = arg_blk1;
arg_gap = BMGAP_PTR(arg_blk2);
}
bm::word_t* block = blockman_.clone_assign_block(i, j, arg_block);
bm::gap_add_to_bitset(block, arg_gap);
return true; // optimization may be needed
}
// 2 bit-blocks
//
bm::word_t* block = blockman_.borrow_tempblock();
blockman_.set_block_ptr(i, j, block);
bool all_one = bm::bit_block_or_2way(block, arg_blk1, arg_blk2);
if (all_one)
{
blockman_.set_block_ptr(i, j, FULL_BLOCK_FAKE_ADDR);
blockman_.return_tempblock(block);
return 0;
}
return true;
}
//---------------------------------------------------------------------
template<class Alloc>
bool bvector<Alloc>::combine_operation_block_xor(unsigned i,
unsigned j,
const bm::word_t* arg_blk1,
const bm::word_t* arg_blk2)
{
bm::gap_word_t tmp_buf[bm::gap_equiv_len * 3]; // temporary result
if (!arg_blk1)
{
blockman_.clone_assign_block(i, j, arg_blk2);
return 0;
}
if (!arg_blk2)
{
blockman_.clone_assign_block(i, j, arg_blk1);
return 0;
}
if (arg_blk1==FULL_BLOCK_FAKE_ADDR)
{
BM_ASSERT(!IS_FULL_BLOCK(arg_blk2));
blockman_.clone_assign_block(i, j, arg_blk2, true); // invert
return 0;
}
if (arg_blk2==FULL_BLOCK_FAKE_ADDR)
{
BM_ASSERT(!IS_FULL_BLOCK(arg_blk1));
blockman_.clone_assign_block(i, j, arg_blk1, true); // invert
return 0;
}
bool is_gap1 = BM_IS_GAP(arg_blk1);
bool is_gap2 = BM_IS_GAP(arg_blk2);
if (is_gap1 | is_gap2) // at least one GAP
{
if (is_gap1 & is_gap2) // both GAPS
{
unsigned res_len;
bm::gap_operation_xor(BMGAP_PTR(arg_blk1),
BMGAP_PTR(arg_blk2),
tmp_buf, res_len);
blockman_.clone_gap_block(i, j, tmp_buf, res_len);
return 0;
}
// one GAP one bit block
const bm::word_t* arg_block;
const bm::gap_word_t* arg_gap;
if (is_gap1) // arg1 is GAP -> clone arg2(bit)
{
arg_block = arg_blk2;
arg_gap = BMGAP_PTR(arg_blk1);
}
else // arg2 is GAP
{
arg_block = arg_blk1;
arg_gap = BMGAP_PTR(arg_blk2);
}
bm::word_t* block = blockman_.clone_assign_block(i, j, arg_block);
bm::gap_xor_to_bitset(block, arg_gap);
return true; // optimization may be needed
}
// 2 bit-blocks
//
bm::word_t* block = blockman_.borrow_tempblock();
blockman_.set_block_ptr(i, j, block);
bm::id64_t or_mask = bm::bit_block_xor_2way(block, arg_blk1, arg_blk2);
if (!or_mask)
{
blockman_.set_block_ptr(i, j, 0);
blockman_.return_tempblock(block);
return 0;
}
return true;
}
//---------------------------------------------------------------------
template<class Alloc>
bool bvector<Alloc>::combine_operation_block_and(unsigned i,
unsigned j,
const bm::word_t* arg_blk1,
const bm::word_t* arg_blk2)
{
bm::gap_word_t tmp_buf[bm::gap_equiv_len * 3]; // temporary result
if (!arg_blk1 || !arg_blk2)
return 0;
if ((arg_blk1==FULL_BLOCK_FAKE_ADDR) && (arg_blk2==FULL_BLOCK_FAKE_ADDR))
{
blockman_.set_block_ptr(i, j, FULL_BLOCK_FAKE_ADDR);
return 0;
}
if (arg_blk1==FULL_BLOCK_FAKE_ADDR)
{
blockman_.clone_assign_block(i, j, arg_blk2);
return 0;
}
if (arg_blk2==FULL_BLOCK_FAKE_ADDR)
{
blockman_.clone_assign_block(i, j, arg_blk1);
return 0;
}
bool is_gap1 = BM_IS_GAP(arg_blk1);
bool is_gap2 = BM_IS_GAP(arg_blk2);
if (is_gap1 | is_gap2) // at least one GAP
{
if (is_gap1 & is_gap2) // both GAPS
{
unsigned res_len;
bm::gap_operation_and(BMGAP_PTR(arg_blk1),
BMGAP_PTR(arg_blk2),
tmp_buf, res_len);
blockman_.clone_gap_block(i, j, tmp_buf, res_len);
return 0;
}
// one GAP one bit block
const bm::word_t* arg_block;
const bm::gap_word_t* arg_gap;
if (is_gap1) // arg1 is GAP -> clone arg2(bit)
{
arg_block = arg_blk2;
arg_gap = BMGAP_PTR(arg_blk1);
}
else // arg2 is GAP
{
arg_block = arg_blk1;
arg_gap = BMGAP_PTR(arg_blk2);
}
bm::word_t* block = blockman_.clone_assign_block(i, j, arg_block);
bm::gap_and_to_bitset(block, arg_gap);
bool all_z = bm::bit_is_all_zero(block); // maybe ALL empty block?
if (all_z)
{
blockman_.set_block_ptr(i, j, 0);
blockman_.return_tempblock(block);
return false;
}
return true; // optimization may be needed
}
// 2 bit-blocks
//
bm::word_t* block = blockman_.borrow_tempblock();
blockman_.set_block_ptr(i, j, block);
bm::id64_t digest = bm::bit_block_and_2way(block, arg_blk1, arg_blk2, ~0ull);
if (!digest)
{
blockman_.set_block_ptr(i, j, 0);
blockman_.return_tempblock(block);
return 0;
}
return true;
}
//---------------------------------------------------------------------
template<class Alloc>
bool bvector<Alloc>::combine_operation_block_and_or(unsigned i,
unsigned j,
const bm::word_t* arg_blk1,
const bm::word_t* arg_blk2)
{
bm::gap_word_t tmp_buf[bm::gap_equiv_len * 3]; // temporary result
bm::word_t* blk = blockman_.get_block_ptr(i, j);
BM_ASSERT(blk); // target block MUST be allocated
if (!arg_blk1 || !arg_blk2)
return 0;
if ((arg_blk1==FULL_BLOCK_FAKE_ADDR) && (arg_blk2==FULL_BLOCK_FAKE_ADDR))
{
if (blk)
blockman_.zero_block(i, j); // free target block and assign FULL
blockman_.set_block_ptr(i, j, FULL_BLOCK_FAKE_ADDR);
return 0;
}
if (arg_blk1==FULL_BLOCK_FAKE_ADDR)
{
combine_operation_block_or(i, j, blk, arg_blk2);
return 0;
}
if (arg_blk2==FULL_BLOCK_FAKE_ADDR)
{
combine_operation_block_or(i, j, blk, arg_blk1);
return 0;
}
blk = blockman_.deoptimize_block_no_check(blk, i, j);
bool is_gap1 = BM_IS_GAP(arg_blk1);
bool is_gap2 = BM_IS_GAP(arg_blk2);
if (is_gap1 | is_gap2) // at least one GAP
{
if (is_gap1 & is_gap2) // both GAPS
{
unsigned res_len;
bm::gap_operation_and(BMGAP_PTR(arg_blk1), BMGAP_PTR(arg_blk2),
tmp_buf, res_len);
bm::gap_add_to_bitset(blk, tmp_buf, res_len);
bool all_one = bm::is_bits_one((bm::wordop_t*) blk);
if (all_one)
{
blockman_.return_tempblock(blk);
blockman_.set_block_ptr(i, j, FULL_BLOCK_FAKE_ADDR);
return false;
}
return true;
}
// one GAP, one bit
const bm::word_t* arg_block;
const bm::gap_word_t* arg_gap;
if (is_gap1) // arg1 is GAP -> clone arg2(bit)
{
arg_block = arg_blk2;
arg_gap = BMGAP_PTR(arg_blk1);
}
else // arg2 is GAP
{
arg_block = arg_blk1;
arg_gap = BMGAP_PTR(arg_blk2);
}
bm::word_t* tmp_blk = blockman_.check_allocate_tempblock();
bm::bit_block_copy(tmp_blk, arg_block);
bm::gap_and_to_bitset(tmp_blk, arg_gap); // bit := bit AND gap
bool all_one = bm::bit_block_or(blk, tmp_blk); // target |= bit
if (all_one)
{
BM_ASSERT(bm::is_bits_one((bm::wordop_t*) blk));
blockman_.return_tempblock(blk);
blockman_.set_block_ptr(i, j, FULL_BLOCK_FAKE_ADDR);
return false;
}
return true; // optimization may be needed
}
// 1+2 bit-blocks
//
bm::id64_t digest_and = ~0ull;
bm::id64_t digest =
bm::bit_block_and_or_2way(blk, arg_blk1, arg_blk2, digest_and);
if (digest == digest_and)
{
bool all_one = bm::is_bits_one((bm::wordop_t*) blk);
if (all_one)
{
blockman_.return_tempblock(blk);
blockman_.set_block_ptr(i, j, FULL_BLOCK_FAKE_ADDR);
return false;
}
}
return true; // optimization may be needed
}
//---------------------------------------------------------------------
template<class Alloc>
bool bvector<Alloc>::combine_operation_block_sub(unsigned i,
unsigned j,
const bm::word_t* arg_blk1,
const bm::word_t* arg_blk2)
{
bm::gap_word_t tmp_buf[bm::gap_equiv_len * 3]; // temporary result
if (!arg_blk1)
return 0;
if (!arg_blk2)
{
blockman_.clone_assign_block(i, j, arg_blk1);
return 0;
}
if (arg_blk2==FULL_BLOCK_FAKE_ADDR)
return 0;
if (arg_blk1==FULL_BLOCK_FAKE_ADDR)
arg_blk1 = FULL_BLOCK_REAL_ADDR;
bool is_gap1 = BM_IS_GAP(arg_blk1);
bool is_gap2 = BM_IS_GAP(arg_blk2);
if (is_gap1 | is_gap2) // at least one GAP
{
if (is_gap1 & is_gap2) // both GAPS
{
unsigned res_len;
bm::gap_operation_sub(BMGAP_PTR(arg_blk1),
BMGAP_PTR(arg_blk2),
tmp_buf, res_len);
blockman_.clone_gap_block(i, j, tmp_buf, res_len);
return 0;
}
if (is_gap1)
{
bm::word_t* block = blockman_.borrow_tempblock();
blockman_.set_block_ptr(i, j, block);
bm::gap_convert_to_bitset(block, BMGAP_PTR(arg_blk1));
bm::id64_t acc = bm::bit_block_sub(block, arg_blk2);
if (!acc)
{
blockman_.set_block_ptr(i, j, 0);
blockman_.return_tempblock(block);
return 0;
}
return true;
}
BM_ASSERT(is_gap2);
bm::word_t* block = blockman_.clone_assign_block(i, j, arg_blk1);
bm::gap_sub_to_bitset(block, BMGAP_PTR(arg_blk2));
return true; // optimization may be needed
}
// 2 bit-blocks:
//
bm::word_t* block = blockman_.borrow_tempblock();
blockman_.set_block_ptr(i, j, block);
bm::id64_t digest = bm::bit_block_sub_2way(block, arg_blk1, arg_blk2, ~0ull);
if (!digest)
{
blockman_.set_block_ptr(i, j, 0);
blockman_.return_tempblock(block);
return 0;
}
return true;
}
//---------------------------------------------------------------------
template<class Alloc>
void bvector<Alloc>::combine_operation_block_or(
unsigned i, unsigned j,
bm::word_t* blk, const bm::word_t* arg_blk)
{
bm::gap_word_t tmp_buf[bm::gap_equiv_len * 3]; // temporary result
if (IS_FULL_BLOCK(blk) || !arg_blk) // all bits are set
return; // nothing to do
if (IS_FULL_BLOCK(arg_blk))
{
if (blk)
blockman_.zero_block(i, j); // free target block and assign FULL
blockman_.set_block_ptr(i, j, FULL_BLOCK_FAKE_ADDR);
return;
}
if (BM_IS_GAP(blk)) // our block GAP-type
{
bm::gap_word_t* gap_blk = BMGAP_PTR(blk);
if (BM_IS_GAP(arg_blk)) // both blocks GAP-type
{
const bm::gap_word_t* res; unsigned res_len;
res = bm::gap_operation_or(gap_blk, BMGAP_PTR(arg_blk),
tmp_buf, res_len);
BM_ASSERT(res == tmp_buf);
blockman_.assign_gap_check(i, j, res, ++res_len, blk, tmp_buf);
return;
}
// GAP or BIT
//
bm::word_t* new_blk = blockman_.get_allocator().alloc_bit_block();
bm::bit_block_copy(new_blk, arg_blk);
bm::gap_add_to_bitset(new_blk, gap_blk);
blockman_.get_allocator().free_gap_block(gap_blk, blockman_.glen());
blockman_.set_block_ptr(i, j, new_blk);
return;
}
else // our block is BITSET-type (but NOT FULL_BLOCK we checked it)
{
if (BM_IS_GAP(arg_blk)) // argument block is GAP-type
{
const bm::gap_word_t* arg_gap = BMGAP_PTR(arg_blk);
if (!blk)
{
bool gap = true;
blk = blockman_.clone_gap_block(arg_gap, gap);
blockman_.set_block(i, j, blk, gap);
return;
}
// BIT & GAP
bm::gap_add_to_bitset(blk, arg_gap);
return;
} // if arg_gap
}
if (!blk)
{
blk = blockman_.alloc_.alloc_bit_block();
bm::bit_block_copy(blk, arg_blk);
blockman_.set_block_ptr(i, j, blk);
return;
}
bool all_one = bm::bit_block_or(blk, arg_blk);
if (all_one)
{
BM_ASSERT(bm::is_bits_one((bm::wordop_t*) blk));
blockman_.get_allocator().free_bit_block(blk);
blockman_.set_block_ptr(i, j, FULL_BLOCK_FAKE_ADDR);
}
}
//---------------------------------------------------------------------
template<class Alloc>
void bvector<Alloc>::combine_operation_block_xor(
unsigned i, unsigned j,
bm::word_t* blk, const bm::word_t* arg_blk)
{
bm::gap_word_t tmp_buf[bm::gap_equiv_len * 3]; // temporary result
if (!arg_blk) // all bits are set
return; // nothing to do
if (IS_FULL_BLOCK(arg_blk))
{
if (blk)
{
if (BM_IS_GAP(blk))
bm::gap_invert(BMGAP_PTR(blk));
else
{
if (IS_FULL_BLOCK(blk)) // 1 xor 1 = 0
blockman_.set_block_ptr(i, j, 0);
else
bm::bit_invert((wordop_t*) blk);
}
}
else // blk == 0
{
blockman_.set_block_ptr(i, j, FULL_BLOCK_FAKE_ADDR);
}
return;
}
if (IS_FULL_BLOCK(blk))
{
if (!arg_blk)
return;
// deoptimize block
blk = blockman_.get_allocator().alloc_bit_block();
bm::bit_block_set(blk, ~0u);
blockman_.set_block_ptr(i, j, blk);
}
if (BM_IS_GAP(blk)) // our block GAP-type
{
bm::gap_word_t* gap_blk = BMGAP_PTR(blk);
if (BM_IS_GAP(arg_blk)) // both blocks GAP-type
{
const bm::gap_word_t* res;
unsigned res_len;
res = bm::gap_operation_xor(gap_blk,
BMGAP_PTR(arg_blk),
tmp_buf,
res_len);
BM_ASSERT(res == tmp_buf);
blockman_.assign_gap_check(i, j, res, ++res_len, blk, tmp_buf);
return;
}
// GAP or BIT
//
bm::word_t* new_blk = blockman_.get_allocator().alloc_bit_block();
bm::bit_block_copy(new_blk, arg_blk);
bm::gap_xor_to_bitset(new_blk, gap_blk);
blockman_.get_allocator().free_gap_block(gap_blk, blockman_.glen());
blockman_.set_block_ptr(i, j, new_blk);
return;
}
else // our block is BITSET-type (but NOT FULL_BLOCK we checked it)
{
if (BM_IS_GAP(arg_blk)) // argument block is GAP-type
{
const bm::gap_word_t* arg_gap = BMGAP_PTR(arg_blk);
if (!blk)
{
bool gap = true;
blk = blockman_.clone_gap_block(arg_gap, gap);
blockman_.set_block(i, j, blk, gap);
return;
}
// BIT & GAP
bm::gap_xor_to_bitset(blk, arg_gap);
return;
} // if arg_gap
}
if (!blk)
{
blk = blockman_.alloc_.alloc_bit_block();
bm::bit_block_copy(blk, arg_blk);
blockman_.set_block_ptr(i, j, blk);
return;
}
auto any_bits = bm::bit_block_xor(blk, arg_blk);
if (!any_bits)
{
blockman_.get_allocator().free_bit_block(blk);
blockman_.set_block_ptr(i, j, 0);
}
}
//---------------------------------------------------------------------
template<class Alloc>
void bvector<Alloc>::combine_operation_block_and(
unsigned i, unsigned j, bm::word_t* blk, const bm::word_t* arg_blk)
{
BM_ASSERT(arg_blk && blk);
if (IS_FULL_BLOCK(arg_blk))
return; // nothing to do
gap_word_t tmp_buf[bm::gap_equiv_len * 3]; // temporary result
if (BM_IS_GAP(blk)) // our block GAP-type
{
bm::gap_word_t* gap_blk = BMGAP_PTR(blk);
if (BM_IS_GAP(arg_blk)) // both blocks GAP-type
{
const bm::gap_word_t* res;
unsigned res_len;
res = bm::gap_operation_and(gap_blk,
BMGAP_PTR(arg_blk),
tmp_buf,
res_len);
BM_ASSERT(res == tmp_buf);
blockman_.assign_gap_check(i, j, res, ++res_len, blk, tmp_buf);
return;
}
// GAP & BIT
//
bm::word_t* new_blk = blockman_.get_allocator().alloc_bit_block();
bm::bit_block_copy(new_blk, arg_blk); // TODO: copy+digest in one pass
bm::id64_t d0 = bm::calc_block_digest0(new_blk);
bm::id64_t d0_1 = bm::gap_and_to_bitset(new_blk, gap_blk, d0);
// bm::id64_t d0_1 = bm::update_block_digest0(new_blk, d0);
BM_ASSERT(bm::word_bitcount64(d0_1) <= bm::word_bitcount64(d0));
if (!d0_1)
{
BM_ASSERT(bm::bit_is_all_zero(new_blk));
blockman_.get_allocator().free_bit_block(new_blk);
new_blk = 0;
}
else
{
BM_ASSERT(!bm::bit_is_all_zero(new_blk));
}
blockman_.get_allocator().free_gap_block(gap_blk, blockman_.glen());
blockman_.set_block_ptr(i, j, new_blk);
return;
}
else // our block is BITSET-type or FULL_BLOCK
{
if (BM_IS_GAP(arg_blk)) // argument block is GAP-type
{
const bm::gap_word_t* arg_gap = BMGAP_PTR(arg_blk);
if (bm::gap_is_all_zero(arg_gap))
{
blockman_.zero_block(i, j);
return;
}
// FULL & GAP is common when AND with set_range() mask
//
if (IS_FULL_BLOCK(blk)) // FULL & gap = gap
{
bool is_new_gap;
bm::word_t* new_blk = blockman_.clone_gap_block(arg_gap, is_new_gap);
if (is_new_gap)
BMSET_PTRGAP(new_blk);
blockman_.set_block_ptr(i, j, new_blk);
return;
}
// BIT & GAP
bm::gap_and_to_bitset(blk, arg_gap);
bool empty = bm::bit_is_all_zero(blk);
if (empty) // operation converged bit-block to empty
blockman_.zero_block(i, j);
return;
} // if arg_gap
}
// FULL & bit is common when AND with set_range() mask
//
if (IS_FULL_BLOCK(blk)) // FULL & bit = bit
{
bm::word_t* new_blk = blockman_.get_allocator().alloc_bit_block();
bm::bit_block_copy(new_blk, arg_blk);
blockman_.set_block_ptr(i, j, new_blk);
return;
}
auto any_bits = bm::bit_block_and(blk, arg_blk);
if (!any_bits)
{
blockman_.get_allocator().free_bit_block(blk);
blockman_.set_block_ptr(i, j, 0);
}
}
//---------------------------------------------------------------------
template<class Alloc>
void bvector<Alloc>::combine_operation_block_sub(
unsigned i, unsigned j, bm::word_t* blk, const bm::word_t* arg_blk)
{
BM_ASSERT(arg_blk && blk);
if (IS_FULL_BLOCK(arg_blk))
{
blockman_.zero_block(i, j);
return;
}
gap_word_t tmp_buf[bm::gap_equiv_len * 3]; // temporary result
if (BM_IS_GAP(blk)) // our block GAP-type
{
bm::gap_word_t* gap_blk = BMGAP_PTR(blk);
if (BM_IS_GAP(arg_blk)) // both blocks GAP-type
{
const bm::gap_word_t* res;
unsigned res_len;
res = bm::gap_operation_sub(gap_blk,
BMGAP_PTR(arg_blk),
tmp_buf,
res_len);
BM_ASSERT(res == tmp_buf);
BM_ASSERT(!(res == tmp_buf && res_len == 0));
blockman_.assign_gap_check(i, j, res, ++res_len, blk, tmp_buf);
return;
}
// else: argument is BITSET-type (own block is GAP)
blk = blockman_.convert_gap2bitset(i, j, gap_blk);
// fall through to bit-block to bit-block operation
}
else // our block is BITSET-type or FULL_BLOCK
{
if (BM_IS_GAP(arg_blk)) // argument block is GAP-type
{
if (!IS_FULL_BLOCK(blk)) // gap combined to bitset
{
bm::gap_sub_to_bitset(blk, BMGAP_PTR(arg_blk));
bool empty = bm::bit_is_all_zero(blk);
if (empty) // operation converged bit-block to empty
blockman_.zero_block(i, j);
return;
}
// the worst case: convert arg block to bitset
arg_blk =
gap_convert_to_bitset_smart(blockman_.check_allocate_tempblock(),
BMGAP_PTR(arg_blk),
bm::gap_max_bits);
}
}
// Now here we combine two plain bitblocks using supplied bit function.
bm::word_t* dst = blk;
bm::word_t* ret;
if (!dst || !arg_blk)
return;
ret = bm::bit_operation_sub(dst, arg_blk);
if (ret && ret == arg_blk)
{
ret = blockman_.get_allocator().alloc_bit_block();
bm::bit_andnot_arr_ffmask(ret, arg_blk);
}
if (ret != dst) // block mutation
{
blockman_.set_block_ptr(i, j, ret);
if (IS_VALID_ADDR(dst))
blockman_.get_allocator().free_bit_block(dst);
}
}
//---------------------------------------------------------------------
template<class Alloc>
void
bvector<Alloc>::combine_operation_with_block(block_idx_type nb,
bool gap,
bm::word_t* blk,
const bm::word_t* arg_blk,
bool arg_gap,
bm::operation opcode)
{
gap_word_t tmp_buf[bm::gap_equiv_len * 3]; // temporary result
const bm::gap_word_t* res;
unsigned res_len;
if (opcode == BM_OR || opcode == BM_XOR)
{
if (!blk && arg_gap)
{
blk = blockman_.clone_gap_block(BMGAP_PTR(arg_blk), gap);
blockman_.set_block(nb, blk, gap);
return;
}
}
if (gap) // our block GAP-type
{
if (arg_gap) // both blocks GAP-type
{
{
gap_operation_func_type gfunc =
operation_functions<true>::gap_operation(opcode);
BM_ASSERT(gfunc);
res = (*gfunc)(BMGAP_PTR(blk),
BMGAP_PTR(arg_blk),
tmp_buf,
res_len);
}
BM_ASSERT(res == tmp_buf);
BM_ASSERT(!(res == tmp_buf && res_len == 0));
// if as a result of the operation gap block turned to zero
// we can now replace it with NULL
if (bm::gap_is_all_zero(res))
blockman_.zero_block(nb);
else
blockman_.assign_gap(nb, res, ++res_len, blk, tmp_buf);
return;
}
else // argument is BITSET-type (own block is GAP)
{
// since we can not combine blocks of mixed type
// we need to convert our block to bitset
if (arg_blk == 0) // Combining against an empty block
{
switch (opcode)
{
case BM_AND: // ("Value" AND 0) == 0
blockman_.zero_block(nb);
return;
case BM_OR: case BM_SUB: case BM_XOR:
return; // nothing to do
default:
return; // nothing to do
}
}
gap_word_t* gap_blk = BMGAP_PTR(blk);
blk = blockman_.convert_gap2bitset(nb, gap_blk);
}
}
else // our block is BITSET-type
{
if (arg_gap) // argument block is GAP-type
{
if (IS_VALID_ADDR(blk))
{
// special case, maybe we can do the job without
// converting the GAP argument to bitblock
gap_operation_to_bitset_func_type gfunc =
bm::operation_functions<true>::gap_op_to_bit(opcode);
BM_ASSERT(gfunc);
(*gfunc)(blk, BMGAP_PTR(arg_blk));
// TODO: commented out optimization, because it can be very slow
// need to take into account previous operation not to make
// fruitless attempts here
//blockman_.optimize_bit_block(nb);
return;
}
// the worst case we need to convert argument block to
// bitset type.
gap_word_t* temp_blk = (gap_word_t*) blockman_.check_allocate_tempblock();
arg_blk =
gap_convert_to_bitset_smart((bm::word_t*)temp_blk,
BMGAP_PTR(arg_blk),
bm::gap_max_bits);
}
}
// Now here we combine two plain bitblocks using supplied bit function.
bm::word_t* dst = blk;
bm::word_t* ret;
if (dst == 0 && arg_blk == 0)
return;
switch (opcode)
{
case BM_AND:
ret = bm::bit_operation_and(dst, arg_blk);
goto copy_block;
case BM_XOR:
ret = bm::bit_operation_xor(dst, arg_blk);
if (ret && (ret == arg_blk) && IS_FULL_BLOCK(dst))
{
ret = blockman_.get_allocator().alloc_bit_block();
#ifdef BMVECTOPT
VECT_XOR_ARR_2_MASK(ret,
arg_blk,
arg_blk + bm::set_block_size,
~0u);
#else
bm::wordop_t* dst_ptr = (wordop_t*)ret;
const bm::wordop_t* wrd_ptr = (wordop_t*) arg_blk;
const bm::wordop_t* wrd_end =
(wordop_t*) (arg_blk + bm::set_block_size);
do
{
dst_ptr[0] = bm::all_bits_mask ^ wrd_ptr[0];
dst_ptr[1] = bm::all_bits_mask ^ wrd_ptr[1];
dst_ptr[2] = bm::all_bits_mask ^ wrd_ptr[2];
dst_ptr[3] = bm::all_bits_mask ^ wrd_ptr[3];
dst_ptr+=4;
wrd_ptr+=4;
} while (wrd_ptr < wrd_end);
#endif
break;
}
goto copy_block;
case BM_OR:
ret = bm::bit_operation_or(dst, arg_blk);
copy_block:
if (ret && (ret == arg_blk) && !IS_FULL_BLOCK(ret))
{
ret = blockman_.get_allocator().alloc_bit_block();
bm::bit_block_copy(ret, arg_blk);
}
break;
case BM_SUB:
ret = bit_operation_sub(dst, arg_blk);
if (ret && ret == arg_blk)
{
ret = blockman_.get_allocator().alloc_bit_block();
bm::bit_andnot_arr_ffmask(ret, arg_blk);
}
break;
default:
BM_ASSERT(0);
ret = 0;
}
if (ret != dst) // block mutation
{
blockman_.set_block(nb, ret);
if (IS_VALID_ADDR(dst))
{
blockman_.get_allocator().free_bit_block(dst);
}
}
}
//---------------------------------------------------------------------
template<class Alloc>
void bvector<Alloc>::set_range_no_check(size_type left,
size_type right)
{
block_idx_type nblock_left = left >> bm::set_block_shift;
block_idx_type nblock_right = right >> bm::set_block_shift;
unsigned nbit_right = unsigned(right & bm::set_block_mask);
unsigned r =
(nblock_left == nblock_right) ? nbit_right :(bm::bits_in_block-1);
bm::gap_word_t tmp_gap_blk[5];
tmp_gap_blk[0] = 0; // just to silence GCC warning on uninit var
// Set bits in the starting block
//
block_idx_type nb;
unsigned i, j;
bm::word_t* block;
unsigned nbit_left = unsigned(left & bm::set_block_mask);
if ((nbit_left == 0) && (r == bm::bits_in_block - 1)) // full block
{
nb = nblock_left;
}
else
{
gap_init_range_block<gap_word_t>(tmp_gap_blk,
(gap_word_t)nbit_left,
(gap_word_t)r,
(gap_word_t)1);
bm::get_block_coord(nblock_left, i, j);
block = blockman_.get_block_ptr(i, j);
combine_operation_with_block(nblock_left,
BM_IS_GAP(block),
block,
(bm::word_t*) tmp_gap_blk,
1, BM_OR);
if (nblock_left == nblock_right) // in one block
return;
nb = nblock_left+1;
}
// Set all full blocks between left and right
//
block_idx_type nb_to = nblock_right + (nbit_right ==(bm::bits_in_block-1));
BM_ASSERT(nb_to >= nblock_right);
if (nb < nb_to)
{
BM_ASSERT(nb_to);
blockman_.set_all_set(nb, nb_to-1);
}
if (nb_to > nblock_right)
return;
bm::get_block_coord(nblock_right, i, j);
block = blockman_.get_block_ptr(i, j);
gap_init_range_block<gap_word_t>(tmp_gap_blk,
(gap_word_t)0,
(gap_word_t)nbit_right,
(gap_word_t)1);
combine_operation_with_block(nblock_right,
BM_IS_GAP(block),
block,
(bm::word_t*) tmp_gap_blk,
1, BM_OR);
}
//---------------------------------------------------------------------
template<class Alloc>
void bvector<Alloc>::clear_range_no_check(size_type left,
size_type right)
{
block_idx_type nb;
unsigned i, j;
// calculate logical number of start and destination blocks
block_idx_type nblock_left = left >> bm::set_block_shift;
block_idx_type nblock_right = right >> bm::set_block_shift;
unsigned nbit_right = unsigned(right & bm::set_block_mask);
unsigned r =
(nblock_left == nblock_right) ? nbit_right : (bm::bits_in_block - 1);
bm::gap_word_t tmp_gap_blk[5];
tmp_gap_blk[0] = 0; // just to silence GCC warning on uninit var
// Set bits in the starting block
bm::word_t* block;
unsigned nbit_left = unsigned(left & bm::set_block_mask);
if ((nbit_left == 0) && (r == bm::bits_in_block - 1)) // full block
{
nb = nblock_left;
}
else
{
bm::gap_init_range_block<gap_word_t>(tmp_gap_blk,
(gap_word_t)nbit_left,
(gap_word_t)r,
(gap_word_t)0);
bm::get_block_coord(nblock_left, i, j);
block = blockman_.get_block_ptr(i, j);
combine_operation_with_block(nblock_left,
BM_IS_GAP(block),
block,
(bm::word_t*) tmp_gap_blk,
1,
BM_AND);
if (nblock_left == nblock_right) // in one block
return;
nb = nblock_left + 1;
}
// Clear all full blocks between left and right
block_idx_type nb_to = nblock_right + (nbit_right == (bm::bits_in_block - 1));
BM_ASSERT(nb_to >= nblock_right);
if (nb < nb_to)
{
BM_ASSERT(nb_to);
blockman_.set_all_zero(nb, nb_to - 1u);
}
if (nb_to > nblock_right)
return;
bm::get_block_coord(nblock_right, i, j);
block = blockman_.get_block_ptr(i, j);
gap_init_range_block<gap_word_t>(tmp_gap_blk,
(gap_word_t)0,
(gap_word_t)nbit_right,
(gap_word_t)0);
combine_operation_with_block(nblock_right,
BM_IS_GAP(block),
block,
(bm::word_t*) tmp_gap_blk,
1,
BM_AND);
}
//---------------------------------------------------------------------
template<class Alloc>
void bvector<Alloc>::copy_range(const bvector<Alloc>& bvect,
size_type left,
size_type right)
{
if (!bvect.blockman_.is_init())
{
clear();
return;
}
if (blockman_.is_init())
{
blockman_.deinit_tree();
}
if (left > right)
bm::xor_swap(left, right);
copy_range_no_check(bvect, left, right);
}
//---------------------------------------------------------------------
template<class Alloc>
void bvector<Alloc>::keep_range_no_check(size_type left, size_type right)
{
BM_ASSERT(left <= right);
BM_ASSERT_THROW(right < bm::id_max, BM_ERR_RANGE);
if (left)
{
clear_range_no_check(0, left - 1); // TODO: optimize clear from
}
if (right < bm::id_max - 1)
{
size_type last;
bool found = find_reverse(last);
if (found && (last > right))
clear_range_no_check(right + 1, last);
}
BM_ASSERT(count() == count_range(left, right));
}
//---------------------------------------------------------------------
template<class Alloc>
void bvector<Alloc>::copy_range_no_check(const bvector<Alloc>& bvect,
size_type left,
size_type right)
{
BM_ASSERT(left <= right);
BM_ASSERT_THROW(right < bm::id_max, BM_ERR_RANGE);
// copy all block(s) belonging to our range
block_idx_type nblock_left = (left >> bm::set_block_shift);
block_idx_type nblock_right = (right >> bm::set_block_shift);
blockman_.copy(bvect.blockman_, nblock_left, nblock_right);
if (left)
{
size_type from =
(left < bm::gap_max_bits) ? 0 : (left - bm::gap_max_bits);
clear_range_no_check(from, left-1); // TODO: optimize clear from
}
if (right < bm::id_max-1)
{
size_type last;
bool found = find_reverse(last);
if (found && (last > right))
clear_range_no_check(right+1, last);
}
//keep_range_no_check(left, right); // clear the flanks
}
//---------------------------------------------------------------------
template<class Alloc>
void bvector<Alloc>::freeze()
{
if (is_ro())
return; // nothing to do read-only vector already
bvector<Alloc> bv_ro(*this, bm::finalization::READONLY);
swap(bv_ro);
}
//---------------------------------------------------------------------
template<class Alloc>
void bvector<Alloc>::throw_bad_alloc()
{
#ifndef BM_NO_STL
throw std::bad_alloc();
#else
BM_THROW(BM_ERR_BADALLOC);
#endif
}
//---------------------------------------------------------------------
//
//---------------------------------------------------------------------
template<class Alloc>
bool bvector<Alloc>::enumerator::go_up() BMNOEXCEPT
{
BM_ASSERT(this->valid());
block_descr_type* bdescr = &(this->bdescr_);
if (this->block_type_) // GAP
{
BM_ASSERT(this->block_type_ == 1);
++this->position_;
if (--(bdescr->gap_.gap_len))
return true;
// next gap is "OFF" by definition.
if (*(bdescr->gap_.ptr) != bm::gap_max_bits - 1)
{
gap_word_t prev = *(bdescr->gap_.ptr);
unsigned val = *(++(bdescr->gap_.ptr));
this->position_ += val - prev;
// next gap is now "ON"
if (*(bdescr->gap_.ptr) != bm::gap_max_bits - 1)
{
prev = *(bdescr->gap_.ptr);
val = *(++(bdescr->gap_.ptr));
bdescr->gap_.gap_len = (gap_word_t)(val - prev);
return true; // next "ON" found;
}
}
}
else // BIT
{
unsigned short idx = ++(bdescr->bit_.idx);
if (idx < bdescr->bit_.cnt)
{
this->position_ = bdescr->bit_.pos + bdescr->bit_.bits[idx];
return true;
}
this->position_ +=
(bm::set_bitscan_wave_size * 32) - bdescr->bit_.bits[--idx];
bdescr->bit_.ptr += bm::set_bitscan_wave_size;
if (decode_bit_group(bdescr))
return true;
}
if (search_in_blocks())
return true;
this->invalidate();
return false;
}
//---------------------------------------------------------------------
template<class Alloc>
bool bvector<Alloc>::enumerator::skip(size_type rank) BMNOEXCEPT
{
if (!this->valid())
return false;
if (!rank)
return this->valid(); // nothing to do
for (; rank; --rank)
{
block_descr_type* bdescr = &(this->bdescr_);
switch (this->block_type_)
{
case 0: // BitBlock
for (; rank; --rank)
{
unsigned short idx = ++(bdescr->bit_.idx);
if (idx < bdescr->bit_.cnt)
{
this->position_ = bdescr->bit_.pos + bdescr->bit_.bits[idx];
continue;
}
this->position_ +=
(bm::set_bitscan_wave_size * 32) - bdescr->bit_.bits[--idx];
bdescr->bit_.ptr += bm::set_bitscan_wave_size;
if (!decode_bit_group(bdescr, rank))
break;
} // for rank
break;
case 1: // DGAP Block
for (; rank; --rank) // TODO: better skip logic
{
++this->position_;
if (--(bdescr->gap_.gap_len))
continue;
// next gap is "OFF" by definition.
if (*(bdescr->gap_.ptr) == bm::gap_max_bits - 1)
break;
gap_word_t prev = *(bdescr->gap_.ptr);
unsigned int val = *(++(bdescr->gap_.ptr));
this->position_ += val - prev;
// next gap is now "ON"
if (*(bdescr->gap_.ptr) == bm::gap_max_bits - 1)
break;
prev = *(bdescr->gap_.ptr);
val = *(++(bdescr->gap_.ptr));
bdescr->gap_.gap_len = (gap_word_t)(val - prev);
} // for rank
break;
default:
BM_ASSERT(0);
} // switch
if (!rank)
return true;
if (!search_in_blocks())
{
this->invalidate();
return false;
}
} // for rank
return this->valid();
}
//---------------------------------------------------------------------
template<class Alloc>
bool bvector<Alloc>::enumerator::go_to(size_type pos) BMNOEXCEPT
{
if (pos == 0)
{
go_first();
return this->valid();
}
size_type new_pos = this->bv_->check_or_next(pos); // find the true pos
if (!new_pos) // no bits available
{
this->invalidate();
return false;
}
BM_ASSERT(new_pos >= pos);
pos = new_pos;
this->position_ = pos;
size_type nb = this->block_idx_ = (pos >> bm::set_block_shift);
bm::bvector<Alloc>::blocks_manager_type& bman =
this->bv_->get_blocks_manager();
unsigned i0, j0;
bm::get_block_coord(nb, i0, j0);
this->block_ = bman.get_block(i0, j0);
BM_ASSERT(this->block_);
this->block_type_ = (bool)BM_IS_GAP(this->block_);
block_descr_type* bdescr = &(this->bdescr_);
unsigned nbit = unsigned(pos & bm::set_block_mask);
if (this->block_type_) // gap
{
this->position_ = nb * bm::set_block_size * 32;
search_in_gapblock();
if (this->position_ == pos)
return this->valid();
this->position_ = pos;
gap_word_t* gptr = BMGAP_PTR(this->block_);
unsigned is_set;
unsigned gpos = bm::gap_bfind(gptr, nbit, &is_set);
BM_ASSERT(is_set);
bdescr->gap_.ptr = gptr + gpos;
if (gpos == 1)
{
bdescr->gap_.gap_len = bm::gap_word_t(gptr[gpos] - (nbit - 1));
}
else
{
bm::gap_word_t interval = bm::gap_word_t(gptr[gpos] - gptr[gpos - 1]);
bm::gap_word_t interval2 = bm::gap_word_t(nbit - gptr[gpos - 1]);
bdescr->gap_.gap_len = bm::gap_word_t(interval - interval2 + 1);
}
}
else // bit
{
if (nbit == 0)
{
search_in_bitblock();
return this->valid();
}
unsigned nword = unsigned(nbit >> bm::set_word_shift);
// check if we need to step back to match the wave
unsigned parity = nword % bm::set_bitscan_wave_size;
bdescr->bit_.ptr = this->block_ + (nword - parity);
bdescr->bit_.cnt = bm::bitscan_wave(bdescr->bit_.ptr, bdescr->bit_.bits);
BM_ASSERT(bdescr->bit_.cnt);
bdescr->bit_.pos = (nb * bm::set_block_size * 32) + ((nword - parity) * 32);
bdescr->bit_.idx = 0;
nbit &= bm::set_word_mask;
nbit += 32 * parity;
for (unsigned i = 0; i < bdescr->bit_.cnt; ++i)
{
if (bdescr->bit_.bits[i] == nbit)
return this->valid();
bdescr->bit_.idx++;
} // for
BM_ASSERT(0);
}
return this->valid();
}
//---------------------------------------------------------------------
template<class Alloc>
void bvector<Alloc>::enumerator::go_first() BMNOEXCEPT
{
BM_ASSERT(this->bv_);
blocks_manager_type* bman = &(this->bv_->blockman_);
if (!bman->is_init())
{
this->invalidate();
return;
}
bm::word_t*** blk_root = bman->top_blocks_root();
this->block_idx_ = this->position_= 0;
unsigned i, j;
for (i = 0; i < bman->top_block_size(); ++i)
{
bm::word_t** blk_blk = blk_root[i];
if (blk_blk == 0) // not allocated
{
this->block_idx_ += bm::set_sub_array_size;
this->position_ += bm::bits_in_array;
continue;
}
if ((bm::word_t*)blk_blk == FULL_BLOCK_FAKE_ADDR)
blk_blk = FULL_SUB_BLOCK_REAL_ADDR;
for (j = 0; j < bm::set_sub_array_size; ++j,++(this->block_idx_))
{
this->block_ = blk_blk[j];
if (this->block_ == 0)
{
this->position_ += bits_in_block;
continue;
}
if (BM_IS_GAP(this->block_))
{
this->block_type_ = 1;
if (search_in_gapblock())
return;
}
else
{
if (this->block_ == FULL_BLOCK_FAKE_ADDR)
this->block_ = FULL_BLOCK_REAL_ADDR;
this->block_type_ = 0;
if (search_in_bitblock())
return;
}
} // for j
} // for i
this->invalidate();
}
//---------------------------------------------------------------------
template<class Alloc>
bool
bvector<Alloc>::enumerator::decode_wave(block_descr_type* bdescr) BMNOEXCEPT
{
bdescr->bit_.cnt = bm::bitscan_wave(bdescr->bit_.ptr, bdescr->bit_.bits);
if (bdescr->bit_.cnt) // found
{
bdescr->bit_.idx = 0;
return true;
}
return false;
}
//---------------------------------------------------------------------
template<class Alloc>
bool
bvector<Alloc>::enumerator::decode_bit_group(block_descr_type* bdescr) BMNOEXCEPT
{
const word_t* block_end = this->block_ + bm::set_block_size;
for (; bdescr->bit_.ptr < block_end;)
{
if (decode_wave(bdescr))
{
bdescr->bit_.pos = this->position_;
this->position_ += bdescr->bit_.bits[0];
return true;
}
this->position_ += bm::set_bitscan_wave_size * 32; // wave size
bdescr->bit_.ptr += bm::set_bitscan_wave_size;
} // for
return false;
}
//---------------------------------------------------------------------
template<class Alloc>
bool
bvector<Alloc>::enumerator::decode_bit_group(block_descr_type* bdescr,
size_type& rank) BMNOEXCEPT
{
const word_t* BMRESTRICT block_end = this->block_ + bm::set_block_size;
for (; bdescr->bit_.ptr < block_end;)
{
unsigned cnt;
#if defined(BMAVX512OPT) || defined(BMAVX2OPT) || defined(BM64OPT) || defined(BM64_SSE4)
{
const bm::id64_t* w64_p = (bm::id64_t*)bdescr->bit_.ptr;
BM_ASSERT(bm::set_bitscan_wave_size == 4);
cnt = bm::word_bitcount64(w64_p[0]);
cnt += bm::word_bitcount64(w64_p[1]);
}
#else
const bm::word_t* BMRESTRICT w = bdescr->bit_.ptr;
unsigned c1= bm::word_bitcount(w[0]);
unsigned c2 = bm::word_bitcount(w[1]);
cnt = c1 + c2;
c1= bm::word_bitcount(w[2]);
c2 = bm::word_bitcount(w[3]);
cnt += c1 + c2;
#endif
if (rank > cnt)
{
rank -= cnt;
}
else
{
if (decode_wave(bdescr))
{
bdescr->bit_.pos = this->position_;
this->position_ += bdescr->bit_.bits[0];
return true;
}
}
this->position_ += bm::set_bitscan_wave_size * 32; // wave size
bdescr->bit_.ptr += bm::set_bitscan_wave_size;
} // for
return false;
}
//---------------------------------------------------------------------
template<class Alloc>
bool bvector<Alloc>::enumerator::search_in_bitblock() BMNOEXCEPT
{
BM_ASSERT(this->block_type_ == 0);
block_descr_type* bdescr = &(this->bdescr_);
bdescr->bit_.ptr = this->block_;
return decode_bit_group(bdescr);
}
//---------------------------------------------------------------------
template<class Alloc>
bool bvector<Alloc>::enumerator::search_in_gapblock() BMNOEXCEPT
{
BM_ASSERT(this->block_type_ == 1);
block_descr_type* bdescr = &(this->bdescr_);
bdescr->gap_.ptr = BMGAP_PTR(this->block_);
unsigned bitval = *(bdescr->gap_.ptr) & 1;
++(bdescr->gap_.ptr);
for (;true;)
{
unsigned val = *(bdescr->gap_.ptr);
if (bitval)
{
gap_word_t* first = BMGAP_PTR(this->block_) + 1;
if (bdescr->gap_.ptr == first)
{
bdescr->gap_.gap_len = (gap_word_t)(val + 1);
}
else
{
bdescr->gap_.gap_len =
(gap_word_t)(val - *(bdescr->gap_.ptr-1));
}
return true;
}
this->position_ += val + 1;
if (val == bm::gap_max_bits - 1)
break;
bitval ^= 1;
++(bdescr->gap_.ptr);
}
return false;
}
//---------------------------------------------------------------------
template<class Alloc>
bool bvector<Alloc>::enumerator::search_in_blocks() BMNOEXCEPT
{
++(this->block_idx_);
const blocks_manager_type& bman = this->bv_->blockman_;
block_idx_type i = this->block_idx_ >> bm::set_array_shift;
block_idx_type top_block_size = bman.top_block_size();
bm::word_t*** blk_root = bman.top_blocks_root();
for (; i < top_block_size; ++i)
{
bm::word_t** blk_blk = blk_root[i];
if (blk_blk == 0)
{
// fast scan fwd in top level
size_type bn = this->block_idx_ + bm::set_sub_array_size;
size_type pos = this->position_ + bm::bits_in_array;
for (++i; i < top_block_size; ++i)
{
if (blk_root[i])
break;
bn += bm::set_sub_array_size;
pos += bm::bits_in_array;
} // for i
this->block_idx_ = bn;
this->position_ = pos;
if ((i < top_block_size) && blk_root[i])
--i;
continue;
}
if ((bm::word_t*)blk_blk == FULL_BLOCK_FAKE_ADDR)
blk_blk = FULL_SUB_BLOCK_REAL_ADDR;
block_idx_type j = this->block_idx_ & bm::set_array_mask;
for(; j < bm::set_sub_array_size; ++j, ++(this->block_idx_))
{
this->block_ = blk_blk[j];
if (this->block_ == 0)
{
this->position_ += bm::bits_in_block;
continue;
}
this->block_type_ = BM_IS_GAP(this->block_);
if (this->block_type_)
{
if (search_in_gapblock())
return true;
}
else
{
if (this->block_ == FULL_BLOCK_FAKE_ADDR)
this->block_ = FULL_BLOCK_REAL_ADDR;
if (search_in_bitblock())
return true;
}
} // for j
} // for i
return false;
}
//---------------------------------------------------------------------
} // namespace
#ifdef _MSC_VER
#pragma warning( pop )
#endif
#endif
BM_BORDER_TEST
#define BM_BORDER_TEST(blk, idx)
Definition bm.h:2649
BM_SUB_OP
#define BM_SUB_OP(x)
Definition bm.h:6680
BM_XOR_OP
#define BM_XOR_OP(x)
Definition bm.h:6492
BM_AND_OP
#define BM_AND_OP(x)
Definition bm.h:6585
BM_OR_OP
#define BM_OR_OP(x)
Definition bm.h:6419
BM_DECLARE_TEMP_BLOCK
#define BM_DECLARE_TEMP_BLOCK(x)
Definition bm.h:47
bmalloc.h
Default SIMD friendly allocator.
VECT_XOR_ARR_2_MASK
#define VECT_XOR_ARR_2_MASK(dst, src, src_end, mask)
Definition bmavx2.h:3432
bmconst.h
Constants, lookup tables and typedefs.
bmdef.h
Definitions(internal).
IS_FULL_BLOCK
#define IS_FULL_BLOCK(addr)
Definition bmdef.h:162
IS_VALID_ADDR
#define IS_VALID_ADDR(addr)
Definition bmdef.h:161
BMRESTRICT
#define BMRESTRICT
Definition bmdef.h:203
BMNOEXCEPT
#define BMNOEXCEPT
Definition bmdef.h:82
BMGAP_PTR
#define BMGAP_PTR(ptr)
Definition bmdef.h:189
BM_IS_GAP
#define BM_IS_GAP(ptr)
Definition bmdef.h:191
BMSET_PTRGAP
#define BMSET_PTRGAP(ptr)
Definition bmdef.h:190
BLOCK_ADDR_SAN
#define BLOCK_ADDR_SAN(addr)
Definition bmdef.h:160
BM_ASSERT
#define BM_ASSERT
Definition bmdef.h:139
BM_ASSERT_THROW
#define BM_ASSERT_THROW(x, xerrcode)
Definition bmdef.h:338
FULL_BLOCK_FAKE_ADDR
#define FULL_BLOCK_FAKE_ADDR
Definition bmdef.h:158
FULL_SUB_BLOCK_REAL_ADDR
#define FULL_SUB_BLOCK_REAL_ADDR
Definition bmdef.h:159
FULL_BLOCK_REAL_ADDR
#define FULL_BLOCK_REAL_ADDR
Definition bmdef.h:157
bmfunc.h
Bit manipulation primitives (internal).
bmsimd.h
SIMD target version definitions.
bm::bvector::bulk_insert_iterator::bulk_insert_iterator
bulk_insert_iterator(const insert_iterator &iit)
Definition bm.h:506
bm::bvector::bulk_insert_iterator::flush
void flush()
Definition bm.h:566
bm::bvector::bulk_insert_iterator::operator=
bulk_insert_iterator & operator=(bulk_insert_iterator &&ii) BMNOEXCEPT
Definition bm.h:533
bm::bvector::bulk_insert_iterator::buf_
size_type * buf_
bulk insert buffer
Definition bm.h:592
bm::bvector::bulk_insert_iterator::~bulk_insert_iterator
~bulk_insert_iterator()
Definition bm.h:480
bm::bvector::bulk_insert_iterator::get_bvector
bvector_type * get_bvector() const BMNOEXCEPT
Definition bm.h:577
bm::bvector::bulk_insert_iterator::sorted_
bm::sort_order sorted_
sort order hint
Definition bm.h:594
bm::bvector::bulk_insert_iterator::bulk_insert_iterator
bulk_insert_iterator(const bulk_insert_iterator &iit)
Definition bm.h:497
bm::bvector::bulk_insert_iterator::bulk_insert_iterator
bulk_insert_iterator(bulk_insert_iterator &&iit) BMNOEXCEPT
Definition bm.h:514
bm::bvector::bulk_insert_iterator::buf_size_max
static size_type buf_size_max() BMNOEXCEPT
Definition bm.h:581
bm::bvector::bulk_insert_iterator::operator++
bulk_insert_iterator & operator++(int)
Definition bm.h:563
bm::bvector::bulk_insert_iterator::size_type
bvector_type::size_type size_type
Definition bm.h:471
bm::bvector::bulk_insert_iterator::buf_size_
size_type buf_size_
current buffer size
Definition bm.h:593
bm::bvector::bulk_insert_iterator::iterator_category
std::output_iterator_tag iterator_category
Definition bm.h:468
bm::bvector::bulk_insert_iterator::bvect_
bvector_type * bvect_
target bvector
Definition bm.h:591
bm::bvector::bulk_insert_iterator::operator++
bulk_insert_iterator & operator++()
Definition bm.h:561
bm::bvector::bulk_insert_iterator::reference
void reference
Definition bm.h:475
bm::bvector::bulk_insert_iterator::bulk_insert_iterator
bulk_insert_iterator(bvector< Alloc > &bvect, bm::sort_order so=BM_UNKNOWN) BMNOEXCEPT
Definition bm.h:487
bm::bvector::bulk_insert_iterator::operator=
bulk_insert_iterator & operator=(const bulk_insert_iterator &ii)
Definition bm.h:522
bm::bvector::bulk_insert_iterator::value_type
bvector_type::size_type value_type
Definition bm.h:472
bm::bvector::bulk_insert_iterator::bulk_insert_iterator
bulk_insert_iterator() BMNOEXCEPT
Definition bm.h:477
bm::bvector::bulk_insert_iterator::difference_type
void difference_type
Definition bm.h:473
bm::bvector::bulk_insert_iterator::pointer
void pointer
Definition bm.h:474
bm::bvector::bulk_insert_iterator::bvector_type
bm::bvector< Alloc > bvector_type
Definition bm.h:470
bm::bvector::bulk_insert_iterator::operator=
bulk_insert_iterator & operator=(size_type n)
Definition bm.h:544
bm::bvector::bulk_insert_iterator::operator*
bulk_insert_iterator & operator*()
Definition bm.h:559
bm::bvector::counted_enumerator
Constant iterator designed to enumerate "ON" bits counted_enumerator keeps bitcount,...
Definition bm.h:734
bm::bvector::counted_enumerator::operator=
counted_enumerator & operator=(const enumerator &en) BMNOEXCEPT
Definition bm.h:746
bm::bvector::counted_enumerator::counted_enumerator
counted_enumerator(const enumerator &en) BMNOEXCEPT
Definition bm.h:741
bm::bvector::counted_enumerator::count
size_type count() const BMNOEXCEPT
Number of bits ON starting from the .
Definition bm.h:775
bm::bvector::counted_enumerator::counted_enumerator
counted_enumerator() BMNOEXCEPT
Definition bm.h:739
bm::bvector::counted_enumerator::operator++
counted_enumerator operator++(int)
Definition bm.h:762
bm::bvector::counted_enumerator::iterator_category
std::input_iterator_tag iterator_category
Definition bm.h:737
bm::bvector::counted_enumerator::operator++
counted_enumerator & operator++() BMNOEXCEPT
Definition bm.h:755
bm::bvector::enumerator::reference
unsigned & reference
Definition bm.h:611
bm::bvector::enumerator::iterator_category
std::input_iterator_tag iterator_category
Definition bm.h:606
bm::bvector::enumerator::enumerator
enumerator(const bvector< Alloc > &bv, size_type pos=0) BMNOEXCEPT
Construct enumerator for bit vector.
Definition bm.h:634
bm::bvector::enumerator::go_first
void go_first() BMNOEXCEPT
Position enumerator to the first available bit.
Definition bm.h:8301
bm::bvector::enumerator::value
size_type value() const BMNOEXCEPT
Get current position (value).
Definition bm.h:659
bm::bvector::enumerator::operator*
size_type operator*() const BMNOEXCEPT
Get current position (value).
Definition bm.h:656
bm::bvector::enumerator::operator++
enumerator operator++(int) BMNOEXCEPT
Advance enumerator forward to the next available bit. Possibly do NOT use this operator it is slower ...
Definition bm.h:667
bm::bvector::enumerator::operator++
enumerator & operator++() BMNOEXCEPT
Advance enumerator forward to the next available bit.
Definition bm.h:662
bm::bvector::enumerator::go_to
bool go_to(size_type pos) BMNOEXCEPT
go to a specific position in the bit-vector (or next)
Definition bm.h:8209
bm::bvector::enumerator::enumerator
enumerator(const bvector< Alloc > *bv) BMNOEXCEPT
Construct enumerator associated with a vector. Important: This construction creates unpositioned iter...
Definition bm.h:622
bm::bvector::enumerator::enumerator
enumerator() BMNOEXCEPT
Definition bm.h:614
bm::bvector::enumerator::difference_type
unsigned difference_type
Definition bm.h:609
bm::bvector::enumerator::value_type
size_type value_type
Definition bm.h:608
bm::bvector::enumerator::pointer
unsigned * pointer
Definition bm.h:610
bm::bvector::enumerator::skip
bool skip(size_type rank) BMNOEXCEPT
Skip specified number of bits from enumeration.
Definition bm.h:8136
bm::bvector::enumerator::go_up
bool go_up() BMNOEXCEPT
Advance enumerator to the next available bit.
Definition bm.h:8083
bm::bvector::enumerator::skip_to_rank
bool skip_to_rank(size_type rank) BMNOEXCEPT
Skip to specified relative rank.
Definition bm.h:690
bm::bvector::enumerator::advance
bool advance() BMNOEXCEPT
Definition bm.h:680
bm::bvector::enumerator::enumerator
enumerator(const bvector< Alloc > *bv, size_type pos) BMNOEXCEPT
Construct enumerator for bit vector.
Definition bm.h:648
bm::bvector::insert_iterator
Output iterator iterator designed to set "ON" bits based on input sequence of integers (bit indeces).
Definition bm.h:381
bm::bvector::insert_iterator::operator*
insert_iterator & operator*()
Definition bm.h:432
bm::bvector::insert_iterator::operator++
insert_iterator & operator++(int)
Definition bm.h:436
bm::bvector::insert_iterator::get_bvector
bvector_type * get_bvector() const
Definition bm.h:438
bm::bvector::insert_iterator::pointer
void pointer
Definition bm.h:390
bm::bvector::insert_iterator::insert_iterator
insert_iterator(const insert_iterator &iit)
Definition bm.h:402
bm::bvector::insert_iterator::insert_iterator
insert_iterator(bvector< Alloc > &bvect) BMNOEXCEPT
Definition bm.h:395
bm::bvector::insert_iterator::insert_iterator
insert_iterator() BMNOEXCEPT
Definition bm.h:393
bm::bvector::insert_iterator::bvect_
bvector_type * bvect_
Definition bm.h:441
bm::bvector::insert_iterator::bulk_insert_iterator
friend class bulk_insert_iterator
Definition bm.h:382
bm::bvector::insert_iterator::difference_type
void difference_type
Definition bm.h:389
bm::bvector::insert_iterator::max_bit_
size_type max_bit_
Definition bm.h:442
bm::bvector::insert_iterator::operator++
insert_iterator & operator++()
Definition bm.h:434
bm::bvector::insert_iterator::bvector_type
bm::bvector< Alloc > bvector_type
Definition bm.h:387
bm::bvector::insert_iterator::operator=
insert_iterator & operator=(const insert_iterator &ii)
Definition bm.h:408
bm::bvector::insert_iterator::operator=
insert_iterator & operator=(size_type n)
Definition bm.h:414
bm::bvector::insert_iterator::iterator_category
std::output_iterator_tag iterator_category
Definition bm.h:385
bm::bvector::insert_iterator::value_type
size_type value_type
Definition bm.h:388
bm::bvector::insert_iterator::reference
void reference
Definition bm.h:391
bm::bvector::iterator_base::position_
size_type position_
Bit position (bit idx).
Definition bm.h:350
bm::bvector::iterator_base::iterator_base
iterator_base() BMNOEXCEPT
Definition bm.h:243
bm::bvector::iterator_base::valid
bool valid() const BMNOEXCEPT
Checks if iterator is still valid.
Definition bm.h:283
bm::bvector::iterator_base::operator!=
bool operator!=(const iterator_base &it) const BMNOEXCEPT
Definition bm.h:253
bm::bvector::iterator_base::bvector
friend class bvector
Definition bm.h:241
bm::bvector::iterator_base::block_type_
unsigned block_type_
Type of block. 0-Bit, 1-GAP.
Definition bm.h:352
bm::bvector::iterator_base::compare_state
bool compare_state(const iterator_base &ib) const BMNOEXCEPT
Compare FSMs for testing purposes.
Definition bm.h:295
bm::bvector::iterator_base::bdescr_
union bm::bvector::iterator_base::block_descr bdescr_
bm::bvector::iterator_base::invalidate
void invalidate() BMNOEXCEPT
Turns iterator into an invalid state.
Definition bm.h:289
bm::bvector::iterator_base::operator<
bool operator<(const iterator_base &it) const BMNOEXCEPT
Definition bm.h:258
bm::bvector::iterator_base::bv_
bm::bvector< Alloc > * bv_
Pointer on parent bitvector.
Definition bm.h:349
bm::bvector::iterator_base::operator==
bool operator==(const iterator_base &it) const BMNOEXCEPT
Definition bm.h:248
bm::bvector::iterator_base::block_
const bm::word_t * block_
Block pointer.(NULL-invalid).
Definition bm.h:351
bm::bvector::iterator_base::operator>=
bool operator>=(const iterator_base &it) const BMNOEXCEPT
Definition bm.h:273
bm::bvector::iterator_base::operator>
bool operator>(const iterator_base &it) const BMNOEXCEPT
Definition bm.h:268
bm::bvector::iterator_base::operator<=
bool operator<=(const iterator_base &it) const BMNOEXCEPT
Definition bm.h:263
bm::bvector::iterator_base::block_idx_
block_idx_type block_idx_
Block index.
Definition bm.h:353
bm::bvector::reference::operator==
bool operator==(const reference &ref) const BMNOEXCEPT
Definition bm.h:180
bm::bvector::reference::operator~
bool operator~() const BMNOEXCEPT
Definition bm.h:216
bm::bvector::reference::operator|=
const reference & operator|=(bool value) const
Definition bm.h:193
bm::bvector::reference::operator=
const reference & operator=(const reference &ref) const
Definition bm.h:168
bm::bvector::reference::operator^=
const reference & operator^=(bool value) const
Definition bm.h:203
bm::bvector::reference::operator=
const reference & operator=(bool value) const BMNOEXCEPT
Definition bm.h:174
bm::bvector::reference::operator&=
const reference & operator&=(bool value) const
Definition bm.h:186
bm::bvector::reference::reference
reference(const reference &ref) BMNOEXCEPT
Definition bm.h:156
bm::bvector::reference::operator!
bool operator!() const BMNOEXCEPT
Definition bm.h:210
bm::bvector::reference::flip
reference & flip()
Definition bm.h:222
bm::bvector::reference::reference
reference(bvector< Alloc > &bv, size_type position) BMNOEXCEPT
Definition bm.h:151
bm::bvector
Bitvector Bit-vector container with runtime compression of bits.
Definition bm.h:115
bm::bvector::bit_or
bm::bvector< Alloc > & bit_or(const bm::bvector< Alloc > &bv1, const bm::bvector< Alloc > &bv2, typename bm::bvector< Alloc >::optmode opt_mode=opt_none)
3-operand OR : this := bv1 OR bv2
Definition bm.h:5906
bm::bvector::import_block
void import_block(const size_type *ids, block_idx_type nblock, size_type start, size_type stop)
Definition bm.h:4363
bm::bvector::const_reference
bool const_reference
Definition bm.h:233
bm::bvector::optmode
optmode
Optimization mode Every next level means additional checks (better compression vs time).
Definition bm.h:133
bm::bvector< dbg_alloc >::opt_compress
@ opt_compress
Definition bm.h:137
bm::bvector< dbg_alloc >::opt_free_01
@ opt_free_01
Definition bm.h:136
bm::bvector< dbg_alloc >::opt_free_0
@ opt_free_0
Definition bm.h:135
bm::bvector< dbg_alloc >::opt_none
@ opt_none
Definition bm.h:134
bm::bvector::find
bool find(size_type &pos) const BMNOEXCEPT
Finds index of first 1 bit.
Definition bm.h:5093
bm::bvector::swap
void swap(size_type idx1, size_type idx2)
swap values of bits
Definition bm.h:4406
bm::bvector::operator=
bvector & operator=(bvector< Alloc > &&bvect) BMNOEXCEPT
Move assignment operator.
Definition bm.h:965
bm::bvector::bvector
bvector(const bvector< Alloc > &bvect, bm::finalization is_final)
Copy-constructor for mutable/immutable initialization.
Definition bm.h:892
bm::bvector::bit_and
bm::bvector< Alloc > & bit_and(const bm::bvector< Alloc > &bv, optmode opt_mode=opt_none)
2 operand logical AND
Definition bm.h:1802
bm::bvector::operator&=
void operator&=(const bvector< Alloc > &bv)
Definition bm.h:1020
bm::bvector< dbg_alloc >::deserializer
friend class deserializer
Definition bm.h:796
bm::bvector::combine_operation_block_and_or
bool combine_operation_block_and_or(unsigned i, unsigned j, const bm::word_t *arg_blk1, const bm::word_t *arg_blk2)
Definition bm.h:7112
bm::bvector::set_gap_levels
void set_gap_levels(const gap_word_t *glevel_len)
Sets new GAP lengths table. All GAP blocks will be reallocated to match the new scheme.
Definition bm.h:3726
bm::bvector::bvector
bvector(strategy strat=BM_BIT, const gap_word_t *glevel_len=bm::gap_len_table< true >::_len, size_type bv_size=bm::id_max, const Alloc &alloc=Alloc())
Constructs bvector class.
Definition bm.h:843
bm::bvector::test
bool test(size_type n) const BMNOEXCEPT
returns true if bit n is set and false is bit n is 0.
Definition bm.h:1502
bm::bvector::get_allocator_pool
allocator_pool_type * get_allocator_pool() BMNOEXCEPT
Get curent allocator pool (if set).
Definition bm.h:1045
bm::bvector::bvector
bvector(bvector< Alloc > &&bvect) BMNOEXCEPT
Move constructor.
Definition bm.h:940
bm::bvector::combine_operation_with_block
void combine_operation_with_block(block_idx_type nb, bool gap, bm::word_t *blk, const bm::word_t *arg_blk, bool arg_gap, bm::operation opcode)
Definition bm.h:7654
bm::bvector::merge
void merge(bm::bvector< Alloc > &bvect)
Merge/move content from another vector.
Definition bm.h:5816
bm::bvector::equal
bool equal(const bvector< Alloc > &bvect) const BMNOEXCEPT
Equal comparison with an agr bit-vector.
Definition bm.h:2017
bm::bvector::clear_range_no_check
void clear_range_no_check(size_type left, size_type right)
Clear range without validity/bounds checking.
Definition bm.h:7904
bm::bvector< dbg_alloc >::aggregator
friend class aggregator
Definition bm.h:794
bm::bvector::invert
bvector< Alloc > & invert()
Invert/NEG all bits It should be noted, invert is affected by size() if size is set - it only inverts...
Definition bm.h:3550
bm::bvector::combine_operation_block_or
void combine_operation_block_or(unsigned i, unsigned j, bm::word_t *blk, const bm::word_t *arg_blk)
Definition bm.h:7286
bm::bvector::set_bit_and
bool set_bit_and(size_type n, bool val=true)
Sets bit n using bit AND with the provided value.
Definition bm.h:4213
bm::bvector::allocator_pool_type
allocator_type::allocator_pool_type allocator_pool_type
Definition bm.h:118
bm::bvector::init
void init(unsigned top_size, bool alloc_subs)
Explicit post-construction initialization. Must be caled right after construction strickly before any...
Definition bm.h:2289
bm::bvector::size
size_type size() const BMNOEXCEPT
Returns bvector's capacity (number of bits it can store).
Definition bm.h:1300
bm::bvector::count
size_type count() const BMNOEXCEPT
population count (count of ON bits)
Definition bm.h:2401
bm::bvector::combine_operation_xor
void combine_operation_xor(const bm::bvector< Alloc > &bvect)
perform a set-algebra operation XOR
Definition bm.h:6499
bm::bvector::set_bit_conditional_impl
bool set_bit_conditional_impl(size_type n, bool val, bool condition)
Definition bm.h:4784
bm::bvector::clear_bit
bool clear_bit(size_type n)
Clears bit n.
Definition bm.h:1247
bm::bvector::operator[]
bool operator[](size_type n) const BMNOEXCEPT
Definition bm.h:1014
bm::bvector::is_init
bool is_init() const BMNOEXCEPT
Return true if bvector is initialized at all.
Definition bm.h:1983
bm::bvector::bit_and
bm::bvector< Alloc > & bit_and(const bm::bvector< Alloc > &bv1, const bm::bvector< Alloc > &bv2, typename bm::bvector< Alloc >::optmode opt_mode=opt_none)
3-operand AND : this := bv1 AND bv2
Definition bm.h:6118
bm::bvector::throw_bad_alloc
static void throw_bad_alloc()
Definition bm.h:8069
bm::bvector::insert
bool insert(size_type n, bool value)
Insert bit into specified position All the vector content after insert position is shifted right.
Definition bm.h:5443
bm::bvector::combine_operation_block_or
bool combine_operation_block_or(unsigned i, unsigned j, const bm::word_t *arg_blk1, const bm::word_t *arg_blk2)
Definition bm.h:6872
bm::bvector::bit_or
bm::bvector< Alloc > & bit_or(const bm::bvector< Alloc > &bv)
2 operand logical OR
Definition bm.h:1790
bm::bvector::operator~
bvector< Alloc > operator~() const
Definition bm.h:1032
bm::bvector::sync_size
void sync_size()
Syncronize size if it got extended due to bulk import.
Definition bm.h:2486
bm::bvector::clear
void clear(bool free_mem=true) BMNOEXCEPT
Clears every bit in the bitvector.
Definition bm.h:4135
bm::bvector::find_range
bool find_range(size_type &first, size_type &last) const BMNOEXCEPT
Finds dynamic range of bit-vector [first, last].
Definition bm.h:5139
bm::bvector::check_or_next_extract
size_type check_or_next_extract(size_type prev)
check if specified bit is 1, and set it to 0 if specified bit is 0, scan for the next 1 and returns i...
Definition bm.h:5408
bm::bvector::set
bvector< Alloc > & set(size_type n, bool val=true)
Sets bit n if val is true, clears bit n if val is false.
Definition bm.h:4188
bm::bvector< dbg_alloc >::any_range
bool any_range(size_type left, size_type right) const BMNOEXCEPT
bm::bvector< dbg_alloc >::reset
bvector< dbg_alloc > & reset() BMNOEXCEPT
Definition bm.h:1267
bm::bvector::resize
void resize(size_type new_size)
Change size of the bvector.
Definition bm.h:2463
bm::bvector::check_or_next
size_type check_or_next(size_type prev) const BMNOEXCEPT
Definition bm.h:5324
bm::bvector::operator[]
reference operator[](size_type n)
Definition bm.h:1004
bm::bvector::bit_sub
bm::bvector< Alloc > & bit_sub(const bm::bvector< Alloc > &bv1, const bm::bvector< Alloc > &bv2, typename bm::bvector< Alloc >::optmode opt_mode=opt_none)
3-operand SUB : this := bv1 MINUS bv2 SUBtraction is also known as AND NOT
Definition bm.h:6330
bm::bvector::set_allocator_pool
void set_allocator_pool(allocator_pool_type *pool_ptr) BMNOEXCEPT
Set allocator pool for local (non-th readed) memory cyclic(lots of alloc-free ops) opertations.
Definition bm.h:1040
bm::bvector::extract_next
size_type extract_next(size_type prev)
Finds the number of the next bit ON and sets it to 0.
Definition bm.h:1619
bm::bvector::bvector
bvector(const bvector< Alloc > &bvect)
Copy constructor.
Definition bm.h:867
bm::bvector::get_new_blocks_strat
strategy get_new_blocks_strat() const BMNOEXCEPT
Returns blocks allocation strategy.
Definition bm.h:1920
bm::bvector::optimize
void optimize(bm::word_t *temp_block=0, optmode opt_mode=opt_compress, statistics *stat=0)
Optimize memory bitvector's memory allocation.
Definition bm.h:3635
bm::bvector::forget_count
void forget_count() BMNOEXCEPT
Definition bm.h:1482
bm::bvector::count_to_test
size_type count_to_test(size_type n, const rs_index_type &rs_idx) const BMNOEXCEPT
popcount in [0..right] range if test(right) == true
Definition bm.h:3141
bm::bvector::set_new_blocks_strat
void set_new_blocks_strat(strategy strat)
Sets new blocks allocation strategy.
Definition bm.h:1912
bm::bvector::find_reverse
bool find_reverse(size_type from, size_type &pos) const BMNOEXCEPT
Reverse finds next(prev) index of 1 bit.
Definition bm.h:4968
bm::bvector::rank
size_type rank(size_type n, const rs_index_type &rs_idx) const BMNOEXCEPT
Returns rank of specified bit position (same as count_to()).
Definition bm.h:1433
bm::bvector::bvector
bvector(std::initializer_list< size_type > il)
Brace constructor.
Definition bm.h:950
bm::bvector::flip
bvector< Alloc > & flip()
Flips all bits.
Definition bm.h:1280
bm::bvector::fill_alloc_digest
void fill_alloc_digest(bvector< Alloc > &bv_blocks) const
Calculate blocks digest vector (for diagnostics purposes) 1 is added if NB is a real,...
Definition bm.h:4058
bm::bvector::any
bool any() const BMNOEXCEPT
Returns true if any bits in this bitset are set, and otherwise returns false.
Definition bm.h:2451
bm::bvector< dbg_alloc >::operation_deserializer
friend class operation_deserializer
Definition bm.h:795
bm::bvector::set_bit
bool set_bit(size_type n, bool val=true)
Sets bit n.
Definition bm.h:4227
bm::bvector::inserter
insert_iterator inserter()
Definition bm.h:1287
bm::bvector::blocks_manager_type
blocks_manager< Alloc > blocks_manager_type
Definition bm.h:119
bm::bvector::enumerator
friend class enumerator
Definition bm.h:793
bm::bvector::empty
bool empty() const BMNOEXCEPT
Returns true if the set is empty (no bits are set, otherwise returns false) Please note that this is ...
Definition bm.h:1562
bm::bvector::keep_range
void keep_range(size_type left, size_type right)
Sets all bits to zero outside of the closed interval [left,right] Expected result: 00000....
Definition bm.h:2353
bm::bvector::combine_operation_block_sub
void combine_operation_block_sub(unsigned i, unsigned j, bm::word_t *blk, const bm::word_t *arg_blk)
Definition bm.h:7573
bm::bvector::get_blocks_manager
const blocks_manager_type & get_blocks_manager() const BMNOEXCEPT
get access to memory manager (internal) Use only if you are BitMagic library
Definition bm.h:2058
bm::bvector::operator-=
void operator-=(const bvector< Alloc > &bv)
Definition bm.h:1023
bm::bvector< dbg_alloc >::is_all_one_range
bool is_all_one_range(size_type left, size_type right) const BMNOEXCEPT
bm::bvector::select
bool select(size_type rank, size_type &pos, const rs_index_type &rs_idx) const BMNOEXCEPT
select bit-vector position for the specified rank(bitcount)
Definition bm.h:5283
bm::bvector::get_allocator
Alloc get_allocator() const
Definition bm.h:1034
bm::bvector::and_bit_no_check
bool and_bit_no_check(size_type n, bool val)
AND specified bit without checking preconditions (size, etc).
Definition bm.h:4836
bm::bvector::size_type
bvector_size_type size_type
Definition bm.h:121
bm::bvector::get_next
size_type get_next(size_type prev) const BMNOEXCEPT
Finds the number of the next bit ON.
Definition bm.h:1609
bm::bvector::clear_range
void clear_range(size_type left, size_type right)
Sets all bits to zero in the specified closed interval [left,right] Interval must be inside the bvect...
Definition bm.h:1216
bm::bvector::combine_operation_block_and
bool combine_operation_block_and(unsigned i, unsigned j, const bm::word_t *arg_blk1, const bm::word_t *arg_blk2)
Definition bm.h:7027
bm::bvector::combine_operation_and
void combine_operation_and(const bm::bvector< Alloc > &bvect, optmode opt_mode)
perform a set-algebra operation AND
Definition bm.h:6598
bm::bvector::find_first_mismatch
bool find_first_mismatch(const bvector< Alloc > &bvect, size_type &pos, size_type search_to=bm::id_max) const BMNOEXCEPT
Find index of first bit different between this and the agr vector.
Definition bm.h:3862
bm::bvector< dbg_alloc >::first
enumerator first() const
Definition bm.h:1871
bm::bvector::combine_operation_block_sub
bool combine_operation_block_sub(unsigned i, unsigned j, const bm::word_t *arg_blk1, const bm::word_t *arg_blk2)
Definition bm.h:7212
bm::bvector::combine_operation_block_xor
bool combine_operation_block_xor(unsigned i, unsigned j, const bm::word_t *arg_blk1, const bm::word_t *arg_blk2)
Definition bm.h:6945
bm::bvector::set
bvector< Alloc > & set()
Sets every bit in this bitset to 1.
Definition bm.h:4177
bm::bvector::shift_left
bool shift_left()
Shift left by 1 bit, fill with zero return carry out.
Definition bm.h:5432
bm::bvector::swap
void swap(bvector< Alloc > &bvect) BMNOEXCEPT
Exchanges content of bv and this bvector.
Definition bm.h:3966
bm::bvector< dbg_alloc >::count_range
size_type count_range(size_type left, size_type right, const rs_index_type &rs_idx) const BMNOEXCEPT
bm::bvector::freeze
void freeze()
Turn current vector to read-only (immutable vector).
Definition bm.h:8058
bm::bvector::find_rank
bool find_rank(size_type rank, size_type from, size_type &pos) const BMNOEXCEPT
Find bit-vector position for the specified rank(bitcount).
Definition bm.h:5159
bm::bvector::combine_operation_block_xor
void combine_operation_block_xor(unsigned i, unsigned j, bm::word_t *blk, const bm::word_t *arg_blk)
Definition bm.h:7365
bm::bvector::optimize_gap_size
void optimize_gap_size()
Optimize sizes of GAP blocks.
Definition bm.h:3700
bm::bvector::set_bit_no_check
bool set_bit_no_check(size_type n, bool val)
Set specified bit without checking preconditions (size, etc).
Definition bm.h:4597
bm::bvector::init
void init()
Explicit post-construction initialization. Must be caled to make sure safe use of *_no_check() method...
Definition bm.h:2280
bm::bvector::shift_right
bool shift_right()
Shift right by 1 bit, fill with zero return carry out.
Definition bm.h:5423
bm::bvector::find_rank
bool find_rank(size_type rank, size_type from, size_type &pos, const rs_index_type &rs_idx) const BMNOEXCEPT
Find bit-vector position for the specified rank(bitcount).
Definition bm.h:5212
bm::bvector::set_range
bvector< Alloc > & set_range(size_type left, size_type right, bool value=true)
Sets all bits in the specified closed interval [left,right] Interval must be inside the bvector's siz...
Definition bm.h:2368
bm::bvector::erase
void erase(size_type n)
Erase bit in the specified position All the vector content after erase position is shifted left.
Definition bm.h:5646
bm::bvector::get_first
size_type get_first() const BMNOEXCEPT
find first 1 bit in vector. Function may return 0 and this requires an extra check if bit 0 is actual...
Definition bm.h:1600
bm::bvector::set
void set(const size_type *ids, size_type ids_size, bm::sort_order so=bm::BM_UNKNOWN)
Set list of bits in this bitset to 1.
Definition bm.h:4088
bm::bvector::copy_range
void copy_range(const bvector< Alloc > &bvect, size_type left, size_type right)
Copy all bits in the specified closed interval [left,right].
Definition bm.h:7981
bm::bvector::is_ro
bool is_ro() const BMNOEXCEPT
Returns true if vector is read-only.
Definition bm.h:1060
bm::bvector::bit_xor
bm::bvector< Alloc > & bit_xor(const bm::bvector< Alloc > &bv)
2 operand logical XOR
Definition bm.h:1814
bm::bvector::get_enumerator
enumerator get_enumerator(size_type pos) const
Returns enumerator pointing on specified or the next available bit.
Definition bm.h:1883
bm::bvector::bit_sub
bm::bvector< Alloc > & bit_sub(const bm::bvector< Alloc > &bv)
2 operand logical SUB(AND NOT). Also known as MINUS.
Definition bm.h:1825
bm::bvector::rank_corrected
size_type rank_corrected(size_type n, const rs_index_type &rs_idx) const BMNOEXCEPT
Returns rank corrceted by the requested border value (as -1).
Definition bm.h:3197
bm::bvector::import
void import(const size_type *ids, size_type ids_size, bm::sort_order sorted_idx)
Import integers (set bits).
Definition bm.h:4245
bm::bvector::operator=
bvector & operator=(const bvector< Alloc > &bvect)
Copy assignment operator.
Definition bm.h:930
bm::bvector::copy_range_no_check
void copy_range_no_check(const bvector< Alloc > &bvect, size_type left, size_type right)
Definition bm.h:8026
bm::bvector::combine_operation_or
void combine_operation_or(const bm::bvector< Alloc > &bvect)
perform a set-algebra operation OR
Definition bm.h:6427
bm::bvector::block_idx_type
blocks_manager_type::block_idx_type block_idx_type
Definition bm.h:120
bm::bvector::copy
void copy(const bvector< Alloc > &bvect, bm::finalization is_final)
Copy bvector from the argument bvector.
Definition bm.h:2303
bm::bvector::combine_operation_block_and
void combine_operation_block_and(unsigned i, unsigned j, bm::word_t *blk, const bm::word_t *arg_blk)
Definition bm.h:7469
bm::bvector::operator^=
void operator^=(const bvector< Alloc > &bv)
Definition bm.h:1021
bm::bvector::operator|=
void operator|=(const bvector< Alloc > &bv)
Definition bm.h:1022
bm::bvector::flip
bvector< Alloc > & flip(size_type n)
Flips bit n.
Definition bm.h:1273
bm::bvector::clear
void clear(const size_type *ids, size_type ids_size, bm::sort_order so=bm::BM_UNKNOWN)
clear list of bits in this bitset
Definition bm.h:4149
bm::bvector::import_sorted
void import_sorted(const size_type *ids, const size_type ids_size, bool opt_flag)
Import sorted integers (set bits).
Definition bm.h:4297
bm::bvector::optimize_range
void optimize_range(size_type left, size_type right, bm::word_t *temp_block, optmode opt_mode=opt_compress)
Definition bm.h:3671
bm::bvector< dbg_alloc >::count_blocks
block_idx_type count_blocks(unsigned *arr) const BMNOEXCEPT
bm::bvector::rs_index_type
rs_index< allocator_type > rs_index_type
Definition bm.h:816
bm::bvector< dbg_alloc >::count_range_no_check
size_type count_range_no_check(size_type left, size_type right) const BMNOEXCEPT
bm::bvector::bvector
bvector(const bvector< Alloc > &bvect, size_type left, size_type right)
Copy constructor for range copy [left..right].
Definition bm.h:877
bm::bvector::combine_operation_sub
void combine_operation_sub(const bm::bvector< Alloc > &bvect)
perform a set-algebra operation MINUS (AND NOT)
Definition bm.h:6686
bm::bvector::compare
int compare(const bvector< Alloc > &bvect) const BMNOEXCEPT
Lexicographical comparison with a bitvector.
Definition bm.h:3744
bm::bvector::allocator_type
Alloc allocator_type
Definition bm.h:117
bm::bvector::get_blocks_manager
blocks_manager_type & get_blocks_manager() BMNOEXCEPT
get access to memory manager (internal) Use only if you are BitMagic library
Definition bm.h:2066
bm::bvector< dbg_alloc >::count_to
size_type count_to(size_type n, const rs_index_type &rs_idx) const BMNOEXCEPT
bm::bvector::blocks_count
rs_index< allocator_type > blocks_count
Definition bm.h:815
bm::bvector< dbg_alloc >::none
bool none() const BMNOEXCEPT
Definition bm.h:1556
bm::bvector::set_bit_conditional
bool set_bit_conditional(size_type n, bool val, bool condition)
Sets bit n only if current value equals the condition.
Definition bm.h:4199
bm::bvector::find_reverse
bool find_reverse(size_type &pos) const BMNOEXCEPT
Finds last index of 1 bit.
Definition bm.h:4911
bm::bvector< dbg_alloc >::build_rs_index
void build_rs_index(rs_index_type *rs_idx, bvector< dbg_alloc > *bv_blocks=0) const
bm::bvector::combine_operation_with_block
void combine_operation_with_block(block_idx_type nb, const bm::word_t *arg_blk, bool arg_gap, bm::operation opcode)
Definition bm.h:5889
bm::bvector::clear_bit_no_check
void clear_bit_no_check(size_type n)
Clears bit n without precondiion checks.
Definition bm.h:4680
bm::bvector::~bvector
~bvector() BMNOEXCEPT
Definition bm.h:906
bm::bvector::gap_block_set_no_ret
void gap_block_set_no_ret(bm::gap_word_t *gap_blk, bool val, block_idx_type nblock, unsigned nbit)
set bit in GAP block with GAP block length control
Definition bm.h:4733
bm::bvector::bvector
bvector(size_type bv_size, strategy strat=BM_BIT, const gap_word_t *glevel_len=bm::gap_len_table< true >::_len, const Alloc &alloc=Alloc())
Constructs bvector class.
Definition bm.h:855
bm::bvector::combine_operation
void combine_operation(const bm::bvector< Alloc > &bvect, bm::operation opcode)
perform a set-algebra operation by operation code
Definition bm.h:6750
bm::bvector::keep
void keep(const size_type *ids, size_type ids_size, bm::sort_order so=bm::BM_UNKNOWN)
Keep list of bits in this bitset, others are cleared.
Definition bm.h:4105
bm::bvector::bit_or_and
bm::bvector< Alloc > & bit_or_and(const bm::bvector< Alloc > &bv1, const bm::bvector< Alloc > &bv2, typename bm::bvector< Alloc >::optmode opt_mode=opt_none)
3-operand AND where result is ORed into the terget vector : this |= bv1 AND bv2 TARGET := TARGET OR (...
Definition bm.h:6213
bm::bvector::end
enumerator end() const
Returns enumerator pointing on the next bit after the last.
Definition bm.h:1877
bm::bvector::get_bit
bool get_bit(size_type n) const BMNOEXCEPT
returns true if bit n is set and false is bit n is 0.
Definition bm.h:3602
bm::bvector::gap_block_set
bool gap_block_set(bm::gap_word_t *gap_blk, bool val, block_idx_type nblock, unsigned nbit)
set bit in GAP block with GAP block length control
Definition bm.h:4714
bm::bvector::calc_stat
void calc_stat(struct bm::bvector< Alloc >::statistics *st) const BMNOEXCEPT
Calculates bitvector statistics.
Definition bm.h:3978
bm::bvector::bit_xor
bm::bvector< Alloc > & bit_xor(const bm::bvector< Alloc > &bv1, const bm::bvector< Alloc > &bv2, typename bm::bvector< Alloc >::optmode opt_mode=opt_none)
3-operand XOR : this := bv1 XOR bv2
Definition bm.h:6005
bm::bvector::set_range_no_check
void set_range_no_check(size_type left, size_type right)
Set range without validity/bounds checking.
Definition bm.h:7830
bm::bvector::recalc_count
size_type recalc_count() BMNOEXCEPT
Definition bm.h:1477
bm::bvector::move_from
void move_from(bvector< Alloc > &bvect) BMNOEXCEPT
Move bvector content from another bvector.
Definition bm.h:2340
bm::bvector::find
bool find(size_type from, size_type &pos) const BMNOEXCEPT
Find index of 1 bit starting from position.
Definition bm.h:4896
bm::bvector::inc
bool inc(size_type n)
Increment the specified element.
Definition bm.h:4751
bm::bvector::set_bit_no_check
void set_bit_no_check(size_type n)
Set bit without checking preconditions (size, etc).
Definition bm.h:4646
encoding.h
Encoding utilities for serialization (internal).
bm::avx2_test_all_zero_wave
BMFORCEINLINE bool avx2_test_all_zero_wave(const void *ptr)
check if wave of pointers is all NULL
Definition bmavx2.h:1805
bm::avx2_test_all_zero_wave2
BMFORCEINLINE bool avx2_test_all_zero_wave2(const void *ptr0, const void *ptr1)
check if 2 wave of pointers are all NULL
Definition bmavx2.h:1816
bm::avx2_test_all_eq_wave2
BMFORCEINLINE bool avx2_test_all_eq_wave2(const void *ptr0, const void *ptr1)
check if 2 wave of pointers are all the same (NULL or FULL)
Definition bmavx2.h:1829
bm::sse42_test_all_eq_wave2
BMFORCEINLINE bool sse42_test_all_eq_wave2(const void *ptr0, const void *ptr1) BMNOEXCEPT
check if wave of 2 pointers are the same (null or FULL)
Definition bmsse4.h:934
bm::sse42_test_all_zero_wave
BMFORCEINLINE bool sse42_test_all_zero_wave(const void *ptr) BMNOEXCEPT
check if wave of pointers is all NULL
Definition bmsse4.h:910
bm::sse42_test_all_zero_wave2
BMFORCEINLINE bool sse42_test_all_zero_wave2(const void *ptr0, const void *ptr1) BMNOEXCEPT
check if 2 waves of pointers are all NULL
Definition bmsse4.h:921
bm::bit_block_find
unsigned bit_block_find(const bm::word_t *BMRESTRICT block, unsigned nbit, unsigned *BMRESTRICT pos) BMNOEXCEPT
Searches for the next 1 bit in the BIT block.
Definition bmfunc.h:8657
bm::bit_block_or_2way
bool bit_block_or_2way(bm::word_t *BMRESTRICT dst, const bm::word_t *BMRESTRICT src1, const bm::word_t *BMRESTRICT src2) BMNOEXCEPT
2 way (target := source1 | source2) bitblock OR operation.
Definition bmfunc.h:7872
bm::word_bitcount
BMFORCEINLINE bm::id_t word_bitcount(bm::id_t w) BMNOEXCEPT
Definition bmutil.h:582
bm::bit_block_copy
void bit_block_copy(bm::word_t *BMRESTRICT dst, const bm::word_t *BMRESTRICT src) BMNOEXCEPT
Bitblock copy operation.
Definition bmfunc.h:6777
bm::bit_block_sub_2way
bm::id64_t bit_block_sub_2way(bm::word_t *BMRESTRICT dst, const bm::word_t *BMRESTRICT src1, const bm::word_t *BMRESTRICT src2, bm::id64_t digest) BMNOEXCEPT
digest based bitblock SUB (AND NOT) operation (3 operand)
Definition bmfunc.h:8201
bm::bit_block_and
bm::id64_t bit_block_and(bm::word_t *BMRESTRICT dst, const bm::word_t *BMRESTRICT src) BMNOEXCEPT
Plain bitblock AND operation. Function does not analyse availability of source and destination blocks...
Definition bmfunc.h:6858
bm::bit_operation_xor
bm::word_t * bit_operation_xor(bm::word_t *BMRESTRICT dst, const bm::word_t *BMRESTRICT src) BMNOEXCEPT
bitblock XOR operation.
Definition bmfunc.h:8505
bm::bit_block_shift_r1_unr
bool bit_block_shift_r1_unr(bm::word_t *BMRESTRICT block, bm::word_t *BMRESTRICT empty_acc, bm::word_t co_flag) BMNOEXCEPT
Right bit-shift of bit-block by 1 bit (loop unrolled).
Definition bmfunc.h:5711
bm::word_bitcount64
BMFORCEINLINE unsigned word_bitcount64(bm::id64_t x) BMNOEXCEPT
Definition bmutil.h:605
bm::bit_block_calc_count_to
bm::id_t bit_block_calc_count_to(const bm::word_t *block, bm::word_t right) BMNOEXCEPT
Definition bmfunc.h:5476
bm::bit_block_erase
void bit_block_erase(bm::word_t *block, unsigned bitpos, bool carry_over) BMNOEXCEPT
erase bit from position and shift the rest right with carryover
Definition bmfunc.h:5834
bm::bit_operation_or
bm::word_t * bit_operation_or(bm::word_t *BMRESTRICT dst, const bm::word_t *BMRESTRICT src) BMNOEXCEPT
Block OR operation. Makes analysis if block is 0 or FULL.
Definition bmfunc.h:8045
bm::bit_block_shift_l1_unr
bool bit_block_shift_l1_unr(bm::word_t *block, bm::word_t *empty_acc, bm::word_t co_flag) BMNOEXCEPT
Left bit-shift of bit-block by 1 bit (loop unrolled).
Definition bmfunc.h:5811
bm::calc_block_digest0
bm::id64_t calc_block_digest0(const bm::word_t *const block) BMNOEXCEPT
Compute digest for 64 non-zero areas.
Definition bmfunc.h:1120
bm::bit_block_and_2way
bm::id64_t bit_block_and_2way(bm::word_t *BMRESTRICT dst, const bm::word_t *BMRESTRICT src1, const bm::word_t *BMRESTRICT src2, bm::id64_t digest) BMNOEXCEPT
digest based bit-block AND
Definition bmfunc.h:7076
bm::bit_operation_sub
bm::word_t * bit_operation_sub(bm::word_t *BMRESTRICT dst, const bm::word_t *BMRESTRICT src) BMNOEXCEPT
bitblock SUB operation.
Definition bmfunc.h:8376
bm::bitscan_wave
unsigned short bitscan_wave(const bm::word_t *BMRESTRICT w_ptr, unsigned char *BMRESTRICT bits) BMNOEXCEPT
Unpacks word wave (Nx 32-bit words).
Definition bmfunc.h:9635
bm::bit_find_first
bool bit_find_first(const bm::word_t *BMRESTRICT block, unsigned *BMRESTRICT pos) BMNOEXCEPT
BIT block find the first set bit.
Definition bmfunc.h:8742
bm::bit_invert
void bit_invert(T *start) BMNOEXCEPT
Definition bmfunc.h:6057
bm::bitcmp
int bitcmp(const T *buf1, const T *buf2, unsigned len) BMNOEXCEPT
Lexicographical comparison of BIT buffers.
Definition bmfunc.h:4700
bm::bit_block_and_or_2way
bm::id64_t bit_block_and_or_2way(bm::word_t *BMRESTRICT dst, const bm::word_t *BMRESTRICT src1, const bm::word_t *BMRESTRICT src2, bm::id64_t digest) BMNOEXCEPT
digest based bit-block AND - OR
Definition bmfunc.h:7210
bm::bit_block_xor
bm::id64_t bit_block_xor(bm::word_t *BMRESTRICT dst, const bm::word_t *BMRESTRICT src) BMNOEXCEPT
Plain bitblock XOR operation. Function does not analyse availability of source and destination blocks...
Definition bmfunc.h:8434
bm::bit_operation_and
bm::word_t * bit_operation_and(bm::word_t *BMRESTRICT dst, const bm::word_t *BMRESTRICT src) BMNOEXCEPT
bitblock AND operation.
Definition bmfunc.h:7578
bm::bit_block_set
void bit_block_set(bm::word_t *BMRESTRICT dst, bm::word_t value) BMNOEXCEPT
Bitblock memset operation.
Definition bmfunc.h:4456
bm::bit_block_or
bool bit_block_or(bm::word_t *BMRESTRICT dst, const bm::word_t *BMRESTRICT src) BMNOEXCEPT
Plain bitblock OR operation. Function does not analyse availability of source and destination blocks.
Definition bmfunc.h:7835
bm::bit_is_all_zero
bool bit_is_all_zero(const bm::word_t *BMRESTRICT start) BMNOEXCEPT
Returns "true" if all bits in the block are 0.
Definition bmfunc.h:1550
bm::bit_find_last
unsigned bit_find_last(const bm::word_t *BMRESTRICT block, unsigned *BMRESTRICT last) BMNOEXCEPT
BIT block find the last set bit (backward search).
Definition bmfunc.h:8708
bm::bit_block_calc_count_range
bm::id_t bit_block_calc_count_range(const bm::word_t *block, bm::word_t left, bm::word_t right) BMNOEXCEPT
Definition bmfunc.h:5390
bm::bit_andnot_arr_ffmask
void bit_andnot_arr_ffmask(bm::word_t *BMRESTRICT dst, const bm::word_t *BMRESTRICT src) BMNOEXCEPT
bitblock AND NOT with constant ~0 mask operation.
Definition bmfunc.h:8470
bm::bit_block_insert
bm::word_t bit_block_insert(bm::word_t *BMRESTRICT block, unsigned bitpos, bool value) BMNOEXCEPT
insert bit into position and shift the rest right with carryover
Definition bmfunc.h:5585
bm::bit_block_sub
bm::id64_t bit_block_sub(bm::word_t *BMRESTRICT dst, const bm::word_t *BMRESTRICT src) BMNOEXCEPT
Plain bitblock SUB (AND NOT) operation. Function does not analyse availability of source and destinat...
Definition bmfunc.h:8105
bm::bit_block_xor_2way
bm::id64_t bit_block_xor_2way(bm::word_t *BMRESTRICT dst, const bm::word_t *BMRESTRICT src1, const bm::word_t *BMRESTRICT src2) BMNOEXCEPT
2 way (target := source1 ^ source2) bitblock XOR operation.
Definition bmfunc.h:7911
bm::is_bits_one
bool is_bits_one(const bm::wordop_t *start) BMNOEXCEPT
Returns "true" if all bits in the block are 1.
Definition bmfunc.h:6081
bm::sort_order
sort_order
Sort order declaration.
Definition bmconst.h:204
bm::bvector::mem_pool_guard
bm::alloc_pool_guard< allocator_pool_type, bvector< Alloc > > mem_pool_guard
Definition bm.h:790
bm::operation
operation
Bit operations.
Definition bmconst.h:191
bit_visitor_callback_type
int(* bit_visitor_callback_type)(void *handle_ptr, bm::id_t bit_idx)
Callback type to visit (callback style) bits in bit-vector(s).
Definition bm.h:72
bm::finalization
finalization
copy strategy
Definition bmconst.h:156
bm::strategy
strategy
Block allocation strategies.
Definition bmconst.h:146
bm::BM_SORTED
@ BM_SORTED
input set is sorted (ascending order)
Definition bmconst.h:206
bm::BM_UNKNOWN
@ BM_UNKNOWN
sort order unknown
Definition bmconst.h:208
bm::BM_OR
@ BM_OR
Definition bmconst.h:193
bm::BM_SUB
@ BM_SUB
Definition bmconst.h:194
bm::BM_XOR
@ BM_XOR
Definition bmconst.h:195
bm::BM_AND
@ BM_AND
Definition bmconst.h:192
bm::finalization::UNDEFINED
@ UNDEFINED
Definition bmconst.h:157
bm::finalization::READWRITE
@ READWRITE
mutable (read-write object)
Definition bmconst.h:159
bm::finalization::READONLY
@ READONLY
immutable (read-only object)
Definition bmconst.h:158
bm::BM_BIT
@ BM_BIT
No GAP compression strategy. All new blocks are bit blocks.
Definition bmconst.h:147
bm::BM_GAP
@ BM_GAP
GAP compression is ON.
Definition bmconst.h:148
bm::gap_operation_or
gap_word_t * gap_operation_or(const gap_word_t *BMRESTRICT vect1, const gap_word_t *BMRESTRICT vect2, gap_word_t *BMRESTRICT tmp_buf, unsigned &dsize) BMNOEXCEPT
GAP OR operation.
Definition bmfunc.h:6666
bm::gap_test_unr
unsigned gap_test_unr(const T *BMRESTRICT buf, const unsigned pos) BMNOEXCEPT
Tests if bit = pos is true. Analog of bm::gap_test with SIMD unrolling.
Definition bmfunc.h:1833
bm::gap_bit_count_range
unsigned gap_bit_count_range(const T *const buf, unsigned left, unsigned right) BMNOEXCEPT
Counts 1 bits in GAP buffer in the closed [left, right] range.
Definition bmfunc.h:2393
bm::gap_find_last
unsigned gap_find_last(const T *BMRESTRICT buf, unsigned *BMRESTRICT last) BMNOEXCEPT
GAP block find the last set bit.
Definition bmfunc.h:1667
bm::gap_and_to_bitset
void gap_and_to_bitset(unsigned *BMRESTRICT dest, const T *BMRESTRICT pcurr) BMNOEXCEPT
ANDs GAP block to bitblock.
Definition bmfunc.h:4090
bm::gap_operation_xor
gap_word_t * gap_operation_xor(const gap_word_t *BMRESTRICT vect1, const gap_word_t *BMRESTRICT vect2, gap_word_t *BMRESTRICT tmp_buf, unsigned &dsize) BMNOEXCEPT
GAP XOR operation.
Definition bmfunc.h:6585
bm::gap_set_value
unsigned gap_set_value(unsigned val, T *BMRESTRICT buf, unsigned pos, unsigned *BMRESTRICT is_set) BMNOEXCEPT
Sets or clears bit in the GAP buffer.
Definition bmfunc.h:3254
bm::gap_level
T gap_level(const T *BMRESTRICT buf) BMNOEXCEPT
Returs GAP blocks capacity level.
Definition bmfunc.h:1649
bm::gap_xor_to_bitset
void gap_xor_to_bitset(unsigned *BMRESTRICT dest, const T *BMRESTRICT pcurr) BMNOEXCEPT
XOR GAP block to bitblock.
Definition bmfunc.h:4011
bm::gap_shift_r1
bool gap_shift_r1(T *BMRESTRICT buf, unsigned co_flag, unsigned *BMRESTRICT new_len) BMNOEXCEPT
Right shift GAP block by 1 bit.
Definition bmfunc.h:3431
bm::gapcmp
int gapcmp(const T *buf1, const T *buf2) BMNOEXCEPT
Lexicographical comparison of GAP buffers.
Definition bmfunc.h:2848
bm::gap_convert_to_bitset
void gap_convert_to_bitset(unsigned *BMRESTRICT dest, const T *BMRESTRICT buf, unsigned len=0) BMNOEXCEPT
GAP block to bitblock conversion.
Definition bmfunc.h:4475
bm::gap_find_first
unsigned gap_find_first(const T *BMRESTRICT buf, unsigned *BMRESTRICT first) BMNOEXCEPT
GAP block find the first set bit.
Definition bmfunc.h:1698
bm::gap_insert
bool gap_insert(T *BMRESTRICT buf, unsigned pos, unsigned val, unsigned *BMRESTRICT new_len) BMNOEXCEPT
isnert bit into GAP compressed block
Definition bmfunc.h:3484
bm::gap_invert
void gap_invert(T *buf) BMNOEXCEPT
Inverts all bits in the GAP buffer.
Definition bmfunc.h:4620
bm::gap_convert_to_bitset_smart
unsigned * gap_convert_to_bitset_smart(unsigned *BMRESTRICT dest, const T *BMRESTRICT buf, id_t set_max) BMNOEXCEPT
Smart GAP block to bitblock conversion.
Definition bmfunc.h:4500
bm::gap_sub_to_bitset
void gap_sub_to_bitset(unsigned *BMRESTRICT dest, const T *BMRESTRICT pcurr) BMNOEXCEPT
SUB (AND NOT) GAP block to bitblock.
Definition bmfunc.h:3912
bm::gap_block_find
unsigned gap_block_find(const T *BMRESTRICT buf, unsigned nbit, bm::id_t *BMRESTRICT prev) BMNOEXCEPT
Searches for the next 1 bit in the GAP block.
Definition bmfunc.h:3694
bm::gap_init_range_block
void gap_init_range_block(T *buf, T from, T to, T value) BMNOEXCEPT
Init gap block so it has block in it (can be whole block).
Definition bmfunc.h:4570
bm::gap_operation_and
gap_word_t * gap_operation_and(const gap_word_t *BMRESTRICT vect1, const gap_word_t *BMRESTRICT vect2, gap_word_t *BMRESTRICT tmp_buf, unsigned &dsize) BMNOEXCEPT
GAP AND operation.
Definition bmfunc.h:6518
bm::gap_is_all_zero
BMFORCEINLINE bool gap_is_all_zero(const bm::gap_word_t *BMRESTRICT buf) BMNOEXCEPT
Checks if GAP block is all-zero.
Definition bmfunc.h:1577
bm::gap_shift_l1
bool gap_shift_l1(T *BMRESTRICT buf, unsigned co_flag, unsigned *BMRESTRICT new_len) BMNOEXCEPT
Left shift GAP block by 1 bit.
Definition bmfunc.h:3540
bm::gap_add_to_bitset
void gap_add_to_bitset(unsigned *BMRESTRICT dest, const T *BMRESTRICT pcurr, unsigned len) BMNOEXCEPT
Adds(OR) GAP block to bitblock.
Definition bmfunc.h:4039
bm::gap_bit_count_range_hint
unsigned gap_bit_count_range_hint(const T *const buf, unsigned left, unsigned right, unsigned hint) BMNOEXCEPT
Counts 1 bits in GAP buffer in the closed [left, right] range using position hint to avoid bfind.
Definition bmfunc.h:2441
bm::gap_operation_sub
gap_word_t * gap_operation_sub(const gap_word_t *BMRESTRICT vect1, const gap_word_t *BMRESTRICT vect2, gap_word_t *BMRESTRICT tmp_buf, unsigned &dsize) BMNOEXCEPT
GAP SUB (AND NOT) operation.
Definition bmfunc.h:6712
bm::improve_gap_levels
bool improve_gap_levels(const T *length, const T *length_end, T *glevel_len) BMNOEXCEPT
Finds optimal gap blocks lengths.
Definition bmfunc.h:9170
bm::gap_capacity
unsigned gap_capacity(const T *BMRESTRICT buf, const T *BMRESTRICT glevel_len) BMNOEXCEPT
Returs GAP block capacity.
Definition bmfunc.h:1619
bm::gap_limit
unsigned gap_limit(const T *BMRESTRICT buf, const T *BMRESTRICT glevel_len) BMNOEXCEPT
Returs GAP block capacity limit.
Definition bmfunc.h:1635
bm::gap_length
BMFORCEINLINE bm::gap_word_t gap_length(const bm::gap_word_t *BMRESTRICT buf) BMNOEXCEPT
Returs GAP block length.
Definition bmfunc.h:1603
bm::gap_set_value_cpos
unsigned gap_set_value_cpos(unsigned val, T *BMRESTRICT buf, unsigned pos, unsigned *BMRESTRICT is_set, unsigned curr) BMNOEXCEPT
Sets or clears bit in the GAP buffer.
Definition bmfunc.h:3168
bm
Definition bm.h:78
bm::set_array_mask
const unsigned set_array_mask
Definition bmconst.h:97
bm::block_any
bool block_any(const bm::word_t *const BMRESTRICT block) BMNOEXCEPT
Returns "true" if one bit is set in the block Function check for block varieties.
Definition bmfunc.h:6482
bm::operator|
bvector< Alloc > operator|(const bvector< Alloc > &bv1, const bvector< Alloc > &bv2)
Definition bm.h:2246
bm::all_bits_mask
const id64_t all_bits_mask
Definition bmconst.h:132
bm::for_each_nzblock
void for_each_nzblock(T ***root, unsigned size1, F &f)
Definition bmfunc.h:1908
bm::id_max
const unsigned id_max
Definition bmconst.h:109
bm::block_is_all_one_range
bool block_is_all_one_range(const bm::word_t *const BMRESTRICT block, unsigned left, unsigned right) BMNOEXCEPT
Returns "true" if all bits are 1 in the block [left, right] Function check for block varieties.
Definition bmfunc.h:6107
bm::word_t
unsigned int word_t
Definition bmconst.h:39
bm::set_block_mask
const unsigned set_block_mask
Definition bmconst.h:57
bm::_lut
const unsigned char lzcnt_table< T >::_lut[16]
Definition bmconst.h:336
bm::gap_bit_count_to
unsigned gap_bit_count_to(const T *const buf, T right) BMNOEXCEPT
Definition bmfunc.h:2696
bm::operator-
bvector< Alloc > operator-(const bvector< Alloc > &bv1, const bvector< Alloc > &bv2)
Definition bm.h:2268
bm::check_block_one
bool check_block_one(const bm::word_t *blk, bool deep_scan) BMNOEXCEPT
Checks if block has only 1 bits.
Definition bmfunc.h:9120
bm::gap_bfind
unsigned gap_bfind(const T *BMRESTRICT buf, unsigned pos, unsigned *BMRESTRICT is_set) BMNOEXCEPT
Definition bmfunc.h:1725
bm::get_block_start
BMFORCEINLINE RTYPE get_block_start(unsigned i, unsigned j) BMNOEXCEPT
Compute bit address of the first bit in a block.
Definition bmfunc.h:201
bm::set_sub_array_size
const unsigned set_sub_array_size
Definition bmconst.h:95
bm::get_block_coord
BMFORCEINLINE void get_block_coord(BI_TYPE nb, unsigned &i, unsigned &j) BMNOEXCEPT
Recalc linear bvector block index into 2D matrix coordinates.
Definition bmfunc.h:180
bm::bits_in_array
const unsigned bits_in_array
Definition bmconst.h:115
bm::set_total_blocks
const unsigned set_total_blocks
Definition bmconst.h:111
bm::operator^
bvector< Alloc > operator^(const bvector< Alloc > &bv1, const bvector< Alloc > &bv2)
Definition bm.h:2257
bm::get_nibble
unsigned char get_nibble(const unsigned char *arr, unsigned idx) BMNOEXCEPT
get nibble from the array
Definition bmfunc.h:10280
bm::gap_operation_func_type
gap_word_t *(* gap_operation_func_type)(const gap_word_t *BMRESTRICT, const gap_word_t *BMRESTRICT, gap_word_t *BMRESTRICT, unsigned &)
Definition bmfunc.h:9541
bm::set_block_size_op
const unsigned set_block_size_op
Definition bmconst.h:133
bm::block_find_first_diff
bool block_find_first_diff(const bm::word_t *BMRESTRICT blk, const bm::word_t *BMRESTRICT arg_blk, unsigned *BMRESTRICT pos) BMNOEXCEPT
Find first bit which is different between two blocks (GAP or bit).
Definition bmfunc.h:9268
bm::rs3_half_span
const unsigned rs3_half_span
Definition bmconst.h:121
bm::gap_levels
const unsigned gap_levels
Definition bmconst.h:85
bm::set_word_shift
const unsigned set_word_shift
Definition bmconst.h:72
bm::xor_swap
BMFORCEINLINE void xor_swap(W &x, W &y) BMNOEXCEPT
XOR swap two variables.
Definition bmutil.h:534
bm::idx_arr_block_lookup_u64
bm::id64_t idx_arr_block_lookup_u64(const bm::id64_t *idx, bm::id64_t size, bm::id64_t nb, bm::id64_t start) BMNOEXCEPT
block boundaries look ahead U32
Definition bmfunc.h:9755
bm::_len
const gap_word_t gap_len_table< T >::_len[bm::gap_levels]
Definition bmconst.h:401
bm::set_block_size
const unsigned set_block_size
Definition bmconst.h:55
bm::id64_t
unsigned long long int id64_t
Definition bmconst.h:35
bm::block_any_range
bool block_any_range(const bm::word_t *const BMRESTRICT block, unsigned left, unsigned right) BMNOEXCEPT
Returns "true" if one bit is set in the block [left, right] Function check for block varieties.
Definition bmfunc.h:6461
bm::gap_equiv_len
const unsigned gap_equiv_len
Definition bmconst.h:82
bm::rs3_border0_1
const unsigned rs3_border0_1
Definition bmconst.h:122
bm::id_t
unsigned int id_t
Definition bmconst.h:38
bm::rs3_border1
const unsigned rs3_border1
Definition bmconst.h:120
bm::set_block_bits_u32
void set_block_bits_u32(bm::word_t *BMRESTRICT block, const unsigned *BMRESTRICT idx, unsigned start, unsigned stop) BMNOEXCEPT
set bits in a bit-block using global index
Definition bmfunc.h:9844
bm::idx_arr_block_lookup_u32
unsigned idx_arr_block_lookup_u32(const unsigned *idx, unsigned size, unsigned nb, unsigned start) BMNOEXCEPT
block boundaries look ahead U32
Definition bmfunc.h:9781
bm::set_bitscan_wave_size
const unsigned short set_bitscan_wave_size
Size of bit decode wave in words.
Definition bmfunc.h:9623
bm::set_array_shift
const unsigned set_array_shift
Definition bmconst.h:96
bm::gap_word_t
unsigned short gap_word_t
Definition bmconst.h:78
bm::rs3_border1_1
const unsigned rs3_border1_1
Definition bmconst.h:123
bm::gap_operation_to_bitset_func_type
void(* gap_operation_to_bitset_func_type)(unsigned *, const gap_word_t *)
Definition bmfunc.h:9537
bm::bvector_size_type
bm::id_t bvector_size_type
Definition bm.h:103
bm::rs3_border0
const unsigned rs3_border0
Definition bmconst.h:119
bm::gap_max_bits
const unsigned gap_max_bits
Definition bmconst.h:81
bm::set_top_array_size
const unsigned set_top_array_size
Definition bmconst.h:110
bm::set_block_shift
const unsigned set_block_shift
Definition bmconst.h:56
bm::for_each_nzblock_range
void for_each_nzblock_range(T ***root, N top_size, N nb_from, N nb_to, F &f) BMNOEXCEPT
Definition bmfunc.h:1851
bm::set_word_mask
const unsigned set_word_mask
Definition bmconst.h:73
bm::find_not_null_ptr
bool find_not_null_ptr(const bm::word_t *const *const *arr, N start, N size, N *pos) BMNOEXCEPT
Definition bmfunc.h:1427
bm::bits_in_block
const unsigned bits_in_block
Definition bmconst.h:114
bm::wordop_t
id64_t wordop_t
Definition bmconst.h:131
bm::block_find_reverse
bool block_find_reverse(const bm::word_t *BMRESTRICT block, unsigned nbit_from, unsigned *BMRESTRICT found_nbit) BMNOEXCEPT
Reverse find 1.
Definition bmfunc.h:6431
bm::set_block_bits_u64
void set_block_bits_u64(bm::word_t *BMRESTRICT block, const bm::id64_t *BMRESTRICT idx, bm::id64_t start, bm::id64_t stop) BMNOEXCEPT
set bits in a bit-block using global index
Definition bmfunc.h:9814
bm::for_each_nzblock_if
bool for_each_nzblock_if(T ***root, BI size1, F &f) BMNOEXCEPT
Definition bmfunc.h:2139
bm::block_find_rank
SIZE_TYPE block_find_rank(const bm::word_t *const block, SIZE_TYPE rank, unsigned nbit_from, unsigned &nbit_pos) BMNOEXCEPT
Find rank in block (GAP or BIT).
Definition bmfunc.h:8997
bvect
bm::bvector< dbg_alloc > bvect
Definition sample6.cpp:116
bm::bv_statistics::bv_statistics
bv_statistics() BMNOEXCEPT
Definition bmfunc.h:67
bm::bv_statistics::gap_levels
gap_word_t gap_levels[bm::gap_levels]
GAP block lengths in the bvect.
Definition bmfunc.h:64
bm::bv_statistics::max_serialize_mem
size_t max_serialize_mem
estimated maximum memory for serialization
Definition bmfunc.h:61
bm::bv_statistics::reset
void reset() BMNOEXCEPT
Reset statisctics.
Definition bmfunc.h:94
bm::bv_statistics::memory_used
size_t memory_used
memory usage for all blocks and service tables
Definition bmfunc.h:62
bm::bvector::allocation_policy::allocation_policy
allocation_policy(bm::strategy s=BM_BIT, const gap_word_t *glevels=bm::gap_len_table< true >::_len) BMNOEXCEPT
Definition bm.h:809
bm::bvector::allocation_policy::strat
bm::strategy strat
Definition bm.h:806
bm::bvector::allocation_policy::glevel_len
const gap_word_t * glevel_len
Definition bm.h:807
bm::bvector::iterator_base::bitblock_descr
Bit-block descriptor.
Definition bm.h:331
bm::bvector::iterator_base::bitblock_descr::idx
unsigned short idx
Current position in the bit list.
Definition bm.h:334
bm::bvector::iterator_base::bitblock_descr::bits
unsigned char bits[set_bitscan_wave_size *32]
bit list
Definition bm.h:333
bm::bvector::iterator_base::bitblock_descr::pos
size_type pos
Last bit position decode before.
Definition bm.h:336
bm::bvector::iterator_base::bitblock_descr::cnt
unsigned short cnt
Number of ON bits.
Definition bm.h:335
bm::bvector::iterator_base::bitblock_descr::ptr
const bm::word_t * ptr
Word pointer.
Definition bm.h:332
bm::bvector::iterator_base::dgap_descr
Information about current DGAP block.
Definition bm.h:343
bm::bvector::iterator_base::dgap_descr::ptr
const gap_word_t * ptr
Word pointer.
Definition bm.h:344
bm::bvector::iterator_base::dgap_descr::gap_len
gap_word_t gap_len
Current dgap length.
Definition bm.h:345
bm::bvector::statistics
Statistical information about bitset's memory allocation details.
Definition bm.h:125
bm::gap_len_table
Default GAP lengths table.
Definition bmconst.h:396
bm::gap_len_table::_len
static const gap_word_t _len[bm::gap_levels]
Definition bmconst.h:397
bm::operation_functions::gap_op_to_bit
static gap_operation_to_bitset_func_type gap_op_to_bit(unsigned i)
Definition bmfunc.h:9562
bm::operation_functions::gap_operation
static gap_operation_func_type gap_operation(unsigned i)
Definition bmfunc.h:9568
bm::bvector::iterator_base::block_descr
Definition bm.h:357
bm::bvector::iterator_base::block_descr::gap_
dgap_descr gap_
DGAP block related info.
Definition bm.h:359
bm::bvector::iterator_base::block_descr::bit_
bitblock_descr bit_
BitBlock related info.
Definition bm.h:358