BitMagic-C++
bm.h
Go to the documentation of this file.
1 #ifndef BM__H__INCLUDED__
2 #define BM__H__INCLUDED__
3 /*
4 Copyright(c) 2002-2019 Anatoliy Kuznetsov(anatoliy_kuznetsov at yahoo.com)
5 
6 Licensed under the Apache License, Version 2.0 (the "License");
7 you may not use this file except in compliance with the License.
8 You may obtain a copy of the License at
9 
10  http://www.apache.org/licenses/LICENSE-2.0
11 
12 Unless required by applicable law or agreed to in writing, software
13 distributed under the License is distributed on an "AS IS" BASIS,
14 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 See the License for the specific language governing permissions and
16 limitations under the License.
17 
18 For 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 
58 extern "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 
69  @ingroup bvector
70  */
71  typedef int (*bit_visitor_callback_type)(void* handle_ptr, bm::id_t bit_idx);
72 #endif
73 }
74 
75 
76 namespace bm
77 {
78 
79 /** @defgroup bmagic BitMagic Library
80  BitMagic C++ Library
81  For more information please visit: http://bitmagic.io
82 */
83 
84 
85 /** @defgroup bvector bvector<> container
86  The Main bvector<> Group
87  bvector<> template: front end of the BitMagic library.
88 
89  @ingroup bmagic
90 */
91 
92 /** @defgroup bvit bvector<> iterators
93  Iterators for compressed bit-vector traversal
94  @ingroup bvector
95 */
96 
97 
98 
99 
100 /*!
101  @brief Bitvector
102  Bit-vector container with runtime compression of bits
103 
104  @ingroup bvector
105 */
106 template<class Alloc>
107 class bvector
108 {
109 public:
110  typedef Alloc allocator_type;
111  typedef typename allocator_type::allocator_pool_type allocator_pool_type;
112  typedef blocks_manager<Alloc> blocks_manager_type;
113  typedef typename blocks_manager_type::block_idx_type block_idx_type;
114 #ifdef BM64ADDR
115  typedef bm::id64_t size_type;
116 #else
118 #endif
119 
120  /** Statistical information about bitset's memory allocation details. */
121  struct statistics : public bv_statistics
122  {};
123 
124  /*!
125  \brief Optimization mode
126  Every next level means additional checks (better compression vs time)
127  \sa optimize
128  */
129  enum optmode
130  {
131  opt_none = 0, ///< no optimization
132  opt_free_0 = 1, ///< Free unused 0 blocks
133  opt_free_01 = 2, ///< Free unused 0 and 1 blocks
134  opt_compress = 3 ///< compress blocks when possible (GAP/prefix sum)
135  };
136 
137 
138  /**
139  @brief Class reference implements an object for bit assignment.
140  Since C++ does not provide with build-in bit type supporting l-value
141  operations we have to emulate it.
142 
143  @ingroup bvector
144  */
145  class reference
146  {
147  public:
149  : bv_(bv),
150  position_(position)
151  {}
152 
154  : bv_(ref.bv_),
155  position_(ref.position_)
156  {
157  bv_.set(position_, ref.bv_.get_bit(position_));
158  }
159 
160  operator bool() const BMNOEXCEPT
161  {
162  return bv_.get_bit(position_);
163  }
164 
165  const reference& operator=(const reference& ref) const
166  {
167  bv_.set(position_, (bool)ref);
168  return *this;
169  }
170 
171  const reference& operator=(bool value) const BMNOEXCEPT
172  {
173  bv_.set(position_, value);
174  return *this;
175  }
176 
177  bool operator==(const reference& ref) const BMNOEXCEPT
178  {
179  return bool(*this) == bool(ref);
180  }
181 
182  /*! Bitwise AND. Performs operation: bit = bit AND value */
183  const reference& operator&=(bool value) const
184  {
185  bv_.set_bit_and(position_, value);
186  return *this;
187  }
188 
189  /*! Bitwise OR. Performs operation: bit = bit OR value */
190  const reference& operator|=(bool value) const
191  {
192  if (value != bv_.get_bit(position_))
193  {
194  bv_.set_bit(position_);
195  }
196  return *this;
197  }
198 
199  /*! Bitwise exclusive-OR (XOR). Performs operation: bit = bit XOR value */
200  const reference& operator^=(bool value) const
201  {
202  bv_.set(position_, value != bv_.get_bit(position_));
203  return *this;
204  }
205 
206  /*! Logical Not operator */
207  bool operator!() const BMNOEXCEPT
208  {
209  return !bv_.get_bit(position_);
210  }
211 
212  /*! Bit Not operator */
213  bool operator~() const BMNOEXCEPT
214  {
215  return !bv_.get_bit(position_);
216  }
217 
218  /*! Negates the bit value */
220  {
221  bv_.flip(position_);
222  return *this;
223  }
224 
225  private:
226  bvector<Alloc>& bv_; //!< Reference variable on the parent.
227  size_type position_; //!< Position in the parent bitvector.
228  };
229 
230  typedef bool const_reference;
231 
232  /*!
233  @brief Base class for all iterators.
234  @ingroup bvit
235  */
237  {
238  friend class bvector;
239  public:
241  : bv_(0), position_(bm::id_max), block_(0), block_type_(0),
242  block_idx_(0)
243  {}
244 
245  bool operator==(const iterator_base& it) const BMNOEXCEPT
246  {
247  return (position_ == it.position_) && (bv_ == it.bv_);
248  }
249 
250  bool operator!=(const iterator_base& it) const BMNOEXCEPT
251  {
252  return ! operator==(it);
253  }
254 
255  bool operator < (const iterator_base& it) const BMNOEXCEPT
256  {
257  return position_ < it.position_;
258  }
259 
260  bool operator <= (const iterator_base& it) const BMNOEXCEPT
261  {
262  return position_ <= it.position_;
263  }
264 
265  bool operator > (const iterator_base& it) const BMNOEXCEPT
266  {
267  return position_ > it.position_;
268  }
269 
270  bool operator >= (const iterator_base& it) const BMNOEXCEPT
271  {
272  return position_ >= it.position_;
273  }
274 
275  /**
276  \fn bool bm::bvector::iterator_base::valid() const
277  \brief Checks if iterator is still valid. Analog of != 0 comparison for pointers.
278  \returns true if iterator is valid.
279  */
280  bool valid() const BMNOEXCEPT { return position_ != bm::id_max; }
281 
282  /**
283  \fn bool bm::bvector::iterator_base::invalidate()
284  \brief Turns iterator into an invalid state.
285  */
287  { position_ = bm::id_max; block_type_ = ~0u;}
288 
289  /** \brief Compare FSMs for testing purposes
290  \internal
291  */
292  bool compare_state(const iterator_base& ib) const BMNOEXCEPT
293  {
294  if (this->bv_ != ib.bv_) return false;
295  if (this->position_ != ib.position_) return false;
296  if (this->block_ != ib.block_) return false;
297  if (this->block_type_ != ib.block_type_) return false;
298  if (this->block_idx_ != ib.block_idx_) return false;
299 
300  const block_descr& bd = this->bdescr_;
301  const block_descr& ib_db = ib.bdescr_;
302 
303  if (this->block_type_ == 0) // bit block
304  {
305  if (bd.bit_.ptr != ib_db.bit_.ptr) return false;
306  if (bd.bit_.idx != ib_db.bit_.idx) return false;
307  if (bd.bit_.cnt != ib_db.bit_.cnt) return false;
308  if (bd.bit_.pos != ib_db.bit_.pos) return false;
309  for (unsigned i = 0; i < bd.bit_.cnt; ++i)
310  {
311  if (bd.bit_.bits[i] != ib_db.bit_.bits[i]) return false;
312  }
313  }
314  else // GAP block
315  {
316  if (bd.gap_.ptr != ib_db.gap_.ptr) return false;
317  if (bd.gap_.gap_len != ib_db.gap_.gap_len) return false;
318  }
319  return true;
320  }
321 
322  public:
323 
324  /** Bit-block descriptor
325  @internal
326  */
328  {
329  const bm::word_t* ptr; //!< Word pointer.
330  unsigned char bits[set_bitscan_wave_size*32]; //!< bit list
331  unsigned short idx; //!< Current position in the bit list
332  unsigned short cnt; //!< Number of ON bits
333  size_type pos; //!< Last bit position decode before
334  };
335 
336  /** Information about current DGAP block.
337  @internal
338  */
339  struct dgap_descr
340  {
341  const gap_word_t* ptr; //!< Word pointer.
342  gap_word_t gap_len; //!< Current dgap length.
343  };
344 
345  protected:
346  bm::bvector<Alloc>* bv_; //!< Pointer on parent bitvector
347  size_type position_; //!< Bit position (bit idx)
348  const bm::word_t* block_; //!< Block pointer.(NULL-invalid)
349  unsigned block_type_; //!< Type of block. 0-Bit, 1-GAP
350  block_idx_type block_idx_; //!< Block index
351 
352  /*! Block type dependent information for current block. */
354  {
355  bitblock_descr bit_; //!< BitBlock related info.
356  dgap_descr gap_; //!< DGAP block related info.
357  } bdescr_;
358  };
359 
360  /*!
361  @brief Output iterator iterator designed to set "ON" bits based on
362  input sequence of integers (bit indeces).
363 
364  STL container can be converted to bvector using this iterator
365  Insert iterator guarantees the vector will be dynamically resized
366  (set_bit does not do that).
367 
368  @note
369  If you have many bits to set it is a good idea to use output iterator
370  instead of explicitly calling set, because iterator may implement
371  some performance specific tricks to make sure bulk insert is fast.
372 
373  @sa bulk_insert_iterator
374 
375  @ingroup bvit
376  */
378  {
379  friend class bulk_insert_iterator;
380  public:
381 #ifndef BM_NO_STL
382  typedef std::output_iterator_tag iterator_category;
383 #endif
386  typedef void difference_type;
387  typedef void pointer;
388  typedef void reference;
389 
391 
393  : bvect_(&bvect),
394  max_bit_(bvect.size())
395  {
396  bvect_->init();
397  }
398 
400  : bvect_(iit.bvect_),
401  max_bit_(iit.max_bit_)
402  {
403  }
404 
406  {
407  bvect_ = ii.bvect_; max_bit_ = ii.max_bit_;
408  return *this;
409  }
410 
412  {
413  BM_ASSERT(n < bm::id_max);
414  BM_ASSERT_THROW(n < bm::id_max, BM_ERR_RANGE);
415 
416  if (n >= max_bit_)
417  {
418  max_bit_ = n;
419  if (n >= bvect_->size())
420  {
421  size_type new_size = (n == bm::id_max) ? bm::id_max : n + 1;
422  bvect_->resize(new_size);
423  }
424  }
426  return *this;
427  }
428  /*! Returns *this without doing anything (no-op) */
429  insert_iterator& operator*() { return *this; }
430  /*! Returns *this. This iterator does not move (no-op) */
431  insert_iterator& operator++() { return *this; }
432  /*! Returns *this. This iterator does not move (no-op)*/
433  insert_iterator& operator++(int) { return *this; }
434 
435  bvector_type* get_bvector() const { return bvect_; }
436 
437  protected:
440  };
441 
442 
443  /*!
444  @brief Output iterator iterator designed to set "ON" bits based on
445  input sequence of integers.
446 
447  STL container can be converted to bvector using this iterator
448  Insert iterator guarantees the vector will be dynamically resized
449  (set_bit does not do that).
450 
451  The difference from the canonical insert iterator, is that
452  bulk insert implements internal buffering, which needs
453  to flushed (or flushed automatically when goes out of scope).
454  Buffering creates a delayed effect, which needs to be
455  taken into account.
456 
457  @sa insert_iterator
458 
459  @ingroup bvit
460  */
462  {
463  public:
464 #ifndef BM_NO_STL
465  typedef std::output_iterator_tag iterator_category;
466 #endif
470  typedef void difference_type;
471  typedef void pointer;
472  typedef void reference;
473 
475  : bvect_(0), buf_(0), buf_size_(0), sorted_(BM_UNKNOWN) {}
476 
478  {
479  flush();
480  if (buf_)
481  bvect_->blockman_.get_allocator().free_bit_block((bm::word_t*)buf_);
482  }
483 
486  : bvect_(&bvect), sorted_(so)
487  {
488  bvect_->init();
489 
490  buf_ = (value_type*) bvect_->blockman_.get_allocator().alloc_bit_block();
491  buf_size_ = 0;
492  }
493 
495  : bvect_(iit.bvect_)
496  {
497  buf_ = bvect_->blockman_.get_allocator().alloc_bit_block();
498  buf_size_ = iit.buf_size_;
499  sorted_ = iit.sorted_;
500  ::memcpy(buf_, iit.buf_, buf_size_ * sizeof(*buf_));
501  }
502 
504  : bvect_(iit.get_bvector())
505  {
506  buf_ = (value_type*) bvect_->blockman_.get_allocator().alloc_bit_block();
507  buf_size_ = 0;
509  }
510 
512  : bvect_(iit.bvect_)
513  {
514  buf_ = iit.buf_; iit.buf_ = 0;
515  buf_size_ = iit.buf_size_;
516  sorted_ = iit.sorted_;
517  }
518 
520  {
521  bvect_ = ii.bvect_;
522  if (!buf_)
523  buf_ = bvect_->allocate_tempblock();
524  buf_size_ = ii.buf_size_;
525  ::memcpy(buf_, ii.buf_, buf_size_ * sizeof(*buf_));
526  sorted_ = ii.sorted_;
527  return *this;
528  }
529 
531  {
532  bvect_ = ii.bvect_;
533  if (buf_)
534  bvect_->free_tempblock(buf_);
535  buf_ = ii.buf_; ii.buf_ = 0;
536  buf_size_ = ii.buf_size_;
537  sorted_ = ii.sorted_;
538  return *this;
539  }
540 
542  {
543  BM_ASSERT(n < bm::id_max);
544  BM_ASSERT_THROW(n < bm::id_max, BM_ERR_RANGE);
545 
546  if (buf_size_ == buf_size_max())
547  {
549  buf_size_ = 0;
550  }
551  buf_[buf_size_++] = n;
552  return *this;
553  }
554 
555  /*! Returns *this without doing anything (no-op) */
556  bulk_insert_iterator& operator*() { return *this; }
557  /*! Returns *this. This iterator does not move (no-op) */
558  bulk_insert_iterator& operator++() { return *this; }
559  /*! Returns *this. This iterator does not move (no-op)*/
560  bulk_insert_iterator& operator++(int) { return *this; }
561 
562  /*! Flush the internal buffer into target bvector */
563  void flush()
564  {
565  BM_ASSERT(bvect_);
566  if (buf_size_)
567  {
569  buf_size_ = 0;
570  }
571  bvect_->sync_size();
572  }
573 
575 
576  protected:
577  static
579  {
580  #ifdef BM64ADDR
581  return bm::set_block_size / 2;
582  #else
583  return bm::set_block_size;
584  #endif
585  }
586 
587  protected:
588  bvector_type* bvect_; ///< target bvector
589  size_type* buf_; ///< bulk insert buffer
590  size_type buf_size_; ///< current buffer size
591  bm::sort_order sorted_; ///< sort order hint
592  };
593 
594 
595 
596  /*! @brief Constant iterator designed to enumerate "ON" bits
597  @ingroup bvit
598  */
599  class enumerator : public iterator_base
600  {
601  public:
602 #ifndef BM_NO_STL
603  typedef std::input_iterator_tag iterator_category;
604 #endif
606  typedef unsigned difference_type;
607  typedef unsigned* pointer;
608  typedef unsigned& reference;
609 
610  public:
612  {}
613 
614  /*! @brief Construct enumerator associated with a vector.
615  This construction creates unpositioned iterator with status
616  valid() == false. It can be re-positioned using go_first() or go_to()
617  */
619  : iterator_base()
620  {
621  this->bv_ = const_cast<bvector<Alloc>*>(bv);
622  }
623 
624  /*! @brief Construct enumerator for bit vector
625  @param bv bit-vector pointer
626  @param pos bit position in the vector
627  if position is 0, it finds the next 1 or becomes not valid
628  (en.valid() == false)
629  */
631  : iterator_base()
632  {
633  this->bv_ = const_cast<bvector<Alloc>*>(bv);
634  this->go_to(pos);
635  }
636 
637  /*! \brief Get current position (value) */
638  size_type operator*() const BMNOEXCEPT { return this->position_; }
639 
640  /*! \brief Get current position (value) */
641  size_type value() const BMNOEXCEPT { return this->position_; }
642 
643  /*! \brief Advance enumerator forward to the next available bit */
644  enumerator& operator++() BMNOEXCEPT { this->go_up(); return *this; }
645 
646  /*! \brief Advance enumerator forward to the next available bit.
647  Possibly do NOT use this operator it is slower than the pre-fix increment.
648  */
650  {
651  enumerator tmp = *this;
652  this->go_up();
653  return tmp;
654  }
655 
656  /*! \brief Position enumerator to the first available bit */
657  void go_first() BMNOEXCEPT;
658 
659  /*! advance iterator forward by one
660  @return true if advance was successfull and the enumerator is valid
661  */
662  bool advance() BMNOEXCEPT { return this->go_up(); }
663 
664  /*! \brief Advance enumerator to the next available bit */
665  bool go_up() BMNOEXCEPT;
666 
667  /*!
668  @brief Skip to specified relative rank
669  @param rank - number of ON bits to go for (must be: > 0)
670  @return true if skip was successfull and enumerator is valid
671  */
672  bool skip_to_rank(size_type rank) BMNOEXCEPT
673  {
674  BM_ASSERT(rank);
675  --rank;
676  if (!rank)
677  return this->valid();
678  return skip(rank);
679  }
680 
681  /*!
682  @brief Skip specified number of bits from enumeration
683  @param rank - number of ON bits to skip
684  @return true if skip was successfull and enumerator is valid
685  */
686  bool skip(size_type rank) BMNOEXCEPT;
687 
688  /*!
689  @brief go to a specific position in the bit-vector (or next)
690  */
691  bool go_to(size_type pos) BMNOEXCEPT;
692 
693  private:
694  typedef typename iterator_base::block_descr block_descr_type;
695 
696  static bool decode_wave(block_descr_type* bdescr) BMNOEXCEPT;
697  bool decode_bit_group(block_descr_type* bdescr) BMNOEXCEPT;
698  bool decode_bit_group(block_descr_type* bdescr,
700  bool search_in_bitblock() BMNOEXCEPT;
701  bool search_in_gapblock() BMNOEXCEPT;
702  bool search_in_blocks() BMNOEXCEPT;
703 
704  };
705 
706  /*!
707  @brief Constant iterator designed to enumerate "ON" bits
708  counted_enumerator keeps bitcount, ie number of ON bits starting
709  from the position 0 in the bit string up to the currently enumerated bit
710 
711  When increment operator called current position is increased by 1.
712 
713  @ingroup bvit
714  */
716  {
717  public:
718 #ifndef BM_NO_STL
719  typedef std::input_iterator_tag iterator_category;
720 #endif
721  counted_enumerator() BMNOEXCEPT : bit_count_(0){}
722 
724  {
725  bit_count_ = this->valid(); // 0 || 1
726  }
727 
729  {
730  enumerator* me = this;
731  *me = en;
732  if (this->valid())
733  this->bit_count_ = 1;
734  return *this;
735  }
736 
738  {
739  this->go_up();
740  this->bit_count_ += this->valid();
741  return *this;
742  }
743 
745  {
746  counted_enumerator tmp(*this);
747  this->go_up();
748  this->bit_count_ += this->valid();
749  return tmp;
750  }
751 
752  /*! @brief Number of bits ON starting from the .
753 
754  Method returns number of ON bits fromn the bit 0 to the current bit
755  For the first bit in bitvector it is 1, for the second 2
756  */
757  size_type count() const BMNOEXCEPT { return bit_count_; }
758  private:
759  /*! Function closed for usage */
761 
762  private:
763  size_type bit_count_;
764  };
765 
766  /*!
767  Resource guard for bvector<>::set_allocator_pool()
768  @ingroup bvector
769  @internal
770  */
772  {
773  public:
775  {}
776 
778  : bv_(&bv)
779  {
780  bv.set_allocator_pool(&pool);
781  }
783  {
784  if (bv_)
785  bv_->set_allocator_pool(0);
786  }
787 
788  /// check if vector has no assigned allocator and set one
791  {
792  if (!bv.get_allocator_pool()) // alloc pool not set yet
793  {
794  BM_ASSERT(!bv_);
795  bv_ = &bv;
796  bv_->set_allocator_pool(&pool);
797  }
798  }
799 
800  private:
801  mem_pool_guard(const mem_pool_guard&) = delete;
802  void operator=(const mem_pool_guard&) = delete;
803  private:
804  bvector<Alloc>* bv_; ///< garded object
805  };
806 
807 
808  friend class iterator_base;
809  friend class enumerator;
810  template<class BV> friend class aggregator;
811  template<class BV> friend class operation_deserializer;
812 
813 public:
814  /*! @brief memory allocation policy
815 
816  Defualt memory allocation policy uses BM_BIT, and standard
817  GAP levels tune-ups
818  */
820  {
823 
826  : strat(s), glevel_len(glevels)
827  {}
828  };
829 
830  typedef rs_index<allocator_type> blocks_count;
831  typedef rs_index<allocator_type> rs_index_type;
832 
833 public:
834  /*! @name Construction, initialization, assignment */
835  //@{
836 
837  /*!
838  \brief Constructs bvector class
839  \param strat - operation mode strategy,
840  BM_BIT - default strategy, bvector use plain bitset
841  blocks, (performance oriented strategy).
842  BM_GAP - memory effitent strategy, bvector allocates
843  blocks as array of intervals(gaps) and convert blocks
844  into plain bitsets only when enthropy grows.
845  \param glevel_len
846  - pointer on C-style array keeping GAP block sizes.
847  bm::gap_len_table<true>::_len - default value set
848  (use bm::gap_len_table_min<true>::_len for very sparse vectors)
849  (use bm::gap_len_table_nl<true>::_len non-linear GAP growth)
850  \param bv_size
851  - bvector size (number of bits addressable by bvector), bm::id_max means
852  "no limits" (recommended).
853  bit vector allocates this space dynamically on demand.
854  \param alloc - alllocator for this instance
855 
856  \sa bm::gap_len_table bm::gap_len_table_min set_new_blocks_strat
857  */
859  const gap_word_t* glevel_len = bm::gap_len_table<true>::_len,
860  size_type bv_size = bm::id_max,
861  const Alloc& alloc = Alloc())
862  : blockman_(glevel_len, bv_size, alloc),
863  new_blocks_strat_(strat),
864  size_(bv_size)
865  {}
866 
867  /*!
868  \brief Constructs bvector class
869  */
871  strategy strat = BM_BIT,
872  const gap_word_t* glevel_len = bm::gap_len_table<true>::_len,
873  const Alloc& alloc = Alloc())
874  : blockman_(glevel_len, bv_size, alloc),
875  new_blocks_strat_(strat),
876  size_(bv_size)
877  {}
878 
879  /*!
880  \brief Copy constructor
881  */
883  : blockman_(bvect.blockman_),
884  new_blocks_strat_(bvect.new_blocks_strat_),
885  size_(bvect.size_)
886  {}
887 
888  /*!
889  \brief Copy constructor for range copy [left..right]
890 
891  \sa copy_range
892  */
894  : blockman_(bvect.blockman_.glevel_len_, bvect.blockman_.max_bits_, bvect.blockman_.alloc_),
895  new_blocks_strat_(bvect.new_blocks_strat_),
896  size_(bvect.size_)
897  {
898  if (!bvect.blockman_.is_init())
899  return;
900  if (left > right)
901  bm::xor_swap(left, right);
902  copy_range_no_check(bvect, left, right);
903  }
904 
905 
907  /*!
908  \brief Explicit post-construction initialization
909  */
910  void init();
911 
912  /*!
913  \brief Copy assignment operator
914  */
916  {
917  if (this != &bvect)
918  {
919  blockman_.deinit_tree();
920  blockman_.copy(bvect.blockman_);
921  resize(bvect.size());
922  }
923  return *this;
924  }
925 
926 #ifndef BM_NO_CXX11
927  /*!
928  \brief Move constructor
929  */
931  {
932  blockman_.move_from(bvect.blockman_);
933  size_ = bvect.size_;
934  new_blocks_strat_ = bvect.new_blocks_strat_;
935  }
936 
937  /*!
938  \brief Brace constructor
939  */
940  bvector(std::initializer_list<size_type> il)
941  : blockman_(bm::gap_len_table<true>::_len, bm::id_max, Alloc()),
942  new_blocks_strat_(BM_BIT),
943  size_(bm::id_max)
944  {
945  init();
946  std::initializer_list<size_type>::const_iterator it_start = il.begin();
947  std::initializer_list<size_type>::const_iterator it_end = il.end();
948  for (; it_start < it_end; ++it_start)
949  {
950  this->set_bit_no_check(*it_start);
951  }
952  }
953 
954  /*!
955  \brief Move assignment operator
956  */
958  {
959  this->move_from(bvect);
960  return *this;
961  }
962 #endif
963  /*!
964  \brief Move bvector content from another bvector
965  */
967 
968  /*! \brief Exchanges content of bv and this bvector.
969  */
971 
972  /*! \brief Merge/move content from another vector
973 
974  Merge performs a logical OR operation, but the source vector
975  is not immutable. Source content gets destroyed (memory moved)
976  to create a union of two vectors.
977  Merge operation can be more efficient than OR if argument is
978  a temporary vector.
979 
980  @param bvect - [in, out] - source vector (NOT immutable)
981  */
983 
984  //@}
985 
987  {
988  if (n >= size_)
989  {
990  size_type new_size = (n == bm::id_max) ? bm::id_max : n + 1;
991  resize(new_size);
992  }
993  return reference(*this, n);
994  }
995 
997  {
998  BM_ASSERT(n < size_);
999  return get_bit(n);
1000  }
1001 
1002  void operator &= (const bvector<Alloc>& bv) { bit_and(bv); }
1003  void operator ^= (const bvector<Alloc>& bv) { bit_xor(bv); }
1004  void operator |= (const bvector<Alloc>& bv) { bit_or(bv); }
1005  void operator -= (const bvector<Alloc>& bv) { bit_sub(bv); }
1006 
1007  bool operator < (const bvector<Alloc>& bv) const { return compare(bv)<0; }
1008  bool operator <= (const bvector<Alloc>& bv) const { return compare(bv)<=0; }
1009  bool operator > (const bvector<Alloc>& bv) const { return compare(bv)>0; }
1010  bool operator >= (const bvector<Alloc>& bv) const { return compare(bv) >= 0; }
1011  bool operator == (const bvector<Alloc>& bv) const BMNOEXCEPT { return equal(bv); }
1012  bool operator != (const bvector<Alloc>& bv) const BMNOEXCEPT { return !equal(bv); }
1013 
1014  bvector<Alloc> operator~() const { return bvector<Alloc>(*this).invert(); }
1015 
1016  Alloc get_allocator() const
1017  { return blockman_.get_allocator(); }
1018 
1019  /// Set allocator pool for local (non-th readed)
1020  /// memory cyclic(lots of alloc-free ops) opertations
1021  ///
1023  { blockman_.get_allocator().set_pool(pool_ptr); }
1024 
1025  /// Get curent allocator pool (if set)
1026  /// @return pointer to the current pool or NULL
1028  { return blockman_.get_allocator().get_pool(); }
1029 
1030  // --------------------------------------------------------------------
1031  /*! @name Bit access/modification methods */
1032  //@{
1033 
1034  /*!
1035  \brief Sets bit n.
1036  \param n - index of the bit to be set.
1037  \param val - new bit value
1038  \return TRUE if bit was changed
1039  */
1040  bool set_bit(size_type n, bool val = true);
1041 
1042  /*!
1043  \brief Sets bit n using bit AND with the provided value.
1044  \param n - index of the bit to be set.
1045  \param val - new bit value
1046  \return TRUE if bit was changed
1047  */
1048  bool set_bit_and(size_type n, bool val = true);
1049 
1050  /*!
1051  \brief Increment the specified element
1052 
1053  Bit increment rules:
1054  0 + 1 = 1 (no carry over)
1055  1 + 1 = 0 (with carry over returned)
1056 
1057  \param n - index of the bit to be set
1058  \return TRUE if carry over created (1+1)
1059  */
1060  bool inc(size_type n);
1061 
1062 
1063  /*!
1064  \brief Sets bit n only if current value equals the condition
1065  \param n - index of the bit to be set.
1066  \param val - new bit value
1067  \param condition - expected current value
1068  \return TRUE if bit was changed
1069  */
1070  bool set_bit_conditional(size_type n, bool val, bool condition);
1071 
1072  /*!
1073  \brief Sets bit n if val is true, clears bit n if val is false
1074  \param n - index of the bit to be set
1075  \param val - new bit value
1076  \return *this
1077  */
1078  bvector<Alloc>& set(size_type n, bool val = true);
1079 
1080  /*!
1081  \brief Sets every bit in this bitset to 1.
1082  \return *this
1083  */
1084  bvector<Alloc>& set();
1085 
1086  /*!
1087  \brief Set list of bits in this bitset to 1.
1088 
1089  Method implements optimized bulk setting of multiple bits at once.
1090  The best results are achieved when the imput comes sorted.
1091  This is equivalent of OR (Set Union), argument set as an array.
1092 
1093  @param ids - pointer on array of indexes to set
1094  @param ids_size - size of the input (ids)
1095  @param so - sort order (use BM_SORTED for faster load)
1096 
1097  @sa keep, clear
1098  */
1099  void set(const size_type* ids, size_type ids_size,
1101 
1102  /*!
1103  \brief Keep list of bits in this bitset, others are cleared
1104 
1105  This is equivalent of AND (Set Intersect), argument set as an array.
1106 
1107  @param ids - pointer on array of indexes to set
1108  @param ids_size - size of the input (ids)
1109  @param so - sort order (use BM_SORTED for faster load)
1110 
1111  @sa set, clear
1112  */
1113  void keep(const size_type* ids, size_type ids_size,
1115 
1116  /*!
1117  \brief clear list of bits in this bitset
1118 
1119  This is equivalent of AND NOT (Set Substract), argument set as an array.
1120 
1121  @param ids - pointer on array of indexes to set
1122  @param ids_size - size of the input (ids)
1123  @param so - sort order (use BM_SORTED for faster load)
1124 
1125  @sa set, keep
1126  */
1127  void clear(const size_type* ids, size_type ids_size,
1129 
1130 
1131  /*!
1132  \brief Set bit without checking preconditions (size, etc)
1133 
1134  Fast set bit method, without safety net.
1135  Make sure you call bvector<>::init() before setting bits with this
1136  function.
1137 
1138  \param n - bit number
1139  */
1140  void set_bit_no_check(size_type n);
1141 
1142  /**
1143  \brief Set specified bit without checking preconditions (size, etc)
1144  */
1145  bool set_bit_no_check(size_type n, bool val);
1146 
1147  /*!
1148  \brief Sets all bits in the specified closed interval [left,right]
1149  Interval must be inside the bvector's size.
1150  This method DOES NOT resize vector.
1151 
1152  \param left - interval start
1153  \param right - interval end (closed interval)
1154  \param value - value to set interval in
1155 
1156  \return *this
1157  @sa clear_range
1158  */
1160  size_type right,
1161  bool value = true);
1162 
1163 
1164  /*!
1165  \brief Sets all bits to zero in the specified closed interval [left,right]
1166  Interval must be inside the bvector's size.
1167  This method DOES NOT resize vector.
1168 
1169  \param left - interval start
1170  \param right - interval end (closed interval)
1171 
1172  @sa set_range
1173  */
1174  void clear_range(size_type left, size_type right)
1175  { set_range(left, right, false); }
1176 
1177 
1178  /*!
1179  \brief Sets all bits to zero outside of the closed interval [left,right]
1180  Expected result: 00000...0[left, right]0....0000
1181 
1182  \param left - interval start
1183  \param right - interval end (closed interval)
1184 
1185  @sa set_range
1186  */
1187  void keep_range(size_type left, size_type right);
1188 
1189  /*!
1190  \brief Copy all bits in the specified closed interval [left,right]
1191 
1192  \param bvect - source bit-vector
1193  \param left - interval start
1194  \param right - interval end (closed interval)
1195  */
1196  void copy_range(const bvector<Alloc>& bvect,
1197  size_type left,
1198  size_type right);
1199 
1200  /*!
1201  \brief Clears bit n.
1202  \param n - bit's index to be cleaned.
1203  \return true if bit was cleared
1204  */
1205  bool clear_bit(size_type n) { return set_bit(n, false); }
1206 
1207  /*!
1208  \brief Clears bit n without precondiion checks
1209  \param n - bit's index to be cleaned.
1210  */
1212 
1213  /*!
1214  \brief Clears every bit in the bitvector.
1215 
1216  \param free_mem if "true" (default) bvector frees the memory,
1217  otherwise sets blocks to 0.
1218  */
1219  void clear(bool free_mem = false) { blockman_.set_all_zero(free_mem); }
1220 
1221  /*!
1222  \brief Clears every bit in the bitvector.
1223  \return *this;
1224  */
1225  bvector<Alloc>& reset() { clear(true); return *this; }
1226 
1227  /*!
1228  \brief Flips bit n
1229  \return *this
1230  */
1231  bvector<Alloc>& flip(size_type n) { this->inc(n); return *this; }
1232 
1233  /*!
1234  \brief Flips all bits
1235  \return *this
1236  @sa invert
1237  */
1238  bvector<Alloc>& flip() { return invert(); }
1239 
1240  //@}
1241  // --------------------------------------------------------------------
1242 
1243 
1244  /*! Function erturns insert iterator for this bitvector */
1245  insert_iterator inserter() { return insert_iterator(*this); }
1246 
1247  // --------------------------------------------------------------------
1248  /*! @name Size and capacity
1249  By default bvector is dynamically sized, manual control methods
1250  available
1251  */
1252  //@{
1253 
1254  /** \brief Returns bvector's capacity (number of bits it can store) */
1255  //size_type capacity() const { return blockman_.capacity(); }
1256 
1257  /*! \brief return current size of the vector (bits) */
1258  size_type size() const BMNOEXCEPT { return size_; }
1259 
1260  /*!
1261  \brief Change size of the bvector
1262  \param new_size - new size in bits
1263  */
1264  void resize(size_type new_size);
1265 
1266  //@}
1267  // --------------------------------------------------------------------
1268 
1269  /*! @name Population counting, ranks, ranges and intervals
1270  */
1271  //@{
1272 
1273  /*!
1274  \brief population cout (count of ON bits)
1275  \sa count_range
1276  \return Total number of bits ON
1277  */
1278  size_type count() const BMNOEXCEPT;
1279 
1280  /*! \brief Computes bitcount values for all bvector blocks
1281  \param arr - pointer on array of block bit counts
1282  \return Index of the last block counted.
1283  This number +1 gives you number of arr elements initialized during the
1284  function call.
1285  */
1286  block_idx_type count_blocks(unsigned* arr) const BMNOEXCEPT;
1287 
1288 
1289  /*!
1290  \brief Returns count of 1 bits in the given range [left..right]
1291  Uses rank-select index to accelerate the search
1292  \param left - index of first bit start counting from
1293  \param right - index of last bit
1294  \param rs_idx - block count structure to accelerate search
1295  \sa build_rs_index
1296 
1297  \return population count in the diapason
1298  */
1300  size_type right,
1301  const rs_index_type& rs_idx) const BMNOEXCEPT;
1302 
1303  /*!
1304  \brief Returns count of 1 bits in the given range [left..right]
1305 
1306  \param left - index of first bit start counting from
1307  \param right - index of last bit
1308 
1309  \return population count in the diapason
1310  */
1311  size_type count_range(size_type left, size_type right) const BMNOEXCEPT;
1312 
1313  /*!
1314  \brief Returns true if all bits in the range are 1s (saturated interval)
1315  Function uses closed interval [left, right]
1316 
1317  \param left - index of first bit start checking
1318  \param right - index of last bit
1319 
1320  \return true if all bits are 1, false otherwise
1321  @sa any_range, count_range
1322  */
1323  bool is_all_one_range(size_type left, size_type right) const BMNOEXCEPT;
1324 
1325  /*!
1326  \brief Returns true if any bits in the range are 1s (non-empty interval)
1327  Function uses closed interval [left, right]
1328 
1329  \param left - index of first bit start checking
1330  \param right - index of last bit
1331 
1332  \return true if at least 1 bits is set
1333  @sa is_all_one_range, count_range
1334  */
1335  bool any_range(size_type left, size_type right) const BMNOEXCEPT;
1336 
1337 
1338  /*! \brief compute running total of all blocks in bit vector (rank-select index)
1339  \param rs_idx - [out] pointer to index / count structure
1340  \param bv_blocks - [out] list of block ids in the vector (internal, optional)
1341  Function will fill full array of running totals
1342  \sa count_to, select, find_rank
1343  */
1344  void build_rs_index(rs_index_type* rs_idx, bvector<Alloc>* bv_blocks=0) const;
1345 
1346  /*!
1347  \brief Returns count of 1 bits (population) in [0..right] range.
1348 
1349  This operation is also known as rank of bit N.
1350 
1351  \param n - index of bit to rank
1352  \param rs_idx - rank-select to accelerate search
1353  should be prepared using build_rs_index
1354  \return population count in the range [0..n]
1355  \sa build_rs_index
1356  \sa count_to_test, select, rank, rank_corrected
1357  */
1359  const rs_index_type& rs_idx) const BMNOEXCEPT;
1360 
1361 
1362  /*!
1363  \brief Returns rank of specified bit position (same as count_to())
1364 
1365  \param n - index of bit to rank
1366  \param rs_idx - rank-select index
1367  \return population count in the range [0..n]
1368  \sa build_rs_index
1369  \sa count_to_test, select, rank, rank_corrected
1370  */
1372  const rs_index_type& rs_idx) const BMNOEXCEPT
1373  { return count_to(n, rs_idx); }
1374 
1375  /*!
1376  \brief Returns rank corrceted by the requested border value (as -1)
1377 
1378  This is rank function (bit-count) minus value of bit 'n'
1379  if bit-n is true function returns rank()-1 if false returns rank()
1380  faster than rank() + test().
1381 
1382 
1383  \param n - index of bit to rank
1384  \param rs_idx - rank-select index
1385  \return population count in the range [0..n] corrected as -1 by the value of n
1386  \sa build_rs_index
1387  \sa count_to_test, select, rank
1388  */
1390  const rs_index_type& rs_idx) const BMNOEXCEPT;
1391 
1392  /*!
1393  \brief popcount in [0..right] range if test(right) == true
1394 
1395  This is conditional rank operation, which is faster than test()
1396  plus count_to()
1397 
1398  \param n - index of bit to test and rank
1399  \param rs_idx - rank-select index
1400  (block count structure to accelerate search)
1401  should be prepared using build_rs_index()
1402 
1403  \return population count in the diapason or 0 if right bit test failed
1404 
1405  \sa build_rs_index
1406  \sa count_to
1407  */
1408  size_type
1410  const rs_index_type& rs_idx) const BMNOEXCEPT;
1411 
1412 
1413  /*! Recalculate bitcount (deprecated)
1414  */
1416 
1417  /*!
1418  Disables count cache. (deprecated).
1419  */
1421 
1422  //@}
1423 
1424  // --------------------------------------------------------------------
1425  /*! @name Bit access (read-only) */
1426  //@{
1427 
1428  /*!
1429  \brief returns true if bit n is set and false is bit n is 0.
1430  \param n - Index of the bit to check.
1431  \return Bit value (1 or 0)
1432  */
1433  bool get_bit(size_type n) const BMNOEXCEPT;
1434 
1435  /*!
1436  \brief returns true if bit n is set and false is bit n is 0.
1437  \param n - Index of the bit to check.
1438  \return Bit value (1 or 0)
1439  */
1440  bool test(size_type n) const BMNOEXCEPT { return get_bit(n); }
1441 
1442  //@}
1443 
1444  // --------------------------------------------------------------------
1445  /*! @name bit-shift and insert operations */
1446  //@{
1447 
1448  /*!
1449  \brief Shift right by 1 bit, fill with zero return carry out
1450  \return Carry over bit value (1 or 0)
1451  */
1452  bool shift_right();
1453 
1454  /*!
1455  \brief Shift left by 1 bit, fill with zero return carry out
1456  \return Carry over bit value (1 or 0)
1457  */
1458  bool shift_left();
1459 
1460  /*!
1461  \brief Insert bit into specified position
1462  All the vector content after insert position is shifted right.
1463 
1464  \param n - index of the bit to insert
1465  \param value - insert value
1466 
1467  \return Carry over bit value (1 or 0)
1468  */
1469  bool insert(size_type n, bool value);
1470 
1471  /*!
1472  \brief Erase bit in the specified position
1473  All the vector content after erase position is shifted left.
1474 
1475  \param n - index of the bit to insert
1476  */
1477  void erase(size_type n);
1478 
1479  //@}
1480 
1481  // --------------------------------------------------------------------
1482  /*! @name Check for empty-ness of container */
1483  //@{
1484 
1485  /*!
1486  \brief Returns true if any bits in this bitset are set, and otherwise returns false.
1487  \return true if any bit is set
1488  */
1489  bool any() const BMNOEXCEPT;
1490 
1491  /*!
1492  \brief Returns true if no bits are set, otherwise returns false.
1493  */
1494  bool none() const BMNOEXCEPT { return !any(); }
1495 
1496  //@}
1497  // --------------------------------------------------------------------
1498 
1499  /*! @name Scan and find bits and indexes */
1500  //@{
1501 
1502  /*!
1503  \fn bool bvector::find(bm::id_t& pos) const
1504  \brief Finds index of first 1 bit
1505  \param pos - [out] index of the found 1 bit
1506  \return true if search returned result
1507  \sa get_first, get_next, extract_next, find_reverse, find_first_mismatch
1508  */
1509  bool find(size_type& pos) const BMNOEXCEPT;
1510 
1511  /*!
1512  \fn bool bvector::find(bm::id_t from, bm::id_t& pos) const
1513  \brief Find index of 1 bit starting from position
1514  \param from - position to start search from
1515  \param pos - [out] index of the found 1 bit
1516  \return true if search returned result
1517  \sa get_first, get_next, extract_next, find_reverse, find_first_mismatch
1518  */
1519  bool find(size_type from, size_type& pos) const BMNOEXCEPT;
1520 
1521 
1522  /*!
1523  \fn bm::id_t bvector::get_first() const
1524  \brief find first 1 bit in vector.
1525  Function may return 0 and this requires an extra check if bit 0 is
1526  actually set or bit-vector is empty
1527 
1528  \return Index of the first 1 bit, may return 0
1529  \sa get_next, find, extract_next, find_reverse
1530  */
1531  size_type get_first() const BMNOEXCEPT { return check_or_next(0); }
1532 
1533  /*!
1534  \fn bm::id_t bvector::get_next(bm::id_t prev) const
1535  \brief Finds the number of the next bit ON.
1536  \param prev - Index of the previously found bit.
1537  \return Index of the next bit which is ON or 0 if not found.
1538  \sa get_first, find, extract_next, find_reverse
1539  */
1541  { return (++prev == bm::id_max) ? 0 : check_or_next(prev); }
1542 
1543  /*!
1544  \fn bm::id_t bvector::extract_next(bm::id_t prev)
1545  \brief Finds the number of the next bit ON and sets it to 0.
1546  \param prev - Index of the previously found bit.
1547  \return Index of the next bit which is ON or 0 if not found.
1548  \sa get_first, get_next, find_reverse
1549  */
1551  {
1552  return (++prev == bm::id_max) ? 0 : check_or_next_extract(prev);
1553  }
1554 
1555  /*!
1556  \brief Finds last index of 1 bit
1557  \param pos - index of the last found 1 bit
1558  \return true if search returned result
1559  \sa get_first, get_next, extract_next, find, find_first_mismatch
1560  */
1561  bool find_reverse(size_type& pos) const BMNOEXCEPT;
1562 
1563  /*!
1564  \brief Finds dynamic range of bit-vector [first, last]
1565  \param first - index of the first found 1 bit
1566  \param last - index of the last found 1 bit
1567  \return true if search returned result
1568  \sa get_first, get_next, extract_next, find, find_reverse
1569  */
1570  bool find_range(size_type& first, size_type& last) const BMNOEXCEPT;
1571 
1572  /*!
1573  \brief Find bit-vector position for the specified rank(bitcount)
1574 
1575  Rank based search, counts number of 1s from specified position until
1576  finds the ranked position relative to start from position.
1577  In other words: range population count between from and pos == rank.
1578 
1579  \param rank - rank to find (bitcount)
1580  \param from - start positioon for rank search
1581  \param pos - position with speciefied rank (relative to from position)
1582 
1583  \return true if requested rank was found
1584  */
1585  bool find_rank(size_type rank, size_type from,
1586  size_type& pos) const BMNOEXCEPT;
1587 
1588  /*!
1589  \brief Find bit-vector position for the specified rank(bitcount)
1590 
1591  Rank based search, counts number of 1s from specified position until
1592  finds the ranked position relative to start from position.
1593  In other words: range population count between from and pos == rank.
1594 
1595  \param rank - rank to find (bitcount)
1596  \param from - start positioon for rank search
1597  \param pos - position with speciefied rank (relative to from position)
1598  \param rs_idx - rank-select index to accelarate search
1599  (should be prepared using build_rs_index)
1600 
1601  \sa build_rs_index, select
1602 
1603  \return true if requested rank was found
1604  */
1605  bool find_rank(size_type rank, size_type from, size_type& pos,
1606  const rs_index_type& rs_idx) const BMNOEXCEPT;
1607 
1608  /*!
1609  \brief select bit-vector position for the specified rank(bitcount)
1610 
1611  Rank based search, counts number of 1s from specified position until
1612  finds the ranked position relative to start from position.
1613  Uses
1614  In other words: range population count between from and pos == rank.
1615 
1616  \param rank - rank to find (bitcount)
1617  \param pos - position with speciefied rank (relative to from position) [out]
1618  \param rs_idx - block count structure to accelerate rank search
1619 
1620  \sa running_count_blocks, find_rank
1621 
1622  \return true if requested rank was found
1623  */
1624  bool select(size_type rank, size_type& pos,
1625  const rs_index_type& rs_idx) const BMNOEXCEPT;
1626 
1627  //@}
1628 
1629 
1630  // --------------------------------------------------------------------
1631  /*! @name Algebra of Sets operations */
1632  //@{
1633 
1634  /*!
1635  \brief 3-operand OR : this := bv1 OR bv2
1636  \param bv1 - Argument vector 1
1637  \param bv2 - Argument vector 2
1638  \param opt_mode - optimization compression
1639  (when it is performed on the fly it is faster than a separate
1640  call to optimize()
1641  @sa optimize, bit_or
1642  */
1644  const bm::bvector<Alloc>& bv2,
1645  typename bm::bvector<Alloc>::optmode opt_mode);
1646 
1647  /*!
1648  \brief 3-operand XOR : this := bv1 XOR bv2
1649  \param bv1 - Argument vector 1
1650  \param bv2 - Argument vector 2
1651  \param opt_mode - optimization compression
1652  (when it is performed on the fly it is faster than a separate
1653  call to optimize()
1654  @sa optimize, bit_xor
1655  */
1657  const bm::bvector<Alloc>& bv2,
1658  typename bm::bvector<Alloc>::optmode opt_mode);
1659 
1660  /*!
1661  \brief 3-operand AND : this := bv1 AND bv2
1662  \param bv1 - Argument vector 1
1663  \param bv2 - Argument vector 2
1664  \param opt_mode - optimization compression
1665  (when it is performed on the fly it is faster than a separate
1666  call to optimize()
1667  @sa optimize, bit_and
1668  */
1670  const bm::bvector<Alloc>& bv2,
1671  typename bm::bvector<Alloc>::optmode opt_mode);
1672 
1673 
1674  /*!
1675  \brief 3-operand SUB : this := bv1 MINUS bv2
1676  SUBtraction is also known as AND NOT
1677  \param bv1 - Argument vector 1
1678  \param bv2 - Argument vector 2
1679  \param opt_mode - optimization compression
1680  (when it is performed on the fly it is faster than a separate
1681  call to optimize()
1682  @sa optimize, bit_sub
1683  */
1685  const bm::bvector<Alloc>& bv2,
1686  typename bm::bvector<Alloc>::optmode opt_mode);
1687 
1688 
1689  /*!
1690  \brief 2 operand logical OR
1691  \param bv - Argument vector.
1692  */
1694  {
1696  return *this;
1697  }
1698 
1699  /*!
1700  \brief 2 operand logical AND
1701  \param bv - argument vector
1702  \param opt_mode - set an immediate optimization
1703  */
1705  optmode opt_mode = opt_none)
1706  {
1707  combine_operation_and(bv, opt_mode);
1708  return *this;
1709  }
1710 
1711  /*!
1712  \brief 2 operand logical XOR
1713  \param bv - argument vector.
1714  */
1716  {
1718  return *this;
1719  }
1720 
1721  /*!
1722  \brief 2 operand logical SUB(AND NOT). Also known as MINUS.
1723  \param bv - argument vector.
1724  */
1726  {
1728  return *this;
1729  }
1730 
1731  /*!
1732  \brief Invert/NEG all bits
1733  It should be noted, invert is affected by size()
1734  if size is set - it only inverts [0..size-1] bits
1735  */
1737 
1738 
1739  /*! \brief perform a set-algebra operation by operation code
1740  */
1742  bm::operation opcode);
1743 
1744  /*! \brief perform a set-algebra operation OR
1745  */
1747 
1748  /*! \brief perform a set-algebra operation AND
1749  */
1751  optmode opt_mode);
1752 
1753  /*! \brief perform a set-algebra operation MINUS (AND NOT)
1754  */
1756 
1757  /*! \brief perform a set-algebra operation XOR
1758  */
1760 
1761  // @}
1762 
1763  // --------------------------------------------------------------------
1764  /*! @name Iterator-traversal methods */
1765  //@{
1766 
1767  /**
1768  \brief Returns enumerator pointing on the first non-zero bit.
1769  */
1770  enumerator first() const { return get_enumerator(0); }
1771 
1772  /**
1773  \fn bvector::enumerator bvector::end() const
1774  \brief Returns enumerator pointing on the next bit after the last.
1775  */
1776  enumerator end() const
1777  { return typename bvector<Alloc>::enumerator(this); }
1778 
1779  /**
1780  \brief Returns enumerator pointing on specified or the next available bit.
1781  */
1783  { return typename bvector<Alloc>::enumerator(this, pos); }
1784 
1785  //@}
1786 
1787  // --------------------------------------------------------------------
1788  /*! @name Memory management and compression */
1789 
1790  //@{
1791 
1792  /*!
1793  @brief Calculates bitvector statistics.
1794 
1795  @param st - pointer on statistics structure to be filled in.
1796 
1797  Function fills statistics structure containing information about how
1798  this vector uses memory and estimation of max. amount of memory
1799  bvector needs to serialize itself.
1800 
1801  @sa statistics
1802  */
1803  void calc_stat(struct bm::bvector<Alloc>::statistics* st) const BMNOEXCEPT;
1804 
1805  /*!
1806  \brief Sets new blocks allocation strategy.
1807  \param strat - Strategy code 0 - bitblocks allocation only.
1808  1 - Blocks mutation mode (adaptive algorithm)
1809  */
1810  void set_new_blocks_strat(strategy strat) { new_blocks_strat_ = strat; }
1811 
1812  /*!
1813  \brief Returns blocks allocation strategy.
1814  \return - Strategy code 0 - bitblocks allocation only.
1815  1 - Blocks mutation mode (adaptive algorithm)
1816  \sa set_new_blocks_strat
1817  */
1819  { return new_blocks_strat_; }
1820 
1821  /*!
1822  \brief Optimize memory bitvector's memory allocation.
1823 
1824  Function analyze all blocks in the bitvector, compresses blocks
1825  with a regular structure, frees some memory. This function is recommended
1826  after a bulk modification of the bitvector using set_bit, clear_bit or
1827  logical operations.
1828 
1829  Optionally function can calculate vector post optimization statistics
1830 
1831  @sa optmode, optimize_gap_size
1832  */
1833  void optimize(bm::word_t* temp_block = 0,
1834  optmode opt_mode = opt_compress,
1835  statistics* stat = 0);
1836 
1837  /*!
1838  \brief Optimize sizes of GAP blocks
1839 
1840  This method runs an analysis to find optimal GAP levels for the
1841  specific vector. Current GAP compression algorithm uses several fixed
1842  GAP sizes. By default bvector uses some reasonable preset.
1843  */
1844  void optimize_gap_size();
1845 
1846  /*!
1847  @brief Sets new GAP lengths table. All GAP blocks will be reallocated
1848  to match the new scheme.
1849 
1850  @param glevel_len - pointer on C-style array keeping GAP block sizes.
1851  */
1852  void set_gap_levels(const gap_word_t* glevel_len);
1853 
1854  /**
1855  Return true if bvector is initialized at all
1856  @internal
1857  */
1858  bool is_init() const BMNOEXCEPT { return blockman_.is_init(); }
1859 
1860  //@}
1861 
1862  // --------------------------------------------------------------------
1863 
1864  /*! @name Comparison */
1865  //@{
1866 
1867  /*!
1868  \brief Lexicographical comparison with a bitvector.
1869 
1870  Function compares current bitvector with the provided argument
1871  bit by bit and returns -1 if this bitvector less than the argument,
1872  1 - greater, 0 - equal
1873 
1874  @return 0 if this == arg, -1 if this < arg, 1 if this > arg
1875  @sa find_first_mismatch
1876  */
1877  int compare(const bvector<Alloc>& bvect) const BMNOEXCEPT;
1878 
1879  /*!
1880  \brief Equal comparison with an agr bit-vector
1881  @return true if vectors are identical
1882  */
1884  {
1885  size_type pos;
1886  bool found = find_first_mismatch(bvect, pos);
1887  return !found;
1888  }
1889 
1890  /*!
1891  \brief Find index of first bit different between this and the agr vector
1892 
1893  @param bvect - argumnet vector to compare with
1894  @param pos - [out] position of the first difference
1895  @param search_to - search limiter [0..to] to avoid overscan
1896  (default: unlimited to the vectors end)
1897 
1898  @return true if didfference found, false - both vectors are equivalent
1899  @sa compare
1900  */
1902  size_type& pos,
1903  size_type search_to = bm::id_max
1904  ) const BMNOEXCEPT;
1905 
1906  //@}
1907 
1908  // --------------------------------------------------------------------
1909  /*! @name Open internals */
1910  //@{
1911 
1912  /*!
1913  @internal
1914  */
1916  const bm::word_t* arg_blk,
1917  bool arg_gap,
1918  bm::operation opcode);
1919  /**
1920  \brief get access to memory manager (internal)
1921  Use only if you are BitMagic library
1922  @internal
1923  */
1925  { return blockman_; }
1926 
1927  /**
1928  \brief get access to memory manager (internal)
1929  Use only if you are BitMagic library
1930  @internal
1931  */
1933  { return blockman_; }
1934 
1935  //@}
1936 
1937  static void throw_bad_alloc();
1938 
1939 protected:
1940  /**
1941  Syncronize size if it got extended due to bulk import
1942  @internal
1943  */
1944  void sync_size();
1945 
1946  /**
1947  Import integers (set bits).
1948  (Fast, no checks).
1949  @internal
1950  */
1951  void import(const size_type* ids, size_type ids_size,
1952  bm::sort_order sorted_idx);
1953 
1954  void import_block(const size_type* ids,
1955  block_idx_type nblock, size_type start, size_type stop);
1956 
1957 private:
1958 
1959  size_type check_or_next(size_type prev) const BMNOEXCEPT;
1960 
1961  /// set bit in GAP block with GAP block length control
1962  bool gap_block_set(bm::gap_word_t* gap_blk,
1963  bool val, block_idx_type nblock, unsigned nbit);
1964 
1965  /// set bit in GAP block with GAP block length control
1966  void gap_block_set_no_ret(bm::gap_word_t* gap_blk,
1967  bool val, block_idx_type nblock,
1968  unsigned nbit);
1969 
1970  /// check if specified bit is 1, and set it to 0
1971  /// if specified bit is 0, scan for the next 1 and returns it
1972  /// if no 1 found returns 0
1973  size_type check_or_next_extract(size_type prev);
1974 
1975 
1976  /**
1977  \brief AND specified bit without checking preconditions (size, etc)
1978  */
1979  bool and_bit_no_check(size_type n, bool val);
1980 
1981  bool set_bit_conditional_impl(size_type n, bool val, bool condition);
1982 
1983 
1985  bool gap,
1986  bm::word_t* blk,
1987  const bm::word_t* arg_blk,
1988  bool arg_gap,
1989  bm::operation opcode);
1990 
1991  /**
1992  @return true if block optimization may be needed
1993  */
1994  bool combine_operation_block_or(unsigned i,
1995  unsigned j,
1996  const bm::word_t* arg_blk1,
1997  const bm::word_t* arg_blk2);
1998  bool combine_operation_block_xor(unsigned i,
1999  unsigned j,
2000  const bm::word_t* arg_blk1,
2001  const bm::word_t* arg_blk2);
2002  bool combine_operation_block_and(unsigned i,
2003  unsigned j,
2004  const bm::word_t* arg_blk1,
2005  const bm::word_t* arg_blk2);
2006  bool combine_operation_block_sub(unsigned i,
2007  unsigned j,
2008  const bm::word_t* arg_blk1,
2009  const bm::word_t* arg_blk2);
2010 
2011 
2012  void combine_operation_block_or(unsigned i,
2013  unsigned j,
2014  bm::word_t* blk,
2015  const bm::word_t* arg_blk);
2016 
2017  void combine_operation_block_xor(unsigned i,
2018  unsigned j,
2019  bm::word_t* blk,
2020  const bm::word_t* arg_blk);
2021 
2022  void combine_operation_block_and(unsigned i,
2023  unsigned j,
2024  bm::word_t* blk,
2025  const bm::word_t* arg_blk);
2026 
2027  void combine_operation_block_sub(unsigned i,
2028  unsigned j,
2029  bm::word_t* blk,
2030  const bm::word_t* arg_blk);
2031 
2032  void copy_range_no_check(const bvector<Alloc>& bvect,
2033  size_type left,
2034  size_type right);
2035 
2036 private:
2037 
2038  /**
2039  \brief Set range without validity/bounds checking
2040  */
2041  void set_range_no_check(size_type left,
2042  size_type right);
2043  /**
2044  \brief Clear range without validity/bounds checking
2045  */
2046  void clear_range_no_check(size_type left,
2047  size_type right);
2048 
2049  /**
2050  \brief Clear outside the range without validity/bounds checking
2051  */
2052  void keep_range_no_check(size_type left,
2053  size_type right);
2054 
2055  /**
2056  Compute rank in block using rank-select index
2057  */
2058  static
2059  size_type block_count_to(const bm::word_t* block,
2060  block_idx_type nb,
2061  unsigned nbit_right,
2062  const rs_index_type& blocks_cnt) BMNOEXCEPT;
2063  /**
2064  Return value of first bit in the block
2065  */
2066  bool test_first_block_bit(block_idx_type nb) const BMNOEXCEPT;
2067 
2068 private:
2069  blocks_manager_type blockman_; //!< bitblocks manager
2070  strategy new_blocks_strat_; //!< block allocation strategy
2071  size_type size_; //!< size in bits
2072 };
2073 
2074 
2075 //---------------------------------------------------------------------
2076 
2077 template<class Alloc>
2079  const bvector<Alloc>& bv2)
2080 {
2081  bvector<Alloc> ret;
2082  ret.bit_and(bv1, bv2, bvector<Alloc>::opt_none);
2083  return ret;
2084 }
2085 
2086 //---------------------------------------------------------------------
2087 
2088 template<class Alloc>
2090  const bvector<Alloc>& bv2)
2091 {
2092  bvector<Alloc> ret;
2093  ret.bit_or(bv1, bv2, bvector<Alloc>::opt_none);
2094  return ret;
2095 }
2096 
2097 //---------------------------------------------------------------------
2098 
2099 template<class Alloc>
2101  const bvector<Alloc>& bv2)
2102 {
2103  bvector<Alloc> ret;
2104  ret.bit_xor(bv1, bv2, bvector<Alloc>::opt_none);
2105  return ret;
2106 }
2107 
2108 //---------------------------------------------------------------------
2109 
2110 template<class Alloc>
2112  const bvector<Alloc>& bv2)
2113 {
2114  bvector<Alloc> ret;
2115  ret.bit_sub(bv1, bv2, bvector<Alloc>::opt_none);
2116  return ret;
2117 }
2118 
2119 
2120 // -----------------------------------------------------------------------
2121 
2122 template<typename Alloc>
2124 {
2125  if (!blockman_.is_init())
2126  blockman_.init_tree();
2127 }
2128 
2129 // -----------------------------------------------------------------------
2130 
2131 template<typename Alloc>
2133 {
2134  if (this != &bvect)
2135  {
2136  blockman_.move_from(bvect.blockman_);
2137  size_ = bvect.size_;
2138  new_blocks_strat_ = bvect.new_blocks_strat_;
2139  }
2140 }
2141 
2142 //---------------------------------------------------------------------
2143 
2144 template<class Alloc>
2146 {
2147  if (!blockman_.is_init())
2148  return; // nothing to do
2149 
2150  if (right < left)
2151  bm::xor_swap(left, right);
2152 
2153  keep_range_no_check(left, right);
2154 }
2155 // -----------------------------------------------------------------------
2156 
2157 template<typename Alloc>
2159  size_type right,
2160  bool value)
2161 {
2162  if (!blockman_.is_init())
2163  {
2164  if (!value)
2165  return *this; // nothing to do
2166  }
2167 
2168  if (right < left)
2169  {
2170  return set_range(right, left, value);
2171  }
2172 
2173  BM_ASSERT_THROW(right < bm::id_max, BM_ERR_RANGE);
2174  if (right >= size_) // this vect shorter than the arg.
2175  {
2176  size_type new_size = (right == bm::id_max) ? bm::id_max : right + 1;
2177  resize(new_size);
2178  }
2179 
2180  BM_ASSERT(left <= right);
2181  BM_ASSERT(left < size_);
2182 
2183  if (value)
2184  set_range_no_check(left, right);
2185  else
2186  clear_range_no_check(left, right);
2187 
2188  return *this;
2189 }
2190 
2191 // -----------------------------------------------------------------------
2192 
2193 template<typename Alloc>
2195 {
2196  if (!blockman_.is_init())
2197  return 0;
2198 
2199  word_t*** blk_root = blockman_.top_blocks_root();
2200  BM_ASSERT(blk_root);
2201 
2202  size_type cnt = 0;
2203  unsigned top_blocks = blockman_.top_block_size();
2204  for (unsigned i = 0; i < top_blocks; ++i)
2205  {
2206  bm::word_t** blk_blk = blk_root[i];
2207  if (!blk_blk)
2208  {
2209  ++i;
2210  bool found = bm::find_not_null_ptr(blk_root, i, top_blocks, &i);
2211  if (!found)
2212  break;
2213  blk_blk = blk_root[i];
2214  BM_ASSERT(blk_blk);
2215  if (!blk_blk)
2216  break;
2217  }
2218  if ((bm::word_t*)blk_blk == FULL_BLOCK_FAKE_ADDR)
2219  {
2221  continue;
2222  }
2223  unsigned j = 0;
2224  do
2225  {
2226  if (blk_blk[j])
2227  cnt += blockman_.block_bitcount(blk_blk[j]);
2228  if (blk_blk[j+1])
2229  cnt += blockman_.block_bitcount(blk_blk[j+1]);
2230  if (blk_blk[j+2])
2231  cnt += blockman_.block_bitcount(blk_blk[j+2]);
2232  if (blk_blk[j+3])
2233  cnt += blockman_.block_bitcount(blk_blk[j+3]);
2234  j += 4;
2235  } while (j < bm::set_sub_array_size);
2236 
2237  } // for i
2238  return cnt;
2239 }
2240 
2241 // -----------------------------------------------------------------------
2242 
2243 template<typename Alloc>
2245 {
2246  word_t*** blk_root = blockman_.top_blocks_root();
2247  if (!blk_root)
2248  return false;
2249  typename blocks_manager_type::block_any_func func(blockman_);
2250  return for_each_nzblock_if(blk_root, blockman_.top_block_size(), func);
2251 }
2252 
2253 // -----------------------------------------------------------------------
2254 
2255 template<typename Alloc>
2257 {
2258  if (size_ == new_size) return; // nothing to do
2259  if (size_ < new_size) // size grows
2260  {
2261  if (!blockman_.is_init())
2262  blockman_.init_tree();
2263 
2264  blockman_.reserve(new_size);
2265  size_ = new_size;
2266  }
2267  else // shrink
2268  {
2269  set_range(new_size, size_ - 1, false); // clear the tail
2270  size_ = new_size;
2271  }
2272 }
2273 
2274 // -----------------------------------------------------------------------
2275 
2276 template<typename Alloc>
2278 {
2279  if (size_ >= bm::id_max)
2280  return;
2282  bool found = find_reverse(last);
2283  if (found && last >= size_)
2284  resize(last+1);
2285 }
2286 
2287 // -----------------------------------------------------------------------
2288 
2289 template<typename Alloc>
2291  bvector<Alloc>* bv_blocks) const
2292 {
2293  BM_ASSERT(rs_idx);
2294  if (bv_blocks)
2295  {
2296  bv_blocks->clear();
2297  bv_blocks->init();
2298  }
2299 
2300  unsigned bcount[bm::set_sub_array_size];
2301  unsigned sub_count[bm::set_sub_array_size];
2302 
2303  rs_idx->init();
2304  if (!blockman_.is_init())
2305  return;
2306 
2307  // resize the RS index to fit the vector
2308  //
2309  size_type last_bit;
2310  bool found = find_reverse(last_bit);
2311  if (!found)
2312  return;
2313  block_idx_type nb = (last_bit >> bm::set_block_shift);
2314  unsigned i0, j0;
2315  bm::get_block_coord(nb, i0, j0);
2316 
2317  unsigned real_top_blocks = blockman_.find_real_top_blocks();
2318  unsigned max_top_blocks = blockman_.find_max_top_blocks();
2319  if (nb < (max_top_blocks * bm::set_sub_array_size))
2320  nb = (max_top_blocks * bm::set_sub_array_size);
2321  rs_idx->set_total(nb + 1);
2322  rs_idx->resize(nb + 1);
2323  rs_idx->resize_effective_super_blocks(real_top_blocks);
2324 
2325  // index construction
2326  //
2327  BM_ASSERT(max_top_blocks <= blockman_.top_block_size());
2328  bm::word_t*** blk_root = blockman_.top_blocks_root();
2329  for (unsigned i = 0; i < max_top_blocks; ++i)
2330  {
2331  bm::word_t** blk_blk = blk_root[i];
2332  if (!blk_blk)
2333  {
2334  rs_idx->set_null_super_block(i);
2335  continue;
2336  }
2337  if ((bm::word_t*)blk_blk == FULL_BLOCK_FAKE_ADDR)
2338  {
2339  rs_idx->set_full_super_block(i);
2340  if (bv_blocks)
2341  {
2342  size_type nb_from = i * bm::set_sub_array_size;
2343  size_type nb_to = nb_from + bm::set_sub_array_size - 1;
2344  bv_blocks->set_range_no_check(nb_from, nb_to);
2345  }
2346  continue;
2347  }
2348 
2349  unsigned j = 0;
2350  do
2351  {
2352  const bm::word_t* block = blk_blk[j];
2353  if (!block)
2354  {
2355  bcount[j] = sub_count[j] = 0;
2356  continue;
2357  }
2358 
2359  unsigned cnt = blockman_.block_bitcount(block);
2360  bcount[j] = cnt;
2361  if (bv_blocks && cnt)
2362  {
2363  bv_blocks->set(i * bm::set_sub_array_size + j);
2364  }
2365 
2366  // TODO: optimize sub-index compute
2367  unsigned local_first, local_second;
2368  if (BM_IS_GAP(block))
2369  {
2370  const bm::gap_word_t* const gap_block = BMGAP_PTR(block);
2371  local_first =
2373  local_second =
2374  bm::gap_bit_count_range(gap_block,
2376  bm::rs3_border1);
2377  }
2378  else
2379  {
2380  block = BLOCK_ADDR_SAN(block); // TODO: optimize FULL
2381 
2382  local_first =
2384  local_second =
2386  bm::rs3_border0+1,
2387  bm::rs3_border1);
2388  }
2389  BM_ASSERT(cnt >= local_first + local_second);
2390  sub_count[j] = local_first | (local_second << 16);
2391 
2392  } while (++j < bm::set_sub_array_size);
2393 
2394  rs_idx->register_super_block(i, &bcount[0], &sub_count[0]);
2395 
2396  } // for i
2397 
2398 }
2399 
2400 
2401 // -----------------------------------------------------------------------
2402 
2403 template<typename Alloc>
2406 {
2407  bm::word_t*** blk_root = blockman_.top_blocks_root();
2408  if (blk_root == 0)
2409  return 0;
2410  typename blocks_manager_type::block_count_arr_func func(blockman_, &(arr[0]));
2411  bm::for_each_nzblock(blk_root, blockman_.top_block_size(), func);
2412  return func.last_block();
2413 }
2414 
2415 // -----------------------------------------------------------------------
2416 
2417 template<typename Alloc>
2420  block_idx_type nb,
2421  unsigned nbit_right,
2422  const rs_index_type& rs_idx) BMNOEXCEPT
2423 {
2424  size_type c;
2425  unsigned sub_range = rs_idx.find_sub_range(nbit_right);
2426 
2427  unsigned sub_cnt = rs_idx.sub_count(nb);
2428  unsigned first = sub_cnt & 0xFFFF;
2429  unsigned second = sub_cnt >> 16;
2430 
2433 
2434  // evaluate 3 sub-block intervals
2435  // |--------[0]-----------[1]----------|
2436 
2437  switch(sub_range) // sub-range rank calc
2438  {
2439  case 0:
2440  // |--x-----[0]-----------[1]----------|
2441  if (nbit_right <= rs3_border0/2)
2442  {
2443  c = bm::bit_block_calc_count_to(block, nbit_right);
2444  }
2445  else
2446  {
2447  // |--------[x]-----------[1]----------|
2448  if (nbit_right == rs3_border0)
2449  {
2450  c = first;
2451  }
2452  else
2453  {
2454  // |------x-[0]-----------[1]----------|
2456  nbit_right+1,
2457  rs3_border0);
2458  c = first - c;
2459  }
2460  }
2461  break;
2462  case 1:
2463  // |--------[0]-x---------[1]----------|
2464  if (nbit_right <= (rs3_border0 + rs3_half_span))
2465  {
2467  rs3_border0 + 1,
2468  nbit_right);
2469  c += first;
2470  }
2471  else
2472  {
2473  unsigned bc_second_range = first + second;
2474  // |--------[0]-----------[x]----------|
2475  if (nbit_right == rs3_border1)
2476  {
2477  c = bc_second_range;
2478  }
2479  else
2480  {
2481  // |--------[0]--------x--[1]----------|
2483  nbit_right+1,
2484  rs3_border1);
2485  c = bc_second_range - c;
2486  }
2487  }
2488  break;
2489  case 2:
2490  {
2491  unsigned bc_second_range = first + second;
2492 
2493  // |--------[0]-----------[1]-x--------|
2494  if (nbit_right <= (rs3_border1 + rs3_half_span))
2495  {
2497  rs3_border1 + 1,
2498  nbit_right);
2499  c += bc_second_range;
2500  }
2501  else
2502  {
2503  // |--------[0]-----------[1]----------x
2504  if (nbit_right == bm::gap_max_bits-1)
2505  {
2506  c = rs_idx.count(nb);
2507  }
2508  else
2509  {
2510  // |--------[0]-----------[1]-------x--|
2512  nbit_right+1,
2513  bm::gap_max_bits-1);
2514  size_type cnt = rs_idx.count(nb);
2515  c = cnt - c;
2516  }
2517  }
2518  }
2519  break;
2520  default:
2521  BM_ASSERT(0);
2522  c = 0;
2523  } // switch
2524 
2525  BM_ASSERT(c == bm::bit_block_calc_count_to(block, nbit_right));
2526  return c;
2527 }
2528 
2529 // -----------------------------------------------------------------------
2530 
2531 template<typename Alloc>
2532 typename bvector<Alloc>::size_type
2534  const rs_index_type& rs_idx) const BMNOEXCEPT
2535 {
2536  BM_ASSERT(right < bm::id_max);
2537  if (!blockman_.is_init())
2538  return 0;
2539 
2540  unsigned nblock_right = unsigned(right >> bm::set_block_shift);
2541  unsigned nbit_right = unsigned(right & bm::set_block_mask);
2542 
2543  // running count of all blocks before target
2544  //
2545  size_type cnt;
2546  if (nblock_right >= rs_idx.get_total())
2547  {
2548  cnt = rs_idx.count();
2549  return cnt;
2550  }
2551  cnt = nblock_right ? rs_idx.rcount(nblock_right-1) : 0;
2552 
2553  unsigned i, j;
2554  bm::get_block_coord(nblock_right, i, j);
2555  const bm::word_t* block = blockman_.get_block_ptr(i, j);
2556 
2557  if (!block)
2558  return cnt;
2559 
2560  bool gap = BM_IS_GAP(block);
2561  if (gap)
2562  {
2563  unsigned c = bm::gap_bit_count_to(BMGAP_PTR(block), (gap_word_t)nbit_right);
2564  BM_ASSERT(c == bm::gap_bit_count_range(BMGAP_PTR(block), (gap_word_t)0, (gap_word_t)nbit_right));
2565  cnt += c;
2566  }
2567  else
2568  {
2569  if (block == FULL_BLOCK_FAKE_ADDR) // TODO: misses REAL full sometimes
2570  {
2571  cnt += nbit_right + 1;
2572  }
2573  else // real bit-block
2574  {
2575  size_type c =
2576  this->block_count_to(block, nblock_right, nbit_right, rs_idx);
2577  cnt += c;
2578  }
2579  }
2580  return cnt;
2581 }
2582 
2583 // -----------------------------------------------------------------------
2584 
2585 template<typename Alloc>
2586 typename bvector<Alloc>::size_type
2588  const rs_index_type& rs_idx) const BMNOEXCEPT
2589 {
2590  BM_ASSERT(right < bm::id_max);
2591  if (!blockman_.is_init())
2592  return 0;
2593 
2594  unsigned nblock_right = unsigned(right >> bm::set_block_shift);
2595  unsigned nbit_right = unsigned(right & bm::set_block_mask);
2596 
2597  unsigned i, j;
2598  bm::get_block_coord(nblock_right, i, j);
2599  const bm::word_t* block = blockman_.get_block_ptr(i, j);
2600 
2601  size_type cnt = 0;
2602  if (!block)
2603  return cnt;
2604 
2605  bool gap = BM_IS_GAP(block);
2606  if (gap)
2607  {
2608  bm::gap_word_t *gap_blk = BMGAP_PTR(block);
2609  if (bm::gap_test_unr(gap_blk, (gap_word_t)nbit_right))
2610  cnt = bm::gap_bit_count_to(gap_blk, (gap_word_t)nbit_right);
2611  else
2612  return cnt;
2613  }
2614  else
2615  {
2616  if (block == FULL_BLOCK_FAKE_ADDR)
2617  {
2618  cnt = nbit_right + 1;
2619  }
2620  else
2621  {
2622  unsigned nword = nbit_right >> bm::set_word_shift;
2623  unsigned w = block[nword];
2624  w &= (1u << (nbit_right & bm::set_word_mask));
2625  if (w)
2626  {
2627  cnt = block_count_to(block, nblock_right, nbit_right, rs_idx);
2628  BM_ASSERT(cnt == bm::bit_block_calc_count_to(block, nbit_right));
2629  }
2630  else
2631  {
2632  return cnt;
2633  }
2634  }
2635  }
2636  cnt += nblock_right ? rs_idx.rcount(nblock_right - 1) : 0;
2637  return cnt;
2638 }
2639 
2640 // -----------------------------------------------------------------------
2641 
2642 template<typename Alloc>
2645  const rs_index_type& rs_idx) const BMNOEXCEPT
2646 {
2647  BM_ASSERT(right < bm::id_max);
2648  if (!blockman_.is_init())
2649  return 0;
2650 
2651  unsigned nblock_right = unsigned(right >> bm::set_block_shift);
2652  unsigned nbit_right = unsigned(right & bm::set_block_mask);
2653 
2654  size_type cnt = nblock_right ? rs_idx.rcount(nblock_right - 1) : 0;
2655 
2656  unsigned i, j;
2657  bm::get_block_coord(nblock_right, i, j);
2658  const bm::word_t* block = blockman_.get_block_ptr(i, j);
2659 
2660  if (!block)
2661  return cnt;
2662 
2663  bool gap = BM_IS_GAP(block);
2664  if (gap)
2665  {
2666  cnt += bm::gap_bit_count_to(BMGAP_PTR(block), (gap_word_t)nbit_right,
2667  true /* rank corrected */);
2668  }
2669  else
2670  {
2671  if (block == FULL_BLOCK_FAKE_ADDR)
2672  cnt += nbit_right;
2673  else
2674  {
2675  cnt += block_count_to(block, nblock_right, nbit_right, rs_idx);
2676  unsigned w = block[nbit_right >> bm::set_word_shift] &
2677  (1u << (nbit_right & bm::set_word_mask));
2678  cnt -= bool(w); // rank correction
2679  }
2680  }
2681  return cnt;
2682 }
2683 
2684 
2685 // -----------------------------------------------------------------------
2686 
2687 template<typename Alloc>
2690 {
2691  BM_ASSERT(left < bm::id_max && right < bm::id_max);
2692  if (left > right)
2693  bm::xor_swap(left, right);
2694  if (right == bm::id_max)
2695  --right;
2696 
2697  if (!blockman_.is_init())
2698  return 0;
2699 
2700  size_type cnt = 0;
2701 
2702  // calculate logical number of start and destination blocks
2703  block_idx_type nblock_left = (left >> bm::set_block_shift);
2704  block_idx_type nblock_right = (right >> bm::set_block_shift);
2705 
2706  unsigned i0, j0;
2707  bm::get_block_coord(nblock_left, i0, j0);
2708  const bm::word_t* block = blockman_.get_block(i0, j0);
2709 
2710  bool left_gap = BM_IS_GAP(block);
2711 
2712  unsigned nbit_left = unsigned(left & bm::set_block_mask);
2713  unsigned nbit_right = unsigned(right & bm::set_block_mask);
2714 
2715  unsigned r =
2716  (nblock_left == nblock_right) ? nbit_right : (bm::bits_in_block-1);
2717 
2718  typename blocks_manager_type::block_count_func func(blockman_);
2719 
2720  if (block)
2721  {
2722  if ((nbit_left == 0) && (r == (bm::bits_in_block-1))) // whole block
2723  {
2724  func(block);
2725  }
2726  else
2727  {
2728  if (left_gap)
2729  {
2730  cnt += bm::gap_bit_count_range(BMGAP_PTR(block),
2731  (gap_word_t)nbit_left,
2732  (gap_word_t)r);
2733  }
2734  else
2735  {
2736  cnt += bm::bit_block_calc_count_range(block, nbit_left, r);
2737  }
2738  }
2739  }
2740 
2741  cnt += func.count();
2742  if (nblock_left == nblock_right) // in one block
2743  {
2744  return cnt;
2745  }
2746 
2747  // process all full mid-blocks
2748  {
2749  func.reset();
2750  word_t*** blk_root = blockman_.top_blocks_root();
2751  block_idx_type top_blocks_size = blockman_.top_block_size();
2752 
2753  bm::for_each_nzblock_range(blk_root, top_blocks_size,
2754  nblock_left+1, nblock_right-1, func);
2755  cnt += func.count();
2756  }
2757 
2758  bm::get_block_coord(nblock_right, i0, j0);
2759  block = blockman_.get_block(i0, j0);
2760  bool right_gap = BM_IS_GAP(block);
2761 
2762  if (block)
2763  {
2764  if (right_gap)
2765  {
2766  cnt += bm::gap_bit_count_range(BMGAP_PTR(block),
2767  (gap_word_t)0,
2768  (gap_word_t)nbit_right);
2769  }
2770  else
2771  {
2772  cnt += bm::bit_block_calc_count_range(block, 0, nbit_right);
2773  }
2774  }
2775  return cnt;
2776 }
2777 
2778 // -----------------------------------------------------------------------
2779 
2780 template<typename Alloc>
2782  size_type right) const BMNOEXCEPT
2783 {
2784  if (!blockman_.is_init())
2785  return false; // nothing to do
2786 
2787  if (right < left)
2788  bm::xor_swap(left, right);
2789  if (right == bm::id_max)
2790  --right;
2791  if (left == right)
2792  return test(left);
2793 
2794  BM_ASSERT(left < bm::id_max && right < bm::id_max);
2795 
2796  block_idx_type nblock_left = (left >> bm::set_block_shift);
2797  block_idx_type nblock_right = (right >> bm::set_block_shift);
2798 
2799  unsigned i0, j0;
2800  bm::get_block_coord(nblock_left, i0, j0);
2801  const bm::word_t* block = blockman_.get_block(i0, j0);
2802 
2803  if (nblock_left == nblock_right) // hit in the same block
2804  {
2805  unsigned nbit_left = unsigned(left & bm::set_block_mask);
2806  unsigned nbit_right = unsigned(right & bm::set_block_mask);
2807  return bm::block_is_all_one_range(block, nbit_left, nbit_right);
2808  }
2809 
2810  // process entry point block
2811  {
2812  unsigned nbit_left = unsigned(left & bm::set_block_mask);
2813  bool all_one = bm::block_is_all_one_range(block,
2814  nbit_left, (bm::gap_max_bits-1));
2815  if (!all_one)
2816  return all_one;
2817  ++nblock_left;
2818  }
2819 
2820  // process tail block
2821  {
2822  bm::get_block_coord(nblock_right, i0, j0);
2823  block = blockman_.get_block(i0, j0);
2824  unsigned nbit_right = unsigned(right & bm::set_block_mask);
2825  bool all_one = bm::block_is_all_one_range(block, 0, nbit_right);
2826  if (!all_one)
2827  return all_one;
2828  --nblock_right;
2829  }
2830 
2831  // check all blocks in the middle
2832  //
2833  if (nblock_left <= nblock_right)
2834  {
2835  unsigned i_from, j_from, i_to, j_to;
2836  bm::get_block_coord(nblock_left, i_from, j_from);
2837  bm::get_block_coord(nblock_right, i_to, j_to);
2838 
2839  bm::word_t*** blk_root = blockman_.top_blocks_root();
2840 
2841  for (unsigned i = i_from; i <= i_to; ++i)
2842  {
2843  bm::word_t** blk_blk = blk_root[i];
2844  if (!blk_blk)
2845  return false;
2846  if ((bm::word_t*)blk_blk == FULL_BLOCK_FAKE_ADDR)
2847  continue;
2848 
2849  unsigned j = (i == i_from) ? j_from : 0;
2850  unsigned j_limit = (i == i_to) ? j_to+1 : bm::set_sub_array_size;
2851  do
2852  {
2853  bool all_one = bm::check_block_one(blk_blk[j], true);
2854  if (!all_one)
2855  return all_one;
2856  } while (++j < j_limit);
2857  } // for i
2858  }
2859  return true;
2860 }
2861 
2862 // -----------------------------------------------------------------------
2863 
2864 template<typename Alloc>
2866 {
2867  BM_ASSERT(left < bm::id_max && right < bm::id_max);
2868 
2869  if (!blockman_.is_init())
2870  return false; // nothing to do
2871 
2872  if (right < left)
2873  bm::xor_swap(left, right);
2874  if (right == bm::id_max)
2875  --right;
2876  if (left == right)
2877  return test(left);
2878 
2879  block_idx_type nblock_left = (left >> bm::set_block_shift);
2880  block_idx_type nblock_right = (right >> bm::set_block_shift);
2881 
2882  unsigned i0, j0;
2883  bm::get_block_coord(nblock_left, i0, j0);
2884  const bm::word_t* block = blockman_.get_block(i0, j0);
2885 
2886  if (nblock_left == nblock_right) // hit in the same block
2887  {
2888  unsigned nbit_left = unsigned(left & bm::set_block_mask);
2889  unsigned nbit_right = unsigned(right & bm::set_block_mask);
2890  return bm::block_any_range(block, nbit_left, nbit_right);
2891  }
2892 
2893  // process entry point block
2894  {
2895  unsigned nbit_left = unsigned(left & bm::set_block_mask);
2896  bool any_one = bm::block_any_range(block,
2897  nbit_left, (bm::gap_max_bits-1));
2898  if (any_one)
2899  return any_one;
2900  ++nblock_left;
2901  }
2902 
2903  // process tail block
2904  {
2905  bm::get_block_coord(nblock_right, i0, j0);
2906  block = blockman_.get_block(i0, j0);
2907  unsigned nbit_right = unsigned(right & bm::set_block_mask);
2908  bool any_one = bm::block_any_range(block, 0, nbit_right);
2909  if (any_one)
2910  return any_one;
2911  --nblock_right;
2912  }
2913 
2914  // check all blocks in the middle
2915  //
2916  if (nblock_left <= nblock_right)
2917  {
2918  unsigned i_from, j_from, i_to, j_to;
2919  bm::get_block_coord(nblock_left, i_from, j_from);
2920  bm::get_block_coord(nblock_right, i_to, j_to);
2921 
2922  bm::word_t*** blk_root = blockman_.top_blocks_root();
2923  {
2924  block_idx_type top_size = blockman_.top_block_size();
2925  if (i_from >= top_size)
2926  return false;
2927  if (i_to >= top_size)
2928  {
2929  i_to = unsigned(top_size-1);
2930  j_to = bm::set_sub_array_size-1;
2931  }
2932  }
2933 
2934  for (unsigned i = i_from; i <= i_to; ++i)
2935  {
2936  bm::word_t** blk_blk = blk_root[i];
2937  if (!blk_blk)
2938  continue;
2939  if ((bm::word_t*)blk_blk == FULL_BLOCK_FAKE_ADDR)
2940  return true;
2941 
2942  unsigned j = (i == i_from) ? j_from : 0;
2943  unsigned j_limit = (i == i_to) ? j_to+1 : bm::set_sub_array_size;
2944  do
2945  {
2946  bool any_one = bm::block_any(blk_blk[j]);
2947  if (any_one)
2948  return any_one;
2949  } while (++j < j_limit);
2950  } // for i
2951  }
2952  return false;
2953 }
2954 
2955 // -----------------------------------------------------------------------
2956 
2957 template<typename Alloc>
2960  size_type right,
2961  const rs_index_type& rs_idx) const BMNOEXCEPT
2962 {
2963  BM_ASSERT(left <= right);
2964 
2965  if (left > right)
2966  bm::xor_swap(left, right);
2967 
2968  BM_ASSERT_THROW(right < bm::id_max, BM_ERR_RANGE);
2969 
2970  if (left == right)
2971  return this->test(left);
2972 
2973  size_type cnt_l, cnt_r;
2974  if (left)
2975  cnt_l = this->count_to(left-1, rs_idx);
2976  else
2977  cnt_l = left; // == 0
2978 
2979  cnt_r = this->count_to(right, rs_idx);
2980 
2981  return cnt_r - cnt_l;
2982 }
2983 
2984 // -----------------------------------------------------------------------
2985 
2986 template<typename Alloc>
2988 {
2989  if (!size_)
2990  return *this; // cannot invert a set of power 0
2991 
2992  unsigned top_blocks = blockman_.reserve_top_blocks(bm::set_top_array_size);
2993  bm::word_t*** blk_root = blockman_.top_blocks_root();
2994  for (unsigned i = 0; i < top_blocks; ++i)
2995  {
2996  bm::word_t** blk_blk = blk_root[i];
2997  if (!blk_blk)
2998  {
2999  blk_root[i] = (bm::word_t**)FULL_BLOCK_FAKE_ADDR;
3000  continue;
3001  }
3002  if (blk_blk == (bm::word_t**)FULL_BLOCK_FAKE_ADDR)
3003  {
3004  blk_root[i] = 0;
3005  continue;
3006  }
3007  unsigned j = 0; bm::word_t* blk;
3008  do
3009  {
3010  blk = blk_blk[j];
3011  if (!blk)
3012  blockman_.set_block_ptr(i, j, FULL_BLOCK_FAKE_ADDR);
3013  else
3014  if (IS_FULL_BLOCK(blk))
3015  blockman_.set_block_ptr(i, j, 0);
3016  else
3017  {
3018  if (BM_IS_GAP(blk))
3019  bm::gap_invert(BMGAP_PTR(blk));
3020  else
3021  bm::bit_invert((wordop_t*)blk);
3022  }
3023  } while (++j < bm::set_sub_array_size);
3024  } // for i
3025 
3026  if (size_ == bm::id_max)
3027  set_bit_no_check(bm::id_max, false);
3028  else
3029  clear_range_no_check(size_, bm::id_max);
3030 
3031  return *this;
3032 }
3033 
3034 // -----------------------------------------------------------------------
3035 
3036 template<typename Alloc>
3038 {
3039  BM_ASSERT(n < size_);
3040  BM_ASSERT_THROW((n < size_), BM_ERR_RANGE);
3041 
3042  // calculate logical block number
3043  unsigned nb = unsigned(n >> bm::set_block_shift);
3044  unsigned i, j;
3045  bm::get_block_coord(nb, i, j);
3046  const bm::word_t* block = blockman_.get_block_ptr(i, j); // get unsanitized block ptr
3047 
3048  if (block)
3049  {
3050  // calculate word number in block and bit
3051  unsigned nbit = unsigned(n & bm::set_block_mask);
3052  if (BM_IS_GAP(block))
3053  {
3054  return gap_test_unr(BMGAP_PTR(block), nbit);
3055  }
3056  else
3057  {
3058  if (block == FULL_BLOCK_FAKE_ADDR)
3059  return true;
3060  unsigned nword = unsigned(nbit >> bm::set_word_shift);
3061  unsigned w = block[nword];
3062  return w & (1u << (nbit & bm::set_word_mask));
3063  }
3064  }
3065  return false;
3066 }
3067 
3068 // -----------------------------------------------------------------------
3069 
3070 template<typename Alloc>
3072  optmode opt_mode,
3073  statistics* stat)
3074 {
3075  if (!blockman_.is_init())
3076  {
3077  if (stat)
3078  calc_stat(stat);
3079  return;
3080  }
3081  if (!temp_block)
3082  temp_block = blockman_.check_allocate_tempblock();
3083 
3084  if (stat)
3085  {
3086  stat->reset();
3087  ::memcpy(stat->gap_levels,
3088  blockman_.glen(), sizeof(gap_word_t) * bm::gap_levels);
3089  stat->max_serialize_mem = (unsigned)sizeof(bm::id_t) * 4;
3090  }
3091 
3092  blockman_.optimize_tree(temp_block, opt_mode, stat);
3093 
3094  if (stat)
3095  {
3096  size_t safe_inc = stat->max_serialize_mem / 10; // 10% increment
3097  if (!safe_inc) safe_inc = 256;
3098  stat->max_serialize_mem += safe_inc;
3099 
3100  stat->memory_used += (unsigned)(sizeof(*this) - sizeof(blockman_));
3101 
3102  unsigned top_size = blockman_.top_block_size();
3103  size_t blocks_mem = sizeof(blockman_);
3104  blocks_mem += sizeof(bm::word_t**) * top_size;
3105  blocks_mem += stat->ptr_sub_blocks * (sizeof(void*) * bm::set_sub_array_size);
3106  stat->memory_used += blocks_mem;
3107  stat->bv_count = 1;
3108  }
3109 
3110  // don't need to keep temp block if we optimizing memory usage
3111  blockman_.free_temp_block();
3112 }
3113 
3114 // -----------------------------------------------------------------------
3115 
3116 template<typename Alloc>
3118 {
3119 #if 0
3120  if (!blockman_.is_init())
3121  return;
3122 
3123  struct bvector<Alloc>::statistics st;
3124  calc_stat(&st);
3125 
3126  if (!st.gap_blocks)
3127  return;
3128 
3129  gap_word_t opt_glen[bm::gap_levels];
3130  ::memcpy(opt_glen, st.gap_levels, bm::gap_levels * sizeof(*opt_glen));
3131 
3132  improve_gap_levels(st.gap_length,
3133  st.gap_length + st.gap_blocks,
3134  opt_glen);
3135 
3136  set_gap_levels(opt_glen);
3137 #endif
3138 }
3139 
3140 // -----------------------------------------------------------------------
3141 
3142 template<typename Alloc>
3143 void bvector<Alloc>::set_gap_levels(const gap_word_t* glevel_len)
3144 {
3145  if (blockman_.is_init())
3146  {
3147  word_t*** blk_root = blockman_.top_blocks_root();
3148  typename
3149  blocks_manager_type::gap_level_func gl_func(blockman_, glevel_len);
3150  for_each_nzblock(blk_root, blockman_.top_block_size(),gl_func);
3151  }
3152 
3153  blockman_.set_glen(glevel_len);
3154 }
3155 
3156 // -----------------------------------------------------------------------
3157 
3158 template<typename Alloc>
3160 {
3161  int res;
3162  unsigned top_blocks = blockman_.top_block_size();
3163  unsigned bvect_top_blocks = bv.blockman_.top_block_size();
3164 
3165  if (bvect_top_blocks > top_blocks) top_blocks = bvect_top_blocks;
3166 
3167  for (unsigned i = 0; i < top_blocks; ++i)
3168  {
3169  const bm::word_t* const* blk_blk = blockman_.get_topblock(i);
3170  const bm::word_t* const* arg_blk_blk = bv.blockman_.get_topblock(i);
3171 
3172  if (blk_blk == arg_blk_blk)
3173  continue;
3174 
3175  for (unsigned j = 0; j < bm::set_sub_array_size; ++j)
3176  {
3177  const bm::word_t* arg_blk; const bm::word_t* blk;
3178  if ((bm::word_t*)arg_blk_blk == FULL_BLOCK_FAKE_ADDR)
3179  arg_blk = FULL_BLOCK_REAL_ADDR;
3180  else
3181  {
3182  arg_blk = arg_blk_blk ? arg_blk_blk[j] : 0;
3183  if (arg_blk == FULL_BLOCK_FAKE_ADDR)
3184  arg_blk = FULL_BLOCK_REAL_ADDR;
3185  }
3186  if ((bm::word_t*)blk_blk == FULL_BLOCK_FAKE_ADDR)
3187  blk = FULL_BLOCK_REAL_ADDR;
3188  else
3189  {
3190  blk = blk_blk ? blk_blk[j] : 0;
3191  if (blk == FULL_BLOCK_FAKE_ADDR)
3192  blk = FULL_BLOCK_REAL_ADDR;
3193  }
3194  if (blk == arg_blk) continue;
3195 
3196  // If one block is zero we check if the other one has at least
3197  // one bit ON
3198 
3199  if (!blk || !arg_blk)
3200  {
3201  const bm::word_t* pblk; bool is_gap;
3202 
3203  if (blk)
3204  {
3205  pblk = blk;
3206  res = 1;
3207  is_gap = BM_IS_GAP(blk);
3208  }
3209  else
3210  {
3211  pblk = arg_blk;
3212  res = -1;
3213  is_gap = BM_IS_GAP(arg_blk);
3214  }
3215 
3216  if (is_gap)
3217  {
3218  if (!bm::gap_is_all_zero(BMGAP_PTR(pblk)))
3219  return res;
3220  }
3221  else
3222  {
3223  if (!bm::bit_is_all_zero(pblk))
3224  return res;
3225  }
3226  continue;
3227  }
3228  bool arg_gap = BM_IS_GAP(arg_blk);
3229  bool gap = BM_IS_GAP(blk);
3230 
3231  if (arg_gap != gap)
3232  {
3233  BM_DECLARE_TEMP_BLOCK(temp_blk);
3234  bm::wordop_t* blk1; bm::wordop_t* blk2;
3235 
3236  if (gap)
3237  {
3239  BMGAP_PTR(blk));
3240  blk1 = (bm::wordop_t*)temp_blk;
3241  blk2 = (bm::wordop_t*)arg_blk;
3242  }
3243  else
3244  {
3246  BMGAP_PTR(arg_blk));
3247  blk1 = (bm::wordop_t*)blk;
3248  blk2 = (bm::wordop_t*)temp_blk;
3249  }
3250  res = bm::bitcmp(blk1, blk2, bm::set_block_size_op);
3251  }
3252  else
3253  {
3254  if (gap)
3255  {
3256  res = bm::gapcmp(BMGAP_PTR(blk), BMGAP_PTR(arg_blk));
3257  }
3258  else
3259  {
3260  res = bm::bitcmp((bm::wordop_t*)blk,
3261  (bm::wordop_t*)arg_blk,
3263  }
3264  }
3265  if (res != 0)
3266  return res;
3267  } // for j
3268 
3269  } // for i
3270 
3271  return 0;
3272 }
3273 
3274 // -----------------------------------------------------------------------
3275 
3276 template<typename Alloc>
3278  const bvector<Alloc>& bvect, size_type& pos,
3279  size_type search_to) const BMNOEXCEPT
3280 {
3281  unsigned top_blocks = blockman_.top_block_size();
3282  bm::word_t*** top_root = blockman_.top_blocks_root();
3283 
3284  if (!top_blocks || !top_root)
3285  {
3286  return bvect.find(pos);
3287  }
3288  bm::word_t*** arg_top_root = bvect.blockman_.top_blocks_root();
3289  unsigned i_to, j_to;
3290  {
3291  unsigned bvect_top_blocks = bvect.blockman_.top_block_size();
3292  if (!bvect_top_blocks || !arg_top_root)
3293  {
3294  bool f = this->find(pos);
3295  if (f)
3296  {
3297  if (pos > search_to)
3298  return false;
3299  }
3300  return f;
3301  }
3302 
3303  if (bvect_top_blocks > top_blocks)
3304  top_blocks = bvect_top_blocks;
3305  block_idx_type nb_to = (search_to >> bm::set_block_shift);
3306  bm::get_block_coord(nb_to, i_to, j_to);
3307  }
3308  if (i_to < top_blocks)
3309  top_blocks = i_to+1;
3310 
3311  for (unsigned i = 0; i < top_blocks; ++i)
3312  {
3313  const bm::word_t* const* blk_blk = blockman_.get_topblock(i);
3314  const bm::word_t* const* arg_blk_blk = bvect.blockman_.get_topblock(i);
3315 
3316  if (blk_blk == arg_blk_blk)
3317  {
3318  /* TODO: fix buffer overrread here
3319  unsigned arg_top_blocks = bvect.blockman_.top_block_size_;
3320  if (top_blocks < arg_top_blocks)
3321  arg_top_blocks = top_blocks;
3322  if (i_to < arg_top_blocks)
3323  arg_top_blocks = i_to+1;
3324 
3325  // look ahead for top level mismatch
3326  for (++i; i < arg_top_blocks; ++i)
3327  {
3328  if (top_root[i] != arg_top_root[i])
3329  {
3330  blk_blk = blockman_.get_topblock(i);
3331  arg_blk_blk = bvect.blockman_.get_topblock(i);
3332  BM_ASSERT(blk_blk != arg_blk_blk);
3333  goto find_sub_block;
3334  }
3335  }
3336  */
3337  continue;
3338  }
3339  //find_sub_block:
3340  unsigned j = 0;
3341  do
3342  {
3343  const bm::word_t* arg_blk; const bm::word_t* blk;
3344  arg_blk = ((bm::word_t*)arg_blk_blk == FULL_BLOCK_FAKE_ADDR) ?
3346  arg_blk_blk ? (BLOCK_ADDR_SAN(arg_blk_blk[j])) : 0;
3347  blk = ((bm::word_t*)blk_blk == FULL_BLOCK_FAKE_ADDR) ?
3349  (blk_blk ? (BLOCK_ADDR_SAN(blk_blk[j])) : 0);
3350  if (blk == arg_blk)
3351  continue;
3352 
3353  unsigned block_pos;
3354  bool found = bm::block_find_first_diff(blk, arg_blk, &block_pos);
3355  if (found)
3356  {
3357  pos =
3359  (size_type(j) * bm::gap_max_bits) + block_pos;
3360  if (pos > search_to)
3361  return false;
3362  return true;
3363  }
3364 
3365  if (i == i_to)
3366  {
3367  if (j >= j_to)
3368  return false;
3369  }
3370 
3371  } while (++j < bm::set_sub_array_size);
3372  } // for i
3373 
3374  return false;
3375 
3376 }
3377 
3378 // -----------------------------------------------------------------------
3379 
3380 template<typename Alloc>
3382 {
3383  if (this != &bvect)
3384  {
3385  blockman_.swap(bvect.blockman_);
3386  bm::xor_swap(size_,bvect.size_);
3387  }
3388 }
3389 
3390 // -----------------------------------------------------------------------
3391 
3392 template<typename Alloc>
3394  struct bvector<Alloc>::statistics* st) const BMNOEXCEPT
3395 {
3396  BM_ASSERT(st);
3397 
3398  st->reset();
3399  ::memcpy(st->gap_levels,
3400  blockman_.glen(), sizeof(gap_word_t) * bm::gap_levels);
3401 
3402  st->max_serialize_mem = unsigned(sizeof(bm::id_t) * 4);
3403  unsigned top_size = blockman_.top_block_size();
3404 
3405  size_t blocks_mem = sizeof(blockman_);
3406  blocks_mem +=
3407  (blockman_.temp_block_ ? sizeof(bm::word_t) * bm::set_block_size : 0);
3408  blocks_mem += sizeof(bm::word_t**) * top_size;
3409  bm::word_t*** blk_root = blockman_.top_blocks_root();
3410 
3411  if (blk_root)
3412  {
3413  for (unsigned i = 0; i < top_size; ++i)
3414  {
3415  const bm::word_t* const* blk_blk = blk_root[i];
3416  if (!blk_blk)
3417  {
3418  ++i;
3419  bool found = bm::find_not_null_ptr(blk_root, i, top_size, &i);
3420  if (!found)
3421  break;
3422  blk_blk = blk_root[i];
3423  BM_ASSERT(blk_blk);
3424  if (!blk_blk)
3425  break;
3426  }
3427  if ((bm::word_t*)blk_blk == FULL_BLOCK_FAKE_ADDR)
3428  continue;
3429  st->ptr_sub_blocks++;
3430  for (unsigned j = 0; j < bm::set_sub_array_size; ++j)
3431  {
3432  const bm::word_t* blk = blk_blk[j];
3433  if (IS_VALID_ADDR(blk))
3434  {
3435  if (BM_IS_GAP(blk))
3436  {
3437  bm::gap_word_t* gap_blk = BMGAP_PTR(blk);
3438  unsigned cap = bm::gap_capacity(gap_blk, blockman_.glen());
3439  unsigned len = gap_length(gap_blk);
3440  st->add_gap_block(cap, len);
3441  }
3442  else // bit block
3443  st->add_bit_block();
3444  }
3445  }
3446  } // for i
3447 
3448  size_t full_null_size = blockman_.calc_serialization_null_full();
3449  st->max_serialize_mem += full_null_size;
3450 
3451  } // if blk_root
3452 
3453  size_t safe_inc = st->max_serialize_mem / 10; // 10% increment
3454  if (!safe_inc) safe_inc = 256;
3455  st->max_serialize_mem += safe_inc;
3456 
3457  // Calc size of different odd and temporary things.
3458  st->memory_used += unsigned(sizeof(*this) - sizeof(blockman_));
3459  blocks_mem += st->ptr_sub_blocks * (sizeof(void*) * bm::set_sub_array_size);
3460  st->memory_used += blocks_mem;
3461  st->bv_count = 1;
3462 
3463 }
3464 
3465 // -----------------------------------------------------------------------
3466 
3467 template<class Alloc>
3469 {
3470  BM_ASSERT_THROW(n < bm::id_max, BM_ERR_RANGE);
3471 
3472  bool val = true; // set bit
3473 
3474  // calculate logical block number
3475  block_idx_type nblock = (n >> bm::set_block_shift);
3476  // calculate word number in block and bit
3477  unsigned nbit = unsigned(n & bm::set_block_mask);
3478 
3479  int block_type;
3480  bm::word_t* blk =
3481  blockman_.check_allocate_block(nblock,
3482  val,
3484  &block_type);
3485  if (!IS_VALID_ADDR(blk))
3486  return;
3487 
3488  if (block_type) // gap block
3489  {
3490  this->gap_block_set_no_ret(BMGAP_PTR(blk), val, nblock, nbit);
3491  }
3492  else // bit block
3493  {
3494  unsigned nword = nbit >> bm::set_word_shift;
3495  nbit &= bm::set_word_mask;
3496  blk[nword] |= (1u << nbit); // set bit
3497  }
3498 }
3499 
3500 // -----------------------------------------------------------------------
3501 
3502 template<class Alloc>
3504  size_type ids_size, bm::sort_order so)
3505 {
3506  if (!ids || !ids_size)
3507  return; // nothing to do
3508  if (!blockman_.is_init())
3509  blockman_.init_tree();
3510 
3511  import(ids, ids_size, so);
3512  sync_size();
3513 }
3514 
3515 // -----------------------------------------------------------------------
3516 
3517 template<class Alloc>
3518 void bvector<Alloc>::keep(const size_type* ids, size_type ids_size,
3519  bm::sort_order so)
3520 {
3521  if (!ids || !ids_size || !blockman_.is_init())
3522  {
3523  clear();
3524  return;
3525  }
3526  bvector<Alloc> bv_tmp; // TODO: better optimize for SORTED case (avoid temp)
3527  bv_tmp.import(ids, ids_size, so);
3528 
3529  size_type last;
3530  bool found = bv_tmp.find_reverse(last);
3531  if (found)
3532  {
3533  bv_tmp.resize(last+1);
3534  bit_and(bv_tmp);
3535  }
3536  else
3537  {
3538  BM_ASSERT(0);
3539  clear();
3540  }
3541 }
3542 
3543 // -----------------------------------------------------------------------
3544 
3545 template<class Alloc>
3547  size_type ids_size, bm::sort_order so)
3548 {
3549  if (!ids || !ids_size || !blockman_.is_init())
3550  {
3551  return;
3552  }
3553  bvector<Alloc> bv_tmp; // TODO: better optimize for SORTED case (avoid temp)
3554  bv_tmp.import(ids, ids_size, so);
3555 
3556  size_type last;
3557  bool found = bv_tmp.find_reverse(last);
3558  if (found)
3559  {
3560  bv_tmp.resize(last+1);
3561  bit_sub(bv_tmp);
3562  }
3563  else
3564  {
3565  BM_ASSERT(0);
3566  }
3567 }
3568 
3569 // -----------------------------------------------------------------------
3570 
3571 template<class Alloc>
3573 {
3574  set_range(0, size_ - 1, true);
3575  return *this;
3576 }
3577 
3578 // -----------------------------------------------------------------------
3579 
3580 template<class Alloc>
3582 {
3583  set_bit(n, val);
3584  return *this;
3585 }
3586 
3587 // -----------------------------------------------------------------------
3588 
3589 template<class Alloc>
3590 bool bvector<Alloc>::set_bit_conditional(size_type n, bool val, bool condition)
3591 {
3592  if (val == condition) return false;
3593  if (n >= size_)
3594  {
3595  size_type new_size = (n == bm::id_max) ? bm::id_max : n + 1;
3596  resize(new_size);
3597  }
3598  return set_bit_conditional_impl(n, val, condition);
3599 }
3600 
3601 // -----------------------------------------------------------------------
3602 
3603 template<class Alloc>
3605 {
3606  BM_ASSERT(n < size_);
3607  BM_ASSERT_THROW(n < size_, BM_ERR_RANGE);
3608 
3609  if (!blockman_.is_init())
3610  blockman_.init_tree();
3611  return and_bit_no_check(n, val);
3612 }
3613 
3614 // -----------------------------------------------------------------------
3615 
3616 template<class Alloc>
3618 {
3619  BM_ASSERT_THROW(n < bm::id_max, BM_ERR_RANGE);
3620 
3621  if (!blockman_.is_init())
3622  blockman_.init_tree();
3623  if (n >= size_)
3624  {
3625  size_type new_size = (n == bm::id_max) ? bm::id_max : n + 1;
3626  resize(new_size);
3627  }
3628  return set_bit_no_check(n, val);
3629 }
3630 
3631 // -----------------------------------------------------------------------
3632 
3633 template<class Alloc>
3634 void bvector<Alloc>::import(const size_type* ids, size_type size_in,
3635  bm::sort_order sorted_idx)
3636 {
3637  size_type n, start, stop = size_in;
3638  block_idx_type nblock;
3639  start = 0;
3640 
3641  n = ids[start];
3642  nblock = (n >> bm::set_block_shift);
3643 
3644  switch(sorted_idx)
3645  {
3646  case BM_SORTED:
3647  {
3648  block_idx_type nblock_end = (ids[size_in-1] >> bm::set_block_shift);
3649  if (nblock == nblock_end) // special case: one block import
3650  {
3651  if (stop == 1)
3652  set_bit_no_check(ids[0]);
3653  else
3654  import_block(ids, nblock, 0, stop);
3655  return;
3656  }
3657  }
3658  break;
3659  default:
3660  break;
3661  } // switch
3662 
3663  do
3664  {
3665  n = ids[start];
3666  nblock = (n >> bm::set_block_shift);
3667  #ifdef BM64ADDR
3668  stop = bm::idx_arr_block_lookup_u64(ids, size_in, nblock, start);
3669  #else
3670  stop = bm::idx_arr_block_lookup_u32(ids, size_in, nblock, start);
3671  #endif
3672  BM_ASSERT(start < stop);
3673 
3674  if (stop - start == 1 && n < bm::id_max) // just one bit to set
3675  set_bit_no_check(n);
3676  else
3677  import_block(ids, nblock, start, stop);
3678  start = stop;
3679  } while (start < size_in);
3680 }
3681 
3682 // -----------------------------------------------------------------------
3683 
3684 template<class Alloc>
3686  block_idx_type nblock,
3687  size_type start,
3688  size_type stop)
3689 {
3690  BM_ASSERT(stop > start);
3691  int block_type;
3692  bm::word_t* blk =
3693  blockman_.check_allocate_block(nblock, 1, 0, &block_type,
3694  true/*allow NULL ret*/);
3695  if (!IS_FULL_BLOCK(blk))
3696  {
3697  // TODO: add a special case when we import just a few bits per block
3698  if (BM_IS_GAP(blk))
3699  {
3700  blk = blockman_.deoptimize_block(nblock); // TODO: try to avoid
3701  }
3702  #ifdef BM64ADDR
3703  bm::set_block_bits_u64(blk, ids, start, stop);
3704  #else
3705  bm::set_block_bits_u32(blk, ids, start, stop);
3706  #endif
3707 
3708  if (nblock == bm::set_total_blocks-1)
3709  blk[bm::set_block_size-1] &= ~(1u<<31);
3710  }
3711 }
3712 
3713 // -----------------------------------------------------------------------
3714 
3715 template<class Alloc>
3717 {
3718  // calculate logical block number
3719  block_idx_type nblock = (n >> bm::set_block_shift);
3720 
3721  int block_type;
3722  bm::word_t* blk =
3723  blockman_.check_allocate_block(nblock,
3724  val,
3726  &block_type);
3727 
3728  if (!IS_VALID_ADDR(blk))
3729  return false;
3730 
3731  // calculate word number in block and bit
3732  unsigned nbit = unsigned(n & bm::set_block_mask);
3733  if (block_type) // gap
3734  {
3735  return gap_block_set(BMGAP_PTR(blk), val, nblock, nbit);
3736  }
3737  else // bit block
3738  {
3739  unsigned nword = unsigned(nbit >> bm::set_word_shift);
3740  nbit &= bm::set_word_mask;
3741  bm::word_t* word = blk + nword;
3742  bm::word_t mask = (((bm::word_t)1) << nbit);
3743 
3744  if (val)
3745  {
3746  val = ~(*word & mask);
3747  *word |= mask; // set bit
3748  return val;
3749  }
3750  else
3751  {
3752  val = ~(*word & mask);
3753  *word &= ~mask; // clear bit
3754  return val;
3755  }
3756  }
3757  //return false;
3758 }
3759 
3760 // -----------------------------------------------------------------------
3761 
3762 template<class Alloc>
3764  bool val, block_idx_type nblock,
3765  unsigned nbit)
3766 {
3767  unsigned is_set, new_len, old_len;
3768  old_len = bm::gap_length(gap_blk)-1;
3769  new_len = bm::gap_set_value(val, gap_blk, nbit, &is_set);
3770  if (old_len < new_len)
3771  {
3772  unsigned threshold = bm::gap_limit(gap_blk, blockman_.glen());
3773  if (new_len > threshold)
3774  blockman_.extend_gap_block(nblock, gap_blk);
3775  }
3776  return is_set;
3777 }
3778 
3779 // -----------------------------------------------------------------------
3780 
3781 template<class Alloc>
3782 void bvector<Alloc>::gap_block_set_no_ret(bm::gap_word_t* gap_blk,
3783  bool val, block_idx_type nblock, unsigned nbit)
3784 {
3785  unsigned new_len, old_len;
3786  old_len = bm::gap_length(gap_blk)-1;
3787  new_len = bm::gap_set_value(val, gap_blk, nbit);
3788  if (old_len < new_len)
3789  {
3790  unsigned threshold = bm::gap_limit(gap_blk, blockman_.glen());
3791  if (new_len > threshold)
3792  blockman_.extend_gap_block(nblock, gap_blk);
3793  }
3794 }
3795 
3796 
3797 // -----------------------------------------------------------------------
3798 
3799 template<class Alloc>
3801 {
3802  // calculate logical block number
3803  block_idx_type nblock = (n >> bm::set_block_shift);
3804  bm::word_t* blk =
3805  blockman_.check_allocate_block(nblock,
3807  BM_ASSERT(IS_VALID_ADDR(blk));
3808 
3809  unsigned nbit = unsigned(n & bm::set_block_mask);
3810 
3811  unsigned is_set;
3812  if (BM_IS_GAP(blk))
3813  {
3814  bm::gap_word_t* gap_blk = BMGAP_PTR(blk);
3815  is_set = (bm::gap_test_unr(gap_blk, nbit) != 0);
3816  this->gap_block_set(gap_blk, !is_set, nblock, nbit); // flip
3817  }
3818  else // bit block
3819  {
3820  unsigned nword = unsigned(nbit >> bm::set_word_shift);
3821  nbit &= bm::set_word_mask;
3822 
3823  bm::word_t* word = blk + nword;
3824  bm::word_t mask = (((bm::word_t)1) << nbit);
3825  is_set = ((*word) & mask);
3826 
3827  *word = (is_set) ? (*word & ~mask) : (*word | mask);
3828  }
3829  return is_set;
3830 }
3831 
3832 // -----------------------------------------------------------------------
3833 
3834 template<class Alloc>
3836  bool val,
3837  bool condition)
3838 {
3839  // calculate logical block number
3840  block_idx_type nblock = (n >> bm::set_block_shift);
3841  int block_type;
3842  bm::word_t* blk =
3843  blockman_.check_allocate_block(nblock,
3844  val,
3846  &block_type);
3847  if (!IS_VALID_ADDR(blk))
3848  return false;
3849 
3850  // calculate word number in block and bit
3851  unsigned nbit = unsigned(n & bm::set_block_mask);
3852 
3853  if (block_type == 1) // gap
3854  {
3855  bm::gap_word_t* gap_blk = BMGAP_PTR(blk);
3856  bool old_val = (bm::gap_test_unr(gap_blk, nbit) != 0);
3857 
3858  if (old_val != condition)
3859  {
3860  return false;
3861  }
3862 
3863  if (val != old_val)
3864  {
3865  unsigned is_set = gap_block_set(gap_blk, val, nblock, nbit);
3866  BM_ASSERT(is_set);
3867  return is_set;
3868  }
3869  }
3870  else // bit block
3871  {
3872  unsigned nword = unsigned(nbit >> bm::set_word_shift);
3873  nbit &= bm::set_word_mask;
3874 
3875  bm::word_t* word = blk + nword;
3876  bm::word_t mask = (((bm::word_t)1) << nbit);
3877  bool is_set = ((*word) & mask) != 0;
3878 
3879  if (is_set != condition)
3880  {
3881  return false;
3882  }
3883  if (is_set != val) // need to change bit
3884  {
3885  if (val) // set bit
3886  {
3887  *word |= mask;
3888  }
3889  else // clear bit
3890  {
3891  *word &= ~mask;
3892  }
3893  return true;
3894  }
3895  }
3896  return false;
3897 
3898 }
3899 
3900 // -----------------------------------------------------------------------
3901 
3902 
3903 template<class Alloc>
3904 bool bvector<Alloc>::and_bit_no_check(size_type n, bool val)
3905 {
3906  // calculate logical block number
3907  block_idx_type nblock = (n >> bm::set_block_shift);
3908 
3909  int block_type;
3910  bm::word_t* blk =
3911  blockman_.check_allocate_block(nblock,
3912  val,
3914  &block_type);
3915  if (!IS_VALID_ADDR(blk))
3916  return false;
3917 
3918  // calculate word number in block and bit
3919  unsigned nbit = unsigned(n & bm::set_block_mask);
3920 
3921  if (block_type == 1) // gap
3922  {
3923  bm::gap_word_t* gap_blk = BMGAP_PTR(blk);
3924  bool old_val = (bm::gap_test_unr(gap_blk, nbit) != 0);
3925 
3926  bool new_val = val & old_val;
3927  if (new_val != old_val)
3928  {
3929  unsigned is_set = gap_block_set(gap_blk, val, nblock, nbit);
3930  BM_ASSERT(is_set);
3931  return is_set;
3932  }
3933  }
3934  else // bit block
3935  {
3936  unsigned nword = unsigned(nbit >> bm::set_word_shift);
3937  nbit &= bm::set_word_mask;
3938 
3939  bm::word_t* word = blk + nword;
3940  bm::word_t mask = (((bm::word_t)1) << nbit);
3941  bool is_set = ((*word) & mask) != 0;
3942 
3943  bool new_val = is_set & val;
3944  if (new_val != val) // need to change bit
3945  {
3946  if (new_val) // set bit
3947  {
3948  *word |= mask;
3949  }
3950  else // clear bit
3951  {
3952  *word &= ~mask;
3953  }
3954  return true;
3955  }
3956  }
3957  return false;
3958 }
3959 
3960 //---------------------------------------------------------------------
3961 
3962 template<class Alloc>
3964 {
3965  if (from == bm::id_max)
3966  return false;
3967  if (!from)
3968  {
3969  return find(pos);
3970  }
3971  pos = check_or_next(from);
3972  return (pos != 0);
3973 }
3974 
3975 //---------------------------------------------------------------------
3976 
3977 template<class Alloc>
3979 {
3980  bool found;
3981 
3982  unsigned top_blocks = blockman_.top_block_size();
3983  if (!top_blocks)
3984  return false;
3985  for (unsigned i = top_blocks-1; true; --i)
3986  {
3987  const bm::word_t* const* blk_blk = blockman_.get_topblock(i);
3988  if (blk_blk)
3989  {
3990  if ((bm::word_t*)blk_blk == FULL_BLOCK_FAKE_ADDR)
3991  blk_blk = FULL_SUB_BLOCK_REAL_ADDR;
3992 
3993  for (unsigned short j = bm::set_sub_array_size-1; true; --j)
3994  {
3995  const bm::word_t* blk = blk_blk[j];
3996  if (blk)
3997  {
3998  unsigned block_pos;
3999  if (blk == FULL_BLOCK_FAKE_ADDR)
4000  {
4001  block_pos = bm::gap_max_bits-1;
4002  found = true;
4003  }
4004  else
4005  {
4006  bool is_gap = BM_IS_GAP(blk);
4007  found = is_gap ? bm::gap_find_last(BMGAP_PTR(blk), &block_pos)
4008  : bm::bit_find_last(blk, &block_pos);
4009  }
4010  if (found)
4011  {
4012  block_idx_type base_idx =
4015  base_idx += j * bm::gap_max_bits;
4016  pos = base_idx + block_pos;
4017  return found;
4018  }
4019  }
4020 
4021  if (j == 0)
4022  break;
4023  } // for j
4024  } // if blk_blk
4025 
4026  if (i == 0)
4027  break;
4028  } // for i
4029  return false;
4030 }
4031 
4032 //---------------------------------------------------------------------
4033 
4034 template<class Alloc>
4036 {
4037  bool found;
4038 
4039  unsigned top_blocks = blockman_.top_block_size();
4040  for (unsigned i = 0; i < top_blocks; ++i)
4041  {
4042  const bm::word_t* const* blk_blk = blockman_.get_topblock(i);
4043  if (blk_blk)
4044  {
4045  if ((bm::word_t*)blk_blk == FULL_BLOCK_FAKE_ADDR)
4046  blk_blk = FULL_SUB_BLOCK_REAL_ADDR;
4047 
4048  for (unsigned j = 0; j < bm::set_sub_array_size; ++j)
4049  {
4050  const bm::word_t* blk = blk_blk[j];
4051  if (blk)
4052  {
4053  unsigned block_pos;
4054  if (blk == FULL_BLOCK_FAKE_ADDR)
4055  {
4056  found = true; block_pos = 0;
4057  }
4058  else
4059  {
4060  bool is_gap = BM_IS_GAP(blk);
4061  found = (is_gap) ? bm::gap_find_first(BMGAP_PTR(blk), &block_pos)
4062  : bm::bit_find_first(blk, &block_pos);
4063  }
4064  if (found)
4065  {
4066  size_type base_idx = block_idx_type(i) * bm::bits_in_array;
4067  base_idx += j * bm::gap_max_bits;
4068  pos = base_idx + block_pos;
4069  return found;
4070  }
4071  }
4072  } // for j
4073  } // if blk_blk
4074  } // for i
4075  return false;
4076 }
4077 
4078 //---------------------------------------------------------------------
4079 
4080 template<class Alloc>
4082  size_type& in_last) const BMNOEXCEPT
4083 {
4084  bool found = find(in_first);
4085  if (found)
4086  {
4087  found = find_reverse(in_last);
4088  BM_ASSERT(found);
4089  BM_ASSERT(in_first <= in_last);
4090  }
4091  else
4092  {
4093  in_first = in_last = 0; // zero the output just in case
4094  }
4095  return found;
4096 }
4097 
4098 //---------------------------------------------------------------------
4099 
4100 template<class Alloc>
4102  size_type from,
4103  size_type& pos) const BMNOEXCEPT
4104 {
4105  BM_ASSERT_THROW(from < bm::id_max, BM_ERR_RANGE);
4106 
4107  bool ret = false;
4108 
4109  if (!rank_in || !blockman_.is_init())
4110  return ret;
4111 
4112  block_idx_type nb = (from >> bm::set_block_shift);
4114  unsigned bit_pos = 0;
4115 
4116  for (; nb < bm::set_total_blocks; ++nb)
4117  {
4118  int no_more_blocks;
4119  const bm::word_t* block = blockman_.get_block(nb, &no_more_blocks);
4120  if (block)
4121  {
4122  if (!nbit && (rank_in > bm::gap_max_bits)) // requested rank cannot be in this block
4123  {
4124  unsigned cnt = blockman_.block_bitcount(block);
4125  BM_ASSERT(cnt < rank_in);
4126  rank_in -= cnt;
4127  continue;
4128  }
4129  else
4130  {
4131  rank_in = bm::block_find_rank(block, rank_in, nbit, bit_pos);
4132  if (!rank_in) // target found
4133  {
4134  pos = bit_pos + (nb * bm::set_block_size * 32);
4135  return true;
4136  }
4137  }
4138  }
4139  else
4140  {
4141  // TODO: better next block search
4142  if (no_more_blocks)
4143  break;
4144  }
4145  nbit ^= nbit; // zero start bit after first scanned block
4146  } // for nb
4147 
4148  return ret;
4149 }
4150 
4151 //---------------------------------------------------------------------
4152 
4153 template<class Alloc>
4155  size_type from,
4156  size_type& pos,
4157  const rs_index_type& rs_idx) const BMNOEXCEPT
4158 {
4159  BM_ASSERT_THROW(from < bm::id_max, BM_ERR_RANGE);
4160 
4161  bool ret = false;
4162 
4163  if (!rank_in ||
4164  !blockman_.is_init() ||
4165  (rs_idx.count() < rank_in))
4166  return ret;
4167 
4168  block_idx_type nb;
4169  if (from)
4170  nb = (from >> bm::set_block_shift);
4171  else
4172  {
4173  nb = rs_idx.find(rank_in);
4174  BM_ASSERT(rs_idx.rcount(nb) >= rank_in);
4175  if (nb)
4176  rank_in -= rs_idx.rcount(nb-1);
4177  }
4178 
4180  unsigned bit_pos = 0;
4181 
4182  for (; nb < rs_idx.get_total(); ++nb)
4183  {
4184  int no_more_blocks;
4185  const bm::word_t* block = blockman_.get_block(nb, &no_more_blocks);
4186  if (block)
4187  {
4188  if (!nbit) // check if the whole block can be skipped
4189  {
4190  unsigned block_bc = rs_idx.count(nb);
4191  if (rank_in <= block_bc) // target block
4192  {
4193  nbit = rs_idx.select_sub_range(nb, rank_in);
4194  rank_in = bm::block_find_rank(block, rank_in, nbit, bit_pos);
4195  BM_ASSERT(rank_in == 0);
4196  pos = bit_pos + (nb * bm::set_block_size * 32);
4197  return true;
4198  }
4199  rank_in -= block_bc;
4200  continue;
4201  }
4202 
4203  rank_in = bm::block_find_rank(block, rank_in, nbit, bit_pos);
4204  if (!rank_in) // target found
4205  {
4206  pos = bit_pos + (nb * bm::set_block_size * 32);
4207  return true;
4208  }
4209  }
4210  else
4211  {
4212  // TODO: better next block search
4213  if (no_more_blocks)
4214  break;
4215  }
4216  nbit ^= nbit; // zero start bit after first scanned block
4217  } // for nb
4218 
4219  return ret;
4220 }
4221 
4222 //---------------------------------------------------------------------
4223 
4224 template<class Alloc>
4226  const rs_index_type& rs_idx) const BMNOEXCEPT
4227 {
4228  bool ret = false;
4229 
4230  if (!rank_in ||
4231  !blockman_.is_init() ||
4232  (rs_idx.count() < rank_in))
4233  return ret;
4234 
4235  block_idx_type nb;
4236  bm::gap_word_t sub_range_from;
4237 
4238  bool found = rs_idx.find(&rank_in, &nb, &sub_range_from);
4239  if (!found)
4240  return found;
4241 
4242  unsigned i, j;
4243  bm::get_block_coord(nb, i, j);
4244  const bm::word_t* block = blockman_.get_block_ptr(i, j);
4245 
4246  block = BLOCK_ADDR_SAN(block); // TODO: optimize FULL block selection
4247 
4248  BM_ASSERT(block);
4249  BM_ASSERT(rank_in <= rs_idx.count(nb));
4250 
4251  unsigned bit_pos = 0;
4252  rank_in = bm::block_find_rank(block, rank_in, sub_range_from, bit_pos);
4253  BM_ASSERT(rank_in == 0);
4254  pos = bit_pos + (nb * bm::set_block_size * 32);
4255  return true;
4256 }
4257 
4258 //---------------------------------------------------------------------
4259 
4260 template<class Alloc>
4261 typename bvector<Alloc>::size_type
4263 {
4264  if (!blockman_.is_init())
4265  return 0;
4266 
4267  // calculate logical block number
4268  block_idx_type nb = (prev >> bm::set_block_shift);
4269  unsigned i, j;
4270  bm::get_block_coord(nb, i, j);
4271  const bm::word_t* block = blockman_.get_block_ptr(i, j);
4272 
4273  if (block)
4274  {
4275  unsigned block_pos;
4276  bool found = false;
4277  // calculate word number in block and bit
4278  unsigned nbit = unsigned(prev & bm::set_block_mask);
4279  if (BM_IS_GAP(block))
4280  {
4281  if (bm::gap_block_find(BMGAP_PTR(block), nbit, &block_pos))
4282  {
4283  prev = (size_type(nb) * bm::gap_max_bits) + block_pos;
4284  return prev;
4285  }
4286  }
4287  else
4288  {
4289  if (block == FULL_BLOCK_FAKE_ADDR)
4290  return prev;
4291  found = bm::bit_block_find(block, nbit, &block_pos);
4292  if (found)
4293  {
4294  prev = (size_type(nb) * bm::gap_max_bits) + block_pos;
4295  return prev;
4296  }
4297  }
4298  }
4299  ++j;
4300  block_idx_type top_blocks = blockman_.top_block_size();
4301  for (; i < top_blocks; ++i)
4302  {
4303  const bm::word_t* const* blk_blk = blockman_.get_topblock(i);
4304  if (blk_blk)
4305  {
4306  if ((bm::word_t*)blk_blk == FULL_BLOCK_FAKE_ADDR)
4307  blk_blk = FULL_SUB_BLOCK_REAL_ADDR;
4308 
4309  for (; j < bm::set_sub_array_size; ++j)
4310  {
4311  const bm::word_t* blk = blk_blk[j];
4312  if (blk)
4313  {
4314  bool found;
4315  unsigned block_pos;
4316  if (blk == FULL_BLOCK_FAKE_ADDR)
4317  {
4318  found = true; block_pos = 0;
4319  }
4320  else
4321  {
4322  bool is_gap = BM_IS_GAP(blk);
4323  found = (is_gap) ? bm::gap_find_first(BMGAP_PTR(blk), &block_pos)
4324  : bm::bit_find_first(blk, &block_pos);
4325  }
4326  if (found)
4327  {
4328  size_type base_idx = size_type(i) * bm::bits_in_array;
4329  base_idx += j * bm::gap_max_bits;
4330  prev = base_idx + block_pos;
4331  return prev;
4332  }
4333  }
4334  } // for j
4335  }
4336  j = 0;
4337  } // for i
4338 
4339  return 0;
4340 }
4341 
4342 //---------------------------------------------------------------------
4343 
4344 template<class Alloc>
4346 bvector<Alloc>::check_or_next_extract(size_type prev)
4347 {
4348  if (!blockman_.is_init())
4349  return 0;
4350  // TODO: optimization
4351  size_type pos = this->check_or_next(prev);
4352  if (pos >= prev)
4353  this->clear_bit_no_check(pos);
4354  return pos;
4355 }
4356 
4357 //---------------------------------------------------------------------
4358 
4359 template<class Alloc>
4361 {
4362  return insert(0, false);
4363 }
4364 
4365 //---------------------------------------------------------------------
4366 
4367 template<class Alloc>
4369 {
4370  bool b = this->test(0);
4371  this->erase(0);
4372  return b;
4373 }
4374 
4375 //---------------------------------------------------------------------
4376 
4377 template<class Alloc>
4379 {
4380  BM_ASSERT_THROW(n < bm::id_max, BM_ERR_RANGE);
4381 
4382  if (size_ < bm::id_max)
4383  ++size_;
4384  if (!blockman_.is_init())
4385  {
4386  if (value)
4387  set(n);
4388  return 0;
4389  }
4390 
4391  // calculate logical block number
4392  block_idx_type nb = (n >> bm::set_block_shift);
4393 
4394  int block_type;
4395  bm::word_t carry_over = 0;
4396 
4397  if (!n && !value) // regular shift-right by 1 bit
4398  {}
4399  else // process target block insertion
4400  {
4401  unsigned i, j;
4402  bm::get_block_coord(nb, i, j);
4403  bm::word_t* block = blockman_.get_block_ptr(i, j);
4404 
4405  if (!block && !value) // nothing to do
4406  {}
4407  else
4408  {
4409  if (!block)
4410  block = blockman_.check_allocate_block(nb, BM_BIT);
4411  if (BM_IS_GAP(block) || IS_FULL_BLOCK(block))
4412  block = blockman_.deoptimize_block(nb); // TODO: optimize GAP block insert
4413  BM_ASSERT(IS_VALID_ADDR(block));
4414  {
4415  unsigned nbit = unsigned(n & bm::set_block_mask);
4416  carry_over = bm::bit_block_insert(block, nbit, value);
4417  }
4418  }
4419  ++nb;
4420  }
4421 
4422  unsigned i0, j0;
4423  bm::get_block_coord(nb, i0, j0);
4424 
4425  unsigned top_blocks = blockman_.top_block_size();
4426  bm::word_t*** blk_root = blockman_.top_blocks_root();
4427  bm::word_t** blk_blk;
4428  bm::word_t* block;
4429 
4430  for (unsigned i = i0; i < bm::set_top_array_size; ++i)
4431  {
4432  if (i >= top_blocks)
4433  {
4434  if (!carry_over)
4435  break;
4436  blk_blk = 0;
4437  }
4438  else
4439  blk_blk = blk_root[i];
4440 
4441  if (!blk_blk) // top level group of blocks missing - can skip it
4442  {
4443  if (carry_over)
4444  {
4445  // carry over: needs block-list extension and a block
4447  if (nblock > nb)
4448  {
4449  block =
4450  blockman_.check_allocate_block(nblock, 0, 0, &block_type, false);
4451  block[0] |= carry_over; // block is brand new (0000)
4452 
4453  // reset all control vars (blocks tree may have re-allocated)
4454  blk_root = blockman_.top_blocks_root();
4455  blk_blk = blk_root[i];
4456  top_blocks = blockman_.top_block_size();
4457 
4458  carry_over = 0;
4459  }
4460  }
4461  continue;
4462  }
4463  if ((bm::word_t*)blk_blk == FULL_BLOCK_FAKE_ADDR)
4464  {
4465  if (carry_over)
4466  continue;
4467  blk_blk = blockman_.check_alloc_top_subblock(i);
4468  }
4469 
4470  unsigned j = j0;
4471  do
4472  {
4474  block = blk_blk[j];
4475  if (!block)
4476  {
4477  if (carry_over)
4478  {
4479  size_type nbit = nblock * bm::gap_max_bits;
4480  set_bit_no_check(nbit);
4481  carry_over = 0; block = 0;
4482  }
4483  // no CO: tight loop scan for the next available block (if any)
4484  for (++j; j < bm::set_sub_array_size; ++j)
4485  {
4486  if (0 != (block = blk_blk[j]))
4487  {
4488  nblock = (i * bm::set_sub_array_size) + j;
4489  break;
4490  }
4491  } // for j
4492  if (!block) // no more blocks in this j-dimention
4493  continue;
4494  }
4495  if (IS_FULL_BLOCK(block))
4496  {
4497  // 1 in 1 out, block is still all 0xFFFF..
4498  // 0 into 1 -> carry in 0, carry out 1
4499  if (!carry_over)
4500  {
4501  block = blockman_.deoptimize_block(nblock);
4502  block[0] <<= (carry_over = 1);
4503  }
4504  continue;
4505  }
4506  if (BM_IS_GAP(block))
4507  {
4508  if (nblock == bm::set_total_blocks-1) // last block
4509  {
4510  // process as a bit-block (for simplicity)
4511  block = blockman_.deoptimize_block(nblock);
4512  }
4513  else // use gap-block shift here
4514  {
4515  unsigned new_block_len;
4516  bm::gap_word_t* gap_blk = BMGAP_PTR(block);
4517 
4518  carry_over = bm::gap_shift_r1(gap_blk, carry_over, &new_block_len);
4519  unsigned threshold = bm::gap_limit(gap_blk, blockman_.glen());
4520  if (new_block_len > threshold)
4521  {
4522  blockman_.extend_gap_block(nblock, gap_blk);
4523  }
4524  continue;
4525  }
4526  }
4527  // bit-block
4528  {
4529  bm::word_t acc;
4530  carry_over = bm::bit_block_shift_r1_unr(block, &acc, carry_over);
4531  BM_ASSERT(carry_over <= 1);
4532 
4533  if (nblock == bm::set_total_blocks-1) // last possible block
4534  {
4535  carry_over = block[bm::set_block_size-1] & (1u<<31);
4536  block[bm::set_block_size-1] &= ~(1u<<31); // clear the 1-bit tail
4537  if (!acc) // block shifted out: release memory
4538  blockman_.zero_block(nblock);
4539  break;
4540  }
4541  if (!acc)
4542  blockman_.zero_block(nblock);
4543  }
4544 
4545  } while (++j < bm::set_sub_array_size);
4546  j0 = 0;
4547  } // for i
4548  return carry_over;
4549 
4550 }
4551 
4552 //---------------------------------------------------------------------
4553 
4554 template<class Alloc>
4556 {
4557  BM_ASSERT_THROW(n < bm::id_max, BM_ERR_RANGE);
4558 
4559  if (!blockman_.is_init())
4560  return ;
4561 
4562  // calculate logical block number
4563  block_idx_type nb = (n >> bm::set_block_shift);
4564 
4565  if (!n ) // regular shift-left by 1 bit
4566  {}
4567  else // process target block bit erase
4568  {
4569  unsigned i, j;
4570  bm::get_block_coord(nb, i, j);
4571  bm::word_t* block = blockman_.get_block_ptr(i, j);
4572  bool carry_over = test_first_block_bit(nb+1);
4573  if (!block)
4574  {
4575  if (carry_over)
4576  {
4577  block = blockman_.check_allocate_block(nb, BM_BIT);
4578  block[bm::set_block_size-1] = (1u << 31u);
4579  }
4580  }
4581  else
4582  {
4583  if (BM_IS_GAP(block) || IS_FULL_BLOCK(block))
4584  block = blockman_.deoptimize_block(nb);
4585  BM_ASSERT(IS_VALID_ADDR(block));
4586  unsigned nbit = unsigned(n & bm::set_block_mask);
4587  bm::bit_block_erase(block, nbit, carry_over);
4588  }
4589  ++nb;
4590  }
4591  // left shifting of all other blocks
4592  //
4593  unsigned i0, j0;
4594  bm::get_block_coord(nb, i0, j0);
4595 
4596  unsigned top_blocks = blockman_.top_block_size();
4597  bm::word_t*** blk_root = blockman_.top_blocks_root();
4598  bm::word_t** blk_blk;
4599  bm::word_t* block;
4600 
4601  for (unsigned i = i0; i < bm::set_top_array_size; ++i)
4602  {
4603  if (i >= top_blocks)
4604  break;
4605  else
4606  blk_blk = blk_root[i];
4607 
4608  if (!blk_blk) // top level group of blocks missing
4609  {
4610  bool found = bm::find_not_null_ptr(blk_root, i+1, top_blocks, &i);
4611  if (!found)
4612  break;
4613  --i;
4614  continue;
4615  }
4616  if ((bm::word_t*)blk_blk == FULL_BLOCK_FAKE_ADDR)
4617  {
4618  bool carry_over = 0;
4619  if (i + 1 < bm::set_top_array_size)
4620  {
4622  carry_over = this->test(co_idx);
4623  if (carry_over)
4624  continue; // nothing to do (1 in)
4625  else
4626  blk_blk = blockman_.check_alloc_top_subblock(i);
4627  }
4628  else
4629  {
4630  blk_blk = blockman_.check_alloc_top_subblock(i);
4631  }
4632  }
4633 
4634  unsigned j = j0;
4635  do
4636  {
4638  bool carry_over = 0; // test_first_block_bit(nblock+1); // look ahead for CO
4639  block = blk_blk[j];
4640  if (!block)
4641  {
4642  // no CO: tight loop scan for the next available block (if any)
4643  bool no_blocks = (j == 0);
4644  for (++j; j < bm::set_sub_array_size; ++j)
4645  {
4646  if (0 != (block = blk_blk[j]))
4647  {
4648  nblock = (block_idx_type(i) * bm::set_sub_array_size) + j;
4649  break;
4650  }
4651  } // for j
4652  if (!block) // no more blocks in this j-dimention ?
4653  {
4654  if (j == bm::set_sub_array_size && no_blocks)
4655  {
4656  blockman_.zero_block(i, j-1); // free the top level
4657  }
4658  continue;
4659  }
4660  }
4661  BM_ASSERT(block);
4662  if (IS_FULL_BLOCK(block))
4663  {
4664  carry_over = test_first_block_bit(nblock+1); // look ahead for CO
4665  // 1 in 1 out, block is still all 0xFFFF..
4666  // 0 into 1 -> carry in 0, carry out 1
4667  if (!carry_over)
4668  {
4669  block = blockman_.deoptimize_block(nblock);
4670  block[bm::set_block_size-1] >>= 1;
4671  }
4672  carry_over = 1;
4673  }
4674  else
4675  if (BM_IS_GAP(block))
4676  {
4677  carry_over = test_first_block_bit(nblock+1); // look ahead for CO
4678  unsigned new_block_len;
4679  bm::gap_word_t* gap_blk = BMGAP_PTR(block);
4680 
4681  carry_over = bm::gap_shift_l1(gap_blk, carry_over, &new_block_len);
4682  unsigned threshold = bm::gap_limit(gap_blk, blockman_.glen());
4683  if (new_block_len > threshold)
4684  blockman_.extend_gap_block(nblock, gap_blk);
4685  else
4686  {
4687  if (bm::gap_is_all_zero(gap_blk))
4688  blockman_.zero_block(i, j);
4689  }
4690  }
4691  else // bit-block
4692  {
4693  bm::word_t acc;
4694  carry_over = bm::bit_block_shift_l1_unr(block, &acc, carry_over);
4695  if (!acc)
4696  blockman_.zero_block(i, j);
4697  }
4698 
4699  if (carry_over && nblock)
4700  {
4702  }
4703 
4704  } while (++j < bm::set_sub_array_size);
4705  j0 = 0;
4706  } // for i
4707 
4708 }
4709 
4710 //---------------------------------------------------------------------
4711 
4712 template<class Alloc>
4714 {
4715  if (nb >= bm::set_total_blocks) // last possible block
4716  return false;
4717  return test(nb * bm::gap_max_bits);
4718 }
4719 
4720 
4721 //---------------------------------------------------------------------
4722 
4723 template<class Alloc>
4725 {
4726  if (!bv.blockman_.is_init())
4727  {
4728  this->move_from(bv);
4729  return;
4730  }
4731 
4732  unsigned top_blocks = blockman_.top_block_size();
4733  if (size_ < bv.size_) // this vect shorter than the arg.
4734  {
4735  size_ = bv.size_;
4736  }
4737  unsigned arg_top_blocks = bv.blockman_.top_block_size();
4738  top_blocks = blockman_.reserve_top_blocks(arg_top_blocks);
4739 
4740 
4741  bm::word_t*** blk_root = blockman_.top_blocks_root();
4742  bm::word_t*** blk_root_arg = bv.blockman_.top_blocks_root();
4743 
4744  for (unsigned i = 0; i < top_blocks; ++i)
4745  {
4746  bm::word_t** blk_blk = blk_root[i];
4747  bm::word_t** blk_blk_arg = (i < arg_top_blocks) ? blk_root_arg[i] : 0;
4748  if (blk_blk == blk_blk_arg || !blk_blk_arg) // nothing to do (0 OR 0 == 0)
4749  continue;
4750  if (!blk_blk && blk_blk_arg) // top block transfer
4751  {
4752  BM_ASSERT(i < arg_top_blocks);
4753 
4754  blk_root[i] = blk_root_arg[i];
4755  blk_root_arg[i] = 0;
4756  continue;
4757  }
4758  if ((bm::word_t*)blk_blk == FULL_BLOCK_FAKE_ADDR)
4759  continue;
4760  if ((bm::word_t*)blk_blk_arg == FULL_BLOCK_FAKE_ADDR)
4761  {
4762  blockman_.deallocate_top_subblock(i);
4763  blk_root[i] = (bm::word_t**)FULL_BLOCK_FAKE_ADDR;
4764  continue;
4765  }
4766 
4767  unsigned j = 0;
4768  bm::word_t* blk;
4769  bm::word_t* arg_blk;
4770  do
4771  {
4772  blk = blk_blk[j]; arg_blk = blk_blk_arg[j];
4773  if (blk != arg_blk)
4774  {
4775  if (!blk && arg_blk) // block transfer
4776  {
4777  blockman_.set_block_ptr(i, j, arg_blk);
4778  bv.blockman_.set_block_ptr(i, j, 0);
4779  }
4780  else // need full OR
4781  {
4782  combine_operation_block_or(i, j, blk, arg_blk);
4783  }
4784  }
4785  } while (++j < bm::set_sub_array_size);
4786  } // for i
4787 }
4788 
4789 //---------------------------------------------------------------------
4790 
4791 template<class Alloc>
4793  const bm::word_t* arg_blk,
4794  bool arg_gap,
4795  bm::operation opcode)
4796 {
4797  unsigned i0, j0;
4798  bm::get_block_coord(nb, i0, j0);
4799  bm::word_t* blk = blockman_.get_block_ptr(i0, j0);
4800 
4801  bool gap = BM_IS_GAP(blk);
4802  combine_operation_with_block(nb, gap, blk, arg_blk, arg_gap, opcode);
4803 }
4804 
4805 //---------------------------------------------------------------------
4806 
4807 template<class Alloc>
4810  const bm::bvector<Alloc>& bv2,
4811  typename bm::bvector<Alloc>::optmode opt_mode)
4812 {
4813  if (blockman_.is_init())
4814  blockman_.deinit_tree();
4815 
4816  if (&bv1 == &bv2)
4817  {
4818  this->bit_or(bv2);
4819  return *this;
4820  }
4821  if (this == &bv1)
4822  {
4823  this->bit_or(bv2);
4824  return *this;
4825  }
4826  if (this == &bv2)
4827  {
4828  this->bit_or(bv1);
4829  return *this;
4830  }
4831 
4832  const blocks_manager_type& bman1 = bv1.get_blocks_manager();
4833  const blocks_manager_type& bman2 = bv2.get_blocks_manager();
4834 
4835  unsigned top_blocks1 = bman1.top_block_size();
4836  unsigned top_blocks2 = bman2.top_block_size();
4837  unsigned top_blocks = (top_blocks2 > top_blocks1) ? top_blocks2 : top_blocks1;
4838  top_blocks = blockman_.reserve_top_blocks(top_blocks);
4839 
4840  size_ = bv1.size_;
4841  if (size_ < bv2.size_)
4842  size_ = bv2.size_;
4843 
4844  bm::word_t*** blk_root_arg1 = bv1.blockman_.top_blocks_root();
4845  if (!blk_root_arg1)
4846  {
4847  this->bit_or(bv2);
4848  return *this;
4849  }
4850  bm::word_t*** blk_root_arg2 = bv2.blockman_.top_blocks_root();
4851  if (!blk_root_arg2)
4852  {
4853  this->bit_or(bv1);
4854  return *this;
4855  }
4856 
4857  for (unsigned i = 0; i < top_blocks; ++i)
4858  {
4859  bm::word_t** blk_blk_arg1 = (i < top_blocks1) ? blk_root_arg1[i] : 0;
4860  bm::word_t** blk_blk_arg2 = (i < top_blocks2) ? blk_root_arg2[i] : 0;
4861 
4862  if (blk_blk_arg1 == blk_blk_arg2)
4863  {
4864  BM_ASSERT(!blk_blk_arg1 || (bm::word_t*)blk_blk_arg1 == FULL_BLOCK_FAKE_ADDR);
4865  bm::word_t*** blk_root = blockman_.top_blocks_root();
4866  blk_root[i] = blk_blk_arg1;
4867  continue;
4868  }
4869  if ((bm::word_t*)blk_blk_arg1 == FULL_BLOCK_FAKE_ADDR ||
4870  (bm::word_t*)blk_blk_arg2 == FULL_BLOCK_FAKE_ADDR)
4871  {
4872  bm::word_t*** blk_root = blockman_.top_blocks_root();
4873  blk_root[i] = (bm::word_t**)FULL_BLOCK_FAKE_ADDR;
4874  continue;
4875  }
4876  bm::word_t** blk_blk = blockman_.alloc_top_subblock(i);
4877  bool any_blocks = false;
4878  unsigned j = 0;
4879  do
4880  {
4881  const bm::word_t* arg_blk1 = blk_blk_arg1 ? blk_blk_arg1[j] : 0;
4882  const bm::word_t* arg_blk2 = blk_blk_arg2 ? blk_blk_arg2[j] : 0;
4883  if (arg_blk1 == arg_blk2 && !arg_blk1)
4884  continue;
4885  bool need_opt = combine_operation_block_or(i, j, arg_blk1, arg_blk2);
4886  if (need_opt && opt_mode == opt_compress)
4887  blockman_.optimize_bit_block(i, j);
4888  any_blocks |= bool(blk_blk[j]);
4889  } while (++j < bm::set_sub_array_size);
4890 
4891  if (!any_blocks)
4892  blockman_.free_top_subblock(i);
4893 
4894  } // for i
4895 
4896  if (opt_mode != opt_none)
4897  blockman_.free_temp_block();
4898 
4899  return *this;
4900 }
4901 
4902 //---------------------------------------------------------------------
4903 
4904 template<class Alloc>
4907  const bm::bvector<Alloc>& bv2,
4908  typename bm::bvector<Alloc>::optmode opt_mode)
4909 {
4910  if (blockman_.is_init())
4911  blockman_.deinit_tree();
4912 
4913  if (&bv1 == &bv2)
4914  return *this; // nothing to do empty result
4915 
4916  if (this == &bv1)
4917  {
4918  this->bit_xor(bv2);
4919  return *this;
4920  }
4921  if (this == &bv2)
4922  {
4923  this->bit_xor(bv1);
4924  return *this;
4925  }
4926 
4927  const blocks_manager_type& bman1 = bv1.get_blocks_manager();
4928  if (!bman1.is_init())
4929  {
4930  *this = bv2;
4931  return *this;
4932  }
4933  const blocks_manager_type& bman2 = bv2.get_blocks_manager();
4934  if (!bman2.is_init())
4935  {
4936  *this = bv1;
4937  return *this;
4938  }
4939 
4940  unsigned top_blocks1 = bman1.top_block_size();
4941  unsigned top_blocks2 = bman2.top_block_size();
4942  unsigned top_blocks = (top_blocks2 > top_blocks1) ? top_blocks2 : top_blocks1;
4943  top_blocks = blockman_.reserve_top_blocks(top_blocks);
4944 
4945  size_ = bv1.size_;
4946  if (size_ < bv2.size_)
4947  size_ = bv2.size_;
4948 
4949  bm::word_t*** blk_root_arg1 = bv1.blockman_.top_blocks_root();
4950  bm::word_t*** blk_root_arg2 = bv2.blockman_.top_blocks_root();
4951 
4952  for (unsigned i = 0; i < top_blocks; ++i)
4953  {
4954  bm::word_t** blk_blk_arg1 = (i < top_blocks1) ? blk_root_arg1[i] : 0;
4955  bm::word_t** blk_blk_arg2 = (i < top_blocks2) ? blk_root_arg2[i] : 0;
4956 
4957  if (blk_blk_arg1 == blk_blk_arg2)
4958  {
4959  if (!blk_blk_arg1)
4960  continue;
4961  BM_ASSERT((bm::word_t*)blk_blk_arg1 == FULL_BLOCK_FAKE_ADDR);
4962  blockman_.deallocate_top_subblock(i);
4963  continue;
4964  }
4965  if ((bm::word_t*)blk_blk_arg1 == FULL_BLOCK_FAKE_ADDR)
4966  {
4967  if (!blk_blk_arg2)
4968  {
4969  set_full_sb:
4970  bm::word_t*** blk_root= blockman_.top_blocks_root();
4971  blk_root[i] = (bm::word_t**)FULL_BLOCK_FAKE_ADDR;
4972  continue;
4973  }
4974  blk_blk_arg1 = FULL_SUB_BLOCK_REAL_ADDR;
4975  }
4976  if ((bm::word_t*)blk_blk_arg2 == FULL_BLOCK_FAKE_ADDR)
4977  {
4978  if (!blk_blk_arg1)
4979  goto set_full_sb;
4980  blk_blk_arg2 = FULL_SUB_BLOCK_REAL_ADDR;
4981  }
4982 
4983  bm::word_t** blk_blk = blockman_.alloc_top_subblock(i);
4984  bool any_blocks = false;
4985  unsigned j = 0;
4986  do
4987  {
4988  const bm::word_t* arg_blk1; const bm::word_t* arg_blk2;
4989  arg_blk1 = blk_blk_arg1 ? blk_blk_arg1[j] : 0;
4990  arg_blk2 = blk_blk_arg2 ? blk_blk_arg2[j] : 0;
4991 
4992  if ((arg_blk1 == arg_blk2) &&
4993  (!arg_blk1 || arg_blk1 == FULL_BLOCK_FAKE_ADDR))
4994  continue; // 0 ^ 0 == 0 , 1 ^ 1 == 0 (nothing to do)
4995 
4996  bool need_opt = combine_operation_block_xor(i, j, arg_blk1, arg_blk2);
4997  if (need_opt && opt_mode == opt_compress)
4998  blockman_.optimize_bit_block(i, j);
4999  any_blocks |= bool(blk_blk[j]);
5000  } while (++j < bm::set_sub_array_size);
5001 
5002  if (!any_blocks)
5003  blockman_.free_top_subblock(i);
5004 
5005  } // for i
5006 
5007  if (opt_mode != opt_none)
5008  blockman_.free_temp_block();
5009 
5010  return *this;
5011 }
5012 
5013 //---------------------------------------------------------------------
5014 
5015 template<class Alloc>
5018  const bm::bvector<Alloc>& bv2,
5019  typename bm::bvector<Alloc>::optmode opt_mode)
5020 {
5021  if (&bv1 == &bv2)
5022  {
5023  this->bit_or(bv1);
5024  return *this;
5025  }
5026  if (this == &bv1)
5027  {
5028  this->bit_and(bv2);
5029  return *this;
5030  }
5031  if (this == &bv2)
5032  {
5033  this->bit_and(bv1);
5034  return *this;
5035  }
5036  if (blockman_.is_init())
5037  blockman_.deinit_tree();
5038 
5039  const blocks_manager_type& bman1 = bv1.get_blocks_manager();
5040  const blocks_manager_type& bman2 = bv2.get_blocks_manager();
5041  if (!bman1.is_init() || !bman2.is_init())
5042  return *this;
5043 
5044  unsigned top_blocks1 = bman1.top_block_size();
5045  unsigned top_blocks2 = bman2.top_block_size();
5046  unsigned top_blocks = (top_blocks2 > top_blocks1) ? top_blocks2 : top_blocks1;
5047  top_blocks = blockman_.reserve_top_blocks(top_blocks);
5048 
5049  size_ = bv1.size_;
5050  if (size_ < bv2.size_)
5051  size_ = bv2.size_;
5052 
5053  bm::word_t*** blk_root_arg1 = bv1.blockman_.top_blocks_root();
5054  bm::word_t*** blk_root_arg2 = bv2.blockman_.top_blocks_root();
5055 
5056  for (unsigned i = 0; i < top_blocks; ++i)
5057  {
5058  bm::word_t** blk_blk_arg1 = (i < top_blocks1) ? blk_root_arg1[i] : 0;
5059  bm::word_t** blk_blk_arg2 = (i < top_blocks2) ? blk_root_arg2[i] : 0;
5060 
5061  if (blk_blk_arg1 == blk_blk_arg2)
5062  {
5063  if (!blk_blk_arg1)
5064  continue; // 0 & 0 == 0
5065  if ((bm::word_t*)blk_blk_arg1 == FULL_BLOCK_FAKE_ADDR)
5066  {
5067  bm::word_t*** blk_root = blockman_.top_blocks_root();
5068  blk_root[i] = (bm::word_t**)FULL_BLOCK_FAKE_ADDR;
5069  continue;
5070  }
5071  }
5072  if ((bm::word_t*)blk_blk_arg1 == FULL_BLOCK_FAKE_ADDR)
5073  blk_blk_arg1 = FULL_SUB_BLOCK_REAL_ADDR;
5074  if ((bm::word_t*)blk_blk_arg2 == FULL_BLOCK_FAKE_ADDR)
5075  blk_blk_arg2 = FULL_SUB_BLOCK_REAL_ADDR;
5076 
5077  bm::word_t** blk_blk = blockman_.alloc_top_subblock(i);
5078  bool any_blocks = false;
5079  unsigned j = 0;
5080  do
5081  {
5082  const bm::word_t* arg_blk1; const bm::word_t* arg_blk2;
5083  arg_blk1 = blk_blk_arg1 ? blk_blk_arg1[j] : 0;
5084  arg_blk2 = blk_blk_arg2 ? blk_blk_arg2[j] : 0;
5085 
5086  if ((arg_blk1 == arg_blk2) && !arg_blk1)
5087  continue; // 0 & 0 == 0
5088 
5089  bool need_opt = combine_operation_block_and(i, j, arg_blk1, arg_blk2);
5090  if (need_opt && opt_mode == opt_compress)
5091  blockman_.optimize_bit_block(i, j);
5092  any_blocks |= bool(blk_blk[j]);
5093  } while (++j < bm::set_sub_array_size);
5094 
5095  if (!any_blocks)
5096  blockman_.free_top_subblock(i);
5097 
5098  } // for i
5099 
5100  if (opt_mode != opt_none)
5101  blockman_.free_temp_block();
5102 
5103  return *this;
5104 }
5105 
5106 
5107 //---------------------------------------------------------------------
5108 
5109 template<class Alloc>
5112  const bm::bvector<Alloc>& bv2,
5113  typename bm::bvector<Alloc>::optmode opt_mode)
5114 {
5115  if (blockman_.is_init())
5116  blockman_.deinit_tree();
5117 
5118  if (&bv1 == &bv2)
5119  return *this; // nothing to do empty result
5120 
5121  if (this == &bv1)
5122  {
5123  this->bit_sub(bv2);
5124  return *this;
5125  }
5126  if (this == &bv2)
5127  {
5128  this->bit_sub(bv1);
5129  return *this;
5130  }
5131 
5132  const blocks_manager_type& bman1 = bv1.get_blocks_manager();
5133  const blocks_manager_type& bman2 = bv2.get_blocks_manager();
5134  if (!bman1.is_init())
5135  {
5136  return *this;
5137  }
5138  if (!bman2.is_init())
5139  {
5140  this->bit_or(bv1);
5141  return *this;
5142  }
5143 
5144  unsigned top_blocks1 = bman1.top_block_size();
5145  unsigned top_blocks2 = bman2.top_block_size();
5146  unsigned top_blocks = (top_blocks2 > top_blocks1) ? top_blocks2 : top_blocks1;
5147  top_blocks = blockman_.reserve_top_blocks(top_blocks);
5148 
5149  size_ = bv1.size_;
5150  if (size_ < bv2.size_)
5151  size_ = bv2.size_;
5152 
5153  bm::word_t*** blk_root_arg1 = bv1.blockman_.top_blocks_root();
5154  bm::word_t*** blk_root_arg2 = bv2.blockman_.top_blocks_root();
5155 
5156  for (unsigned i = 0; i < top_blocks; ++i)
5157  {
5158  bm::word_t** blk_blk_arg1 = (i < top_blocks1) ? blk_root_arg1[i] : 0;
5159  bm::word_t** blk_blk_arg2 = (i < top_blocks2) ? blk_root_arg2[i] : 0;
5160 
5161  if (blk_blk_arg1 == blk_blk_arg2)
5162  continue; // 0 AND NOT 0 == 0
5163  if ((bm::word_t*)blk_blk_arg2 == FULL_BLOCK_FAKE_ADDR)
5164  continue;
5165  if ((bm::word_t*)blk_blk_arg1 == FULL_BLOCK_FAKE_ADDR)
5166  blk_blk_arg1 = FULL_SUB_BLOCK_REAL_ADDR;
5167 
5168  bm::word_t** blk_blk = blockman_.alloc_top_subblock(i);
5169  bool any_blocks = false;
5170  unsigned j = 0;
5171  do
5172  {
5173  const bm::word_t* arg_blk1 = blk_blk_arg1 ? blk_blk_arg1[j] : 0;
5174  const bm::word_t* arg_blk2 = blk_blk_arg2 ? blk_blk_arg2[j] : 0;
5175  if ((arg_blk1 == arg_blk2) && !arg_blk1)
5176  continue; // 0 & ~0 == 0
5177 
5178  bool need_opt = combine_operation_block_sub(i, j, arg_blk1, arg_blk2);
5179  if (need_opt && opt_mode == opt_compress)
5180  blockman_.optimize_bit_block(i, j);
5181  any_blocks |= bool(blk_blk[j]);
5182  } while (++j < bm::set_sub_array_size);
5183 
5184  if (!any_blocks)
5185  blockman_.free_top_subblock(i);
5186 
5187  } // for i
5188 
5189  if (opt_mode != opt_none)
5190  blockman_.free_temp_block();
5191 
5192  return *this;
5193 }
5194 
5195 
5196 //---------------------------------------------------------------------
5197 
5198 #define BM_OR_OP(x) \
5199  { \
5200  blk = blk_blk[j+x]; arg_blk = blk_blk_arg[j+x]; \
5201  if (blk != arg_blk) \
5202  combine_operation_block_or(i, j+x, blk, arg_blk); \
5203  }
5204 
5205 template<class Alloc>
5207 {
5208  if (!bv.blockman_.is_init())
5209  return;
5210 
5211  unsigned top_blocks = blockman_.top_block_size();
5212  if (size_ < bv.size_)
5213  size_ = bv.size_;
5214 
5215  unsigned arg_top_blocks = bv.blockman_.top_block_size();
5216  top_blocks = blockman_.reserve_top_blocks(arg_top_blocks);
5217 
5218  bm::word_t*** blk_root = blockman_.top_blocks_root();
5219  bm::word_t*** blk_root_arg = bv.blockman_.top_blocks_root();
5220 
5221  for (unsigned i = 0; i < top_blocks; ++i)
5222  {
5223  bm::word_t** blk_blk = blk_root[i];
5224  bm::word_t** blk_blk_arg = (i < arg_top_blocks) ? blk_root_arg[i] : 0;
5225  if (blk_blk == blk_blk_arg || !blk_blk_arg) // nothing to do (0 OR 0 == 0)
5226  continue;
5227  if ((bm::word_t*)blk_blk == FULL_BLOCK_FAKE_ADDR)
5228  continue;
5229  if ((bm::word_t*)blk_blk_arg == FULL_BLOCK_FAKE_ADDR)
5230  {
5231  blockman_.deallocate_top_subblock(i);
5232  blk_root[i] = (bm::word_t**)FULL_BLOCK_FAKE_ADDR;
5233  continue;
5234  }
5235  if (!blk_blk)
5236  blk_blk = blockman_.alloc_top_subblock(i);
5237 
5238  unsigned j = 0;
5239  bm::word_t* blk;
5240  const bm::word_t* arg_blk;
5241  do
5242  {
5243  #if defined(BM64_AVX2) || defined(BM64_AVX512)
5244  if (!avx2_test_all_eq_wave2(blk_blk + j, blk_blk_arg + j))
5245  {
5246  BM_OR_OP(0)
5247  BM_OR_OP(1)
5248  BM_OR_OP(2)
5249  BM_OR_OP(3)
5250  }
5251  j += 4;
5252  #elif defined(BM64_SSE4)
5253  if (!sse42_test_all_eq_wave2(blk_blk + j, blk_blk_arg + j))
5254  {
5255  BM_OR_OP(0)
5256  BM_OR_OP(1)
5257  }
5258  j += 2;
5259  #else
5260  BM_OR_OP(0)
5261  ++j;
5262  #endif
5263  } while (j < bm::set_sub_array_size);
5264  } // for i
5265 }
5266 
5267 #undef BM_OR_OP
5268 
5269 //---------------------------------------------------------------------
5270 
5271 #define BM_XOR_OP(x) \
5272  { \
5273  blk = blk_blk[j+x]; arg_blk = blk_blk_arg[j+x]; \
5274  combine_operation_block_xor(i, j+x, blk, arg_blk); \
5275  }
5276 
5277 template<class Alloc>
5279 {
5280  if (!bv.blockman_.is_init())
5281  return;
5282  if (!blockman_.is_init())
5283  {
5284  *this = bv;
5285  return;
5286  }
5287 
5288  unsigned top_blocks = blockman_.top_block_size();
5289  if (size_ < bv.size_) // this vect shorter than the arg.
5290  {
5291  size_ = bv.size_;
5292  }
5293  unsigned arg_top_blocks = bv.blockman_.top_block_size();
5294  top_blocks = blockman_.reserve_top_blocks(arg_top_blocks);
5295 
5296  bm::word_t*** blk_root = blockman_.top_blocks_root();
5297  bm::word_t*** blk_root_arg = bv.blockman_.top_blocks_root();
5298 
5299  for (unsigned i = 0; i < top_blocks; ++i)
5300  {
5301  bm::word_t** blk_blk_arg = (i < arg_top_blocks) ? blk_root_arg[i] : 0;
5302  if (!blk_blk_arg)
5303  continue;
5304  bm::word_t** blk_blk = blk_root[i];
5305  if (blk_blk == blk_blk_arg) // nothing to do (any XOR 0 == 0)
5306  {
5307  if ((bm::word_t*)blk_blk == FULL_BLOCK_FAKE_ADDR)
5308  blk_root[i] = 0;
5309  continue;
5310  }
5311  if ((bm::word_t*)blk_blk == FULL_BLOCK_FAKE_ADDR)
5312  {
5313  if (!blk_blk_arg)
5314  continue;
5315  blk_blk = blockman_.check_alloc_top_subblock(i);
5316  }
5317  if ((bm::word_t*)blk_blk_arg == FULL_BLOCK_FAKE_ADDR)
5318  {
5319  if (!blk_blk)
5320  {
5321  blk_root[i] = (bm::word_t**) FULL_BLOCK_FAKE_ADDR;
5322  continue;
5323  }
5324  blk_blk_arg = FULL_SUB_BLOCK_REAL_ADDR;
5325  }
5326 
5327  if (!blk_blk)
5328  blk_blk = blockman_.alloc_top_subblock(i);
5329 
5330  unsigned j = 0;
5331  bm::word_t* blk;
5332  const bm::word_t* arg_blk;
5333  do
5334  {
5335  #if defined(BM64_AVX2) || defined(BM64_AVX512)
5336  if (!avx2_test_all_zero_wave2(blk_blk + j, blk_blk_arg + j))
5337  {
5338  BM_XOR_OP(0)
5339  BM_XOR_OP(1)
5340  BM_XOR_OP(2)
5341  BM_XOR_OP(3)
5342  }
5343  j += 4;
5344  #elif defined(BM64_SSE4)
5345  if (!sse42_test_all_zero_wave2(blk_blk + j, blk_blk_arg + j))
5346  {
5347  BM_XOR_OP(0)
5348  BM_XOR_OP(1)
5349  }
5350  j += 2;
5351  #else
5352  BM_XOR_OP(0)
5353  ++j;
5354  #endif
5355  } while (j < bm::set_sub_array_size);
5356  } // for i
5357 }
5358 
5359 #undef BM_XOR_OP
5360 
5361 
5362 //---------------------------------------------------------------------
5363 
5364 #define BM_AND_OP(x) if (0 != (blk = blk_blk[j+x])) \
5365  { \
5366  if (0 != (arg_blk = blk_blk_arg[j+x])) \
5367  { \
5368  combine_operation_block_and(i, j+x, blk, arg_blk); \
5369  if (opt_mode == opt_compress) \
5370  blockman_.optimize_bit_block(i, j+x); \
5371  } \
5372  else \
5373  blockman_.zero_block(i, j+x); \
5374  }
5375 
5376 template<class Alloc>
5378  typename bm::bvector<Alloc>::optmode opt_mode)
5379 {
5380  if (!blockman_.is_init())
5381  return; // nothing to do, already empty
5382  if (!bv.blockman_.is_init())
5383  {
5384  clear(true);
5385  return;
5386  }
5387 
5388  unsigned top_blocks = blockman_.top_block_size();
5389  if (size_ < bv.size_) // this vect shorter than the arg.
5390  size_ = bv.size_;
5391 
5392  unsigned arg_top_blocks = bv.blockman_.top_block_size();
5393  top_blocks = blockman_.reserve_top_blocks(arg_top_blocks);
5394 
5395 
5396  bm::word_t*** blk_root = blockman_.top_blocks_root();
5397  bm::word_t*** blk_root_arg = bv.blockman_.top_blocks_root();
5398 
5399  for (unsigned i = 0; i < top_blocks; ++i)
5400  {
5401  bm::word_t** blk_blk = blk_root[i];
5402  if (!blk_blk) // nothing to do (0 AND 1 == 0)
5403  continue;
5404  bm::word_t** blk_blk_arg = (i < arg_top_blocks) ? blk_root_arg[i] : 0;
5405  if (!blk_blk_arg) // free a whole group of blocks
5406  {
5407  if ((bm::word_t*)blk_blk == FULL_BLOCK_FAKE_ADDR)
5408  {
5409  blk_root[i] = 0;
5410  }
5411  else
5412  {
5413  for (unsigned j = 0; j < bm::set_sub_array_size; ++j)
5414  blockman_.zero_block(i, j);
5415  blockman_.deallocate_top_subblock(i);
5416  }
5417  continue;
5418  }
5419  if ((bm::word_t*)blk_blk_arg == FULL_BLOCK_FAKE_ADDR)
5420  continue; // any & 1 == any
5421 
5422  if ((bm::word_t*)blk_blk == FULL_BLOCK_FAKE_ADDR)
5423  blk_blk = blockman_.check_alloc_top_subblock(i);
5424 
5425  unsigned j = 0;
5426  bm::word_t* blk;
5427  const bm::word_t* arg_blk;
5428  do
5429  {
5430  #if defined(BM64_AVX2) || defined(BM64_AVX512)
5431  if (!avx2_test_all_zero_wave(blk_blk + j))
5432  {
5433  BM_AND_OP(0)
5434  BM_AND_OP(1)
5435  BM_AND_OP(2)
5436  BM_AND_OP(3)
5437  }
5438  j += 4;
5439  #elif defined(BM64_SSE4)
5440  if (!sse42_test_all_zero_wave(blk_blk + j))
5441  {
5442  BM_AND_OP(0)
5443  BM_AND_OP(1)
5444  }
5445  j += 2;
5446  #else
5447  BM_AND_OP(0)
5448  ++j;
5449  #endif
5450  } while (j < bm::set_sub_array_size);
5451  } // for i
5452 }
5453 
5454 #undef BM_AND_OP
5455 
5456 
5457 //---------------------------------------------------------------------
5458 
5459 #define BM_SUB_OP(x) \
5460  if ((0 != (blk = blk_blk[j+x])) && (0 != (arg_blk = blk_blk_arg[j+x]))) \
5461  combine_operation_block_sub(i, j+x, blk, arg_blk);
5462 
5463 
5464 template<class Alloc>
5466 {
5467  if (!blockman_.is_init() || !bv.blockman_.is_init())
5468  return;
5469 
5470  unsigned top_blocks = blockman_.top_block_size();
5471  if (size_ < bv.size_) // this vect shorter than the arg.
5472  size_ = bv.size_;
5473 
5474  unsigned arg_top_blocks = bv.blockman_.top_block_size();
5475  top_blocks = blockman_.reserve_top_blocks(arg_top_blocks);
5476 
5477  bm::word_t*** blk_root = blockman_.top_blocks_root();
5478  bm::word_t*** blk_root_arg = bv.blockman_.top_blocks_root();
5479 
5480  for (unsigned i = 0; i < top_blocks; ++i)
5481  {
5482  bm::word_t** blk_blk = blk_root[i];
5483  bm::word_t** blk_blk_arg = (i < arg_top_blocks) ? blk_root_arg[i] : 0;
5484  if (!blk_blk || !blk_blk_arg) // nothing to do (0 AND NOT 1 == 0)
5485  continue;
5486 
5487  if ((bm::word_t*)blk_blk_arg == FULL_BLOCK_FAKE_ADDR) // zero result
5488  {
5489  blockman_.deallocate_top_subblock(i);
5490  continue;
5491  }
5492  if ((bm::word_t*)blk_blk == FULL_BLOCK_FAKE_ADDR)
5493  blk_blk = blockman_.check_alloc_top_subblock(i);
5494 
5495  bm::word_t* blk;
5496  const bm::word_t* arg_blk;
5497  unsigned j = 0;
5498  do
5499  {
5500  #if defined(BM64_AVX2) || defined(BM64_AVX512)
5501  if (!avx2_test_all_zero_wave(blk_blk + j))
5502  {
5503  BM_SUB_OP(0)
5504  BM_SUB_OP(1)
5505  BM_SUB_OP(2)
5506  BM_SUB_OP(3)
5507  }
5508  j += 4;
5509  #elif defined(BM64_SSE4)
5510  if (!sse42_test_all_zero_wave(blk_blk + j))
5511  {
5512  BM_SUB_OP(0)
5513  BM_SUB_OP(1)
5514  }
5515  j += 2;
5516  #else
5517  BM_SUB_OP(0)
5518  ++j;
5519  #endif
5520  } while (j < bm::set_sub_array_size);
5521  } // for i
5522 }
5523 
5524 #undef BM_SUB_OP
5525 
5526 //---------------------------------------------------------------------
5527 
5528 template<class Alloc>
5530  const bm::bvector<Alloc>& bv,
5531  bm::operation opcode)
5532 {
5533  if (!blockman_.is_init())
5534  {
5535  if (opcode == BM_AND || opcode == BM_SUB)
5536  return;
5537  blockman_.init_tree();
5538  }
5539 
5540  unsigned top_blocks = blockman_.top_block_size();
5541  unsigned arg_top_blocks = bv.blockman_.top_block_size();
5542 
5543  if (arg_top_blocks > top_blocks)
5544  top_blocks = blockman_.reserve_top_blocks(arg_top_blocks);
5545 
5546  if (size_ < bv.size_) // this vect shorter than the arg.
5547  {
5548  size_ = bv.size_;
5549  // stretch our capacity
5550  blockman_.reserve_top_blocks(arg_top_blocks);
5551  top_blocks = blockman_.top_block_size();
5552  }
5553  else
5554  if (size_ > bv.size_) // this vector larger
5555  {
5556  if (opcode == BM_AND) // clear the tail with zeros
5557  {
5558  set_range(bv.size_, size_ - 1, false);
5559  if (arg_top_blocks < top_blocks)
5560  {
5561  // not to scan blocks we already swiped
5562  top_blocks = arg_top_blocks;
5563  }
5564  }
5565  }
5566 
5567  bm::word_t*** blk_root = blockman_.top_blocks_root();
5568  unsigned block_idx = 0;