include/util/bitset/bm.h

Go to the documentation of this file.
00001 #ifndef BM__H__INCLUDED__
00002 #define BM__H__INCLUDED__
00003 /*
00004 Copyright(c) 2002-2009 Anatoliy Kuznetsov(anatoliy_kuznetsov at yahoo.com)
00005 
00006 Permission is hereby granted, free of charge, to any person 
00007 obtaining a copy of this software and associated documentation 
00008 files (the "Software"), to deal in the Software without restriction, 
00009 including without limitation the rights to use, copy, modify, merge, 
00010 publish, distribute, sublicense, and/or sell copies of the Software, 
00011 and to permit persons to whom the Software is furnished to do so, 
00012 subject to the following conditions:
00013 
00014 The above copyright notice and this permission notice shall be included 
00015 in all copies or substantial portions of the Software.
00016 
00017 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 
00018 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 
00019 OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 
00020 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
00021 DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 
00022 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 
00023 OTHER DEALINGS IN THE SOFTWARE.
00024 
00025 For more information please visit:  http://bmagic.sourceforge.net
00026 
00027 */
00028 
00029 
00030 // define BM_NO_STL if you use BM in "STL free" environment and want
00031 // to disable any references to STL headers
00032 #ifndef BM_NO_STL
00033 # include <iterator>
00034 #endif
00035 
00036 #ifdef _MSC_VER
00037 #pragma warning( disable : 4311 4312)
00038 #endif
00039 
00040 
00041 
00042 #include "bmconst.h"
00043 #include "bmdef.h"
00044 
00045 
00046 // Vector based optimizations are incompatible with 64-bit optimization
00047 // which is considered a form of vectorization
00048 
00049 #ifdef BMSSE42OPT
00050 # undef BMSSE2OPT
00051 # undef BM64OPT
00052 # define BMVECTOPT
00053 # include "bmsse4.h"
00054 #endif
00055 
00056 #ifdef BMSSE2OPT
00057 # undef BM64OPT
00058 # define BMVECTOPT
00059 # include "bmsse2.h"
00060 #endif
00061 
00062 #include "bmfwd.h"
00063 #include "bmfunc.h"
00064 #include "bmvmin.h"
00065 #include "encoding.h"
00066 #include "bmalloc.h"
00067 #include "bmblocks.h"
00068 
00069 namespace bm
00070 {
00071 
00072 
00073 #ifdef BMCOUNTOPT
00074 
00075 # define BMCOUNT_INC ++count_;
00076 # define BMCOUNT_DEC --count_;
00077 # define BMCOUNT_VALID(x) count_is_valid_ = x;
00078 # define BMCOUNT_SET(x) count_ = x; count_is_valid_ = true;
00079 # define BMCOUNT_ADJ(x) if (x) ++count_; else --count_;
00080 
00081 #else
00082 
00083 # define BMCOUNT_INC
00084 # define BMCOUNT_DEC
00085 # define BMCOUNT_VALID(x)
00086 # define BMCOUNT_SET(x)
00087 # define BMCOUNT_ADJ(x)
00088 
00089 #endif
00090 
00091 
00092 
00093 typedef bm::miniset<bm::block_allocator, bm::set_total_blocks> mem_save_set;
00094 
00095 
00096 /** @defgroup bmagic BitMagic C++ Library
00097  *  For more information please visit:  http://bmagic.sourceforge.net
00098  *  
00099  */
00100 
00101 
00102 /** @defgroup bvector The Main bvector<> Group
00103  *  This is the main group. It includes bvector template: front end of the bm library.
00104  *  @ingroup bmagic 
00105  */
00106 
00107 
00108 
00109 
00110 /*!
00111    @brief bitvector with runtime compression of bits.
00112    @ingroup bvector
00113 */
00114 
00115 template<class Alloc, class MS> 
00116 class bvector
00117 {
00118 public:
00119 
00120     typedef Alloc  allocator_type;
00121     typedef blocks_manager<Alloc, MS>  blocks_manager_type;
00122     /** Type used to count bits in the bit vector */
00123     typedef bm::id_t                   size_type; 
00124 
00125     /** Statistical information about bitset's memory allocation details. */
00126     struct statistics : public bv_statistics
00127     {};
00128 
00129     /**
00130         @brief Class reference implements an object for bit assignment.
00131         Since C++ does not provide with build-in bit type supporting l-value 
00132         operations we have to emulate it.
00133 
00134         @ingroup bvector
00135     */
00136     class reference
00137     {
00138     public:
00139         reference(bvector<Alloc, MS>& bv, bm::id_t position) 
00140         : bv_(bv),
00141           position_(position)
00142         {}
00143 
00144         reference(const reference& ref)
00145         : bv_(ref.bv_), 
00146           position_(ref.position_)
00147         {
00148             bv_.set(position_, ref.bv_.get_bit(position_));
00149         }
00150         
00151         operator bool() const
00152         {
00153             return bv_.get_bit(position_);
00154         }
00155 
00156         const reference& operator=(const reference& ref) const
00157         {
00158             bv_.set(position_, (bool)ref);
00159             return *this;
00160         }
00161 
00162         const reference& operator=(bool value) const
00163         {
00164             bv_.set(position_, value);
00165             return *this;
00166         }
00167 
00168         bool operator==(const reference& ref) const
00169         {
00170             return bool(*this) == bool(ref);
00171         }
00172 
00173         /*! Bitwise AND. Performs operation: bit = bit AND value */
00174         const reference& operator&=(bool value) const
00175         {
00176             bv_.set_bit_and(position_, value);
00177             return *this;
00178         }
00179 
00180         /*! Bitwise OR. Performs operation: bit = bit OR value */
00181         const reference& operator|=(bool value) const
00182         {
00183             if (value != bv_.get_bit(position_))
00184             {
00185                 bv_.set_bit(position_);
00186             }
00187             return *this;
00188         }
00189 
00190         /*! Bitwise exclusive-OR (XOR). Performs operation: bit = bit XOR value */
00191         const reference& operator^=(bool value) const
00192         {
00193             bv_.set(position_, value != bv_.get_bit(position_));
00194             return *this;
00195         }
00196 
00197         /*! Logical Not operator */
00198         bool operator!() const
00199         {
00200             return !bv_.get_bit(position_);
00201         }
00202 
00203         /*! Bit Not operator */
00204         bool operator~() const
00205         {
00206             return !bv_.get_bit(position_);
00207         }
00208 
00209         /*! Negates the bit value */
00210         reference& flip()
00211         {
00212             bv_.flip(position_);
00213             return *this;
00214         }
00215 
00216     private:
00217         bvector<Alloc, MS>& bv_;       //!< Reference variable on the parent.
00218         bm::id_t            position_; //!< Position in the parent bitvector.
00219     };
00220 
00221     typedef bool const_reference;
00222 
00223     /*!
00224         @brief Base class for all iterators.
00225         @ingroup bvector
00226     */
00227     class iterator_base
00228     {
00229     friend class bvector;
00230     public:
00231         iterator_base() : bv_(0), position_(bm::id_max), block_(0) {}
00232 
00233         bool operator==(const iterator_base& it) const
00234         {
00235             return (position_ == it.position_) && (bv_ == it.bv_);
00236         }
00237 
00238         bool operator!=(const iterator_base& it) const
00239         {
00240             return ! operator==(it);
00241         }
00242 
00243         bool operator < (const iterator_base& it) const
00244         {
00245             return position_ < it.position_;
00246         }
00247 
00248         bool operator <= (const iterator_base& it) const
00249         {
00250             return position_ <= it.position_;
00251         }
00252 
00253         bool operator > (const iterator_base& it) const
00254         {
00255             return position_ > it.position_;
00256         }
00257 
00258         bool operator >= (const iterator_base& it) const
00259         {
00260             return position_ >= it.position_;
00261         }
00262 
00263         /**
00264            \fn bool bm::bvector::iterator_base::valid() const
00265            \brief Checks if iterator is still valid. Analog of != 0 comparison for pointers.
00266            \returns true if iterator is valid.
00267         */
00268         bool valid() const
00269         {
00270             return position_ != bm::id_max;
00271         }
00272 
00273         /**
00274            \fn bool bm::bvector::iterator_base::invalidate() 
00275            \brief Turns iterator into an invalid state.
00276         */
00277         void invalidate()
00278         {
00279             position_ = bm::id_max;
00280         }
00281 
00282     public:
00283 
00284         /** Information about current bitblock. */
00285         struct bitblock_descr
00286         {
00287             const bm::word_t*   ptr;      //!< Word pointer.
00288             unsigned            bits[32]; //!< Unpacked list of ON bits
00289             unsigned            idx;      //!< Current position in the bit list
00290             unsigned            cnt;      //!< Number of ON bits
00291             bm::id_t            pos;      //!< Last bit position before 
00292         };
00293 
00294         /** Information about current DGAP block. */
00295         struct dgap_descr
00296         {
00297             const gap_word_t*   ptr;       //!< Word pointer.
00298             gap_word_t          gap_len;   //!< Current dgap length.
00299         };
00300 
00301     protected:
00302         bm::bvector<Alloc, MS>* bv_;         //!< Pointer on parent bitvector
00303         bm::id_t                position_;   //!< Bit position (bit idx)
00304         const bm::word_t*       block_;      //!< Block pointer.(NULL-invalid)
00305         unsigned                block_type_; //!< Type of block. 0-Bit, 1-GAP
00306         unsigned                block_idx_;  //!< Block index
00307 
00308         /*! Block type dependent information for current block. */
00309         union block_descr
00310         {
00311             bitblock_descr   bit_;  //!< BitBlock related info.
00312             dgap_descr       gap_;  //!< DGAP block related info.
00313         } bdescr_;
00314     };
00315 
00316     /*!
00317         @brief Output iterator iterator designed to set "ON" bits based on
00318         input sequence of integers (bit indeces).
00319 
00320         STL container can be converted to bvector using this iterator
00321         Insert iterator guarantees the vector will be dynamically resized
00322         (set_bit does not do that).
00323 
00324         @note
00325         If you have many bits to set it is a good idea to use output iterator
00326         instead of explicitly calling set, because iterator may implement
00327         some performance specific tricks to make sure bulk insert is fast.
00328 
00329         @ingroup bvector
00330     */
00331     class insert_iterator
00332     {
00333     public:
00334 #ifndef BM_NO_STL
00335         typedef std::output_iterator_tag  iterator_category;
00336 #endif
00337         typedef unsigned value_type;
00338         typedef void difference_type;
00339         typedef void pointer;
00340         typedef void reference;
00341 
00342         insert_iterator(bvector<Alloc, MS>& bvect)
00343             : bvect_(bvect), 
00344               max_bit_(bvect.size())
00345         {
00346         }
00347         
00348         insert_iterator& operator=(bm::id_t n)
00349         {
00350             BM_ASSERT(n < bm::id_max);
00351 
00352             if (n >= max_bit_) 
00353             {
00354                 max_bit_ = n;
00355                 if (n >= bvect_.size()) 
00356                 {
00357                     bvect_.resize(n + 1);
00358                 }
00359             }
00360 
00361             bvect_.set(n);
00362             return *this;
00363         }
00364         
00365         /*! Returns *this without doing anything (no-op) */
00366         insert_iterator& operator*() { return *this; }
00367         /*! Returns *this. This iterator does not move (no-op) */
00368         insert_iterator& operator++() { return *this; }
00369         /*! Returns *this. This iterator does not move (no-op)*/
00370         insert_iterator& operator++(int) { return *this; }
00371         
00372     protected:
00373         bm::bvector<Alloc, MS>&   bvect_;
00374         bm::id_t                  max_bit_;
00375     };
00376 
00377     /*!
00378         @brief Constant input iterator designed to enumerate "ON" bits
00379         @ingroup bvector
00380     */
00381     class enumerator : public iterator_base
00382     {
00383     public:
00384 #ifndef BM_NO_STL
00385         typedef std::input_iterator_tag  iterator_category;
00386 #endif
00387         typedef unsigned   value_type;
00388         typedef unsigned   difference_type;
00389         typedef unsigned*  pointer;
00390         typedef unsigned&  reference;
00391 
00392     public:
00393         enumerator() : iterator_base() {}
00394         enumerator(const bvector<Alloc, MS>* bvect, int position)
00395             : iterator_base()
00396         { 
00397             this->bv_ = const_cast<bvector<Alloc, MS>*>(bvect);
00398             if (position == 0)
00399             {
00400                 go_first();
00401             }
00402             else
00403             {
00404                 this->invalidate();
00405             }
00406         }
00407 
00408         bm::id_t operator*() const
00409         { 
00410             return this->position_; 
00411         }
00412 
00413         enumerator& operator++()
00414         {
00415             return this->go_up();
00416         }
00417 
00418         enumerator operator++(int)
00419         {
00420             enumerator tmp = *this;
00421             this->go_up();
00422             return tmp;
00423         }
00424 
00425 
00426         void go_first()
00427         {
00428             BM_ASSERT(this->bv_);
00429 
00430         #ifdef BMCOUNTOPT
00431             if (this->bv_->count_is_valid_ && 
00432                 this->bv_->count_ == 0)
00433             {
00434                 this->invalidate();
00435                 return;
00436             }
00437         #endif
00438 
00439             blocks_manager_type* bman = &(this->bv_->blockman_);
00440             bm::word_t*** blk_root = bman->blocks_root();
00441 
00442             this->block_idx_ = this->position_= 0;
00443             unsigned i, j;
00444 
00445             for (i = 0; i < bman->top_block_size(); ++i)
00446             {
00447                 bm::word_t** blk_blk = blk_root[i];
00448 
00449                 if (blk_blk == 0) // not allocated
00450                 {
00451                     this->block_idx_ += bm::set_array_size;
00452                     this->position_ += bm::bits_in_array;
00453                     continue;
00454                 }
00455 
00456 
00457                 for (j = 0; j < bm::set_array_size; ++j,++(this->block_idx_))
00458                 {
00459                     this->block_ = blk_blk[j];
00460 
00461                     if (this->block_ == 0)
00462                     {
00463                         this->position_ += bits_in_block;
00464                         continue;
00465                     }
00466 
00467                     if (BM_IS_GAP((*bman), this->block_, this->block_idx_))
00468                     {
00469                         this->block_type_ = 1;
00470                         if (search_in_gapblock())
00471                         {
00472                             return;
00473                         }
00474                     }
00475                     else
00476                     {
00477                         this->block_type_ = 0;
00478                         if (search_in_bitblock())
00479                         {
00480                             return;
00481                         }
00482                     }
00483             
00484                 } // for j
00485 
00486             } // for i
00487 
00488             this->invalidate();
00489         }
00490 
00491         enumerator& go_up()
00492         {
00493             // Current block search.
00494             ++this->position_;
00495             typedef typename iterator_base::block_descr block_descr_type;
00496             
00497             block_descr_type* bdescr = &(this->bdescr_);
00498 
00499             switch (this->block_type_)
00500             {
00501             case 0:   //  BitBlock
00502                 {
00503 
00504                 // check if we can get the value from the 
00505                 // bits cache
00506 
00507                 unsigned idx = ++(bdescr->bit_.idx);
00508                 if (idx < bdescr->bit_.cnt)
00509                 {
00510                     this->position_ = bdescr->bit_.pos + 
00511                                       bdescr->bit_.bits[idx];
00512                     return *this; 
00513                 }
00514                 this->position_ += 31 - bdescr->bit_.bits[--idx];
00515 
00516                 const bm::word_t* pend = this->block_ + bm::set_block_size;
00517 
00518                 while (++(bdescr->bit_.ptr) < pend)
00519                 {
00520                     bm::word_t w = *(bdescr->bit_.ptr);
00521                     if (w)
00522                     {
00523                         bdescr->bit_.idx = 0;
00524                         bdescr->bit_.pos = this->position_;
00525                         bdescr->bit_.cnt = bm::bit_list_4(w, bdescr->bit_.bits); 
00526                         this->position_ += bdescr->bit_.bits[0];
00527                         return *this;
00528                     }
00529                     else
00530                     {
00531                         this->position_ += 32;
00532                     }
00533                 }
00534     
00535                 }
00536                 break;
00537 
00538             case 1:   // DGAP Block
00539                 {
00540                     if (--(bdescr->gap_.gap_len))
00541                     {
00542                         return *this;
00543                     }
00544 
00545                     // next gap is "OFF" by definition.
00546                     if (*(bdescr->gap_.ptr) == bm::gap_max_bits - 1)
00547                     {
00548                         break;
00549                     }
00550                     gap_word_t prev = *(bdescr->gap_.ptr);
00551                     register unsigned val = *(++(bdescr->gap_.ptr));
00552 
00553                     this->position_ += val - prev;
00554                     // next gap is now "ON"
00555 
00556                     if (*(bdescr->gap_.ptr) == bm::gap_max_bits - 1)
00557                     {
00558                         break;
00559                     }
00560                     prev = *(bdescr->gap_.ptr);
00561                     val = *(++(bdescr->gap_.ptr));
00562                     bdescr->gap_.gap_len = val - prev;
00563                     return *this;  // next "ON" found;
00564                 }
00565 
00566             default:
00567                 BM_ASSERT(0);
00568 
00569             } // switch
00570 
00571 
00572             // next bit not present in the current block
00573             // keep looking in the next blocks.
00574             ++(this->block_idx_);
00575             unsigned i = this->block_idx_ >> bm::set_array_shift;
00576             unsigned top_block_size = this->bv_->blockman_.top_block_size();
00577             for (; i < top_block_size; ++i)
00578             {
00579                 bm::word_t** blk_blk = this->bv_->blockman_.blocks_root()[i];
00580                 if (blk_blk == 0)
00581                 {
00582                     this->block_idx_ += bm::set_array_size;
00583                     this->position_ += bm::bits_in_array;
00584                     continue;
00585                 }
00586 
00587                 unsigned j = this->block_idx_ & bm::set_array_mask;
00588 
00589                 for(; j < bm::set_array_size; ++j, ++(this->block_idx_))
00590                 {
00591                     this->block_ = blk_blk[j];
00592 
00593                     if (this->block_ == 0)
00594                     {
00595                         this->position_ += bm::bits_in_block;
00596                         continue;
00597                     }
00598 
00599                     if (BM_IS_GAP((this->bv_->blockman_), 
00600                                    this->block_, 
00601                                    this->block_idx_))
00602                     {
00603                         this->block_type_ = 1;
00604                         if (search_in_gapblock())
00605                         {
00606                             return *this;
00607                         }
00608                     }
00609                     else
00610                     {
00611                         this->block_type_ = 0;
00612                         if (search_in_bitblock())
00613                         {
00614                             return *this;
00615                         }
00616                     }
00617 
00618             
00619                 } // for j
00620 
00621             } // for i
00622 
00623 
00624             this->invalidate();
00625             return *this;
00626         }
00627 
00628 
00629     private:
00630         bool search_in_bitblock()
00631         {
00632             BM_ASSERT(this->block_type_ == 0);
00633             
00634             typedef typename iterator_base::block_descr block_descr_type;
00635             block_descr_type* bdescr = &(this->bdescr_);            
00636 
00637             // now lets find the first bit in block.
00638             bdescr->bit_.ptr = this->block_;
00639 
00640             const word_t* ptr_end = this->block_ + bm::set_block_size;
00641 
00642             do
00643             {
00644                 register bm::word_t w = *(bdescr->bit_.ptr);
00645 
00646                 if (w)  
00647                 {
00648                     bdescr->bit_.idx = 0;
00649                     bdescr->bit_.pos = this->position_;
00650                     bdescr->bit_.cnt = 
00651                               bm::bit_list_4(w, bdescr->bit_.bits);
00652                     this->position_ += bdescr->bit_.bits[0];
00653 
00654                     return true;
00655                 }
00656                 else
00657                 {
00658                     this->position_ += 32;
00659                 }
00660 
00661             } 
00662             while (++(bdescr->bit_.ptr) < ptr_end);
00663 
00664             return false;
00665         }
00666 
00667         bool search_in_gapblock()
00668         {
00669             BM_ASSERT(this->block_type_ == 1);
00670 
00671             typedef typename iterator_base::block_descr block_descr_type;
00672             block_descr_type* bdescr = &(this->bdescr_);            
00673 
00674             bdescr->gap_.ptr = BMGAP_PTR(this->block_);
00675             unsigned bitval = *(bdescr->gap_.ptr) & 1;
00676 
00677             ++(bdescr->gap_.ptr);
00678 
00679             do
00680             {
00681                 register unsigned val = *(bdescr->gap_.ptr);
00682 
00683                 if (bitval)
00684                 {
00685                     gap_word_t* first = BMGAP_PTR(this->block_) + 1;
00686                     if (bdescr->gap_.ptr == first)
00687                     {
00688                         bdescr->gap_.gap_len = val + 1;
00689                     }
00690                     else
00691                     {
00692                         bdescr->gap_.gap_len = 
00693                              val - *(bdescr->gap_.ptr-1);
00694                     }
00695            
00696                     return true;
00697                 }
00698                 this->position_ += val + 1;
00699 
00700                 if (val == bm::gap_max_bits - 1)
00701                 {
00702                     break;
00703                 }
00704 
00705                 bitval ^= 1;
00706                 ++(bdescr->gap_.ptr);
00707 
00708             } while (1);
00709 
00710             return false;
00711         }
00712 
00713     };
00714     
00715     /*!
00716         @brief Constant input iterator designed to enumerate "ON" bits
00717         counted_enumerator keeps bitcount, ie number of ON bits starting
00718         from the position 0 in the bit string up to the currently enumerated bit
00719         
00720         When increment operator called current position is increased by 1.
00721         
00722         @ingroup bvector
00723     */
00724     class counted_enumerator : public enumerator
00725     {
00726     public:
00727 #ifndef BM_NO_STL
00728         typedef std::input_iterator_tag  iterator_category;
00729 #endif
00730         counted_enumerator() : bit_count_(0){}
00731         
00732         counted_enumerator(const enumerator& en)
00733         : enumerator(en)
00734         {
00735             if (this->valid())
00736                 bit_count_ = 1;
00737         }
00738         
00739         counted_enumerator& operator=(const enumerator& en)
00740         {
00741             enumerator* me = this;
00742             *me = en;
00743             if (this->valid())
00744                 this->bit_count_ = 1;
00745             return *this;
00746         }
00747         
00748         counted_enumerator& operator++()
00749         {
00750             this->go_up();
00751             if (this->valid())
00752                 ++(this->bit_count_);
00753             return *this;
00754         }
00755 
00756         counted_enumerator operator++(int)
00757         {
00758             counted_enumerator tmp(*this);
00759             this->go_up();
00760             if (this->valid())
00761                 ++bit_count_;
00762             return tmp;
00763         }
00764         
00765         /*! @brief Number of bits ON starting from the .
00766         
00767             Method returns number of ON bits fromn the bit 0 to the current bit 
00768             For the first bit in bitvector it is 1, for the second 2 
00769         */
00770         bm::id_t count() const { return bit_count_; }
00771         
00772     private:
00773         bm::id_t   bit_count_;
00774     };
00775 
00776     friend class iterator_base;
00777     friend class enumerator;
00778 
00779 public:
00780 
00781 #ifdef BMCOUNTOPT
00782     bvector(strategy          strat      = BM_BIT,
00783             const gap_word_t* glevel_len = bm::gap_len_table<true>::_len,
00784             size_type         bv_size    = bm::id_max,
00785             const Alloc&      alloc      = Alloc()) 
00786     : count_(0),
00787       count_is_valid_(true),
00788       blockman_(glevel_len, bv_size, alloc),
00789       new_blocks_strat_(strat),
00790       size_(bv_size)
00791     {}
00792 
00793     bvector(size_type         bv_size,
00794             bm::strategy      strat      = BM_BIT,
00795             const gap_word_t* glevel_len = bm::gap_len_table<true>::_len,
00796             const Alloc&      alloc = Alloc()) 
00797     : count_(0),
00798       count_is_valid_(true),
00799       blockman_(glevel_len, bv_size, alloc),
00800       new_blocks_strat_(strat),
00801       size_(bv_size)
00802     {}
00803 
00804 
00805     bvector(const bm::bvector<Alloc, MS>& bvect)
00806      : count_(bvect.count_),
00807        count_is_valid_(bvect.count_is_valid_),
00808        blockman_(bvect.blockman_),
00809        new_blocks_strat_(bvect.new_blocks_strat_),
00810        size_(bvect.size_)
00811     {}
00812 
00813 #else
00814     /*!
00815         \brief Constructs bvector class
00816         \param strat - operation mode strategy, 
00817                        BM_BIT - default strategy, bvector use plain bitset 
00818                        blocks, (performance oriented strategy).
00819                        BM_GAP - memory effitent strategy, bvector allocates 
00820                        blocks as array of intervals(gaps) and convert blocks 
00821                        into plain bitsets only when enthropy grows.
00822         \param glevel_len 
00823            - pointer on C-style array keeping GAP block sizes. 
00824             (Put bm::gap_len_table_min<true>::_len for GAP memory saving mode)
00825         \param bv_size 
00826           - bvector size (number of bits addressable by bvector), bm::id_max means 
00827           "no limits" (recommended). 
00828           bit vector allocates this space dynamically on demand.
00829 
00830         \sa bm::gap_len_table bm::gap_len_table_min set_new_blocks_strat
00831     */
00832     bvector(strategy          strat      = BM_BIT,
00833             const gap_word_t* glevel_len = bm::gap_len_table<true>::_len,
00834             size_type         bv_size    = bm::id_max,
00835             const Alloc&      alloc      = Alloc()) 
00836     : blockman_(glevel_len, bv_size, alloc),
00837       new_blocks_strat_(strat),
00838       size_(bv_size)
00839     {}
00840 
00841     /*!
00842         \brief Constructs bvector class
00843     */
00844     bvector(size_type         bv_size,
00845             strategy          strat      = BM_BIT,
00846             const gap_word_t* glevel_len = bm::gap_len_table<true>::_len,
00847             const Alloc&      alloc      = Alloc()) 
00848     : blockman_(glevel_len, bv_size, alloc),
00849       new_blocks_strat_(strat),
00850       size_(bv_size)
00851     {}
00852 
00853 
00854     bvector(const bvector<Alloc, MS>& bvect)
00855         :  blockman_(bvect.blockman_),
00856            new_blocks_strat_(bvect.new_blocks_strat_),
00857            size_(bvect.size_)
00858     {}
00859 
00860 #endif
00861 
00862     bvector& operator=(const bvector<Alloc, MS>& bvect)
00863     {
00864         clear(true); // memory free cleaning
00865         resize(bvect.size());
00866         bit_or(bvect);
00867         return *this;
00868     }
00869 
00870     reference operator[](bm::id_t n)
00871     {
00872         BM_ASSERT(n < size_);
00873         return reference(*this, n);
00874     }
00875 
00876 
00877     bool operator[](bm::id_t n) const
00878     {
00879         BM_ASSERT(n < size_);
00880         return get_bit(n);
00881     }
00882 
00883     void operator &= (const bvector<Alloc, MS>& bvect)
00884     {
00885         bit_and(bvect);
00886     }
00887 
00888     void operator ^= (const bvector<Alloc, MS>& bvect)
00889     {
00890         bit_xor(bvect);
00891     }
00892 
00893     void operator |= (const bvector<Alloc, MS>& bvect)
00894     {
00895         bit_or(bvect);
00896     }
00897 
00898     void operator -= (const bvector<Alloc, MS>& bvect)
00899     {
00900         bit_sub(bvect);
00901     }
00902 
00903     bool operator < (const bvector<Alloc, MS>& bvect) const
00904     {
00905         return compare(bvect) < 0;
00906     }
00907 
00908     bool operator <= (const bvector<Alloc, MS>& bvect) const
00909     {
00910         return compare(bvect) <= 0;
00911     }
00912 
00913     bool operator > (const bvector<Alloc, MS>& bvect) const
00914     {
00915         return compare(bvect) > 0;
00916     }
00917 
00918     bool operator >= (const bvector<Alloc, MS>& bvect) const
00919     {
00920         return compare(bvect) >= 0;
00921     }
00922 
00923     bool operator == (const bvector<Alloc, MS>& bvect) const
00924     {
00925         return compare(bvect) == 0;
00926     }
00927 
00928     bool operator != (const bvector<Alloc, MS>& bvect) const
00929     {
00930         return compare(bvect) != 0;
00931     }
00932 
00933     bvector<Alloc, MS> operator~() const
00934     {
00935         return bvector<Alloc, MS>(*this).invert();
00936     }
00937     
00938     Alloc get_allocator() const
00939     {
00940         return blockman_.get_allocator();
00941     }
00942 
00943 
00944     /*!
00945        \brief Sets bit n.
00946        \param n - index of the bit to be set. 
00947        \param val - new bit value
00948        \return  TRUE if bit was changed
00949     */
00950     bool set_bit(bm::id_t n, bool val = true)
00951     {
00952         BM_ASSERT(n < size_);
00953         return set_bit_no_check(n, val);
00954     }
00955 
00956     /*!
00957        \brief Sets bit n using bit AND with the provided value.
00958        \param n - index of the bit to be set. 
00959        \param val - new bit value
00960        \return  TRUE if bit was changed
00961     */
00962     bool set_bit_and(bm::id_t n, bool val = true)
00963     {
00964         BM_ASSERT(n < size_);
00965         return and_bit_no_check(n, val);
00966     }
00967 
00968     /*!
00969        \brief Sets bit n only if current value is equal to the condition
00970        \param n - index of the bit to be set. 
00971        \param val - new bit value
00972        \param condition - expected current value
00973        \return TRUE if bit was changed
00974     */
00975     bool set_bit_conditional(bm::id_t n, bool val, bool condition)
00976     {
00977         BM_ASSERT(n < size_);
00978         if (val == condition) return false;
00979         return set_bit_conditional_impl(n, val, condition);
00980     }
00981 
00982 
00983     /*!
00984         \brief Sets bit n if val is true, clears bit n if val is false
00985         \param n - index of the bit to be set
00986         \param val - new bit value
00987         \return *this
00988     */
00989     bvector<Alloc, MS>& set(bm::id_t n, bool val = true)
00990     {
00991         set_bit(n, val);
00992         return *this;
00993     }
00994 
00995 
00996 
00997     /*!
00998        \brief Sets every bit in this bitset to 1.
00999        \return *this
01000     */
01001     bvector<Alloc, MS>& set()
01002     {
01003         BMCOUNT_VALID(false)
01004         set_range(0, size_ - 1, true);
01005         return *this;
01006     }
01007 
01008 
01009     /*!
01010         \brief Sets all bits in the specified closed interval [left,right]
01011         Interval must be inside the bvector's size. 
01012         This method DOES NOT resize vector.
01013         
01014         \param left  - interval start
01015         \param right - interval end (closed interval)
01016         \param value - value to set interval in
01017         
01018         \return *this
01019     */
01020     bvector<Alloc, MS>& set_range(bm::id_t left,
01021                                   bm::id_t right,
01022                                   bool     value = true);
01023 
01024     
01025     /*! Function erturns insert iterator for this bitvector */
01026     insert_iterator inserter()
01027     {
01028         return insert_iterator(*this);
01029     }
01030 
01031 
01032     /*!
01033        \brief Clears bit n.
01034        \param n - bit's index to be cleaned.
01035     */
01036     void clear_bit(bm::id_t n)
01037     {
01038         set(n, false);
01039     }
01040 
01041 
01042     /*!
01043        \brief Clears every bit in the bitvector.
01044 
01045        \param free_mem if "true" (default) bvector frees the memory,
01046        otherwise sets blocks to 0.
01047     */
01048     void clear(bool free_mem = false)
01049     {
01050         blockman_.set_all_zero(free_mem);
01051         BMCOUNT_SET(0);
01052     }
01053 
01054     /*!
01055        \brief Clears every bit in the bitvector.
01056        \return *this;
01057     */
01058     bvector<Alloc, MS>& reset()
01059     {
01060         clear();
01061         return *this;
01062     }
01063 
01064 
01065     /*!
01066        \brief Returns count of bits which are 1.
01067        \return Total number of bits ON. 
01068     */
01069     bm::id_t count() const;
01070 
01071     /**
01072         \brief Returns bvector's capacity (number of bits it can store)
01073     */
01074     size_type capacity() const 
01075     {
01076         return blockman_.capacity();
01077     }
01078 
01079     /*!
01080         \brief return current size of the vector (bits)
01081     */
01082     size_type size() const 
01083     {
01084         return size_;
01085     }
01086 
01087     /*!
01088         \brief Change size of the bvector
01089         \param new_size - new size in bits
01090     */
01091     void resize(size_type new_size);
01092 
01093     /*! \brief Computes bitcount values for all bvector blocks
01094         \param arr - pointer on array of block bit counts
01095         \return Index of the last block counted. 
01096         This number +1 gives you number of arr elements initialized during the
01097         function call.
01098     */
01099     unsigned count_blocks(unsigned* arr) const
01100     {
01101         bm::word_t*** blk_root = blockman_.get_rootblock();
01102         typename blocks_manager_type::block_count_arr_func func(blockman_, &(arr[0]));
01103         for_each_nzblock(blk_root, blockman_.effective_top_block_size(), 
01104                                    bm::set_array_size, func);
01105         return func.last_block();
01106     }
01107 
01108     /*!
01109        \brief Returns count of 1 bits in the given diapason.
01110        \param left - index of first bit start counting from
01111        \param right - index of last bit 
01112        \param block_count_arr - optional parameter (bitcount by bvector blocks)
01113               calculated by count_blocks method. Used to improve performance of
01114               wide range searches
01115        \return Total number of bits ON. 
01116     */
01117     bm::id_t count_range(bm::id_t left, 
01118                          bm::id_t right, 
01119                          unsigned* block_count_arr=0) const;
01120 
01121 
01122     bm::id_t recalc_count()
01123     {
01124         BMCOUNT_VALID(false)
01125         return count();
01126     }
01127     
01128     /*!
01129         Disables count cache. Next call to count() or recalc_count()
01130         restores count caching.
01131         
01132         @note Works only if BMCOUNTOPT enabled(defined). 
01133         Othewise does nothing.
01134     */
01135     void forget_count()
01136     {
01137         BMCOUNT_VALID(false)    
01138     }
01139 
01140     /*!
01141         \brief Inverts all bits.
01142     */
01143     bvector<Alloc, MS>& invert();
01144 
01145 
01146     /*!
01147        \brief returns true if bit n is set and false is bit n is 0. 
01148        \param n - Index of the bit to check.
01149        \return Bit value (1 or 0)
01150     */
01151     bool get_bit(bm::id_t n) const;
01152 
01153     /*!
01154        \brief returns true if bit n is set and false is bit n is 0. 
01155        \param n - Index of the bit to check.
01156        \return Bit value (1 or 0)
01157     */
01158     bool test(bm::id_t n) const 
01159     { 
01160         return get_bit(n); 
01161     }
01162 
01163     /*!
01164        \brief Returns true if any bits in this bitset are set, and otherwise returns false.
01165        \return true if any bit is set
01166     */
01167     bool any() const
01168     {
01169     #ifdef BMCOUNTOPT
01170         if (count_is_valid_ && count_) return true;
01171     #endif
01172         
01173         word_t*** blk_root = blockman_.get_rootblock();
01174         if (!blk_root) 
01175             return false;
01176         typename blocks_manager_type::block_any_func func(blockman_);
01177         return for_each_nzblock_if(blk_root, 
01178                                    blockman_.effective_top_block_size(),
01179                                    bm::set_array_size, 
01180                                    func);
01181     }
01182 
01183     /*!
01184         \brief Returns true if no bits are set, otherwise returns false.
01185     */
01186     bool none() const
01187     {
01188         return !any();
01189     }
01190 
01191     /*!
01192        \brief Flips bit n
01193        \return *this
01194     */
01195     bvector<Alloc, MS>& flip(bm::id_t n) 
01196     {
01197         set(n, !get_bit(n));
01198         return *this;
01199     }
01200 
01201     /*!
01202        \brief Flips all bits
01203        \return *this
01204     */
01205     bvector<Alloc, MS>& flip() 
01206     {
01207         return invert();
01208     }
01209 
01210     /*! \brief Exchanges content of bv and this bitvector.
01211     */
01212     void swap(bvector<Alloc, MS>& bv)
01213     {
01214         if (this != &bv) 
01215         {
01216             blockman_.swap(bv.blockman_);
01217             bm::xor_swap(size_,bv.size_);
01218     #ifdef BMCOUNTOPT
01219             BMCOUNT_VALID(false)
01220             bv.recalc_count();
01221     #endif
01222         }
01223     }
01224 
01225 
01226     /*!
01227        \fn bm::id_t bvector::get_first() const
01228        \brief Gets number of first bit which is ON.
01229        \return Index of the first 1 bit.
01230        \sa get_next, extract_next
01231     */
01232     bm::id_t get_first() const { return check_or_next(0); }
01233 
01234     /*!
01235        \fn bm::id_t bvector::get_next(bm::id_t prev) const
01236        \brief Finds the number of the next bit ON.
01237        \param prev - Index of the previously found bit. 
01238        \return Index of the next bit which is ON or 0 if not found.
01239        \sa get_first, extract_next
01240     */
01241     bm::id_t get_next(bm::id_t prev) const
01242     {
01243         return (++prev == bm::id_max) ? 0 : check_or_next(prev);
01244     }
01245 
01246     /*!
01247        \fn bm::id_t bvector::extract_next(bm::id_t prev)
01248        \brief Finds the number of the next bit ON and sets it to 0.
01249        \param prev - Index of the previously found bit. 
01250        \return Index of the next bit which is ON or 0 if not found.
01251        \sa get_first, get_next, 
01252     */
01253     bm::id_t extract_next(bm::id_t prev)
01254     {
01255         return (++prev == bm::id_max) ? 0 : check_or_next_extract(prev);
01256     }
01257 
01258 
01259     /*!
01260        @brief Calculates bitvector statistics.
01261 
01262        @param st - pointer on statistics structure to be filled in. 
01263 
01264        Function fills statistics structure containing information about how 
01265        this vector uses memory and estimation of max. amount of memory 
01266        bvector needs to serialize itself.
01267 
01268        @sa statistics
01269     */
01270     void calc_stat(struct bm::bvector<Alloc, MS>::statistics* st) const;
01271 
01272     /*!
01273        \brief Logical OR operation.
01274        \param vect - Argument vector.
01275     */
01276     bm::bvector<Alloc, MS>& bit_or(const  bm::bvector<Alloc, MS>& vect)
01277     {
01278         BMCOUNT_VALID(false);
01279         combine_operation(vect, BM_OR);
01280         return *this;
01281     }
01282 
01283     /*!
01284        \brief Logical AND operation.
01285        \param vect - Argument vector.
01286     */
01287     bm::bvector<Alloc, MS>& bit_and(const bm::bvector<Alloc, MS>& vect)
01288     {
01289         BMCOUNT_VALID(false);
01290         combine_operation(vect, BM_AND);
01291         return *this;
01292     }
01293 
01294     /*!
01295        \brief Logical XOR operation.
01296        \param vect - Argument vector.
01297     */
01298     bm::bvector<Alloc, MS>& bit_xor(const bm::bvector<Alloc, MS>& vect)
01299     {
01300         BMCOUNT_VALID(false);
01301         combine_operation(vect, BM_XOR);
01302         return *this;
01303     }
01304 
01305     /*!
01306        \brief Logical SUB operation.
01307        \param vect - Argument vector.
01308     */
01309     bm::bvector<Alloc, MS>& bit_sub(const bm::bvector<Alloc, MS>& vect)
01310     {
01311         BMCOUNT_VALID(false);
01312         combine_operation(vect, BM_SUB);
01313         return *this;
01314     }
01315 
01316 
01317     /*!
01318        \brief Sets new blocks allocation strategy.
01319        \param strat - Strategy code 0 - bitblocks allocation only.
01320                       1 - Blocks mutation mode (adaptive algorithm)
01321     */
01322     void set_new_blocks_strat(strategy strat) 
01323     { 
01324         new_blocks_strat_ = strat; 
01325     }
01326 
01327     /*!
01328        \brief Returns blocks allocation strategy.
01329        \return - Strategy code 0 - bitblocks allocation only.
01330                  1 - Blocks mutation mode (adaptive algorithm)
01331        \sa set_new_blocks_strat
01332     */
01333     strategy  get_new_blocks_strat() const 
01334     { 
01335         return new_blocks_strat_; 
01336     }
01337 
01338 
01339     /*! 
01340         \brief Optimization mode
01341         Every next level means additional checks (better compression vs time)
01342         \sa optimize
01343     */
01344     enum optmode
01345     {
01346         opt_free_0    = 1, ///< Free unused 0 blocks
01347         opt_free_01   = 2, ///< Free unused 0 and 1 blocks
01348         opt_compress  = 3  ///< compress blocks when possible
01349     };
01350 
01351     /*!
01352        \brief Optimize memory bitvector's memory allocation.
01353    
01354        Function analyze all blocks in the bitvector, compresses blocks 
01355        with a regular structure, frees some memory. This function is recommended
01356        after a bulk modification of the bitvector using set_bit, clear_bit or
01357        logical operations.
01358 
01359        Optionally function can calculate vector post optimization statistics
01360        
01361        @sa optmode, optimize_gap_size
01362     */
01363     void optimize(bm::word_t* temp_block = 0, 
01364                   optmode opt_mode       = opt_compress,
01365                   statistics* stat       = 0);
01366 
01367     /*!
01368        \brief Optimize sizes of GAP blocks
01369 
01370        This method runs an analysis to find optimal GAP levels for the 
01371        specific vector. Current GAP compression algorithm uses several fixed
01372        GAP sizes. By default bvector uses some reasonable preset. 
01373     */
01374     void optimize_gap_size();
01375 
01376 
01377     /*!
01378         @brief Sets new GAP lengths table. All GAP blocks will be reallocated 
01379         to match the new scheme.
01380 
01381         @param glevel_len - pointer on C-style array keeping GAP block sizes. 
01382     */
01383     void set_gap_levels(const gap_word_t* glevel_len);
01384 
01385     /*!
01386         \brief Lexicographical comparison with a bitvector.
01387 
01388         Function compares current bitvector with the provided argument 
01389         bit by bit and returns -1 if our bitvector less than the argument, 
01390         1 - greater, 0 - equal.
01391     */
01392     int compare(const bvector<Alloc, MS>& bvect) const;
01393 
01394     /*! @brief Allocates temporary block of memory. 
01395 
01396         Temp block can be passed to bvector functions requiring some temp memory
01397         for their operation. (like serialize)
01398         
01399         @note method is marked const, but it's not quite true, since
01400         it can in some cases modify the state of the block allocator
01401         (if it has a state). (Can be important in MT programs).
01402 
01403         @sa free_tempblock
01404     */
01405     bm::word_t* allocate_tempblock() const
01406     {
01407         blocks_manager_type* bm = 
01408             const_cast<blocks_manager_type*>(&blockman_);
01409         return bm->get_allocator().alloc_bit_block();
01410     }
01411 
01412     /*! @brief Frees temporary block of memory. 
01413 
01414         @note method is marked const, but it's not quite true, since
01415         it can in some cases modify the state of the block allocator
01416         (if it has a state). (Can be important in MT programs).
01417 
01418         @sa allocate_tempblock
01419     */
01420     void free_tempblock(bm::word_t* block) const
01421     {
01422         blocks_manager_type* bm = 
01423             const_cast<blocks_manager_type*>(&blockman_);
01424         bm->get_allocator().free_bit_block(block);
01425     }
01426 
01427     /**
01428        \brief Returns enumerator pointing on the first non-zero bit.
01429     */
01430     enumerator first() const
01431     {
01432         typedef typename bvector<Alloc, MS>::enumerator enumerator_type;
01433         return enumerator_type(this, 0);
01434     }
01435 
01436     /**
01437        \fn bvector::enumerator bvector::end() const
01438        \brief Returns enumerator pointing on the next bit after the last.
01439     */
01440     enumerator end() const
01441     {
01442         typedef typename bvector<Alloc, MS>::enumerator enumerator_type;
01443         return enumerator_type(this, 1);
01444     }
01445 
01446 
01447     const bm::word_t* get_block(unsigned nb) const 
01448     { 
01449         return blockman_.get_block(nb); 
01450     }
01451     
01452     void combine_operation(const bm::bvector<Alloc, MS>& bvect, 
01453                             bm::operation                opcode);
01454     
01455 private:
01456 
01457     bm::id_t check_or_next(bm::id_t prev) const;
01458     
01459     /// check if specified bit is 1, and set it to 0
01460     /// if specified bit is 0, scan for the next 1 and returns it
01461     /// if no 1 found returns 0
01462     bm::id_t check_or_next_extract(bm::id_t prev);
01463 
01464     /**
01465         \brief Set specified bit without checking preconditions (size, etc)
01466     */
01467     bool set_bit_no_check(bm::id_t n, bool val);
01468 
01469     /**
01470         \brief AND specified bit without checking preconditions (size, etc)
01471     */
01472     bool and_bit_no_check(bm::id_t n, bool val);
01473 
01474     bool set_bit_conditional_impl(bm::id_t n, bool val, bool condition);
01475 
01476 
01477     void combine_operation_with_block(unsigned nb,
01478                                       unsigned gap,
01479                                       bm::word_t* blk,
01480                                       const bm::word_t* arg_blk,
01481                                       int arg_gap,
01482                                       bm::operation opcode);
01483 public:
01484     void combine_operation_with_block(unsigned nb,
01485                                       const bm::word_t* arg_blk,
01486                                       int arg_gap,
01487                                       bm::operation opcode)
01488     {
01489         bm::word_t* blk = const_cast<bm::word_t*>(get_block(nb));
01490         bool gap = BM_IS_GAP((*this), blk, nb);
01491         combine_operation_with_block(nb, gap, blk, arg_blk, arg_gap, opcode);
01492     }
01493 private:
01494     void combine_count_operation_with_block(unsigned nb,
01495                                             const bm::word_t* arg_blk,
01496                                             int arg_gap,
01497                                             bm::operation opcode)
01498     {
01499         const bm::word_t* blk = get_block(nb);
01500         bool gap = BM_IS_GAP((*this), blk, nb);
01501         combine_count_operation_with_block(nb, gap, blk, arg_blk, arg_gap, opcode);
01502     }
01503 
01504 
01505     /**
01506        \brief Extends GAP block to the next level or converts it to bit block.
01507        \param nb - Block's linear index.
01508        \param blk - Blocks's pointer 
01509     */
01510     void extend_gap_block(unsigned nb, gap_word_t* blk)
01511     {
01512         blockman_.extend_gap_block(nb, blk);
01513     }
01514 
01515     /**
01516        \brief Set range without validity checking
01517     */
01518     void set_range_no_check(bm::id_t left,
01519                             bm::id_t right,
01520                             bool     value);
01521 public:
01522 
01523     const blocks_manager_type& get_blocks_manager() const
01524     {
01525         return blockman_;
01526     }
01527 
01528     blocks_manager_type& get_blocks_manager()
01529     {
01530         return blockman_;
01531     }
01532 
01533 
01534 private:
01535 
01536 // This block defines two additional hidden variables used for bitcount
01537 // optimization, in rare cases can make bitvector thread unsafe.
01538 #ifdef BMCOUNTOPT
01539     mutable id_t      count_;            //!< number of 1 bits in the vector
01540     mutable bool      count_is_valid_;   //!< actualization flag
01541 #endif
01542 
01543     blocks_manager_type  blockman_;         //!< bitblocks manager
01544     strategy             new_blocks_strat_; //!< block allocation strategy
01545     size_type            size_;             //!< size in bits
01546 };
01547 
01548 
01549 
01550 
01551 
01552 //---------------------------------------------------------------------
01553 
01554 template<class Alloc, class MS> 
01555 inline bvector<Alloc, MS> operator& (const bvector<Alloc, MS>& v1,
01556                                      const bvector<Alloc, MS>& v2)
01557 {
01558 #ifdef BM_USE_EXPLICIT_TEMP
01559     bvector<Alloc, MS> ret(v1);
01560     ret.bit_and(v2);
01561     return ret;
01562 #else    
01563     return bvector<Alloc, MS>(v1).bit_and(v2);
01564 #endif
01565 }
01566 
01567 //---------------------------------------------------------------------
01568 
01569 template<class Alloc, class MS> 
01570 inline bvector<Alloc, MS> operator| (const bvector<Alloc, MS>& v1,
01571                                      const bvector<Alloc>& v2)
01572 {
01573 #ifdef BM_USE_EXPLICIT_TEMP
01574     bvector<Alloc, MS> ret(v1);
01575     ret.bit_or(v2);
01576     return ret;
01577 #else    
01578     return bvector<Alloc, MS>(v1).bit_or(v2);
01579 #endif
01580 }
01581 
01582 //---------------------------------------------------------------------
01583 
01584 template<class Alloc, class MS> 
01585 inline bvector<Alloc, MS> operator^ (const bvector<Alloc, MS>& v1,
01586                                      const bvector<Alloc, MS>& v2)
01587 {
01588 #ifdef BM_USE_EXPLICIT_TEMP
01589     bvector<Alloc, MS> ret(v1);
01590     ret.bit_xor(v2);
01591     return ret;
01592 #else    
01593     return bvector<Alloc, MS>(v1).bit_xor(v2);
01594 #endif
01595 }
01596 
01597 //---------------------------------------------------------------------
01598 
01599 template<class Alloc, class MS> 
01600 inline bvector<Alloc, MS> operator- (const bvector<Alloc, MS>& v1,
01601                                      const bvector<Alloc, MS>& v2)
01602 {
01603 #ifdef BM_USE_EXPLICIT_TEMP
01604     bvector<Alloc, MS> ret(v1);
01605     ret.bit_sub(v2);
01606     return ret;
01607 #else    
01608     return bvector<Alloc, MS>(v1).bit_sub(v2);
01609 #endif
01610 }
01611 
01612 
01613 
01614 
01615 // -----------------------------------------------------------------------
01616 
01617 template<typename Alloc, typename MS> 
01618 bvector<Alloc, MS>& bvector<Alloc, MS>::set_range(bm::id_t left,
01619                                                   bm::id_t right,
01620                                                   bool     value)
01621 {
01622     if (right < left)
01623     {
01624         return set_range(right, left, value);
01625     }
01626 
01627     BM_ASSERT(left < size_);
01628     BM_ASSERT(right < size_);
01629 
01630     BMCOUNT_VALID(false)
01631     BM_SET_MMX_GUARD
01632 
01633     set_range_no_check(left, right, value);
01634 
01635     return *this;
01636 }
01637 
01638 // -----------------------------------------------------------------------
01639 
01640 template<typename Alloc, typename MS> 
01641 bm::id_t bvector<Alloc, MS>::count() const
01642 {
01643 #ifdef BMCOUNTOPT
01644     if (count_is_valid_) return count_;
01645 #endif
01646     word_t*** blk_root = blockman_.get_rootblock();
01647     if (!blk_root) 
01648     {
01649         BMCOUNT_SET(0);
01650         return 0;
01651     }    
01652     typename blocks_manager_type::block_count_func func(blockman_);
01653     for_each_nzblock(blk_root, blockman_.effective_top_block_size(), 
01654                                 bm::set_array_size, func);
01655 
01656     BMCOUNT_SET(func.count());
01657     return func.count();
01658 }
01659 
01660 // -----------------------------------------------------------------------
01661 
01662 template<typename Alloc, typename MS> 
01663 void bvector<Alloc, MS>::resize(size_type new_size)
01664 {
01665     if (size_ == new_size) return; // nothing to do
01666     if (size_ < new_size) // size grows 
01667     {
01668         blockman_.reserve(new_size);
01669         size_ = new_size;
01670     }
01671     else // shrink
01672     {
01673         set_range(new_size, size_ - 1, false); // clear the tail
01674         size_ = new_size;
01675     }
01676 }
01677 
01678 // -----------------------------------------------------------------------
01679 
01680 template<typename Alloc, typename MS> 
01681 bm::id_t bvector<Alloc, MS>::count_range(bm::id_t left, 
01682                                          bm::id_t right, 
01683                                          unsigned* block_count_arr) const
01684 {
01685     BM_ASSERT(left <= right);
01686 
01687     unsigned count = 0;
01688 
01689     // calculate logical number of start and destination blocks
01690     unsigned nblock_left  = unsigned(left  >>  bm::set_block_shift);
01691     unsigned nblock_right = unsigned(right >>  bm::set_block_shift);
01692 
01693     const bm::word_t* block = blockman_.get_block(nblock_left);
01694     bool left_gap = BM_IS_GAP(blockman_, block, nblock_left);
01695 
01696     unsigned nbit_left  = unsigned(left  & bm::set_block_mask); 
01697     unsigned nbit_right = unsigned(right & bm::set_block_mask); 
01698 
01699     unsigned r = 
01700         (nblock_left == nblock_right) ? nbit_right : (bm::bits_in_block-1);
01701 
01702     typename blocks_manager_type::block_count_func func(blockman_);
01703 
01704     if (block)
01705     {
01706         if ((nbit_left == 0) && (r == (bm::bits_in_block-1))) // whole block
01707         {
01708             if (block_count_arr)
01709             {
01710                 count += block_count_arr[nblock_left];
01711             }
01712             else
01713             {
01714                 func(block, nblock_left);
01715             }
01716         }
01717         else
01718         {
01719             if (left_gap)
01720             {
01721                 count += gap_bit_count_range(BMGAP_PTR(block), 
01722                                             (gap_word_t)nbit_left,
01723                                             (gap_word_t)r);
01724             }
01725             else
01726             {
01727                 count += bit_block_calc_count_range(block, nbit_left, r);
01728             }
01729         }
01730     }
01731 
01732     if (nblock_left == nblock_right)  // in one block
01733     {
01734         return count + func.count();
01735     }
01736 
01737     for (unsigned nb = nblock_left+1; nb < nblock_right; ++nb)
01738     {
01739         block = blockman_.get_block(nb);
01740         if (block_count_arr)
01741         {
01742             count += block_count_arr[nb];
01743         }
01744         else 
01745         {
01746             if (block)
01747                 func(block, nb);
01748         }
01749     }
01750     count += func.count();
01751 
01752     block = blockman_.get_block(nblock_right);
01753     bool right_gap = BM_IS_GAP(blockman_, block, nblock_right);
01754 
01755     if (block)
01756     {
01757         if (right_gap)
01758         {
01759             count += gap_bit_count_range(BMGAP_PTR(block),
01760                                         (gap_word_t)0,
01761                                         (gap_word_t)nbit_right);
01762         }
01763         else
01764         {
01765             count += bit_block_calc_count_range(block, 0, nbit_right);
01766         }
01767     }
01768 
01769     return count;
01770 }
01771 
01772 // -----------------------------------------------------------------------
01773 
01774 template<typename Alloc, typename MS>
01775 bvector<Alloc, MS>& bvector<Alloc, MS>::invert()
01776 {
01777     BMCOUNT_VALID(false)
01778     BM_SET_MMX_GUARD
01779 
01780     bm::word_t*** blk_root = blockman_.get_rootblock();
01781     typename blocks_manager_type::block_invert_func func(blockman_);    
01782     for_each_block(blk_root, blockman_.top_block_size(),
01783                                 bm::set_array_size, func);
01784     if (size_ == bm::id_max) 
01785     {
01786         set_bit_no_check(bm::id_max, false);
01787     } 
01788     else
01789     {
01790         set_range_no_check(size_, bm::id_max, false);
01791     }
01792 
01793     return *this;
01794 }
01795 
01796 // -----------------------------------------------------------------------
01797 
01798 template<typename Alloc, typename MS> 
01799 bool bvector<Alloc, MS>::get_bit(bm::id_t n) const
01800 {    
01801     BM_ASSERT(n < size_);
01802 
01803     // calculate logical block number
01804     unsigned nblock = unsigned(n >>  bm::set_block_shift); 
01805 
01806     const bm::word_t* block = blockman_.get_block(nblock);
01807 
01808     if (block)
01809     {
01810         // calculate word number in block and bit
01811         unsigned nbit = unsigned(n & bm::set_block_mask); 
01812         unsigned is_set;
01813 
01814         if (BM_IS_GAP(blockman_, block, nblock))
01815         {
01816             is_set = gap_test(BMGAP_PTR(block), nbit);
01817         }
01818         else 
01819         {
01820             unsigned nword  = unsigned(nbit >> bm::set_word_shift); 
01821             nbit &= bm::set_word_mask;
01822 
01823             is_set = (block[nword] & (((bm::word_t)1) << nbit));
01824         }
01825         return is_set != 0;
01826     }
01827     return false;
01828 }
01829 
01830 // -----------------------------------------------------------------------
01831 
01832 template<typename Alloc, typename MS> 
01833 void bvector<Alloc, MS>::optimize(bm::word_t* temp_block, 
01834                                   optmode     opt_mode,
01835                                   statistics* stat)
01836 {
01837     word_t*** blk_root = blockman_.blocks_root();
01838 
01839     if (!temp_block)
01840         temp_block = blockman_.check_allocate_tempblock();
01841 
01842     typename 
01843         blocks_manager_type::block_opt_func  opt_func(blockman_, 
01844                                                 temp_block, 
01845                                                 (int)opt_mode,
01846                                                 stat);
01847     if (stat)
01848     {
01849         stat->bit_blocks = stat->gap_blocks 
01850                          = stat->max_serialize_mem 
01851                          = stat->memory_used 
01852                          = 0;
01853         ::memcpy(stat->gap_levels, 
01854                 blockman_.glen(), sizeof(gap_word_t) * bm::gap_levels);
01855         stat->max_serialize_mem = sizeof(id_t) * 4;
01856 
01857     }
01858 
01859     for_each_nzblock(blk_root, blockman_.effective_top_block_size(),
01860                                bm::set_array_size, opt_func);
01861 
01862     if (stat)
01863     {
01864         unsigned safe_inc = stat->max_serialize_mem / 10; // 10% increment
01865         if (!safe_inc) safe_inc = 256;
01866         stat->max_serialize_mem += safe_inc;
01867         stat->memory_used += sizeof(*this) - sizeof(blockman_);
01868         stat->memory_used += blockman_.mem_used();
01869     }
01870 }
01871 
01872 // -----------------------------------------------------------------------
01873 
01874 template<typename Alloc, typename MS> 
01875 void bvector<Alloc, MS>::optimize_gap_size()
01876 {
01877     struct bvector<Alloc, MS>::statistics st;
01878     calc_stat(&st);
01879 
01880     if (!st.gap_blocks)
01881         return;
01882 
01883     gap_word_t opt_glen[bm::gap_levels];
01884     ::memcpy(opt_glen, st.gap_levels, bm::gap_levels * sizeof(*opt_glen));
01885 
01886     improve_gap_levels(st.gap_length, 
01887                             st.gap_length + st.gap_blocks, 
01888                             opt_glen);
01889     
01890     set_gap_levels(opt_glen);
01891 }
01892 
01893 // -----------------------------------------------------------------------
01894 
01895 template<typename Alloc, typename MS> 
01896 void bvector<Alloc, MS>::set_gap_levels(const gap_word_t* glevel_len)
01897 {
01898     word_t*** blk_root = blockman_.blocks_root();
01899 
01900     typename 
01901         blocks_manager_type::gap_level_func  gl_func(blockman_, glevel_len);
01902 
01903     for_each_nzblock(blk_root, blockman_.top_block_size(),
01904                                 bm::set_array_size, gl_func);
01905 
01906     blockman_.set_glen(glevel_len);
01907 }
01908 
01909 // -----------------------------------------------------------------------
01910 
01911 template<typename Alloc, typename MS> 
01912 int bvector<Alloc, MS>::compare(const bvector<Alloc, MS>& bvect) const
01913 {
01914     int res;
01915     unsigned bn = 0;
01916 
01917     unsigned top_blocks = blockman_.effective_top_block_size();
01918     unsigned bvect_top_blocks = bvect.blockman_.effective_top_block_size();
01919 
01920     if (bvect_top_blocks > top_blocks) top_blocks = bvect_top_blocks;
01921 
01922     for (unsigned i = 0; i < top_blocks; ++i)
01923     {
01924         const bm::word_t* const* blk_blk = blockman_.get_topblock(i);
01925         const bm::word_t* const* arg_blk_blk = 
01926                                 bvect.blockman_.get_topblock(i);
01927 
01928         if (blk_blk == arg_blk_blk) 
01929         {
01930             bn += bm::set_array_size;
01931             continue;
01932         }
01933 
01934         for (unsigned j = 0; j < bm::set_array_size; ++j, ++bn)
01935         {
01936             const bm::word_t* arg_blk = arg_blk_blk ? arg_blk_blk[j] : 0;
01937             const bm::word_t* blk = blk_blk ? blk_blk[j] : 0;
01938             if (blk == arg_blk) continue;
01939 
01940             // If one block is zero we check if the other one has at least 
01941             // one bit ON
01942 
01943             if (!blk || !arg_blk)  
01944             {
01945                 const bm::word_t*  pblk;
01946                 bool is_gap;
01947 
01948                 if (blk)
01949                 {
01950                     pblk = blk;
01951                     res = 1;
01952                     is_gap = BM_IS_GAP((*this), blk, bn);
01953                 }
01954                 else
01955                 {
01956                     pblk = arg_blk;
01957                     res = -1;
01958                     is_gap = BM_IS_GAP(bvect, arg_blk, bn);
01959                 }
01960 
01961                 if (is_gap)
01962                 {
01963                     if (!gap_is_all_zero(BMGAP_PTR(pblk), bm::gap_max_bits))
01964                     {
01965                         return res;
01966                     }
01967                 }
01968                 else
01969                 {
01970                     bm::wordop_t* blk1 = (wordop_t*)pblk;
01971                     bm::wordop_t* blk2 = 
01972                         (wordop_t*)(pblk + bm::set_block_size);
01973                     if (!bit_is_all_zero(blk1, blk2))
01974                     {
01975                         return res;
01976                     }
01977                 }
01978 
01979                 continue;
01980             }
01981 
01982             bool arg_gap = BM_IS_GAP(bvect, arg_blk, bn);
01983             bool gap = BM_IS_GAP((*this), blk, bn);
01984 
01985             if (arg_gap != gap)
01986             {
01987                 bm::wordop_t temp_blk[bm::set_block_size_op]; 
01988                 bm::wordop_t* blk1;
01989                 bm::wordop_t* blk2;
01990 
01991                 if (gap)
01992                 {
01993                     gap_convert_to_bitset((bm::word_t*)temp_blk, 
01994                                             BMGAP_PTR(blk));
01995 
01996                     blk1 = (bm::wordop_t*)temp_blk;
01997                     blk2 = (bm::wordop_t*)arg_blk;
01998                 }
01999                 else
02000                 {
02001                     gap_convert_to_bitset((bm::word_t*)temp_blk, 
02002                                             BMGAP_PTR(arg_blk));
02003 
02004                     blk1 = (bm::wordop_t*)blk;
02005                     blk2 = (bm::wordop_t*)temp_blk;
02006 
02007                 }                        
02008                 res = bitcmp(blk1, blk2, bm::set_block_size_op);  
02009 
02010             }
02011             else
02012             {
02013                 if (gap)
02014                 {
02015                     res = gapcmp(BMGAP_PTR(blk), BMGAP_PTR(arg_blk));
02016                 }
02017                 else
02018                 {
02019                     res = bitcmp((bm::wordop_t*)blk, 
02020                                     (bm::wordop_t*)arg_blk, 
02021                                     bm::set_block_size_op);
02022                 }
02023             }
02024 
02025             if (res != 0)
02026             {
02027                 return res;
02028             }
02029         
02030 
02031         } // for j
02032 
02033     } // for i
02034 
02035     return 0;
02036 }
02037 
02038 
02039 // -----------------------------------------------------------------------
02040 
02041 template<typename Alloc, typename MS> 
02042 void bvector<Alloc, MS>::calc_stat(struct bvector<Alloc, MS>::statistics* st) const
02043 {
02044     st->bit_blocks = st->gap_blocks 
02045                    = st->max_serialize_mem 
02046                    = st->memory_used = 0;
02047 
02048     ::memcpy(st->gap_levels, 
02049              blockman_.glen(), sizeof(gap_word_t) * bm::gap_levels);
02050 
02051     unsigned empty_blocks = 0;
02052     unsigned blocks_memory = 0;
02053     gap_word_t* gapl_ptr = st->gap_length;
02054 
02055     st->max_serialize_mem = sizeof(id_t) * 4;
02056 
02057     unsigned block_idx = 0;
02058 
02059     unsigned top_size = blockman_.effective_top_block_size();
02060     // Walk the blocks, calculate statistics.
02061     for (unsigned i = 0; i < top_size; ++i)
02062     {
02063         const bm::word_t* const* blk_blk = blockman_.get_topblock(i);
02064 
02065         if (!blk_blk) 
02066         {
02067             block_idx += bm::set_array_size;
02068             st->max_serialize_mem += sizeof(unsigned) + 1;
02069             continue;
02070         }
02071 
02072         for (unsigned j = 0;j < bm::set_array_size; ++j, ++block_idx)
02073         {
02074             const bm::word_t* blk = blk_blk[j];
02075             if (IS_VALID_ADDR(blk))
02076             {
02077                 st->max_serialize_mem += empty_blocks << 2;
02078                 empty_blocks = 0;
02079 
02080                 if (BM_IS_GAP(blockman_, blk, block_idx)) // gap block
02081                 {
02082                     ++(st->gap_blocks);
02083 
02084                     bm::gap_word_t* gap_blk = BMGAP_PTR(blk);
02085 
02086                     unsigned mem_used = 
02087                         bm::gap_capacity(gap_blk, blockman_.glen()) 
02088                         * sizeof(gap_word_t);
02089 
02090                     *gapl_ptr = gap_length(gap_blk);
02091 
02092                     st->max_serialize_mem += *gapl_ptr * sizeof(gap_word_t);
02093                     blocks_memory += mem_used;
02094 
02095                     ++gapl_ptr;
02096                 }
02097                 else // bit block
02098                 {
02099                     ++(st->bit_blocks);
02100                     unsigned mem_used = sizeof(bm::word_t) * bm::set_block_size;
02101                     st->max_serialize_mem += mem_used;
02102                     blocks_memory += mem_used;
02103                 }
02104             }
02105             else
02106             {
02107                 ++empty_blocks;
02108             }
02109         }
02110     }  
02111 
02112     unsigned safe_inc = st->max_serialize_mem / 10; // 10% increment
02113     if (!safe_inc) safe_inc = 256;
02114     st->max_serialize_mem += safe_inc;
02115 
02116     // Calc size of different odd and temporary things.
02117 
02118     st->memory_used += sizeof(*this) - sizeof(blockman_);
02119     st->memory_used += blockman_.mem_used();
02120     st->memory_used += blocks_memory;
02121 }
02122 
02123 
02124 // -----------------------------------------------------------------------
02125 
02126 
02127 template<class Alloc, class MS> 
02128 bool bvector<Alloc, MS>::set_bit_no_check(bm::id_t n, bool val)
02129 {
02130     // calculate logical block number
02131     unsigned nblock = unsigned(n >>  bm::set_block_shift); 
02132 
02133     int block_type;
02134 
02135     bm::word_t* blk = 
02136         blockman_.check_allocate_block(nblock, 
02137                                         val,
02138                                         get_new_blocks_strat(), 
02139                                         &block_type);
02140 
02141     if (!blk) return false;
02142 
02143     // calculate word number in block and bit
02144     unsigned nbit   = unsigned(n & bm::set_block_mask); 
02145 
02146     if (block_type == 1) // gap
02147     {
02148         unsigned is_set;
02149         unsigned new_block_len;
02150         
02151         new_block_len = 
02152             gap_set_value(val, BMGAP_PTR(blk), nbit, &is_set);
02153         if (is_set)
02154         {
02155             BMCOUNT_ADJ(val)
02156 
02157             unsigned threshold = 
02158             bm::gap_limit(BMGAP_PTR(blk), blockman_.glen());
02159 
02160             if (new_block_len > threshold) 
02161             {
02162                 extend_gap_block(nblock, BMGAP_PTR(blk));
02163             }
02164             return true;
02165         }
02166     }
02167     else  // bit block
02168     {
02169         unsigned nword  = unsigned(nbit >> bm::set_word_shift); 
02170         nbit &= bm::set_word_mask;
02171 
02172         bm::word_t* word = blk + nword;
02173         bm::word_t  mask = (((bm::word_t)1) << nbit);
02174 
02175         if (val)
02176         {
02177             if ( ((*word) & mask) == 0 )
02178             {
02179                 *word |= mask; // set bit
02180                 BMCOUNT_INC;
02181                 return true;
02182             }
02183         }
02184         else
02185         {
02186             if ((*word) & mask)
02187             {
02188                 *word &= ~mask; // clear bit
02189                 BMCOUNT_DEC;
02190                 return true;
02191             }
02192         }
02193     }
02194     return false;
02195 }
02196 
02197 // -----------------------------------------------------------------------
02198 
02199 template<class Alloc, class MS> 
02200 bool bvector<Alloc, MS>::set_bit_conditional_impl(bm::id_t n, 
02201                                                   bool     val, 
02202                                                   bool     condition)
02203 {
02204     // calculate logical block number
02205     unsigned nblock = unsigned(n >>  bm::set_block_shift); 
02206 
02207     int block_type;
02208     bm::word_t* blk = 
02209         blockman_.check_allocate_block(nblock, 
02210                                        val,
02211                                        get_new_blocks_strat(), 
02212                                        &block_type);
02213     if (!blk) 
02214         return false;
02215 
02216     // calculate word number in block and bit
02217     unsigned nbit   = unsigned(n & bm::set_block_mask); 
02218 
02219     if (block_type == 1) // gap
02220     {
02221         bm::gap_word_t* gap_blk = BMGAP_PTR(blk);
02222         bool old_val = (gap_test(gap_blk, nbit) != 0);
02223 
02224         if (old_val != condition) 
02225         {
02226             return false;
02227         }
02228 
02229         if (val != old_val)
02230         {
02231             unsigned is_set;
02232             unsigned new_block_len = 
02233                 gap_set_value(val, gap_blk, nbit, &is_set);
02234             BM_ASSERT(is_set);
02235             BMCOUNT_ADJ(val)
02236 
02237             unsigned threshold = 
02238                 bm::gap_limit(gap_blk, blockman_.glen());
02239             if (new_block_len > threshold) 
02240             {
02241                 extend_gap_block(nblock, gap_blk);
02242             }
02243             return true;
02244         }
02245     }
02246     else  // bit block
02247     {
02248         unsigned nword  = unsigned(nbit >> bm::set_word_shift); 
02249         nbit &= bm::set_word_mask;
02250 
02251         bm::word_t* word = blk + nword;
02252         bm::word_t  mask = (((bm::word_t)1) << nbit);
02253         bool is_set = ((*word) & mask) != 0;
02254 
02255         if (is_set != condition)
02256         {
02257             return false;
02258         }
02259         if (is_set != val)    // need to change bit
02260         {
02261             if (val)          // set bit
02262             {
02263                 *word |= mask;
02264                 BMCOUNT_INC;
02265             }
02266             else               // clear bit
02267             {
02268                 *word &= ~mask;
02269                 BMCOUNT_DEC;
02270             }
02271             return true;
02272         }
02273     }
02274     return false;
02275 
02276 }
02277 
02278 // -----------------------------------------------------------------------
02279 
02280 
02281 template<class Alloc, class MS> 
02282 bool bvector<Alloc, MS>::and_bit_no_check(bm::id_t n, bool val)
02283 {
02284     // calculate logical block number
02285     unsigned nblock = unsigned(n >>  bm::set_block_shift); 
02286 
02287     int block_type;
02288     bm::word_t* blk = 
02289         blockman_.check_allocate_block(nblock, 
02290                                        val,
02291                                        get_new_blocks_strat(), 
02292                                        &block_type);
02293     if (!blk) return false;
02294 
02295     // calculate word number in block and bit
02296     unsigned nbit   = unsigned(n & bm::set_block_mask); 
02297 
02298     if (block_type == 1) // gap
02299     {
02300         bm::gap_word_t* gap_blk = BMGAP_PTR(blk);
02301         bool old_val = (gap_test(gap_blk, nbit) != 0);
02302 
02303         bool new_val = val & old_val;
02304         if (new_val != old_val)
02305         {
02306             unsigned is_set;
02307             unsigned new_block_len = 
02308                 gap_set_value(new_val, gap_blk, nbit, &is_set);
02309             BM_ASSERT(is_set);
02310             BMCOUNT_ADJ(val)
02311 
02312             unsigned threshold = 
02313                 bm::gap_limit(gap_blk, blockman_.glen());
02314             if (new_block_len > threshold) 
02315             {
02316                 extend_gap_block(nblock, gap_blk);
02317             }
02318             return true;
02319         }
02320     }
02321     else  // bit block
02322     {
02323         unsigned nword  = unsigned(nbit >> bm::set_word_shift); 
02324         nbit &= bm::set_word_mask;
02325 
02326         bm::word_t* word = blk + nword;
02327         bm::word_t  mask = (((bm::word_t)1) << nbit);
02328         bool is_set = ((*word) & mask) != 0;
02329 
02330         bool new_val = is_set & val;
02331         if (new_val != val)    // need to change bit
02332         {
02333             if (new_val)       // set bit
02334             {
02335                 *word |= mask;
02336                 BMCOUNT_INC;
02337             }
02338             else               // clear bit
02339             {
02340                 *word &= ~mask;
02341                 BMCOUNT_DEC;
02342             }
02343             return true;
02344         }
02345     }
02346     return false;
02347 }
02348 
02349 
02350 //---------------------------------------------------------------------
02351 
02352 template<class Alloc, class MS> 
02353 bm::id_t bvector<Alloc, MS>::check_or_next(bm::id_t prev) const
02354 {
02355     for (;;)
02356     {
02357         unsigned nblock = unsigned(prev >> bm::set_block_shift); 
02358         if (nblock >= bm::set_total_blocks) 
02359             break;
02360 
02361         if (blockman_.is_subblock_null(nblock >> bm::set_array_shift))
02362         {
02363             prev += (bm::set_blkblk_mask + 1) -
02364                             (prev & bm::set_blkblk_mask);
02365         }
02366         else
02367         {
02368             unsigned nbit = unsigned(prev & bm::set_block_mask);
02369             int no_more_blocks;
02370             const bm::word_t* block = 
02371                 blockman_.get_block(nblock, &no_more_blocks);
02372 
02373             if (no_more_blocks) 
02374             {
02375                 BM_ASSERT(block == 0);
02376                 break;
02377             }
02378 
02379             if (block)
02380             {
02381                 if (IS_FULL_BLOCK(block)) return prev;
02382                 if (BM_IS_GAP(blockman_, block, nblock))
02383                 {
02384                     if (bm::gap_find_in_block(BMGAP_PTR(block),
02385                                                 nbit,
02386                                                 &prev))
02387                     {
02388                         return prev;
02389                     }
02390                 }
02391                 else
02392                 {
02393                     if (bm::bit_find_in_block(block, nbit, &prev)) 
02394                     {
02395                         return prev;
02396                     }
02397                 }
02398             }
02399             else
02400             {
02401                 prev += (bm::set_block_mask + 1) - 
02402                             (prev & bm::set_block_mask);
02403             }
02404 
02405         }
02406         if (!prev) break;
02407     }
02408 
02409     return 0;
02410 }
02411 
02412 
02413 //---------------------------------------------------------------------
02414 
02415 template<class Alloc, class MS> 
02416 bm::id_t bvector<Alloc, MS>::check_or_next_extract(bm::id_t prev)
02417 {
02418     for (;;)
02419     {
02420         unsigned nblock = unsigned(prev >> bm::set_block_shift); 
02421         if (nblock >= bm::set_total_blocks) break;
02422 
02423         if (blockman_.is_subblock_null(nblock >> bm::set_array_shift))
02424         {
02425             prev += (bm::set_blkblk_mask + 1) -
02426                             (prev & bm::set_blkblk_mask);
02427         }
02428         else
02429         {
02430             unsigned nbit = unsigned(prev & bm::set_block_mask);
02431 
02432             int no_more_blocks;
02433             bm::word_t* block = 
02434                 blockman_.get_block(nblock, &no_more_blocks);
02435 
02436             if (no_more_blocks) 
02437             {
02438                 BM_ASSERT(block == 0);
02439                 break;
02440             }
02441 
02442 
02443             if (block)
02444             {
02445                 if (IS_FULL_BLOCK(block))
02446                 {
02447                     set(prev, false);
02448                     return prev;
02449                 }
02450                 if (BM_IS_GAP(blockman_, block, nblock))
02451                 {
02452                     unsigned is_set;
02453                     unsigned new_block_len = 
02454                         gap_set_value(0, BMGAP_PTR(block), nbit, &is_set);
02455                     if (is_set) {
02456                         BMCOUNT_DEC
02457                         unsigned threshold = 
02458                             bm::gap_limit(BMGAP_PTR(block), blockman_.glen());
02459                         if (new_block_len > threshold) 
02460                         {
02461                             extend_gap_block(nblock, BMGAP_PTR(block));
02462                         }
02463                         return prev;
02464                     } else {
02465                         if (bm::gap_find_in_block(BMGAP_PTR(block),
02466                                                     nbit,
02467                                                     &prev))
02468                         {
02469                             set(prev, false);
02470                             return prev;
02471                         }
02472                     }
02473                 }
02474                 else // bit block
02475                 {
02476                     if (bm::bit_find_in_block(block, nbit, &prev)) 
02477                     {
02478                         BMCOUNT_DEC
02479 
02480                         unsigned nbit = 
02481                             unsigned(prev & bm::set_block_mask); 
02482                         unsigned nword = 
02483                             unsigned(nbit >> bm::set_word_shift);
02484                         nbit &= bm::set_word_mask;
02485                         bm::word_t* word = block + nword;
02486                         bm::word_t  mask = ((bm::word_t)1) << nbit;
02487                         *word &= ~mask;
02488 
02489                         return prev;
02490                     }
02491                 }
02492             }
02493             else
02494             {
02495                 prev += (bm::set_block_mask + 1) - 
02496                             (prev & bm::set_block_mask);
02497             }
02498 
02499         }
02500         if (!prev) break;
02501     }
02502 
02503     return 0;
02504 }
02505 
02506 //---------------------------------------------------------------------
02507 
02508 template<class Alloc, class MS> 
02509 void bvector<Alloc, MS>::combine_operation(
02510                                   const bm::bvector<Alloc, MS>& bvect, 
02511                                   bm::operation                 opcode)
02512 {
02513     typedef void (*block_bit_op)(bm::word_t*, const bm::word_t*);
02514     typedef void (*block_bit_op_next)(bm::word_t*, 
02515                                         const bm::word_t*, 
02516                                         bm::word_t*, 
02517                                         const bm::word_t*);
02518 
02519     unsigned top_blocks = blockman_.top_block_size();
02520     unsigned bvect_top_blocks = bvect.blockman_.top_block_size();
02521 
02522     if (size_ == bvect.size_) 
02523     {
02524         BM_ASSERT(top_blocks >= bvect_top_blocks);
02525     }
02526     else
02527     if (size_ < bvect.size_) // this vect shorter than the arg.
02528     {
02529         size_ = bvect.size_;
02530         // stretch our capacity
02531         blockman_.reserve_top_blocks(bvect_top_blocks);
02532         top_blocks = blockman_.top_block_size();
02533     }
02534     else 
02535     if (size_ > bvect.size_) // this vector larger
02536     {
02537         if (opcode == BM_AND) // clear the tail with zeros
02538         {
02539             set_range(bvect.size_, size_ - 1, false);
02540             if (bvect_top_blocks < top_blocks)
02541             {
02542                 // not to scan blocks we already swiped
02543                 top_blocks = bvect_top_blocks;
02544             }
02545         }
02546     }
02547     
02548     bm::word_t*** blk_root = blockman_.blocks_root();
02549     unsigned block_idx = 0;
02550     unsigned i, j;
02551 
02552     BM_SET_MMX_GUARD
02553 
02554     // calculate effective top size to avoid overscan
02555     top_blocks = blockman_.effective_top_block_size();
02556     if (top_blocks < bvect.blockman_.effective_top_block_size())
02557     {
02558         if (opcode != BM_AND)
02559         {
02560             top_blocks = bvect.blockman_.effective_top_block_size();
02561         }
02562     }
02563 
02564     for (i = 0; i < top_blocks; ++i)
02565     {
02566         bm::word_t** blk_blk = blk_root[i];
02567 
02568         if (blk_blk == 0) // not allocated
02569         {
02570             if (opcode == BM_AND) // 0 AND anything == 0
02571             {
02572                 block_idx += bm::set_array_size;
02573                 continue; 
02574             }
02575             const bm::word_t* const* bvbb = bvect.blockman_.get_topblock(i);
02576             if (bvbb == 0) // skip it because 0 OP 0 == 0 
02577             {
02578                 block_idx += bm::set_array_size;
02579                 continue; 
02580             }
02581             // 0 - self, non-zero argument
02582             for (j = 0; j < bm::set_array_size; ++j,++block_idx)
02583             {
02584                 const bm::word_t* arg_blk = 
02585                     bvect.blockman_.get_block(i, j);
02586                 if (arg_blk != 0)
02587                 {
02588                     bool arg_gap = 
02589                         BM_IS_GAP(bvect.blockman_, arg_blk, block_idx);
02590                     combine_operation_with_block(block_idx, 0, 0, 
02591                                                  arg_blk, arg_gap, 
02592                                                  opcode);
02593                 }
02594 
02595             } // for j
02596             continue;
02597         }
02598 
02599         for (j = 0; j < bm::set_array_size; ++j, ++block_idx)
02600         {            
02601             bm::word_t* blk = blk_blk[j];
02602             const bm::word_t* arg_blk = bvect.blockman_.get_block(i, j);
02603         
02604             if (arg_blk || blk)
02605             {
02606                 if (opcode == BM_AND)
02607                 {
02608                     if (!blk) continue;
02609                     if (!arg_blk)
02610                     {
02611                         if (blk) blockman_.zero_block(block_idx);
02612                         continue;
02613                     }
02614                 }
02615 
02616                 bool arg_gap = BM_IS_GAP(bvect.blockman_, arg_blk, block_idx);
02617                 bool gap = BM_IS_GAP((*this).blockman_, blk, block_idx);
02618                 combine_operation_with_block(block_idx, gap, blk, 
02619                                              arg_blk, arg_gap,
02620                                              opcode);
02621             }
02622 
02623         } // for j
02624 
02625     } // for i
02626 
02627 }
02628 
02629 
02630 //---------------------------------------------------------------------
02631 
02632 
02633 template<class Alloc, class MS> 
02634 void 
02635 bvector<Alloc, MS>::combine_operation_with_block(unsigned          nb,
02636                                                  unsigned          gap,
02637                                                  bm::word_t*       blk,
02638                                                  const bm::word_t* arg_blk,
02639                                                  int               arg_gap,
02640                                                  bm::operation     opcode)
02641 {
02642     if (!blk && arg_gap && (opcode == BM_OR || opcode == BM_XOR)) 
02643     {
02644         blk = 
02645             blockman_.check_allocate_block(nb, 
02646                                         0,
02647                                         BM_GAP, 
02648                                         (int*)&gap,
02649                                         false /*no null return*/);
02650     }
02651 
02652         if (gap) // our block GAP-type
02653         {
02654             if (arg_gap)  // both blocks GAP-type
02655             {
02656                 gap_word_t tmp_buf[bm::gap_equiv_len * 3]; // temporary result            
02657                 gap_word_t* res;
02658                 unsigned res_len;
02659 
02660                 gap_operation_func_type gfunc = 
02661                     operation_functions<true>::gap_operation(opcode);
02662                 BM_ASSERT(gfunc);
02663                 res = (*gfunc)(BMGAP_PTR(blk), 
02664                                BMGAP_PTR(arg_blk), 
02665                                tmp_buf,
02666                                res_len);
02667                 BM_ASSERT(res == tmp_buf);
02668                 ++res_len;// = bm::gap_length(res);
02669 
02670                 BM_ASSERT(!(res == tmp_buf && res_len == 0));
02671 
02672                 // if as a result of the operation gap block turned to zero
02673                 // we can now replace it with NULL
02674                 if (gap_is_all_zero(res, bm::gap_max_bits))
02675                 {
02676                     blockman_.zero_block(nb);
02677                     return;
02678                 }
02679 
02680                 // mutation check
02681 
02682                 int level = gap_level(BMGAP_PTR(blk));
02683                 unsigned threshold = blockman_.glen(level)-4;
02684                 int new_level = gap_calc_level(res_len, blockman_.glen());
02685 
02686                 if (new_level == -1)
02687                 {
02688                     blockman_.convert_gap2bitset(nb, res);
02689                     return;
02690                 }
02691 
02692                 if (res_len > threshold)
02693                 {
02694                     set_gap_level(res, new_level);
02695                     gap_word_t* new_blk = 
02696                         blockman_.allocate_gap_block(new_level, res);
02697 
02698                     bm::word_t* p = (bm::word_t*)new_blk;
02699                     BMSET_PTRGAP(p);
02700 
02701                     blockman_.set_block_ptr(nb, p);
02702                     blockman_.get_allocator().free_gap_block(BMGAP_PTR(blk), 
02703                                                             blockman_.glen());
02704                     return;
02705                 }
02706 
02707                 // gap opeartion result is in the temporary buffer
02708                 // we copy it back to the gap_block
02709 
02710                 set_gap_level(tmp_buf, level);
02711                 ::memcpy(BMGAP_PTR(blk), tmp_buf, res_len * sizeof(gap_word_t));
02712                 return;
02713             }
02714             else // argument is BITSET-type (own block is GAP)
02715             {
02716                 // since we can not combine blocks of mixed type
02717                 // we need to convert our block to bitset
02718                
02719                 if (arg_blk == 0)  // Combining against an empty block
02720                 {
02721                     switch (opcode)
02722                     {
02723                     case BM_AND:  // ("Value" AND  0) == 0
02724                         blockman_.zero_block(nb);
02725                         return;
02726                     case BM_OR: case BM_SUB: case BM_XOR:
02727                         return; // nothing to do
02728                     }
02729                 }
02730                 gap_word_t* gap_blk = BMGAP_PTR(blk);
02731                 if (opcode == BM_AND)
02732                 {
02733                     unsigned gap_cnt = gap_bit_count(gap_blk);
02734                     if (gap_cnt < 128)
02735                     {
02736                         gap_word_t tmp_buf[bm::gap_equiv_len * 3];         
02737                         gap_word_t arr_len = 
02738                             gap_convert_to_arr(tmp_buf, gap_blk, 
02739                                                bm::gap_equiv_len-10);
02740                         BM_ASSERT(gap_cnt == arr_len);
02741                         blockman_.zero_block(nb);
02742                         unsigned arr_i = 0;
02743                         int block_type;
02744                         blk =
02745                             blockman_.check_allocate_block(nb,
02746                                                            true,
02747                                                            BM_GAP,
02748                                                            &block_type,
02749                                                            false //no null return
02750                                                            );
02751                         BM_ASSERT(block_type==1); // GAP
02752                         gap_blk = BMGAP_PTR(blk);
02753                         unsigned threshold = bm::gap_limit(gap_blk, blockman_.glen());
02754                         for (; arr_i < arr_len; ++arr_i)
02755                         {
02756                             gap_word_t bit_idx = tmp_buf[arr_i];
02757                             if (bm::test_bit(arg_blk, bit_idx))
02758                             {
02759                                 unsigned is_set;
02760                                 unsigned new_block_len =
02761                                     gap_set_value(true, gap_blk, bit_idx, &is_set);
02762                                 BM_ASSERT(is_set);
02763                                 if (new_block_len > threshold) 
02764                                 {
02765                                     gap_blk = 
02766                                         blockman_.extend_gap_block(nb, gap_blk);
02767                                     if (gap_blk == 0) // mutated into bit-block
02768                                     {
02769                                         blk = blockman_.check_allocate_block(
02770                                                          nb,
02771                                                          true,
02772                                                          this->get_new_blocks_strat(),
02773                                                          &block_type,
02774                                                          false // no null return
02775                                                          );  
02776                                         BM_ASSERT(block_type == 0); // BIT
02777                                         // target block degraded into plain bit-block
02778                                         for (++arr_i; arr_i < arr_len; ++arr_i)
02779                                         {
02780                                             bit_idx = tmp_buf[arr_i];
02781                                             if (bm::test_bit(arg_blk, bit_idx))
02782                                             {
02783                                                 or_bit_block(blk, bit_idx, 1);
02784                                             }
02785                                         } // for arr_i
02786                                         return;
02787                                     } // if gap mutated
02788                                 }
02789                             } // for arr_i
02790                         }
02791 
02792                         return;
02793                     }                    
02794                 } // BM_AND
02795 
02796                 blk = blockman_.convert_gap2bitset(nb, gap_blk);
02797             }
02798         } 
02799         else // our block is BITSET-type
02800         {
02801             if (arg_gap) // argument block is GAP-type
02802             {
02803                 if (IS_VALID_ADDR(blk))
02804                 {
02805                     // special case, maybe we can do the job without 
02806                     // converting the GAP argument to bitblock
02807                     gap_operation_to_bitset_func_type gfunc = 
02808                         operation_functions<true>::gap_op_to_bit(opcode);
02809                     BM_ASSERT(gfunc);
02810                     (*gfunc)(blk, BMGAP_PTR(arg_blk));
02811                     return;
02812                 }
02813                 
02814                 // the worst case we need to convert argument block to 
02815                 // bitset type.
02816                 gap_word_t* temp_blk = (gap_word_t*) blockman_.check_allocate_tempblock();
02817                 arg_blk = 
02818                     gap_convert_to_bitset_smart((bm::word_t*)temp_blk, 
02819                                                 BMGAP_PTR(arg_blk), 
02820                                                 bm::gap_max_bits);
02821             
02822             }   
02823         }
02824     
02825         // Now here we combine two plain bitblocks using supplied bit function.
02826         bm::word_t* dst = blk;
02827 
02828         bm::word_t* ret; 
02829         if (dst == 0 && arg_blk == 0)
02830         {
02831             return;
02832         }
02833 
02834         switch (opcode)
02835         {
02836         case BM_AND:
02837             ret = bit_operation_and(dst, arg_blk);
02838             goto copy_block;
02839         case BM_XOR:
02840             ret = bit_operation_xor(dst, arg_blk);
02841             if (ret && (ret == arg_blk) && IS_FULL_BLOCK(dst))
02842             {
02843                 ret = blockman_.get_allocator().alloc_bit_block();
02844 #ifdef BMVECTOPT
02845             VECT_XOR_ARR_2_MASK(ret, 
02846                                 arg_blk, 
02847                                 arg_blk + bm::set_block_size, 
02848                                 bm::all_bits_mask);
02849 #else
02850                 bm::wordop_t* dst_ptr = (wordop_t*)ret;
02851                 const bm::wordop_t* wrd_ptr = (wordop_t*) arg_blk;
02852                 const bm::wordop_t* wrd_end = 
02853                 (wordop_t*) (arg_blk + bm::set_block_size);
02854 
02855                 do
02856                 {
02857                     dst_ptr[0] = bm::all_bits_mask ^ wrd_ptr[0];
02858                     dst_ptr[1] = bm::all_bits_mask ^ wrd_ptr[1];
02859                     dst_ptr[2] = bm::all_bits_mask ^ wrd_ptr[2];
02860                     dst_ptr[3] = bm::all_bits_mask ^ wrd_ptr[3];
02861 
02862                     dst_ptr+=4;
02863                     wrd_ptr+=4;
02864 
02865                 } while (wrd_ptr < wrd_end);
02866 #endif
02867                 break;
02868             }
02869             goto copy_block;
02870         case BM_OR:
02871             ret = bit_operation_or(dst, arg_blk);
02872         copy_block:
02873             if (ret && (ret == arg_blk) && !IS_FULL_BLOCK(ret))
02874             {
02875             ret = blockman_.get_allocator().alloc_bit_block();
02876             bit_block_copy(ret, arg_blk);
02877             }
02878             break;
02879 
02880         case BM_SUB:
02881             ret = bit_operation_sub(dst, arg_blk);
02882             if (ret && ret == arg_blk)
02883             {
02884                 ret = blockman_.get_allocator().alloc_bit_block();
02885 #ifdef BMVECTOPT
02886                 VECT_ANDNOT_ARR_2_MASK(ret, 
02887                                     arg_blk,
02888                                     arg_blk + bm::set_block_size,
02889                                     bm::all_bits_mask);
02890 #else
02891 
02892                 bm::wordop_t* dst_ptr = (wordop_t*)ret;
02893                 const bm::wordop_t* wrd_ptr = (wordop_t*) arg_blk;
02894                 const bm::wordop_t* wrd_end = 
02895                 (wordop_t*) (arg_blk + bm::set_block_size);
02896 
02897                 do
02898                 {
02899                     dst_ptr[0] = bm::all_bits_mask & ~wrd_ptr[0];
02900                     dst_ptr[1] = bm::all_bits_mask & ~wrd_ptr[1];
02901                     dst_ptr[2] = bm::all_bits_mask & ~wrd_ptr[2];
02902                     dst_ptr[3] = bm::all_bits_mask & ~wrd_ptr[3];
02903 
02904                     dst_ptr+=4;
02905                     wrd_ptr+=4;
02906 
02907                 } while (wrd_ptr < wrd_end);
02908 #endif
02909             }
02910             break;
02911         default:
02912             BM_ASSERT(0);
02913             ret = 0;
02914         }
02915 
02916         if (ret != dst) // block mutation
02917         {
02918             blockman_.set_block(nb, ret);
02919             blockman_.get_allocator().free_bit_block(dst);
02920         }
02921 }
02922 
02923 //---------------------------------------------------------------------
02924 
02925 template<class Alloc, class MS> 
02926 void bvector<Alloc, MS>::set_range_no_check(bm::id_t left,
02927                                             bm::id_t right,
02928                                             bool     value)
02929 {
02930     // calculate logical number of start and destination blocks
02931     unsigned nblock_left  = unsigned(left  >>  bm::set_block_shift);
02932     unsigned nblock_right = unsigned(right >>  bm::set_block_shift);
02933 
02934     bm::word_t* block = blockman_.get_block(nblock_left);
02935     bool left_gap = BM_IS_GAP(blockman_, block, nblock_left);
02936 
02937     unsigned nbit_left  = unsigned(left  & bm::set_block_mask); 
02938     unsigned nbit_right = unsigned(right & bm::set_block_mask); 
02939 
02940     unsigned r = 
02941         (nblock_left == nblock_right) ? nbit_right :(bm::bits_in_block-1);
02942 
02943         bm::gap_word_t tmp_gap_blk[5] = {0,};
02944 
02945     // Set bits in the starting block
02946 
02947     unsigned nb;
02948     if ((nbit_left == 0) && (r == bm::bits_in_block - 1)) // full block
02949     {
02950         nb = nblock_left;
02951     }
02952     else
02953     {
02954         gap_init_range_block(tmp_gap_blk,
02955                             nbit_left, r, value, bm::bits_in_block);
02956 
02957         combine_operation_with_block(nblock_left, 
02958                                     left_gap, 
02959                                     block,
02960                                     (bm::word_t*) tmp_gap_blk,
02961                                     1,
02962                                     value ? BM_OR : BM_AND);
02963 
02964         if (nblock_left == nblock_right)  // in one block
02965             return;
02966         nb = nblock_left+1;
02967     }
02968 
02969     // Set (or clear) all full blocks between left and right
02970     
02971     unsigned nb_to = nblock_right + (nbit_right ==(bm::bits_in_block-1));
02972             
02973     if (value)
02974     {
02975         for (; nb < nb_to; ++nb)
02976         {
02977             block = blockman_.get_block(nb);
02978             if (IS_FULL_BLOCK(block)) 
02979                 continue;
02980 
02981             bool is_gap = BM_IS_GAP(blockman_, block, nb);
02982 
02983             blockman_.set_block(nb, FULL_BLOCK_ADDR);
02984             blockman_.set_block_bit(nb);
02985             
02986             if (is_gap)
02987             {
02988                 blockman_.get_allocator().free_gap_block(BMGAP_PTR(block), 
02989                                                             blockman_.glen());
02990             }
02991             else
02992             {
02993                 blockman_.get_allocator().free_bit_block(block);
02994             }
02995             
02996         } // for
02997     }
02998     else // value == 0
02999     {
03000         for (; nb < nb_to; ++nb)
03001         {
03002             block = blockman_.get_block(nb);
03003             if (block == 0)  // nothing to do
03004                 continue;
03005             bool is_gap = BM_IS_GAP(blockman_, block, nb);
03006             blockman_.set_block(nb, 0, false /*bit*/);
03007             //blockman_.set_block_bit(nb);
03008 
03009             if (is_gap) 
03010             {
03011                 blockman_.get_allocator().free_gap_block(BMGAP_PTR(block),
03012                                                          blockman_.glen());
03013             }
03014             else
03015             {
03016                 blockman_.get_allocator().free_bit_block(block);
03017             }
03018 
03019         } // for
03020     } // if value else 
03021 
03022     if (nb_to > nblock_right)
03023         return;
03024 
03025     block = blockman_.get_block(nblock_right);
03026     bool right_gap = BM_IS_GAP(blockman_, block, nblock_right);
03027 
03028     gap_init_range_block(tmp_gap_blk, 
03029                             0, nbit_right, value, bm::bits_in_block);
03030 
03031     combine_operation_with_block(nblock_right, 
03032                                     right_gap, 
03033                                     block,
03034                                     (bm::word_t*) tmp_gap_blk,
03035                                     1,
03036                                     value ? BM_OR : BM_AND);
03037 
03038 }
03039 
03040 //---------------------------------------------------------------------
03041 
03042 
03043 } // namespace
03044 
03045 #include "bmundef.h"
03046 
03047 #ifdef _MSC_VER
03048 #pragma warning( default : 4311 4312)
03049 #endif
03050 
03051 
03052 #endif
03053 
03054 

Generated on Sun Dec 6 22:15:46 2009 for NCBI C++ ToolKit by  doxygen 1.4.6
Modified on Mon Dec 07 16:20:49 2009 by modify_doxy.py rev. 173732