#ifndef BMBMATRIX__H__INCLUDED__
#define BMBMATRIX__H__INCLUDED__
#include <stddef.h>
#include <type_traits>
#include "bmconst.h"
#ifndef BM_NO_STL
#include <stdexcept>
#endif
#include "bm.h"
#include "bmtrans.h"
#include "bmdef.h"
namespace bm
{
template<typename BV>
class basic_bmatrix
{
public:
typedef BV bvector_type;
typedef bvector_type* bvector_type_ptr;
typedef const bvector_type* bvector_type_const_ptr;
typedef typename BV::allocator_type allocator_type;
typedef typename bvector_type::allocation_policy allocation_policy_type;
typedef typename allocator_type::allocator_pool_type allocator_pool_type;
typedef typename bvector_type::size_type size_type;
typedef typename bvector_type::block_idx_type block_idx_type;
typedef unsigned char octet_type;
public:
basic_bmatrix(size_type rsize,
allocation_policy_type ap = allocation_policy_type(),
size_type bv_max_size = bm::id_max,
const allocator_type& alloc = allocator_type());
~basic_bmatrix() BMNOEXCEPT;
basic_bmatrix(const basic_bmatrix<BV>& bbm);
basic_bmatrix<BV>& operator=(const basic_bmatrix<BV>& bbm)
{
copy_from(bbm);
return *this;
}
#ifndef BM_NO_CXX11
basic_bmatrix(basic_bmatrix<BV>&& bbm) BMNOEXCEPT;
basic_bmatrix<BV>& operator = (basic_bmatrix<BV>&& bbm) BMNOEXCEPT
{
if (this != &bbm)
{
free_rows();
swap(bbm);
}
return *this;
}
#endif
void set_allocator_pool(allocator_pool_type* pool_ptr) BMNOEXCEPT
{ pool_ = pool_ptr; }
void swap(basic_bmatrix<BV>& bbm) BMNOEXCEPT;
void copy_from(const basic_bmatrix<BV>& bbm);
const bvector_type* row(size_type i) const BMNOEXCEPT;
bvector_type_const_ptr get_row(size_type i) const BMNOEXCEPT;
bvector_type* get_row(size_type i) BMNOEXCEPT;
size_type rows() const BMNOEXCEPT { return rsize_; }
bvector_type_ptr construct_row(size_type row);
bvector_type_ptr construct_row(size_type row, const bvector_type& bv);
void destruct_row(size_type row);
void clear_row(size_type row, bool free_mem);
size_type get_null_idx() const BMNOEXCEPT { return null_idx_; }
void set_null_idx(size_type null_idx) BMNOEXCEPT;
void allocate_rows(size_type rsize);
void free_rows() BMNOEXCEPT;
void set_octet(size_type pos, size_type octet_idx, unsigned char octet);
void insert_octet(size_type pos, size_type octet_idx, unsigned char octet);
unsigned char get_octet(size_type pos, size_type octet_idx) const BMNOEXCEPT;
int compare_octet(size_type pos,
size_type octet_idx, char octet) const BMNOEXCEPT;
size_type octet_size() const BMNOEXCEPT;
const bm::word_t* get_block(size_type p,
unsigned i, unsigned j) const BMNOEXCEPT;
void clear_slices_range(unsigned slice_from, unsigned slize_until,
size_type idx);
unsigned get_half_octet(size_type pos, size_type row_idx) const BMNOEXCEPT;
void optimize(
bm::word_t* temp_block = 0,
typename bvector_type::optmode opt_mode = bvector_type::opt_compress,
typename bvector_type::statistics* stat = 0);
void optimize_block(block_idx_type nb);
void calc_stat(typename bvector_type::statistics& st,
size_type rsize) const BMNOEXCEPT;
void erase_column(size_type idx, bool erase_null);
void insert_column(size_type idx, size_type row_from);
void clear_column(size_type idx, size_type row_from);
protected:
bvector_type* construct_bvector(const bvector_type* bv) const;
void destruct_bvector(bvector_type* bv) const;
static
void throw_bad_alloc() { BV::throw_bad_alloc(); }
template<typename Val, typename BVect, unsigned MAX_SIZE>
friend class base_sparse_vector;
protected:
size_type bv_size_;
allocator_type alloc_;
allocation_policy_type ap_;
allocator_pool_type* pool_;
bvector_type_ptr* bv_rows_;
size_type rsize_;
size_type null_idx_; };
template<typename Val, typename BV, unsigned MAX_SIZE>
class base_sparse_vector
{
public:
enum bit_planes
{
sv_slices = (sizeof(Val) * 8 * MAX_SIZE + 1),
sv_value_slices = (sizeof(Val) * 8 * MAX_SIZE)
};
enum vector_capacity
{
max_vector_size = MAX_SIZE
};
typedef Val value_type;
typedef BV bvector_type;
typedef typename BV::size_type size_type;
typedef bvector_type* bvector_type_ptr;
typedef const bvector_type* bvector_type_const_ptr;
typedef const value_type& const_reference;
typedef typename BV::allocator_type allocator_type;
typedef typename bvector_type::allocation_policy allocation_policy_type;
typedef typename bvector_type::enumerator bvector_enumerator_type;
typedef typename allocator_type::allocator_pool_type allocator_pool_type;
typedef bm::basic_bmatrix<BV> bmatrix_type;
typedef typename std::make_unsigned<value_type>::type unsigned_value_type;
public:
base_sparse_vector();
base_sparse_vector(bm::null_support null_able,
allocation_policy_type ap,
size_type bv_max_size,
const allocator_type& alloc);
base_sparse_vector(const base_sparse_vector<Val, BV, MAX_SIZE>& bsv);
#ifndef BM_NO_CXX11
base_sparse_vector(base_sparse_vector<Val, BV, MAX_SIZE>&& bsv) BMNOEXCEPT
{
bmatr_.swap(bsv.bmatr_);
size_ = bsv.size_;
effective_slices_ = bsv.effective_slices_;
bsv.size_ = 0;
}
#endif
void swap(base_sparse_vector<Val, BV, MAX_SIZE>& bsv) BMNOEXCEPT;
size_type size() const BMNOEXCEPT { return size_; }
void resize(size_type new_size);
void clear_range(size_type left, size_type right, bool set_null);
void keep_range_no_check(size_type left, size_type right,
bm::null_support slice_null);
void clear_all(bool free_mem = true) BMNOEXCEPT;
bool empty() const BMNOEXCEPT { return size() == 0; }
public:
static constexpr bool is_signed() BMNOEXCEPT
{ return std::is_signed<value_type>::value; }
bool is_nullable() const BMNOEXCEPT { return bmatr_.get_null_idx(); }
bm::null_support get_null_support() const BMNOEXCEPT
{ return is_nullable() ? bm::use_null : bm::no_null; }
const bvector_type* get_null_bvector() const BMNOEXCEPT
{
if (size_type null_idx = bmatr_.get_null_idx())
return bmatr_.get_row(null_idx);
return 0;
}
bool is_null(size_type idx) const BMNOEXCEPT;
bvector_type_ptr get_create_slice(unsigned i);
bvector_type_const_ptr
get_slice(unsigned i) const BMNOEXCEPT { return bmatr_.row(i); }
static unsigned slices() BMNOEXCEPT { return value_bits(); }
static unsigned stored_slices() BMNOEXCEPT { return value_bits()+1; }
unsigned effective_slices() const BMNOEXCEPT
{ return effective_slices_ + 1; }
bvector_type_ptr slice(unsigned i) BMNOEXCEPT { return bmatr_.get_row(i); }
bvector_type_const_ptr slice(unsigned i) const BMNOEXCEPT
{ return bmatr_.get_row(i); }
bvector_type* get_null_bvect() BMNOEXCEPT
{
if (size_type null_idx = bmatr_.get_null_idx())
return bmatr_.get_row(null_idx);
return 0;
}
void free_slice(unsigned i) { bmatr_.destruct_row(i); }
bm::id64_t get_slice_mask(unsigned element_idx) const BMNOEXCEPT;
const bmatrix_type& get_bmatrix() const BMNOEXCEPT { return bmatr_; }
bmatrix_type& get_bmatrix() BMNOEXCEPT { return bmatr_; }
void mark_null_idx(unsigned null_idx) BMNOEXCEPT
{ bmatr_.null_idx_ = null_idx; }
static
unsigned_value_type s2u(value_type v) BMNOEXCEPT;
static
value_type u2s(unsigned_value_type v) BMNOEXCEPT;
void optimize(bm::word_t* temp_block = 0,
typename bvector_type::optmode opt_mode = bvector_type::opt_compress,
typename bvector_type::statistics* stat = 0);
void calc_stat(typename bvector_type::statistics* st) const BMNOEXCEPT;
bool equal(const base_sparse_vector<Val, BV, MAX_SIZE>& sv,
bm::null_support null_able = bm::use_null) const BMNOEXCEPT;
protected:
void copy_from(const base_sparse_vector<Val, BV, MAX_SIZE>& bsv);
void merge_matr(bmatrix_type& bmatr);
void clear_value_planes_from(unsigned plane_idx, size_type idx);
void insert_clear_value_planes_from(unsigned plane_idx, size_type idx);
void erase_column(size_type idx, bool erase_null);
void insert_null(size_type idx, bool not_null);
protected:
typedef typename bvector_type::block_idx_type block_idx_type;
static constexpr unsigned value_bits() BMNOEXCEPT
{ return base_sparse_vector<Val, BV, MAX_SIZE>::sv_value_slices; }
void optimize_block(block_idx_type nb) { bmatr_.optimize_block(nb); }
void copy_range_slices(
const base_sparse_vector<Val, BV, MAX_SIZE>& bsv,
typename base_sparse_vector<Val, BV, MAX_SIZE>::size_type left,
typename base_sparse_vector<Val, BV, MAX_SIZE>::size_type right,
bm::null_support slice_null);
protected:
bmatrix_type bmatr_; unsigned_value_type slice_mask_; size_type size_; unsigned effective_slices_;
};
#ifdef _MSC_VER
#pragma warning( push )
#pragma warning( disable : 4146 )
#endif
template<typename BV>
basic_bmatrix<BV>::basic_bmatrix(size_type rsize,
allocation_policy_type ap,
size_type bv_max_size,
const allocator_type& alloc)
: bv_size_(bv_max_size),
alloc_(alloc),
ap_(ap),
pool_(0),
bv_rows_(0),
rsize_(0),
null_idx_(0)
{
allocate_rows(rsize);
}
template<typename BV>
basic_bmatrix<BV>::~basic_bmatrix() BMNOEXCEPT
{
free_rows();
}
template<typename BV>
basic_bmatrix<BV>::basic_bmatrix(const basic_bmatrix<BV>& bbm)
: bv_size_(bbm.bv_size_),
alloc_(bbm.alloc_),
ap_(bbm.ap_),
pool_(0),
bv_rows_(0),
rsize_(0),
null_idx_(0)
{
copy_from(bbm);
}
template<typename BV>
basic_bmatrix<BV>::basic_bmatrix(basic_bmatrix<BV>&& bbm) BMNOEXCEPT
: bv_size_(bbm.bv_size_),
alloc_(bbm.alloc_),
ap_(bbm.ap_),
pool_(0),
bv_rows_(0),
rsize_(0),
null_idx_(0)
{
swap(bbm);
}
template<typename BV>
const typename basic_bmatrix<BV>::bvector_type*
basic_bmatrix<BV>::row(size_type i) const BMNOEXCEPT
{
BM_ASSERT(i < rsize_);
return bv_rows_[i];
}
template<typename BV>
const typename basic_bmatrix<BV>::bvector_type*
basic_bmatrix<BV>::get_row(size_type i) const BMNOEXCEPT
{
BM_ASSERT(i < rsize_);
return bv_rows_[i];
}
template<typename BV>
typename basic_bmatrix<BV>::bvector_type*
basic_bmatrix<BV>::get_row(size_type i) BMNOEXCEPT
{
BM_ASSERT(i < rsize_);
return bv_rows_[i];
}
template<typename BV>
void basic_bmatrix<BV>::set_null_idx(size_type null_idx) BMNOEXCEPT
{
BM_ASSERT(null_idx);
BM_ASSERT(get_row(null_idx));
null_idx_ = null_idx;
}
template<typename BV>
void basic_bmatrix<BV>::copy_from(const basic_bmatrix<BV>& bbm)
{
if (this == &bbm) return;
free_rows();
bv_size_ = bbm.bv_size_;
alloc_ = bbm.alloc_;
ap_ = bbm.ap_;
null_idx_ = bbm.null_idx_;
size_type rsize = bbm.rsize_;
if (rsize)
{
bv_rows_ = (bvector_type_ptr*)alloc_.alloc_ptr(rsize);
if (!bv_rows_)
throw_bad_alloc();
rsize_ = rsize;
for (size_type i = 0; i < rsize_; ++i)
{
const bvector_type_ptr bv = bbm.bv_rows_[i];
bv_rows_[i] = bv ? construct_bvector(bv) : 0;
}
}
}
template<typename BV>
void basic_bmatrix<BV>::erase_column(size_type idx, bool erase_null)
{
size_type r_to = (!erase_null && null_idx_) ? null_idx_ : rsize_;
for (size_type i = 0; i < r_to; ++i)
if (bvector_type* bv = get_row(i))
bv->erase(idx);
}
template<typename BV>
void basic_bmatrix<BV>::insert_column(size_type idx,
size_type row_from)
{
for (size_type i = row_from; i < rsize_; ++i)
if (bvector_type* bv = get_row(i))
bv->insert(idx, false);
}
template<typename BV>
void basic_bmatrix<BV>::clear_column(size_type idx,
size_type row_from)
{
for (size_type i = row_from; i < rsize_; ++i)
if (bvector_type* bv = get_row(i))
bv->clear_bit_no_check(idx);
}
template<typename BV>
void basic_bmatrix<BV>::allocate_rows(size_type rsize)
{
size_type rsize_prev(rsize_);
if (rsize <= rsize_prev)
return; bvector_type_ptr* bv_rows_prev(bv_rows_);
BM_ASSERT(rsize);
bv_rows_ = (bvector_type_ptr*)alloc_.alloc_ptr(unsigned(rsize));
if (!bv_rows_)
throw_bad_alloc();
rsize_ = rsize;
BM_ASSERT((!null_idx_) || (rsize & 1u));
for (size_type i = 0; i < rsize; ++i)
bv_rows_[i] = 0;
if (bv_rows_prev) {
for (size_type i = 0; i < rsize_prev; ++i)
bv_rows_[i] = bv_rows_prev[i];
alloc_.free_ptr(bv_rows_prev, unsigned(rsize_prev));
if (null_idx_) {
bv_rows_[rsize-1] = bv_rows_[null_idx_];
bv_rows_[null_idx_] = 0;
null_idx_ = rsize-1;
}
}
}
template<typename BV>
typename basic_bmatrix<BV>::size_type
basic_bmatrix<BV>::octet_size() const BMNOEXCEPT
{
size_type osize = (7 + rsize_) / 8;
return osize;
}
template<typename BV>
void basic_bmatrix<BV>::free_rows() BMNOEXCEPT
{
for (size_type i = 0; i < rsize_; ++i)
{
if (bvector_type_ptr bv = bv_rows_[i])
{
destruct_bvector(bv);
bv_rows_[i] = 0;
}
} if (bv_rows_)
alloc_.free_ptr(bv_rows_, unsigned(rsize_));
bv_rows_ = 0;
}
template<typename BV>
void basic_bmatrix<BV>::swap(basic_bmatrix<BV>& bbm) BMNOEXCEPT
{
if (this == &bbm)
return;
bm::xor_swap(bv_size_, bbm.bv_size_);
allocator_type alloc_tmp = alloc_;
alloc_ = bbm.alloc_;
bbm.alloc_ = alloc_tmp;
allocation_policy_type ap_tmp = ap_;
ap_ = bbm.ap_;
bbm.ap_ = ap_tmp;
allocator_pool_type* pool_tmp = pool_;
pool_ = bbm.pool_;
bbm.pool_ = pool_tmp;
bm::xor_swap(rsize_, bbm.rsize_);
bm::xor_swap(null_idx_, bbm.null_idx_);
bvector_type_ptr* rtmp = bv_rows_;
bv_rows_ = bbm.bv_rows_;
bbm.bv_rows_ = rtmp;
}
template<typename BV>
typename basic_bmatrix<BV>::bvector_type_ptr
basic_bmatrix<BV>::construct_row(size_type row)
{
if (row > rsize_)
allocate_rows(row + 8);
BM_ASSERT(row < rsize_);
bvector_type_ptr bv = bv_rows_[row];
if (!bv)
bv = bv_rows_[row] = construct_bvector(0);
return bv;
}
template<typename BV>
typename basic_bmatrix<BV>::bvector_type_ptr
basic_bmatrix<BV>::construct_row(size_type row, const bvector_type& bv_src)
{
if (row > rsize_)
allocate_rows(row + 8);
BM_ASSERT(row < rsize_);
bvector_type_ptr bv = bv_rows_[row];
if (bv)
*bv = bv_src;
else
bv = bv_rows_[row] = construct_bvector(&bv_src);
return bv;
}
template<typename BV>
void basic_bmatrix<BV>::destruct_row(size_type row)
{
BM_ASSERT(row < rsize_);
if (bvector_type_ptr bv = bv_rows_[row])
{
destruct_bvector(bv);
bv_rows_[row] = 0;
}
}
template<typename BV>
void basic_bmatrix<BV>::clear_row(size_type row, bool free_mem)
{
BM_ASSERT(row < rsize_);
if (bvector_type_ptr bv = bv_rows_[row])
{
if (free_mem)
{
destruct_bvector(bv);
bv_rows_[row] = 0;
}
else
bv->clear(true);
}
}
template<typename BV>
typename basic_bmatrix<BV>::bvector_type*
basic_bmatrix<BV>::construct_bvector(const bvector_type* bv) const
{
bvector_type* rbv = 0;
#ifdef BM_NO_STL
void* mem = ::malloc(sizeof(bvector_type));
if (mem == 0)
{
BM_THROW(false, BM_ERR_BADALLOC);
}
if (bv)
rbv = new(mem) bvector_type(*bv);
else
{
rbv = new(mem) bvector_type(ap_.strat, ap_.glevel_len, bv_size_, alloc_);
rbv->init();
}
#else
if (bv)
rbv = new bvector_type(*bv);
else
{
rbv = new bvector_type(ap_.strat, ap_.glevel_len, bv_size_, alloc_);
rbv->init();
}
#endif
return rbv;
}
template<typename BV>
void basic_bmatrix<BV>::destruct_bvector(bvector_type* bv) const
{
#ifdef BM_NO_STL
bv->~TBM_bvector();
::free((void*)bv);
#else
delete bv;
#endif
}
template<typename BV>
const bm::word_t*
basic_bmatrix<BV>::get_block(size_type p,
unsigned i, unsigned j) const BMNOEXCEPT
{
if (bvector_type_const_ptr bv = this->row(p))
return bv->get_blocks_manager().get_block_ptr(i, j);
return 0;
}
template<typename BV>
void basic_bmatrix<BV>::clear_slices_range(
unsigned slice_from, unsigned slice_until,
size_type idx)
{
for (unsigned p = slice_from; p < slice_until; ++p)
if (bvector_type* bv = this->get_row(p)) bv->clear_bit_no_check(idx);
}
template<typename BV>
void basic_bmatrix<BV>::set_octet(size_type pos,
size_type octet_idx,
unsigned char octet)
{
if (7u + octet_idx * 8u > rsize_)
allocate_rows(rsize_ + 16);
size_type row = octet_idx * 8;
size_type row_end = row + 8;
for (; row < row_end; ++row)
{
bvector_type* bv = (row < rsize_) ? this->get_row(row) : 0;
if (octet & 1u)
{
if (!bv)
bv = this->construct_row(row);
bv->set_bit_no_check(pos);
}
else
{
if (bv)
bv->clear_bit_no_check(pos);
}
octet >>= 1;
if (!octet)
break;
}
if (row_end > rsize_)
row_end = rsize_;
for (++row; row < row_end; ++row)
if (bvector_type* bv = this->get_row(row))
bv->clear_bit_no_check(pos);
}
template<typename BV>
void basic_bmatrix<BV>::insert_octet(size_type pos,
size_type octet_idx,
unsigned char octet)
{
BM_ASSERT(octet_idx * 8u < rsize_);
size_type oct = octet;
size_type row = octet_idx * 8;
size_type row_end = row + 8;
for (; row < row_end; ++row)
{
bvector_type* bv = (row < rsize_) ? this->get_row(row) : 0;
if (oct & 1u)
{
if (!bv)
{
bv = this->construct_row(row);
bv->set_bit_no_check(pos);
}
else
{
bv->insert(pos, true);
}
}
else
{
if (bv)
bv->insert(pos, false);
}
oct >>= 1;
if (!oct)
break;
}
if (row_end > rsize_)
row_end = rsize_;
for (++row; row < row_end; ++row)
if (bvector_type* bv = this->get_row(row))
bv->insert(pos, false);
}
template<typename BV>
unsigned char
basic_bmatrix<BV>::get_octet(size_type pos, size_type octet_idx) const BMNOEXCEPT
{
unsigned v = 0;
block_idx_type nb = (pos >> bm::set_block_shift);
unsigned i0 = unsigned(nb >> bm::set_array_shift); unsigned j0 = unsigned(nb & bm::set_array_mask);
const bm::word_t* blk;
const bm::word_t* blka[8];
unsigned nbit = unsigned(pos & bm::set_block_mask);
unsigned nword = unsigned(nbit >> bm::set_word_shift);
unsigned mask0 = 1u << (nbit & bm::set_word_mask);
unsigned row_idx = unsigned(octet_idx * 8);
if (row_idx + 7 >= rsize_ ||
(null_idx_ && (row_idx + 7 > null_idx_))) return (unsigned char)v;
blka[0] = get_block(row_idx+0, i0, j0);
blka[1] = get_block(row_idx+1, i0, j0);
blka[2] = get_block(row_idx+2, i0, j0);
blka[3] = get_block(row_idx+3, i0, j0);
blka[4] = get_block(row_idx+4, i0, j0);
blka[5] = get_block(row_idx+5, i0, j0);
blka[6] = get_block(row_idx+6, i0, j0);
blka[7] = get_block(row_idx+7, i0, j0);
unsigned is_set;
if ((blk = blka[0])!=0)
{
if (blk == FULL_BLOCK_FAKE_ADDR)
is_set = 1;
else
is_set = (BM_IS_GAP(blk)) ? bm::gap_test_unr(BMGAP_PTR(blk), nbit) : (blk[nword] & mask0);
v |= (unsigned)bool(is_set);
}
if ((blk = blka[1])!=0)
{
if (blk == FULL_BLOCK_FAKE_ADDR)
is_set = 1;
else
is_set = (BM_IS_GAP(blk)) ? bm::gap_test_unr(BMGAP_PTR(blk), nbit) : (blk[nword] & mask0);
v |= unsigned(bool(is_set)) << 1u;
}
if ((blk = blka[2])!=0)
{
if (blk == FULL_BLOCK_FAKE_ADDR)
is_set = 1;
else
is_set = (BM_IS_GAP(blk)) ? bm::gap_test_unr(BMGAP_PTR(blk), nbit) : (blk[nword] & mask0);
v |= unsigned(bool(is_set)) << 2u;
}
if ((blk = blka[3])!=0)
{
if (blk == FULL_BLOCK_FAKE_ADDR)
is_set = 1;
else
is_set = (BM_IS_GAP(blk)) ? bm::gap_test_unr(BMGAP_PTR(blk), nbit) : (blk[nword] & mask0);
v |= unsigned(bool(is_set)) << 3u;
}
if ((blk = blka[4])!=0)
{
if (blk == FULL_BLOCK_FAKE_ADDR)
is_set = 1;
else
is_set = (BM_IS_GAP(blk)) ? bm::gap_test_unr(BMGAP_PTR(blk), nbit) : (blk[nword] & mask0);
v |= unsigned(bool(is_set)) << 4u;
}
if ((blk = blka[5])!=0)
{
if (blk == FULL_BLOCK_FAKE_ADDR)
is_set = 1;
else
is_set = (BM_IS_GAP(blk)) ? bm::gap_test_unr(BMGAP_PTR(blk), nbit) : (blk[nword] & mask0);
v |= unsigned(bool(is_set)) << 5u;
}
if ((blk = blka[6])!=0)
{
if (blk == FULL_BLOCK_FAKE_ADDR)
is_set = 1;
else
is_set = (BM_IS_GAP(blk)) ? bm::gap_test_unr(BMGAP_PTR(blk), nbit) : (blk[nword] & mask0);
v |= unsigned(bool(is_set)) << 6u;
}
if ((blk = blka[7])!=0)
{
if (blk == FULL_BLOCK_FAKE_ADDR)
is_set = 1;
else
is_set = (BM_IS_GAP(blk)) ? bm::gap_test_unr(BMGAP_PTR(blk), nbit) : (blk[nword] & mask0);
v |= unsigned(bool(is_set)) << 7u;
}
return (unsigned char)v;
}
template<typename BV>
int basic_bmatrix<BV>::compare_octet(size_type pos,
size_type octet_idx,
char octet) const BMNOEXCEPT
{
char value = char(get_octet(pos, octet_idx));
return (value > octet) - (value < octet);
}
template<typename BV>
unsigned
basic_bmatrix<BV>::get_half_octet(size_type pos, size_type row_idx) const BMNOEXCEPT
{
unsigned v = 0;
block_idx_type nb = (pos >> bm::set_block_shift);
unsigned i0 = unsigned(nb >> bm::set_array_shift); unsigned j0 = unsigned(nb & bm::set_array_mask);
const bm::word_t* blk;
const bm::word_t* blka[4];
unsigned nbit = unsigned(pos & bm::set_block_mask);
unsigned nword = unsigned(nbit >> bm::set_word_shift);
unsigned mask0 = 1u << (nbit & bm::set_word_mask);
blka[0] = get_block(row_idx+0, i0, j0);
blka[1] = get_block(row_idx+1, i0, j0);
blka[2] = get_block(row_idx+2, i0, j0);
blka[3] = get_block(row_idx+3, i0, j0);
unsigned is_set;
if ((blk = blka[0])!=0)
{
if (blk == FULL_BLOCK_FAKE_ADDR)
is_set = 1;
else
is_set = (BM_IS_GAP(blk)) ? bm::gap_test_unr(BMGAP_PTR(blk), nbit) : (blk[nword] & mask0);
v |= unsigned(bool(is_set));
}
if ((blk = blka[1])!=0)
{
if (blk == FULL_BLOCK_FAKE_ADDR)
is_set = 1;
else
is_set = (BM_IS_GAP(blk)) ? bm::gap_test_unr(BMGAP_PTR(blk), nbit) : (blk[nword] & mask0);
v |= unsigned(bool(is_set)) << 1u;
}
if ((blk = blka[2])!=0)
{
if (blk == FULL_BLOCK_FAKE_ADDR)
is_set = 1;
else
is_set = (BM_IS_GAP(blk)) ? bm::gap_test_unr(BMGAP_PTR(blk), nbit) : (blk[nword] & mask0);
v |= unsigned(bool(is_set)) << 2u;
}
if ((blk = blka[3])!=0)
{
if (blk == FULL_BLOCK_FAKE_ADDR)
is_set = 1;
else
is_set = (BM_IS_GAP(blk)) ? bm::gap_test_unr(BMGAP_PTR(blk), nbit) : (blk[nword] & mask0);
v |= unsigned(bool(is_set)) << 3u;
}
return v;
}
template<typename BV>
void basic_bmatrix<BV>::optimize(bm::word_t* temp_block,
typename bvector_type::optmode opt_mode,
typename bvector_type::statistics* st)
{
if (st)
st->reset();
BM_DECLARE_TEMP_BLOCK(tb)
if (!temp_block)
temp_block = tb;
for (unsigned k = 0; k < rsize_; ++k)
{
if (bvector_type* bv = get_row(k))
{
typename bvector_type::statistics stbv;
stbv.reset();
bv->optimize(temp_block, opt_mode, st ? &stbv : 0);
if (st)
st->add(stbv);
}
} }
template<typename BV>
void basic_bmatrix<BV>::calc_stat(typename bvector_type::statistics& st,
size_type rsize) const BMNOEXCEPT
{
for (size_type i = 0; i < rsize; ++i)
if (const bvector_type* bv = row(i))
{
typename bvector_type::statistics stbv;
bv->calc_stat(&stbv);
st.add(stbv);
}
else
st.max_serialize_mem += 8;
}
template<typename BV>
void basic_bmatrix<BV>::optimize_block(block_idx_type nb)
{
for (unsigned k = 0; k < rsize_; ++k)
{
if (bvector_type* bv = get_row(k))
{
unsigned i, j;
bm::get_block_coord(nb, i, j);
typename bvector_type::blocks_manager_type& bman =
bv->get_blocks_manager();
bman.optimize_bit_block(i, j);
}
}
}
template<class Val, class BV, unsigned MAX_SIZE>
base_sparse_vector<Val, BV, MAX_SIZE>::base_sparse_vector()
: bmatr_(sv_slices, allocation_policy_type(), bm::id_max, allocator_type()),
slice_mask_(0),
size_(0),
effective_slices_(0)
{
}
template<class Val, class BV, unsigned MAX_SIZE>
base_sparse_vector<Val, BV, MAX_SIZE>::base_sparse_vector(
bm::null_support null_able,
allocation_policy_type ap,
size_type bv_max_size,
const allocator_type& alloc)
: bmatr_(sv_slices, ap, bv_max_size, alloc),
slice_mask_(0),
size_(0),
effective_slices_(0)
{
if (null_able == bm::use_null)
{
size_type null_idx = (MAX_SIZE * sizeof(Val) * 8);
bmatr_.construct_row(null_idx)->init();
bmatr_.set_null_idx(null_idx);
slice_mask_ |= unsigned_value_type(1) << null_idx;
}
}
template<class Val, class BV, unsigned MAX_SIZE>
base_sparse_vector<Val, BV, MAX_SIZE>::base_sparse_vector(
const base_sparse_vector<Val, BV, MAX_SIZE>& bsv)
: bmatr_(bsv.bmatr_),
slice_mask_(bsv.slice_mask_),
size_(bsv.size_),
effective_slices_(bsv.effective_slices_)
{
}
template<class Val, class BV, unsigned MAX_SIZE>
void base_sparse_vector<Val, BV, MAX_SIZE>::copy_from(
const base_sparse_vector<Val, BV, MAX_SIZE>& bsv)
{
resize(bsv.size());
effective_slices_ = bsv.effective_slices_;
size_type arg_null_idx = bsv.bmatr_.get_null_idx();
if (arg_null_idx)
bmatr_.null_idx_ = arg_null_idx;
size_type slices = bsv.get_bmatrix().rows(); bmatr_.allocate_rows(slices);
for (size_type i = 0; i < slices; ++i)
{
bvector_type* bv = bmatr_.get_row(i);
const bvector_type* bv_src = bsv.bmatr_.row(i);
if (i && (i == arg_null_idx)) {
if (bv && !bv_src) {
if (size_)
bv->set_range(0, size_-1);
continue;
}
}
if (bv)
{
bmatr_.destruct_row(i);
slice_mask_ &= ~(unsigned_value_type(1) << i);
}
if (bv_src)
{
bmatr_.construct_row(i, *bv_src);
slice_mask_ |= (unsigned_value_type(1) << i);
}
} }
template<class Val, class BV, unsigned MAX_SIZE>
void base_sparse_vector<Val, BV, MAX_SIZE>::merge_matr(
bmatrix_type& bmatr)
{
size_type rows = this->bmatr_.rows();
const size_type arg_rows = bmatr.rows();
if (rows < arg_rows)
{
rows = arg_rows;
bmatr_.allocate_rows(rows);
BM_ASSERT(this->bmatr_.rows() == arg_rows);
}
bvector_type* bv_null_arg = 0;
size_type null_idx = bmatr.get_null_idx();
if (null_idx)
bv_null_arg = bmatr.get_row(null_idx);
if (bvector_type* bv_null = get_null_bvect())
{
BM_ASSERT(bv_null_arg);
bv_null->merge(*bv_null_arg);
}
if (rows > arg_rows)
rows = arg_rows; for (unsigned j = 0; j < rows; ++j)
{
bvector_type* arg_bv = bmatr.get_row(j);
if (arg_bv && arg_bv != bv_null_arg)
{
bvector_type* bv = this->get_create_slice(j);
slice_mask_ |= (unsigned_value_type(1) << j);
bv->merge(*arg_bv);
}
} }
template<class Val, class BV, unsigned MAX_SIZE>
void base_sparse_vector<Val, BV, MAX_SIZE>::swap(
base_sparse_vector<Val, BV, MAX_SIZE>& bsv) BMNOEXCEPT
{
if (this != &bsv)
{
bmatr_.swap(bsv.bmatr_);
bm::xor_swap(slice_mask_, bsv.slice_mask_);
bm::xor_swap(size_, bsv.size_);
bm::xor_swap(effective_slices_, bsv.effective_slices_);
}
}
template<class Val, class BV, unsigned MAX_SIZE>
void base_sparse_vector<Val, BV, MAX_SIZE>::clear_all(bool free_mem) BMNOEXCEPT
{
unsigned slices = value_bits();
for (size_type i = 0; i < slices; ++i)
bmatr_.clear_row(i, free_mem);
slice_mask_ = 0; size_ = 0;
if (bvector_type* bv_null = get_null_bvect())
bv_null->clear(true);
}
template<class Val, class BV, unsigned MAX_SIZE>
void base_sparse_vector<Val, BV, MAX_SIZE>::clear_range(
typename base_sparse_vector<Val, BV, MAX_SIZE>::size_type left,
typename base_sparse_vector<Val, BV, MAX_SIZE>::size_type right,
bool set_null)
{
if (right < left)
return clear_range(right, left, set_null);
unsigned planes = value_bits();
for (unsigned i = 0; i < planes; ++i)
if (bvector_type* bv = this->bmatr_.get_row(i))
bv->set_range(left, right, false);
if (set_null)
if (bvector_type* bv_null = this->get_null_bvect())
bv_null->set_range(left, right, false);
}
template<class Val, class BV, unsigned MAX_SIZE>
void base_sparse_vector<Val, BV, MAX_SIZE>::keep_range_no_check(
size_type left, size_type right,
bm::null_support slice_null)
{
if (left)
this->clear_range(0, left-1, (slice_null == bm::use_null));
size_type sz = size();
if (right < sz)
this->clear_range(right + 1, sz, (slice_null == bm::use_null));
}
template<class Val, class BV, unsigned MAX_SIZE>
void base_sparse_vector<Val, BV, MAX_SIZE>::resize(size_type sz)
{
if (sz == size()) return;
if (!sz) {
clear_all();
return;
}
if (sz < size()) clear_range(sz, this->size_-1, true); size_ = sz;
}
template<class Val, class BV, unsigned MAX_SIZE>
bool base_sparse_vector<Val, BV, MAX_SIZE>::is_null(
size_type idx) const BMNOEXCEPT
{
const bvector_type* bv_null = get_null_bvector();
return (bv_null) ? (!bv_null->test(idx)) : false;
}
template<class Val, class BV, unsigned MAX_SIZE>
void base_sparse_vector<Val, BV, MAX_SIZE>::insert_null(size_type idx,
bool not_null)
{
if (bvector_type* bv_null = this->get_null_bvect())
bv_null->insert(idx, not_null);
}
template<class Val, class BV, unsigned MAX_SIZE>
typename base_sparse_vector<Val, BV, MAX_SIZE>::bvector_type_ptr
base_sparse_vector<Val, BV, MAX_SIZE>::get_create_slice(unsigned i)
{
bvector_type_ptr bv = bmatr_.construct_row(i);
if (i < (sizeof(value_type) * 8))
{
slice_mask_ |= (unsigned_value_type(1) << i);
if (i > effective_slices_)
effective_slices_ = i;
}
return bv;
}
template<class Val, class BV, unsigned MAX_SIZE>
bm::id64_t base_sparse_vector<Val, BV, MAX_SIZE>::get_slice_mask(
unsigned element_idx) const BMNOEXCEPT
{
bm::id64_t mask = 0;
bm::id64_t mask1 = 1;
const unsigned planes = sizeof(value_type) * 8;
unsigned bidx = 0;
unsigned slice_size = (element_idx+1) * planes;
if (slice_size > this->bmatr_.rows())
slice_size = (unsigned) this->bmatr_.rows();
for (unsigned i = element_idx * planes; i < slice_size; ++i, ++bidx)
mask |= get_slice(i) ? (mask1 << bidx) : 0ull;
return mask;
}
template<class Val, class BV, unsigned MAX_SIZE>
void base_sparse_vector<Val, BV, MAX_SIZE>::optimize(bm::word_t* temp_block,
typename bvector_type::optmode opt_mode,
typename bvector_type::statistics* st)
{
typename bvector_type::statistics stbv;
bmatr_.optimize(temp_block, opt_mode, &stbv);
if (st)
st->add(stbv);
bvector_type* bv_null = this->get_null_bvect();
unsigned slices = (unsigned)this->bmatr_.rows();
for (unsigned j = 0; j < slices; ++j)
{
bvector_type* bv = this->bmatr_.get_row(j);
if (bv && (bv != bv_null)) {
if (!bv->any()) {
this->bmatr_.destruct_row(j);
slice_mask_ &= ~(unsigned_value_type(1) << j);
continue;
}
}
} }
template<class Val, class BV, unsigned MAX_SIZE>
void base_sparse_vector<Val, BV, MAX_SIZE>::calc_stat(
typename bvector_type::statistics* st) const BMNOEXCEPT
{
BM_ASSERT(st);
st->reset();
size_type slices = this->get_bmatrix().rows(); bmatr_.calc_stat(*st, slices);
st->max_serialize_mem += 1 + 1 + 1 + 1 + 8 + (8 * slices);
st->max_serialize_mem += 1 + 8; }
template<class Val, class BV, unsigned MAX_SIZE>
void base_sparse_vector<Val, BV, MAX_SIZE>::clear_value_planes_from(
unsigned plane_idx, size_type idx)
{
bmatr_.clear_column(idx, plane_idx);
}
template<class Val, class BV, unsigned MAX_SIZE>
void base_sparse_vector<Val, BV, MAX_SIZE>::insert_clear_value_planes_from(
unsigned plane_idx, size_type idx)
{
bmatr_.insert_column(idx, plane_idx);
}
template<class Val, class BV, unsigned MAX_SIZE>
void base_sparse_vector<Val, BV, MAX_SIZE>::erase_column(
size_type idx, bool erase_null)
{
bmatr_.erase_column(idx, erase_null);
}
template<class Val, class BV, unsigned MAX_SIZE>
bool base_sparse_vector<Val, BV, MAX_SIZE>::equal(
const base_sparse_vector<Val, BV, MAX_SIZE>& sv,
bm::null_support null_able) const BMNOEXCEPT
{
if (size_type arg_size = sv.size(); this->size_ != arg_size)
return false;
unsigned slices = (unsigned) this->bmatr_.rows();
unsigned arg_slices = (unsigned) sv.bmatr_.rows();
unsigned max_slices(slices);
if (max_slices < arg_slices)
max_slices = arg_slices;
const bvector_type* bv_null = this->get_null_bvector();
const bvector_type* bv_null_arg = sv.get_null_bvector();
for (unsigned j = 0; j < max_slices; ++j)
{
const bvector_type* bv;
const bvector_type* arg_bv;
bv = (j < slices) ? this->bmatr_.get_row(j) : 0;
arg_bv = (j < arg_slices) ? sv.bmatr_.get_row(j) : 0;
if (bv == bv_null)
bv = 0; if (arg_bv == bv_null_arg)
arg_bv = 0;
if (bv == arg_bv) continue;
if (!bv && arg_bv)
{
if (arg_bv->any())
return false;
continue;
}
if (bv && !arg_bv)
{
if (bv->any())
return false;
continue;
}
bool eq = bv->equal(*arg_bv);
if (!eq)
return false;
}
if (null_able == bm::use_null)
{
if (bv_null == bv_null_arg)
return true;
if (!bv_null || !bv_null_arg)
return false;
BM_ASSERT(bv_null);
BM_ASSERT(bv_null_arg);
bool eq = bv_null->equal(*bv_null_arg);
if (!eq)
return false;
}
return true;
}
template<class Val, class BV, unsigned MAX_SIZE>
void base_sparse_vector<Val, BV, MAX_SIZE>::copy_range_slices(
const base_sparse_vector<Val, BV, MAX_SIZE>& bsv,
typename base_sparse_vector<Val, BV, MAX_SIZE>::size_type left,
typename base_sparse_vector<Val, BV, MAX_SIZE>::size_type right,
bm::null_support slice_null)
{
if (bmatr_.rows() < bsv.bmatr_.rows())
bmatr_.allocate_rows(bsv.bmatr_.rows());
size_type spli;
const bvector_type* bv_null_arg = bsv.get_null_bvector();
if (bvector_type* bv_null = get_null_bvect())
{
spli = this->bmatr_.rows(); if (bv_null_arg && (slice_null == bm::use_null))
bv_null->copy_range(*bv_null_arg, left, right);
--spli;
}
else
spli = this->bmatr_.rows();
for (size_type j = 0; j < spli; ++j)
{
if (const bvector_type* arg_bv = bsv.bmatr_.row(j))
{
if (arg_bv == bv_null_arg)
continue;
bvector_type* bv = this->get_create_slice(unsigned(j));
bv->copy_range(*arg_bv, left, right);
}
}
}
template<class Val, class BV, unsigned MAX_SIZE>
typename base_sparse_vector<Val, BV, MAX_SIZE>::unsigned_value_type
base_sparse_vector<Val, BV, MAX_SIZE>::s2u(value_type v) BMNOEXCEPT
{
if constexpr (is_signed())
{
if (v < 0)
{
value_type uv = -(v+1);
return 1u | unsigned_value_type((unsigned_value_type(uv) << 1u));
}
return unsigned_value_type(unsigned_value_type(v) << 1u);
}
else
return v;
}
template<class Val, class BV, unsigned MAX_SIZE>
typename base_sparse_vector<Val, BV, MAX_SIZE>::value_type
base_sparse_vector<Val, BV, MAX_SIZE>::u2s(unsigned_value_type uv) BMNOEXCEPT
{
if constexpr (is_signed())
{
if (uv & 1u) {
value_type s = (-(uv >> 1u)) - 1;
return s;
}
return value_type(uv >> 1u);
}
else
return uv;
}
#ifdef _MSC_VER
#pragma warning( pop )
#endif
}
#endif