2
Copyright(c) 2002-2005 Anatoliy Kuznetsov(anatoliy_kuznetsov at yahoo.com)
4
PermiFor more information please visit: http://bmagic.sourceforge.net
5
ssion is hereby granted, free of charge, to any person
6
obtaining a copy of this software and associated documentation
7
files (the "Software"), to deal in the Software without restriction,
8
including without limitation the rights to use, copy, modify, merge,
9
publish, distribute, sublicense, and/or sell copies of the Software,
10
and to permit persons to whom the Software is furnished to do so,
11
subject to the following conditions:
13
The above copyright notice and this permission notice shall be included
14
in all copies or substantial portions of the Software.
16
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
18
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
20
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22
OTHER DEALINGS IN THE SOFTWARE.
24
For more information please visit: http://bmagic.sourceforge.net
29
#ifndef BM_BLOCKS__H__INCLUDED__
30
#define BM_BLOCKS__H__INCLUDED__
38
@brief bitvector blocks manager
39
Embedded class managing bit-blocks on very low level.
40
Includes number of functor classes used in different bitset algorithms.
45
template<class Alloc, class MS>
50
typedef Alloc allocator_type;
52
/** Base functor class */
56
bm_func_base(blocks_manager& bman) : bm_(bman) {}
63
/** Base functor class connected for "constant" functors*/
64
class bm_func_base_const
67
bm_func_base_const(const blocks_manager& bman) : bm_(bman) {}
70
const blocks_manager& bm_;
74
/** Base class for bitcounting functors */
75
class block_count_base : public bm_func_base_const
78
block_count_base(const blocks_manager& bm)
79
: bm_func_base_const(bm) {}
81
bm::id_t block_count(const bm::word_t* block, unsigned idx) const
84
if (IS_FULL_BLOCK(block))
86
count = bm::bits_in_block;
90
if (BM_IS_GAP(this->bm_, block, idx))
92
count = gap_bit_count(BMGAP_PTR(block));
97
bit_block_calc_count(block,
98
block + bm::set_block_size);
106
/** Bitcounting functor */
107
class block_count_func : public block_count_base
110
block_count_func(const blocks_manager& bm)
111
: block_count_base(bm), count_(0) {}
113
bm::id_t count() const { return count_; }
115
void operator()(const bm::word_t* block, unsigned idx)
117
count_ += this->block_count(block, idx);
125
/** Bitcounting functor filling the block counts array*/
126
class block_count_arr_func : public block_count_base
129
block_count_arr_func(const blocks_manager& bm, unsigned* arr)
130
: block_count_base(bm), arr_(arr), last_idx_(0)
135
void operator()(const bm::word_t* block, unsigned idx)
137
while (++last_idx_ < idx)
141
arr_[idx] = this->block_count(block, idx);
145
unsigned last_block() const { return last_idx_; }
152
/** bit value change counting functor */
153
class block_count_change_func : public bm_func_base_const
156
block_count_change_func(const blocks_manager& bm)
157
: bm_func_base_const(bm),
159
prev_block_border_bit_(0)
162
bm::id_t block_count(const bm::word_t* block, unsigned idx)
167
if (IS_FULL_BLOCK(block) || (block == 0))
172
first_bit = block ? 1 : 0;
173
count -= !(prev_block_border_bit_ ^ first_bit);
175
prev_block_border_bit_ = block ? 1 : 0;
179
if (BM_IS_GAP(this->bm_, block, idx))
181
gap_word_t* gap_block = BMGAP_PTR(block);
182
count = gap_length(gap_block) - 1;
185
first_bit = gap_test(gap_block, 0);
186
count -= !(prev_block_border_bit_ ^ first_bit);
189
prev_block_border_bit_ =
190
gap_test(gap_block, gap_max_bits-1);
194
count = bit_block_calc_count_change(block,
195
block + bm::set_block_size);
198
first_bit = block[0] & 1;
199
count -= !(prev_block_border_bit_ ^ first_bit);
201
prev_block_border_bit_ =
202
block[set_block_size-1] >> ((sizeof(block[0]) * 8) - 1);
209
bm::id_t count() const { return count_; }
211
void operator()(const bm::word_t* block, unsigned idx)
213
count_ += block_count(block, idx);
218
bm::id_t prev_block_border_bit_;
222
/** Functor detects if any bit set*/
223
class block_any_func : public bm_func_base_const
226
block_any_func(const blocks_manager& bm)
227
: bm_func_base_const(bm)
230
bool operator()(const bm::word_t* block, unsigned idx)
232
if (IS_FULL_BLOCK(block)) return true;
234
if (BM_IS_GAP(this->bm_, block, idx)) // gap block
236
if (!gap_is_all_zero(BMGAP_PTR(block), bm::gap_max_bits))
243
bm::wordop_t* blk1 = (wordop_t*)block;
245
(wordop_t*)(block + bm::set_block_size);
246
if (!bit_is_all_zero(blk1, blk2))
255
/*! Change GAP level lengths functor */
256
class gap_level_func : public bm_func_base
259
gap_level_func(blocks_manager& bm, const gap_word_t* glevel_len)
261
glevel_len_(glevel_len)
263
BM_ASSERT(glevel_len);
266
void operator()(bm::word_t* block, unsigned idx)
268
blocks_manager& bman = this->bm_;
270
if (!BM_IS_GAP(bman, block, idx))
273
gap_word_t* gap_blk = BMGAP_PTR(block);
275
// TODO: Use the same code as in the optimize functor
276
if (gap_is_all_zero(gap_blk, bm::gap_max_bits))
278
bman.set_block_ptr(idx, 0);
282
if (gap_is_all_one(gap_blk, bm::gap_max_bits))
284
bman.set_block_ptr(idx, FULL_BLOCK_ADDR);
286
bman.get_allocator().free_gap_block(gap_blk,
288
bman.set_block_bit(idx);
292
unsigned len = gap_length(gap_blk);
293
int level = gap_calc_level(len, glevel_len_);
297
bman.get_allocator().alloc_bit_block();
298
bman.set_block_ptr(idx, blk);
299
bman.set_block_bit(idx);
300
gap_convert_to_bitset(blk, gap_blk);
304
gap_word_t* gap_blk_new =
305
bman.allocate_gap_block(level, gap_blk, glevel_len_);
307
bm::word_t* p = (bm::word_t*) gap_blk_new;
309
bman.set_block_ptr(idx, p);
311
bman.get_allocator().free_gap_block(gap_blk, bman.glen());
315
const gap_word_t* glevel_len_;
319
/*! Bitblock optimization functor */
320
class block_opt_func : public bm_func_base
323
block_opt_func(blocks_manager& bm,
324
bm::word_t* temp_block,
327
temp_block_(temp_block),
330
BM_ASSERT(temp_block);
333
void operator()(bm::word_t* block, unsigned idx)
335
blocks_manager& bman = this->bm_;
336
if (IS_FULL_BLOCK(block)) return;
340
if (BM_IS_GAP(bman, block, idx)) // gap block
342
gap_blk = BMGAP_PTR(block);
344
if (gap_is_all_zero(gap_blk, bm::gap_max_bits))
346
bman.set_block_ptr(idx, 0);
350
if (gap_is_all_one(gap_blk, bm::gap_max_bits))
352
bman.set_block_ptr(idx, FULL_BLOCK_ADDR);
354
bman.get_allocator().free_gap_block(gap_blk,
356
bman.set_block_bit(idx);
361
if (opt_mode_ < 3) // free_01 optimization
363
bm::wordop_t* blk1 = (wordop_t*)block;
365
(wordop_t*)(block + bm::set_block_size);
367
bool b = bit_is_all_zero(blk1, blk2);
370
bman.get_allocator().free_bit_block(block);
371
bman.set_block_ptr(idx, 0);
374
if (opt_mode_ == 2) // check if it is all 1 block
376
b = is_bits_one(blk1, blk2);
379
bman.get_allocator().free_bit_block(block);
380
bman.set_block_ptr(idx, FULL_BLOCK_ADDR);
389
gap_word_t* tmp_gap_blk = (gap_word_t*)temp_block_;
390
*tmp_gap_blk = bm::gap_max_level << 1;
392
unsigned threashold = bman.glen(bm::gap_max_level)-4;
394
unsigned len = bit_convert_to_gap(tmp_gap_blk,
402
// convertion successful
404
bman.get_allocator().free_bit_block(block);
406
// check if new gap block can be eliminated
408
if (gap_is_all_zero(tmp_gap_blk, bm::gap_max_bits))
410
bman.set_block_ptr(idx, 0);
412
else if (gap_is_all_one(tmp_gap_blk, bm::gap_max_bits))
414
bman.set_block_ptr(idx, FULL_BLOCK_ADDR);
418
int level = bm::gap_calc_level(len, bman.glen());
421
bman.allocate_gap_block(level, tmp_gap_blk);
422
bman.set_block_ptr(idx, (bm::word_t*)gap_blk);
423
bman.set_block_gap(idx);
431
bm::word_t* temp_block_;
435
/** Bitblock invert functor */
436
class block_invert_func : public bm_func_base
439
block_invert_func(blocks_manager& bm)
440
: bm_func_base(bm) {}
442
void operator()(bm::word_t* block, unsigned idx)
446
this->bm_.set_block(idx, FULL_BLOCK_ADDR);
449
if (IS_FULL_BLOCK(block))
451
this->bm_.set_block_ptr(idx, 0);
455
if (BM_IS_GAP(this->bm_, block, idx)) // gap block
457
gap_invert(BMGAP_PTR(block));
461
bm::wordop_t* wrd_ptr = (wordop_t*) block;
462
bm::wordop_t* wrd_end =
463
(wordop_t*) (block + bm::set_block_size);
464
bit_invert(wrd_ptr, wrd_end);
471
/** Set block zero functor */
472
class block_zero_func : public bm_func_base
475
block_zero_func(blocks_manager& bm, bool free_mem)
480
void operator()(bm::word_t* block, unsigned idx)
482
blocks_manager& bman = this->bm_;
483
if (IS_FULL_BLOCK(block))
485
bman.set_block_ptr(idx, 0);
489
if (BM_IS_GAP(bman, block, idx))
491
gap_set_all(BMGAP_PTR(block), bm::gap_max_bits, 0);
497
bman.get_allocator().free_bit_block(block);
498
bman.set_block_ptr(idx, 0);
502
bit_block_set(block, 0);
508
bool free_mem_; //!< If "true" frees bitblocks memsets to '0'
511
/** Fill block with all-one bits functor */
512
class block_one_func : public bm_func_base
515
block_one_func(blocks_manager& bm) : bm_func_base(bm) {}
517
void operator()(bm::word_t* block, unsigned idx)
519
if (!IS_FULL_BLOCK(block))
521
this->bm_.set_block_all_set(idx);
526
/** Block deallocation functor */
527
class block_free_func : public bm_func_base
530
block_free_func(blocks_manager& bm) : bm_func_base(bm) {}
532
void operator()(bm::word_t* block, unsigned idx)
534
blocks_manager& bman = this->bm_;
535
if (BM_IS_GAP(bman, block, idx)) // gap block
537
bman.get_allocator().free_gap_block(BMGAP_PTR(block),
542
bman.get_allocator().free_bit_block(block);
547
/** Block copy functor */
548
class block_copy_func : public bm_func_base
551
block_copy_func(blocks_manager& bm_target,
552
const blocks_manager& bm_src)
553
: bm_func_base(bm_target),
557
void operator()(bm::word_t* block, unsigned idx)
559
bool gap = bm_src_.is_block_gap(idx);
562
blocks_manager& bman = this->bm_;
566
bm::gap_word_t* gap_block = BMGAP_PTR(block);
567
unsigned level = gap_level(gap_block);
568
new_blk = (bm::word_t*)
569
bman.get_allocator().alloc_gap_block(level,
571
int len = gap_length(BMGAP_PTR(block));
572
::memcpy(new_blk, gap_block, len * sizeof(gap_word_t));
573
BMSET_PTRGAP(new_blk);
577
if (IS_FULL_BLOCK(block))
583
new_blk = bman.get_allocator().alloc_bit_block();
584
bit_block_copy(new_blk, block);
587
bman.set_block(idx, new_blk);
591
const blocks_manager& bm_src_;
597
blocks_manager(const gap_word_t* glevel_len,
599
const Alloc& alloc = Alloc())
603
::memcpy(glevel_len_, glevel_len, sizeof(glevel_len_));
607
top_block_size_ = compute_top_block_size(max_bits);
608
// allocate first level descr. of blocks
609
blocks_ = (bm::word_t***) alloc_.alloc_ptr(top_block_size_);
610
::memset(blocks_, 0, top_block_size_ * sizeof(bm::word_t**));
617
volatile const char* vp = _copyright<true>::_p;
622
blocks_manager(const blocks_manager& blockman)
624
top_block_size_(blockman.top_block_size_),
625
#ifdef BM_DISBALE_BIT_IN_PTR
626
gap_flags_(blockman.gap_flags_),
629
alloc_(blockman.alloc_)
631
::memcpy(glevel_len_, blockman.glevel_len_, sizeof(glevel_len_));
633
blocks_ = (bm::word_t***)alloc_.alloc_ptr(top_block_size_);
634
::memset(blocks_, 0, top_block_size_ * sizeof(bm::word_t**));
637
const_cast<blocks_manager*>(&blockman);
639
word_t*** blk_root = bm->blocks_root();
641
block_copy_func copy_func(*this, blockman);
642
for_each_nzblock(blk_root, top_block_size_,
643
bm::set_array_size, copy_func);
648
alloc_.free_bit_block(temp_block_);
652
void free_ptr(bm::word_t** ptr)
654
if (ptr) alloc_.free_ptr(ptr);
658
\brief Compute size of the block array needed to store bits
659
\param bits_to_store - supposed capacity (number of bits)
660
\return size of the top level block
662
unsigned compute_top_block_size(bm::id_t bits_to_store)
664
if (bits_to_store == bm::id_max) // working in full-range mode
666
return bm::set_array_size;
669
unsigned top_block_size =
670
bits_to_store / (bm::set_block_size * sizeof(bm::word_t) *
671
bm::set_array_size * 8);
672
if (top_block_size < bm::set_array_size) ++top_block_size;
673
return top_block_size;
677
Returns current capacity (bits)
679
bm::id_t capacity() const
681
// arithmetic overflow protection...
682
return top_block_size_ == bm::set_array_size ? bm::id_max :
683
top_block_size_ * bm::set_array_size * bm::bits_in_block;
687
\brief Finds block in 2-level blocks array
688
\param nb - Index of block (logical linear number)
689
\return block adress or NULL if not yet allocated
691
bm::word_t* get_block(unsigned nb) const
693
unsigned block_idx = nb >> bm::set_array_shift;
694
if (block_idx >= top_block_size_)
698
bm::word_t** blk_blk = blocks_[block_idx];
699
return blk_blk ? blk_blk[nb & bm::set_array_mask] : 0;
703
\brief Finds block in 2-level blocks array
704
Specilized version of get_block(unsigned), returns an additional
705
condition when there are no more blocks
707
\param nb - Index of block (logical linear number)
708
\param no_more_blocks - 1 if there are no more blocks at all
709
\return block adress or NULL if not yet allocated
711
bm::word_t* get_block(unsigned nb, int* no_more_blocks) const
713
unsigned block_idx = nb >> bm::set_array_shift;
714
if (block_idx >= top_block_size_)
720
bm::word_t** blk_blk = blocks_[block_idx];
721
return blk_blk ? blk_blk[nb & bm::set_array_mask] : 0;
724
bool is_no_more_blocks(unsigned nb) const
727
unsigned block_idx = nb >> bm::set_array_shift;
728
for (unsigned i = block_idx; i < top_block_size_; ++i) {
729
bm::word_t** blk_blk = blocks_[i];
732
for (unsigned j = block & bm::set_array_mask;
733
j < bm::set_array_size; ++j)
735
bm::word_t* blk = blk_blk[j];
736
if (blk && !is_block_zero(i, blk))
745
block += bm::set_array_size;
752
\brief Finds block in 2-level blocks array
753
\param i - top level block index
754
\param j - second level block index
755
\return block adress or NULL if not yet allocated
757
const bm::word_t* get_block(unsigned i, unsigned j) const
759
if (i >= top_block_size_) return 0;
760
const bm::word_t* const* blk_blk = blocks_[i];
761
return (blk_blk == 0) ? 0 : blk_blk[j];
765
\brief Function returns top-level block in 2-level blocks array
766
\param i - top level block index
767
\return block adress or NULL if not yet allocated
769
const bm::word_t* const * get_topblock(unsigned i) const
771
return (i >= top_block_size_) ? 0 : blocks_[i];
775
\brief Returns root block in the tree.
777
bm::word_t*** get_rootblock() const
780
const_cast<blocks_manager*>(this);
781
return bm->blocks_root();
784
void set_block_all_set(unsigned nb)
786
bm::word_t* block = this->get_block(nb);
787
set_block(nb, const_cast<bm::word_t*>(FULL_BLOCK_ADDR));
789
// If we keep block type flag in pointer itself we dp not need
791
#ifdef BM_DISBALE_BIT_IN_PTR
795
if (BM_IS_GAP((*this), block, nb))
797
alloc_.free_gap_block(BMGAP_PTR(block), glevel_len_);
801
alloc_.free_bit_block(block);
806
Function checks if block is not yet allocated, allocates it and sets to
807
all-zero or all-one bits.
809
If content_flag == 1 (ALLSET block) requested and taken block is already ALLSET,
810
function will return NULL
812
initial_block_type and actual_block_type : 0 - bitset, 1 - gap
814
bm::word_t* check_allocate_block(unsigned nb,
815
unsigned content_flag,
816
int initial_block_type,
817
int* actual_block_type,
818
bool allow_null_ret=true)
820
bm::word_t* block = this->get_block(nb);
822
if (!IS_VALID_ADDR(block)) // NULL block or ALLSET
824
// if we wanted ALLSET and requested block is ALLSET return NULL
825
unsigned block_flag = IS_FULL_BLOCK(block);
826
*actual_block_type = initial_block_type;
827
if (block_flag == content_flag && allow_null_ret)
829
return 0; // it means nothing to do for the caller
832
if (initial_block_type == 0) // bitset requested
834
block = alloc_.alloc_bit_block();
836
// initialize block depending on its previous status
838
bit_block_set(block, block_flag ? 0xFF : 0);
840
set_block(nb, block);
842
else // gap block requested
844
bm::gap_word_t* gap_block = allocate_gap_block(0);
845
gap_set_all(gap_block, bm::gap_max_bits, block_flag);
846
set_block(nb, (bm::word_t*)gap_block);
850
return (bm::word_t*)gap_block;
854
else // block already exists
856
*actual_block_type = BM_IS_GAP((*this), block, nb);
862
/*! @brief Fills all blocks with 0.
863
@param free_mem - if true function frees the resources
865
void set_all_zero(bool free_mem)
867
block_zero_func zero_func(*this, free_mem);
868
for_each_nzblock(blocks_, top_block_size_,
869
bm::set_array_size, zero_func);
872
/*! Replaces all blocks with ALL_ONE block.
876
block_one_func func(*this);
877
for_each_block(blocks_, top_block_size_,
878
bm::set_array_size, func);
882
Places new block into descriptors table, returns old block's address.
883
Old block is not deleted.
885
bm::word_t* set_block(unsigned nb, bm::word_t* block)
887
bm::word_t* old_block;
890
register unsigned nblk_blk = nb >> bm::set_array_shift;
892
// auto-resize the top block array
893
if (nblk_blk >= top_block_size_)
894
reserve_top_blocks(nblk_blk + 1);
896
// If first level array not yet allocated, allocate it and
897
// assign block to it
898
if (blocks_[nblk_blk] == 0)
900
blocks_[nblk_blk] = (bm::word_t**)alloc_.alloc_ptr();
901
::memset(blocks_[nblk_blk], 0,
902
bm::set_array_size * sizeof(bm::word_t*));
908
old_block = blocks_[nblk_blk][nb & bm::set_array_mask];
911
// NOTE: block will be replaced without freeing,
912
// potential memory leak may lay here....
913
blocks_[nblk_blk][nb & bm::set_array_mask] = block; // equivalent to %
919
Places new block into blocks table.
921
void set_block_ptr(unsigned nb, bm::word_t* block)
923
blocks_[nb >> bm::set_array_shift][nb & bm::set_array_mask] = block;
927
\brief Converts block from type gap to conventional bitset block.
928
\param nb - Block's index.
929
\param gap_block - Pointer to the gap block,
930
if NULL block nb will be taken
931
\return new gap block's memory
933
bm::word_t* convert_gap2bitset(unsigned nb, gap_word_t* gap_block=0)
935
bm::word_t* block = this->get_block(nb);
938
gap_block = BMGAP_PTR(block);
941
BM_ASSERT(IS_VALID_ADDR((bm::word_t*)gap_block));
942
BM_ASSERT(is_block_gap(nb)); // must be GAP type
944
bm::word_t* new_block = alloc_.alloc_bit_block();
946
gap_convert_to_bitset(new_block, gap_block);
948
// new block will replace the old one(no deletion)
949
set_block_ptr(nb, new_block);
951
alloc_.free_gap_block(BMGAP_PTR(block), glen());
953
// If GAP flag is in block pointer no need to clean the gap bit twice
954
#ifdef BM_DISBALE_BIT_IN_PTR
962
\brief Extends GAP block to the next level or converts it to bit block.
963
\param nb - Block's linear index.
964
\param blk - Blocks's pointer
966
void extend_gap_block(unsigned nb, gap_word_t* blk)
968
unsigned level = bm::gap_level(blk);
969
unsigned len = bm::gap_length(blk);
970
if (level == bm::gap_max_level || len >= gap_max_buff_len)
972
convert_gap2bitset(nb);
976
bm::word_t* new_blk = (bm::word_t*)allocate_gap_block(++level, blk);
978
BMSET_PTRGAP(new_blk);
980
set_block_ptr(nb, new_blk);
981
alloc_.free_gap_block(blk, glen());
985
bool is_block_gap(unsigned nb) const
987
#ifdef BM_DISBALE_BIT_IN_PTR
988
return gap_flags_.test(nb)!=0;
990
bm::word_t* block = get_block(nb);
991
return BMPTR_TESTBIT0(block) != 0;
995
void set_block_bit(unsigned nb)
997
#ifdef BM_DISBALE_BIT_IN_PTR
998
gap_flags_.set(nb, false);
1000
bm::word_t* block = get_block(nb);
1001
block = (bm::word_t*) BMPTR_CLEARBIT0(block);
1002
set_block_ptr(nb, block);
1006
void set_block_gap(unsigned nb)
1008
#ifdef BM_DISBALE_BIT_IN_PTR
1011
bm::word_t* block = get_block(nb);
1012
block = (bm::word_t*)BMPTR_SETBIT0(block);
1013
set_block_ptr(nb, block);
1018
\fn bool bm::bvector::blocks_manager::is_block_zero(unsigned nb, bm::word_t* blk)
1019
\brief Checks all conditions and returns true if block consists of only 0 bits
1020
\param nb - Block's linear index.
1021
\param blk - Blocks's pointer
1022
\returns true if all bits are in the block are 0.
1024
bool is_block_zero(unsigned nb, const bm::word_t* blk) const
1026
if (blk == 0) return true;
1028
if (BM_IS_GAP((*this), blk, nb)) // GAP
1030
gap_word_t* b = BMGAP_PTR(blk);
1031
return gap_is_all_zero(b, bm::gap_max_bits);
1035
for (unsigned i = 0; i < bm::set_block_size; ++i)
1044
\brief Checks if block has only 1 bits
1045
\param nb - Index of the block.
1046
\param blk - Block's pointer
1047
\return true if block consists of 1 bits.
1049
bool is_block_one(unsigned nb, const bm::word_t* blk) const
1051
if (blk == 0) return false;
1053
if (BM_IS_GAP((*this), blk, nb)) // GAP
1055
gap_word_t* b = BMGAP_PTR(blk);
1056
return gap_is_all_one(b, bm::gap_max_bits);
1061
if (IS_FULL_BLOCK(blk))
1065
return is_bits_one((wordop_t*)blk,
1066
(wordop_t*)(blk + bm::set_block_size));
1069
/*! Returns temporary block, allocates if needed. */
1070
bm::word_t* check_allocate_tempblock()
1072
return temp_block_ ? temp_block_
1073
: (temp_block_ = alloc_.alloc_bit_block());
1076
/*! Assigns new GAP lengths vector */
1077
void set_glen(const gap_word_t* glevel_len)
1079
::memcpy(glevel_len_, glevel_len, sizeof(glevel_len_));
1083
bm::gap_word_t* allocate_gap_block(unsigned level,
1084
gap_word_t* src = 0,
1085
const gap_word_t* glevel_len = 0)
1088
glevel_len = glevel_len_;
1089
gap_word_t* ptr = alloc_.alloc_gap_block(level, glevel_len);
1092
unsigned len = gap_length(src);
1093
::memcpy(ptr, src, len * sizeof(gap_word_t));
1094
// Reconstruct the mask word using the new level code.
1095
*ptr = ((len-1) << 3) | (level << 1) | (*src & 1);
1104
unsigned mem_used() const
1106
unsigned mem_used = sizeof(*this);
1107
mem_used += temp_block_ ? sizeof(word_t) * bm::set_block_size : 0;
1108
mem_used += sizeof(bm::word_t**) * top_block_size_;
1110
#ifdef BM_DISBALE_BIT_IN_PTR
1111
mem_used += gap_flags_.mem_used() - sizeof(gap_flags_);
1114
for (unsigned i = 0; i < top_block_size_; ++i)
1116
mem_used += blocks_[i] ? sizeof(void*) * bm::set_array_size : 0;
1122
/** Returns true if second level block pointer is 0.
1124
bool is_subblock_null(unsigned nsub) const
1126
return blocks_[nsub] == NULL;
1130
bm::word_t*** blocks_root()
1135
/*! \brief Returns current GAP level vector
1137
const gap_word_t* glen() const
1142
/*! \brief Returns GAP level length for specified level
1143
\param level - level number
1145
unsigned glen(unsigned level) const
1147
return glevel_len_[level];
1150
/*! \brief Swaps content
1151
\param bm another blocks manager
1153
void swap(blocks_manager& bm)
1155
BM_ASSERT(this != &bm);
1157
word_t*** btmp = blocks_;
1158
blocks_ = bm.blocks_;
1161
#ifdef BM_DISBALE_BIT_IN_PTR
1162
gap_flags_.swap(bm.gap_flags_);
1165
xor_swap(this->top_block_size_, bm.top_block_size_);
1167
BM_ASSERT(sizeof(glevel_len_) / sizeof(glevel_len_[0])
1168
== bm::gap_levels); // paranoiya check
1169
for (unsigned i = 0; i < bm::gap_levels; ++i)
1171
xor_swap(glevel_len_[i], bm.glevel_len_[i]);
1175
/*! \brief Returns size of the top block array in the tree
1177
unsigned top_block_size() const
1179
return top_block_size_;
1183
\brief reserve capacity for specified number of bits
1185
void reserve(unsigned max_bits)
1189
unsigned b = compute_top_block_size(max_bits);
1190
reserve_top_blocks(b);
1195
\brief Make sure blocks manager has enough blocks capacity
1197
void reserve_top_blocks(unsigned top_blocks)
1199
BM_ASSERT(top_blocks <= bm::set_array_size);
1200
if (top_blocks <= top_block_size_) return; // nothing to do
1201
bm::word_t*** new_blocks =
1202
(bm::word_t***)alloc_.alloc_ptr(top_blocks);
1204
for (unsigned i = 0; i < top_block_size_; ++i)
1206
new_blocks[i] = blocks_[i];
1208
for (unsigned j = top_block_size_; j < top_blocks; ++j)
1212
alloc_.free_ptr(blocks_, top_block_size_);
1213
blocks_ = new_blocks;
1214
top_block_size_ = top_blocks;
1217
/** \brief Returns reference on the allocator
1219
allocator_type& get_allocator() { return alloc_; }
1221
/** \brief Returns allocator
1223
allocator_type get_allocator() const { return alloc_; }
1227
void operator =(const blocks_manager&);
1231
if (blocks_ == 0) return;
1233
block_free_func free_func(*this);
1234
for_each_nzblock(blocks_, top_block_size_,
1235
bm::set_array_size, free_func);
1237
for(unsigned i = 0; i < top_block_size_; ++i)
1239
bm::word_t** blk_blk = blocks_[i];
1241
alloc_.free_ptr(blk_blk);
1243
alloc_.free_ptr(blocks_, top_block_size_);
1248
bm::word_t*** blocks_;
1249
/// Size of the top level block array in blocks_ tree
1250
unsigned top_block_size_;
1251
#ifdef BM_DISBALE_BIT_IN_PTR
1252
/// mini bitvector used to indicate gap blocks
1256
bm::word_t* temp_block_;
1257
/// vector defines gap block lengths for different levels
1258
gap_word_t glevel_len_[bm::gap_levels];
1260
allocator_type alloc_;
2
Copyright(c) 2002-2005 Anatoliy Kuznetsov(anatoliy_kuznetsov at yahoo.com)
4
Permission is hereby granted, free of charge, to any person
5
obtaining a copy of this software and associated documentation
6
files (the "Software"), to deal in the Software without restriction,
7
including without limitation the rights to use, copy, modify, merge,
8
publish, distribute, sublicense, and/or sell copies of the Software,
9
and to permit persons to whom the Software is furnished to do so,
10
subject to the following conditions:
12
The above copyright notice and this permission notice shall be included
13
in all copies or substantial portions of the Software.
15
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
17
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
19
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
20
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
21
OTHER DEALINGS IN THE SOFTWARE.
23
For more information please visit: http://bmagic.sourceforge.net
28
#ifndef BM_BLOCKS__H__INCLUDED__
29
#define BM_BLOCKS__H__INCLUDED__
38
@brief bitvector blocks manager
39
Embedded class managing bit-blocks on very low level.
40
Includes number of functor classes used in different bitset algorithms.
45
template<class Alloc, class MS>
50
typedef Alloc allocator_type;
52
/** Base functor class (block visitor)*/
56
bm_func_base(blocks_manager& bman) : bm_(bman) {}
58
void on_empty_top(unsigned /* top_block_idx*/ ) {}
59
void on_empty_block(unsigned /* block_idx*/ ) {}
65
/** Base functor class connected for "constant" functors*/
66
class bm_func_base_const
69
bm_func_base_const(const blocks_manager& bman) : bm_(bman) {}
71
void on_empty_top(unsigned /* top_block_idx*/ ) {}
72
void on_empty_block(unsigned /* block_idx*/ ) {}
74
const blocks_manager& bm_;
78
/** Base class for bitcounting functors */
79
class block_count_base : public bm_func_base_const
82
block_count_base(const blocks_manager& bm)
83
: bm_func_base_const(bm) {}
85
bm::id_t block_count(const bm::word_t* block, unsigned idx) const
87
return this->bm_.block_bitcount(block, idx);
92
/** Bitcounting functor */
93
class block_count_func : public block_count_base
96
block_count_func(const blocks_manager& bm)
97
: block_count_base(bm), count_(0) {}
99
bm::id_t count() const { return count_; }
101
void operator()(const bm::word_t* block, unsigned idx)
103
count_ += this->block_count(block, idx);
111
/** Bitcounting functor filling the block counts array*/
112
class block_count_arr_func : public block_count_base
115
block_count_arr_func(const blocks_manager& bm, unsigned* arr)
116
: block_count_base(bm), arr_(arr), last_idx_(0)
121
void operator()(const bm::word_t* block, unsigned idx)
123
while (++last_idx_ < idx)
127
arr_[idx] = this->block_count(block, idx);
131
unsigned last_block() const { return last_idx_; }
138
/** bit value change counting functor */
139
class block_count_change_func : public bm_func_base_const
142
block_count_change_func(const blocks_manager& bm)
143
: bm_func_base_const(bm),
145
prev_block_border_bit_(0)
148
bm::id_t block_count(const bm::word_t* block, unsigned idx)
153
if (IS_FULL_BLOCK(block) || (block == 0))
158
first_bit = block ? 1 : 0;
159
count -= !(prev_block_border_bit_ ^ first_bit);
161
prev_block_border_bit_ = block ? 1 : 0;
165
if (BM_IS_GAP(*this, block, idx))
167
gap_word_t* gap_block = BMGAP_PTR(block);
168
count = gap_length(gap_block) - 1;
171
first_bit = gap_test(gap_block, 0);
172
count -= !(prev_block_border_bit_ ^ first_bit);
175
prev_block_border_bit_ =
176
gap_test(gap_block, gap_max_bits-1);
180
count = bit_block_calc_count_change(block,
181
block + bm::set_block_size);
184
first_bit = block[0] & 1;
185
count -= !(prev_block_border_bit_ ^ first_bit);
187
prev_block_border_bit_ =
188
block[set_block_size-1] >> ((sizeof(block[0]) * 8) - 1);
195
bm::id_t count() const { return count_; }
197
void operator()(const bm::word_t* block, unsigned idx)
199
count_ += block_count(block, idx);
204
bm::id_t prev_block_border_bit_;
208
/** Functor detects if any bit set*/
209
class block_any_func : public bm_func_base_const
212
block_any_func(const blocks_manager& bm)
213
: bm_func_base_const(bm)
216
bool operator()(const bm::word_t* block, unsigned idx)
218
if (IS_FULL_BLOCK(block)) return true;
220
if (BM_IS_GAP(*this, block, idx)) // gap block
222
if (!gap_is_all_zero(BMGAP_PTR(block), bm::gap_max_bits))
229
bm::wordop_t* blk1 = (wordop_t*)block;
231
(wordop_t*)(block + bm::set_block_size);
232
if (!bit_is_all_zero(blk1, blk2))
241
/*! Change GAP level lengths functor */
242
class gap_level_func : public bm_func_base
245
gap_level_func(blocks_manager& bm, const gap_word_t* glevel_len)
247
glevel_len_(glevel_len)
249
BM_ASSERT(glevel_len);
252
void operator()(bm::word_t* block, unsigned idx)
254
blocks_manager& bman = this->bm_;
256
if (!BM_IS_GAP(*this, block, idx))
259
gap_word_t* gap_blk = BMGAP_PTR(block);
261
// TODO: Use the same code as in the optimize functor
262
if (gap_is_all_zero(gap_blk, bm::gap_max_bits))
264
bman.set_block_ptr(idx, 0);
268
if (gap_is_all_one(gap_blk, bm::gap_max_bits))
270
bman.set_block_ptr(idx, FULL_BLOCK_ADDR);
272
bman.get_allocator().free_gap_block(gap_blk,
274
bman.set_block_bit(idx);
278
unsigned len = gap_length(gap_blk);
279
int level = gap_calc_level(len, glevel_len_);
283
bman.get_allocator().alloc_bit_block();
284
bman.set_block_ptr(idx, blk);
285
bman.set_block_bit(idx);
286
gap_convert_to_bitset(blk, gap_blk);
290
gap_word_t* gap_blk_new =
291
bman.allocate_gap_block(level, gap_blk, glevel_len_);
293
bm::word_t* p = (bm::word_t*) gap_blk_new;
295
bman.set_block_ptr(idx, p);
297
bman.get_allocator().free_gap_block(gap_blk, bman.glen());
301
const gap_word_t* glevel_len_;
305
/*! Bitblock optimization functor */
306
class block_opt_func : public bm_func_base
309
block_opt_func(blocks_manager& bm,
310
bm::word_t* temp_block,
312
bv_statistics* bv_stat=0)
314
temp_block_(temp_block),
319
BM_ASSERT(temp_block);
322
void on_empty_top(unsigned i)
324
bm::word_t*** blk_root = this->bm_.get_rootblock();
325
bm::word_t** blk_blk = blk_root[i];
328
this->bm_.get_allocator().free_ptr(blk_blk);
333
stat_->max_serialize_mem += sizeof(unsigned) + 1;
336
void on_empty_block(unsigned /* block_idx*/ ) { ++empty_; }
338
void operator()(bm::word_t* block, unsigned idx)
340
blocks_manager& bman = this->bm_;
341
if (IS_FULL_BLOCK(block))
349
stat_->max_serialize_mem += empty_ << 2;
354
if (BM_IS_GAP(*this, block, idx)) // gap block
356
gap_blk = BMGAP_PTR(block);
357
// check if block is empty (or all 1)
358
if (gap_is_all_zero(gap_blk, bm::gap_max_bits))
360
bman.set_block_ptr(idx, 0);
361
this->free_block(gap_blk, idx);
365
if (gap_is_all_one(gap_blk, bm::gap_max_bits))
367
bman.set_block_ptr(idx, FULL_BLOCK_ADDR);
368
this->free_block(gap_blk, idx);
373
// regular gap block - compute statistics
376
stat_->add_gap_block(
377
bm::gap_capacity(gap_blk, bman.glen()),
378
bm::gap_length(gap_blk));
384
if (opt_mode_ < 3) // free_01 optimization
386
bm::wordop_t* blk1 = (wordop_t*)block;
388
(wordop_t*)(block + bm::set_block_size);
390
bool b = bit_is_all_zero(blk1, blk2);
393
bman.get_allocator().free_bit_block(block);
394
bman.set_block_ptr(idx, 0);
398
if (opt_mode_ == 2) // check if it is all 1 block
400
b = is_bits_one(blk1, blk2);
403
bman.get_allocator().free_bit_block(block);
404
bman.set_block_ptr(idx, FULL_BLOCK_ADDR);
410
stat_->add_bit_block();
417
gap_word_t* tmp_gap_blk = (gap_word_t*)temp_block_;
418
*tmp_gap_blk = bm::gap_max_level << 1;
420
unsigned threashold = bman.glen(bm::gap_max_level)-4;
422
unsigned len = bit_convert_to_gap(tmp_gap_blk,
426
if (len) // compression successful
428
bman.get_allocator().free_bit_block(block);
430
// check if new gap block can be eliminated
431
if (gap_is_all_zero(tmp_gap_blk, bm::gap_max_bits))
433
bman.set_block_ptr(idx, 0);
436
else if (gap_is_all_one(tmp_gap_blk, bm::gap_max_bits))
438
bman.set_block_ptr(idx, FULL_BLOCK_ADDR);
443
int level = bm::gap_calc_level(len, bman.glen());
446
bman.allocate_gap_block(level, tmp_gap_blk);
447
bman.set_block_ptr(idx, (bm::word_t*)gap_blk);
448
bman.set_block_gap(idx);
451
stat_->add_gap_block(
452
bm::gap_capacity(gap_blk, bman.glen()),
453
bm::gap_length(gap_blk));
457
else // non-compressable bit-block
460
stat_->add_bit_block();
465
void free_block(gap_word_t* gap_blk, unsigned idx)
467
this->bm_.get_allocator().free_gap_block(gap_blk,
469
this->bm_.set_block_bit(idx);
473
bm::word_t* temp_block_;
475
bv_statistics* stat_;
479
/** Bitblock invert functor */
480
class block_invert_func : public bm_func_base
483
block_invert_func(blocks_manager& bm)
484
: bm_func_base(bm) {}
486
void operator()(bm::word_t* block, unsigned idx)
490
this->bm_.set_block(idx, FULL_BLOCK_ADDR);
493
if (IS_FULL_BLOCK(block))
495
this->bm_.set_block_ptr(idx, 0);
499
if (BM_IS_GAP(*this, block, idx)) // gap block
501
gap_invert(BMGAP_PTR(block));
505
bm::wordop_t* wrd_ptr = (wordop_t*) block;
506
bm::wordop_t* wrd_end =
507
(wordop_t*) (block + bm::set_block_size);
508
bit_invert(wrd_ptr, wrd_end);
515
/** Set block zero functor */
516
class block_zero_func : public bm_func_base
519
block_zero_func(blocks_manager& bm, bool free_mem)
524
void operator()(bm::word_t* block, unsigned idx)
526
blocks_manager& bman = this->bm_;
527
if (IS_FULL_BLOCK(block))
529
bman.set_block_ptr(idx, 0);
533
if (BM_IS_GAP(*this, block, idx))
535
gap_set_all(BMGAP_PTR(block), bm::gap_max_bits, 0);
541
bman.get_allocator().free_bit_block(block);
542
bman.set_block_ptr(idx, 0);
546
bit_block_set(block, 0);
552
bool free_mem_; //!< If "true" frees bitblocks memsets to '0'
555
/** Fill block with all-one bits functor */
556
class block_one_func : public bm_func_base
559
block_one_func(blocks_manager& bm) : bm_func_base(bm) {}
561
void operator()(bm::word_t* block, unsigned idx)
563
if (!IS_FULL_BLOCK(block))
565
this->bm_.set_block_all_set(idx);
570
/** Block deallocation functor */
571
class block_free_func : public bm_func_base
574
block_free_func(blocks_manager& bm) : bm_func_base(bm) {}
576
void operator()(bm::word_t* block, unsigned idx)
578
blocks_manager& bman = this->bm_;
579
if (BM_IS_GAP(bman, block, idx)) // gap block
581
bman.get_allocator().free_gap_block(BMGAP_PTR(block),
586
bman.get_allocator().free_bit_block(block);
591
/** Block copy functor */
592
class block_copy_func : public bm_func_base
595
block_copy_func(blocks_manager& bm_target,
596
const blocks_manager& bm_src)
597
: bm_func_base(bm_target),
601
void operator()(bm::word_t* block, unsigned idx)
603
bool is_gap = bm_src_.is_block_gap(idx);
606
blocks_manager& bman = this->bm_;
610
bm::gap_word_t* gap_block = BMGAP_PTR(block);
611
unsigned level = gap_level(gap_block);
612
new_blk = (bm::word_t*)
613
bman.get_allocator().alloc_gap_block(level,
615
int len = gap_length(BMGAP_PTR(block));
616
::memcpy(new_blk, gap_block, len * sizeof(gap_word_t));
617
//BMSET_PTRGAP(new_blk);
621
if (IS_FULL_BLOCK(block))
627
new_blk = bman.get_allocator().alloc_bit_block();
628
bit_block_copy(new_blk, block);
631
bman.set_block(idx, new_blk, is_gap);
635
const blocks_manager& bm_src_;
641
blocks_manager(const gap_word_t* glevel_len,
643
const Alloc& alloc = Alloc())
647
::memcpy(glevel_len_, glevel_len, sizeof(glevel_len_));
651
top_block_size_ = compute_top_block_size(max_bits);
652
// allocate first level descr. of blocks
653
blocks_ = (bm::word_t***) alloc_.alloc_ptr(top_block_size_);
654
::memset(blocks_, 0, top_block_size_ * sizeof(bm::word_t**));
661
volatile const char* vp = _copyright<true>::_p;
664
effective_top_block_size_ = 1;
667
blocks_manager(const blocks_manager& blockman)
669
top_block_size_(blockman.top_block_size_),
670
effective_top_block_size_(blockman.effective_top_block_size_),
671
#ifdef BM_DISBALE_BIT_IN_PTR
672
gap_flags_(blockman.gap_flags_),
675
alloc_(blockman.alloc_)
677
::memcpy(glevel_len_, blockman.glevel_len_, sizeof(glevel_len_));
679
blocks_ = (bm::word_t***)alloc_.alloc_ptr(top_block_size_);
680
::memset(blocks_, 0, top_block_size_ * sizeof(bm::word_t**));
683
const_cast<blocks_manager*>(&blockman);
685
word_t*** blk_root = bm->blocks_root();
687
block_copy_func copy_func(*this, blockman);
688
for_each_nzblock(blk_root, top_block_size_,
689
bm::set_array_size, copy_func);
694
alloc_.free_bit_block(temp_block_);
698
void free_ptr(bm::word_t** ptr)
700
if (ptr) alloc_.free_ptr(ptr);
704
\brief Compute size of the block array needed to store bits
705
\param bits_to_store - supposed capacity (number of bits)
706
\return size of the top level block
708
unsigned compute_top_block_size(bm::id_t bits_to_store)
710
if (bits_to_store == bm::id_max) // working in full-range mode
712
return bm::set_array_size;
715
unsigned top_block_size =
716
bits_to_store / (bm::set_block_size * sizeof(bm::word_t) *
717
bm::set_array_size * 8);
718
if (top_block_size < bm::set_array_size) ++top_block_size;
719
return top_block_size;
723
Returns current capacity (bits)
725
bm::id_t capacity() const
727
// arithmetic overflow protection...
728
return top_block_size_ == bm::set_array_size ? bm::id_max :
729
top_block_size_ * bm::set_array_size * bm::bits_in_block;
733
\brief Finds block in 2-level blocks array
734
\param nb - Index of block (logical linear number)
735
\return block adress or NULL if not yet allocated
737
bm::word_t* get_block(unsigned nb) const
739
unsigned block_idx = nb >> bm::set_array_shift;
740
if (block_idx >= top_block_size_)
744
bm::word_t** blk_blk = blocks_[block_idx];
745
return blk_blk ? blk_blk[nb & bm::set_array_mask] : 0;
749
\brief Finds block in 2-level blocks array
750
Specilized version of get_block(unsigned), returns an additional
751
condition when there are no more blocks
753
\param nb - Index of block (logical linear number)
754
\param no_more_blocks - 1 if there are no more blocks at all
755
\return block adress or NULL if not yet allocated
757
bm::word_t* get_block(unsigned nb, int* no_more_blocks) const
759
unsigned block_idx = nb >> bm::set_array_shift;
760
if (block_idx >= top_block_size_)
766
bm::word_t** blk_blk = blocks_[block_idx];
767
return blk_blk ? blk_blk[nb & bm::set_array_mask] : 0;
771
Recalculate absolute block address into coordinates
773
void get_block_coord(unsigned nb, unsigned* i, unsigned* j) const
778
*i = nb >> bm::set_array_shift; // top block address
779
*j = nb & bm::set_array_mask; // address in sub-block
782
bool is_no_more_blocks(unsigned nb) const
785
get_block_coord(nb, &i, &j);
786
for (;i < effective_top_block_size_; ++i)
788
bm::word_t** blk_blk = blocks_[i];
791
nb += bm::set_array_size;
794
for (;j < bm::set_array_size; ++j, ++nb)
796
bm::word_t* blk = blk_blk[j];
797
if (blk && !is_block_zero(nb, blk))
808
\brief Finds block in 2-level blocks array
809
\param i - top level block index
810
\param j - second level block index
811
\return block adress or NULL if not yet allocated
813
const bm::word_t* get_block(unsigned i, unsigned j) const
815
if (i >= top_block_size_) return 0;
816
const bm::word_t* const* blk_blk = blocks_[i];
817
return (blk_blk == 0) ? 0 : blk_blk[j];
821
\brief Function returns top-level block in 2-level blocks array
822
\param i - top level block index
823
\return block adress or NULL if not yet allocated
825
const bm::word_t* const * get_topblock(unsigned i) const
827
return (i >= top_block_size_) ? 0 : blocks_[i];
831
\brief Returns root block in the tree.
833
bm::word_t*** get_rootblock() const
836
const_cast<blocks_manager*>(this);
837
return bm->blocks_root();
840
void set_block_all_set(unsigned nb)
842
bm::word_t* block = this->get_block(nb);
843
set_block(nb, const_cast<bm::word_t*>(FULL_BLOCK_ADDR));
845
// If we keep block type flag in pointer itself we dp not need
847
#ifdef BM_DISBALE_BIT_IN_PTR
851
if (BM_IS_GAP(*this, block, nb))
853
alloc_.free_gap_block(BMGAP_PTR(block), glevel_len_);
857
alloc_.free_bit_block(block);
862
Create all-zeros bit block. Old block (if exists) is deleted.
864
bm::word_t* make_bit_block(unsigned nb)
866
bm::word_t* block = this->get_allocator().alloc_bit_block();
867
bit_block_set(block, 0);
868
bm::word_t* old_block = set_block(nb, block);
869
if (IS_VALID_ADDR(old_block))
871
if (BM_IS_GAP(*this, old_block, nb))
873
alloc_.free_gap_block(BMGAP_PTR(old_block), glen());
877
alloc_.free_bit_block(old_block);
884
Function checks if block is not yet allocated, allocates it and sets to
885
all-zero or all-one bits.
887
If content_flag == 1 (ALLSET block) requested and taken block is already ALLSET,
888
function will return NULL
890
initial_block_type and actual_block_type : 0 - bitset, 1 - gap
892
bm::word_t* check_allocate_block(unsigned nb,
893
unsigned content_flag,
894
int initial_block_type,
895
int* actual_block_type,
896
bool allow_null_ret=true)
898
bm::word_t* block = this->get_block(nb);
900
if (!IS_VALID_ADDR(block)) // NULL block or ALLSET
902
// if we wanted ALLSET and requested block is ALLSET return NULL
903
unsigned block_flag = IS_FULL_BLOCK(block);
904
*actual_block_type = initial_block_type;
905
if (block_flag == content_flag && allow_null_ret)
907
return 0; // it means nothing to do for the caller
910
if (initial_block_type == 0) // bitset requested
912
block = alloc_.alloc_bit_block();
913
// initialize block depending on its previous status
914
bit_block_set(block, block_flag ? 0xFF : 0);
915
set_block(nb, block);
917
else // gap block requested
919
bm::gap_word_t* gap_block = allocate_gap_block(0);
920
gap_set_all(gap_block, bm::gap_max_bits, block_flag);
921
set_block(nb, (bm::word_t*)gap_block, true/*gap*/);
922
return (bm::word_t*)gap_block;
925
else // block already exists
927
*actual_block_type = BM_IS_GAP((*this), block, nb);
933
/*! @brief Fills all blocks with 0.
934
@param free_mem - if true function frees the resources
936
void set_all_zero(bool free_mem)
938
block_zero_func zero_func(*this, free_mem);
939
for_each_nzblock(blocks_, top_block_size_,
940
bm::set_array_size, zero_func);
943
/*! Replaces all blocks with ALL_ONE block.
947
block_one_func func(*this);
948
for_each_block(blocks_, top_block_size_,
949
bm::set_array_size, func);
953
Places new block into descriptors table, returns old block's address.
954
Old block is not deleted.
956
bm::word_t* set_block(unsigned nb, bm::word_t* block)
958
bm::word_t* old_block;
961
register unsigned nblk_blk = nb >> bm::set_array_shift;
963
// auto-resize the top block array
964
if (nblk_blk >= top_block_size_)
965
reserve_top_blocks(nblk_blk + 1);
966
if (nblk_blk >= effective_top_block_size_)
967
effective_top_block_size_ = nblk_blk + 1;
969
// If first level array not yet allocated, allocate it and
970
// assign block to it
971
if (blocks_[nblk_blk] == 0)
973
blocks_[nblk_blk] = (bm::word_t**)alloc_.alloc_ptr();
974
::memset(blocks_[nblk_blk], 0,
975
bm::set_array_size * sizeof(bm::word_t*));
981
old_block = blocks_[nblk_blk][nb & bm::set_array_mask];
984
// NOTE: block will be replaced without freeing,
985
// potential memory leak may lay here....
986
blocks_[nblk_blk][nb & bm::set_array_mask] = block; // equivalent to %
992
Places new block into descriptors table, returns old block's address.
993
Old block is not deleted.
995
bm::word_t* set_block(unsigned nb, bm::word_t* block, bool gap)
997
bm::word_t* old_block;
1003
#ifdef BM_DISBALE_BIT_IN_PTR
1006
block = (bm::word_t*)BMPTR_SETBIT0(block);
1011
#ifdef BM_DISBALE_BIT_IN_PTR
1012
gap_flags_.set(nb, false);
1014
block = (bm::word_t*)BMPTR_CLEARBIT0(block);
1020
register unsigned nblk_blk = nb >> bm::set_array_shift;
1022
// auto-resize the top block array
1023
if (nblk_blk >= top_block_size_)
1024
reserve_top_blocks(nblk_blk + 1);
1025
if (nblk_blk >= effective_top_block_size_)
1026
effective_top_block_size_ = nblk_blk + 1;
1028
// If first level array not yet allocated, allocate it and
1029
// assign block to it
1030
if (blocks_[nblk_blk] == 0)
1032
blocks_[nblk_blk] = (bm::word_t**)alloc_.alloc_ptr();
1033
::memset(blocks_[nblk_blk], 0,
1034
bm::set_array_size * sizeof(bm::word_t*));
1040
old_block = blocks_[nblk_blk][nb & bm::set_array_mask];
1043
// NOTE: block will be replaced without freeing,
1044
// potential memory leak may lay here....
1045
blocks_[nblk_blk][nb & bm::set_array_mask] = block; // equivalent to %
1051
Places new block into blocks table.
1053
void set_block_ptr(unsigned nb, bm::word_t* block)
1055
BM_ASSERT((nb >> bm::set_array_shift) < effective_top_block_size_);
1056
blocks_[nb >> bm::set_array_shift][nb & bm::set_array_mask] = block;
1060
\brief Converts block from type gap to conventional bitset block.
1061
\param nb - Block's index.
1062
\param gap_block - Pointer to the gap block,
1063
if NULL block nb will be taken
1064
\return new bit block's memory
1066
bm::word_t* convert_gap2bitset(unsigned nb, gap_word_t* gap_block=0)
1068
bm::word_t* block = this->get_block(nb);
1071
gap_block = BMGAP_PTR(block);
1074
BM_ASSERT(IS_VALID_ADDR((bm::word_t*)gap_block));
1075
BM_ASSERT(is_block_gap(nb)); // must be GAP type
1077
bm::word_t* new_block = alloc_.alloc_bit_block();
1079
gap_convert_to_bitset(new_block, gap_block);
1081
// new block will replace the old one(no deletion)
1082
set_block_ptr(nb, new_block);
1084
alloc_.free_gap_block(BMGAP_PTR(block), glen());
1086
// If GAP flag is in block pointer no need to clean the gap bit twice
1087
#ifdef BM_DISBALE_BIT_IN_PTR
1095
Make sure block turns into true bit-block if it is GAP or a full block
1097
bm::word_t* deoptimize_block(unsigned nb)
1099
bm::word_t* block = this->get_block(nb);
1100
if (BM_IS_GAP(*this, block, nb))
1102
return convert_gap2bitset(nb);
1104
if (IS_FULL_BLOCK(block))
1106
bm::word_t* new_block = get_allocator().alloc_bit_block();
1107
bit_block_copy(new_block, block);
1108
set_block(nb, new_block);
1115
Free block, make it zero pointer in the tree
1117
bm::word_t* zero_block(unsigned nb)
1119
bm::word_t* block = this->get_block(nb);
1120
if (!block) return block;
1121
if (BM_IS_GAP(*this, block, nb)) // gap block
1123
get_allocator().free_gap_block(BMGAP_PTR(block), glen());
1127
// deallocates only valid pointers
1128
get_allocator().free_bit_block(block);
1135
Count number of bits ON in the block
1137
bm::id_t block_bitcount(const bm::word_t* block, unsigned idx) const
1140
if (!block) return count;
1141
if (IS_FULL_BLOCK(block))
1142
count = bm::bits_in_block;
1145
if (BM_IS_GAP(*this, block, idx))
1147
count = gap_bit_count(BMGAP_PTR(block));
1152
bit_block_calc_count(block,
1153
block + bm::set_block_size);
1160
\brief Extends GAP block to the next level or converts it to bit block.
1161
\param nb - Block's linear index.
1162
\param blk - Blocks's pointer
1164
void extend_gap_block(unsigned nb, gap_word_t* blk)
1166
unsigned level = bm::gap_level(blk);
1167
unsigned len = bm::gap_length(blk);
1168
if (level == bm::gap_max_level || len >= gap_max_buff_len)
1170
convert_gap2bitset(nb);
1174
bm::word_t* new_blk = (bm::word_t*)allocate_gap_block(++level, blk);
1176
BMSET_PTRGAP(new_blk);
1178
set_block_ptr(nb, new_blk);
1179
alloc_.free_gap_block(blk, glen());
1183
bool is_block_gap(unsigned nb) const
1185
#ifdef BM_DISBALE_BIT_IN_PTR
1186
return gap_flags_.test(nb)!=0;
1188
bm::word_t* block = get_block(nb);
1189
return BMPTR_TESTBIT0(block) != 0;
1193
void set_block_bit(unsigned nb)
1195
#ifdef BM_DISBALE_BIT_IN_PTR
1196
gap_flags_.set(nb, false);
1198
bm::word_t* block = get_block(nb);
1199
block = (bm::word_t*) BMPTR_CLEARBIT0(block);
1200
set_block_ptr(nb, block);
1204
void set_block_gap(unsigned nb)
1206
#ifdef BM_DISBALE_BIT_IN_PTR
1209
bm::word_t* block = get_block(nb);
1210
block = (bm::word_t*)BMPTR_SETBIT0(block);
1211
set_block_ptr(nb, block);
1216
\fn bool bm::bvector::blocks_manager::is_block_zero(unsigned nb, bm::word_t* blk)
1217
\brief Checks all conditions and returns true if block consists of only 0 bits
1218
\param nb - Block's linear index.
1219
\param blk - Blocks's pointer
1220
\returns true if all bits are in the block are 0.
1222
bool is_block_zero(unsigned nb, const bm::word_t* blk) const
1224
if (blk == 0) return true;
1226
if (BM_IS_GAP(*this, blk, nb)) // GAP
1228
gap_word_t* b = BMGAP_PTR(blk);
1229
return gap_is_all_zero(b, bm::gap_max_bits);
1233
for (unsigned i = 0; i < bm::set_block_size; ++i)
1242
\brief Checks if block has only 1 bits
1243
\param nb - Index of the block.
1244
\param blk - Block's pointer
1245
\return true if block consists of 1 bits.
1247
bool is_block_one(unsigned nb, const bm::word_t* blk) const
1249
if (blk == 0) return false;
1251
if (BM_IS_GAP(*this, blk, nb)) // GAP
1253
gap_word_t* b = BMGAP_PTR(blk);
1254
return gap_is_all_one(b, bm::gap_max_bits);
1259
if (IS_FULL_BLOCK(blk))
1263
return is_bits_one((wordop_t*)blk,
1264
(wordop_t*)(blk + bm::set_block_size));
1267
/*! Returns temporary block, allocates if needed. */
1268
bm::word_t* check_allocate_tempblock()
1270
return temp_block_ ? temp_block_
1271
: (temp_block_ = alloc_.alloc_bit_block());
1274
/*! Assigns new GAP lengths vector */
1275
void set_glen(const gap_word_t* glevel_len)
1277
::memcpy(glevel_len_, glevel_len, sizeof(glevel_len_));
1281
bm::gap_word_t* allocate_gap_block(unsigned level,
1282
gap_word_t* src = 0,
1283
const gap_word_t* glevel_len = 0)
1286
glevel_len = glevel_len_;
1287
gap_word_t* ptr = alloc_.alloc_gap_block(level, glevel_len);
1290
unsigned len = gap_length(src);
1291
::memcpy(ptr, src, len * sizeof(gap_word_t));
1292
// Reconstruct the mask word using the new level code.
1293
*ptr = ((len-1) << 3) | (level << 1) | (*src & 1);
1302
unsigned mem_used() const
1304
unsigned mem_used = sizeof(*this);
1305
mem_used += temp_block_ ? sizeof(word_t) * bm::set_block_size : 0;
1306
mem_used += sizeof(bm::word_t**) * top_block_size_;
1308
#ifdef BM_DISBALE_BIT_IN_PTR
1309
mem_used += gap_flags_.mem_used() - sizeof(gap_flags_);
1312
for (unsigned i = 0; i < top_block_size_; ++i)
1314
mem_used += blocks_[i] ? sizeof(void*) * bm::set_array_size : 0;
1320
/** Returns true if second level block pointer is 0.
1322
bool is_subblock_null(unsigned nsub) const
1324
return blocks_[nsub] == NULL;
1328
bm::word_t*** blocks_root()
1333
/*! \brief Returns current GAP level vector
1335
const gap_word_t* glen() const
1340
/*! \brief Returns GAP level length for specified level
1341
\param level - level number
1343
unsigned glen(unsigned level) const
1345
return glevel_len_[level];
1348
/*! \brief Swaps content
1349
\param bm another blocks manager
1351
void swap(blocks_manager& bm)
1353
BM_ASSERT(this != &bm);
1355
word_t*** btmp = blocks_;
1356
blocks_ = bm.blocks_;
1359
#ifdef BM_DISBALE_BIT_IN_PTR
1360
gap_flags_.swap(bm.gap_flags_);
1363
xor_swap(this->top_block_size_, bm.top_block_size_);
1364
xor_swap(this->effective_top_block_size_, bm.effective_top_block_size_);
1366
BM_ASSERT(sizeof(glevel_len_) / sizeof(glevel_len_[0])
1367
== bm::gap_levels); // paranoiya check
1368
for (unsigned i = 0; i < bm::gap_levels; ++i)
1370
xor_swap(glevel_len_[i], bm.glevel_len_[i]);
1374
/*! \brief Returns size of the top block array in the tree
1376
unsigned top_block_size() const
1378
return top_block_size_;
1381
/*! \brief Returns effective size of the top block array in the tree
1382
Effective size excludes NULL pointers at the top descriptor end
1384
unsigned effective_top_block_size() const
1386
return effective_top_block_size_;
1388
unsigned i = top_block_size();
1390
for (--i; i > 0; --i)
1392
if (blocks_[i] != 0)
1394
if (this->effective_top_block_size_ < i+1)
1396
printf("Effective size error!\n");
1402
BM_ASSERT(this->effective_top_block_size_ >= 1);
1409
\brief reserve capacity for specified number of bits
1411
void reserve(unsigned max_bits)
1415
unsigned b = compute_top_block_size(max_bits);
1416
reserve_top_blocks(b);
1421
\brief Make sure blocks manager has enough blocks capacity
1423
void reserve_top_blocks(unsigned top_blocks)
1425
BM_ASSERT(top_blocks <= bm::set_array_size);
1426
if (top_blocks <= top_block_size_) return; // nothing to do
1427
bm::word_t*** new_blocks =
1428
(bm::word_t***)alloc_.alloc_ptr(top_blocks);
1430
for (unsigned i = 0; i < top_block_size_; ++i)
1432
new_blocks[i] = blocks_[i];
1434
for (unsigned j = top_block_size_; j < top_blocks; ++j)
1438
alloc_.free_ptr(blocks_, top_block_size_);
1439
blocks_ = new_blocks;
1440
top_block_size_ = top_blocks;
1443
/** \brief Returns reference on the allocator
1445
allocator_type& get_allocator() { return alloc_; }
1447
/** \brief Returns allocator
1449
allocator_type get_allocator() const { return alloc_; }
1453
void operator =(const blocks_manager&);
1457
if (blocks_ == 0) return;
1458
unsigned top_size = this->effective_top_block_size();
1459
block_free_func free_func(*this);
1460
for_each_nzblock(blocks_, top_size,
1461
bm::set_array_size, free_func);
1463
for(unsigned i = 0; i < top_size; ++i)
1465
bm::word_t** blk_blk = blocks_[i];
1467
alloc_.free_ptr(blk_blk);
1469
alloc_.free_ptr(blocks_, top_block_size_);
1474
bm::word_t*** blocks_;
1475
/// Size of the top level block array in blocks_ tree
1476
unsigned top_block_size_;
1477
/// Effective size of the top level block array in blocks_ tree
1478
unsigned effective_top_block_size_;
1479
#ifdef BM_DISBALE_BIT_IN_PTR
1480
/// mini bitvector used to indicate gap blocks
1484
bm::word_t* temp_block_;
1485
/// vector defines gap block lengths for different levels
1486
gap_word_t glevel_len_[bm::gap_levels];
1488
allocator_type alloc_;
1492
Bit block buffer guard
1495
template<class BlocksManager>
1496
class bit_block_guard
1499
bit_block_guard(BlocksManager& bman, bm::word_t* blk=0)
1505
bman_.get_allocator().free_bit_block(block_);
1507
void attach(bm::word_t* blk)
1509
bman_.get_allocator().free_bit_block(block_);
1512
bm::word_t* allocate()
1514
attach(bman_.get_allocator().alloc_bit_block());
1517
bm::word_t* get() { return block_; }
1519
BlocksManager& bman_;