1 //---------------------------------------------------------------------------// 2 // Copyright (c) 2013-2014 Kyle Lutz <kyle.r.lutz@gmail.com> 3 // 4 // Distributed under the Boost Software License, Version 1.0 5 // See accompanying file LICENSE_1_0.txt or copy at 6 // http://www.boost.org/LICENSE_1_0.txt 7 // 8 // See http://boostorg.github.com/compute for more information. 9 //---------------------------------------------------------------------------// 10 11 #ifndef BOOST_COMPUTE_CONTAINER_DYNAMIC_BITSET_HPP 12 #define BOOST_COMPUTE_CONTAINER_DYNAMIC_BITSET_HPP 13 14 #include <boost/compute/lambda.hpp> 15 #include <boost/compute/algorithm/any_of.hpp> 16 #include <boost/compute/algorithm/fill.hpp> 17 #include <boost/compute/algorithm/transform_reduce.hpp> 18 #include <boost/compute/container/vector.hpp> 19 #include <boost/compute/functional/integer.hpp> 20 #include <boost/compute/types/fundamental.hpp> 21 22 namespace boost { 23 namespace compute { 24 25 /// \class dynamic_bitset 26 /// \brief The dynamic_bitset class contains a resizable bit array. 27 /// 28 /// For example, to create a dynamic-bitset with space for 1000 bits on the 29 /// device: 30 /// \code 31 /// boost::compute::dynamic_bitset<> bits(1000, queue); 32 /// \endcode 33 /// 34 /// The Boost.Compute \c dynamic_bitset class provides a STL-like API and is 35 /// modeled after the \c boost::dynamic_bitset class from Boost. 36 /// 37 /// \see \ref vector "vector<T>" 38 template<class Block = ulong_, class Alloc = buffer_allocator<Block> > 39 class dynamic_bitset 40 { 41 public: 42 typedef Block block_type; 43 typedef Alloc allocator_type; 44 typedef vector<Block, Alloc> container_type; 45 typedef typename container_type::size_type size_type; 46 47 BOOST_STATIC_CONSTANT(size_type, bits_per_block = sizeof(block_type) * CHAR_BIT); 48 BOOST_STATIC_CONSTANT(size_type, npos = static_cast<size_type>(-1)); 49 50 /// Creates a new dynamic bitset with storage for \p size bits. Initializes 51 /// all bits to zero. dynamic_bitset(size_type size,command_queue & queue)52 dynamic_bitset(size_type size, command_queue &queue) 53 : m_bits(size / sizeof(block_type), queue.get_context()), 54 m_size(size) 55 { 56 // initialize all bits to zero 57 reset(queue); 58 } 59 60 /// Creates a new dynamic bitset as a copy of \p other. dynamic_bitset(const dynamic_bitset & other)61 dynamic_bitset(const dynamic_bitset &other) 62 : m_bits(other.m_bits), 63 m_size(other.m_size) 64 { 65 } 66 67 /// Copies the data from \p other to \c *this. operator =(const dynamic_bitset & other)68 dynamic_bitset& operator=(const dynamic_bitset &other) 69 { 70 if(this != &other){ 71 m_bits = other.m_bits; 72 m_size = other.m_size; 73 } 74 75 return *this; 76 } 77 78 /// Destroys the dynamic bitset. ~dynamic_bitset()79 ~dynamic_bitset() 80 { 81 } 82 83 /// Returns the size of the dynamic bitset. size() const84 size_type size() const 85 { 86 return m_size; 87 } 88 89 /// Returns the number of blocks to store the bits in the dynamic bitset. num_blocks() const90 size_type num_blocks() const 91 { 92 return m_bits.size(); 93 } 94 95 /// Returns the maximum possible size for the dynamic bitset. max_size() const96 size_type max_size() const 97 { 98 return m_bits.max_size() * bits_per_block; 99 } 100 101 /// Returns \c true if the dynamic bitset is empty (i.e. \c size() == \c 0). empty() const102 bool empty() const 103 { 104 return size() == 0; 105 } 106 107 /// Returns the number of set bits (i.e. '1') in the bitset. count(command_queue & queue) const108 size_type count(command_queue &queue) const 109 { 110 ulong_ count = 0; 111 transform_reduce( 112 m_bits.begin(), 113 m_bits.end(), 114 &count, 115 popcount<block_type>(), 116 plus<ulong_>(), 117 queue 118 ); 119 return static_cast<size_type>(count); 120 } 121 122 /// Resizes the bitset to contain \p num_bits. If the new size is greater 123 /// than the current size the new bits are set to zero. resize(size_type num_bits,command_queue & queue)124 void resize(size_type num_bits, command_queue &queue) 125 { 126 // resize bits 127 const size_type current_block_count = m_bits.size(); 128 m_bits.resize(num_bits * bits_per_block, queue); 129 130 // fill new block with zeros (if new blocks were added) 131 const size_type new_block_count = m_bits.size(); 132 if(new_block_count > current_block_count){ 133 fill_n( 134 m_bits.begin() + current_block_count, 135 new_block_count - current_block_count, 136 block_type(0), 137 queue 138 ); 139 } 140 141 // store new size 142 m_size = num_bits; 143 } 144 145 /// Sets the bit at position \p n to \c true. set(size_type n,command_queue & queue)146 void set(size_type n, command_queue &queue) 147 { 148 set(n, true, queue); 149 } 150 151 /// Sets the bit at position \p n to \p value. set(size_type n,bool value,command_queue & queue)152 void set(size_type n, bool value, command_queue &queue) 153 { 154 const size_type bit = n % bits_per_block; 155 const size_type block = n / bits_per_block; 156 157 // load current block 158 block_type block_value; 159 copy_n(m_bits.begin() + block, 1, &block_value, queue); 160 161 // update block value 162 if(value){ 163 block_value |= (size_type(1) << bit); 164 } 165 else { 166 block_value &= ~(size_type(1) << bit); 167 } 168 169 // store new block 170 copy_n(&block_value, 1, m_bits.begin() + block, queue); 171 } 172 173 /// Returns \c true if the bit at position \p n is set (i.e. '1'). test(size_type n,command_queue & queue)174 bool test(size_type n, command_queue &queue) 175 { 176 const size_type bit = n % (sizeof(block_type) * CHAR_BIT); 177 const size_type block = n / (sizeof(block_type) * CHAR_BIT); 178 179 block_type block_value; 180 copy_n(m_bits.begin() + block, 1, &block_value, queue); 181 182 return block_value & (size_type(1) << bit); 183 } 184 185 /// Flips the value of the bit at position \p n. flip(size_type n,command_queue & queue)186 void flip(size_type n, command_queue &queue) 187 { 188 set(n, !test(n, queue), queue); 189 } 190 191 /// Returns \c true if any bit in the bitset is set (i.e. '1'). any(command_queue & queue) const192 bool any(command_queue &queue) const 193 { 194 return any_of( 195 m_bits.begin(), m_bits.end(), lambda::_1 != block_type(0), queue 196 ); 197 } 198 199 /// Returns \c true if all of the bits in the bitset are set to zero. none(command_queue & queue) const200 bool none(command_queue &queue) const 201 { 202 return !any(queue); 203 } 204 205 /// Sets all of the bits in the bitset to zero. reset(command_queue & queue)206 void reset(command_queue &queue) 207 { 208 fill(m_bits.begin(), m_bits.end(), block_type(0), queue); 209 } 210 211 /// Sets the bit at position \p n to zero. reset(size_type n,command_queue & queue)212 void reset(size_type n, command_queue &queue) 213 { 214 set(n, false, queue); 215 } 216 217 /// Empties the bitset (e.g. \c resize(0)). clear()218 void clear() 219 { 220 m_bits.clear(); 221 } 222 223 /// Returns the allocator used to allocate storage for the bitset. get_allocator() const224 allocator_type get_allocator() const 225 { 226 return m_bits.get_allocator(); 227 } 228 229 private: 230 container_type m_bits; 231 size_type m_size; 232 }; 233 234 } // end compute namespace 235 } // end boost namespace 236 237 #endif // BOOST_COMPUTE_CONTAINER_DYNAMIC_BITSET_HPP 238