BitMagic-C++
bm.h
Go to the documentation of this file.
1#ifndef BM__H__INCLUDED__
2#define BM__H__INCLUDED__
3/*
4Copyright(c) 2002-2019 Anatoliy Kuznetsov(anatoliy_kuznetsov at yahoo.com)
5
6Licensed under the Apache License, Version 2.0 (the "License");
7you may not use this file except in compliance with the License.
8You may obtain a copy of the License at
9
10 http://www.apache.org/licenses/LICENSE-2.0
11
12Unless required by applicable law or agreed to in writing, software
13distributed under the License is distributed on an "AS IS" BASIS,
14WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15See the License for the specific language governing permissions and
16limitations under the License.
17
18For more information please visit: http://bitmagic.io
19*/
20
21/*! \file bm.h
22 \brief Compressed bit-vector bvector<> container, set algebraic methods, traversal iterators
23*/
24
25
26// define BM_NO_STL if you use BM in "STL free" environment and want
27// to disable any references to STL headers
28#ifndef BM_NO_STL
29# include <iterator>
30# include <initializer_list>
31# include <stdexcept>
32#endif
33
34#include <limits.h>
35
36#ifdef _MSC_VER
37#pragma warning( push )
38#pragma warning( disable : 4311 4312 4127)
39#endif
40
41
42#include "bmdef.h"
43#include "bmconst.h"
44#include "bmsimd.h"
45#include "bmfwd.h"
46
47# define BM_DECLARE_TEMP_BLOCK(x) bm::bit_block_t x;
48
49#include "bmfunc.h"
50#include "encoding.h"
51#include "bmalloc.h"
52#include "bmblocks.h"
53#include "bmbuffer.h"
54#include "bmdef.h"
55
56#include "bmrs.h"
57
58extern "C"
59{
60#ifdef BM64ADDR
61 typedef int (*bit_visitor_callback_type)(void* handle_ptr, bm::id64_t bit_idx);
62#else
63 /**
64 Callback type to visit (callback style) bits in bit-vector(s)
65
66 @param handle_ptr - custom pointer to callback specific data
67 @param bit_idx - number/index of visited bit
68 @return negative return code is recognised as a request to interrupt visiting
69
70 @ingroup bvector
71 */
72 typedef int (*bit_visitor_callback_type)(void* handle_ptr, bm::id_t bit_idx);
73#endif
74}
75
76
77namespace bm
78{
79
80/** @defgroup bmagic BitMagic Library
81 BitMagic C++ Library
82 For more information please visit: http://bitmagic.io
83*/
84
85
86/** @defgroup bvector bvector<> container
87 The Main bvector<> Group
88 bvector<> template: front end of the BitMagic library.
89
90 @ingroup bmagic
91*/
92
93/** @defgroup bvit bvector<> iterators
94 Iterators for compressed bit-vector traversal
95 @ingroup bvector
96*/
97
98
99
100#ifdef BM64ADDR
102#else
104#endif
105
106
107/*!
108 @brief Bitvector
109 Bit-vector container with runtime compression of bits
110
111 @ingroup bvector
112*/
113template<class Alloc>
115{
116public:
117 typedef Alloc allocator_type;
118 typedef typename allocator_type::allocator_pool_type allocator_pool_type;
119 typedef blocks_manager<Alloc> blocks_manager_type;
120 typedef typename blocks_manager_type::block_idx_type block_idx_type;
122
123 /** Statistical information about bitset's memory allocation details. */
124 struct statistics : public bv_statistics
125 {};
126
127 /*!
128 \brief Optimization mode
129 Every next level means additional checks (better compression vs time)
130 \sa optimize
131 */
133 {
134 opt_none = 0, ///< no optimization
135 opt_free_0 = 1, ///< Free unused 0 blocks
136 opt_free_01 = 2, ///< Free unused 0 and 1 blocks
137 opt_compress = 3 ///< compress blocks when possible (GAP/prefix sum)
138 };
139
140
141 /**
142 @brief Class reference implements an object for bit assignment.
143 Since C++ does not provide with build-in bit type supporting l-value
144 operations we have to emulate it.
145
146 @ingroup bvector
147 */
149 {
150 public:
152 : bv_(bv),
153 position_(position)
154 {}
155
157 : bv_(ref.bv_),
158 position_(ref.position_)
159 {
160 bv_.set(position_, ref.bv_.get_bit(position_));
161 }
162
163 operator bool() const BMNOEXCEPT
164 {
165 return bv_.get_bit(position_);
166 }
167
168 const reference& operator=(const reference& ref) const
169 {
170 bv_.set(position_, (bool)ref);
171 return *this;
172 }
173
174 const reference& operator=(bool value) const BMNOEXCEPT
175 {
176 bv_.set(position_, value);
177 return *this;
178 }
179
180 bool operator==(const reference& ref) const BMNOEXCEPT
181 {
182 return bool(*this) == bool(ref);
183 }
184
185 /*! Bitwise AND. Performs operation: bit = bit AND value */
186 const reference& operator&=(bool value) const
187 {
188 bv_.set_bit_and(position_, value);
189 return *this;
190 }
191
192 /*! Bitwise OR. Performs operation: bit = bit OR value */
193 const reference& operator|=(bool value) const
194 {
195 if (value != bv_.get_bit(position_))
196 {
197 bv_.set_bit(position_);
198 }
199 return *this;
200 }
201
202 /*! Bitwise exclusive-OR (XOR). Performs operation: bit = bit XOR value */
203 const reference& operator^=(bool value) const
204 {
205 bv_.set(position_, value != bv_.get_bit(position_));
206 return *this;
207 }
208
209 /*! Logical Not operator */
211 {
212 return !bv_.get_bit(position_);
213 }
214
215 /*! Bit Not operator */
217 {
218 return !bv_.get_bit(position_);
219 }
220
221 /*! Negates the bit value */
223 {
224 bv_.flip(position_);
225 return *this;
226 }
227
228 private:
229 bvector<Alloc>& bv_; //!< Reference variable on the parent.
230 size_type position_; //!< Position in the parent bitvector.
231 };
232
233 typedef bool const_reference;
234
235 /*!
236 @brief Base class for all iterators.
237 @ingroup bvit
238 */
240 {
241 friend class bvector;
242 public:
244 : bv_(0), position_(bm::id_max), block_(0), block_type_(0),
245 block_idx_(0)
246 {}
247
248 bool operator==(const iterator_base& it) const BMNOEXCEPT
249 {
250 return (position_ == it.position_) && (bv_ == it.bv_);
251 }
252
253 bool operator!=(const iterator_base& it) const BMNOEXCEPT
254 {
255 return ! operator==(it);
256 }
257
259 {
260 return position_ < it.position_;
261 }
262
264 {
265 return position_ <= it.position_;
266 }
267
269 {
270 return position_ > it.position_;
271 }
272
274 {
275 return position_ >= it.position_;
276 }
277
278 /**
279 \fn bool bm::bvector::iterator_base::valid() const
280 \brief Checks if iterator is still valid. Analog of != 0 comparison for pointers.
281 \returns true if iterator is valid.
282 */
283 bool valid() const BMNOEXCEPT { return position_ != bm::id_max; }
284
285 /**
286 \fn bool bm::bvector::iterator_base::invalidate()
287 \brief Turns iterator into an invalid state.
288 */
290 { position_ = bm::id_max; block_type_ = ~0u;}
291
292 /** \brief Compare FSMs for testing purposes
293 \internal
294 */
296 {
297 if (this->bv_ != ib.bv_) return false;
298 if (this->position_ != ib.position_) return false;
299 if (this->block_ != ib.block_) return false;
300 if (this->block_type_ != ib.block_type_) return false;
301 if (this->block_idx_ != ib.block_idx_) return false;
302
303 const block_descr& bd = this->bdescr_;
304 const block_descr& ib_db = ib.bdescr_;
305
306 if (this->block_type_ == 0) // bit block
307 {
308 if (bd.bit_.ptr != ib_db.bit_.ptr) return false;
309 if (bd.bit_.idx != ib_db.bit_.idx) return false;
310 if (bd.bit_.cnt != ib_db.bit_.cnt) return false;
311 if (bd.bit_.pos != ib_db.bit_.pos) return false;
312 for (unsigned i = 0; i < bd.bit_.cnt; ++i)
313 {
314 if (bd.bit_.bits[i] != ib_db.bit_.bits[i]) return false;
315 }
316 }
317 else // GAP block
318 {
319 if (bd.gap_.ptr != ib_db.gap_.ptr) return false;
320 if (bd.gap_.gap_len != ib_db.gap_.gap_len) return false;
321 }
322 return true;
323 }
324
325 public:
326
327 /** Bit-block descriptor
328 @internal
329 */
331 {
332 const bm::word_t* ptr; //!< Word pointer.
333 unsigned char bits[set_bitscan_wave_size*32]; //!< bit list
334 unsigned short idx; //!< Current position in the bit list
335 unsigned short cnt; //!< Number of ON bits
336 size_type pos; //!< Last bit position decode before
337 };
338
339 /** Information about current DGAP block.
340 @internal
341 */
343 {
344 const gap_word_t* ptr; //!< Word pointer.
345 gap_word_t gap_len; //!< Current dgap length.
346 };
347
348 protected:
349 bm::bvector<Alloc>* bv_; //!< Pointer on parent bitvector
350 size_type position_; //!< Bit position (bit idx)
351 const bm::word_t* block_; //!< Block pointer.(NULL-invalid)
352 unsigned block_type_; //!< Type of block. 0-Bit, 1-GAP
353 block_idx_type block_idx_; //!< Block index
354
355 /*! Block type dependent information for current block. */
357 {
358 bitblock_descr bit_; //!< BitBlock related info.
359 dgap_descr gap_; //!< DGAP block related info.
361 };
362
363 /*!
364 @brief Output iterator iterator designed to set "ON" bits based on
365 input sequence of integers (bit indeces).
366
367 STL container can be converted to bvector using this iterator
368 Insert iterator guarantees the vector will be dynamically resized
369 (set_bit does not do that).
370
371 @note
372 If you have many bits to set it is a good idea to use output iterator
373 instead of explicitly calling set, because iterator may implement
374 some performance specific tricks to make sure bulk insert is fast.
375
376 @sa bulk_insert_iterator
377
378 @ingroup bvit
379 */
381 {
383 public:
384#ifndef BM_NO_STL
385 typedef std::output_iterator_tag iterator_category;
386#endif
389 typedef void difference_type;
390 typedef void pointer;
391 typedef void reference;
392
394
396 : bvect_(&bvect),
398 {
399 bvect_->init();
400 }
401
403 : bvect_(iit.bvect_),
404 max_bit_(iit.max_bit_)
405 {
406 }
407
409 {
410 bvect_ = ii.bvect_; max_bit_ = ii.max_bit_;
411 return *this;
412 }
413
415 {
417 BM_ASSERT_THROW(n < bm::id_max, BM_ERR_RANGE);
418
419 if (n >= max_bit_)
420 {
421 max_bit_ = n;
422 if (n >= bvect_->size())
423 {
424 size_type new_size = (n == bm::id_max) ? bm::id_max : n + 1;
425 bvect_->resize(new_size);
426 }
427 }
429 return *this;
430 }
431 /*! Returns *this without doing anything (no-op) */
432 insert_iterator& operator*() { return *this; }
433 /*! Returns *this. This iterator does not move (no-op) */
434 insert_iterator& operator++() { return *this; }
435 /*! Returns *this. This iterator does not move (no-op)*/
436 insert_iterator& operator++(int) { return *this; }
437
438 bvector_type* get_bvector() const { return bvect_; }
439
440 protected:
443 };
444
445
446 /*!
447 @brief Output iterator iterator designed to set "ON" bits based on
448 input sequence of integers.
449
450 STL container can be converted to bvector using this iterator
451 Insert iterator guarantees the vector will be dynamically resized
452 (set_bit does not do that).
453
454 The difference from the canonical insert iterator, is that
455 bulk insert implements internal buffering, which needs
456 to flushed (or flushed automatically when goes out of scope).
457 Buffering creates a delayed effect, which needs to be
458 taken into account.
459
460 @sa insert_iterator
461
462 @ingroup bvit
463 */
465 {
466 public:
467#ifndef BM_NO_STL
468 typedef std::output_iterator_tag iterator_category;
469#endif
473 typedef void difference_type;
474 typedef void pointer;
475 typedef void reference;
476
478 : bvect_(0), buf_(0), buf_size_(0), sorted_(BM_UNKNOWN) {}
479
481 {
482 flush();
483 if (buf_)
484 bvect_->blockman_.get_allocator().free_bit_block((bm::word_t*)buf_);
485 }
486
489 : bvect_(&bvect), sorted_(so)
490 {
491 bvect_->init();
492
493 buf_ = (value_type*) bvect_->blockman_.get_allocator().alloc_bit_block();
494 buf_size_ = 0;
495 }
496
498 : bvect_(iit.bvect_)
499 {
500 buf_ = bvect_->blockman_.get_allocator().alloc_bit_block();
501 buf_size_ = iit.buf_size_;
502 sorted_ = iit.sorted_;
503 ::memcpy(buf_, iit.buf_, buf_size_ * sizeof(*buf_));
504 }
505
507 : bvect_(iit.get_bvector())
508 {
509 buf_ = (value_type*) bvect_->blockman_.get_allocator().alloc_bit_block();
510 buf_size_ = 0;
512 }
513
515 : bvect_(iit.bvect_)
516 {
517 buf_ = iit.buf_; iit.buf_ = 0;
518 buf_size_ = iit.buf_size_;
519 sorted_ = iit.sorted_;
520 }
521
523 {
524 bvect_ = ii.bvect_;
525 if (!buf_)
526 buf_ = bvect_->allocate_tempblock();
527 buf_size_ = ii.buf_size_;
528 ::memcpy(buf_, ii.buf_, buf_size_ * sizeof(*buf_));
529 sorted_ = ii.sorted_;
530 return *this;
531 }
532
534 {
535 bvect_ = ii.bvect_;
536 if (buf_)
537 bvect_->free_tempblock(buf_);
538 buf_ = ii.buf_; ii.buf_ = 0;
539 buf_size_ = ii.buf_size_;
540 sorted_ = ii.sorted_;
541 return *this;
542 }
543
545 {
547 BM_ASSERT_THROW(n < bm::id_max, BM_ERR_RANGE);
548
549 if (buf_size_ == buf_size_max())
550 {
552 buf_size_ = 0;
553 }
554 buf_[buf_size_++] = n;
555 return *this;
556 }
557
558 /*! Returns *this without doing anything (no-op) */
559 bulk_insert_iterator& operator*() { return *this; }
560 /*! Returns *this. This iterator does not move (no-op) */
561 bulk_insert_iterator& operator++() { return *this; }
562 /*! Returns *this. This iterator does not move (no-op)*/
563 bulk_insert_iterator& operator++(int) { return *this; }
564
565 /*! Flush the internal buffer into target bvector */
566 void flush()
567 {
569 if (buf_size_)
570 {
572 buf_size_ = 0;
573 }
574 bvect_->sync_size();
575 }
576
578
579 protected:
580 static
582 {
583 #ifdef BM64ADDR
584 return bm::set_block_size / 2;
585 #else
586 return bm::set_block_size;
587 #endif
588 }
589
590 protected:
591 bvector_type* bvect_; ///< target bvector
592 size_type* buf_; ///< bulk insert buffer
593 size_type buf_size_; ///< current buffer size
594 bm::sort_order sorted_; ///< sort order hint
595 };
596
597
598
599 /*! @brief Constant iterator designed to enumerate "ON" bits
600 @ingroup bvit
601 */
603 {
604 public:
605#ifndef BM_NO_STL
606 typedef std::input_iterator_tag iterator_category;
607#endif
609 typedef unsigned difference_type;
610 typedef unsigned* pointer;
611 typedef unsigned& reference;
612
613 public:
615 {}
616
617 /*! @brief Construct enumerator associated with a vector.
618 Important: This construction creates unpositioned iterator with status
619 valid() == false. It can be re-positioned using go_first() or go_to().
620 @sa go_to
621 */
623 : iterator_base()
624 {
625 this->bv_ = const_cast<bvector<Alloc>*>(bv);
626 }
627
628 /*! @brief Construct enumerator for bit vector
629 @param bv bit-vector reference
630 @param pos bit position in the vector
631 if position is 0, it finds the next 1 or becomes not valid
632 (en.valid() == false)
633 */
635 : iterator_base()
636 {
637 this->bv_ = const_cast<bvector<Alloc>*>(&bv);
638 go_to(pos);
639 }
640
641
642 /*! @brief Construct enumerator for bit vector
643 @param bv bit-vector pointer
644 @param pos bit position in the vector
645 if position is 0, it finds the next 1 or becomes not valid
646 (en.valid() == false)
647 */
649 : iterator_base()
650 {
651 this->bv_ = const_cast<bvector<Alloc>*>(bv);
652 this->go_to(pos);
653 }
654
655 /*! \brief Get current position (value) */
656 size_type operator*() const BMNOEXCEPT { return this->position_; }
657
658 /*! \brief Get current position (value) */
659 size_type value() const BMNOEXCEPT { return this->position_; }
660
661 /*! \brief Advance enumerator forward to the next available bit */
662 enumerator& operator++() BMNOEXCEPT { this->go_up(); return *this; }
663
664 /*! \brief Advance enumerator forward to the next available bit.
665 Possibly do NOT use this operator it is slower than the pre-fix increment.
666 */
668 {
669 enumerator tmp = *this;
670 this->go_up();
671 return tmp;
672 }
673
674 /*! \brief Position enumerator to the first available bit */
675 void go_first() BMNOEXCEPT;
676
677 /*! advance iterator forward by one
678 @return true if advance was successfull and the enumerator is valid
679 */
680 bool advance() BMNOEXCEPT { return this->go_up(); }
681
682 /*! \brief Advance enumerator to the next available bit */
683 bool go_up() BMNOEXCEPT;
684
685 /*!
686 @brief Skip to specified relative rank
687 @param rank - number of ON bits to go for (must be: > 0)
688 @return true if skip was successfull and enumerator is valid
689 */
691 {
693 --rank;
694 if (!rank)
695 return this->valid();
696 return skip(rank);
697 }
698
699 /*!
700 @brief Skip specified number of bits from enumeration
701 @param rank - number of ON bits to skip
702 @return true if skip was successfull and enumerator is valid
703 */
704 bool skip(size_type rank) BMNOEXCEPT;
705
706 /*!
707 @brief go to a specific position in the bit-vector (or next)
708 */
709 bool go_to(size_type pos) BMNOEXCEPT;
710
711 private:
712 typedef typename iterator_base::block_descr block_descr_type;
713
714 static bool decode_wave(block_descr_type* bdescr) BMNOEXCEPT;
715 bool decode_bit_group(block_descr_type* bdescr) BMNOEXCEPT;
716 bool decode_bit_group(block_descr_type* bdescr,
718 bool search_in_bitblock() BMNOEXCEPT;
719 bool search_in_gapblock() BMNOEXCEPT;
720 bool search_in_blocks() BMNOEXCEPT;
721
722 };
723
724 /*!
725 @brief Constant iterator designed to enumerate "ON" bits
726 counted_enumerator keeps bitcount, ie number of ON bits starting
727 from the position 0 in the bit string up to the currently enumerated bit
728
729 When increment operator called current position is increased by 1.
730
731 @ingroup bvit
732 */
734 {
735 public:
736#ifndef BM_NO_STL
737 typedef std::input_iterator_tag iterator_category;
738#endif
739 counted_enumerator() BMNOEXCEPT : bit_count_(0){}
740
742 {
743 bit_count_ = this->valid(); // 0 || 1
744 }
745
747 {
748 enumerator* me = this;
749 *me = en;
750 if (this->valid())
751 this->bit_count_ = 1;
752 return *this;
753 }
754
756 {
757 this->go_up();
758 this->bit_count_ += this->valid();
759 return *this;
760 }
761
763 {
764 counted_enumerator tmp(*this);
765 this->go_up();
766 this->bit_count_ += this->valid();
767 return tmp;
768 }
769
770 /*! @brief Number of bits ON starting from the .
771
772 Method returns number of ON bits fromn the bit 0 to the current bit
773 For the first bit in bitvector it is 1, for the second 2
774 */
775 size_type count() const BMNOEXCEPT { return bit_count_; }
776 private:
777 /*! Function closed for usage */
779
780 private:
781 size_type bit_count_;
782 };
783
784 /*!
785 Resource guard for bvector<>::set_allocator_pool()
786 @ingroup bvector
787 @internal
788 */
789 typedef
790 bm::alloc_pool_guard<allocator_pool_type, bvector<Alloc> > mem_pool_guard;
791
792 friend class iterator_base;
793 friend class enumerator;
794 template<class BV> friend class aggregator;
795 template<class BV> friend class operation_deserializer;
796 template<class BV, class DEC> friend class deserializer;
797
798public:
799 /*! @brief memory allocation policy
800
801 Defualt memory allocation policy uses BM_BIT, and standard
802 GAP levels tune-ups
803 */
805 {
808
811 : strat(s), glevel_len(glevels)
812 {}
813 };
814
815 typedef rs_index<allocator_type> blocks_count;
816 typedef rs_index<allocator_type> rs_index_type;
817
818public:
819 /*! @name Construction, initialization, assignment */
820 //@{
821
822 /*!
823 \brief Constructs bvector class
824 \param strat - operation mode strategy,
825 BM_BIT - default strategy, bvector use plain bitset
826 blocks, (performance oriented strategy).
827 BM_GAP - memory effitent strategy, bvector allocates
828 blocks as array of intervals(gaps) and convert blocks
829 into plain bitsets only when enthropy grows.
830 \param glevel_len
831 - pointer on C-style array keeping GAP block sizes.
832 bm::gap_len_table<true>::_len - default value set
833 (use bm::gap_len_table_min<true>::_len for very sparse vectors)
834 (use bm::gap_len_table_nl<true>::_len non-linear GAP growth)
835 \param bv_size
836 - bvector size (number of bits addressable by bvector), bm::id_max means
837 "no limits" (recommended).
838 bit vector allocates this space dynamically on demand.
839 \param alloc - alllocator for this instance
840
841 \sa bm::gap_len_table bm::gap_len_table_min set_new_blocks_strat
842 */
844 const gap_word_t* glevel_len = bm::gap_len_table<true>::_len,
845 size_type bv_size = bm::id_max,
846 const Alloc& alloc = Alloc())
847 : blockman_(glevel_len, bv_size, alloc),
848 new_blocks_strat_(strat),
849 size_(bv_size)
850 {}
851
852 /*!
853 \brief Constructs bvector class
854 */
856 strategy strat = BM_BIT,
857 const gap_word_t* glevel_len = bm::gap_len_table<true>::_len,
858 const Alloc& alloc = Alloc())
859 : blockman_(glevel_len, bv_size, alloc),
860 new_blocks_strat_(strat),
861 size_(bv_size)
862 {}
863
864 /*!
865 \brief Copy constructor
866 */
868 : blockman_(bvect.blockman_),
869 new_blocks_strat_(bvect.new_blocks_strat_),
870 size_(bvect.size_)
871 {}
872
873 /*!
874 \brief Copy constructor for range copy [left..right]
875 \sa copy_range
876 */
878 : blockman_(bvect.blockman_.glevel_len_, bvect.blockman_.max_bits_, bvect.blockman_.alloc_),
879 new_blocks_strat_(bvect.new_blocks_strat_),
880 size_(bvect.size_)
881 {
882 if (!bvect.blockman_.is_init())
883 return;
884 if (left > right)
885 bm::xor_swap(left, right);
886 copy_range_no_check(bvect, left, right);
887 }
888
889 /*!
890 \brief Copy-constructor for mutable/immutable initialization
891 */
893 : blockman_(bvect.blockman_.glevel_len_, bvect.blockman_.max_bits_, bvect.blockman_.alloc_),
894 new_blocks_strat_(bvect.new_blocks_strat_),
895 size_(bvect.size_)
896 {
897 if (!bvect.blockman_.is_init())
898 return;
899 if (is_final == bm::finalization::READONLY)
900 blockman_.copy_to_arena(bvect.blockman_);
901 else
902 blockman_.copy(bvect.blockman_);
903 }
904
905
907 /*!
908 \brief Explicit post-construction initialization.
909 Must be caled to make sure safe use of *_no_check() methods
910 */
911 void init();
912
913 /*!
914 \brief Copy assignment operator
915 */
917 {
918 this->copy(bvect, bm::finalization::UNDEFINED);
919 return *this;
920 }
921
922#ifndef BM_NO_CXX11
923 /*!
924 \brief Move constructor
925 */
927 {
928 blockman_.move_from(bvect.blockman_);
929 size_ = bvect.size_;
930 new_blocks_strat_ = bvect.new_blocks_strat_;
931 }
932
933 /*!
934 \brief Brace constructor
935 */
936 bvector(std::initializer_list<size_type> il)
937 : blockman_(bm::gap_len_table<true>::_len, bm::id_max, Alloc()),
938 new_blocks_strat_(BM_BIT),
939 size_(bm::id_max)
940 {
941 init();
942 std::initializer_list<size_type>::const_iterator it_start = il.begin();
943 std::initializer_list<size_type>::const_iterator it_end = il.end();
944 for (; it_start < it_end; ++it_start)
945 this->set_bit_no_check(*it_start);
946 }
947
948 /*!
949 \brief Move assignment operator
950 */
952 {
953 this->move_from(bvect);
954 return *this;
955 }
956#endif
957
958 /*!
959 \brief Copy bvector from the argument bvector
960 \param bvect - bit-vector to copy from
961 \param is_final - BM_READONLY - copies as immutable, BM_READWRITE - copies as mutable
962 even if the argument bvect is read-only vector,
963 BM_UNDEFINED - follow the argument type as is
964 */
965 void copy(const bvector<Alloc>& bvect, bm::finalization is_final);
966
967 /*!
968 \brief Move bvector content from another bvector
969 */
971
972 /*! \brief Exchanges content of bv and this bvector.
973 */
975
976 /*! \brief Merge/move content from another vector
977
978 Merge performs a logical OR operation, but the source vector
979 is not immutable. Source content gets destroyed (memory moved)
980 to create a union of two vectors.
981 Merge operation can be more efficient than OR if argument is
982 a temporary vector.
983
984 @param bvect - [in, out] - source vector (NOT immutable)
985 */
987
988 //@}
989
991 {
992 if (n >= size_)
993 {
994 size_type new_size = (n == bm::id_max) ? bm::id_max : n + 1;
995 resize(new_size);
996 }
997 return reference(*this, n);
998 }
999
1001 {
1002 BM_ASSERT(n < size_);
1003 return get_bit(n);
1004 }
1005
1006 void operator &= (const bvector<Alloc>& bv) { bit_and(bv); }
1007 void operator ^= (const bvector<Alloc>& bv) { bit_xor(bv); }
1008 void operator |= (const bvector<Alloc>& bv) { bit_or(bv); }
1009 void operator -= (const bvector<Alloc>& bv) { bit_sub(bv); }
1010
1011 bool operator < (const bvector<Alloc>& bv) const { return compare(bv)<0; }
1012 bool operator <= (const bvector<Alloc>& bv) const { return compare(bv)<=0; }
1013 bool operator > (const bvector<Alloc>& bv) const { return compare(bv)>0; }
1014 bool operator >= (const bvector<Alloc>& bv) const { return compare(bv) >= 0; }
1015 bool operator == (const bvector<Alloc>& bv) const BMNOEXCEPT { return equal(bv); }
1016 bool operator != (const bvector<Alloc>& bv) const BMNOEXCEPT { return !equal(bv); }
1017
1018 bvector<Alloc> operator~() const { return bvector<Alloc>(*this).invert(); }
1019
1020 Alloc get_allocator() const
1021 { return blockman_.get_allocator(); }
1022
1023 /// Set allocator pool for local (non-th readed)
1024 /// memory cyclic(lots of alloc-free ops) opertations
1025 ///
1027 { blockman_.get_allocator().set_pool(pool_ptr); }
1028
1029 /// Get curent allocator pool (if set)
1030 /// @return pointer to the current pool or NULL
1032 { return blockman_.get_allocator().get_pool(); }
1033
1034 // --------------------------------------------------------------------
1035 /*! @name Read-only / immutable vector methods */
1036 //@{
1037
1038 /// Turn current vector to read-only (immutable vector).
1039 /// After calling this method any modification (non-const methods) will cause undefined behavior
1040 /// (likely crash or assert)
1041 ///
1042 /// \sa is_ro
1043 void freeze();
1044
1045 /// Returns true if vector is read-only
1046 bool is_ro() const BMNOEXCEPT { return blockman_.arena_; }
1047
1048 //@}
1049
1050 // --------------------------------------------------------------------
1051 /*! @name Bit access/modification methods */
1052 //@{
1053
1054 /*!
1055 \brief Sets bit n.
1056 \param n - index of the bit to be set.
1057 \param val - new bit value
1058 \return TRUE if bit was changed
1059 */
1060 bool set_bit(size_type n, bool val = true);
1061
1062 /*!
1063 \brief Sets bit n using bit AND with the provided value.
1064 \param n - index of the bit to be set.
1065 \param val - new bit value
1066 \return TRUE if bit was changed
1067 */
1068 bool set_bit_and(size_type n, bool val = true);
1069
1070 /*!
1071 \brief Increment the specified element
1072
1073 Bit increment rules:
1074 0 + 1 = 1 (no carry over)
1075 1 + 1 = 0 (with carry over returned)
1076
1077 \param n - index of the bit to be set
1078 \return TRUE if carry over created (1+1)
1079 */
1080 bool inc(size_type n);
1081
1082
1083 /*!
1084 \brief Sets bit n only if current value equals the condition
1085 \param n - index of the bit to be set.
1086 \param val - new bit value
1087 \param condition - expected current value
1088 \return TRUE if bit was changed
1089 */
1090 bool set_bit_conditional(size_type n, bool val, bool condition);
1091
1092 /*!
1093 \brief Sets bit n if val is true, clears bit n if val is false
1094 \param n - index of the bit to be set
1095 \param val - new bit value
1096 \return *this
1097 */
1098 bvector<Alloc>& set(size_type n, bool val = true);
1099
1100 /*!
1101 \brief Sets every bit in this bitset to 1.
1102 \return *this
1103 */
1105
1106 /*!
1107 \brief Set list of bits in this bitset to 1.
1108
1109 Method implements optimized bulk setting of multiple bits at once.
1110 The best results are achieved when the imput comes sorted.
1111 This is equivalent of OR (Set Union), argument set as an array.
1112
1113 @param ids - pointer on array of indexes to set
1114 @param ids_size - size of the input (ids)
1115 @param so - sort order (use BM_SORTED for faster load)
1116
1117 @sa keep, clear
1118 */
1119 void set(const size_type* ids, size_type ids_size,
1121
1122 /*!
1123 \brief Keep list of bits in this bitset, others are cleared
1124
1125 This is equivalent of AND (Set Intersect), argument set as an array.
1126
1127 @param ids - pointer on array of indexes to set
1128 @param ids_size - size of the input (ids)
1129 @param so - sort order (use BM_SORTED for faster load)
1130
1131 @sa set, clear
1132 */
1133 void keep(const size_type* ids, size_type ids_size,
1135
1136 /*!
1137 \brief clear list of bits in this bitset
1138
1139 This is equivalent of AND NOT (Set Substract), argument set as an array.
1140
1141 @param ids - pointer on array of indexes to set
1142 @param ids_size - size of the input (ids)
1143 @param so - sort order (use BM_SORTED for faster load)
1144
1145 @sa set, keep
1146 */
1147 void clear(const size_type* ids, size_type ids_size,
1149
1150
1151 /*!
1152 \brief Set bit without checking preconditions (size, etc)
1153
1154 Fast set bit method, without safety net.
1155 Make sure you call bvector<>::init() before setting bits with this
1156 function.
1157
1158 \param n - bit number
1159 */
1161
1162 /**
1163 \brief Set specified bit without checking preconditions (size, etc)
1164 */
1165 bool set_bit_no_check(size_type n, bool val);
1166
1167 /*!
1168 \brief Sets all bits in the specified closed interval [left,right]
1169 Interval must be inside the bvector's size.
1170 This method DOES NOT resize vector.
1171
1172 \param left - interval start
1173 \param right - interval end (closed interval)
1174 \param value - value to set interval in
1175
1176 \return *this
1177 @sa clear_range
1178 */
1180 size_type right,
1181 bool value = true);
1182
1183
1184 /*!
1185 \brief Sets all bits to zero in the specified closed interval [left,right]
1186 Interval must be inside the bvector's size.
1187 This method DOES NOT resize vector.
1188
1189 \param left - interval start
1190 \param right - interval end (closed interval)
1191
1192 @sa set_range
1193 */
1195 { set_range(left, right, false); }
1196
1197
1198 /*!
1199 \brief Sets all bits to zero outside of the closed interval [left,right]
1200 Expected result: 00000...0[left, right]0....0000
1201
1202 \param left - interval start
1203 \param right - interval end (closed interval)
1204
1205 @sa set_range
1206 */
1207 void keep_range(size_type left, size_type right);
1208
1209 /*!
1210 \brief Copy all bits in the specified closed interval [left,right]
1211
1212 \param bvect - source bit-vector
1213 \param left - interval start
1214 \param right - interval end (closed interval)
1215 */
1216 void copy_range(const bvector<Alloc>& bvect,
1217 size_type left,
1218 size_type right);
1219
1220 /*!
1221 \brief Clears bit n.
1222 \param n - bit's index to be cleaned.
1223 \return true if bit was cleared
1224 */
1225 bool clear_bit(size_type n) { return set_bit(n, false); }
1226
1227 /*!
1228 \brief Clears bit n without precondiion checks
1229 \param n - bit's index to be cleaned.
1230 */
1232
1233 /*!
1234 \brief Clears every bit in the bitvector.
1235
1236 \param free_mem if "true" (default) bvector frees the memory,
1237 otherwise sets blocks to 0.
1238 */
1239 void clear(bool free_mem = true) BMNOEXCEPT;
1240
1241 /*!
1242 \brief Clears every bit in the bitvector.
1243 \return *this;
1244 */
1245 bvector<Alloc>& reset() BMNOEXCEPT { clear(true); return *this; }
1246
1247 /*!
1248 \brief Flips bit n
1249 \return *this
1250 */
1251 bvector<Alloc>& flip(size_type n) { this->inc(n); return *this; }
1252
1253 /*!
1254 \brief Flips all bits
1255 \return *this
1256 @sa invert
1257 */
1258 bvector<Alloc>& flip() { return invert(); }
1259
1260 //@}
1261 // --------------------------------------------------------------------
1262
1263
1264 /*! Function erturns insert iterator for this bitvector */
1266
1267 // --------------------------------------------------------------------
1268 /*! @name Size and capacity
1269 By default bvector is dynamically sized, manual control methods
1270 available
1271 */
1272 //@{
1273
1274 /** \brief Returns bvector's capacity (number of bits it can store) */
1275 //size_type capacity() const { return blockman_.capacity(); }
1276
1277 /*! \brief return current size of the vector (bits) */
1278 size_type size() const BMNOEXCEPT { return size_; }
1279
1280 /*!
1281 \brief Change size of the bvector
1282 \param new_size - new size in bits
1283 */
1284 void resize(size_type new_size);
1285
1286 //@}
1287 // --------------------------------------------------------------------
1288
1289 /*! @name Population counting, ranks, ranges and intervals
1290 */
1291 //@{
1292
1293 /*!
1294 \brief population count (count of ON bits)
1295 \sa count_range
1296 \return Total number of bits ON
1297 */
1298 size_type count() const BMNOEXCEPT;
1299
1300 /*! \brief Computes bitcount values for all bvector blocks
1301 \param arr - pointer on array of block bit counts
1302 \return Index of the last block counted.
1303 This number +1 gives you number of arr elements initialized during the
1304 function call.
1305 */
1306 block_idx_type count_blocks(unsigned* arr) const BMNOEXCEPT;
1307
1308
1309 /*!
1310 \brief Returns count of 1 bits in the given range [left..right]
1311 Uses rank-select index to accelerate the search
1312 \param left - index of first bit start counting from
1313 \param right - index of last bit
1314 \param rs_idx - block count structure to accelerate search
1315 \sa build_rs_index
1316
1317 \return population count in the diapason
1318 */
1320 size_type right,
1321 const rs_index_type& rs_idx) const BMNOEXCEPT;
1322
1323 /*!
1324 \brief Returns count of 1 bits in the given range [left..right]
1325
1326 \param left - index of first bit start counting from
1327 \param right - index of last bit
1328
1329 \return population count in the diapason
1330 @sa count_range_no_check
1331 */
1333
1334 /*!
1335 Returns count of 1 bits in the given range [left..right]
1336 Function expects that caller guarantees that left < right
1337
1338 @sa count_range
1339 */
1341
1342
1343 /*!
1344 Returns count of 1 bits in the given range [left..right]
1345 Function expects that caller guarantees that left < right
1346
1347 @sa count_range
1348 */
1350 size_type right,
1351 const rs_index_type& rs_idx) const BMNOEXCEPT;
1352
1353 /*!
1354 \brief Returns true if all bits in the range are 1s (saturated interval)
1355 Function uses closed interval [left, right]
1356
1357 \param left - index of first bit start checking
1358 \param right - index of last bit
1359
1360 \return true if all bits are 1, false otherwise
1361 @sa any_range, count_range
1362 */
1363 bool is_all_one_range(size_type left, size_type right) const BMNOEXCEPT;
1364
1365 /*!
1366 \brief Returns true if any bits in the range are 1s (non-empty interval)
1367 Function uses closed interval [left, right]
1368
1369 \param left - index of first bit start checking
1370 \param right - index of last bit
1371
1372 \return true if at least 1 bits is set
1373 @sa is_all_one_range, count_range
1374 */
1375 bool any_range(size_type left, size_type right) const BMNOEXCEPT;
1376
1377
1378 /*! \brief compute running total of all blocks in bit vector (rank-select index)
1379 \param rs_idx - [out] pointer to index / count structure
1380 \param bv_blocks - [out] list of block ids in the vector (internal, optional)
1381 Function will fill full array of running totals
1382 \sa count_to, select, find_rank
1383 */
1384 void build_rs_index(rs_index_type* rs_idx, bvector<Alloc>* bv_blocks=0) const;
1385
1386 /*!
1387 \brief Returns count of 1 bits (population) in [0..right] range.
1388
1389 This operation is also known as rank of bit N.
1390
1391 \param n - index of bit to rank
1392 \param rs_idx - rank-select to accelerate search
1393 should be prepared using build_rs_index
1394 \return population count in the range [0..n]
1395 \sa build_rs_index
1396 \sa count_to_test, select, rank, rank_corrected
1397 */
1399 const rs_index_type& rs_idx) const BMNOEXCEPT;
1400
1401
1402 /*!
1403 \brief Returns rank of specified bit position (same as count_to())
1404
1405 \param n - index of bit to rank
1406 \param rs_idx - rank-select index
1407 \return population count in the range [0..n]
1408 \sa build_rs_index
1409 \sa count_to_test, select, rank, rank_corrected
1410 */
1412 const rs_index_type& rs_idx) const BMNOEXCEPT
1413 { return count_to(n, rs_idx); }
1414
1415 /*!
1416 \brief Returns rank corrceted by the requested border value (as -1)
1417
1418 This is rank function (bit-count) minus value of bit 'n'
1419 if bit-n is true function returns rank()-1 if false returns rank()
1420 faster than rank() + test().
1421
1422
1423 \param n - index of bit to rank
1424 \param rs_idx - rank-select index
1425 \return population count in the range [0..n] corrected as -1 by the value of n
1426 \sa build_rs_index
1427 \sa count_to_test, select, rank
1428 */
1430 const rs_index_type& rs_idx) const BMNOEXCEPT;
1431
1432 /*!
1433 \brief popcount in [0..right] range if test(right) == true
1434
1435 This is conditional rank operation, which is faster than test()
1436 plus count_to()
1437
1438 \param n - index of bit to test and rank
1439 \param rs_idx - rank-select index
1440 (block count structure to accelerate search)
1441 should be prepared using build_rs_index()
1442
1443 \return population count in the diapason or 0 if right bit test failed
1444
1445 \sa build_rs_index
1446 \sa count_to
1447 */
1448 size_type
1450 const rs_index_type& rs_idx) const BMNOEXCEPT;
1451
1452
1453 /*! Recalculate bitcount (deprecated)
1454 */
1456
1457 /*!
1458 Disables count cache. (deprecated).
1459 */
1461
1462 //@}
1463
1464 // --------------------------------------------------------------------
1465 /*! @name Bit access (read-only) */
1466 //@{
1467
1468 /*!
1469 \brief returns true if bit n is set and false is bit n is 0.
1470 \param n - Index of the bit to check.
1471 \return Bit value (1 or 0)
1472 */
1473 bool get_bit(size_type n) const BMNOEXCEPT;
1474
1475 /*!
1476 \brief returns true if bit n is set and false is bit n is 0.
1477 \param n - Index of the bit to check.
1478 \return Bit value (1 or 0)
1479 */
1480 bool test(size_type n) const BMNOEXCEPT { return get_bit(n); }
1481
1482 //@}
1483
1484 // --------------------------------------------------------------------
1485 /*! @name bit-shift and insert operations */
1486 //@{
1487
1488 /*!
1489 \brief Shift right by 1 bit, fill with zero return carry out
1490 \return Carry over bit value (1 or 0)
1491 */
1492 bool shift_right();
1493
1494 /*!
1495 \brief Shift left by 1 bit, fill with zero return carry out
1496 \return Carry over bit value (1 or 0)
1497 */
1498 bool shift_left();
1499
1500 /*!
1501 \brief Insert bit into specified position
1502 All the vector content after insert position is shifted right.
1503
1504 \param n - index of the bit to insert
1505 \param value - insert value
1506
1507 \return Carry over bit value (1 or 0)
1508 */
1509 bool insert(size_type n, bool value);
1510
1511 /*!
1512 \brief Erase bit in the specified position
1513 All the vector content after erase position is shifted left.
1514
1515 \param n - index of the bit to insert
1516 */
1517 void erase(size_type n);
1518
1519 //@}
1520
1521 // --------------------------------------------------------------------
1522 /*! @name Check for empty-ness of container */
1523 //@{
1524
1525 /*!
1526 \brief Returns true if any bits in this bitset are set, and otherwise returns false.
1527 \return true if any bit is set
1528 */
1529 bool any() const BMNOEXCEPT;
1530
1531 /*!
1532 \brief Returns true if no bits are set, otherwise returns false.
1533 */
1534 bool none() const BMNOEXCEPT { return !any(); }
1535
1536 /**
1537 \brief Returns true if the set is empty (no bits are set, otherwise returns false)
1538 Please note that this is NOT a size check, it is an empty SET check (absense of 1s)
1539 */
1540 bool empty() const BMNOEXCEPT { return !any(); }
1541
1542 //@}
1543 // --------------------------------------------------------------------
1544
1545 /*! @name Scan and find bits and indexes */
1546 //@{
1547
1548 /*!
1549 \fn bool bvector::find(bm::id_t& pos) const
1550 \brief Finds index of first 1 bit
1551 \param pos - [out] index of the found 1 bit
1552 \return true if search returned result
1553 \sa get_first, get_next, extract_next, find_reverse, find_first_mismatch
1554 */
1555 bool find(size_type& pos) const BMNOEXCEPT;
1556
1557 /*!
1558 \fn bool bvector::find(bm::id_t from, bm::id_t& pos) const
1559 \brief Find index of 1 bit starting from position
1560 \param from - position to start search from, please note that if bit at from position
1561 is set then it will be found, function uses closed interval [from...
1562 \param pos - [out] index of the found 1 bit
1563 \return true if search returned result
1564 \sa get_first, get_next, extract_next, find_reverse, find_first_mismatch
1565 */
1566 bool find(size_type from, size_type& pos) const BMNOEXCEPT;
1567
1568
1569 /*!
1570 \fn bm::id_t bvector::get_first() const
1571 \brief find first 1 bit in vector.
1572 Function may return 0 and this requires an extra check if bit 0 is
1573 actually set or bit-vector is empty
1574
1575 \return Index of the first 1 bit, may return 0
1576 \sa get_next, find, extract_next, find_reverse
1577 */
1579
1580 /*!
1581 \fn bm::id_t bvector::get_next(bm::id_t prev) const
1582 \brief Finds the number of the next bit ON.
1583 \param prev - Index of the previously found bit.
1584 \return Index of the next bit which is ON or 0 if not found.
1585 \sa get_first, find, extract_next, find_reverse
1586 */
1588 { return (++prev == bm::id_max) ? 0 : check_or_next(prev); }
1589
1590 /*!
1591 \fn bm::id_t bvector::extract_next(bm::id_t prev)
1592 \brief Finds the number of the next bit ON and sets it to 0.
1593 \param prev - Index of the previously found bit.
1594 \return Index of the next bit which is ON or 0 if not found.
1595 \sa get_first, get_next, find_reverse
1596 */
1598 {
1599 return (++prev == bm::id_max) ? 0 : check_or_next_extract(prev);
1600 }
1601
1602 /*!
1603 \brief Finds last index of 1 bit
1604 \param pos - [out] index of the last found 1 bit
1605 \return true if search returned result
1606 \sa get_first, get_next, extract_next,
1607 \sa find, find_first_mismatch, find_range
1608 */
1609 bool find_reverse(size_type& pos) const BMNOEXCEPT;
1610
1611 /*!
1612 \brief Reverse finds next(prev) index of 1 bit
1613 \param from - index to search from
1614 \param pos - [out] found position index
1615 (undefined if method returns false)
1616 \return true if search returned result
1617 \sa get_first, get_next, extract_next,
1618 \sa find, find_first_mismatch, find_range
1619 */
1620 bool find_reverse(size_type from, size_type& pos) const BMNOEXCEPT;
1621
1622 /*!
1623 \brief Finds dynamic range of bit-vector [first, last]
1624 \param first - index of the first found 1 bit
1625 \param last - index of the last found 1 bit
1626 \return true if search returned result
1627 \sa get_first, get_next, extract_next, find, find_reverse
1628 */
1629 bool find_range(size_type& first, size_type& last) const BMNOEXCEPT;
1630
1631 /*!
1632 \brief Find bit-vector position for the specified rank(bitcount)
1633
1634 Rank based search, counts number of 1s from specified position until
1635 finds the ranked position relative to start from position.
1636 In other words: range population count between from and pos == rank.
1637
1638 \param rank - rank to find (bitcount)
1639 \param from - start positioon for rank search
1640 \param pos - position with speciefied rank (relative to from position)
1641
1642 \return true if requested rank was found
1643 */
1644 bool find_rank(size_type rank, size_type from,
1645 size_type& pos) const BMNOEXCEPT;
1646
1647 /*!
1648 \brief Find bit-vector position for the specified rank(bitcount)
1649
1650 Rank based search, counts number of 1s from specified position until
1651 finds the ranked position relative to start from position.
1652 In other words: range population count between from and pos == rank.
1653
1654 \param rank - rank to find (bitcount)
1655 \param from - start positioon for rank search
1656 \param pos - position with speciefied rank (relative to from position)
1657 \param rs_idx - rank-select index to accelarate search
1658 (should be prepared using build_rs_index)
1659
1660 \sa build_rs_index, select
1661
1662 \return true if requested rank was found
1663 */
1664 bool find_rank(size_type rank, size_type from, size_type& pos,
1665 const rs_index_type& rs_idx) const BMNOEXCEPT;
1666
1667 /*!
1668 \brief select bit-vector position for the specified rank(bitcount)
1669
1670 Rank based search, counts number of 1s from specified position until
1671 finds the ranked position relative to start from position.
1672 Uses
1673 In other words: range population count between from and pos == rank.
1674
1675 \param rank - rank to find (bitcount)
1676 \param pos - position with speciefied rank (relative to from position) [out]
1677 \param rs_idx - block count structure to accelerate rank search
1678
1679 \sa running_count_blocks, find_rank
1680
1681 \return true if requested rank was found
1682 */
1683 bool select(size_type rank, size_type& pos,
1684 const rs_index_type& rs_idx) const BMNOEXCEPT;
1685
1686 //@}
1687
1688
1689 // --------------------------------------------------------------------
1690 /*! @name Algebra of Sets operations */
1691 //@{
1692
1693 /*!
1694 \brief 3-operand OR : this := bv1 OR bv2
1695 \param bv1 - Argument vector 1
1696 \param bv2 - Argument vector 2
1697 \param opt_mode - optimization compression
1698 (when it is performed on the fly it is faster than a separate
1699 call to optimize()
1700 @sa optimize, bit_or
1701 */
1703 const bm::bvector<Alloc>& bv2,
1704 typename bm::bvector<Alloc>::optmode opt_mode=opt_none);
1705
1706 /*!
1707 \brief 3-operand XOR : this := bv1 XOR bv2
1708 \param bv1 - Argument vector 1
1709 \param bv2 - Argument vector 2
1710 \param opt_mode - optimization compression
1711 (when it is performed on the fly it is faster than a separate
1712 call to optimize()
1713 @sa optimize, bit_xor
1714 */
1716 const bm::bvector<Alloc>& bv2,
1717 typename bm::bvector<Alloc>::optmode opt_mode=opt_none);
1718
1719 /*!
1720 \brief 3-operand AND : this := bv1 AND bv2
1721 \param bv1 - Argument vector 1
1722 \param bv2 - Argument vector 2
1723 \param opt_mode - optimization compression
1724 (when it is performed on the fly it is faster than a separate
1725 call to optimize()
1726 @sa optimize, bit_and
1727 */
1729 const bm::bvector<Alloc>& bv2,
1730 typename bm::bvector<Alloc>::optmode opt_mode=opt_none);
1731
1732
1733 /*!
1734 \brief 3-operand AND where result is ORed into the terget vector : this |= bv1 AND bv2
1735 TARGET := TARGET OR (BV1 AND BV2)
1736
1737 \param bv1 - Argument vector 1
1738 \param bv2 - Argument vector 2
1739 \param opt_mode - optimization compression
1740 (when it is performed on the fly it is faster than a separate
1741 call to optimize()
1742 @sa optimize, bit_and
1743 */
1745 const bm::bvector<Alloc>& bv2,
1746 typename bm::bvector<Alloc>::optmode opt_mode=opt_none);
1747
1748
1749 /*!
1750 \brief 3-operand SUB : this := bv1 MINUS bv2
1751 SUBtraction is also known as AND NOT
1752 \param bv1 - Argument vector 1
1753 \param bv2 - Argument vector 2
1754 \param opt_mode - optimization compression
1755 (when it is performed on the fly it is faster than a separate
1756 call to optimize()
1757 @sa optimize, bit_sub
1758 */
1760 const bm::bvector<Alloc>& bv2,
1761 typename bm::bvector<Alloc>::optmode opt_mode=opt_none);
1762
1763
1764 /*!
1765 \brief 2 operand logical OR
1766 \param bv - Argument vector.
1767 */
1769 {
1770 BM_ASSERT(!is_ro());
1772 return *this;
1773 }
1774
1775 /*!
1776 \brief 2 operand logical AND
1777 \param bv - argument vector
1778 \param opt_mode - set an immediate optimization
1779 */
1781 optmode opt_mode = opt_none)
1782 {
1783 BM_ASSERT(!is_ro());
1784 combine_operation_and(bv, opt_mode);
1785 return *this;
1786 }
1787
1788 /*!
1789 \brief 2 operand logical XOR
1790 \param bv - argument vector.
1791 */
1793 {
1794 BM_ASSERT(!is_ro());
1796 return *this;
1797 }
1798
1799 /*!
1800 \brief 2 operand logical SUB(AND NOT). Also known as MINUS.
1801 \param bv - argument vector.
1802 */
1804 {
1805 BM_ASSERT(!is_ro());
1807 return *this;
1808 }
1809
1810 /*!
1811 \brief Invert/NEG all bits
1812 It should be noted, invert is affected by size()
1813 if size is set - it only inverts [0..size-1] bits
1814 */
1816
1817
1818 /*! \brief perform a set-algebra operation by operation code
1819 */
1821 bm::operation opcode);
1822
1823 /*! \brief perform a set-algebra operation OR
1824 */
1826
1827 /*! \brief perform a set-algebra operation AND
1828 */
1830 optmode opt_mode);
1831
1832 /*! \brief perform a set-algebra operation MINUS (AND NOT)
1833 */
1835
1836 /*! \brief perform a set-algebra operation XOR
1837 */
1839
1840 // @}
1841
1842 // --------------------------------------------------------------------
1843 /*! @name Iterator-traversal methods */
1844 //@{
1845
1846 /**
1847 \brief Returns enumerator pointing on the first non-zero bit.
1848 */
1849 enumerator first() const { return get_enumerator(0); }
1850
1851 /**
1852 \fn bvector::enumerator bvector::end() const
1853 \brief Returns enumerator pointing on the next bit after the last.
1854 */
1856 { return typename bvector<Alloc>::enumerator(this); }
1857
1858 /**
1859 \brief Returns enumerator pointing on specified or the next available bit.
1860 */
1862 { return typename bvector<Alloc>::enumerator(this, pos); }
1863
1864 //@}
1865
1866 // --------------------------------------------------------------------
1867 /*! @name Memory management and compression */
1868
1869 //@{
1870
1871 /*!
1872 @brief Calculates bitvector statistics.
1873
1874 @param st - pointer on statistics structure to be filled in.
1875
1876 Function fills statistics structure containing information about how
1877 this vector uses memory and estimation of max. amount of memory
1878 bvector needs to serialize itself.
1879
1880 @sa statistics
1881 */
1883
1884
1885 /*!
1886 \brief Sets new blocks allocation strategy.
1887 \param strat - Strategy code 0 - bitblocks allocation only.
1888 1 - Blocks mutation mode (adaptive algorithm)
1889 */
1890 void set_new_blocks_strat(strategy strat) { new_blocks_strat_ = strat; }
1891
1892 /*!
1893 \brief Returns blocks allocation strategy.
1894 \return - Strategy code 0 - bitblocks allocation only.
1895 1 - Blocks mutation mode (adaptive algorithm)
1896 \sa set_new_blocks_strat
1897 */
1899 { return new_blocks_strat_; }
1900
1901 /*!
1902 \brief Optimize memory bitvector's memory allocation.
1903
1904 Function analyze all blocks in the bitvector, compresses blocks
1905 with a regular structure, frees some memory. This function is recommended
1906 after a bulk modification of the bitvector using set_bit, clear_bit or
1907 logical operations.
1908
1909 Optionally function can calculate vector post optimization statistics
1910
1911 @param temp_block - externally allocated temp buffer for optimization
1912 BM_DECLARE_TEMP_BLOCK(tb)
1913 if NULL - it will allocated (and de-allocated upon exit)
1914 @param opt_mode - optimization level
1915 @param stat - statistics of memory consumption and serialization
1916 stat can also be computed by calc_stat() but it would require an extra pass
1917
1918 @sa optmode, optimize_gap_size, calc_stat
1919 */
1920 void optimize(bm::word_t* temp_block = 0,
1921 optmode opt_mode = opt_compress,
1922 statistics* stat = 0);
1923
1924 /*!
1925 Run partial vector optimization for the area [left..right] (specified in bit coordinates)
1926
1927 @param left - bit index to optimize from (approximate, rounded up to a nearest block)
1928 @param right - bit index to optimize to
1929 Please note that left and right define range in bit coordinates but later rounded to blocks
1930 @param temp_block - external scratch memory (MUST be pre-allocated)
1931 @param opt_mode - optimization level
1932
1933 @sa optimize
1934 */
1935 void optimize_range(
1936 size_type left, size_type right,
1937 bm::word_t* temp_block,
1938 optmode opt_mode = opt_compress);
1939
1940 /*!
1941 \brief Optimize sizes of GAP blocks
1942
1943 This method runs an analysis to find optimal GAP levels for the
1944 specific vector. Current GAP compression algorithm uses several fixed
1945 GAP sizes. By default bvector uses some reasonable preset.
1946 */
1947 void optimize_gap_size();
1948
1949 /*!
1950 @brief Sets new GAP lengths table. All GAP blocks will be reallocated
1951 to match the new scheme.
1952
1953 @param glevel_len - pointer on C-style array keeping GAP block sizes.
1954 */
1955 void set_gap_levels(const gap_word_t* glevel_len);
1956
1957 /**
1958 Return true if bvector is initialized at all
1959 @internal
1960 */
1961 bool is_init() const BMNOEXCEPT { return blockman_.is_init(); }
1962
1963 /**
1964 Calculate blocks digest vector (for diagnostics purposes)
1965 1 is added if NB is a real, allocated block
1966
1967 @param bv_blocks - [out] bvector of blocks statistics
1968 @internal
1969 */
1970 void fill_alloc_digest(bvector<Alloc>& bv_blocks) const;
1971
1972 //@}
1973
1974 // --------------------------------------------------------------------
1975
1976 /*! @name Comparison */
1977 //@{
1978
1979 /*!
1980 \brief Lexicographical comparison with a bitvector.
1981
1982 Function compares current bitvector with the provided argument
1983 bit by bit and returns -1 if this bitvector less than the argument,
1984 1 - greater, 0 - equal
1985
1986 @return 0 if this == arg, -1 if this < arg, 1 if this > arg
1987 @sa find_first_mismatch
1988 */
1989 int compare(const bvector<Alloc>& bvect) const BMNOEXCEPT;
1990
1991 /*!
1992 \brief Equal comparison with an agr bit-vector
1993 @return true if vectors are identical
1994 */
1996 {
1997 size_type pos;
1998 bool found = find_first_mismatch(bvect, pos);
1999 return !found;
2000 }
2001
2002 /*!
2003 \brief Find index of first bit different between this and the agr vector
2004
2005 @param bvect - argumnet vector to compare with
2006 @param pos - [out] position of the first difference
2007 @param search_to - search limiter [0..to] to avoid overscan
2008 (default: unlimited to the vectors end)
2009
2010 @return true if didfference found, false - both vectors are equivalent
2011 @sa compare
2012 */
2014 size_type& pos,
2015 size_type search_to = bm::id_max
2016 ) const BMNOEXCEPT;
2017
2018 //@}
2019
2020 // --------------------------------------------------------------------
2021 /*! @name Open internals */
2022 //@{
2023
2024 /*!
2025 @internal
2026 */
2028 const bm::word_t* arg_blk,
2029 bool arg_gap,
2030 bm::operation opcode);
2031 /**
2032 \brief get access to memory manager (internal)
2033 Use only if you are BitMagic library
2034 @internal
2035 */
2037 { return blockman_; }
2038
2039 /**
2040 \brief get access to memory manager (internal)
2041 Use only if you are BitMagic library
2042 @internal
2043 */
2045 { return blockman_; }
2046
2047 /**
2048 Import integers (set bits). (Fast, no checks).
2049 @internal
2050 */
2051 void import(const size_type* ids, size_type ids_size,
2052 bm::sort_order sorted_idx);
2053
2054 /**
2055 Import sorted integers (set bits). (Fast, no checks).
2056 @internal
2057 */
2058 void import_sorted(const size_type* ids,
2059 const size_type ids_size, bool opt_flag);
2060
2061 /**
2062 \brief Set range without validity/bounds checking
2063 */
2064 void set_range_no_check(size_type left,
2065 size_type right);
2066 /**
2067 \brief Clear range without validity/bounds checking
2068 */
2070 size_type right);
2071
2072
2073 //@}
2074
2075 static void throw_bad_alloc();
2076
2077protected:
2078 /**
2079 Syncronize size if it got extended due to bulk import
2080 @internal
2081 */
2082 void sync_size();
2083
2084
2085 void import_block(const size_type* ids,
2086 block_idx_type nblock, size_type start, size_type stop);
2087
2088
2089
2091
2092 /// set bit in GAP block with GAP block length control
2093 bool gap_block_set(bm::gap_word_t* gap_blk,
2094 bool val, block_idx_type nblock, unsigned nbit);
2095
2096 /// set bit in GAP block with GAP block length control
2098 bool val, block_idx_type nblock,
2099 unsigned nbit);
2100
2101 /// check if specified bit is 1, and set it to 0
2102 /// if specified bit is 0, scan for the next 1 and returns it
2103 /// if no 1 found returns 0
2105
2106
2107 /**
2108 \brief AND specified bit without checking preconditions (size, etc)
2109 */
2110 bool and_bit_no_check(size_type n, bool val);
2111
2112 bool set_bit_conditional_impl(size_type n, bool val, bool condition);
2113
2114
2116 bool gap,
2117 bm::word_t* blk,
2118 const bm::word_t* arg_blk,
2119 bool arg_gap,
2120 bm::operation opcode);
2121
2122 /**
2123 @return true if block optimization may be needed
2124 */
2125 bool combine_operation_block_or(unsigned i,
2126 unsigned j,
2127 const bm::word_t* arg_blk1,
2128 const bm::word_t* arg_blk2);
2129 bool combine_operation_block_xor(unsigned i,
2130 unsigned j,
2131 const bm::word_t* arg_blk1,
2132 const bm::word_t* arg_blk2);
2133 bool combine_operation_block_and(unsigned i,
2134 unsigned j,
2135 const bm::word_t* arg_blk1,
2136 const bm::word_t* arg_blk2);
2137
2138 bool combine_operation_block_and_or(unsigned i,
2139 unsigned j,
2140 const bm::word_t* arg_blk1,
2141 const bm::word_t* arg_blk2);
2142 bool combine_operation_block_sub(unsigned i,
2143 unsigned j,
2144 const bm::word_t* arg_blk1,
2145 const bm::word_t* arg_blk2);
2146
2147
2148 void combine_operation_block_or(unsigned i,
2149 unsigned j,
2150 bm::word_t* blk,
2151 const bm::word_t* arg_blk);
2152
2153 void combine_operation_block_xor(unsigned i,
2154 unsigned j,
2155 bm::word_t* blk,
2156 const bm::word_t* arg_blk);
2157
2158 void combine_operation_block_and(unsigned i,
2159 unsigned j,
2160 bm::word_t* blk,
2161 const bm::word_t* arg_blk);
2162
2163 void combine_operation_block_sub(unsigned i,
2164 unsigned j,
2165 bm::word_t* blk,
2166 const bm::word_t* arg_blk);
2167
2169 size_type left,
2170 size_type right);
2171
2172private:
2173 /**
2174 \brief Clear outside the range without validity/bounds checking
2175 */
2176 void keep_range_no_check(size_type left,
2177 size_type right);
2178
2179 /**
2180 Compute rank in bit-block using rank-select index
2181 */
2182 static
2183 size_type block_count_to(const bm::word_t* block,
2184 block_idx_type nb,
2185 unsigned nbit_right,
2186 const rs_index_type& rs_idx) BMNOEXCEPT;
2187 /**
2188 Compute rank in GAP block using rank-select index
2189 @param test_set - request to test nbit_right before computing count
2190 (returns 0 if not set)
2191 */
2192 static
2193 size_type gap_count_to(const bm::gap_word_t* gap_block,
2194 block_idx_type nb,
2195 unsigned nbit_right,
2196 const rs_index_type& rs_idx,
2197 bool test_set = false) BMNOEXCEPT;
2198 /**
2199 Return value of first bit in the block
2200 */
2201 bool test_first_block_bit(block_idx_type nb) const BMNOEXCEPT;
2202
2203private:
2204 blocks_manager_type blockman_; //!< bitblocks manager
2205 strategy new_blocks_strat_; //!< block allocation strategy
2206 size_type size_; //!< size in bits
2207};
2208
2209
2210//---------------------------------------------------------------------
2211
2212template<class Alloc>
2213inline bvector<Alloc> operator& (const bvector<Alloc>& bv1,
2214 const bvector<Alloc>& bv2)
2215{
2216 bvector<Alloc> ret;
2217 ret.bit_and(bv1, bv2, bvector<Alloc>::opt_none);
2218 return ret;
2219}
2220
2221//---------------------------------------------------------------------
2222
2223template<class Alloc>
2225 const bvector<Alloc>& bv2)
2226{
2227 bvector<Alloc> ret;
2228 ret.bit_or(bv1, bv2, bvector<Alloc>::opt_none);
2229 return ret;
2230}
2231
2232//---------------------------------------------------------------------
2233
2234template<class Alloc>
2236 const bvector<Alloc>& bv2)
2237{
2238 bvector<Alloc> ret;
2239 ret.bit_xor(bv1, bv2, bvector<Alloc>::opt_none);
2240 return ret;
2241}
2242
2243//---------------------------------------------------------------------
2244
2245template<class Alloc>
2247 const bvector<Alloc>& bv2)
2248{
2249 bvector<Alloc> ret;
2250 ret.bit_sub(bv1, bv2, bvector<Alloc>::opt_none);
2251 return ret;
2252}
2253
2254
2255// -----------------------------------------------------------------------
2256
2257template<typename Alloc>
2259{
2260 BM_ASSERT(!is_ro());
2261 if (!blockman_.is_init())
2262 blockman_.init_tree();
2263}
2264
2265// -----------------------------------------------------------------------
2266
2267template<typename Alloc>
2269{
2270 if (this != &bvect)
2271 {
2272 blockman_.deinit_tree();
2273 switch (is_final)
2274 {
2276 if (bvect.is_ro())
2277 {
2278 blockman_.copy_to_arena(bvect.blockman_);
2279 size_ = bvect.size();
2280 }
2281 else
2282 {
2283 blockman_.copy(bvect.blockman_);
2284 resize(bvect.size());
2285 }
2286 break;
2288 blockman_.copy_to_arena(bvect.blockman_);
2289 size_ = bvect.size();
2290 break;
2292 blockman_.copy(bvect.blockman_);
2293 resize(bvect.size());
2294 break;
2295 default:
2296 BM_ASSERT(0);
2297 break;
2298 } // switch
2299 }
2300}
2301
2302// -----------------------------------------------------------------------
2303
2304template<typename Alloc>
2306{
2307 if (this != &bvect)
2308 {
2309 blockman_.move_from(bvect.blockman_);
2310 size_ = bvect.size_;
2311 new_blocks_strat_ = bvect.new_blocks_strat_;
2312 }
2313}
2314
2315//---------------------------------------------------------------------
2316
2317template<class Alloc>
2319{
2320 BM_ASSERT(!is_ro());
2321 if (!blockman_.is_init())
2322 return; // nothing to do
2323
2324 if (right < left)
2325 bm::xor_swap(left, right);
2326
2327 keep_range_no_check(left, right);
2328}
2329
2330// -----------------------------------------------------------------------
2331
2332template<typename Alloc>
2334 size_type right,
2335 bool value)
2336{
2337 BM_ASSERT(!is_ro());
2338
2339 if (!blockman_.is_init() && !value)
2340 return *this; // nothing to do
2341
2342 if (right < left)
2343 return set_range(right, left, value);
2344
2345 BM_ASSERT_THROW(right < bm::id_max, BM_ERR_RANGE);
2346 if (right >= size_) // this vect shorter than the arg.
2347 {
2348 size_type new_size = (right == bm::id_max) ? bm::id_max : right + 1;
2349 resize(new_size);
2350 }
2351
2352 BM_ASSERT(left <= right);
2353 BM_ASSERT(left < size_);
2354
2355 if (value)
2356 set_range_no_check(left, right);
2357 else
2358 clear_range_no_check(left, right);
2359
2360 return *this;
2361}
2362
2363// -----------------------------------------------------------------------
2364
2365template<typename Alloc>
2367{
2368 if (!blockman_.is_init())
2369 return 0;
2370
2371 word_t*** blk_root = blockman_.top_blocks_root();
2372 BM_ASSERT(blk_root);
2373
2374 size_type cnt = 0;
2375 unsigned top_blocks = blockman_.top_block_size();
2376 for (unsigned i = 0; i < top_blocks; ++i)
2377 {
2378 bm::word_t** blk_blk = blk_root[i];
2379 if (!blk_blk)
2380 {
2381 ++i;
2382 bool found = bm::find_not_null_ptr(blk_root, i, top_blocks, &i);
2383 if (!found)
2384 break;
2385 blk_blk = blk_root[i];
2386 BM_ASSERT(blk_blk);
2387 if (!blk_blk)
2388 break;
2389 }
2390 if ((bm::word_t*)blk_blk == FULL_BLOCK_FAKE_ADDR)
2391 {
2393 continue;
2394 }
2395 unsigned j = 0;
2396 do
2397 {
2398 if (blk_blk[j])
2399 cnt += blockman_.block_bitcount(blk_blk[j]);
2400 if (blk_blk[j+1])
2401 cnt += blockman_.block_bitcount(blk_blk[j+1]);
2402 if (blk_blk[j+2])
2403 cnt += blockman_.block_bitcount(blk_blk[j+2]);
2404 if (blk_blk[j+3])
2405 cnt += blockman_.block_bitcount(blk_blk[j+3]);
2406 j += 4;
2407 } while (j < bm::set_sub_array_size);
2408
2409 } // for i
2410 return cnt;
2411}
2412
2413// -----------------------------------------------------------------------
2414
2415template<typename Alloc>
2417{
2418 word_t*** blk_root = blockman_.top_blocks_root();
2419 if (!blk_root)
2420 return false;
2421 typename blocks_manager_type::block_any_func func(blockman_);
2422 return for_each_nzblock_if(blk_root, blockman_.top_block_size(), func);
2423}
2424
2425// -----------------------------------------------------------------------
2426
2427template<typename Alloc>
2429{
2430 BM_ASSERT(!is_ro());
2431
2432 if (size_ == new_size) return; // nothing to do
2433 if (size_ < new_size) // size grows
2434 {
2435 if (!blockman_.is_init())
2436 blockman_.init_tree();
2437
2438 blockman_.reserve(new_size);
2439 size_ = new_size;
2440 }
2441 else // shrink
2442 {
2443 set_range(new_size, size_ - 1, false); // clear the tail
2444 size_ = new_size;
2445 }
2446}
2447
2448// -----------------------------------------------------------------------
2449
2450template<typename Alloc>
2452{
2453 BM_ASSERT(!is_ro());
2454
2455 if (size_ >= bm::id_max)
2456 return;
2458 bool found = find_reverse(last);
2459 if (found && last >= size_)
2460 resize(last+1);
2461}
2462
2463// -----------------------------------------------------------------------
2464
2465template<typename Alloc>
2467 bvector<Alloc>* bv_blocks) const
2468{
2469 BM_ASSERT(rs_idx);
2470 if (bv_blocks)
2471 {
2472 bv_blocks->clear();
2473 bv_blocks->init();
2474 }
2475
2476 unsigned bcount[bm::set_sub_array_size];
2478
2479 rs_idx->init();
2480 if (!blockman_.is_init())
2481 return;
2482
2483 // resize the RS index to fit the vector
2484 //
2485 size_type last_bit;
2486 bool found = find_reverse(last_bit);
2487 if (!found)
2488 return;
2489 block_idx_type nb = (last_bit >> bm::set_block_shift);
2490 unsigned i0, j0;
2491 bm::get_block_coord(nb, i0, j0);
2492
2493 unsigned real_top_blocks = blockman_.find_real_top_blocks();
2494 unsigned max_top_blocks = blockman_.find_max_top_blocks();
2495 if (nb < (max_top_blocks * bm::set_sub_array_size))
2496 nb = (max_top_blocks * bm::set_sub_array_size);
2497 rs_idx->set_total(nb + 1);
2498 rs_idx->resize(nb + 1);
2499 rs_idx->resize_effective_super_blocks(real_top_blocks);
2500
2501 // index construction
2502 //
2503 BM_ASSERT(max_top_blocks <= blockman_.top_block_size());
2504 bm::word_t*** blk_root = blockman_.top_blocks_root();
2505 for (unsigned i = 0; i < max_top_blocks; ++i)
2506 {
2507 bm::word_t** blk_blk = blk_root[i];
2508 if (!blk_blk)
2509 {
2510 rs_idx->set_null_super_block(i);
2511 continue;
2512 }
2513 if ((bm::word_t*)blk_blk == FULL_BLOCK_FAKE_ADDR)
2514 {
2515 rs_idx->set_full_super_block(i);
2516 if (bv_blocks)
2517 {
2518 size_type nb_from = i * bm::set_sub_array_size;
2519 size_type nb_to = nb_from + bm::set_sub_array_size - 1;
2520 bv_blocks->set_range_no_check(nb_from, nb_to);
2521 }
2522 continue;
2523 }
2524
2525 unsigned j = 0;
2526 do
2527 {
2528 const bm::word_t* block = blk_blk[j];
2529 if (!block)
2530 {
2531 bcount[j] = 0; sub_count[j] = 0;
2532 continue;
2533 }
2534 unsigned local_first, local_second, local_third;
2535 bm::id64_t aux0, aux1; // aux infomation to encode
2536 if (BM_IS_GAP(block))
2537 {
2538 const bm::gap_word_t* const gap_block = BMGAP_PTR(block);
2539 local_first =
2541 local_second =
2542 bm::gap_bit_count_range(gap_block,
2545 local_third =
2546 bm::gap_bit_count_range(gap_block,
2549
2550 // for GAP block calculate borderline positions in GAP
2551 // and value (0|1), save to AUX
2552 //
2553 unsigned is_set;
2554 aux0 = bm::gap_bfind(gap_block, rs3_border0+1, &is_set);
2555 aux0 <<= 1;
2556 if (is_set) aux0 |= 1;
2557 aux1 = bm::gap_bfind(gap_block, rs3_border1+1, &is_set);
2558 aux1 <<= 1;
2559 if (is_set) aux1 |= 1;
2560 }
2561 else
2562 {
2563 block = BLOCK_ADDR_SAN(block); // TODO: optimize FULL
2564 local_first =
2566 local_second =
2570 local_third =
2574 // compute inetrmediate points
2577 }
2578 unsigned cnt = local_first + local_second + local_third;
2579 BM_ASSERT(cnt == blockman_.block_bitcount(block));
2580
2581 bcount[j] = cnt;
2582 if (bv_blocks && cnt)
2583 bv_blocks->set_bit_no_check(i * bm::set_sub_array_size + j);
2584
2585 BM_ASSERT(cnt >= local_first + local_second);
2586 sub_count[j] = bm::id64_t(local_first | (local_second << 16)) |
2587 (aux0 << 32) | (aux1 << 48);
2588
2589 } while (++j < bm::set_sub_array_size);
2590
2591 rs_idx->register_super_block(i, &bcount[0], &sub_count[0]);
2592
2593 } // for i
2594
2595}
2596
2597
2598// -----------------------------------------------------------------------
2599
2600template<typename Alloc>
2603{
2604 bm::word_t*** blk_root = blockman_.top_blocks_root();
2605 if (blk_root == 0)
2606 return 0;
2607 typename blocks_manager_type::block_count_arr_func func(blockman_, &(arr[0]));
2608 bm::for_each_nzblock(blk_root, blockman_.top_block_size(), func);
2609 return func.last_block();
2610}
2611
2612// -----------------------------------------------------------------------
2613
2614#define BM_BORDER_TEST(blk, idx) bool(blk[idx >> bm::set_word_shift] & (1u << (idx & bm::set_word_mask)))
2615
2616
2617#if (defined(BMSSE42OPT) || defined(BMAVX2OPT) || defined(BMAVX512OPT) || \
2618 defined(BMWASMSIMDOPT) || defined(BMNEONOPT))
2619
2620
2621template<typename Alloc>
2623bvector<Alloc>::block_count_to(const bm::word_t* block,
2624 block_idx_type nb,
2625 unsigned nbit_right,
2626 const rs_index_type& rs_idx) BMNOEXCEPT
2627{
2628 BM_ASSERT(IS_VALID_ADDR(block));
2629 size_type c;
2630
2631 bm::id64_t sub = rs_idx.sub_count(nb);
2632 unsigned sub_cnt = unsigned(sub);
2633 unsigned first = sub_cnt & 0xFFFF;
2634 unsigned second = sub_cnt >> 16;
2635
2638
2639
2640 {
2641 unsigned cnt, aux0(bm::gap_word_t(sub >> 32)); (void)cnt; (void)aux0;
2643 unsigned cnt1, aux1(bm::gap_word_t(sub >> 48)); (void)aux1; (void) cnt1;
2645 }
2646
2647
2648 #if defined(BM64_SSE4) || defined(BM64_AVX2) || defined(BM64_AVX512)
2649 const unsigned cutoff_bias = rs3_half_span/8;
2650 #else
2651 const unsigned cutoff_bias = 0;
2652 #endif
2653
2654 unsigned sub_range = rs_idx.find_sub_range(nbit_right);
2655
2656 // evaluate 3 sub-block intervals (and sub-intervals)
2657 // |--------[0]-----*-----[1]----*-----|
2658 switch(sub_range) // sub-range rank calc
2659 {
2660 case 0:
2661 // |--x-----[0]-----------[1]----------|
2662 if (nbit_right <= rs3_border0/2 + cutoff_bias)
2663 {
2664 c = bm::bit_block_calc_count_range<true, false>(block, 0, nbit_right);
2665 }
2666 else
2667 {
2668 // |--------[x]-----------[1]----------|
2669 if (nbit_right == rs3_border0)
2670 {
2671 c = first;
2672 }
2673 else
2674 {
2675 // |------x-[0]-----------[1]----------|
2676 c = bm::bit_block_calc_count_range(block, nbit_right+1,
2677 rs3_border0);
2678 c = first - c;
2679 }
2680 }
2681 break;
2682 case 1:
2683 {
2684 // |--------[0]-x---------[1]----------|
2685 if (nbit_right <= rs3_border0_1 + cutoff_bias)
2686 {
2687 c =
2688 bm::bit_block_calc_count_range<true, false>(block,
2690 nbit_right);
2691 c += first - BM_BORDER_TEST(block, bm::rs3_border0);
2692 }
2693 else
2694 {
2695 unsigned bc_second_range = first + second;
2696 // |--------[0]-----------[x]----------|
2697 if (nbit_right == rs3_border1)
2698 {
2699 c = bc_second_range;
2700 }
2701 else // sub-range processing
2702 {
2703 // |--------[0]--------x--[1]----------|
2704 BM_ASSERT(nbit_right > bm::rs3_border0_1);
2705 unsigned d1 = nbit_right - bm::rs3_border0_1;
2706 unsigned d2 = rs3_border1 - nbit_right;
2707 if (d2 < d1)
2708 {
2709 // |--------[0]----|----x-[1]----------|
2711 nbit_right+1,
2712 rs3_border1);
2713 c = bc_second_range - c;
2714 }
2715 else
2716 {
2717 // |--------[0]----|-x----[1]----------|
2718 c = bm::bit_block_calc_count_range<true, false>(
2719 block,
2721 nbit_right);
2722 unsigned aux0 = bm::gap_word_t(sub >> 32);
2723 c += aux0;
2724 c -= BM_BORDER_TEST(block, bm::rs3_border0_1);
2725 }
2726 }
2727 }
2728 }
2729 break;
2730 case 2:
2731 {
2732 // |--------[0]-----------[1]-x---*----|
2733 if (nbit_right <= rs3_border1_1)
2734 {
2735 unsigned d1 = nbit_right - bm::rs3_border1;
2736 unsigned d2 = (rs3_border1_1 + cutoff_bias) - nbit_right;
2737 if (d1 < d2) // |--------[0]-----------[1]-x---*----|
2738 {
2739 c = bm::bit_block_calc_count_range<true, false>(block,
2741 nbit_right);
2742 c += first + second; //bc_second_range;
2743 c -= BM_BORDER_TEST(block, bm::rs3_border1);
2744 }
2745 else // |--------[0]-----------[1]---x-*----|
2746 {
2747 if (nbit_right == rs3_border1_1)
2748 {
2749 unsigned aux1 = bm::gap_word_t(sub >> 48);
2750 c = aux1;
2751 }
2752 else
2753 {
2755 nbit_right+1,
2757 unsigned aux1 = bm::gap_word_t(sub >> 48);
2758 c = aux1 - c;
2759 }
2760 }
2761 }
2762 else
2763 {
2764 // |--------[0]-----------[1]----------x
2765 if (nbit_right == bm::gap_max_bits-1)
2766 {
2767 c = rs_idx.count(nb);
2768 }
2769 else // sub-range processing
2770 {
2771 // |--------[0]-----------[1]-------x--|
2772 BM_ASSERT(nbit_right > bm::rs3_border1_1);
2773 unsigned d1 = nbit_right - bm::rs3_border1_1;
2774 unsigned d2 = bm::gap_max_bits - nbit_right;
2775 if (d2 < d1)
2776 {
2777 // |--------[0]----------[1]----*---x-|
2779 nbit_right+1,
2781 size_type cnt = rs_idx.count(nb);
2782 c = cnt - c;
2783 }
2784 else
2785 {
2786 // |--------[0]----------[1]----*-x---|
2787 c = bm::bit_block_calc_count_range<true, false>(block,
2789 nbit_right);
2790 unsigned aux1 = bm::gap_word_t(sub >> 48);
2791 c += aux1;
2792 c -= BM_BORDER_TEST(block, bm::rs3_border1_1);
2793 }
2794 }
2795 }
2796 }
2797 break;
2798 default:
2799 BM_ASSERT(0);
2800 c = 0;
2801 } // switch
2802
2803 BM_ASSERT(c == bm::bit_block_calc_count_to(block, nbit_right));
2804 return c;
2805}
2806
2807#else // non-SIMD version
2808
2809template<typename Alloc>
2811bvector<Alloc>::block_count_to(const bm::word_t* block,
2812 block_idx_type nb,
2813 unsigned nbit_right,
2814 const rs_index_type& rs_idx) BMNOEXCEPT
2815{
2816 BM_ASSERT(block);
2817
2818 bm::id64_t sub = rs_idx.sub_count(nb);
2819 unsigned sub_cnt = unsigned(sub);
2820 unsigned first = sub_cnt & 0xFFFF;
2821 unsigned second = sub_cnt >> 16;
2822
2825
2826
2827 {
2828 unsigned cnt, aux0(bm::gap_word_t(sub >> 32)); (void)cnt; (void)aux0;
2830 unsigned cnt1, aux1(bm::gap_word_t(sub >> 48)); (void)aux1; (void) cnt1;
2832 }
2833
2834 size_type c=0;
2835 unsigned sub_choice =
2836 bm::get_nibble(bm::rs_intervals<true>::_c._lut, nbit_right);
2837
2838 switch(sub_choice)
2839 {
2840 case 0:
2841 c = bm::bit_block_calc_count_range<true, false>(block, 0, nbit_right);
2842 break;
2843 case 1:
2844 c = first;
2845 break;
2846 case 2:
2847 c = bm::bit_block_calc_count_range(block, nbit_right+1, rs3_border0);
2848 c = first - c;
2849 break;
2850 case 3:
2851 c = bm::bit_block_calc_count_range<true, false>(block,
2853 nbit_right);
2854 c += first - BM_BORDER_TEST(block, bm::rs3_border0);
2855 break;
2856 case 4:
2857 c = first + second;
2858 break;
2859 case 5:
2860 c = bm::bit_block_calc_count_range(block, nbit_right+1, rs3_border1);
2861 c = first + second - c;
2862 break;
2863 case 6:
2864 c = bm::bit_block_calc_count_range<true, false>(
2865 block,
2867 nbit_right);
2868 c += bm::gap_word_t(sub >> 32); // aux0
2869 c -= BM_BORDER_TEST(block, bm::rs3_border0_1);
2870 break;
2871 case 7:
2872 c = bm::bit_block_calc_count_range<true, false>(block,
2874 nbit_right);
2875 c += first + second; //bc_second_range;
2876 c -= BM_BORDER_TEST(block, bm::rs3_border1);
2877 break;
2878 case 8:
2879 c = bm::gap_word_t(sub >> 48); // aux1;
2880 break;
2881 case 9:
2883 nbit_right+1,
2885 c = bm::gap_word_t(sub >> 48) - c; // aux1 - c
2886 break;
2887 case 10:
2888 c = rs_idx.count(nb);
2889 break;
2890 case 11:
2892 nbit_right+1,
2894 c = rs_idx.count(nb) - c;
2895 break;
2896 case 12:
2897 c = bm::bit_block_calc_count_range<true, false>(block,
2899 nbit_right);
2900 c += bm::gap_word_t(sub >> 48); // aux1;
2901 c -= BM_BORDER_TEST(block, bm::rs3_border1_1);
2902 break;
2903 default:
2904 BM_ASSERT(0);
2905 } // switch
2906 BM_ASSERT(c == bm::bit_block_calc_count_to(block, nbit_right));
2907 return c;
2908}
2909#endif
2910
2911#undef BM_BORDER_TEST
2912
2913// -----------------------------------------------------------------------
2914
2915template<typename Alloc>
2917bvector<Alloc>::gap_count_to(const bm::gap_word_t* gap_block,
2918 block_idx_type nb,
2919 unsigned nbit_right,
2920 const rs_index_type& rs_idx,
2921 bool test_set) BMNOEXCEPT
2922{
2923 BM_ASSERT(gap_block);
2924 size_type c;
2925
2926
2927 if (test_set)
2928 {
2929 bool is_set = bm::gap_test_unr(gap_block, (gap_word_t)nbit_right);
2930 if (!is_set)
2931 return 0;
2932 }
2933/*
2934 {
2935 unsigned len = bm::gap_length(gap_block);
2936 if (len < 64)
2937 {
2938 c = bm::gap_bit_count_to(gap_block, (gap_word_t)nbit_right);
2939 return c;
2940 }
2941 }
2942*/
2943 bm::id64_t sub = rs_idx.sub_count(nb);
2944 if (!sub)
2945 {
2946 c = 0;
2947 BM_ASSERT(c == bm::gap_bit_count_to(gap_block, (gap_word_t)nbit_right));
2948 return c;
2949 }
2950
2951 unsigned sub_cnt = unsigned(sub);
2952 unsigned first = bm::gap_word_t(sub_cnt);
2953 unsigned second = (sub_cnt >> 16);
2954
2955
2957 BM_ASSERT(second == bm::gap_bit_count_range(gap_block, rs3_border0+1, rs3_border1));
2958
2959 // evaluate 3 sub-block intervals
2960 // |--------[0]-----------[1]----------|
2961 const unsigned cutoff_bias = rs3_half_span/8;
2962 unsigned sub_range = rs_idx.find_sub_range(nbit_right);
2963 switch(sub_range) // sub-range rank calc
2964 {
2965 case 0:
2966 // |--x-----[0]-----------[1]----------|
2967 if (nbit_right <= (rs3_border0/2 + cutoff_bias))
2968 {
2969 c = bm::gap_bit_count_to(gap_block,(gap_word_t)nbit_right);
2970 }
2971 else
2972 {
2973 // |--------[x]-----------[1]----------|
2974 if (nbit_right == rs3_border0)
2975 {
2976 c = first;
2977 }
2978 else
2979 {
2980 // |------x-[0]-----------[1]----------|
2981 c =
2982 bm::gap_bit_count_range(gap_block, nbit_right+1, rs3_border0);
2983 c = first - c;
2984 }
2985 }
2986 break;
2987 case 1:
2988 // |--------[0]-x---------[1]----------|
2989 if (nbit_right <= (rs3_border0 + rs3_half_span + cutoff_bias))
2990 {
2991 unsigned aux0 = bm::gap_word_t(sub >> 32);
2992 c = bm::gap_bit_count_range_hint(gap_block,
2993 rs3_border0+1, nbit_right, aux0);
2994 c += first;
2995 }
2996 else
2997 {
2998 // |--------[0]-----------[x]----------|
2999 if (nbit_right == rs3_border1)
3000 {
3001 c = first + second;
3002 }
3003 else
3004 {
3005 // |--------[0]--------x--[1]----------|
3006 c =
3007 bm::gap_bit_count_range(gap_block, nbit_right+1, rs3_border1);
3008 c = first + second - c;
3009 }
3010 }
3011 break;
3012 case 2:
3013 {
3014 // |--------[0]-----------[1]-x--------|
3015 if (nbit_right <= (rs3_border1 + rs3_half_span + cutoff_bias))
3016 {
3017 unsigned aux1 = bm::gap_word_t(sub >> 48);
3018 c = bm::gap_bit_count_range_hint(gap_block,
3019 rs3_border1 + 1, nbit_right, aux1);
3020 c += first + second; // += bc_second_range
3021 }
3022 else
3023 {
3024 // |--------[0]-----------[1]----------x
3025 if (nbit_right == bm::gap_max_bits-1)
3026 {
3027 c = rs_idx.count(nb);
3028 }
3029 else
3030 {
3031 // |--------[0]-----------[1]-------x--|
3032 c = bm::gap_bit_count_range<bm::gap_word_t, true> (gap_block,
3033 nbit_right+1, bm::gap_max_bits-1);
3034 size_type cnt = rs_idx.count(nb);
3035 c = cnt - c;
3036 }
3037 }
3038 }
3039 break;
3040 default:
3041 BM_ASSERT(0);
3042 c = 0;
3043 } // switch
3044
3045 BM_ASSERT(c == bm::gap_bit_count_to(gap_block, (gap_word_t)nbit_right));
3046 return c;
3047}
3048
3049// -----------------------------------------------------------------------
3050
3051template<typename Alloc>
3054 const rs_index_type& rs_idx) const BMNOEXCEPT
3055{
3056 BM_ASSERT(right < bm::id_max);
3057 if (!blockman_.is_init())
3058 return 0;
3059
3060 unsigned nb_right = unsigned(right >> bm::set_block_shift);
3061
3062 // running count of all blocks before target
3063 //
3064 size_type cnt;
3065 if (nb_right >= rs_idx.get_total())
3066 {
3067 cnt = rs_idx.count();
3068 return cnt;
3069 }
3070 cnt = nb_right ? rs_idx.rcount(nb_right-1) : 0;
3071
3072 unsigned i, j;
3073 bm::get_block_coord(nb_right, i, j);
3074 const bm::word_t* block = blockman_.get_block_ptr(i, j);
3075
3076 if (block)
3077 {
3078 size_type c;
3079 unsigned nbit_right = unsigned(right & bm::set_block_mask);
3080 if (BM_IS_GAP(block))
3081 {
3082 const bm::gap_word_t* gap_block = BMGAP_PTR(block);
3083 c = this->gap_count_to(gap_block, nb_right, nbit_right, rs_idx);
3084 }
3085 else
3086 {
3087 if (block == FULL_BLOCK_FAKE_ADDR) // TODO: misses REAL full sometimes
3088 {
3089 return cnt + nbit_right + 1;
3090 }
3091 else // real bit-block
3092 {
3093 c = this->block_count_to(block, nb_right, nbit_right, rs_idx);
3094 }
3095 }
3096 cnt += c;
3097
3098 }
3099 return cnt;
3100}
3101
3102// -----------------------------------------------------------------------
3103
3104template<typename Alloc>
3107 const rs_index_type& rs_idx) const BMNOEXCEPT
3108{
3109 BM_ASSERT(right < bm::id_max);
3110 if (!blockman_.is_init())
3111 return 0;
3112
3113 unsigned nb_right = unsigned(right >> bm::set_block_shift);
3114
3115 unsigned i, j;
3116 bm::get_block_coord(nb_right, i, j);
3117 const bm::word_t* block = blockman_.get_block_ptr(i, j);
3118 if (!block)
3119 return 0;
3120
3121 unsigned nbit_right = unsigned(right & bm::set_block_mask);
3122 size_type cnt = nbit_right + 1; // default for FULL BLOCK
3123 if (BM_IS_GAP(block))
3124 {
3125 bm::gap_word_t *gap_blk = BMGAP_PTR(block);
3126 cnt = gap_count_to(gap_blk, nb_right, nbit_right, rs_idx, true);
3127 if (!cnt)
3128 return cnt;
3129 BM_ASSERT(cnt == bm::gap_bit_count_to(gap_blk, (gap_word_t)nbit_right));
3130 /*
3131 if (bm::gap_test_unr(gap_blk, (gap_word_t)nbit_right))
3132 {
3133 cnt = gap_count_to(gap_blk, nb_right, nbit_right, rs_idx);
3134 BM_ASSERT(cnt == bm::gap_bit_count_to(gap_blk, (gap_word_t)nbit_right));
3135 }
3136 else
3137 return 0;
3138 */
3139 }
3140 else
3141 {
3142 if (block != FULL_BLOCK_FAKE_ADDR)
3143 {
3144 unsigned w = block[nbit_right >> bm::set_word_shift]; // nword
3145 if (w &= (1u << (nbit_right & bm::set_word_mask)))
3146 {
3147 cnt = block_count_to(block, nb_right, nbit_right, rs_idx);
3148 BM_ASSERT(cnt == bm::bit_block_calc_count_to(block, nbit_right));
3149 }
3150 else
3151 return 0;
3152 }
3153 }
3154 cnt += nb_right ? rs_idx.rcount(nb_right - 1) : 0;
3155 return cnt;
3156}
3157
3158// -----------------------------------------------------------------------
3159
3160template<typename Alloc>
3163 const rs_index_type& rs_idx) const BMNOEXCEPT
3164{
3165 BM_ASSERT(right < bm::id_max);
3166 if (!blockman_.is_init())
3167 return 0;
3168
3169 unsigned nblock_right = unsigned(right >> bm::set_block_shift);
3170 unsigned nbit_right = unsigned(right & bm::set_block_mask);
3171
3172 size_type cnt = nblock_right ? rs_idx.rcount(nblock_right - 1) : 0;
3173
3174 unsigned i, j;
3175 bm::get_block_coord(nblock_right, i, j);
3176 const bm::word_t* block = blockman_.get_block_ptr(i, j);
3177
3178 if (!block)
3179 return cnt;
3180
3181 bool gap = BM_IS_GAP(block);
3182 if (gap)
3183 {
3184 cnt += bm::gap_bit_count_to<bm::gap_word_t, true>(
3185 BMGAP_PTR(block), (gap_word_t)nbit_right);
3186 }
3187 else
3188 {
3189 if (block == FULL_BLOCK_FAKE_ADDR)
3190 cnt += nbit_right;
3191 else
3192 {
3193 cnt += block_count_to(block, nblock_right, nbit_right, rs_idx);
3194 unsigned w = block[nbit_right >> bm::set_word_shift] &
3195 (1u << (nbit_right & bm::set_word_mask));
3196 cnt -= bool(w); // rank correction
3197 }
3198 }
3199 return cnt;
3200}
3201
3202
3203// -----------------------------------------------------------------------
3204
3205template<typename Alloc>
3208{
3209 BM_ASSERT(left < bm::id_max && right < bm::id_max);
3210 if (!blockman_.is_init())
3211 return 0;
3212 if (left > right)
3213 bm::xor_swap(left, right);
3214 if (right == bm::id_max)
3215 --right;
3216 return count_range_no_check(left, right);
3217}
3218
3219// -----------------------------------------------------------------------
3220
3221template<typename Alloc>
3224{
3225 size_type cnt = 0;
3226
3227 // calculate logical number of start and destination blocks
3228 block_idx_type nblock_left = (left >> bm::set_block_shift);
3229 block_idx_type nblock_right = (right >> bm::set_block_shift);
3230
3231 unsigned i0, j0;
3232 bm::get_block_coord(nblock_left, i0, j0);
3233 const bm::word_t* block = blockman_.get_block(i0, j0);
3234
3235 bool left_gap = BM_IS_GAP(block);
3236
3237 unsigned nbit_left = unsigned(left & bm::set_block_mask);
3238 unsigned nbit_right = unsigned(right & bm::set_block_mask);
3239
3240 unsigned r =
3241 (nblock_left == nblock_right) ? nbit_right : (bm::bits_in_block-1);
3242
3243 typename blocks_manager_type::block_count_func func(blockman_);
3244
3245 if (block)
3246 {
3247 if ((nbit_left == 0) && (r == (bm::bits_in_block-1))) // whole block
3248 {
3249 func(block);
3250 cnt += func.count();
3251 }
3252 else
3253 {
3254 if (left_gap)
3255 {
3256 cnt += bm::gap_bit_count_range(BMGAP_PTR(block),
3257 (gap_word_t)nbit_left,
3258 (gap_word_t)r);
3259 }
3260 else
3261 {
3262 cnt += bm::bit_block_calc_count_range(block, nbit_left, r);
3263 }
3264 }
3265 }
3266
3267 if (nblock_left == nblock_right) // in one block
3268 return cnt;
3269
3270 // process all full mid-blocks
3271 {
3272 func.reset();
3273 word_t*** blk_root = blockman_.top_blocks_root();
3274 block_idx_type top_blocks_size = blockman_.top_block_size();
3275
3276 bm::for_each_nzblock_range(blk_root, top_blocks_size,
3277 nblock_left+1, nblock_right-1, func);
3278 cnt += func.count();
3279 }
3280
3281 bm::get_block_coord(nblock_right, i0, j0);
3282 block = blockman_.get_block(i0, j0);
3283 bool right_gap = BM_IS_GAP(block);
3284
3285 if (block)
3286 {
3287 if (right_gap)
3288 {
3289 cnt +=
3290 bm::gap_bit_count_to(BMGAP_PTR(block), (gap_word_t)nbit_right);
3291 }
3292 else
3293 {
3294 cnt += bm::bit_block_calc_count_range(block, 0, nbit_right);
3295 }
3296 }
3297 return cnt;
3298}
3299
3300// -----------------------------------------------------------------------
3301
3302template<typename Alloc>
3304 size_type right) const BMNOEXCEPT
3305{
3306 if (!blockman_.is_init())
3307 return false; // nothing to do
3308
3309 if (right < left)
3310 bm::xor_swap(left, right);
3311 if (right == bm::id_max)
3312 --right;
3313 if (left == right)
3314 return test(left);
3315
3316 BM_ASSERT(left < bm::id_max && right < bm::id_max);
3317
3318 block_idx_type nblock_left = (left >> bm::set_block_shift);
3319 block_idx_type nblock_right = (right >> bm::set_block_shift);
3320
3321 unsigned i0, j0;
3322 bm::get_block_coord(nblock_left, i0, j0);
3323 const bm::word_t* block = blockman_.get_block(i0, j0);
3324
3325 if (nblock_left == nblock_right) // hit in the same block
3326 {
3327 unsigned nbit_left = unsigned(left & bm::set_block_mask);
3328 unsigned nbit_right = unsigned(right & bm::set_block_mask);
3329 return bm::block_is_all_one_range(block, nbit_left, nbit_right);
3330 }
3331
3332 // process entry point block
3333 {
3334 unsigned nbit_left = unsigned(left & bm::set_block_mask);
3335 bool all_one = bm::block_is_all_one_range(block,
3336 nbit_left, (bm::gap_max_bits-1));
3337 if (!all_one)
3338 return all_one;
3339 ++nblock_left;
3340 }
3341
3342 // process tail block
3343 {
3344 bm::get_block_coord(nblock_right, i0, j0);
3345 block = blockman_.get_block(i0, j0);
3346 unsigned nbit_right = unsigned(right & bm::set_block_mask);
3347 bool all_one = bm::block_is_all_one_range(block, 0, nbit_right);
3348 if (!all_one)
3349 return all_one;
3350 --nblock_right;
3351 }
3352
3353 // check all blocks in the middle
3354 //
3355 if (nblock_left <= nblock_right)
3356 {
3357 unsigned i_from, j_from, i_to, j_to;
3358 bm::get_block_coord(nblock_left, i_from, j_from);
3359 bm::get_block_coord(nblock_right, i_to, j_to);
3360
3361 bm::word_t*** blk_root = blockman_.top_blocks_root();
3362
3363 for (unsigned i = i_from; i <= i_to; ++i)
3364 {
3365 bm::word_t** blk_blk = blk_root[i];
3366 if (!blk_blk)
3367 return false;
3368 if ((bm::word_t*)blk_blk == FULL_BLOCK_FAKE_ADDR)
3369 continue;
3370
3371 unsigned j = (i == i_from) ? j_from : 0;
3372 unsigned j_limit = (i == i_to) ? j_to+1 : bm::set_sub_array_size;
3373 do
3374 {
3375 bool all_one = bm::check_block_one(blk_blk[j], true);
3376 if (!all_one)
3377 return all_one;
3378 } while (++j < j_limit);
3379 } // for i
3380 }
3381 return true;
3382}
3383
3384// -----------------------------------------------------------------------
3385
3386template<typename Alloc>
3388{
3389 BM_ASSERT(left < bm::id_max && right < bm::id_max);
3390
3391 if (!blockman_.is_init())
3392 return false; // nothing to do
3393
3394 if (right < left)
3395 bm::xor_swap(left, right);
3396 if (right == bm::id_max)
3397 --right;
3398 if (left == right)
3399 return test(left);
3400
3401 block_idx_type nblock_left = (left >> bm::set_block_shift);
3402 block_idx_type nblock_right = (right >> bm::set_block_shift);
3403
3404 unsigned i0, j0;
3405 bm::get_block_coord(nblock_left, i0, j0);
3406 const bm::word_t* block = blockman_.get_block(i0, j0);
3407
3408 if (nblock_left == nblock_right) // hit in the same block
3409 {
3410 unsigned nbit_left = unsigned(left & bm::set_block_mask);
3411 unsigned nbit_right = unsigned(right & bm::set_block_mask);
3412 return bm::block_any_range(block, nbit_left, nbit_right);
3413 }
3414
3415 // process entry point block
3416 {
3417 unsigned nbit_left = unsigned(left & bm::set_block_mask);
3418 bool any_one = bm::block_any_range(block,
3419 nbit_left, (bm::gap_max_bits-1));
3420 if (any_one)
3421 return any_one;
3422 ++nblock_left;
3423 }
3424
3425 // process tail block
3426 {
3427 bm::get_block_coord(nblock_right, i0, j0);
3428 block = blockman_.get_block(i0, j0);
3429 unsigned nbit_right = unsigned(right & bm::set_block_mask);
3430 bool any_one = bm::block_any_range(block, 0, nbit_right);
3431 if (any_one)
3432 return any_one;
3433 --nblock_right;
3434 }
3435
3436 // check all blocks in the middle
3437 //
3438 if (nblock_left <= nblock_right)
3439 {
3440 unsigned i_from, j_from, i_to, j_to;
3441 bm::get_block_coord(nblock_left, i_from, j_from);
3442 bm::get_block_coord(nblock_right, i_to, j_to);
3443
3444 bm::word_t*** blk_root = blockman_.top_blocks_root();
3445 {
3446 block_idx_type top_size = blockman_.top_block_size();
3447 if (i_from >= top_size)
3448 return false;
3449 if (i_to >= top_size)
3450 {
3451 i_to = unsigned(top_size-1);
3452 j_to = bm::set_sub_array_size-1;
3453 }
3454 }
3455
3456 for (unsigned i = i_from; i <= i_to; ++i)
3457 {
3458 bm::word_t** blk_blk = blk_root[i];
3459 if (!blk_blk)
3460 continue;
3461 if ((bm::word_t*)blk_blk == FULL_BLOCK_FAKE_ADDR)
3462 return true;
3463
3464 unsigned j = (i == i_from) ? j_from : 0;
3465 unsigned j_limit = (i == i_to) ? j_to+1 : bm::set_sub_array_size;
3466 do
3467 {
3468 bool any_one = bm::block_any(blk_blk[j]);
3469 if (any_one)
3470 return any_one;
3471 } while (++j < j_limit);
3472 } // for i
3473 }
3474 return false;
3475}
3476
3477// -----------------------------------------------------------------------
3478
3479template<typename Alloc>
3482 size_type right,
3483 const rs_index_type& rs_idx) const BMNOEXCEPT
3484{
3485 if (left > right)
3486 bm::xor_swap(left, right);
3487 BM_ASSERT_THROW(right < bm::id_max, BM_ERR_RANGE);
3488 return count_range_no_check(left, right, rs_idx);
3489}
3490
3491// -----------------------------------------------------------------------
3492
3493template<typename Alloc>
3496 size_type right,
3497 const rs_index_type& rs_idx) const BMNOEXCEPT
3498{
3499 BM_ASSERT(left <= right);
3500 if (left == right)
3501 return this->test(left);
3502 size_type cnt_l, cnt_r;
3503 if (left)
3504 cnt_l = this->count_to(left-1, rs_idx);
3505 else
3506 cnt_l = left; // == 0
3507 cnt_r = this->count_to(right, rs_idx);
3508 BM_ASSERT(cnt_r >= cnt_l);
3509 return cnt_r - cnt_l;
3510}
3511
3512// -----------------------------------------------------------------------
3513
3514template<typename Alloc>
3516{
3517 BM_ASSERT(!is_ro());
3518
3519 if (!size_)
3520 return *this; // cannot invert a set of power 0
3521
3522 unsigned top_blocks = blockman_.reserve_top_blocks(bm::set_top_array_size);
3523 bm::word_t*** blk_root = blockman_.top_blocks_root();
3524 for (unsigned i = 0; i < top_blocks; ++i)
3525 {
3526 bm::word_t** blk_blk = blk_root[i];
3527 if (!blk_blk)
3528 {
3529 blk_root[i] = (bm::word_t**)FULL_BLOCK_FAKE_ADDR;
3530 continue;
3531 }
3532 if (blk_blk == (bm::word_t**)FULL_BLOCK_FAKE_ADDR)
3533 {
3534 blk_root[i] = 0;
3535 continue;
3536 }
3537 unsigned j = 0; bm::word_t* blk;
3538 do
3539 {
3540 blk = blk_blk[j];
3541 if (!blk)
3542 blockman_.set_block_ptr(i, j, FULL_BLOCK_FAKE_ADDR);
3543 else
3544 if (IS_FULL_BLOCK(blk))
3545 blockman_.set_block_ptr(i, j, 0);
3546 else
3547 {
3548 if (BM_IS_GAP(blk))
3550 else
3551 bm::bit_invert((wordop_t*)blk);
3552 }
3553 } while (++j < bm::set_sub_array_size);
3554 } // for i
3555
3556 if (size_ == bm::id_max)
3558 else
3560
3561 return *this;
3562}
3563
3564// -----------------------------------------------------------------------
3565
3566template<typename Alloc>
3568{
3569 BM_ASSERT(n < size_);
3570 BM_ASSERT_THROW((n < size_), BM_ERR_RANGE);
3571
3572 // calculate logical block number
3573 unsigned nb = unsigned(n >> bm::set_block_shift);
3574 unsigned i, j;
3575 bm::get_block_coord(nb, i, j);
3576
3577 if (!blockman_.top_blocks_ || i >= blockman_.top_block_size_)
3578 return false;
3579
3580 const bm::word_t* const* blk_blk = blockman_.top_blocks_[i];
3581 if ((bm::word_t*)blk_blk == FULL_BLOCK_FAKE_ADDR)
3582 return true;
3583 if (!blk_blk) return false;
3584 if (const bm::word_t* block = blk_blk[j])
3585 {
3586 if (block == FULL_BLOCK_FAKE_ADDR)
3587 return true;
3588 unsigned nbit = unsigned(n & bm::set_block_mask);
3589 if (BM_IS_GAP(block))
3590 return bm::gap_test_unr(BMGAP_PTR(block), nbit);
3591 return block[nbit >> bm::set_word_shift] &
3592 (1u << (nbit & bm::set_word_mask));
3593 }
3594 return false;
3595}
3596
3597// -----------------------------------------------------------------------
3598
3599template<typename Alloc>
3601 optmode opt_mode,
3602 statistics* stat)
3603{
3604 BM_ASSERT(!is_ro());
3605
3606 if (!blockman_.is_init())
3607 {
3608 if (stat)
3609 calc_stat(stat);
3610 return;
3611 }
3612 if (!temp_block)
3613 temp_block = blockman_.check_allocate_tempblock();
3614
3615 if (stat)
3616 {
3617 stat->reset();
3618 ::memcpy(stat->gap_levels,
3619 blockman_.glen(), sizeof(gap_word_t) * bm::gap_levels);
3620 stat->max_serialize_mem = (unsigned)sizeof(bm::id_t) * 4;
3621 }
3622 blockman_.optimize_tree(temp_block, opt_mode, stat);
3623 if (stat)
3624 {
3625 blockman_.stat_correction(stat);
3626 stat->memory_used += (unsigned)(sizeof(*this) - sizeof(blockman_));
3627 }
3628
3629 // don't need to keep temp block if we optimizing memory usage
3630 blockman_.free_temp_block();
3631}
3632
3633// -----------------------------------------------------------------------
3634
3635template<typename Alloc>
3637 size_type left,
3638 size_type right,
3639 bm::word_t* temp_block,
3640 optmode opt_mode)
3641{
3642 BM_ASSERT(!is_ro());
3643 BM_ASSERT(left <= right);
3644 BM_ASSERT(temp_block);
3645
3646 block_idx_type nblock_left = (left >> bm::set_block_shift);
3647 block_idx_type nblock_right = (right >> bm::set_block_shift);
3648
3649 for (; nblock_left <= nblock_right; ++nblock_left)
3650 {
3651 unsigned i0, j0;
3652 bm::get_block_coord(nblock_left, i0, j0);
3653 if (i0 >= blockman_.top_block_size())
3654 break;
3655 bm::word_t* block = blockman_.get_block_ptr(i0, j0);
3656 if (block)
3657 blockman_.optimize_block(i0, j0, block, temp_block, opt_mode, 0);
3658 } // for
3659
3660}
3661
3662// -----------------------------------------------------------------------
3663
3664template<typename Alloc>
3666{
3667#if 0
3668 if (!blockman_.is_init())
3669 return;
3670
3671 struct bvector<Alloc>::statistics st;
3672 calc_stat(&st);
3673
3674 if (!st.gap_blocks)
3675 return;
3676
3677 gap_word_t opt_glen[bm::gap_levels];
3678 ::memcpy(opt_glen, st.gap_levels, bm::gap_levels * sizeof(*opt_glen));
3679
3680 improve_gap_levels(st.gap_length,
3681 st.gap_length + st.gap_blocks,
3682 opt_glen);
3683
3684 set_gap_levels(opt_glen);
3685#endif
3686}
3687
3688// -----------------------------------------------------------------------
3689
3690template<typename Alloc>
3691void bvector<Alloc>::set_gap_levels(const gap_word_t* glevel_len)
3692{
3693 BM_ASSERT(!is_ro());
3694
3695 if (blockman_.is_init())
3696 {
3697 word_t*** blk_root = blockman_.top_blocks_root();
3698 typename
3699 blocks_manager_type::gap_level_func gl_func(blockman_, glevel_len);
3700 for_each_nzblock(blk_root, blockman_.top_block_size(),gl_func);
3701 }
3702
3703 blockman_.set_glen(glevel_len);
3704}
3705
3706// -----------------------------------------------------------------------
3707
3708template<typename Alloc>
3710{
3711 int res;
3712 unsigned top_blocks = blockman_.top_block_size();
3713 unsigned bvect_top_blocks = bv.blockman_.top_block_size();
3714
3715 if (bvect_top_blocks > top_blocks) top_blocks = bvect_top_blocks;
3716
3717 for (unsigned i = 0; i < top_blocks; ++i)
3718 {
3719 const bm::word_t* const* blk_blk = blockman_.get_topblock(i);
3720 const bm::word_t* const* arg_blk_blk = bv.blockman_.get_topblock(i);
3721
3722 if (blk_blk == arg_blk_blk)
3723 continue;
3724
3725 for (unsigned j = 0; j < bm::set_sub_array_size; ++j)
3726 {
3727 const bm::word_t* arg_blk; const bm::word_t* blk;
3728 if ((bm::word_t*)arg_blk_blk == FULL_BLOCK_FAKE_ADDR)
3729 arg_blk = FULL_BLOCK_REAL_ADDR;
3730 else
3731 {
3732 arg_blk = arg_blk_blk ? arg_blk_blk[j] : 0;
3733 if (arg_blk == FULL_BLOCK_FAKE_ADDR)
3734 arg_blk = FULL_BLOCK_REAL_ADDR;
3735 }
3736 if ((bm::word_t*)blk_blk == FULL_BLOCK_FAKE_ADDR)
3738 else
3739 {
3740 blk = blk_blk ? blk_blk[j] : 0;
3741 if (blk == FULL_BLOCK_FAKE_ADDR)
3743 }
3744 if (blk == arg_blk) continue;
3745
3746 // If one block is zero we check if the other one has at least
3747 // one bit ON
3748
3749 if (!blk || !arg_blk)
3750 {
3751 const bm::word_t* pblk; bool is_gap;
3752
3753 if (blk)
3754 {
3755 pblk = blk;
3756 res = 1;
3757 is_gap = BM_IS_GAP(blk);
3758 }
3759 else
3760 {
3761 pblk = arg_blk;
3762 res = -1;
3763 is_gap = BM_IS_GAP(arg_blk);
3764 }
3765
3766 if (is_gap)
3767 {
3768 if (!bm::gap_is_all_zero(BMGAP_PTR(pblk)))
3769 return res;
3770 }
3771 else
3772 {
3773 if (!bm::bit_is_all_zero(pblk))
3774 return res;
3775 }
3776 continue;
3777 }
3778 bool arg_gap = BM_IS_GAP(arg_blk);
3779 bool gap = BM_IS_GAP(blk);
3780
3781 if (arg_gap != gap)
3782 {
3783 BM_DECLARE_TEMP_BLOCK(temp_blk)
3784 bm::wordop_t* blk1; bm::wordop_t* blk2;
3785
3786 if (gap)
3787 {
3789 BMGAP_PTR(blk));
3790 blk1 = (bm::wordop_t*)temp_blk;
3791 blk2 = (bm::wordop_t*)arg_blk;
3792 }
3793 else
3794 {
3796 BMGAP_PTR(arg_blk));
3797 blk1 = (bm::wordop_t*)blk;
3798 blk2 = (bm::wordop_t*)temp_blk;
3799 }
3800 res = bm::bitcmp(blk1, blk2, bm::set_block_size_op);
3801 }
3802 else
3803 {
3804 if (gap)
3805 {
3806 res = bm::gapcmp(BMGAP_PTR(blk), BMGAP_PTR(arg_blk));
3807 }
3808 else
3809 {
3810 res = bm::bitcmp((bm::wordop_t*)blk,
3811 (bm::wordop_t*)arg_blk,
3813 }
3814 }
3815 if (res != 0)
3816 return res;
3817 } // for j
3818
3819 } // for i
3820
3821 return 0;
3822}
3823
3824// -----------------------------------------------------------------------
3825
3826template<typename Alloc>
3828 const bvector<Alloc>& bvect, size_type& pos,
3829 size_type search_to) const BMNOEXCEPT
3830{
3831 unsigned top_blocks = blockman_.top_block_size();
3832 bm::word_t*** top_root = blockman_.top_blocks_root();
3833
3834 if (!top_blocks || !top_root)
3835 {
3836 return bvect.find(pos);
3837 }
3838 bm::word_t*** arg_top_root = bvect.blockman_.top_blocks_root();
3839 unsigned i_to, j_to;
3840 {
3841 unsigned bvect_top_blocks = bvect.blockman_.top_block_size();
3842 if (!bvect_top_blocks || !arg_top_root)
3843 {
3844 bool f = this->find(pos);
3845 if (f)
3846 {
3847 if (pos > search_to)
3848 return false;
3849 }
3850 return f;
3851 }
3852
3853 if (bvect_top_blocks > top_blocks)
3854 top_blocks = bvect_top_blocks;
3855 block_idx_type nb_to = (search_to >> bm::set_block_shift);
3856 bm::get_block_coord(nb_to, i_to, j_to);
3857 }
3858 if (i_to < top_blocks)
3859 top_blocks = i_to+1;
3860
3861 for (unsigned i = 0; i < top_blocks; ++i)
3862 {
3863 const bm::word_t* const* blk_blk = blockman_.get_topblock(i);
3864 const bm::word_t* const* arg_blk_blk = bvect.blockman_.get_topblock(i);
3865
3866 if (blk_blk == arg_blk_blk)
3867 {
3868 /* TODO: fix buffer overrread here
3869 unsigned arg_top_blocks = bvect.blockman_.top_block_size_;
3870 if (top_blocks < arg_top_blocks)
3871 arg_top_blocks = top_blocks;
3872 if (i_to < arg_top_blocks)
3873 arg_top_blocks = i_to+1;
3874
3875 // look ahead for top level mismatch
3876 for (++i; i < arg_top_blocks; ++i)
3877 {
3878 if (top_root[i] != arg_top_root[i])
3879 {
3880 blk_blk = blockman_.get_topblock(i);
3881 arg_blk_blk = bvect.blockman_.get_topblock(i);
3882 BM_ASSERT(blk_blk != arg_blk_blk);
3883 goto find_sub_block;
3884 }
3885 }
3886 */
3887 continue;
3888 }
3889 //find_sub_block:
3890 unsigned j = 0;
3891 do
3892 {
3893 const bm::word_t* arg_blk; const bm::word_t* blk;
3894 arg_blk = ((bm::word_t*)arg_blk_blk == FULL_BLOCK_FAKE_ADDR) ?
3896 arg_blk_blk ? (BLOCK_ADDR_SAN(arg_blk_blk[j])) : 0;
3897 blk = ((bm::word_t*)blk_blk == FULL_BLOCK_FAKE_ADDR) ?
3899 (blk_blk ? (BLOCK_ADDR_SAN(blk_blk[j])) : 0);
3900 if (blk == arg_blk)
3901 continue;
3902
3903 unsigned block_pos;
3904 bool found = bm::block_find_first_diff(blk, arg_blk, &block_pos);
3905 if (found)
3906 {
3907 pos =
3909 (size_type(j) * bm::gap_max_bits) + block_pos;
3910 if (pos > search_to)
3911 return false;
3912 return true;
3913 }
3914
3915 if (i == i_to)
3916 {
3917 if (j >= j_to)
3918 return false;
3919 }
3920
3921 } while (++j < bm::set_sub_array_size);
3922 } // for i
3923
3924 return false;
3925
3926}
3927
3928// -----------------------------------------------------------------------
3929
3930template<typename Alloc>
3932{
3933 if (this != &bvect)
3934 {
3935 blockman_.swap(bvect.blockman_);
3936 bm::xor_swap(size_,bvect.size_);
3937 }
3938}
3939
3940// -----------------------------------------------------------------------
3941
3942template<typename Alloc>
3944 struct bvector<Alloc>::statistics* st) const BMNOEXCEPT
3945{
3946 BM_ASSERT(st);
3947
3948 st->reset();
3949 ::memcpy(st->gap_levels,
3950 blockman_.glen(), sizeof(gap_word_t) * bm::gap_levels);
3951
3952 st->max_serialize_mem = unsigned(sizeof(bm::id_t) * 4);
3953 unsigned top_size = blockman_.top_block_size();
3954
3955 size_t blocks_mem = sizeof(blockman_);
3956 blocks_mem +=
3957 (blockman_.temp_block_ ? sizeof(bm::word_t) * bm::set_block_size : 0);
3958 blocks_mem += sizeof(bm::word_t**) * top_size;
3959 bm::word_t*** blk_root = blockman_.top_blocks_root();
3960
3961 if (blk_root)
3962 {
3963 for (unsigned i = 0; i < top_size; ++i)
3964 {
3965 const bm::word_t* const* blk_blk = blk_root[i];
3966 if (!blk_blk)
3967 {
3968 ++i;
3969 bool found = bm::find_not_null_ptr(blk_root, i, top_size, &i);
3970 if (!found)
3971 break;
3972 blk_blk = blk_root[i];
3973 BM_ASSERT(blk_blk);
3974 if (!blk_blk)
3975 break;
3976 }
3977 if ((bm::word_t*)blk_blk == FULL_BLOCK_FAKE_ADDR)
3978 continue;
3979 st->ptr_sub_blocks++;
3980 for (unsigned j = 0; j < bm::set_sub_array_size; ++j)
3981 {
3982 const bm::word_t* blk = blk_blk[j];
3983 if (IS_VALID_ADDR(blk))
3984 {
3985 if (BM_IS_GAP(blk))
3986 {
3987 const bm::gap_word_t* gap_blk = BMGAP_PTR(blk);
3988 unsigned cap;
3989 unsigned len = gap_length(gap_blk);
3990 cap = is_ro() ? len
3991 : bm::gap_capacity(gap_blk, blockman_.glen());
3992 unsigned level = bm::gap_level(gap_blk);
3993 st->add_gap_block(cap, len, level);
3994 }
3995 else // bit block
3996 st->add_bit_block();
3997 }
3998 } // for j
3999 } // for i
4000
4001 size_t full_null_size = blockman_.calc_serialization_null_full();
4002 st->max_serialize_mem += full_null_size;
4003
4004 } // if blk_root
4005
4006 size_t safe_inc = st->max_serialize_mem / 10; // 10% increment
4007 if (!safe_inc) safe_inc = 256;
4008 st->max_serialize_mem += safe_inc;
4009
4010 // Calc size of different odd and temporary things.
4011 st->memory_used += unsigned(sizeof(*this) - sizeof(blockman_));
4012 blocks_mem += st->ptr_sub_blocks * (sizeof(void*) * bm::set_sub_array_size);
4013 st->memory_used += blocks_mem;
4014 if (is_ro())
4015 st->memory_used += sizeof(typename blocks_manager_type::arena);
4016 st->bv_count = 1;
4017
4018}
4019
4020// -----------------------------------------------------------------------
4021
4022template<typename Alloc>
4024{
4025 bv_blocks.init();
4026
4027 unsigned top_size = blockman_.top_block_size();
4028 bm::word_t*** blk_root = blockman_.top_blocks_root();
4029 if (blk_root)
4030 {
4031 for (unsigned i = 0; i < top_size; ++i)
4032 {
4033 const bm::word_t* const* blk_blk = blk_root[i];
4034 if (!blk_blk || ((bm::word_t*)blk_blk == FULL_BLOCK_FAKE_ADDR))
4035 continue;
4036 for (unsigned j = 0; j < bm::set_sub_array_size; ++j)
4037 {
4038 const bm::word_t* blk = blk_blk[j];
4039 if (IS_VALID_ADDR(blk))
4040 {
4041 size_type nb = i * bm::set_sub_array_size + j;
4042 bv_blocks.set_bit_no_check(nb);
4043 }
4044 } // for j
4045 } // for i
4046 } // if blk_root
4047}
4048
4049
4050// -----------------------------------------------------------------------
4051
4052template<class Alloc>
4054 size_type ids_size, bm::sort_order so)
4055{
4056 BM_ASSERT(!is_ro());
4057
4058 if (!ids || !ids_size)
4059 return; // nothing to do
4060 if (!blockman_.is_init())
4061 blockman_.init_tree();
4062
4063 import(ids, ids_size, so);
4064 sync_size();
4065}
4066
4067// -----------------------------------------------------------------------
4068
4069template<class Alloc>
4070void bvector<Alloc>::keep(const size_type* ids, size_type ids_size,
4071 bm::sort_order so)
4072{
4073 BM_ASSERT(!is_ro());
4074
4075 if (!ids || !ids_size || !blockman_.is_init())
4076 {
4077 clear();
4078 return;
4079 }
4080 bvector<Alloc> bv_tmp; // TODO: better optimize for SORTED case (avoid temp)
4081 bv_tmp.import(ids, ids_size, so);
4082
4083 size_type last;
4084 bool found = bv_tmp.find_reverse(last);
4085 if (found)
4086 {
4087 bv_tmp.resize(last+1);
4088 bit_and(bv_tmp);
4089 }
4090 else
4091 {
4092 BM_ASSERT(0);
4093 clear();
4094 }
4095}
4096
4097// -----------------------------------------------------------------------
4098
4099template<class Alloc>
4101{
4102 if (is_ro())
4103 {
4104 BM_ASSERT(free_mem);
4105 blockman_.destroy_arena();
4106 }
4107 else
4108 blockman_.set_all_zero(free_mem);
4109}
4110
4111// -----------------------------------------------------------------------
4112
4113template<class Alloc>
4115 size_type ids_size, bm::sort_order so)
4116{
4117 BM_ASSERT(!is_ro());
4118
4119 if (!ids || !ids_size || !blockman_.is_init())
4120 {
4121 return;
4122 }
4123 bvector<Alloc> bv_tmp; // TODO: better optimize for SORTED case (avoid temp)
4124 bv_tmp.import(ids, ids_size, so);
4125
4126 size_type last;
4127 bool found = bv_tmp.find_reverse(last);
4128 if (found)
4129 {
4130 bv_tmp.resize(last+1);
4131 bit_sub(bv_tmp);
4132 }
4133 else
4134 {
4135 BM_ASSERT(0);
4136 }
4137}
4138
4139// -----------------------------------------------------------------------
4140
4141template<class Alloc>
4143{
4144 BM_ASSERT(!is_ro());
4145
4146 set_range(0, size_ - 1, true);
4147 return *this;
4148}
4149
4150// -----------------------------------------------------------------------
4151
4152template<class Alloc>
4154{
4155 BM_ASSERT(!is_ro());
4156
4157 set_bit(n, val);
4158 return *this;
4159}
4160
4161// -----------------------------------------------------------------------
4162
4163template<class Alloc>
4164bool bvector<Alloc>::set_bit_conditional(size_type n, bool val, bool condition)
4165{
4166 if (val == condition) return false;
4167 if (n >= size_)
4168 {
4169 size_type new_size = (n == bm::id_max) ? bm::id_max : n + 1;
4170 resize(new_size);
4171 }
4172 return set_bit_conditional_impl(n, val, condition);
4173}
4174
4175// -----------------------------------------------------------------------
4176
4177template<class Alloc>
4179{
4180 BM_ASSERT(!is_ro());
4181 BM_ASSERT(n < size_);
4182 BM_ASSERT_THROW(n < size_, BM_ERR_RANGE);
4183
4184 if (!blockman_.is_init())
4185 blockman_.init_tree();
4186 return and_bit_no_check(n, val);
4187}
4188
4189// -----------------------------------------------------------------------
4190
4191template<class Alloc>
4193{
4194 BM_ASSERT(!is_ro());
4195 BM_ASSERT_THROW(n < bm::id_max, BM_ERR_RANGE);
4196
4197 if (!blockman_.is_init())
4198 blockman_.init_tree();
4199 if (n >= size_)
4200 {
4201 size_type new_size = (n == bm::id_max) ? bm::id_max : n + 1;
4202 resize(new_size);
4203 }
4204 return set_bit_no_check(n, val);
4205}
4206
4207// -----------------------------------------------------------------------
4208
4209template<class Alloc>
4211 bm::sort_order sorted_idx)
4212{
4213 BM_ASSERT(!is_ro());
4214
4215 size_type n, start(0), stop(size_in);
4216 block_idx_type nblock;
4217
4218 n = ids[start];
4219 nblock = (n >> bm::set_block_shift);
4220
4221 switch(sorted_idx)
4222 {
4223 case BM_SORTED:
4224 {
4225 block_idx_type nblock_end = (ids[size_in-1] >> bm::set_block_shift);
4226 if (nblock == nblock_end) // special case: one block import
4227 {
4228 import_block(ids, nblock, 0, stop);
4229 return;
4230 }
4231 }
4232 break;
4233 default:
4234 break;
4235 } // switch
4236
4237 do
4238 {
4239 n = ids[start];
4240 nblock = (n >> bm::set_block_shift);
4241 #ifdef BM64ADDR
4242 stop = bm::idx_arr_block_lookup_u64(ids, size_in, nblock, start);
4243 #else
4244 stop = bm::idx_arr_block_lookup_u32(ids, size_in, nblock, start);
4245 #endif
4246 BM_ASSERT(start < stop);
4247 import_block(ids, nblock, start, stop);
4248 start = stop;
4249 } while (start < size_in);
4250}
4251
4252// -----------------------------------------------------------------------
4253
4254template<class Alloc>
4256 const size_type size_in,
4257 bool opt_flag)
4258{
4259 BM_ASSERT(size_in);
4260 BM_ASSERT(ids[0] < bm::id_max); // limit is 2^31-1 (for 32-bit mode)
4261 BM_ASSERT(ids[size_in-1] < bm::id_max);
4262
4263 size_type n, start(0), stop = size_in;
4264 block_idx_type nblock, nblock_end;
4265
4266 n = ids[start];
4267 nblock = (n >> bm::set_block_shift);
4268 nblock_end = (ids[size_in-1] >> bm::set_block_shift);
4269
4270 if (nblock == nblock_end) // special (but frequent)case: one block import
4271 {
4272 import_block(ids, nblock, 0, stop);
4273 unsigned nbit = unsigned(ids[size_in-1] & bm::set_block_mask);
4274 if (opt_flag && nbit == 65535) // last bit in block
4275 {
4276 unsigned i, j;
4277 bm::get_block_coord(nblock, i, j);
4278 blockman_.optimize_bit_block(i, j, opt_compress);
4279 }
4280 }
4281 else
4282 {
4283 do
4284 {
4285 // TODO: use one-sided binary search to find the block limits
4286 #ifdef BM64ADDR
4287 stop = bm::idx_arr_block_lookup_u64(ids, size_in, nblock, start);
4288 #else
4289 stop = bm::idx_arr_block_lookup_u32(ids, size_in, nblock, start);
4290 #endif
4291 BM_ASSERT(start < stop);
4292
4293 import_block(ids, nblock, start, stop);
4294 start = stop;
4295 nblock = (ids[stop] >> bm::set_block_shift);
4296 } while (start < size_in);
4297
4298
4299 if (opt_flag) // multi-block sorted import, lets optimize
4300 {
4301 n = ids[start];
4302 nblock = (n >> bm::set_block_shift);
4303 nblock_end = (ids[size_in-1] >> bm::set_block_shift);
4304 unsigned nbit = unsigned(ids[size_in-1] & bm::set_block_mask);
4305 nblock_end += bool(nbit == 65535);
4306 do
4307 {
4308 unsigned i, j;
4309 bm::get_block_coord(nblock++, i, j);
4310 blockman_.optimize_bit_block(i, j, opt_compress);
4311 } while (nblock < nblock_end);
4312 }
4313
4314 }
4315}
4316
4317
4318// -----------------------------------------------------------------------
4319
4320template<class Alloc>
4322 block_idx_type nblock,
4323 size_type start,
4324 size_type stop)
4325{
4326 BM_ASSERT(stop > start);
4327 int block_type;
4328 bm::word_t* blk =
4329 blockman_.check_allocate_block(nblock, 1, 0, &block_type,
4330 true/*allow NULL ret*/);
4331 if (!IS_FULL_BLOCK(blk))
4332 {
4333 if (BM_IS_GAP(blk))
4334 {
4335 if (stop-start == 1)
4336 {
4337 unsigned nbit = unsigned(ids[0] & bm::set_block_mask);
4338 gap_block_set_no_ret(BMGAP_PTR(blk), true, nblock, nbit);
4339 return;
4340 }
4341 blk = blockman_.deoptimize_block(nblock); // TODO: try to avoid
4342 }
4343 #ifdef BM64ADDR
4344 bm::set_block_bits_u64(blk, ids, start, stop);
4345 #else
4346 bm::set_block_bits_u32(blk, ids, start, stop);
4347 #endif
4348 if (nblock == bm::set_total_blocks-1)
4349 blk[bm::set_block_size-1] &= ~(1u<<31);
4350 }
4351}
4352
4353// -----------------------------------------------------------------------
4354
4355template<class Alloc>
4357{
4358 BM_ASSERT(!is_ro());
4359 BM_ASSERT_THROW(n < bm::id_max, BM_ERR_RANGE);
4360
4361 // calculate logical block number
4362 block_idx_type nblock = (n >> bm::set_block_shift);
4363
4364 int block_type;
4365 bm::word_t* blk =
4366 blockman_.check_allocate_block(nblock,
4367 val,
4369 &block_type);
4370
4371 if (!IS_VALID_ADDR(blk))
4372 return false;
4373
4374 // calculate word number in block and bit
4375 unsigned nbit = unsigned(n & bm::set_block_mask);
4376 if (block_type) // gap
4377 {
4378 return gap_block_set(BMGAP_PTR(blk), val, nblock, nbit);
4379 }
4380 else // bit block
4381 {
4382 unsigned nword = unsigned(nbit >> bm::set_word_shift);
4383 nbit &= bm::set_word_mask;
4384 bm::word_t* word = blk + nword;
4385 bm::word_t mask = (((bm::word_t)1) << nbit);
4386
4387 if (val)
4388 {
4389 val = ~(*word & mask);
4390 *word |= mask; // set bit
4391 return val;
4392 }
4393 else
4394 {
4395 val = ~(*word & mask);
4396 *word &= ~~mask; // clear bit
4397 return val;
4398 }
4399 }
4400}
4401
4402// -----------------------------------------------------------------------
4403
4404template<class Alloc>
4406{
4407 BM_ASSERT(!is_ro());
4408 BM_ASSERT_THROW(n < bm::id_max, BM_ERR_RANGE);
4409
4410 const bool val = true; // set bit
4411
4412 block_idx_type nblock = (n >> bm::set_block_shift);
4413 unsigned nbit = unsigned(n & bm::set_block_mask);
4414
4415 int block_type;
4416 bm::word_t* blk =
4417 blockman_.check_allocate_block(nblock,
4418 val,
4420 &block_type);
4421 if (!IS_VALID_ADDR(blk))
4422 return;
4423
4424 if (block_type) // gap block
4425 {
4426 this->gap_block_set_no_ret(BMGAP_PTR(blk), val, nblock, nbit);
4427 }
4428 else // bit block
4429 {
4430 unsigned nword = nbit >> bm::set_word_shift;
4431 nbit &= bm::set_word_mask;
4432 blk[nword] |= (1u << nbit); // set bit
4433 }
4434}
4435
4436// -----------------------------------------------------------------------
4437
4438template<class Alloc>
4440{
4441 BM_ASSERT(!is_ro());
4442 BM_ASSERT_THROW(n < bm::id_max, BM_ERR_RANGE);
4443
4444 const bool val = false; // clear bit
4445
4446 block_idx_type nblock = (n >> bm::set_block_shift);
4447 int block_type;
4448 bm::word_t* blk =
4449 blockman_.check_allocate_block(nblock,
4450 val,
4452 &block_type);
4453 if (!blk)
4454 return;
4455
4456 unsigned nbit = unsigned(n & bm::set_block_mask);
4457 if (block_type) // gap
4458 {
4459 this->gap_block_set_no_ret(BMGAP_PTR(blk), val, nblock, nbit);
4460 }
4461 else // bit block
4462 {
4463 unsigned nword = unsigned(nbit >> bm::set_word_shift);
4464 nbit &= bm::set_word_mask;
4465 blk[nword] &= ~(1u << nbit); // clear bit
4466 }
4467}
4468
4469
4470// -----------------------------------------------------------------------
4471
4472template<class Alloc>
4474 bool val, block_idx_type nblock,
4475 unsigned nbit)
4476{
4477 unsigned is_set, new_len, old_len;
4478 old_len = bm::gap_length(gap_blk)-1;
4479 new_len = bm::gap_set_value(val, gap_blk, nbit, &is_set);
4480 if (old_len < new_len)
4481 {
4482 unsigned threshold = bm::gap_limit(gap_blk, blockman_.glen());
4483 if (new_len > threshold)
4484 blockman_.extend_gap_block(nblock, gap_blk);
4485 }
4486 return is_set;
4487}
4488
4489// -----------------------------------------------------------------------
4490
4491template<class Alloc>
4493 bool val, block_idx_type nblock, unsigned nbit)
4494{
4495 unsigned new_len, old_len;
4496 old_len = bm::gap_length(gap_blk)-1;
4497 new_len = bm::gap_set_value(val, gap_blk, nbit);
4498 if (old_len < new_len)
4499 {
4500 unsigned threshold = bm::gap_limit(gap_blk, blockman_.glen());
4501 if (new_len > threshold)
4502 blockman_.extend_gap_block(nblock, gap_blk);
4503 }
4504}
4505
4506
4507// -----------------------------------------------------------------------
4508
4509template<class Alloc>
4511{
4512 BM_ASSERT(!is_ro());
4513 // calculate logical block number
4514 block_idx_type nblock = (n >> bm::set_block_shift);
4515 bm::word_t* blk =
4516 blockman_.check_allocate_block(nblock,
4519
4520 unsigned nbit = unsigned(n & bm::set_block_mask);
4521
4522 unsigned is_set;
4523 if (BM_IS_GAP(blk))
4524 {
4525 bm::gap_word_t* gap_blk = BMGAP_PTR(blk);
4526 is_set = (bm::gap_test_unr(gap_blk, nbit) != 0);
4527 this->gap_block_set(gap_blk, !is_set, nblock, nbit); // flip
4528 }
4529 else // bit block
4530 {
4531 unsigned nword = unsigned(nbit >> bm::set_word_shift);
4532 nbit &= bm::set_word_mask;
4533
4534 bm::word_t* word = blk + nword;
4535 bm::word_t mask = (((bm::word_t)1) << nbit);
4536 is_set = ((*word) & mask);
4537
4538 *word = (is_set) ? (*word & ~mask) : (*word | mask);
4539 }
4540 return is_set;
4541}
4542
4543// -----------------------------------------------------------------------
4544
4545template<class Alloc>
4547 bool val,
4548 bool condition)
4549{
4550 // calculate logical block number
4551 block_idx_type nblock = (n >> bm::set_block_shift);
4552 int block_type;
4553 bm::word_t* blk =
4554 blockman_.check_allocate_block(nblock,
4555 val,
4557 &block_type);
4558 if (!IS_VALID_ADDR(blk))
4559 return false;
4560
4561 // calculate word number in block and bit
4562 unsigned nbit = unsigned(n & bm::set_block_mask);
4563
4564 if (block_type == 1) // gap
4565 {
4566 bm::gap_word_t* gap_blk = BMGAP_PTR(blk);
4567 unsigned is_set = gap_block_set(gap_blk, val, nblock, nbit);
4568 return is_set;
4569 }
4570 else // bit block
4571 {
4572 unsigned nword = unsigned(nbit >> bm::set_word_shift);
4573 nbit &= bm::set_word_mask;
4574
4575 bm::word_t* word = blk + nword;
4576 bm::word_t mask = (((bm::word_t)1) << nbit);
4577 bool is_set = ((*word) & mask) != 0;
4578
4579 if (is_set != condition)
4580 return false;
4581 if (is_set != val) // need to change bit
4582 {
4583 if (val) // set bit
4584 *word |= mask;
4585 else // clear bit
4586 *word &= ~~mask;
4587 return true;
4588 }
4589 }
4590 return false;
4591
4592}
4593
4594// -----------------------------------------------------------------------
4595
4596
4597template<class Alloc>
4599{
4600 BM_ASSERT(!is_ro());
4601 // calculate logical block number
4602 block_idx_type nblock = (n >> bm::set_block_shift);
4603
4604 int block_type;
4605 bm::word_t* blk =
4606 blockman_.check_allocate_block(nblock,
4607 val,
4609 &block_type);
4610 if (!IS_VALID_ADDR(blk))
4611 return false;
4612
4613 // calculate word number in block and bit
4614 unsigned nbit = unsigned(n & bm::set_block_mask);
4615
4616 if (block_type == 1) // gap
4617 {
4618 bm::gap_word_t* gap_blk = BMGAP_PTR(blk);
4619 bool old_val = (bm::gap_test_unr(gap_blk, nbit) != 0);
4620
4621 bool new_val = val & old_val;
4622 if (new_val != old_val)
4623 {
4624 unsigned is_set = gap_block_set(gap_blk, val, nblock, nbit);
4625 BM_ASSERT(is_set);
4626 return is_set;
4627 }
4628 }
4629 else // bit block
4630 {
4631 unsigned nword = unsigned(nbit >> bm::set_word_shift);
4632 nbit &= bm::set_word_mask;
4633
4634 bm::word_t* word = blk + nword;
4635 bm::word_t mask = (((bm::word_t)1) << nbit);
4636 bool is_set = ((*word) & mask) != 0;
4637
4638 bool new_val = is_set & val;
4639 if (new_val != val) // need to change bit
4640 {
4641 if (new_val) // set bit
4642 {
4643 *word |= mask;
4644 }
4645 else // clear bit
4646 {
4647 *word &= ~~mask;
4648 }
4649 return true;
4650 }
4651 }
4652 return false;
4653}
4654
4655//---------------------------------------------------------------------
4656
4657template<class Alloc>
4659{
4660 if (from == bm::id_max)
4661 return false;
4662 if (!from)
4663 {
4664 return find(pos);
4665 }
4666 pos = check_or_next(from);
4667 return (pos != 0);
4668}
4669
4670//---------------------------------------------------------------------
4671
4672template<class Alloc>
4674{
4675 bool found;
4676
4677 unsigned top_blocks = blockman_.top_block_size();
4678 if (!top_blocks)
4679 return false;
4680 for (unsigned i = top_blocks-1; true; --i)
4681 {
4682 const bm::word_t* const* blk_blk = blockman_.get_topblock(i);
4683 if (blk_blk)
4684 {
4685 if ((bm::word_t*)blk_blk == FULL_BLOCK_FAKE_ADDR)
4686 blk_blk = FULL_SUB_BLOCK_REAL_ADDR;
4687
4688 for (unsigned short j = bm::set_sub_array_size-1; true; --j)
4689 {
4690 const bm::word_t* blk = blk_blk[j];
4691 if (blk)
4692 {
4693 unsigned block_pos;
4694 if (blk == FULL_BLOCK_FAKE_ADDR)
4695 {
4696 block_pos = bm::gap_max_bits-1;
4697 found = true;
4698 }
4699 else
4700 {
4701 bool is_gap = BM_IS_GAP(blk);
4702 found = is_gap ? bm::gap_find_last(BMGAP_PTR(blk), &block_pos)
4703 : bm::bit_find_last(blk, &block_pos);
4704 }
4705 if (found)
4706 {
4707 block_idx_type base_idx =
4710 base_idx += j * bm::gap_max_bits;
4711 pos = base_idx + block_pos;
4712 return found;
4713 }
4714 }
4715
4716 if (j == 0)
4717 break;
4718 } // for j
4719 } // if blk_blk
4720
4721 if (i == 0)
4722 break;
4723 } // for i
4724 return false;
4725}
4726
4727//---------------------------------------------------------------------
4728
4729template<class Alloc>
4731{
4732 bool found;
4733 if (!blockman_.is_init())
4734 return false; // nothing to do
4735 if (!from)
4736 {
4737 pos = from;
4738 return this->test(from);
4739 }
4740
4741 block_idx_type nb = (from >> bm::set_block_shift);
4742 unsigned i0, j0;
4743 bm::get_block_coord(nb, i0, j0);
4744
4745 const bm::word_t* block = blockman_.get_block_ptr(i0, j0);
4746 if (block)
4747 {
4748 size_type base_idx;
4749 unsigned found_nbit;
4750 unsigned nbit = unsigned(from & bm::set_block_mask);
4751 found = bm::block_find_reverse(block, nbit, &found_nbit);
4752 if (found)
4753 {
4754 base_idx = bm::get_block_start<size_type>(i0, j0);
4755 pos = base_idx + found_nbit;
4756 return found;
4757 }
4758 }
4759
4760 if (nb)
4761 --nb;
4762 else
4763 return false;
4764 bm::get_block_coord(nb, i0, j0);
4765
4766 const bm::word_t* const* blk_blk = blockman_.get_topblock(i0);
4767 if (blk_blk)
4768 {
4769 if ((bm::word_t*)blk_blk == FULL_BLOCK_FAKE_ADDR)
4770 blk_blk = FULL_SUB_BLOCK_REAL_ADDR;
4771 for (unsigned j = j0; true; --j)
4772 {
4773 const bm::word_t* blk = blk_blk[j];
4774 if (blk)
4775 {
4776 unsigned block_pos;
4777 if (blk == FULL_BLOCK_FAKE_ADDR)
4778 {
4779 block_pos = bm::gap_max_bits-1;
4780 found = true;
4781 }
4782 else
4783 {
4784 bool is_gap = BM_IS_GAP(blk);
4785 found = is_gap ? bm::gap_find_last(BMGAP_PTR(blk), &block_pos)
4786 : bm::bit_find_last(blk, &block_pos);
4787 }
4788 if (found)
4789 {
4790 block_idx_type base_idx =
4793 base_idx += j * bm::gap_max_bits;
4794 pos = base_idx + block_pos;
4795 return found;
4796 }
4797 }
4798 if (!j)
4799 break;
4800 } // for j
4801 }
4802 if (i0)
4803 --i0;
4804 else
4805 return false;
4806
4807 for (unsigned i = i0; true; --i)
4808 {
4809 blk_blk = blockman_.get_topblock(i);
4810 if (blk_blk)
4811 {
4812 if ((bm::word_t*)blk_blk == FULL_BLOCK_FAKE_ADDR)
4813 blk_blk = FULL_SUB_BLOCK_REAL_ADDR;
4814 for (unsigned short j = bm::set_sub_array_size-1; true; --j)
4815 {
4816 const bm::word_t* blk = blk_blk[j];
4817 if (blk)
4818 {
4819 unsigned block_pos;
4820 if (blk == FULL_BLOCK_FAKE_ADDR)
4821 {
4822 block_pos = bm::gap_max_bits-1;
4823 found = true;
4824 }
4825 else
4826 {
4827 bool is_gap = BM_IS_GAP(blk);
4828 found = is_gap ? bm::gap_find_last(BMGAP_PTR(blk), &block_pos)
4829 : bm::bit_find_last(blk, &block_pos);
4830 }
4831 if (found)
4832 {
4833 block_idx_type base_idx =
4836 base_idx += j * bm::gap_max_bits;
4837 pos = base_idx + block_pos;
4838 return found;
4839 }
4840 }
4841 if (!j)
4842 break;
4843 } // for j
4844 }
4845 if (i == 0)
4846 break;
4847 } // for i
4848
4849 return false;
4850}
4851
4852//---------------------------------------------------------------------
4853
4854template<class Alloc>
4856{
4857 bool found;
4858
4859 unsigned top_blocks = blockman_.top_block_size();
4860 for (unsigned i = 0; i < top_blocks; ++i)
4861 {
4862 const bm::word_t* const* blk_blk = blockman_.get_topblock(i);
4863 if (blk_blk)
4864 {
4865 if ((bm::word_t*)blk_blk == FULL_BLOCK_FAKE_ADDR)
4866 blk_blk = FULL_SUB_BLOCK_REAL_ADDR;
4867
4868 for (unsigned j = 0; j < bm::set_sub_array_size; ++j)
4869 {
4870 const bm::word_t* blk = blk_blk[j];
4871 if (blk)
4872 {
4873 unsigned block_pos;
4874 if (blk == FULL_BLOCK_FAKE_ADDR)
4875 {
4876 found = true; block_pos = 0;
4877 }
4878 else
4879 {
4880 bool is_gap = BM_IS_GAP(blk);
4881 found = (is_gap) ? bm::gap_find_first(BMGAP_PTR(blk), &block_pos)
4882 : bm::bit_find_first(blk, &block_pos);
4883 }
4884 if (found)
4885 {
4887 base_idx += j * bm::gap_max_bits;
4888 pos = base_idx + block_pos;
4889 return found;
4890 }
4891 }
4892 } // for j
4893 } // if blk_blk
4894 } // for i
4895 return false;
4896}
4897
4898//---------------------------------------------------------------------
4899
4900template<class Alloc>
4902 size_type& in_last) const BMNOEXCEPT
4903{
4904 bool found = find(in_first);
4905 if (found)
4906 {
4907 found = find_reverse(in_last);
4908 BM_ASSERT(found);
4909 BM_ASSERT(in_first <= in_last);
4910 }
4911 else
4912 {
4913 in_first = in_last = 0; // zero the output just in case
4914 }
4915 return found;
4916}
4917
4918//---------------------------------------------------------------------
4919
4920template<class Alloc>
4922 size_type from,
4923 size_type& pos) const BMNOEXCEPT
4924{
4925 BM_ASSERT_THROW(from < bm::id_max, BM_ERR_RANGE);
4926
4927 bool ret = false;
4928
4929 if (!rank_in || !blockman_.is_init())
4930 return ret;
4931
4932 block_idx_type nb = (from >> bm::set_block_shift);
4934 unsigned bit_pos = 0;
4935
4936 for (; nb < bm::set_total_blocks; ++nb)
4937 {
4938 int no_more_blocks;
4939 const bm::word_t* block = blockman_.get_block(nb, &no_more_blocks);
4940 if (block)
4941 {
4942 if (!nbit && (rank_in > bm::gap_max_bits)) // requested rank cannot be in this block
4943 {
4944 unsigned cnt = blockman_.block_bitcount(block);
4945 BM_ASSERT(cnt < rank_in);
4946 rank_in -= cnt;
4947 continue;
4948 }
4949 else
4950 {
4951 rank_in = bm::block_find_rank(block, rank_in, nbit, bit_pos);
4952 if (!rank_in) // target found
4953 {
4954 pos = bit_pos + (nb * bm::set_block_size * 32);
4955 return true;
4956 }
4957 }
4958 }
4959 else
4960 {
4961 // TODO: better next block search
4962 if (no_more_blocks)
4963 break;
4964 }
4965 nbit ^= nbit; // zero start bit after first scanned block
4966 } // for nb
4967
4968 return ret;
4969}
4970
4971//---------------------------------------------------------------------
4972
4973template<class Alloc>
4975 size_type from,
4976 size_type& pos,
4977 const rs_index_type& rs_idx) const BMNOEXCEPT
4978{
4979 BM_ASSERT_THROW(from < bm::id_max, BM_ERR_RANGE);
4980
4981 bool ret = false;
4982
4983 if (!rank_in ||
4984 !blockman_.is_init() ||
4985 (rs_idx.count() < rank_in))
4986 return ret;
4987
4988 block_idx_type nb;
4989 if (from)
4990 nb = (from >> bm::set_block_shift);
4991 else
4992 {
4993 nb = rs_idx.find(rank_in);
4994 BM_ASSERT(rs_idx.rcount(nb) >= rank_in);
4995 if (nb)
4996 rank_in -= rs_idx.rcount(nb-1);
4997 }
4998
5000 unsigned bit_pos = 0;
5001
5002 for (; nb < rs_idx.get_total(); ++nb)
5003 {
5004 int no_more_blocks;
5005 const bm::word_t* block = blockman_.get_block(nb, &no_more_blocks);
5006 if (block)
5007 {
5008 if (!nbit) // check if the whole block can be skipped
5009 {
5010 unsigned block_bc = rs_idx.count(nb);
5011 if (rank_in <= block_bc) // target block
5012 {
5013 nbit = rs_idx.select_sub_range(nb, rank_in);
5014 rank_in = bm::block_find_rank(block, rank_in, nbit, bit_pos);
5015 BM_ASSERT(rank_in == 0);
5016 pos = bit_pos + (nb * bm::set_block_size * 32);
5017 return true;
5018 }
5019 rank_in -= block_bc;
5020 continue;
5021 }
5022
5023 rank_in = bm::block_find_rank(block, rank_in, nbit, bit_pos);
5024 if (!rank_in) // target found
5025 {
5026 pos = bit_pos + (nb * bm::set_block_size * 32);
5027 return true;
5028 }
5029 }
5030 else
5031 {
5032 // TODO: better next block search
5033 if (no_more_blocks)
5034 break;
5035 }
5036 nbit ^= nbit; // zero start bit after first scanned block
5037 } // for nb
5038
5039 return ret;
5040}
5041
5042//---------------------------------------------------------------------
5043
5044template<class Alloc>
5046 const rs_index_type& rs_idx) const BMNOEXCEPT
5047{
5048 bool ret = false;
5049
5050 if (!rank_in ||
5051 !blockman_.is_init() ||
5052 (rs_idx.count() < rank_in))
5053 return ret;
5054
5055 block_idx_type nb;
5056 bm::gap_word_t sub_range_from;
5057 bool found = rs_idx.find(&rank_in, &nb, &sub_range_from);
5058 if (!found)
5059 return found;
5060
5061 unsigned i, j;
5062 bm::get_block_coord(nb, i, j);
5063 const bm::word_t* block = blockman_.get_block_ptr(i, j);
5064 BM_ASSERT(block);
5065 BM_ASSERT(rank_in <= rs_idx.count(nb));
5066
5067 unsigned bit_pos = 0;
5068 if (block == FULL_BLOCK_FAKE_ADDR)
5069 {
5070 BM_ASSERT(rank_in <= bm::gap_max_bits);
5071 bit_pos = sub_range_from + unsigned(rank_in) - 1;
5072 }
5073 else
5074 {
5075 rank_in = bm::block_find_rank(block, rank_in, sub_range_from, bit_pos);
5076 BM_ASSERT(rank_in == 0);
5077 }
5078 pos = bit_pos + (nb * bm::set_block_size * 32);
5079 return true;
5080}
5081
5082//---------------------------------------------------------------------
5083
5084template<class Alloc>
5087{
5088 if (!blockman_.is_init())
5089 return 0;
5090
5091 // calculate logical block number
5092 block_idx_type nb = (prev >> bm::set_block_shift);
5093 unsigned i, j;
5094 bm::get_block_coord(nb, i, j);
5095 const bm::word_t* block = blockman_.get_block_ptr(i, j);
5096
5097 if (block)
5098 {
5099 unsigned block_pos;
5100 bool found = false;
5101 // calculate word number in block and bit
5102 unsigned nbit = unsigned(prev & bm::set_block_mask);
5103 if (BM_IS_GAP(block))
5104 {
5105 if (bm::gap_block_find(BMGAP_PTR(block), nbit, &block_pos))
5106 {
5107 prev = (size_type(nb) * bm::gap_max_bits) + block_pos;
5108 return prev;
5109 }
5110 }
5111 else
5112 {
5113 if (block == FULL_BLOCK_FAKE_ADDR)
5114 return prev;
5115 found = bm::bit_block_find(block, nbit, &block_pos);
5116 if (found)
5117 {
5118 prev = (size_type(nb) * bm::gap_max_bits) + block_pos;
5119 return prev;
5120 }
5121 }
5122 }
5123 ++j;
5124 block_idx_type top_blocks = blockman_.top_block_size();
5125 for (; i < top_blocks; ++i)
5126 {
5127 const bm::word_t* const* blk_blk = blockman_.get_topblock(i);
5128 if (blk_blk)
5129 {
5130 if ((bm::word_t*)blk_blk == FULL_BLOCK_FAKE_ADDR)
5131 blk_blk = FULL_SUB_BLOCK_REAL_ADDR;
5132
5133 for (; j < bm::set_sub_array_size; ++j)
5134 {
5135 const bm::word_t* blk = blk_blk[j];
5136 if (blk)
5137 {
5138 bool found;
5139 unsigned block_pos;
5140 if (blk == FULL_BLOCK_FAKE_ADDR)
5141 {
5142 found = true; block_pos = 0;
5143 }
5144 else
5145 {
5146 bool is_gap = BM_IS_GAP(blk);
5147 found = (is_gap) ? bm::gap_find_first(BMGAP_PTR(blk), &block_pos)
5148 : bm::bit_find_first(blk, &block_pos);
5149 }
5150 if (found)
5151 {
5152 size_type base_idx = size_type(i) * bm::bits_in_array;
5153 base_idx += j * bm::gap_max_bits;
5154 prev = base_idx + block_pos;
5155 return prev;
5156 }
5157 }
5158 } // for j
5159 }
5160 j = 0;
5161 } // for i
5162
5163 return 0;
5164}
5165
5166//---------------------------------------------------------------------
5167
5168template<class Alloc>
5171{
5172 BM_ASSERT(!is_ro());
5173 if (!blockman_.is_init())
5174 return 0;
5175 // TODO: optimization
5176 size_type pos = this->check_or_next(prev);
5177 if (pos >= prev)
5178 this->clear_bit_no_check(pos);
5179 return pos;
5180}
5181
5182//---------------------------------------------------------------------
5183
5184template<class Alloc>
5186{
5187 BM_ASSERT(!is_ro());
5188 return insert(0, false);
5189}
5190
5191//---------------------------------------------------------------------
5192
5193template<class Alloc>
5195{
5196 BM_ASSERT(!is_ro());
5197 bool b = this->test(0);
5198 this->erase(0);
5199 return b;
5200}
5201
5202//---------------------------------------------------------------------
5203
5204template<class Alloc>
5206{
5207 BM_ASSERT(!is_ro());
5208 BM_ASSERT_THROW(n < bm::id_max, BM_ERR_RANGE);
5209
5210 if (size_ < bm::id_max)
5211 ++size_;
5212 if (!blockman_.is_init())
5213 {
5214 if (value)
5215 set(n);
5216 return 0;
5217 }
5218
5219 // calculate logical block number
5221
5222 int block_type;
5223 bm::word_t carry_over = 0;
5224
5225 // 1: process target block insertion
5226 if (value || n)
5227 {
5228 unsigned i, j;
5229 bm::get_block_coord(nb, i, j);
5230 bm::word_t* block = blockman_.get_block_ptr(i, j);
5231
5232 const unsigned nbit = unsigned(n & bm::set_block_mask);
5233 if (!block)
5234 {
5235 if (value)
5236 {
5237 block = blockman_.check_allocate_block(nb, get_new_blocks_strat());
5238 goto insert_bit_check;
5239 }
5240 }
5241 else
5242 {
5243 insert_bit_check:
5244 if (BM_IS_GAP(block))
5245 {
5246 unsigned new_block_len;
5247 bm::gap_word_t* gap_blk = BMGAP_PTR(block);
5248 carry_over = bm::gap_insert(gap_blk, nbit, value, &new_block_len);
5249 unsigned threshold = bm::gap_limit(gap_blk, blockman_.glen());
5250 if (new_block_len > threshold)
5251 blockman_.extend_gap_block(nb, gap_blk);
5252 }
5253 else
5254 {
5255 if (IS_FULL_BLOCK(block))
5256 {
5257 if (!value)
5258 {
5259 block = blockman_.deoptimize_block(nb);
5260 goto insert_bit;
5261 }
5262 carry_over = 1;
5263 }
5264 else // BIT block
5265 {
5266 insert_bit:
5267 BM_ASSERT(IS_VALID_ADDR(block));
5268 carry_over = bm::bit_block_insert(block, nbit, value);
5269 }
5270 }
5271 }
5272 ++nb;
5273 }
5274
5275 // 2: shift right everything else
5276 //
5277 unsigned i0, j0;
5278 bm::get_block_coord(nb, i0, j0);
5279
5280 unsigned top_blocks = blockman_.top_block_size();
5281 bm::word_t*** blk_root = blockman_.top_blocks_root();
5282 bm::word_t** blk_blk;
5283 bm::word_t* block;
5284
5285 for (unsigned i = i0; i < bm::set_top_array_size; ++i)
5286 {
5287 if (i >= top_blocks)
5288 {
5289 if (!carry_over)
5290 break;
5291 blk_blk = 0;
5292 }
5293 else
5294 blk_blk = blk_root[i];
5295
5296 if (!blk_blk) // top level group of blocks missing - can skip it
5297 {
5298 if (carry_over)
5299 {
5300 // carry over: needs block-list extension and a block
5302 if (nblock > nb)
5303 {
5304 block =
5305 blockman_.check_allocate_block(nblock, 0, 0, &block_type, false);
5306 block[0] |= carry_over; // block is brand new (0000)
5307
5308 // reset all control vars (blocks tree may have re-allocated)
5309 blk_root = blockman_.top_blocks_root();
5310 blk_blk = blk_root[i];
5311 top_blocks = blockman_.top_block_size();
5312
5313 carry_over = 0;
5314 }
5315 }
5316 continue;
5317 }
5318 if ((bm::word_t*)blk_blk == FULL_BLOCK_FAKE_ADDR)
5319 {
5320 if (carry_over)
5321 continue;
5322 blk_blk = blockman_.check_alloc_top_subblock(i);
5323 }
5324
5325 unsigned j = j0;
5326 do
5327 {
5329 block = blk_blk[j];
5330 if (!block)
5331 {
5332 if (carry_over)
5333 {
5334 size_type nbit = nblock * bm::gap_max_bits;
5335 set_bit_no_check(nbit);
5336 carry_over = 0; block = 0;
5337 }
5338 // no CO: tight loop scan for the next available block (if any)
5339 for (++j; j < bm::set_sub_array_size; ++j)
5340 {
5341 if (0 != (block = blk_blk[j]))
5342 {
5343 nblock = (i * bm::set_sub_array_size) + j;
5344 break;
5345 }
5346 } // for j
5347 if (!block) // no more blocks in this j-dimention
5348 continue;
5349 }
5350 if (IS_FULL_BLOCK(block))
5351 {
5352 // 1 in 1 out, block is still all 0xFFFF..
5353 // 0 into 1 -> carry in 0, carry out 1
5354 if (!carry_over)
5355 {
5356 block = blockman_.deoptimize_block(nblock);
5357 block[0] <<= (carry_over = 1);
5358 }
5359 continue;
5360 }
5361 if (BM_IS_GAP(block))
5362 {
5363 if (nblock == bm::set_total_blocks-1) // last block
5364 {
5365 // process as a bit-block (for simplicity)
5366 block = blockman_.deoptimize_block(nblock);
5367 }
5368 else // use gap-block shift here
5369 {
5370 unsigned new_block_len;
5371 bm::gap_word_t* gap_blk = BMGAP_PTR(block);
5372
5373 carry_over = bm::gap_shift_r1(gap_blk, carry_over, &new_block_len);
5374 unsigned threshold = bm::gap_limit(gap_blk, blockman_.glen());
5375 if (new_block_len > threshold)
5376 blockman_.extend_gap_block(nblock, gap_blk);
5377 continue;
5378 }
5379 }
5380 // bit-block
5381 {
5382 bm::word_t acc;
5383 carry_over = bm::bit_block_shift_r1_unr(block, &acc, carry_over);
5384 BM_ASSERT(carry_over <= 1);
5385
5386 if (nblock == bm::set_total_blocks-1) // last possible block
5387 {
5388 carry_over = block[bm::set_block_size-1] & (1u<<31);
5389 block[bm::set_block_size-1] &= ~(1u<<31); // clear the 1-bit tail
5390 if (!acc) // block shifted out: release memory
5391 blockman_.zero_block(nblock);
5392 break;
5393 }
5394 if (!acc)
5395 blockman_.zero_block(nblock);
5396 }
5397
5398 } while (++j < bm::set_sub_array_size);
5399 j0 = 0;
5400 } // for i
5401 return carry_over;
5402
5403}
5404
5405//---------------------------------------------------------------------
5406
5407template<class Alloc>
5409{
5410 BM_ASSERT(!is_ro());
5411 BM_ASSERT_THROW(n < bm::id_max, BM_ERR_RANGE);
5412
5413 if (!blockman_.is_init())
5414 return ;
5415
5416 // calculate logical block number
5418
5419 if (!n ) // regular shift-left by 1 bit
5420 {}
5421 else // process target block bit erase
5422 {
5423 unsigned i, j;
5424 bm::get_block_coord(nb, i, j);
5425 bm::word_t* block = blockman_.get_block_ptr(i, j);
5426 bool carry_over = test_first_block_bit(nb+1);
5427 if (!block)
5428 {
5429 if (carry_over)
5430 {
5431 block = blockman_.check_allocate_block(nb, BM_BIT);
5432 block[bm::set_block_size-1] = (1u << 31u);
5433 }
5434 }
5435 else
5436 {
5437 if (BM_IS_GAP(block) || IS_FULL_BLOCK(block))
5438 block = blockman_.deoptimize_block(nb);
5439 BM_ASSERT(IS_VALID_ADDR(block));
5440 unsigned nbit = unsigned(n & bm::set_block_mask);
5441 bm::bit_block_erase(block, nbit, carry_over);
5442 }
5443 ++nb;
5444 }
5445 // left shifting of all other blocks
5446 //
5447 unsigned i0, j0;
5448 bm::get_block_coord(nb, i0, j0);
5449
5450 unsigned top_blocks = blockman_.top_block_size();
5451 bm::word_t*** blk_root = blockman_.top_blocks_root();
5452 bm::word_t** blk_blk;
5453 bm::word_t* block;
5454
5455 for (unsigned i = i0; i < bm::set_top_array_size; ++i)
5456 {
5457 if (i >= top_blocks)
5458 break;
5459 else
5460 blk_blk = blk_root[i];
5461
5462 if (!blk_blk) // top level group of blocks missing
5463 {
5464 bool found = bm::find_not_null_ptr(blk_root, i+1, top_blocks, &i);
5465 if (!found)
5466 break;
5467 --i;
5468 continue;
5469 }
5470 if ((bm::word_t*)blk_blk == FULL_BLOCK_FAKE_ADDR)
5471 {
5472 bool carry_over = 0;
5473 if (i + 1 < bm::set_top_array_size)
5474 {
5476 carry_over = this->test(co_idx);
5477 if (carry_over)
5478 continue; // nothing to do (1 in)
5479 else
5480 blk_blk = blockman_.check_alloc_top_subblock(i);
5481 }
5482 else
5483 {
5484 blk_blk = blockman_.check_alloc_top_subblock(i);
5485 }
5486 }
5487
5488 unsigned j = j0;
5489 do
5490 {
5492 bool carry_over = 0; // test_first_block_bit(nblock+1); // look ahead for CO
5493 block = blk_blk[j];
5494 if (!block)
5495 {
5496 // no CO: tight loop scan for the next available block (if any)
5497 bool no_blocks = (j == 0);
5498 for (++j; j < bm::set_sub_array_size; ++j)
5499 {
5500 if (0 != (block = blk_blk[j]))
5501 {
5502 nblock = (block_idx_type(i) * bm::set_sub_array_size) + j;
5503 break;
5504 }
5505 } // for j
5506 if (!block) // no more blocks in this j-dimention ?
5507 {
5508 if (j == bm::set_sub_array_size && no_blocks)
5509 {
5510 blockman_.zero_block(i, j-1); // free the top level
5511 }
5512 continue;
5513 }
5514 }
5515 BM_ASSERT(block);
5516 if (IS_FULL_BLOCK(block))
5517 {
5518 carry_over = test_first_block_bit(nblock+1); // look ahead for CO
5519 // 1 in 1 out, block is still all 0xFFFF..
5520 // 0 into 1 -> carry in 0, carry out 1
5521 if (!carry_over)
5522 {
5523 block = blockman_.deoptimize_block(nblock);
5524 block[bm::set_block_size-1] >>= 1;
5525 }
5526 carry_over = 1;
5527 }
5528 else
5529 if (BM_IS_GAP(block))
5530 {
5531 carry_over = test_first_block_bit(nblock+1); // look ahead for CO
5532 unsigned new_block_len;
5533 bm::gap_word_t* gap_blk = BMGAP_PTR(block);
5534
5535 carry_over = bm::gap_shift_l1(gap_blk, carry_over, &new_block_len);
5536 unsigned threshold = bm::gap_limit(gap_blk, blockman_.glen());
5537 if (new_block_len > threshold)
5538 blockman_.extend_gap_block(nblock, gap_blk);
5539 else
5540 {
5541 if (bm::gap_is_all_zero(gap_blk))
5542 blockman_.zero_block(i, j);
5543 }
5544 }
5545 else // bit-block
5546 {
5547 bm::word_t acc;
5548 carry_over = bm::bit_block_shift_l1_unr(block, &acc, carry_over);
5549 if (!acc)
5550 blockman_.zero_block(i, j);
5551 }
5552
5553 if (carry_over && nblock)
5554 {
5556 }
5557
5558 } while (++j < bm::set_sub_array_size);
5559 j0 = 0;
5560 } // for i
5561
5562}
5563
5564//---------------------------------------------------------------------
5565
5566template<class Alloc>
5568{
5569 if (nb >= bm::set_total_blocks) // last possible block
5570 return false;
5571 return test(nb * bm::gap_max_bits);
5572}
5573
5574
5575//---------------------------------------------------------------------
5576
5577template<class Alloc>
5579{
5580 BM_ASSERT(!is_ro());
5581
5582 if (!bv.blockman_.is_init()) // nothing to OR
5583 return;
5584
5585 if (bv.is_ro()) // argument is immutable, just use OR
5586 {
5587 this->bit_or(bv);
5588 return;
5589 }
5590
5591 unsigned top_blocks = blockman_.top_block_size();
5592 if (size_ < bv.size_) // this vect shorter than the arg.
5593 {
5594 size_ = bv.size_;
5595 }
5596 unsigned arg_top_blocks = bv.blockman_.top_block_size();
5597 top_blocks = blockman_.reserve_top_blocks(arg_top_blocks);
5598
5599
5600 bm::word_t*** blk_root = blockman_.top_blocks_root();
5601 bm::word_t*** blk_root_arg = bv.blockman_.top_blocks_root();
5602
5603 for (unsigned i = 0; i < top_blocks; ++i)
5604 {
5605 bm::word_t** blk_blk = blk_root[i];
5606 bm::word_t** blk_blk_arg = (i < arg_top_blocks) ? blk_root_arg[i] : 0;
5607 if (blk_blk == blk_blk_arg || !blk_blk_arg) // nothing to do (0 OR 0 == 0)
5608 continue;
5609 if (!blk_blk && blk_blk_arg) // top block transfer
5610 {
5611 BM_ASSERT(i < arg_top_blocks);
5612
5613 blk_root[i] = blk_root_arg[i];
5614 blk_root_arg[i] = 0;
5615 continue;
5616 }
5617 if ((bm::word_t*)blk_blk == FULL_BLOCK_FAKE_ADDR)
5618 continue;
5619 if ((bm::word_t*)blk_blk_arg == FULL_BLOCK_FAKE_ADDR)
5620 {
5621 blockman_.deallocate_top_subblock(i);
5622 blk_root[i] = (bm::word_t**)FULL_BLOCK_FAKE_ADDR;
5623 continue;
5624 }
5625
5626 unsigned j = 0;
5627 bm::word_t* blk;
5628 bm::word_t* arg_blk;
5629 do
5630 {
5631 blk = blk_blk[j]; arg_blk = blk_blk_arg[j];
5632 if (blk != arg_blk)
5633 {
5634 if (!blk && arg_blk) // block transfer
5635 {
5636 blockman_.set_block_ptr(i, j, arg_blk);
5637 bv.blockman_.set_block_ptr(i, j, 0);
5638 }
5639 else // need full OR
5640 {
5641 combine_operation_block_or(i, j, blk, arg_blk);
5642 }
5643 }
5644 } while (++j < bm::set_sub_array_size);
5645 } // for i
5646}
5647
5648//---------------------------------------------------------------------
5649
5650template<class Alloc>
5652 const bm::word_t* arg_blk,
5653 bool arg_gap,
5654 bm::operation opcode)
5655{
5656 unsigned i0, j0;
5657 bm::get_block_coord(nb, i0, j0);
5658 bm::word_t* blk = blockman_.get_block_ptr(i0, j0);
5659
5660 bool gap = BM_IS_GAP(blk);
5661 combine_operation_with_block(nb, gap, blk, arg_blk, arg_gap, opcode);
5662}
5663
5664//---------------------------------------------------------------------
5665
5666template<class Alloc>
5669 const bm::bvector<Alloc>& bv2,
5670 typename bm::bvector<Alloc>::optmode opt_mode)
5671{
5672 BM_ASSERT(!is_ro());
5673
5674 if (blockman_.is_init())
5675 blockman_.deinit_tree();
5676
5677 if (&bv1 == &bv2)
5678 {
5679 this->bit_or(bv2);
5680 return *this;
5681 }
5682 if (this == &bv1)
5683 {
5684 this->bit_or(bv2);
5685 return *this;
5686 }
5687 if (this == &bv2)
5688 {
5689 this->bit_or(bv1);
5690 return *this;
5691 }
5692
5693 const blocks_manager_type& bman1 = bv1.get_blocks_manager();
5694 const blocks_manager_type& bman2 = bv2.get_blocks_manager();
5695
5696 unsigned top_blocks1 = bman1.top_block_size();
5697 unsigned top_blocks2 = bman2.top_block_size();
5698 unsigned top_blocks = (top_blocks2 > top_blocks1) ? top_blocks2 : top_blocks1;
5699 top_blocks = blockman_.reserve_top_blocks(top_blocks);
5700
5701 size_ = bv1.size_;
5702 if (size_ < bv2.size_)
5703 size_ = bv2.size_;
5704
5705 bm::word_t*** blk_root_arg1 = bv1.blockman_.top_blocks_root();
5706 if (!blk_root_arg1)
5707 {
5708 this->bit_or(bv2);
5709 return *this;
5710 }
5711 bm::word_t*** blk_root_arg2 = bv2.blockman_.top_blocks_root();
5712 if (!blk_root_arg2)
5713 {
5714 this->bit_or(bv1);
5715 return *this;
5716 }
5717
5718 for (unsigned i = 0; i < top_blocks; ++i)
5719 {
5720 bm::word_t** blk_blk_arg1 = (i < top_blocks1) ? blk_root_arg1[i] : 0;
5721 bm::word_t** blk_blk_arg2 = (i < top_blocks2) ? blk_root_arg2[i] : 0;
5722
5723 if (blk_blk_arg1 == blk_blk_arg2)
5724 {
5725 BM_ASSERT(!blk_blk_arg1 || (bm::word_t*)blk_blk_arg1 == FULL_BLOCK_FAKE_ADDR);
5726 bm::word_t*** blk_root = blockman_.top_blocks_root();
5727 blk_root[i] = blk_blk_arg1;
5728 continue;
5729 }
5730 if ((bm::word_t*)blk_blk_arg1 == FULL_BLOCK_FAKE_ADDR ||
5731 (bm::word_t*)blk_blk_arg2 == FULL_BLOCK_FAKE_ADDR)
5732 {
5733 bm::word_t*** blk_root = blockman_.top_blocks_root();
5734 blk_root[i] = (bm::word_t**)FULL_BLOCK_FAKE_ADDR;
5735 continue;
5736 }
5737 bm::word_t** blk_blk = blockman_.alloc_top_subblock(i);
5738 bool any_blocks = false;
5739 unsigned j = 0;
5740 do
5741 {
5742 const bm::word_t* arg_blk1 = blk_blk_arg1 ? blk_blk_arg1[j] : 0;
5743 const bm::word_t* arg_blk2 = blk_blk_arg2 ? blk_blk_arg2[j] : 0;
5744 if (arg_blk1 == arg_blk2 && !arg_blk1)
5745 continue;
5746 bool need_opt = combine_operation_block_or(i, j, arg_blk1, arg_blk2);
5747 if (need_opt && opt_mode == opt_compress)
5748 blockman_.optimize_bit_block(i, j, opt_mode);
5749 any_blocks |= bool(blk_blk[j]);
5750 } while (++j < bm::set_sub_array_size);
5751
5752 if (!any_blocks)
5753 blockman_.free_top_subblock(i);
5754
5755 } // for i
5756
5757 if (opt_mode != opt_none)
5758 blockman_.free_temp_block();
5759
5760 return *this;
5761}
5762
5763//---------------------------------------------------------------------
5764
5765template<class Alloc>
5768 const bm::bvector<Alloc>& bv2,
5769 typename bm::bvector<Alloc>::optmode opt_mode)
5770{
5771 BM_ASSERT(!is_ro());
5772
5773 if (blockman_.is_init())
5774 blockman_.deinit_tree();
5775
5776 if (&bv1 == &bv2)
5777 return *this; // nothing to do empty result
5778
5779 if (this == &bv1)
5780 {
5781 this->bit_xor(bv2);
5782 return *this;
5783 }
5784 if (this == &bv2)
5785 {
5786 this->bit_xor(bv1);
5787 return *this;
5788 }
5789
5790 const blocks_manager_type& bman1 = bv1.get_blocks_manager();
5791 if (!bman1.is_init())
5792 {
5793 *this = bv2;
5794 return *this;
5795 }
5796 const blocks_manager_type& bman2 = bv2.get_blocks_manager();
5797 if (!bman2.is_init())
5798 {
5799 *this = bv1;
5800 return *this;
5801 }
5802
5803 unsigned top_blocks1 = bman1.top_block_size();
5804 unsigned top_blocks2 = bman2.top_block_size();
5805 unsigned top_blocks = (top_blocks2 > top_blocks1) ? top_blocks2 : top_blocks1;
5806 top_blocks = blockman_.reserve_top_blocks(top_blocks);
5807
5808 size_ = bv1.size_;
5809 if (size_ < bv2.size_)
5810 size_ = bv2.size_;
5811
5812 bm::word_t*** blk_root_arg1 = bv1.blockman_.top_blocks_root();
5813 bm::word_t*** blk_root_arg2 = bv2.blockman_.top_blocks_root();
5814
5815 for (unsigned i = 0; i < top_blocks; ++i)
5816 {
5817 bm::word_t** blk_blk_arg1 = (i < top_blocks1) ? blk_root_arg1[i] : 0;
5818 bm::word_t** blk_blk_arg2 = (i < top_blocks2) ? blk_root_arg2[i] : 0;
5819
5820 if (blk_blk_arg1 == blk_blk_arg2)
5821 {
5822 if (!blk_blk_arg1)
5823 continue;
5824 BM_ASSERT((bm::word_t*)blk_blk_arg1 == FULL_BLOCK_FAKE_ADDR);
5825 blockman_.deallocate_top_subblock(i);
5826 continue;
5827 }
5828 if ((bm::word_t*)blk_blk_arg1 == FULL_BLOCK_FAKE_ADDR)
5829 {
5830 if (!blk_blk_arg2)
5831 {
5832 set_full_sb:
5833 bm::word_t*** blk_root= blockman_.top_blocks_root();
5834 blk_root[i] = (bm::word_t**)FULL_BLOCK_FAKE_ADDR;
5835 continue;
5836 }
5837 blk_blk_arg1 = FULL_SUB_BLOCK_REAL_ADDR;
5838 }
5839 if ((bm::word_t*)blk_blk_arg2 == FULL_BLOCK_FAKE_ADDR)
5840 {
5841 if (!blk_blk_arg1)
5842 goto set_full_sb;
5843 blk_blk_arg2 = FULL_SUB_BLOCK_REAL_ADDR;
5844 }
5845
5846 bm::word_t** blk_blk = blockman_.alloc_top_subblock(i);
5847 bool any_blocks = false;
5848 unsigned j = 0;
5849 do
5850 {
5851 const bm::word_t* arg_blk1; const bm::word_t* arg_blk2;
5852 arg_blk1 = blk_blk_arg1 ? blk_blk_arg1[j] : 0;
5853 arg_blk2 = blk_blk_arg2 ? blk_blk_arg2[j] : 0;
5854
5855 if ((arg_blk1 == arg_blk2) &&
5856 (!arg_blk1 || arg_blk1 == FULL_BLOCK_FAKE_ADDR))
5857 continue; // 0 ^ 0 == 0 , 1 ^ 1 == 0 (nothing to do)
5858
5859 bool need_opt = combine_operation_block_xor(i, j, arg_blk1, arg_blk2);
5860 if (need_opt && opt_mode == opt_compress)
5861 blockman_.optimize_bit_block(i, j, opt_mode);
5862 any_blocks |= bool(blk_blk[j]);
5863 } while (++j < bm::set_sub_array_size);
5864
5865 if (!any_blocks)
5866 blockman_.free_top_subblock(i);
5867
5868 } // for i
5869
5870 if (opt_mode != opt_none)
5871 blockman_.free_temp_block();
5872
5873 return *this;
5874}
5875
5876//---------------------------------------------------------------------
5877
5878template<class Alloc>
5881 const bm::bvector<Alloc>& bv2,
5882 typename bm::bvector<Alloc>::optmode opt_mode)
5883{
5884 BM_ASSERT(!is_ro());
5885
5886 if (&bv1 == &bv2)
5887 {
5888 *this = bv1;
5889 return *this;
5890 }
5891 if (this == &bv1)
5892 {
5893 this->bit_and(bv2);
5894 return *this;
5895 }
5896 if (this == &bv2)
5897 {
5898 this->bit_and(bv1);
5899 return *this;
5900 }
5901 if (blockman_.is_init())
5902 blockman_.deinit_tree();
5903
5904 const blocks_manager_type& bman1 = bv1.get_blocks_manager();
5905 const blocks_manager_type& bman2 = bv2.get_blocks_manager();
5906 if (!bman1.is_init() || !bman2.is_init())
5907 return *this;
5908
5909 unsigned top_blocks1 = bman1.top_block_size();
5910 unsigned top_blocks2 = bman2.top_block_size();
5911 unsigned top_blocks = (top_blocks2 > top_blocks1) ? top_blocks2 : top_blocks1;
5912 top_blocks = blockman_.reserve_top_blocks(top_blocks);
5913
5914 size_ = bv1.size_;
5915 if (size_ < bv2.size_)
5916 size_ = bv2.size_;
5917
5918 bm::word_t*** blk_root_arg1 = bv1.blockman_.top_blocks_root();
5919 bm::word_t*** blk_root_arg2 = bv2.blockman_.top_blocks_root();
5920
5921 for (unsigned i = 0; i < top_blocks; ++i)
5922 {
5923 bm::word_t** blk_blk_arg1 = (i < top_blocks1) ? blk_root_arg1[i] : 0;
5924 bm::word_t** blk_blk_arg2 = (i < top_blocks2) ? blk_root_arg2[i] : 0;
5925
5926 if (blk_blk_arg1 == blk_blk_arg2)
5927 {
5928 if (!blk_blk_arg1)
5929 continue; // 0 & 0 == 0
5930 if ((bm::word_t*)blk_blk_arg1 == FULL_BLOCK_FAKE_ADDR)
5931 {
5932 bm::word_t*** blk_root = blockman_.top_blocks_root();
5933 blk_root[i] = (bm::word_t**)FULL_BLOCK_FAKE_ADDR;
5934 continue;
5935 }
5936 }
5937 if ((bm::word_t*)blk_blk_arg1 == FULL_BLOCK_FAKE_ADDR)
5938 blk_blk_arg1 = FULL_SUB_BLOCK_REAL_ADDR;
5939 if ((bm::word_t*)blk_blk_arg2 == FULL_BLOCK_FAKE_ADDR)
5940 blk_blk_arg2 = FULL_SUB_BLOCK_REAL_ADDR;
5941
5942 bm::word_t** blk_blk = blockman_.alloc_top_subblock(i);
5943 bool any_blocks = false;
5944 unsigned j = 0;
5945 do
5946 {
5947 const bm::word_t* arg_blk1; const bm::word_t* arg_blk2;
5948 arg_blk1 = blk_blk_arg1 ? blk_blk_arg1[j] : 0;
5949 arg_blk2 = blk_blk_arg2 ? blk_blk_arg2[j] : 0;
5950
5951 if ((arg_blk1 == arg_blk2) && !arg_blk1)
5952 continue; // 0 & 0 == 0
5953
5954 bool need_opt = combine_operation_block_and(i, j, arg_blk1, arg_blk2);
5955 if (need_opt && opt_mode == opt_compress)
5956 blockman_.optimize_bit_block(i, j, opt_mode);
5957 any_blocks |= bool(blk_blk[j]);
5958 } while (++j < bm::set_sub_array_size);
5959
5960 if (!any_blocks)
5961 blockman_.free_top_subblock(i);
5962
5963 } // for i
5964
5965 if (opt_mode != opt_none)
5966 blockman_.free_temp_block();
5967
5968 return *this;
5969}
5970
5971//---------------------------------------------------------------------
5972
5973template<class Alloc>
5976 const bm::bvector<Alloc>& bv2,
5977 typename bm::bvector<Alloc>::optmode opt_mode)
5978{
5979 BM_ASSERT(!is_ro());
5980
5981 if (&bv1 == &bv2)
5982 {
5983 this->bit_or(bv1);
5984 return *this;
5985 }
5986 if (this == &bv1)
5987 {
5988 this->bit_and(bv2);
5989 return *this;
5990 }
5991 if (this == &bv2)
5992 {
5993 this->bit_and(bv1);
5994 return *this;
5995 }
5996
5997 const blocks_manager_type& bman1 = bv1.get_blocks_manager();
5998 const blocks_manager_type& bman2 = bv2.get_blocks_manager();
5999 if (!bman1.is_init() || !bman2.is_init())
6000 return *this;
6001
6002 unsigned top_blocks1 = bman1.top_block_size();
6003 unsigned top_blocks2 = bman2.top_block_size();
6004 unsigned top_blocks = (top_blocks2 > top_blocks1) ? top_blocks2 : top_blocks1;
6005 top_blocks = blockman_.reserve_top_blocks(top_blocks);
6006
6007 size_type new_size = bv1.size_;
6008 if (new_size < bv2.size_)
6009 new_size = bv2.size_;
6010 if (size_ < new_size)
6011 size_ = new_size;
6012
6013 bm::word_t*** blk_root_arg1 = bv1.blockman_.top_blocks_root();
6014 bm::word_t*** blk_root_arg2 = bv2.blockman_.top_blocks_root();
6015
6016 for (unsigned i = 0; i < top_blocks; ++i)
6017 {
6018 bm::word_t** blk_blk_arg1 = (i < top_blocks1) ? blk_root_arg1[i] : 0;
6019 bm::word_t** blk_blk_arg2 = (i < top_blocks2) ? blk_root_arg2[i] : 0;
6020
6021 if (blk_blk_arg1 == blk_blk_arg2)
6022 {
6023 if (!blk_blk_arg1)
6024 continue; // 0 & 0 == 0
6025 if ((bm::word_t*)blk_blk_arg1 == FULL_BLOCK_FAKE_ADDR)
6026 {
6027 bm::word_t*** blk_root = blockman_.top_blocks_root();
6028 if (blk_root[i])
6029 blockman_.deallocate_top_subblock(i);
6030 BM_ASSERT(!blk_root[i]);
6031 blk_root[i] = (bm::word_t**)FULL_BLOCK_FAKE_ADDR;
6032 continue;
6033 }
6034 }
6035 if ((bm::word_t*)blk_blk_arg1 == FULL_BLOCK_FAKE_ADDR)
6036 blk_blk_arg1 = FULL_SUB_BLOCK_REAL_ADDR;
6037 if ((bm::word_t*)blk_blk_arg2 == FULL_BLOCK_FAKE_ADDR)
6038 blk_blk_arg2 = FULL_SUB_BLOCK_REAL_ADDR;
6039
6040 bm::word_t** blk_blk = blockman_.check_alloc_top_subblock(i);
6041 bool any_blocks = false;
6042 for (unsigned j = 0; j < bm::set_sub_array_size; ++j)
6043 {
6044 if (blk_blk[j] == FULL_BLOCK_FAKE_ADDR) // saturated: nothing to do
6045 {
6046 any_blocks = true;
6047 continue;
6048 }
6049
6050 const bm::word_t* arg_blk1; const bm::word_t* arg_blk2;
6051 arg_blk1 = blk_blk_arg1 ? blk_blk_arg1[j] : 0;
6052 arg_blk2 = blk_blk_arg2 ? blk_blk_arg2[j] : 0;
6053
6054 if ((arg_blk1 == arg_blk2) && !arg_blk1)
6055 continue; // 0 & 0 == 0
6056
6057 bool need_opt;
6058 if (!blk_blk[j]) // nothing to OR
6059 {
6060 need_opt =
6061 combine_operation_block_and(i, j, arg_blk1, arg_blk2);
6062 }
6063 else
6064 {
6065 need_opt =
6066 combine_operation_block_and_or(i, j, arg_blk1, arg_blk2);
6067 }
6068 if (need_opt && opt_mode == opt_compress)
6069 blockman_.optimize_bit_block(i, j, opt_mode);
6070
6071 any_blocks |= bool(blk_blk[j]);
6072
6073 } // for j
6074
6075 if (!any_blocks)
6076 blockman_.free_top_subblock(i);
6077
6078 } // for i
6079
6080 if (opt_mode != opt_none)
6081 blockman_.free_temp_block();
6082
6083 return *this;
6084}
6085
6086
6087
6088//---------------------------------------------------------------------
6089
6090template<class Alloc>
6093 const bm::bvector<Alloc>& bv2,
6094 typename bm::bvector<Alloc>::optmode opt_mode)
6095{
6096 BM_ASSERT(!is_ro());
6097
6098 if (blockman_.is_init())
6099 blockman_.deinit_tree();
6100
6101 if (&bv1 == &bv2)
6102 return *this; // nothing to do empty result
6103
6104 if (this == &bv1)
6105 {
6106 this->bit_sub(bv2);
6107 return *this;
6108 }
6109 if (this == &bv2)
6110 {
6111 this->bit_sub(bv1);
6112 return *this;
6113 }
6114
6115 const blocks_manager_type& bman1 = bv1.get_blocks_manager();
6116 const blocks_manager_type& bman2 = bv2.get_blocks_manager();
6117 if (!bman1.is_init())
6118 {
6119 return *this;
6120 }
6121 if (!bman2.is_init())
6122 {
6123 this->bit_or(bv1);
6124 return *this;
6125 }
6126
6127 unsigned top_blocks1 = bman1.top_block_size();
6128 unsigned top_blocks2 = bman2.top_block_size();
6129 unsigned top_blocks = (top_blocks2 > top_blocks1) ? top_blocks2 : top_blocks1;
6130 top_blocks = blockman_.reserve_top_blocks(top_blocks);
6131
6132 size_ = bv1.size_;
6133 if (size_ < bv2.size_)
6134 size_ = bv2.size_;
6135
6136 bm::word_t*** blk_root_arg1 = bv1.blockman_.top_blocks_root();
6137 bm::word_t*** blk_root_arg2 = bv2.blockman_.top_blocks_root();
6138
6139 for (unsigned i = 0; i < top_blocks; ++i)
6140 {
6141 bm::word_t** blk_blk_arg1 = (i < top_blocks1) ? blk_root_arg1[i] : 0;
6142 bm::word_t** blk_blk_arg2 = (i < top_blocks2) ? blk_root_arg2[i] : 0;
6143
6144 if (blk_blk_arg1 == blk_blk_arg2)
6145 continue; // 0 AND NOT 0 == 0
6146 if ((bm::word_t*)blk_blk_arg2 == FULL_BLOCK_FAKE_ADDR)
6147 continue;
6148 if ((bm::word_t*)blk_blk_arg1 == FULL_BLOCK_FAKE_ADDR)
6149 blk_blk_arg1 = FULL_SUB_BLOCK_REAL_ADDR;
6150
6151 bm::word_t** blk_blk = blockman_.alloc_top_subblock(i);
6152 bool any_blocks = false;
6153 unsigned j = 0;
6154 do
6155 {
6156 const bm::word_t* arg_blk1 = blk_blk_arg1 ? blk_blk_arg1[j] : 0;
6157 const bm::word_t* arg_blk2 = blk_blk_arg2 ? blk_blk_arg2[j] : 0;
6158 if ((arg_blk1 == arg_blk2) && !arg_blk1)
6159 continue; // 0 & ~0 == 0
6160
6161 bool need_opt = combine_operation_block_sub(i, j, arg_blk1, arg_blk2);
6162 if (need_opt && opt_mode == opt_compress)
6163 blockman_.optimize_bit_block(i, j, opt_mode);
6164 any_blocks |= bool(blk_blk[j]);
6165 } while (++j < bm::set_sub_array_size);
6166
6167 if (!any_blocks)
6168 blockman_.free_top_subblock(i);
6169
6170 } // for i
6171
6172 if (opt_mode != opt_none)
6173 blockman_.free_temp_block();
6174
6175 return *this;
6176}
6177
6178
6179//---------------------------------------------------------------------
6180
6181#define BM_OR_OP(x) \
6182 { \
6183 blk = blk_blk[j+x]; arg_blk = blk_blk_arg[j+x]; \
6184 if (blk != arg_blk) \
6185 combine_operation_block_or(i, j+x, blk, arg_blk); \
6186 }
6187
6188template<class Alloc>
6190{
6191 if (!bv.blockman_.is_init())
6192 return;
6193
6194 unsigned top_blocks = blockman_.top_block_size();
6195 if (size_ < bv.size_)
6196 size_ = bv.size_;
6197
6198 unsigned arg_top_blocks = bv.blockman_.top_block_size();
6199 top_blocks = blockman_.reserve_top_blocks(arg_top_blocks);
6200
6201 bm::word_t*** blk_root = blockman_.top_blocks_root();
6202 bm::word_t*** blk_root_arg = bv.blockman_.top_blocks_root();
6203
6204 for (unsigned i = 0; i < top_blocks; ++i)
6205 {
6206 bm::word_t** blk_blk = blk_root[i];
6207 bm::word_t** blk_blk_arg = (i < arg_top_blocks) ? blk_root_arg[i] : 0;
6208 if (blk_blk == blk_blk_arg || !blk_blk_arg) // nothing to do (0 OR 0 == 0)
6209 continue;
6210 if ((bm::word_t*)blk_blk == FULL_BLOCK_FAKE_ADDR)
6211 continue;
6212 if ((bm::word_t*)blk_blk_arg == FULL_BLOCK_FAKE_ADDR)
6213 {
6214 blockman_.deallocate_top_subblock(i);
6215 blk_root[i] = (bm::word_t**)FULL_BLOCK_FAKE_ADDR;
6216 continue;
6217 }
6218 if (!blk_blk)
6219 blk_blk = blockman_.alloc_top_subblock(i);
6220
6221 unsigned j = 0;
6222 bm::word_t* blk;
6223 const bm::word_t* arg_blk;
6224 do
6225 {
6226 #if defined(BM64_AVX2) || defined(BM64_AVX512)
6227 if (!avx2_test_all_eq_wave2(blk_blk + j, blk_blk_arg + j))
6228 {
6229 BM_OR_OP(0)
6230 BM_OR_OP(1)
6231 BM_OR_OP(2)
6232 BM_OR_OP(3)
6233 }
6234 j += 4;
6235 #elif defined(BM64_SSE4)
6236 if (!sse42_test_all_eq_wave2(blk_blk + j, blk_blk_arg + j))
6237 {
6238 BM_OR_OP(0)
6239 BM_OR_OP(1)
6240 }
6241 j += 2;
6242 #else
6243 BM_OR_OP(0)
6244 ++j;
6245 #endif
6246 } while (j < bm::set_sub_array_size);
6247 } // for i
6248}
6249
6250#undef BM_OR_OP
6251
6252//---------------------------------------------------------------------
6253
6254#define BM_XOR_OP(x) \
6255 { \
6256 blk = blk_blk[j+x]; arg_blk = blk_blk_arg[j+x]; \
6257 combine_operation_block_xor(i, j+x, blk, arg_blk); \
6258 }
6259
6260template<class Alloc>
6262{
6263 if (!bv.blockman_.is_init())
6264 return;
6265 if (!blockman_.is_init())
6266 {
6267 *this = bv;
6268 return;
6269 }
6270
6271 unsigned top_blocks = blockman_.top_block_size();
6272 if (size_ < bv.size_) // this vect shorter than the arg.
6273 {
6274 size_ = bv.size_;
6275 }
6276 unsigned arg_top_blocks = bv.blockman_.top_block_size();
6277 top_blocks = blockman_.reserve_top_blocks(arg_top_blocks);
6278
6279 bm::word_t*** blk_root = blockman_.top_blocks_root();
6280 bm::word_t*** blk_root_arg = bv.blockman_.top_blocks_root();
6281
6282 for (unsigned i = 0; i < top_blocks; ++i)
6283 {
6284 bm::word_t** blk_blk_arg = (i < arg_top_blocks) ? blk_root_arg[i] : 0;
6285 if (!blk_blk_arg)
6286 continue;
6287 bm::word_t** blk_blk = blk_root[i];
6288 if (blk_blk == blk_blk_arg) // nothing to do (any XOR 0 == 0)
6289 {
6290 if ((bm::word_t*)blk_blk == FULL_BLOCK_FAKE_ADDR)
6291 blk_root[i] = 0;
6292 continue;
6293 }
6294 if ((bm::word_t*)blk_blk == FULL_BLOCK_FAKE_ADDR)
6295 {
6296 if (!blk_blk_arg)
6297 continue;
6298 blk_blk = blockman_.check_alloc_top_subblock(i);
6299 }
6300 if ((bm::word_t*)blk_blk_arg == FULL_BLOCK_FAKE_ADDR)
6301 {
6302 if (!blk_blk)
6303 {
6304 blk_root[i] = (bm::word_t**) FULL_BLOCK_FAKE_ADDR;
6305 continue;
6306 }
6307 blk_blk_arg = FULL_SUB_BLOCK_REAL_ADDR;
6308 }
6309
6310 if (!blk_blk)
6311 blk_blk = blockman_.alloc_top_subblock(i);
6312
6313 unsigned j = 0;
6314 bm::word_t* blk;
6315 const bm::word_t* arg_blk;
6316 do
6317 {
6318 #if defined(BM64_AVX2) || defined(BM64_AVX512)
6319 if (!avx2_test_all_zero_wave2(blk_blk + j, blk_blk_arg + j))
6320 {
6321 BM_XOR_OP(0)
6322 BM_XOR_OP(1)
6323 BM_XOR_OP(2)
6324 BM_XOR_OP(3)
6325 }
6326 j += 4;
6327 #elif defined(BM64_SSE4)
6328 if (!sse42_test_all_zero_wave2(blk_blk + j, blk_blk_arg + j))
6329 {
6330 BM_XOR_OP(0)
6331 BM_XOR_OP(1)
6332 }
6333 j += 2;
6334 #else
6335 BM_XOR_OP(0)
6336 ++j;
6337 #endif
6338 } while (j < bm::set_sub_array_size);
6339 } // for i
6340}
6341
6342#undef BM_XOR_OP
6343
6344
6345//---------------------------------------------------------------------
6346
6347#define BM_AND_OP(x) if (0 != (blk = blk_blk[j+x])) \
6348 { \
6349 if (0 != (arg_blk = blk_blk_arg[j+x])) \
6350 { \
6351 combine_operation_block_and(i, j+x, blk, arg_blk); \
6352 if (opt_mode == opt_compress) \
6353 blockman_.optimize_bit_block(i, j+x, opt_mode); \
6354 } \
6355 else \
6356 blockman_.zero_block(i, j+x); \
6357 }
6358
6359template<class Alloc>
6361 typename bm::bvector<Alloc>::optmode opt_mode)
6362{
6363 if (!blockman_.is_init())
6364 return; // nothing to do, already empty
6365 if (!bv.blockman_.is_init())
6366 {
6367 clear(true);
6368 return;
6369 }
6370
6371 unsigned top_blocks = blockman_.top_block_size();
6372 if (size_ < bv.size_) // this vect shorter than the arg.
6373 size_ = bv.size_;
6374
6375 unsigned arg_top_blocks = bv.blockman_.top_block_size();
6376 top_blocks = blockman_.reserve_top_blocks(arg_top_blocks);
6377
6378
6379 bm::word_t*** blk_root = blockman_.top_blocks_root();
6380 bm::word_t*** blk_root_arg = bv.blockman_.top_blocks_root();
6381
6382 for (unsigned i = 0; i < top_blocks; ++i)
6383 {
6384 bm::word_t** blk_blk = blk_root[i];
6385 if (!blk_blk) // nothing to do (0 AND 1 == 0)
6386 continue;
6387 bm::word_t** blk_blk_arg = (i < arg_top_blocks) ? blk_root_arg[i] : 0;
6388 if (!blk_blk_arg) // free a whole group of blocks
6389 {
6390 if ((bm::word_t*)blk_blk == FULL_BLOCK_FAKE_ADDR)
6391 {
6392 blk_root[i] = 0;
6393 }
6394 else
6395 {
6396 for (unsigned j = 0; j < bm::set_sub_array_size; ++j)
6397 blockman_.zero_block(i, j);
6398 blockman_.deallocate_top_subblock(i);
6399 }
6400 continue;
6401 }
6402 if ((bm::word_t*)blk_blk_arg == FULL_BLOCK_FAKE_ADDR)
6403 continue; // any & 1 == any
6404
6405 if ((bm::word_t*)blk_blk == FULL_BLOCK_FAKE_ADDR)
6406 blk_blk = blockman_.check_alloc_top_subblock(i);
6407
6408 unsigned j = 0;
6409 bm::word_t* blk;
6410 const bm::word_t* arg_blk;
6411 do
6412 {
6413 #if defined(BM64_AVX2) || defined(BM64_AVX512)
6414 if (!avx2_test_all_zero_wave(blk_blk + j))
6415 {
6416 BM_AND_OP(0)
6417 BM_AND_OP(1)
6418 BM_AND_OP(2)
6419 BM_AND_OP(3)
6420 }
6421 j += 4;
6422 #elif defined(BM64_SSE4)
6423 if (!sse42_test_all_zero_wave(blk_blk + j))
6424 {
6425 BM_AND_OP(0)
6426 BM_AND_OP(1)
6427 }
6428 j += 2;
6429 #else
6430 BM_AND_OP(0)
6431 ++j;
6432 #endif
6433 } while (j < bm::set_sub_array_size);
6434 } // for i
6435}
6436
6437#undef BM_AND_OP
6438
6439
6440//---------------------------------------------------------------------
6441
6442#define BM_SUB_OP(x) \
6443 if ((0 != (blk = blk_blk[j+x])) && (0 != (arg_blk = blk_blk_arg[j+x]))) \
6444 combine_operation_block_sub(i, j+x, blk, arg_blk);
6445
6446
6447template<class Alloc>
6449{
6450 if (!blockman_.is_init() || !bv.blockman_.is_init())
6451 return;
6452
6453 unsigned top_blocks = blockman_.top_block_size();
6454 if (size_ < bv.size_) // this vect shorter than the arg.
6455 size_ = bv.size_;
6456
6457 unsigned arg_top_blocks = bv.blockman_.top_block_size();
6458 top_blocks = blockman_.reserve_top_blocks(arg_top_blocks);
6459
6460 bm::word_t*** blk_root = blockman_.top_blocks_root();
6461 bm::word_t*** blk_root_arg = bv.blockman_.top_blocks_root();
6462
6463 for (unsigned i = 0; i < top_blocks; ++i)
6464 {
6465 bm::word_t** blk_blk = blk_root[i];
6466 bm::word_t** blk_blk_arg = (i < arg_top_blocks) ? blk_root_arg[i] : 0;
6467 if (!blk_blk || !blk_blk_arg) // nothing to do (0 AND NOT 1 == 0)
6468 continue;
6469
6470 if ((bm::word_t*)blk_blk_arg == FULL_BLOCK_FAKE_ADDR) // zero result
6471 {
6472 blockman_.deallocate_top_subblock(i);
6473 continue;
6474 }
6475 if ((bm::word_t*)blk_blk == FULL_BLOCK_FAKE_ADDR)
6476 blk_blk = blockman_.check_alloc_top_subblock(i);
6477
6478 bm::word_t* blk;
6479 const bm::word_t* arg_blk;
6480 unsigned j = 0;
6481 do
6482 {
6483 #if defined(BM64_AVX2) || defined(BM64_AVX512)
6484 if (!avx2_test_all_zero_wave(blk_blk + j))
6485 {
6486 BM_SUB_OP(0)
6487 BM_SUB_OP(1)
6488 BM_SUB_OP(2)
6489 BM_SUB_OP(3)
6490 }
6491 j += 4;
6492 #elif defined(BM64_SSE4)
6493 if (!sse42_test_all_zero_wave(blk_blk + j))
6494 {
6495 BM_SUB_OP(0)
6496 BM_SUB_OP(1)
6497 }
6498 j += 2;
6499 #else
6500 BM_SUB_OP(0)
6501 ++j;
6502 #endif
6503 } while (j < bm::set_sub_array_size);
6504 } // for i
6505}
6506
6507#undef BM_SUB_OP
6508
6509//---------------------------------------------------------------------
6510
6511template<class Alloc>
6513 const bm::bvector<Alloc>& bv,
6514 bm::operation opcode)
6515{
6516 if (!blockman_.is_init())
6517 {
6518 if (opcode == BM_AND || opcode == BM_SUB)
6519 return;
6520 blockman_.init_tree();
6521 }
6522
6523 unsigned top_blocks = blockman_.top_block_size();
6524 unsigned arg_top_blocks = bv.blockman_.top_block_size();
6525
6526 if (arg_top_blocks > top_blocks)
6527 top_blocks = blockman_.reserve_top_blocks(arg_top_blocks);
6528
6529 if (size_ < bv.size_) // this vect shorter than the arg.
6530 {
6531 size_ = bv.size_;
6532 // stretch our capacity
6533 blockman_.reserve_top_blocks(arg_top_blocks);
6534 top_blocks = blockman_.top_block_size();
6535 }
6536 else
6537 if (size_ > bv.size_) // this vector larger
6538 {
6539 if (opcode == BM_AND) // clear the tail with zeros
6540 {
6541 set_range(bv.size_, size_ - 1, false);
6542 if (arg_top_blocks < top_blocks)
6543 {
6544 // not to scan blocks we already swiped
6545 top_blocks = arg_top_blocks;
6546 }
6547 }
6548 }
6549
6550 bm::word_t*** blk_root = blockman_.top_blocks_root();
6551 unsigned block_idx = 0;
6552 unsigned i, j;
6553
6554 // calculate effective top size to avoid overscan
6555 top_blocks = blockman_.top_block_size();
6556 if (top_blocks < bv.blockman_.top_block_size())
6557 {
6558 if (opcode != BM_AND)
6559 {
6560 top_blocks = bv.blockman_.top_block_size();
6561 }
6562 }
6563
6564 for (i = 0; i < top_blocks; ++i)
6565 {
6566 bm::word_t** blk_blk = blk_root[i];
6567 if (blk_blk == 0) // not allocated
6568 {
6569 if (opcode == BM_AND) // 0 AND anything == 0
6570 {
6571 block_idx += bm::set_sub_array_size;
6572 continue;
6573 }
6574 const bm::word_t* const* bvbb = bv.blockman_.get_topblock(i);
6575 if (bvbb == 0) // skip it because 0 OP 0 == 0
6576 {
6577 block_idx += bm::set_sub_array_size;
6578 continue;
6579 }
6580 // 0 - self, non-zero argument
6582 for (j = 0; j < bm::set_sub_array_size; ++j)
6583 {
6584 const bm::word_t* arg_blk = bv.blockman_.get_block(i, j);
6585 if (arg_blk )
6587 0, 0,
6588 arg_blk, BM_IS_GAP(arg_blk),
6589 opcode);
6590 } // for j
6591 continue;
6592 }
6593
6594 if (opcode == BM_AND)
6595 {
6597 for (j = 0; j < bm::set_sub_array_size; ++j)
6598 {
6599 bm::word_t* blk = blk_blk[j];
6600 if (blk)
6601 {
6602 const bm::word_t* arg_blk = bv.blockman_.get_block(i, j);
6603 if (arg_blk)
6605 BM_IS_GAP(blk), blk,
6606 arg_blk, BM_IS_GAP(arg_blk),
6607 opcode);
6608 else
6609 blockman_.zero_block(i, j);
6610 }
6611
6612 } // for j
6613 }
6614 else // OR, SUB, XOR
6615 {
6617 for (j = 0; j < bm::set_sub_array_size; ++j)
6618 {
6619 bm::word_t* blk = blk_blk[j];
6620 const bm::word_t* arg_blk = bv.blockman_.get_block(i, j);
6621 if (arg_blk || blk)
6622 combine_operation_with_block(r + j, BM_IS_GAP(blk), blk,
6623 arg_blk, BM_IS_GAP(arg_blk),
6624 opcode);
6625 } // for j
6626 }
6627 } // for i
6628
6629}
6630
6631//---------------------------------------------------------------------
6632
6633template<class Alloc>
6635 unsigned j,
6636 const bm::word_t* arg_blk1,
6637 const bm::word_t* arg_blk2)
6638{
6639 bm::gap_word_t tmp_buf[bm::gap_equiv_len * 3]; // temporary result
6640 if (!arg_blk1)
6641 {
6642 blockman_.clone_assign_block(i, j, arg_blk2);
6643 return 0;
6644 }
6645 if (!arg_blk2)
6646 {
6647 blockman_.clone_assign_block(i, j, arg_blk1);
6648 return 0;
6649 }
6650 if ((arg_blk1==FULL_BLOCK_FAKE_ADDR) || (arg_blk2==FULL_BLOCK_FAKE_ADDR))
6651 {
6652 blockman_.set_block_ptr(i, j, FULL_BLOCK_FAKE_ADDR);
6653 return 0;
6654 }
6655
6656 bool is_gap1 = BM_IS_GAP(arg_blk1);
6657 bool is_gap2 = BM_IS_GAP(arg_blk2);
6658
6659 if (is_gap1 | is_gap2) // at least one GAP
6660 {
6661 if (is_gap1 & is_gap2) // both GAPS
6662 {
6663 unsigned res_len;
6665 BMGAP_PTR(arg_blk2),
6666 tmp_buf, res_len);
6667 blockman_.clone_gap_block(i, j, tmp_buf, res_len);
6668 return 0;
6669 }
6670 // one GAP one bit block
6671 const bm::word_t* arg_block;
6672 const bm::gap_word_t* arg_gap;
6673 if (is_gap1) // arg1 is GAP -> clone arg2(bit)
6674 {
6675 arg_block = arg_blk2;
6676 arg_gap = BMGAP_PTR(arg_blk1);
6677 }
6678 else // arg2 is GAP
6679 {
6680 arg_block = arg_blk1;
6681 arg_gap = BMGAP_PTR(arg_blk2);
6682 }
6683 bm::word_t* block = blockman_.clone_assign_block(i, j, arg_block);
6684 bm::gap_add_to_bitset(block, arg_gap);
6685
6686 return true; // optimization may be needed
6687 }
6688
6689 // 2 bit-blocks
6690 //
6691 bm::word_t* block = blockman_.borrow_tempblock();
6692 blockman_.set_block_ptr(i, j, block);
6693
6694 bool all_one = bm::bit_block_or_2way(block, arg_blk1, arg_blk2);
6695 if (all_one)
6696 {
6697 blockman_.set_block_ptr(i, j, FULL_BLOCK_FAKE_ADDR);
6698 blockman_.return_tempblock(block);
6699 return 0;
6700 }
6701 return true;
6702}
6703
6704//---------------------------------------------------------------------
6705
6706template<class Alloc>
6708 unsigned j,
6709 const bm::word_t* arg_blk1,
6710 const bm::word_t* arg_blk2)
6711{
6712 bm::gap_word_t tmp_buf[bm::gap_equiv_len * 3]; // temporary result
6713
6714 if (!arg_blk1)
6715 {
6716 blockman_.clone_assign_block(i, j, arg_blk2);
6717 return 0;
6718 }
6719 if (!arg_blk2)
6720 {
6721 blockman_.clone_assign_block(i, j, arg_blk1);
6722 return 0;
6723 }
6724 if (arg_blk1==FULL_BLOCK_FAKE_ADDR)
6725 {
6726 BM_ASSERT(!IS_FULL_BLOCK(arg_blk2));
6727 blockman_.clone_assign_block(i, j, arg_blk2, true); // invert
6728 return 0;
6729 }
6730 if (arg_blk2==FULL_BLOCK_FAKE_ADDR)
6731 {
6732 BM_ASSERT(!IS_FULL_BLOCK(arg_blk1));
6733 blockman_.clone_assign_block(i, j, arg_blk1, true); // invert
6734 return 0;
6735 }
6736
6737 bool is_gap1 = BM_IS_GAP(arg_blk1);
6738 bool is_gap2 = BM_IS_GAP(arg_blk2);
6739
6740 if (is_gap1 | is_gap2) // at least one GAP
6741 {
6742 if (is_gap1 & is_gap2) // both GAPS
6743 {
6744 unsigned res_len;
6746 BMGAP_PTR(arg_blk2),
6747 tmp_buf, res_len);
6748 blockman_.clone_gap_block(i, j, tmp_buf, res_len);
6749 return 0;
6750 }
6751 // one GAP one bit block
6752 const bm::word_t* arg_block;
6753 const bm::gap_word_t* arg_gap;
6754 if (is_gap1) // arg1 is GAP -> clone arg2(bit)
6755 {
6756 arg_block = arg_blk2;
6757 arg_gap = BMGAP_PTR(arg_blk1);
6758 }
6759 else // arg2 is GAP
6760 {
6761 arg_block = arg_blk1;
6762 arg_gap = BMGAP_PTR(arg_blk2);
6763 }
6764 bm::word_t* block = blockman_.clone_assign_block(i, j, arg_block);
6765 bm::gap_xor_to_bitset(block, arg_gap);
6766
6767 return true; // optimization may be needed
6768 }
6769
6770 // 2 bit-blocks
6771 //
6772 bm::word_t* block = blockman_.borrow_tempblock();
6773 blockman_.set_block_ptr(i, j, block);
6774
6775 bm::id64_t or_mask = bm::bit_block_xor_2way(block, arg_blk1, arg_blk2);
6776 if (!or_mask)
6777 {
6778 blockman_.set_block_ptr(i, j, 0);
6779 blockman_.return_tempblock(block);
6780 return 0;
6781 }
6782
6783 return true;
6784}
6785
6786//---------------------------------------------------------------------
6787
6788template<class Alloc>
6790 unsigned j,
6791 const bm::word_t* arg_blk1,
6792 const bm::word_t* arg_blk2)
6793{
6794 bm::gap_word_t tmp_buf[bm::gap_equiv_len * 3]; // temporary result
6795
6796 if (!arg_blk1 || !arg_blk2)
6797 return 0;
6798 if ((arg_blk1==FULL_BLOCK_FAKE_ADDR) && (arg_blk2==FULL_BLOCK_FAKE_ADDR))
6799 {
6800 blockman_.set_block_ptr(i, j, FULL_BLOCK_FAKE_ADDR);
6801 return 0;
6802 }
6803 if (arg_blk1==FULL_BLOCK_FAKE_ADDR)
6804 {
6805 blockman_.clone_assign_block(i, j, arg_blk2);
6806 return 0;
6807 }
6808 if (arg_blk2==FULL_BLOCK_FAKE_ADDR)
6809 {
6810 blockman_.clone_assign_block(i, j, arg_blk1);
6811 return 0;
6812 }
6813
6814 bool is_gap1 = BM_IS_GAP(arg_blk1);
6815 bool is_gap2 = BM_IS_GAP(arg_blk2);
6816
6817 if (is_gap1 | is_gap2) // at least one GAP
6818 {
6819 if (is_gap1 & is_gap2) // both GAPS
6820 {
6821 unsigned res_len;
6823 BMGAP_PTR(arg_blk2),
6824 tmp_buf, res_len);
6825 blockman_.clone_gap_block(i, j, tmp_buf, res_len);
6826 return 0;
6827 }
6828 // one GAP one bit block
6829 const bm::word_t* arg_block;
6830 const bm::gap_word_t* arg_gap;
6831 if (is_gap1) // arg1 is GAP -> clone arg2(bit)
6832 {
6833 arg_block = arg_blk2;
6834 arg_gap = BMGAP_PTR(arg_blk1);
6835 }
6836 else // arg2 is GAP
6837 {
6838 arg_block = arg_blk1;
6839 arg_gap = BMGAP_PTR(arg_blk2);
6840 }
6841 bm::word_t* block = blockman_.clone_assign_block(i, j, arg_block);
6842 bm::gap_and_to_bitset(block, arg_gap);
6843
6844 bool all_z = bm::bit_is_all_zero(block); // maybe ALL empty block?
6845 if (all_z)
6846 {
6847 blockman_.set_block_ptr(i, j, 0);
6848 blockman_.return_tempblock(block);
6849 return false;
6850 }
6851
6852 return true; // optimization may be needed
6853 }
6854
6855 // 2 bit-blocks
6856 //
6857 bm::word_t* block = blockman_.borrow_tempblock();
6858 blockman_.set_block_ptr(i, j, block);
6859
6860 bm::id64_t digest = bm::bit_block_and_2way(block, arg_blk1, arg_blk2, ~0ull);
6861 if (!digest)
6862 {
6863 blockman_.set_block_ptr(i, j, 0);
6864 blockman_.return_tempblock(block);
6865 return 0;
6866 }
6867
6868 return true;
6869}
6870
6871//---------------------------------------------------------------------
6872
6873template<class Alloc>
6875 unsigned j,
6876 const bm::word_t* arg_blk1,
6877 const bm::word_t* arg_blk2)
6878{
6879 bm::gap_word_t tmp_buf[bm::gap_equiv_len * 3]; // temporary result
6880 bm::word_t* blk = blockman_.get_block_ptr(i, j);
6881 BM_ASSERT(blk); // target block MUST be allocated
6882
6883 if (!arg_blk1 || !arg_blk2)
6884 return 0;
6885 if ((arg_blk1==FULL_BLOCK_FAKE_ADDR) && (arg_blk2==FULL_BLOCK_FAKE_ADDR))
6886 {
6887 if (blk)
6888 blockman_.zero_block(i, j); // free target block and assign FULL
6889 blockman_.set_block_ptr(i, j, FULL_BLOCK_FAKE_ADDR);
6890 return 0;
6891 }
6892 if (arg_blk1==FULL_BLOCK_FAKE_ADDR)
6893 {
6894 combine_operation_block_or(i, j, blk, arg_blk2);
6895 return 0;
6896 }
6897 if (arg_blk2==FULL_BLOCK_FAKE_ADDR)
6898 {
6899 combine_operation_block_or(i, j, blk, arg_blk1);
6900 return 0;
6901 }
6902
6903 blk = blockman_.deoptimize_block_no_check(blk, i, j);
6904
6905 bool is_gap1 = BM_IS_GAP(arg_blk1);
6906 bool is_gap2 = BM_IS_GAP(arg_blk2);
6907
6908 if (is_gap1 | is_gap2) // at least one GAP
6909 {
6910 if (is_gap1 & is_gap2) // both GAPS
6911 {
6912 unsigned res_len;
6913 bm::gap_operation_and(BMGAP_PTR(arg_blk1), BMGAP_PTR(arg_blk2),
6914 tmp_buf, res_len);
6915 bm::gap_add_to_bitset(blk, tmp_buf, res_len);
6916 bool all_one = bm::is_bits_one((bm::wordop_t*) blk);
6917 if (all_one)
6918 {
6919 blockman_.return_tempblock(blk);
6920 blockman_.set_block_ptr(i, j, FULL_BLOCK_FAKE_ADDR);
6921 return false;
6922 }
6923 return true;
6924 }
6925 // one GAP, one bit
6926 const bm::word_t* arg_block;
6927 const bm::gap_word_t* arg_gap;
6928 if (is_gap1) // arg1 is GAP -> clone arg2(bit)
6929 {
6930 arg_block = arg_blk2;
6931 arg_gap = BMGAP_PTR(arg_blk1);
6932 }
6933 else // arg2 is GAP
6934 {
6935 arg_block = arg_blk1;
6936 arg_gap = BMGAP_PTR(arg_blk2);
6937 }
6938 bm::word_t* tmp_blk = blockman_.check_allocate_tempblock();
6939 bm::bit_block_copy(tmp_blk, arg_block);
6940 bm::gap_and_to_bitset(tmp_blk, arg_gap); // bit := bit AND gap
6941 bool all_one = bm::bit_block_or(blk, tmp_blk); // target |= bit
6942 if (all_one)
6943 {
6945 blockman_.return_tempblock(blk);
6946 blockman_.set_block_ptr(i, j, FULL_BLOCK_FAKE_ADDR);
6947 return false;
6948 }
6949 return true; // optimization may be needed
6950 }
6951
6952 // 1+2 bit-blocks
6953 //
6954 bm::id64_t digest_and = ~0ull;
6955 bm::id64_t digest =
6956 bm::bit_block_and_or_2way(blk, arg_blk1, arg_blk2, digest_and);
6957 if (digest == digest_and)
6958 {
6959 bool all_one = bm::is_bits_one((bm::wordop_t*) blk);
6960 if (all_one)
6961 {
6962 blockman_.return_tempblock(blk);
6963 blockman_.set_block_ptr(i, j, FULL_BLOCK_FAKE_ADDR);
6964 return false;
6965 }
6966 }
6967 return true; // optimization may be needed
6968}
6969
6970
6971//---------------------------------------------------------------------
6972
6973template<class Alloc>
6975 unsigned j,
6976 const bm::word_t* arg_blk1,
6977 const bm::word_t* arg_blk2)
6978{
6979 bm::gap_word_t tmp_buf[bm::gap_equiv_len * 3]; // temporary result
6980
6981 if (!arg_blk1)
6982 return 0;
6983 if (!arg_blk2)
6984 {
6985 blockman_.clone_assign_block(i, j, arg_blk1);
6986 return 0;
6987 }
6988 if (arg_blk2==FULL_BLOCK_FAKE_ADDR)
6989 return 0;
6990 if (arg_blk1==FULL_BLOCK_FAKE_ADDR)
6991 arg_blk1 = FULL_BLOCK_REAL_ADDR;
6992
6993 bool is_gap1 = BM_IS_GAP(arg_blk1);
6994 bool is_gap2 = BM_IS_GAP(arg_blk2);
6995
6996 if (is_gap1 | is_gap2) // at least one GAP
6997 {
6998 if (is_gap1 & is_gap2) // both GAPS
6999 {
7000 unsigned res_len;
7002 BMGAP_PTR(arg_blk2),
7003 tmp_buf, res_len);
7004 blockman_.clone_gap_block(i, j, tmp_buf, res_len);
7005 return 0;
7006 }
7007
7008 if (is_gap1)
7009 {
7010 bm::word_t* block = blockman_.borrow_tempblock();
7011 blockman_.set_block_ptr(i, j, block);
7012 bm::gap_convert_to_bitset(block, BMGAP_PTR(arg_blk1));
7013 bm::id64_t acc = bm::bit_block_sub(block, arg_blk2);
7014 if (!acc)
7015 {
7016 blockman_.set_block_ptr(i, j, 0);
7017 blockman_.return_tempblock(block);
7018 return 0;
7019 }
7020 return true;
7021 }
7022 BM_ASSERT(is_gap2);
7023 bm::word_t* block = blockman_.clone_assign_block(i, j, arg_blk1);
7024 bm::gap_sub_to_bitset(block, BMGAP_PTR(arg_blk2));
7025
7026 return true; // optimization may be needed
7027 }
7028
7029 // 2 bit-blocks:
7030 //
7031 bm::word_t* block = blockman_.borrow_tempblock();
7032 blockman_.set_block_ptr(i, j, block);
7033
7034 bm::id64_t digest = bm::bit_block_sub_2way(block, arg_blk1, arg_blk2, ~0ull);
7035 if (!digest)
7036 {
7037 blockman_.set_block_ptr(i, j, 0);
7038 blockman_.return_tempblock(block);
7039 return 0;
7040 }
7041 return true;
7042}
7043
7044
7045//---------------------------------------------------------------------
7046
7047template<class Alloc>
7049 unsigned i, unsigned j,
7050 bm::word_t* blk, const bm::word_t* arg_blk)
7051{
7052 bm::gap_word_t tmp_buf[bm::gap_equiv_len * 3]; // temporary result
7053 if (IS_FULL_BLOCK(blk) || !arg_blk) // all bits are set
7054 return; // nothing to do
7055
7056 if (IS_FULL_BLOCK(arg_blk))
7057 {
7058 if (blk)
7059 blockman_.zero_block(i, j); // free target block and assign FULL
7060 blockman_.set_block_ptr(i, j, FULL_BLOCK_FAKE_ADDR);
7061 return;
7062 }
7063
7064 if (BM_IS_GAP(blk)) // our block GAP-type
7065 {
7066 bm::gap_word_t* gap_blk = BMGAP_PTR(blk);
7067 if (BM_IS_GAP(arg_blk)) // both blocks GAP-type
7068 {
7069 const bm::gap_word_t* res; unsigned res_len;
7070 res = bm::gap_operation_or(gap_blk, BMGAP_PTR(arg_blk),
7071 tmp_buf, res_len);
7072 BM_ASSERT(res == tmp_buf);
7073 blockman_.assign_gap_check(i, j, res, ++res_len, blk, tmp_buf);
7074 return;
7075 }
7076 // GAP or BIT
7077 //
7078 bm::word_t* new_blk = blockman_.get_allocator().alloc_bit_block();
7079 bm::bit_block_copy(new_blk, arg_blk);
7080 bm::gap_add_to_bitset(new_blk, gap_blk);
7081
7082 blockman_.get_allocator().free_gap_block(gap_blk, blockman_.glen());
7083 blockman_.set_block_ptr(i, j, new_blk);
7084
7085 return;
7086 }
7087 else // our block is BITSET-type (but NOT FULL_BLOCK we checked it)
7088 {
7089 if (BM_IS_GAP(arg_blk)) // argument block is GAP-type
7090 {
7091 const bm::gap_word_t* arg_gap = BMGAP_PTR(arg_blk);
7092 if (!blk)
7093 {
7094 bool gap = true;
7095 blk = blockman_.clone_gap_block(arg_gap, gap);
7096 blockman_.set_block(i, j, blk, gap);
7097 return;
7098 }
7099
7100 // BIT & GAP
7101 bm::gap_add_to_bitset(blk, arg_gap);
7102 return;
7103 } // if arg_gap
7104 }
7105
7106 if (!blk)
7107 {
7108 blk = blockman_.alloc_.alloc_bit_block();
7109 bm::bit_block_copy(blk, arg_blk);
7110 blockman_.set_block_ptr(i, j, blk);
7111 return;
7112 }
7113
7114 bool all_one = bm::bit_block_or(blk, arg_blk);
7115 if (all_one)
7116 {
7118 blockman_.get_allocator().free_bit_block(blk);
7119 blockman_.set_block_ptr(i, j, FULL_BLOCK_FAKE_ADDR);
7120 }
7121
7122}
7123
7124//---------------------------------------------------------------------
7125
7126template<class Alloc>
7128 unsigned i, unsigned j,
7129 bm::word_t* blk, const bm::word_t* arg_blk)
7130{
7131 bm::gap_word_t tmp_buf[bm::gap_equiv_len * 3]; // temporary result
7132 if (!arg_blk) // all bits are set
7133 return; // nothing to do
7134
7135 if (IS_FULL_BLOCK(arg_blk))
7136 {
7137 if (blk)
7138 {
7139 if (BM_IS_GAP(blk))
7141 else
7142 {
7143 if (IS_FULL_BLOCK(blk)) // 1 xor 1 = 0
7144 blockman_.set_block_ptr(i, j, 0);
7145 else
7146 bm::bit_invert((wordop_t*) blk);
7147 }
7148 }
7149 else // blk == 0
7150 {
7151 blockman_.set_block_ptr(i, j, FULL_BLOCK_FAKE_ADDR);
7152 }
7153 return;
7154 }
7155 if (IS_FULL_BLOCK(blk))
7156 {
7157 if (!arg_blk)
7158 return;
7159 // deoptimize block
7160 blk = blockman_.get_allocator().alloc_bit_block();
7161 bm::bit_block_set(blk, ~0u);
7162 blockman_.set_block_ptr(i, j, blk);
7163 }
7164
7165
7166 if (BM_IS_GAP(blk)) // our block GAP-type
7167 {
7168 bm::gap_word_t* gap_blk = BMGAP_PTR(blk);
7169 if (BM_IS_GAP(arg_blk)) // both blocks GAP-type
7170 {
7171 const bm::gap_word_t* res;
7172 unsigned res_len;
7173 res = bm::gap_operation_xor(gap_blk,
7174 BMGAP_PTR(arg_blk),
7175 tmp_buf,
7176 res_len);
7177 BM_ASSERT(res == tmp_buf);
7178 blockman_.assign_gap_check(i, j, res, ++res_len, blk, tmp_buf);
7179 return;
7180 }
7181 // GAP or BIT
7182 //
7183 bm::word_t* new_blk = blockman_.get_allocator().alloc_bit_block();
7184 bm::bit_block_copy(new_blk, arg_blk);
7185 bm::gap_xor_to_bitset(new_blk, gap_blk);
7186
7187 blockman_.get_allocator().free_gap_block(gap_blk, blockman_.glen());
7188 blockman_.set_block_ptr(i, j, new_blk);
7189
7190 return;
7191 }
7192 else // our block is BITSET-type (but NOT FULL_BLOCK we checked it)
7193 {
7194 if (BM_IS_GAP(arg_blk)) // argument block is GAP-type
7195 {
7196 const bm::gap_word_t* arg_gap = BMGAP_PTR(arg_blk);
7197 if (!blk)
7198 {
7199 bool gap = true;
7200 blk = blockman_.clone_gap_block(arg_gap, gap);
7201 blockman_.set_block(i, j, blk, gap);
7202 return;
7203 }
7204 // BIT & GAP
7205 bm::gap_xor_to_bitset(blk, arg_gap);
7206 return;
7207 } // if arg_gap
7208 }
7209
7210 if (!blk)
7211 {
7212 blk = blockman_.alloc_.alloc_bit_block();
7213 bm::bit_block_copy(blk, arg_blk);
7214 blockman_.set_block_ptr(i, j, blk);
7215 return;
7216 }
7217
7218 auto any_bits = bm::bit_block_xor(blk, arg_blk);
7219 if (!any_bits)
7220 {
7221 blockman_.get_allocator().free_bit_block(blk);
7222 blockman_.set_block_ptr(i, j, 0);
7223 }
7224}
7225
7226
7227//---------------------------------------------------------------------
7228
7229
7230template<class Alloc>
7232 unsigned i, unsigned j, bm::word_t* blk, const bm::word_t* arg_blk)
7233{
7234 BM_ASSERT(arg_blk && blk);
7235
7236 if (IS_FULL_BLOCK(arg_blk))
7237 return; // nothing to do
7238
7239 gap_word_t tmp_buf[bm::gap_equiv_len * 3]; // temporary result
7240
7241 if (BM_IS_GAP(blk)) // our block GAP-type
7242 {
7243 bm::gap_word_t* gap_blk = BMGAP_PTR(blk);
7244 if (BM_IS_GAP(arg_blk)) // both blocks GAP-type
7245 {
7246 const bm::gap_word_t* res;
7247 unsigned res_len;
7248 res = bm::gap_operation_and(gap_blk,
7249 BMGAP_PTR(arg_blk),
7250 tmp_buf,
7251 res_len);
7252 BM_ASSERT(res == tmp_buf);
7253 blockman_.assign_gap_check(i, j, res, ++res_len, blk, tmp_buf);
7254 return;
7255 }
7256 // GAP & BIT
7257 //
7258 bm::word_t* new_blk = blockman_.get_allocator().alloc_bit_block();
7259 bm::bit_block_copy(new_blk, arg_blk); // TODO: copy+digest in one pass
7260 bm::id64_t d0 = bm::calc_block_digest0(new_blk);
7261
7262 bm::gap_and_to_bitset(new_blk, gap_blk, d0);
7263
7264 bm::id64_t d0_1 = bm::update_block_digest0(new_blk, d0);
7266 if (!d0_1)
7267 {
7269 blockman_.get_allocator().free_bit_block(new_blk);
7270 new_blk = 0;
7271 }
7272 else
7273 {
7274 BM_ASSERT(!bm::bit_is_all_zero(new_blk));
7275 }
7276 blockman_.get_allocator().free_gap_block(gap_blk, blockman_.glen());
7277 blockman_.set_block_ptr(i, j, new_blk);
7278
7279 return;
7280 }
7281 else // our block is BITSET-type or FULL_BLOCK
7282 {
7283 if (BM_IS_GAP(arg_blk)) // argument block is GAP-type
7284 {
7285 const bm::gap_word_t* arg_gap = BMGAP_PTR(arg_blk);
7286 if (bm::gap_is_all_zero(arg_gap))
7287 {
7288 blockman_.zero_block(i, j);
7289 return;
7290 }
7291 // FULL & GAP is common when AND with set_range() mask
7292 //
7293 if (IS_FULL_BLOCK(blk)) // FULL & gap = gap
7294 {
7295 bool is_new_gap;
7296 bm::word_t* new_blk = blockman_.clone_gap_block(arg_gap, is_new_gap);
7297 if (is_new_gap)
7298 BMSET_PTRGAP(new_blk);
7299
7300 blockman_.set_block_ptr(i, j, new_blk);
7301
7302 return;
7303 }
7304 // BIT & GAP
7305 bm::gap_and_to_bitset(blk, arg_gap);
7306 bool empty = bm::bit_is_all_zero(blk);
7307 if (empty) // operation converged bit-block to empty
7308 blockman_.zero_block(i, j);
7309
7310 return;
7311 } // if arg_gap
7312 }
7313
7314 // FULL & bit is common when AND with set_range() mask
7315 //
7316 if (IS_FULL_BLOCK(blk)) // FULL & bit = bit
7317 {
7318 bm::word_t* new_blk = blockman_.get_allocator().alloc_bit_block();
7319 bm::bit_block_copy(new_blk, arg_blk);
7320 blockman_.set_block_ptr(i, j, new_blk);
7321
7322 return;
7323 }
7324 auto any_bits = bm::bit_block_and(blk, arg_blk);
7325 if (!any_bits)
7326 {
7327 blockman_.get_allocator().free_bit_block(blk);
7328 blockman_.set_block_ptr(i, j, 0);
7329 }
7330}
7331
7332//---------------------------------------------------------------------
7333
7334template<class Alloc>
7336 unsigned i, unsigned j, bm::word_t* blk, const bm::word_t* arg_blk)
7337{
7338 BM_ASSERT(arg_blk && blk);
7339
7340 if (IS_FULL_BLOCK(arg_blk))
7341 {
7342 blockman_.zero_block(i, j);
7343 return;
7344 }
7345
7346 gap_word_t tmp_buf[bm::gap_equiv_len * 3]; // temporary result
7347
7348 if (BM_IS_GAP(blk)) // our block GAP-type
7349 {
7350 bm::gap_word_t* gap_blk = BMGAP_PTR(blk);
7351 if (BM_IS_GAP(arg_blk)) // both blocks GAP-type
7352 {
7353 const bm::gap_word_t* res;
7354 unsigned res_len;
7355 res = bm::gap_operation_sub(gap_blk,
7356 BMGAP_PTR(arg_blk),
7357 tmp_buf,
7358 res_len);
7359
7360 BM_ASSERT(res == tmp_buf);
7361 BM_ASSERT(!(res == tmp_buf && res_len == 0));
7362
7363 blockman_.assign_gap_check(i, j, res, ++res_len, blk, tmp_buf);
7364 return;
7365 }
7366 // else: argument is BITSET-type (own block is GAP)
7367 blk = blockman_.convert_gap2bitset(i, j, gap_blk);
7368 // fall through to bit-block to bit-block operation
7369 }
7370 else // our block is BITSET-type or FULL_BLOCK
7371 {
7372 if (BM_IS_GAP(arg_blk)) // argument block is GAP-type
7373 {
7374 if (!IS_FULL_BLOCK(blk)) // gap combined to bitset
7375 {
7376 bm::gap_sub_to_bitset(blk, BMGAP_PTR(arg_blk));
7377 bool empty = bm::bit_is_all_zero(blk);
7378 if (empty) // operation converged bit-block to empty
7379 blockman_.zero_block(i, j);
7380 return;
7381 }
7382 // the worst case: convert arg block to bitset
7383 arg_blk =
7384 gap_convert_to_bitset_smart(blockman_.check_allocate_tempblock(),
7385 BMGAP_PTR(arg_blk),
7387 }
7388 }
7389
7390 // Now here we combine two plain bitblocks using supplied bit function.
7391 bm::word_t* dst = blk;
7392
7393 bm::word_t* ret;
7394 if (!dst || !arg_blk)
7395 return;
7396
7397 ret = bm::bit_operation_sub(dst, arg_blk);
7398 if (ret && ret == arg_blk)
7399 {
7400 ret = blockman_.get_allocator().alloc_bit_block();
7401 bm::bit_andnot_arr_ffmask(ret, arg_blk);
7402 }
7403
7404 if (ret != dst) // block mutation
7405 {
7406 blockman_.set_block_ptr(i, j, ret);
7407 if (IS_VALID_ADDR(dst))
7408 blockman_.get_allocator().free_bit_block(dst);
7409 }
7410}
7411
7412//---------------------------------------------------------------------
7413
7414template<class Alloc>
7415void
7417 bool gap,
7418 bm::word_t* blk,
7419 const bm::word_t* arg_blk,
7420 bool arg_gap,
7421 bm::operation opcode)
7422{
7423 gap_word_t tmp_buf[bm::gap_equiv_len * 3]; // temporary result
7424 const bm::gap_word_t* res;
7425 unsigned res_len;
7426
7427 if (opcode == BM_OR || opcode == BM_XOR)
7428 {
7429 if (!blk && arg_gap)
7430 {
7431 blk = blockman_.clone_gap_block(BMGAP_PTR(arg_blk), gap);
7432 blockman_.set_block(nb, blk, gap);
7433 return;
7434 }
7435 }
7436
7437 if (gap) // our block GAP-type
7438 {
7439 if (arg_gap) // both blocks GAP-type
7440 {
7441 {
7444 BM_ASSERT(gfunc);
7445 res = (*gfunc)(BMGAP_PTR(blk),
7446 BMGAP_PTR(arg_blk),
7447 tmp_buf,
7448 res_len);
7449 }
7450 BM_ASSERT(res == tmp_buf);
7451 BM_ASSERT(!(res == tmp_buf && res_len == 0));
7452
7453 // if as a result of the operation gap block turned to zero
7454 // we can now replace it with NULL
7455 if (bm::gap_is_all_zero(res))
7456 blockman_.zero_block(nb);
7457 else
7458 blockman_.assign_gap(nb, res, ++res_len, blk, tmp_buf);
7459 return;
7460 }
7461 else // argument is BITSET-type (own block is GAP)
7462 {
7463 // since we can not combine blocks of mixed type
7464 // we need to convert our block to bitset
7465
7466 if (arg_blk == 0) // Combining against an empty block
7467 {
7468 switch (opcode)
7469 {
7470 case BM_AND: // ("Value" AND 0) == 0
7471 blockman_.zero_block(nb);
7472 return;
7473 case BM_OR: case BM_SUB: case BM_XOR:
7474 return; // nothing to do
7475 default:
7476 return; // nothing to do
7477 }
7478 }
7479 gap_word_t* gap_blk = BMGAP_PTR(blk);
7480 blk = blockman_.convert_gap2bitset(nb, gap_blk);
7481 }
7482 }
7483 else // our block is BITSET-type
7484 {
7485 if (arg_gap) // argument block is GAP-type
7486 {
7487 if (IS_VALID_ADDR(blk))
7488 {
7489 // special case, maybe we can do the job without
7490 // converting the GAP argument to bitblock
7493 BM_ASSERT(gfunc);
7494 (*gfunc)(blk, BMGAP_PTR(arg_blk));
7495
7496 // TODO: commented out optimization, because it can be very slow
7497 // need to take into account previous operation not to make
7498 // fruitless attempts here
7499 //blockman_.optimize_bit_block(nb);
7500 return;
7501 }
7502
7503 // the worst case we need to convert argument block to
7504 // bitset type.
7505 gap_word_t* temp_blk = (gap_word_t*) blockman_.check_allocate_tempblock();
7506 arg_blk =
7508 BMGAP_PTR(arg_blk),
7510 }
7511 }
7512
7513 // Now here we combine two plain bitblocks using supplied bit function.
7514 bm::word_t* dst = blk;
7515
7516 bm::word_t* ret;
7517 if (dst == 0 && arg_blk == 0)
7518 return;
7519
7520 switch (opcode)
7521 {
7522 case BM_AND:
7523 ret = bm::bit_operation_and(dst, arg_blk);
7524 goto copy_block;
7525 case BM_XOR:
7526 ret = bm::bit_operation_xor(dst, arg_blk);
7527 if (ret && (ret == arg_blk) && IS_FULL_BLOCK(dst))
7528 {
7529 ret = blockman_.get_allocator().alloc_bit_block();
7530#ifdef BMVECTOPT
7532 arg_blk,
7533 arg_blk + bm::set_block_size,
7534 ~0u);
7535#else
7536 bm::wordop_t* dst_ptr = (wordop_t*)ret;
7537 const bm::wordop_t* wrd_ptr = (wordop_t*) arg_blk;
7538 const bm::wordop_t* wrd_end =
7539 (wordop_t*) (arg_blk + bm::set_block_size);
7540
7541 do
7542 {
7543 dst_ptr[0] = bm::all_bits_mask ^ wrd_ptr[0];
7544 dst_ptr[1] = bm::all_bits_mask ^ wrd_ptr[1];
7545 dst_ptr[2] = bm::all_bits_mask ^ wrd_ptr[2];
7546 dst_ptr[3] = bm::all_bits_mask ^ wrd_ptr[3];
7547
7548 dst_ptr+=4;
7549 wrd_ptr+=4;
7550
7551 } while (wrd_ptr < wrd_end);
7552#endif
7553 break;
7554 }
7555 goto copy_block;
7556 case BM_OR:
7557 ret = bm::bit_operation_or(dst, arg_blk);
7558 copy_block:
7559 if (ret && (ret == arg_blk) && !IS_FULL_BLOCK(ret))
7560 {
7561 ret = blockman_.get_allocator().alloc_bit_block();
7562 bm::bit_block_copy(ret, arg_blk);
7563 }
7564 break;
7565
7566 case BM_SUB:
7567 ret = bit_operation_sub(dst, arg_blk);
7568 if (ret && ret == arg_blk)
7569 {
7570 ret = blockman_.get_allocator().alloc_bit_block();
7571 bm::bit_andnot_arr_ffmask(ret, arg_blk);
7572 }
7573 break;
7574 default:
7575 BM_ASSERT(0);
7576 ret = 0;
7577 }
7578
7579 if (ret != dst) // block mutation
7580 {
7581 blockman_.set_block(nb, ret);
7582 if (IS_VALID_ADDR(dst))
7583 {
7584 blockman_.get_allocator().free_bit_block(dst);
7585 }
7586 }
7587}
7588
7589//---------------------------------------------------------------------
7590
7591template<class Alloc>
7593 size_type right)
7594{
7595 block_idx_type nblock_left = left >> bm::set_block_shift;
7596 block_idx_type nblock_right = right >> bm::set_block_shift;
7597
7598 unsigned nbit_right = unsigned(right & bm::set_block_mask);
7599
7600 unsigned r =
7601 (nblock_left == nblock_right) ? nbit_right :(bm::bits_in_block-1);
7602
7603 bm::gap_word_t tmp_gap_blk[5];
7604 tmp_gap_blk[0] = 0; // just to silence GCC warning on uninit var
7605
7606 // Set bits in the starting block
7607 //
7608 block_idx_type nb;
7609 unsigned i, j;
7610 bm::word_t* block;
7611 unsigned nbit_left = unsigned(left & bm::set_block_mask);
7612 if ((nbit_left == 0) && (r == bm::bits_in_block - 1)) // full block
7613 {
7614 nb = nblock_left;
7615 }
7616 else
7617 {
7618 gap_init_range_block<gap_word_t>(tmp_gap_blk,
7619 (gap_word_t)nbit_left,
7620 (gap_word_t)r,
7621 (gap_word_t)1);
7622 bm::get_block_coord(nblock_left, i, j);
7623 block = blockman_.get_block_ptr(i, j);
7624 combine_operation_with_block(nblock_left,
7625 BM_IS_GAP(block),
7626 block,
7627 (bm::word_t*) tmp_gap_blk,
7628 1, BM_OR);
7629
7630 if (nblock_left == nblock_right) // in one block
7631 return;
7632 nb = nblock_left+1;
7633 }
7634
7635 // Set all full blocks between left and right
7636 //
7637 block_idx_type nb_to = nblock_right + (nbit_right ==(bm::bits_in_block-1));
7638 BM_ASSERT(nb_to >= nblock_right);
7639 if (nb < nb_to)
7640 {
7641 BM_ASSERT(nb_to);
7642 blockman_.set_all_set(nb, nb_to-1);
7643 }
7644
7645 if (nb_to > nblock_right)
7646 return;
7647
7648 bm::get_block_coord(nblock_right, i, j);
7649 block = blockman_.get_block_ptr(i, j);
7650
7651 gap_init_range_block<gap_word_t>(tmp_gap_blk,
7652 (gap_word_t)0,
7653 (gap_word_t)nbit_right,
7654 (gap_word_t)1);
7655
7656 combine_operation_with_block(nblock_right,
7657 BM_IS_GAP(block),
7658 block,
7659 (bm::word_t*) tmp_gap_blk,
7660 1, BM_OR);
7661}
7662
7663//---------------------------------------------------------------------
7664
7665template<class Alloc>
7667 size_type right)
7668{
7669 block_idx_type nb;
7670 unsigned i, j;
7671
7672 // calculate logical number of start and destination blocks
7673 block_idx_type nblock_left = left >> bm::set_block_shift;
7674 block_idx_type nblock_right = right >> bm::set_block_shift;
7675
7676 unsigned nbit_right = unsigned(right & bm::set_block_mask);
7677 unsigned r =
7678 (nblock_left == nblock_right) ? nbit_right : (bm::bits_in_block - 1);
7679
7680 bm::gap_word_t tmp_gap_blk[5];
7681 tmp_gap_blk[0] = 0; // just to silence GCC warning on uninit var
7682
7683 // Set bits in the starting block
7684 bm::word_t* block;
7685
7686 unsigned nbit_left = unsigned(left & bm::set_block_mask);
7687 if ((nbit_left == 0) && (r == bm::bits_in_block - 1)) // full block
7688 {
7689 nb = nblock_left;
7690 }
7691 else
7692 {
7693 bm::gap_init_range_block<gap_word_t>(tmp_gap_blk,
7694 (gap_word_t)nbit_left,
7695 (gap_word_t)r,
7696 (gap_word_t)0);
7697 bm::get_block_coord(nblock_left, i, j);
7698 block = blockman_.get_block_ptr(i, j);
7699 combine_operation_with_block(nblock_left,
7700 BM_IS_GAP(block),
7701 block,
7702 (bm::word_t*) tmp_gap_blk,
7703 1,
7704 BM_AND);
7705
7706 if (nblock_left == nblock_right) // in one block
7707 return;
7708 nb = nblock_left + 1;
7709 }
7710
7711 // Clear all full blocks between left and right
7712
7713 block_idx_type nb_to = nblock_right + (nbit_right == (bm::bits_in_block - 1));
7714 BM_ASSERT(nb_to >= nblock_right);
7715 if (nb < nb_to)
7716 {
7717 BM_ASSERT(nb_to);
7718 blockman_.set_all_zero(nb, nb_to - 1u);
7719 }
7720
7721 if (nb_to > nblock_right)
7722 return;
7723
7724 bm::get_block_coord(nblock_right, i, j);
7725 block = blockman_.get_block_ptr(i, j);
7726 gap_init_range_block<gap_word_t>(tmp_gap_blk,
7727 (gap_word_t)0,
7728 (gap_word_t)nbit_right,
7729 (gap_word_t)0);
7730
7731 combine_operation_with_block(nblock_right,
7732 BM_IS_GAP(block),
7733 block,
7734 (bm::word_t*) tmp_gap_blk,
7735 1,
7736 BM_AND);
7737}
7738
7739
7740//---------------------------------------------------------------------
7741
7742template<class Alloc>
7744 size_type left,
7745 size_type right)
7746{
7747 if (!bvect.blockman_.is_init())
7748 {
7749 clear();
7750 return;
7751 }
7752
7753 if (blockman_.is_init())
7754 {
7755 blockman_.deinit_tree();
7756 }
7757 if (left > right)
7758 bm::xor_swap(left, right);
7759
7760 copy_range_no_check(bvect, left, right);
7761}
7762
7763//---------------------------------------------------------------------
7764
7765template<class Alloc>
7767{
7768 BM_ASSERT(left <= right);
7769 BM_ASSERT_THROW(right < bm::id_max, BM_ERR_RANGE);
7770
7771 if (left)
7772 {
7773 clear_range_no_check(0, left - 1); // TODO: optimize clear from
7774 }
7775 if (right < bm::id_max - 1)
7776 {
7777 size_type last;
7778 bool found = find_reverse(last);
7779 if (found && (last > right))
7780 clear_range_no_check(right + 1, last);
7781 }
7782 BM_ASSERT(count() == count_range(left, right));
7783}
7784
7785//---------------------------------------------------------------------
7786
7787template<class Alloc>
7789 size_type left,
7790 size_type right)
7791{
7792 BM_ASSERT(left <= right);
7793 BM_ASSERT_THROW(right < bm::id_max, BM_ERR_RANGE);
7794
7795 // copy all block(s) belonging to our range
7796 block_idx_type nblock_left = (left >> bm::set_block_shift);
7797 block_idx_type nblock_right = (right >> bm::set_block_shift);
7798
7799 blockman_.copy(bvect.blockman_, nblock_left, nblock_right);
7800
7801 if (left)
7802 {
7803 size_type from =
7804 (left < bm::gap_max_bits) ? 0 : (left - bm::gap_max_bits);
7805 clear_range_no_check(from, left-1); // TODO: optimize clear from
7806 }
7807 if (right < bm::id_max-1)
7808 {
7809 size_type last;
7810 bool found = find_reverse(last);
7811 if (found && (last > right))
7812 clear_range_no_check(right+1, last);
7813 }
7814 //keep_range_no_check(left, right); // clear the flanks
7815}
7816
7817//---------------------------------------------------------------------
7818
7819template<class Alloc>
7821{
7822 if (is_ro())
7823 return; // nothing to do read-only vector already
7825 swap(bv_ro);
7826}
7827
7828//---------------------------------------------------------------------
7829
7830template<class Alloc>
7832{
7833#ifndef BM_NO_STL
7834 throw std::bad_alloc();
7835#else
7836 BM_THROW(BM_ERR_BADALLOC);
7837#endif
7838}
7839
7840//---------------------------------------------------------------------
7841//
7842//---------------------------------------------------------------------
7843
7844template<class Alloc>
7846{
7847 BM_ASSERT(this->valid());
7848
7849 block_descr_type* bdescr = &(this->bdescr_);
7850 if (this->block_type_) // GAP
7851 {
7852 BM_ASSERT(this->block_type_ == 1);
7853 ++this->position_;
7854 if (--(bdescr->gap_.gap_len))
7855 return true;
7856 // next gap is "OFF" by definition.
7857 if (*(bdescr->gap_.ptr) != bm::gap_max_bits - 1)
7858 {
7859 gap_word_t prev = *(bdescr->gap_.ptr);
7860 unsigned val = *(++(bdescr->gap_.ptr));
7861 this->position_ += val - prev;
7862 // next gap is now "ON"
7863 if (*(bdescr->gap_.ptr) != bm::gap_max_bits - 1)
7864 {
7865 prev = *(bdescr->gap_.ptr);
7866 val = *(++(bdescr->gap_.ptr));
7867 bdescr->gap_.gap_len = (gap_word_t)(val - prev);
7868 return true; // next "ON" found;
7869 }
7870 }
7871 }
7872 else // BIT
7873 {
7874 unsigned short idx = ++(bdescr->bit_.idx);
7875 if (idx < bdescr->bit_.cnt)
7876 {
7877 this->position_ = bdescr->bit_.pos + bdescr->bit_.bits[idx];
7878 return true;
7879 }
7880 this->position_ +=
7881 (bm::set_bitscan_wave_size * 32) - bdescr->bit_.bits[--idx];
7883 if (decode_bit_group(bdescr))
7884 return true;
7885 }
7886
7887 if (search_in_blocks())
7888 return true;
7889
7890 this->invalidate();
7891 return false;
7892}
7893
7894//---------------------------------------------------------------------
7895
7896
7897template<class Alloc>
7899{
7900 if (!this->valid())
7901 return false;
7902 if (!rank)
7903 return this->valid(); // nothing to do
7904
7905 for (; rank; --rank)
7906 {
7907 block_descr_type* bdescr = &(this->bdescr_);
7908 switch (this->block_type_)
7909 {
7910 case 0: // BitBlock
7911 for (; rank; --rank)
7912 {
7913 unsigned short idx = ++(bdescr->bit_.idx);
7914 if (idx < bdescr->bit_.cnt)
7915 {
7916 this->position_ = bdescr->bit_.pos + bdescr->bit_.bits[idx];
7917 continue;
7918 }
7919 this->position_ +=
7920 (bm::set_bitscan_wave_size * 32) - bdescr->bit_.bits[--idx];
7922
7923 if (!decode_bit_group(bdescr, rank))
7924 break;
7925 } // for rank
7926 break;
7927 case 1: // DGAP Block
7928 for (; rank; --rank) // TODO: better skip logic
7929 {
7930 ++this->position_;
7931 if (--(bdescr->gap_.gap_len))
7932 continue;
7933
7934 // next gap is "OFF" by definition.
7935 if (*(bdescr->gap_.ptr) == bm::gap_max_bits - 1)
7936 break;
7937 gap_word_t prev = *(bdescr->gap_.ptr);
7938 unsigned int val = *(++(bdescr->gap_.ptr));
7939
7940 this->position_ += val - prev;
7941 // next gap is now "ON"
7942 if (*(bdescr->gap_.ptr) == bm::gap_max_bits - 1)
7943 break;
7944 prev = *(bdescr->gap_.ptr);
7945 val = *(++(bdescr->gap_.ptr));
7946 bdescr->gap_.gap_len = (gap_word_t)(val - prev);
7947 } // for rank
7948 break;
7949 default:
7950 BM_ASSERT(0);
7951 } // switch
7952
7953 if (!rank)
7954 return true;
7955
7956 if (!search_in_blocks())
7957 {
7958 this->invalidate();
7959 return false;
7960 }
7961 } // for rank
7962
7963 return this->valid();
7964}
7965
7966
7967//---------------------------------------------------------------------
7968
7969
7970template<class Alloc>
7972{
7973 if (pos == 0)
7974 {
7975 go_first();
7976 return this->valid();
7977 }
7978
7979 size_type new_pos = this->bv_->check_or_next(pos); // find the true pos
7980 if (!new_pos) // no bits available
7981 {
7982 this->invalidate();
7983 return false;
7984 }
7985 BM_ASSERT(new_pos >= pos);
7986 pos = new_pos;
7987
7988
7989 this->position_ = pos;
7990 size_type nb = this->block_idx_ = (pos >> bm::set_block_shift);
7992 this->bv_->get_blocks_manager();
7993 unsigned i0, j0;
7994 bm::get_block_coord(nb, i0, j0);
7995 this->block_ = bman.get_block(i0, j0);
7996
7997 BM_ASSERT(this->block_);
7998
7999 this->block_type_ = (bool)BM_IS_GAP(this->block_);
8000
8001 block_descr_type* bdescr = &(this->bdescr_);
8002 unsigned nbit = unsigned(pos & bm::set_block_mask);
8003
8004 if (this->block_type_) // gap
8005 {
8006 this->position_ = nb * bm::set_block_size * 32;
8007 search_in_gapblock();
8008
8009 if (this->position_ == pos)
8010 return this->valid();
8011 this->position_ = pos;
8012
8013 gap_word_t* gptr = BMGAP_PTR(this->block_);
8014 unsigned is_set;
8015 unsigned gpos = bm::gap_bfind(gptr, nbit, &is_set);
8016 BM_ASSERT(is_set);
8017
8018 bdescr->gap_.ptr = gptr + gpos;
8019 if (gpos == 1)
8020 {
8021 bdescr->gap_.gap_len = bm::gap_word_t(gptr[gpos] - (nbit - 1));
8022 }
8023 else
8024 {
8025 bm::gap_word_t interval = bm::gap_word_t(gptr[gpos] - gptr[gpos - 1]);
8026 bm::gap_word_t interval2 = bm::gap_word_t(nbit - gptr[gpos - 1]);
8027 bdescr->gap_.gap_len = bm::gap_word_t(interval - interval2 + 1);
8028 }
8029 }
8030 else // bit
8031 {
8032 if (nbit == 0)
8033 {
8034 search_in_bitblock();
8035 return this->valid();
8036 }
8037
8038 unsigned nword = unsigned(nbit >> bm::set_word_shift);
8039
8040 // check if we need to step back to match the wave
8041 unsigned parity = nword % bm::set_bitscan_wave_size;
8042 bdescr->bit_.ptr = this->block_ + (nword - parity);
8043 bdescr->bit_.cnt = bm::bitscan_wave(bdescr->bit_.ptr, bdescr->bit_.bits);
8044 BM_ASSERT(bdescr->bit_.cnt);
8045 bdescr->bit_.pos = (nb * bm::set_block_size * 32) + ((nword - parity) * 32);
8046 bdescr->bit_.idx = 0;
8047 nbit &= bm::set_word_mask;
8048 nbit += 32 * parity;
8049 for (unsigned i = 0; i < bdescr->bit_.cnt; ++i)
8050 {
8051 if (bdescr->bit_.bits[i] == nbit)
8052 return this->valid();
8053 bdescr->bit_.idx++;
8054 } // for
8055 BM_ASSERT(0);
8056 }
8057 return this->valid();
8058}
8059
8060//---------------------------------------------------------------------
8061
8062template<class Alloc>
8064{
8065 BM_ASSERT(this->bv_);
8066
8067 blocks_manager_type* bman = &(this->bv_->blockman_);
8068 if (!bman->is_init())
8069 {
8070 this->invalidate();
8071 return;
8072 }
8073
8074 bm::word_t*** blk_root = bman->top_blocks_root();
8075 this->block_idx_ = this->position_= 0;
8076 unsigned i, j;
8077
8078 for (i = 0; i < bman->top_block_size(); ++i)
8079 {
8080 bm::word_t** blk_blk = blk_root[i];
8081 if (blk_blk == 0) // not allocated
8082 {
8085 continue;
8086 }
8087
8088 if ((bm::word_t*)blk_blk == FULL_BLOCK_FAKE_ADDR)
8089 blk_blk = FULL_SUB_BLOCK_REAL_ADDR;
8090
8091 for (j = 0; j < bm::set_sub_array_size; ++j,++(this->block_idx_))
8092 {
8093 this->block_ = blk_blk[j];
8094 if (this->block_ == 0)
8095 {
8096 this->position_ += bits_in_block;
8097 continue;
8098 }
8099 if (BM_IS_GAP(this->block_))
8100 {
8101 this->block_type_ = 1;
8102 if (search_in_gapblock())
8103 return;
8104 }
8105 else
8106 {
8107 if (this->block_ == FULL_BLOCK_FAKE_ADDR)
8109 this->block_type_ = 0;
8110 if (search_in_bitblock())
8111 return;
8112 }
8113 } // for j
8114 } // for i
8115
8116 this->invalidate();
8117}
8118
8119//---------------------------------------------------------------------
8120
8121template<class Alloc>
8122bool
8124{
8125 bdescr->bit_.cnt = bm::bitscan_wave(bdescr->bit_.ptr, bdescr->bit_.bits);
8126 if (bdescr->bit_.cnt) // found
8127 {
8128 bdescr->bit_.idx = 0;
8129 return true;
8130 }
8131 return false;
8132}
8133
8134//---------------------------------------------------------------------
8135
8136template<class Alloc>
8137bool
8138bvector<Alloc>::enumerator::decode_bit_group(block_descr_type* bdescr) BMNOEXCEPT
8139{
8140 const word_t* block_end = this->block_ + bm::set_block_size;
8141 for (; bdescr->bit_.ptr < block_end;)
8142 {
8143 if (decode_wave(bdescr))
8144 {
8145 bdescr->bit_.pos = this->position_;
8146 this->position_ += bdescr->bit_.bits[0];
8147 return true;
8148 }
8149 this->position_ += bm::set_bitscan_wave_size * 32; // wave size
8150 bdescr->bit_.ptr += bm::set_bitscan_wave_size;
8151 } // for
8152 return false;
8153}
8154
8155//---------------------------------------------------------------------
8156
8157template<class Alloc>
8158bool
8159bvector<Alloc>::enumerator::decode_bit_group(block_descr_type* bdescr,
8161{
8162 const word_t* BMRESTRICT block_end = this->block_ + bm::set_block_size;
8163 for (; bdescr->bit_.ptr < block_end;)
8164 {
8165 unsigned cnt;
8166 #if defined(BMAVX512OPT) || defined(BMAVX2OPT) || defined(BM64OPT) || defined(BM64_SSE4)
8167 {
8168 const bm::id64_t* w64_p = (bm::id64_t*)bdescr->bit_.ptr;
8170 cnt = bm::word_bitcount64(w64_p[0]);
8171 cnt += bm::word_bitcount64(w64_p[1]);
8172 }
8173 #else
8174 const bm::word_t* BMRESTRICT w = bdescr->bit_.ptr;
8175 unsigned c1= bm::word_bitcount(w[0]);
8176 unsigned c2 = bm::word_bitcount(w[1]);
8177 cnt = c1 + c2;
8178 c1= bm::word_bitcount(w[2]);
8179 c2 = bm::word_bitcount(w[3]);
8180 cnt += c1 + c2;
8181 #endif
8182
8183 if (rank > cnt)
8184 {
8185 rank -= cnt;
8186 }
8187 else
8188 {
8189 if (decode_wave(bdescr))
8190 {
8191 bdescr->bit_.pos = this->position_;
8192 this->position_ += bdescr->bit_.bits[0];
8193 return true;
8194 }
8195 }
8196 this->position_ += bm::set_bitscan_wave_size * 32; // wave size
8197 bdescr->bit_.ptr += bm::set_bitscan_wave_size;
8198 } // for
8199 return false;
8200}
8201
8202
8203//---------------------------------------------------------------------
8204
8205template<class Alloc>
8206bool bvector<Alloc>::enumerator::search_in_bitblock() BMNOEXCEPT
8207{
8208 BM_ASSERT(this->block_type_ == 0);
8209
8210 block_descr_type* bdescr = &(this->bdescr_);
8211 bdescr->bit_.ptr = this->block_;
8212 return decode_bit_group(bdescr);
8213}
8214
8215//---------------------------------------------------------------------
8216
8217template<class Alloc>
8218bool bvector<Alloc>::enumerator::search_in_gapblock() BMNOEXCEPT
8219{
8220 BM_ASSERT(this->block_type_ == 1);
8221
8222 block_descr_type* bdescr = &(this->bdescr_);
8223 bdescr->gap_.ptr = BMGAP_PTR(this->block_);
8224 unsigned bitval = *(bdescr->gap_.ptr) & 1;
8225
8226 ++(bdescr->gap_.ptr);
8227
8228 for (;true;)
8229 {
8230 unsigned val = *(bdescr->gap_.ptr);
8231 if (bitval)
8232 {
8233 gap_word_t* first = BMGAP_PTR(this->block_) + 1;
8234 if (bdescr->gap_.ptr == first)
8235 {
8236 bdescr->gap_.gap_len = (gap_word_t)(val + 1);
8237 }
8238 else
8239 {
8240 bdescr->gap_.gap_len =
8241 (gap_word_t)(val - *(bdescr->gap_.ptr-1));
8242 }
8243 return true;
8244 }
8245 this->position_ += val + 1;
8246 if (val == bm::gap_max_bits - 1)
8247 break;
8248 bitval ^= 1;
8249 ++(bdescr->gap_.ptr);
8250 }
8251 return false;
8252}
8253
8254//---------------------------------------------------------------------
8255
8256template<class Alloc>
8257bool bvector<Alloc>::enumerator::search_in_blocks() BMNOEXCEPT
8258{
8259 ++(this->block_idx_);
8260 const blocks_manager_type& bman = this->bv_->blockman_;
8261 block_idx_type i = this->block_idx_ >> bm::set_array_shift;
8262 block_idx_type top_block_size = bman.top_block_size();
8263 bm::word_t*** blk_root = bman.top_blocks_root();
8264 for (; i < top_block_size; ++i)
8265 {
8266 bm::word_t** blk_blk = blk_root[i];
8267 if (blk_blk == 0)
8268 {
8269 // fast scan fwd in top level
8271 size_type pos = this->position_ + bm::bits_in_array;
8272 for (++i; i < top_block_size; ++i)
8273 {
8274 if (blk_root[i])
8275 break;
8277 pos += bm::bits_in_array;
8278 } // for i
8279 this->block_idx_ = bn;
8280 this->position_ = pos;
8281 if ((i < top_block_size) && blk_root[i])
8282 --i;
8283 continue;
8284 }
8285 if ((bm::word_t*)blk_blk == FULL_BLOCK_FAKE_ADDR)
8286 blk_blk = FULL_SUB_BLOCK_REAL_ADDR;
8287
8289
8290 for(; j < bm::set_sub_array_size; ++j, ++(this->block_idx_))
8291 {
8292 this->block_ = blk_blk[j];
8293 if (this->block_ == 0)
8294 {
8296 continue;
8297 }
8298 this->block_type_ = BM_IS_GAP(this->block_);
8299 if (this->block_type_)
8300 {
8301 if (search_in_gapblock())
8302 return true;
8303 }
8304 else
8305 {
8306 if (this->block_ == FULL_BLOCK_FAKE_ADDR)
8308 if (search_in_bitblock())
8309 return true;
8310 }
8311 } // for j
8312 } // for i
8313 return false;
8314}
8315
8316//---------------------------------------------------------------------
8317
8318
8319} // namespace
8320
8321
8322#ifdef _MSC_VER
8323#pragma warning( pop )
8324#endif
8325
8326
8327#endif
#define BM_BORDER_TEST(blk, idx)
Definition: bm.h:2614
#define BM_SUB_OP(x)
Definition: bm.h:6442
#define BM_XOR_OP(x)
Definition: bm.h:6254
#define BM_AND_OP(x)
Definition: bm.h:6347
#define BM_OR_OP(x)
Definition: bm.h:6181
#define BM_DECLARE_TEMP_BLOCK(x)
Definition: bm.h:47
Default SIMD friendly allocator.
#define VECT_XOR_ARR_2_MASK(dst, src, src_end, mask)
Definition: bmavx2.h:3200
Constants, lookup tables and typedefs.
Definitions(internal)
#define IS_FULL_BLOCK(addr)
Definition: bmdef.h:162
#define IS_VALID_ADDR(addr)
Definition: bmdef.h:161
#define BMRESTRICT
Definition: bmdef.h:203
#define BMNOEXCEPT
Definition: bmdef.h:82
#define BMGAP_PTR(ptr)
Definition: bmdef.h:189
#define BM_IS_GAP(ptr)
Definition: bmdef.h:191
#define BMSET_PTRGAP(ptr)
Definition: bmdef.h:190
#define BLOCK_ADDR_SAN(addr)
Definition: bmdef.h:160
#define BM_ASSERT
Definition: bmdef.h:139
#define BM_ASSERT_THROW(x, xerrcode)
Definition: bmdef.h:338
#define FULL_BLOCK_FAKE_ADDR
Definition: bmdef.h:158
#define FULL_SUB_BLOCK_REAL_ADDR
Definition: bmdef.h:159
#define FULL_BLOCK_REAL_ADDR
Definition: bmdef.h:157
Bit manipulation primitives (internal)
SIMD target version definitions.
Algorithms for fast aggregation of a group of bit-vectors.
Definition: bmaggregator.h:122
Output iterator iterator designed to set "ON" bits based on input sequence of integers.
Definition: bm.h:465
bulk_insert_iterator(const insert_iterator &iit)
Definition: bm.h:506
size_type * buf_
bulk insert buffer
Definition: bm.h:592
bulk_insert_iterator & operator++()
Definition: bm.h:561
bm::sort_order sorted_
sort order hint
Definition: bm.h:594
bulk_insert_iterator(const bulk_insert_iterator &iit)
Definition: bm.h:497
bulk_insert_iterator(bulk_insert_iterator &&iit) BMNOEXCEPT
Definition: bm.h:514
static size_type buf_size_max() BMNOEXCEPT
Definition: bm.h:581
bulk_insert_iterator & operator=(size_type n)
Definition: bm.h:544
bvector_type::size_type size_type
Definition: bm.h:471
bulk_insert_iterator & operator=(const bulk_insert_iterator &ii)
Definition: bm.h:522
bulk_insert_iterator & operator*()
Definition: bm.h:559
size_type buf_size_
current buffer size
Definition: bm.h:593
std::output_iterator_tag iterator_category
Definition: bm.h:468
bulk_insert_iterator & operator=(bulk_insert_iterator &&ii) BMNOEXCEPT
Definition: bm.h:533
bvector_type * bvect_
target bvector
Definition: bm.h:591
bvector_type * get_bvector() const BMNOEXCEPT
Definition: bm.h:577
bulk_insert_iterator & operator++(int)
Definition: bm.h:563
bulk_insert_iterator(bvector< Alloc > &bvect, bm::sort_order so=BM_UNKNOWN) BMNOEXCEPT
Definition: bm.h:487
bvector_type::size_type value_type
Definition: bm.h:472
bulk_insert_iterator() BMNOEXCEPT
Definition: bm.h:477
bm::bvector< Alloc > bvector_type
Definition: bm.h:470
Constant iterator designed to enumerate "ON" bits counted_enumerator keeps bitcount,...
Definition: bm.h:734
counted_enumerator & operator++() BMNOEXCEPT
Definition: bm.h:755
counted_enumerator(const enumerator &en) BMNOEXCEPT
Definition: bm.h:741
size_type count() const BMNOEXCEPT
Number of bits ON starting from the .
Definition: bm.h:775
counted_enumerator() BMNOEXCEPT
Definition: bm.h:739
counted_enumerator operator++(int)
Definition: bm.h:762
std::input_iterator_tag iterator_category
Definition: bm.h:737
counted_enumerator & operator=(const enumerator &en) BMNOEXCEPT
Definition: bm.h:746
Constant iterator designed to enumerate "ON" bits.
Definition: bm.h:603
unsigned & reference
Definition: bm.h:611
std::input_iterator_tag iterator_category
Definition: bm.h:606
enumerator(const bvector< Alloc > &bv, size_type pos=0) BMNOEXCEPT
Construct enumerator for bit vector.
Definition: bm.h:634
void go_first() BMNOEXCEPT
Position enumerator to the first available bit.
Definition: bm.h:8063
size_type value() const BMNOEXCEPT
Get current position (value)
Definition: bm.h:659
size_type operator*() const BMNOEXCEPT
Get current position (value)
Definition: bm.h:656
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
bool go_to(size_type pos) BMNOEXCEPT
go to a specific position in the bit-vector (or next)
Definition: bm.h:7971
enumerator & operator++() BMNOEXCEPT
Advance enumerator forward to the next available bit.
Definition: bm.h:662
enumerator(const bvector< Alloc > *bv) BMNOEXCEPT
Construct enumerator associated with a vector. Important: This construction creates unpositioned iter...
Definition: bm.h:622
enumerator() BMNOEXCEPT
Definition: bm.h:614
unsigned difference_type
Definition: bm.h:609
size_type value_type
Definition: bm.h:608
unsigned * pointer
Definition: bm.h:610
bool skip(size_type rank) BMNOEXCEPT
Skip specified number of bits from enumeration.
Definition: bm.h:7898
bool go_up() BMNOEXCEPT
Advance enumerator to the next available bit.
Definition: bm.h:7845
bool skip_to_rank(size_type rank) BMNOEXCEPT
Skip to specified relative rank.
Definition: bm.h:690
bool advance() BMNOEXCEPT
Definition: bm.h:680
enumerator(const bvector< Alloc > *bv, size_type pos) BMNOEXCEPT
Construct enumerator for bit vector.
Definition: bm.h:648
Output iterator iterator designed to set "ON" bits based on input sequence of integers (bit indeces).
Definition: bm.h:381
insert_iterator(const insert_iterator &iit)
Definition: bm.h:402
insert_iterator(bvector< Alloc > &bvect) BMNOEXCEPT
Definition: bm.h:395
bvector_type * get_bvector() const
Definition: bm.h:438
insert_iterator() BMNOEXCEPT
Definition: bm.h:393
insert_iterator & operator++(int)
Definition: bm.h:436
insert_iterator & operator=(const insert_iterator &ii)
Definition: bm.h:408
bvector_type * bvect_
Definition: bm.h:441
insert_iterator & operator++()
Definition: bm.h:434
insert_iterator & operator*()
Definition: bm.h:432
bm::bvector< Alloc > bvector_type
Definition: bm.h:387
insert_iterator & operator=(size_type n)
Definition: bm.h:414
std::output_iterator_tag iterator_category
Definition: bm.h:385
size_type value_type
Definition: bm.h:388
Base class for all iterators.
Definition: bm.h:240
size_type position_
Bit position (bit idx)
Definition: bm.h:350
iterator_base() BMNOEXCEPT
Definition: bm.h:243
bool valid() const BMNOEXCEPT
Checks if iterator is still valid.
Definition: bm.h:283
bool operator!=(const iterator_base &it) const BMNOEXCEPT
Definition: bm.h:253
unsigned block_type_
Type of block. 0-Bit, 1-GAP.
Definition: bm.h:352
bool compare_state(const iterator_base &ib) const BMNOEXCEPT
Compare FSMs for testing purposes.
Definition: bm.h:295
union bm::bvector::iterator_base::block_descr bdescr_
void invalidate() BMNOEXCEPT
Turns iterator into an invalid state.
Definition: bm.h:289
bool operator<(const iterator_base &it) const BMNOEXCEPT
Definition: bm.h:258
bm::bvector< Alloc > * bv_
Pointer on parent bitvector.
Definition: bm.h:349
bool operator==(const iterator_base &it) const BMNOEXCEPT
Definition: bm.h:248
const bm::word_t * block_
Block pointer.(NULL-invalid)
Definition: bm.h:351
bool operator>=(const iterator_base &it) const BMNOEXCEPT
Definition: bm.h:273
bool operator>(const iterator_base &it) const BMNOEXCEPT
Definition: bm.h:268
bool operator<=(const iterator_base &it) const BMNOEXCEPT
Definition: bm.h:263
block_idx_type block_idx_
Block index.
Definition: bm.h:353
Class reference implements an object for bit assignment.
Definition: bm.h:149
reference & flip()
Definition: bm.h:222
bool operator==(const reference &ref) const BMNOEXCEPT
Definition: bm.h:180
bool operator~() const BMNOEXCEPT
Definition: bm.h:216
reference(const reference &ref) BMNOEXCEPT
Definition: bm.h:156
bool operator!() const BMNOEXCEPT
Definition: bm.h:210
const reference & operator|=(bool value) const
Definition: bm.h:193
const reference & operator=(const reference &ref) const
Definition: bm.h:168
const reference & operator=(bool value) const BMNOEXCEPT
Definition: bm.h:174
const reference & operator&=(bool value) const
Definition: bm.h:186
const reference & operator^=(bool value) const
Definition: bm.h:203
reference(bvector< Alloc > &bv, size_type position) BMNOEXCEPT
Definition: bm.h:151
Bitvector Bit-vector container with runtime compression of bits.
Definition: bm.h:115
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:5668
void import_block(const size_type *ids, block_idx_type nblock, size_type start, size_type stop)
Definition: bm.h:4321
bool const_reference
Definition: bm.h:233
optmode
Optimization mode Every next level means additional checks (better compression vs time)
Definition: bm.h:133
@ opt_compress
compress blocks when possible (GAP/prefix sum)
Definition: bm.h:137
@ opt_free_01
Free unused 0 and 1 blocks.
Definition: bm.h:136
@ opt_free_0
Free unused 0 blocks.
Definition: bm.h:135
@ opt_none
no optimization
Definition: bm.h:134
bool find(size_type &pos) const BMNOEXCEPT
Finds index of first 1 bit.
Definition: bm.h:4855
bvector(const bvector< Alloc > &bvect, bm::finalization is_final)
Copy-constructor for mutable/immutable initialization.
Definition: bm.h:892
void operator&=(const bvector< Alloc > &bv)
Definition: bm.h:1006
blocks_manager_type & get_blocks_manager() BMNOEXCEPT
get access to memory manager (internal) Use only if you are BitMagic library
Definition: bm.h:2044
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:6874
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:3691
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
bool test(size_type n) const BMNOEXCEPT
returns true if bit n is set and false is bit n is 0.
Definition: bm.h:1480
bvector(bvector< Alloc > &&bvect) BMNOEXCEPT
Move constructor.
Definition: bm.h:926
void merge(bm::bvector< Alloc > &bvect)
Merge/move content from another vector.
Definition: bm.h:5578
bool equal(const bvector< Alloc > &bvect) const BMNOEXCEPT
Equal comparison with an agr bit-vector.
Definition: bm.h:1995
void clear_range_no_check(size_type left, size_type right)
Clear range without validity/bounds checking.
Definition: bm.h:7666
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:3515
bool set_bit_and(size_type n, bool val=true)
Sets bit n using bit AND with the provided value.
Definition: bm.h:4178
allocator_type::allocator_pool_type allocator_pool_type
Definition: bm.h:118
size_type size() const BMNOEXCEPT
Returns bvector's capacity (number of bits it can store)
Definition: bm.h:1278
size_type count() const BMNOEXCEPT
population count (count of ON bits)
Definition: bm.h:2366
void combine_operation_xor(const bm::bvector< Alloc > &bvect)
perform a set-algebra operation XOR
Definition: bm.h:6261
bool set_bit_conditional_impl(size_type n, bool val, bool condition)
Definition: bm.h:4546
bool clear_bit(size_type n)
Clears bit n.
Definition: bm.h:1225
bool operator[](size_type n) const BMNOEXCEPT
Definition: bm.h:1000
bool is_init() const BMNOEXCEPT
Return true if bvector is initialized at all.
Definition: bm.h:1961
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:5880
static void throw_bad_alloc()
Definition: bm.h:7831
size_type get_next(size_type prev) const BMNOEXCEPT
Finds the number of the next bit ON.
Definition: bm.h:1587
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:5205
bool combine_operation_block_or(unsigned i, unsigned j, const bm::word_t *arg_blk1, const bm::word_t *arg_blk2)
Definition: bm.h:6634
bvector & operator=(const bvector< Alloc > &bvect)
Copy assignment operator.
Definition: bm.h:916
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:2036
void sync_size()
Syncronize size if it got extended due to bulk import.
Definition: bm.h:2451
bool find_range(size_type &first, size_type &last) const BMNOEXCEPT
Finds dynamic range of bit-vector [first, last].
Definition: bm.h:4901
bvector< Alloc > operator~() const
Definition: bm.h:1018
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:5170
bool any_range(size_type left, size_type right) const BMNOEXCEPT
Returns true if any bits in the range are 1s (non-empty interval) Function uses closed interval [left...
Definition: bm.h:3387
void resize(size_type new_size)
Change size of the bvector.
Definition: bm.h:2428
size_type check_or_next(size_type prev) const BMNOEXCEPT
Definition: bm.h:5086
reference operator[](size_type n)
Definition: bm.h:990
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:6092
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:1026
bvector(const bvector< Alloc > &bvect)
Copy constructor.
Definition: bm.h:867
strategy get_new_blocks_strat() const BMNOEXCEPT
Returns blocks allocation strategy.
Definition: bm.h:1898
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:3600
void forget_count() BMNOEXCEPT
Definition: bm.h:1460
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:3106
void set_new_blocks_strat(strategy strat)
Sets new blocks allocation strategy.
Definition: bm.h:1890
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:1411
bvector(std::initializer_list< size_type > il)
Brace constructor.
Definition: bm.h:936
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:4023
bool any() const BMNOEXCEPT
Returns true if any bits in this bitset are set, and otherwise returns false.
Definition: bm.h:2416
bool set_bit(size_type n, bool val=true)
Sets bit n.
Definition: bm.h:4192
insert_iterator inserter()
Definition: bm.h:1265
blocks_manager< Alloc > blocks_manager_type
Definition: bm.h:119
friend class enumerator
Definition: bm.h:793
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:1540
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:2318
void operator-=(const bvector< Alloc > &bv)
Definition: bm.h:1009
bool is_all_one_range(size_type left, size_type right) const BMNOEXCEPT
Returns true if all bits in the range are 1s (saturated interval) Function uses closed interval [left...
Definition: bm.h:3303
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:5045
Alloc get_allocator() const
Definition: bm.h:1020
bool and_bit_no_check(size_type n, bool val)
AND specified bit without checking preconditions (size, etc)
Definition: bm.h:4598
bvector_size_type size_type
Definition: bm.h:121
bvector< Alloc > & flip(size_type n)
Flips bit n.
Definition: bm.h:1251
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:1194
bool combine_operation_block_and(unsigned i, unsigned j, const bm::word_t *arg_blk1, const bm::word_t *arg_blk2)
Definition: bm.h:6789
void combine_operation_and(const bm::bvector< Alloc > &bvect, optmode opt_mode)
perform a set-algebra operation AND
Definition: bm.h:6360
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:3827
enumerator first() const
Returns enumerator pointing on the first non-zero bit.
Definition: bm.h:1849
bool combine_operation_block_sub(unsigned i, unsigned j, const bm::word_t *arg_blk1, const bm::word_t *arg_blk2)
Definition: bm.h:6974
bool combine_operation_block_xor(unsigned i, unsigned j, const bm::word_t *arg_blk1, const bm::word_t *arg_blk2)
Definition: bm.h:6707
enumerator end() const
Returns enumerator pointing on the next bit after the last.
Definition: bm.h:1855
bvector< Alloc > & set()
Sets every bit in this bitset to 1.
Definition: bm.h:4142
bool shift_left()
Shift left by 1 bit, fill with zero return carry out.
Definition: bm.h:5194
void swap(bvector< Alloc > &bvect) BMNOEXCEPT
Exchanges content of bv and this bvector.
Definition: bm.h:3931
size_type count_range(size_type left, size_type right, const rs_index_type &rs_idx) const BMNOEXCEPT
Returns count of 1 bits in the given range [left..right] Uses rank-select index to accelerate the sea...
Definition: bm.h:3481
bm::bvector< Alloc > & bit_and(const bm::bvector< Alloc > &bv, optmode opt_mode=opt_none)
2 operand logical AND
Definition: bm.h:1780
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:1578
void freeze()
Turn current vector to read-only (immutable vector).
Definition: bm.h:7820
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:4921
bvector & operator=(bvector< Alloc > &&bvect) BMNOEXCEPT
Move assignment operator.
Definition: bm.h:951
void optimize_gap_size()
Optimize sizes of GAP blocks.
Definition: bm.h:3665
void init()
Explicit post-construction initialization. Must be caled to make sure safe use of *_no_check() method...
Definition: bm.h:2258
bool shift_right()
Shift right by 1 bit, fill with zero return carry out.
Definition: bm.h:5185
bvector< Alloc > & flip()
Flips all bits.
Definition: bm.h:1258
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:2333
void erase(size_type n)
Erase bit in the specified position All the vector content after erase position is shifted left.
Definition: bm.h:5408
size_type extract_next(size_type prev)
Finds the number of the next bit ON and sets it to 0.
Definition: bm.h:1597
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:7743
bool is_ro() const BMNOEXCEPT
Returns true if vector is read-only.
Definition: bm.h:1046
enumerator get_enumerator(size_type pos) const
Returns enumerator pointing on specified or the next available bit.
Definition: bm.h:1861
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:3162
void import(const size_type *ids, size_type ids_size, bm::sort_order sorted_idx)
Import integers (set bits).
Definition: bm.h:4210
void copy_range_no_check(const bvector< Alloc > &bvect, size_type left, size_type right)
Definition: bm.h:7788
void combine_operation_or(const bm::bvector< Alloc > &bvect)
perform a set-algebra operation OR
Definition: bm.h:6189
blocks_manager_type::block_idx_type block_idx_type
Definition: bm.h:120
void copy(const bvector< Alloc > &bvect, bm::finalization is_final)
Copy bvector from the argument bvector.
Definition: bm.h:2268
void operator^=(const bvector< Alloc > &bv)
Definition: bm.h:1007
void operator|=(const bvector< Alloc > &bv)
Definition: bm.h:1008
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:4114
void import_sorted(const size_type *ids, const size_type ids_size, bool opt_flag)
Import sorted integers (set bits).
Definition: bm.h:4255
void optimize_range(size_type left, size_type right, bm::word_t *temp_block, optmode opt_mode=opt_compress)
Definition: bm.h:3636
block_idx_type count_blocks(unsigned *arr) const BMNOEXCEPT
Computes bitcount values for all bvector blocks.
Definition: bm.h:2602
rs_index< allocator_type > rs_index_type
Definition: bm.h:816
size_type count_range_no_check(size_type left, size_type right) const BMNOEXCEPT
Definition: bm.h:3223
bvector(const bvector< Alloc > &bvect, size_type left, size_type right)
Copy constructor for range copy [left..right].
Definition: bm.h:877
void combine_operation_sub(const bm::bvector< Alloc > &bvect)
perform a set-algebra operation MINUS (AND NOT)
Definition: bm.h:6448
int compare(const bvector< Alloc > &bvect) const BMNOEXCEPT
Lexicographical comparison with a bitvector.
Definition: bm.h:3709
Alloc allocator_type
Definition: bm.h:117
size_type count_to(size_type n, const rs_index_type &rs_idx) const BMNOEXCEPT
Returns count of 1 bits (population) in [0..right] range.
Definition: bm.h:3053
rs_index< allocator_type > blocks_count
Definition: bm.h:815
bool none() const BMNOEXCEPT
Returns true if no bits are set, otherwise returns false.
Definition: bm.h:1534
bool set_bit_conditional(size_type n, bool val, bool condition)
Sets bit n only if current value equals the condition.
Definition: bm.h:4164
bool find_reverse(size_type &pos) const BMNOEXCEPT
Finds last index of 1 bit.
Definition: bm.h:4673
allocator_pool_type * get_allocator_pool() BMNOEXCEPT
Get curent allocator pool (if set)
Definition: bm.h:1031
void build_rs_index(rs_index_type *rs_idx, bvector< Alloc > *bv_blocks=0) const
compute running total of all blocks in bit vector (rank-select index)
Definition: bm.h:2466
void combine_operation_with_block(block_idx_type nb, const bm::word_t *arg_blk, bool arg_gap, bm::operation opcode)
Definition: bm.h:5651
bm::bvector< Alloc > & bit_xor(const bm::bvector< Alloc > &bv)
2 operand logical XOR
Definition: bm.h:1792
void clear_bit_no_check(size_type n)
Clears bit n without precondiion checks.
Definition: bm.h:4439
~bvector() BMNOEXCEPT
Definition: bm.h:906
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:4492
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
void combine_operation(const bm::bvector< Alloc > &bvect, bm::operation opcode)
perform a set-algebra operation by operation code
Definition: bm.h:6512
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:4070
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:5975
bm::bvector< Alloc > & bit_sub(const bm::bvector< Alloc > &bv)
2 operand logical SUB(AND NOT). Also known as MINUS.
Definition: bm.h:1803
bvector< Alloc > & reset() BMNOEXCEPT
Clears every bit in the bitvector.
Definition: bm.h:1245
bm::bvector< Alloc > & bit_or(const bm::bvector< Alloc > &bv)
2 operand logical OR
Definition: bm.h:1768
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:3567
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:4473
void calc_stat(struct bm::bvector< Alloc >::statistics *st) const BMNOEXCEPT
Calculates bitvector statistics.
Definition: bm.h:3943
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:5767
void set_range_no_check(size_type left, size_type right)
Set range without validity/bounds checking.
Definition: bm.h:7592
size_type recalc_count() BMNOEXCEPT
Definition: bm.h:1455
void move_from(bvector< Alloc > &bvect) BMNOEXCEPT
Move bvector content from another bvector.
Definition: bm.h:2305
bool inc(size_type n)
Increment the specified element.
Definition: bm.h:4510
void set_bit_no_check(size_type n)
Set bit without checking preconditions (size, etc)
Definition: bm.h:4405
Deserializer for bit-vector.
Definition: bmserial.h:570
Deserializer, performs logical operations between bit-vector and serialized bit-vector.
Definition: bmserial.h:930
Encoding utilities for serialization (internal)
BMFORCEINLINE bool avx2_test_all_zero_wave(const void *ptr)
check if wave of pointers is all NULL
Definition: bmavx2.h:1592
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:1603
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:1616
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:695
BMFORCEINLINE bool sse42_test_all_zero_wave(const void *ptr) BMNOEXCEPT
check if wave of pointers is all NULL
Definition: bmsse4.h:671
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:682
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:8389
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:7712
BMFORCEINLINE bm::id_t word_bitcount(bm::id_t w) BMNOEXCEPT
Definition: bmutil.h:573
void bit_block_copy(bm::word_t *BMRESTRICT dst, const bm::word_t *BMRESTRICT src) BMNOEXCEPT
Bitblock copy operation.
Definition: bmfunc.h:6743
bm::word_t * bit_operation_sub(bm::word_t *BMRESTRICT dst, const bm::word_t *BMRESTRICT src) BMNOEXCEPT
bitblock SUB operation.
Definition: bmfunc.h:8108
bm::word_t * bit_operation_xor(bm::word_t *BMRESTRICT dst, const bm::word_t *BMRESTRICT src) BMNOEXCEPT
bitblock XOR operation.
Definition: bmfunc.h:8237
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:8041
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:6824
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:5677
BMFORCEINLINE unsigned word_bitcount64(bm::id64_t x) BMNOEXCEPT
Definition: bmutil.h:596
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:7885
bm::id_t bit_block_calc_count_to(const bm::word_t *block, bm::word_t right) BMNOEXCEPT
Definition: bmfunc.h:5442
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:5800
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:5777
bm::id64_t calc_block_digest0(const bm::word_t *const block) BMNOEXCEPT
Compute digest for 64 non-zero areas.
Definition: bmfunc.h:1092
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:6983
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:9320
bool bit_find_first(const bm::word_t *BMRESTRICT block, unsigned *BMRESTRICT pos) BMNOEXCEPT
BIT block find the first set bit.
Definition: bmfunc.h:8474
void bit_invert(T *start) BMNOEXCEPT
Definition: bmfunc.h:6023
int bitcmp(const T *buf1, const T *buf2, unsigned len) BMNOEXCEPT
Lexicographical comparison of BIT buffers.
Definition: bmfunc.h:4666
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:7050
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:8166
void bit_block_set(bm::word_t *BMRESTRICT dst, bm::word_t value) BMNOEXCEPT
Bitblock memset operation.
Definition: bmfunc.h:4422
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:7675
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:1522
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:8440
bm::id64_t update_block_digest0(const bm::word_t *const block, bm::id64_t digest) BMNOEXCEPT
Compute digest for 64 non-zero areas based on existing digest (function revalidates zero areas)
Definition: bmfunc.h:1134
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:5356
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:8202
bm::word_t * bit_operation_and(bm::word_t *BMRESTRICT dst, const bm::word_t *BMRESTRICT src) BMNOEXCEPT
bitblock AND operation.
Definition: bmfunc.h:7418
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:5551
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:7945
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:7751
bool is_bits_one(const bm::wordop_t *start) BMNOEXCEPT
Returns "true" if all bits in the block are 1.
Definition: bmfunc.h:6047
sort_order
Sort order declaration.
Definition: bmconst.h:203
bm::alloc_pool_guard< allocator_pool_type, bvector< Alloc > > mem_pool_guard
Definition: bm.h:790
operation
Bit operations.
Definition: bmconst.h:190
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
finalization
copy strategy
Definition: bmconst.h:155
strategy
Block allocation strategies.
Definition: bmconst.h:145
@ BM_SORTED
input set is sorted (ascending order)
Definition: bmconst.h:205
@ BM_UNKNOWN
sort order unknown
Definition: bmconst.h:207
@ BM_OR
Definition: bmconst.h:192
@ BM_SUB
Definition: bmconst.h:193
@ BM_XOR
Definition: bmconst.h:194
@ BM_AND
Definition: bmconst.h:191
@ READWRITE
mutable (read-write object)
@ READONLY
immutable (read-only object)
@ BM_BIT
No GAP compression strategy. All new blocks are bit blocks.
Definition: bmconst.h:146
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:1784
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:2353
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:6632
unsigned gap_find_last(const T *BMRESTRICT buf, unsigned *BMRESTRICT last) BMNOEXCEPT
GAP block find the last set bit.
Definition: bmfunc.h:1639
void gap_and_to_bitset(unsigned *BMRESTRICT dest, const T *BMRESTRICT pcurr) BMNOEXCEPT
ANDs GAP block to bitblock.
Definition: bmfunc.h:4067
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:3173
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:6551
T gap_level(const T *BMRESTRICT buf) BMNOEXCEPT
Returs GAP blocks capacity level.
Definition: bmfunc.h:1621
unsigned gap_bit_count_to(const T *const buf, T right) BMNOEXCEPT
Counts 1 bits in GAP buffer in the closed [0, right] range.
Definition: bmfunc.h:2703
void gap_xor_to_bitset(unsigned *BMRESTRICT dest, const T *BMRESTRICT pcurr) BMNOEXCEPT
XOR GAP block to bitblock.
Definition: bmfunc.h:3988
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:3413
int gapcmp(const T *buf1, const T *buf2) BMNOEXCEPT
Lexicographical comparison of GAP buffers.
Definition: bmfunc.h:2855
void gap_convert_to_bitset(unsigned *BMRESTRICT dest, const T *BMRESTRICT buf, unsigned len=0) BMNOEXCEPT
GAP block to bitblock conversion.
Definition: bmfunc.h:4441
unsigned gap_find_first(const T *BMRESTRICT buf, unsigned *BMRESTRICT first) BMNOEXCEPT
GAP block find the first set bit.
Definition: bmfunc.h:1670
bool gap_insert(T *BMRESTRICT buf, unsigned pos, unsigned val, unsigned *BMRESTRICT new_len) BMNOEXCEPT
isnert bit into GAP compressed block
Definition: bmfunc.h:3466
void gap_invert(T *buf) BMNOEXCEPT
Inverts all bits in the GAP buffer.
Definition: bmfunc.h:4586
void gap_sub_to_bitset(unsigned *BMRESTRICT dest, const T *BMRESTRICT pcurr) BMNOEXCEPT
SUB (AND NOT) GAP block to bitblock.
Definition: bmfunc.h:3900
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:6484
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:3676
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:6678
BMFORCEINLINE bool gap_is_all_zero(const bm::gap_word_t *BMRESTRICT buf) BMNOEXCEPT
Checks if GAP block is all-zero.
Definition: bmfunc.h:1549
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:4466
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:3522
void gap_add_to_bitset(unsigned *BMRESTRICT dest, const T *BMRESTRICT pcurr, unsigned len) BMNOEXCEPT
Adds(OR) GAP block to bitblock.
Definition: bmfunc.h:4016
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:2401
bool improve_gap_levels(const T *length, const T *length_end, T *glevel_len) BMNOEXCEPT
Finds optimal gap blocks lengths.
Definition: bmfunc.h:8855
unsigned gap_capacity(const T *BMRESTRICT buf, const T *BMRESTRICT glevel_len) BMNOEXCEPT
Returs GAP block capacity.
Definition: bmfunc.h:1591
unsigned gap_limit(const T *BMRESTRICT buf, const T *BMRESTRICT glevel_len) BMNOEXCEPT
Returs GAP block capacity limit.
Definition: bmfunc.h:1607
BMFORCEINLINE bm::gap_word_t gap_length(const bm::gap_word_t *BMRESTRICT buf) BMNOEXCEPT
Returs GAP block length.
Definition: bmfunc.h:1575
Definition: bm.h:78
const unsigned set_array_mask
Definition: bmconst.h:97
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:6448
const id64_t all_bits_mask
Definition: bmconst.h:131
void for_each_nzblock(T ***root, unsigned size1, F &f)
Definition: bmfunc.h:1868
const unsigned id_max
Definition: bmconst.h:109
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:6073
unsigned int word_t
Definition: bmconst.h:39
const unsigned set_block_mask
Definition: bmconst.h:57
bool check_block_one(const bm::word_t *blk, bool deep_scan) BMNOEXCEPT
Checks if block has only 1 bits.
Definition: bmfunc.h:8805
unsigned gap_bfind(const T *BMRESTRICT buf, unsigned pos, unsigned *BMRESTRICT is_set) BMNOEXCEPT
Definition: bmfunc.h:1697
bvector< Alloc > operator-(const bvector< Alloc > &bv1, const bvector< Alloc > &bv2)
Definition: bm.h:2246
const unsigned set_sub_array_size
Definition: bmconst.h:95
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:172
const unsigned bits_in_array
Definition: bmconst.h:115
const unsigned set_total_blocks
Definition: bmconst.h:111
unsigned char get_nibble(const unsigned char *arr, unsigned idx) BMNOEXCEPT
get nibble from the array
Definition: bmfunc.h:9965
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:9226
const unsigned set_block_size_op
Definition: bmconst.h:132
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:8953
const unsigned rs3_half_span
Definition: bmconst.h:121
const unsigned gap_levels
Definition: bmconst.h:85
const unsigned set_word_shift
Definition: bmconst.h:72
BMFORCEINLINE void xor_swap(W &x, W &y) BMNOEXCEPT
XOR swap two variables.
Definition: bmutil.h:534
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:9440
const unsigned set_block_size
Definition: bmconst.h:55
unsigned long long int id64_t
Definition: bmconst.h:35
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:6427
const unsigned gap_equiv_len
Definition: bmconst.h:82
const unsigned rs3_border0_1
Definition: bmconst.h:122
unsigned int id_t
Definition: bmconst.h:38
bvector< Alloc > operator|(const bvector< Alloc > &bv1, const bvector< Alloc > &bv2)
Definition: bm.h:2224
const unsigned rs3_border1
Definition: bmconst.h:120
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:9529
bvector< Alloc > operator^(const bvector< Alloc > &bv1, const bvector< Alloc > &bv2)
Definition: bm.h:2235
unsigned idx_arr_block_lookup_u32(const unsigned *idx, unsigned size, unsigned nb, unsigned start) BMNOEXCEPT
block boundaries look ahead U32
Definition: bmfunc.h:9466
const unsigned short set_bitscan_wave_size
Size of bit decode wave in words.
Definition: bmfunc.h:9308
const unsigned set_array_shift
Definition: bmconst.h:96
unsigned short gap_word_t
Definition: bmconst.h:78
const unsigned rs3_border1_1
Definition: bmconst.h:123
void(* gap_operation_to_bitset_func_type)(unsigned *, const gap_word_t *)
Definition: bmfunc.h:9222
bm::id_t bvector_size_type
Definition: bm.h:103
const unsigned rs3_border0
Definition: bmconst.h:119
const unsigned gap_max_bits
Definition: bmconst.h:81
const unsigned set_top_array_size
Definition: bmconst.h:110
const unsigned set_block_shift
Definition: bmconst.h:56
void for_each_nzblock_range(T ***root, N top_size, N nb_from, N nb_to, F &f) BMNOEXCEPT
Definition: bmfunc.h:1811
const unsigned set_word_mask
Definition: bmconst.h:73
bool find_not_null_ptr(const bm::word_t *const *const *arr, N start, N size, N *pos) BMNOEXCEPT
Definition: bmfunc.h:1399
const unsigned bits_in_block
Definition: bmconst.h:114
id64_t wordop_t
Definition: bmconst.h:130
bool block_find_reverse(const bm::word_t *BMRESTRICT block, unsigned nbit_from, unsigned *BMRESTRICT found_nbit) BMNOEXCEPT
Reverse find 1.
Definition: bmfunc.h:6397
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:9499
bool for_each_nzblock_if(T ***root, BI size1, F &f) BMNOEXCEPT
Definition: bmfunc.h:2099
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:8682
Structure with statistical information about memory allocation footprint, serialization projection,...
Definition: bmfunc.h:56
gap_word_t gap_levels[bm::gap_levels]
GAP block lengths in the bvect.
Definition: bmfunc.h:64
size_t max_serialize_mem
estimated maximum memory for serialization
Definition: bmfunc.h:61
void reset() BMNOEXCEPT
Reset statisctics.
Definition: bmfunc.h:92
size_t memory_used
memory usage for all blocks and service tables
Definition: bmfunc.h:62
memory allocation policy
Definition: bm.h:805
allocation_policy(bm::strategy s=BM_BIT, const gap_word_t *glevels=bm::gap_len_table< true >::_len) BMNOEXCEPT
Definition: bm.h:809
bm::strategy strat
Definition: bm.h:806
const gap_word_t * glevel_len
Definition: bm.h:807
unsigned short idx
Current position in the bit list.
Definition: bm.h:334
unsigned char bits[set_bitscan_wave_size *32]
bit list
Definition: bm.h:333
size_type pos
Last bit position decode before.
Definition: bm.h:336
unsigned short cnt
Number of ON bits.
Definition: bm.h:335
const bm::word_t * ptr
Word pointer.
Definition: bm.h:332
Information about current DGAP block.
Definition: bm.h:343
const gap_word_t * ptr
Word pointer.
Definition: bm.h:344
gap_word_t gap_len
Current dgap length.
Definition: bm.h:345
Statistical information about bitset's memory allocation details.
Definition: bm.h:125
Default GAP lengths table.
Definition: bmconst.h:395
static gap_operation_to_bitset_func_type gap_op_to_bit(unsigned i)
Definition: bmfunc.h:9247
static gap_operation_func_type gap_operation(unsigned i)
Definition: bmfunc.h:9253
dgap_descr gap_
DGAP block related info.
Definition: bm.h:359
bitblock_descr bit_
BitBlock related info.
Definition: bm.h:358