dynamic_bitset.hpp 6.7 KB

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