std::vector like container (random-access, size_t - index type, bool - value type) with all bits after size() considered off during testing
| 66 | /// std::vector<bool> like container (random-access, size_t - index type, bool - value type) |
| 67 | /// with all bits after size() considered off during testing |
| 68 | class BitSet |
| 69 | { |
| 70 | public: |
| 71 | using block_type = std::uint64_t; |
| 72 | inline static constexpr size_t bits_per_block = sizeof( block_type ) * 8; |
| 73 | inline static constexpr size_t npos = (size_t)-1; |
| 74 | |
| 75 | using size_type = size_t; |
| 76 | using IndexType = size_t; |
| 77 | |
| 78 | /// creates empty bitset |
| 79 | BitSet() noexcept = default; |
| 80 | |
| 81 | /// creates bitset of given size filled with given value |
| 82 | explicit BitSet( size_t numBits, bool fillValue = false ) { resize( numBits, fillValue ); } |
| 83 | |
| 84 | /// creates bitset from the given blocks of bits |
| 85 | static BitSet fromBlocks( std::vector<block_type> && blocks ) |
| 86 | { |
| 87 | BitSet res; |
| 88 | res.blocks_ = std::move( blocks ); |
| 89 | res.numBits_ = res.blocks_.size() * bits_per_block; |
| 90 | return res; |
| 91 | } |
| 92 | |
| 93 | void reserve( size_type numBits ) { blocks_.reserve( calcNumBlocks_( numBits ) ); } |
| 94 | MRMESH_API void resize( size_type numBits, bool fillValue = false ); |
| 95 | void clear() { numBits_ = 0; blocks_.clear(); } |
| 96 | void shrink_to_fit() { blocks_.shrink_to_fit(); } |
| 97 | |
| 98 | [[nodiscard]] bool empty() const noexcept { return numBits_ == 0; } |
| 99 | [[nodiscard]] size_type size() const noexcept { return numBits_; } |
| 100 | [[nodiscard]] size_type num_blocks() const noexcept { return blocks_.size(); } |
| 101 | [[nodiscard]] size_type capacity() const noexcept { return blocks_.capacity() * bits_per_block; } |
| 102 | |
| 103 | [[nodiscard]] bool uncheckedTest( IndexType n ) const { assert( n < size() ); return blocks_[blockIndex_( n )] & bitMask_( n ); } |
| 104 | [[nodiscard]] bool uncheckedTestSet( IndexType n, bool val = true ) { assert( n < size() ); bool b = uncheckedTest( n ); if ( b != val ) set( n, val ); return b; } |
| 105 | |
| 106 | // all bits after size() we silently consider as not-set |
| 107 | [[nodiscard]] bool test( IndexType n ) const { return n < size() ? uncheckedTest( n ) : false; } // return n < size() && uncheckedTest( n ); was compiled with extra conditional jump inside uncheckedTest() by MSVC |
| 108 | [[nodiscard]] bool test_set( IndexType n, bool val = true ) { return ( val || n < size() ) ? uncheckedTestSet( n, val ) : false; } |
| 109 | |
| 110 | MRMESH_API BitSet & set( IndexType n, size_type len, bool val ); |
| 111 | BitSet & set( IndexType n, bool val ) { return val ? set( n ) : reset( n ); } // Not using a default argument for `val` to get better C bindings. |
| 112 | BitSet & set( IndexType n ) { assert( n < size() ); blocks_[blockIndex_( n )] |= bitMask_( n ); return * this; } |
| 113 | MRMESH_API BitSet & set(); |
| 114 | |
| 115 | MRMESH_API BitSet & reset( IndexType n, size_type len ); |
| 116 | BitSet & reset( IndexType n ) { if ( n < size() ) blocks_[blockIndex_( n )] &= ~bitMask_( n ); return * this; } |
| 117 | MRMESH_API BitSet & reset(); |
| 118 | |
| 119 | MRMESH_API BitSet & flip( IndexType n, size_type len ); |
| 120 | BitSet & flip( IndexType n ) { assert( n < size() ); blocks_[blockIndex_( n )] ^= bitMask_( n ); return * this; } |
| 121 | MRMESH_API BitSet & flip(); |
| 122 | |
| 123 | /// changes the order of bits on the opposite |
| 124 | MRMESH_API void reverse(); |
| 125 |