large_bitset.hpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213
  1. /*-----------------------------------------------------------------------------+
  2. Author: Joachim Faulhaber
  3. Copyright (c) 2009-2009: Joachim Faulhaber
  4. +------------------------------------------------------------------------------+
  5. Distributed under the Boost Software License, Version 1.0.
  6. (See accompanying file LICENCE.txt or copy at
  7. http://www.boost.org/LICENSE_1_0.txt)
  8. +-----------------------------------------------------------------------------*/
  9. #ifndef BOOST_LIBS_ICL_EXAMPLE_LARGE_BITSET__LARGE_BITSET_HPP_JOFA_091019
  10. #define BOOST_LIBS_ICL_EXAMPLE_LARGE_BITSET__LARGE_BITSET_HPP_JOFA_091019
  11. //[large_bitset_includes
  12. #include <iostream> // to organize output
  13. #include <limits> // limits and associated constants
  14. #include <boost/operators.hpp> // to define operators with minimal effort
  15. #include "meta_log.hpp" // a meta logarithm
  16. #include "bits.hpp" // a minimal bitset implementation
  17. #include <boost/icl/interval_map.hpp> // base of large bitsets
  18. namespace mini // minimal implementations for example projects
  19. {
  20. //]
  21. //[large_bitset_natural_typedefs
  22. typedef unsigned char nat8; // nati i: number bits
  23. typedef unsigned short nat16;
  24. typedef unsigned long nat32;
  25. typedef unsigned long long nat64;
  26. typedef unsigned long nat;
  27. typedef bits<nat8> bits8;
  28. typedef bits<nat16> bits16;
  29. typedef bits<nat32> bits32;
  30. typedef bits<nat64> bits64;
  31. //]
  32. //[large_bitset_class_template_header
  33. template
  34. <
  35. typename DomainT = nat64,
  36. typename BitSetT = bits64,
  37. ICL_COMPARE Compare = ICL_COMPARE_INSTANCE(std::less, DomainT),
  38. ICL_INTERVAL(ICL_COMPARE) Interval = ICL_INTERVAL_INSTANCE(ICL_INTERVAL_DEFAULT, DomainT, Compare),
  39. ICL_ALLOC Alloc = std::allocator
  40. >
  41. class large_bitset
  42. : boost::equality_comparable < large_bitset<DomainT,BitSetT,Compare,Interval,Alloc>
  43. , boost::less_than_comparable< large_bitset<DomainT,BitSetT,Compare,Interval,Alloc>
  44. , boost::addable < large_bitset<DomainT,BitSetT,Compare,Interval,Alloc>
  45. , boost::orable < large_bitset<DomainT,BitSetT,Compare,Interval,Alloc>
  46. , boost::subtractable < large_bitset<DomainT,BitSetT,Compare,Interval,Alloc>
  47. , boost::andable < large_bitset<DomainT,BitSetT,Compare,Interval,Alloc>
  48. , boost::xorable < large_bitset<DomainT,BitSetT,Compare,Interval,Alloc>
  49. , boost::addable2 < large_bitset<DomainT,BitSetT,Compare,Interval,Alloc>, DomainT
  50. , boost::orable2 < large_bitset<DomainT,BitSetT,Compare,Interval,Alloc>, DomainT
  51. , boost::subtractable2 < large_bitset<DomainT,BitSetT,Compare,Interval,Alloc>, DomainT
  52. , boost::andable2 < large_bitset<DomainT,BitSetT,Compare,Interval,Alloc>, DomainT
  53. , boost::xorable2 < large_bitset<DomainT,BitSetT,Compare,Interval,Alloc>, DomainT
  54. , boost::addable2 < large_bitset<DomainT,BitSetT,Compare,Interval,Alloc>, ICL_INTERVAL_TYPE(Interval,DomainT,Compare)
  55. , boost::orable2 < large_bitset<DomainT,BitSetT,Compare,Interval,Alloc>, ICL_INTERVAL_TYPE(Interval,DomainT,Compare)
  56. , boost::subtractable2 < large_bitset<DomainT,BitSetT,Compare,Interval,Alloc>, ICL_INTERVAL_TYPE(Interval,DomainT,Compare)
  57. , boost::andable2 < large_bitset<DomainT,BitSetT,Compare,Interval,Alloc>, ICL_INTERVAL_TYPE(Interval,DomainT,Compare)
  58. , boost::xorable2 < large_bitset<DomainT,BitSetT,Compare,Interval,Alloc>, ICL_INTERVAL_TYPE(Interval,DomainT,Compare)
  59. > > > > > > > > > > > > > > > > >
  60. //^ & - | + ^ & - | + ^ & - | + < ==
  61. //segment element container
  62. //]
  63. {
  64. public:
  65. //[large_bitset_associated_types
  66. typedef boost::icl::interval_map
  67. <DomainT, BitSetT, boost::icl::partial_absorber,
  68. std::less, boost::icl::inplace_bit_add, boost::icl::inplace_bit_and> interval_bitmap_type;
  69. typedef DomainT domain_type;
  70. typedef DomainT element_type;
  71. typedef BitSetT bitset_type;
  72. typedef typename BitSetT::word_type word_type;
  73. typedef typename interval_bitmap_type::interval_type interval_type;
  74. typedef typename interval_bitmap_type::value_type value_type;
  75. //]
  76. //[large_bitset_operators
  77. public:
  78. bool operator ==(const large_bitset& rhs)const { return _map == rhs._map; }
  79. bool operator < (const large_bitset& rhs)const { return _map < rhs._map; }
  80. large_bitset& operator +=(const large_bitset& rhs) {_map += rhs._map; return *this;}
  81. large_bitset& operator |=(const large_bitset& rhs) {_map |= rhs._map; return *this;}
  82. large_bitset& operator -=(const large_bitset& rhs) {_map -= rhs._map; return *this;}
  83. large_bitset& operator &=(const large_bitset& rhs) {_map &= rhs._map; return *this;}
  84. large_bitset& operator ^=(const large_bitset& rhs) {_map ^= rhs._map; return *this;}
  85. large_bitset& operator +=(const element_type& rhs) {return add(interval_type(rhs)); }
  86. large_bitset& operator |=(const element_type& rhs) {return add(interval_type(rhs)); }
  87. large_bitset& operator -=(const element_type& rhs) {return subtract(interval_type(rhs)); }
  88. large_bitset& operator &=(const element_type& rhs) {return intersect(interval_type(rhs));}
  89. large_bitset& operator ^=(const element_type& rhs) {return flip(interval_type(rhs)); }
  90. large_bitset& operator +=(const interval_type& rhs){return add(rhs); }
  91. large_bitset& operator |=(const interval_type& rhs){return add(rhs); }
  92. large_bitset& operator -=(const interval_type& rhs){return subtract(rhs); }
  93. large_bitset& operator &=(const interval_type& rhs){return intersect(rhs);}
  94. large_bitset& operator ^=(const interval_type& rhs){return flip(rhs); }
  95. //]
  96. //[large_bitset_fundamental_functions
  97. large_bitset& add (const interval_type& rhs){return segment_apply(&large_bitset::add_, rhs);}
  98. large_bitset& subtract (const interval_type& rhs){return segment_apply(&large_bitset::subtract_, rhs);}
  99. large_bitset& intersect(const interval_type& rhs){return segment_apply(&large_bitset::intersect_,rhs);}
  100. large_bitset& flip (const interval_type& rhs){return segment_apply(&large_bitset::flip_, rhs);}
  101. //]
  102. //[large_bitset_demo_functions
  103. size_t interval_count()const { return boost::icl::interval_count(_map); }
  104. void show_segments()const
  105. {
  106. for(typename interval_bitmap_type::const_iterator it_ = _map.begin();
  107. it_ != _map.end(); ++it_)
  108. {
  109. interval_type itv = it_->first;
  110. bitset_type bits = it_->second;
  111. std::cout << itv << "->" << bits.as_string("01") << std::endl;
  112. }
  113. }
  114. void show_matrix(const char off_on[2] = " 1")const
  115. {
  116. using namespace boost;
  117. typename interval_bitmap_type::const_iterator iter = _map.begin();
  118. while(iter != _map.end())
  119. {
  120. element_type fst = icl::first(iter->first), lst = icl::last(iter->first);
  121. for(element_type chunk = fst; chunk <= lst; chunk++)
  122. std::cout << iter->second.as_string(off_on) << std::endl;
  123. ++iter;
  124. }
  125. }
  126. //]
  127. //[large_bitset_impl_constants
  128. private: // Example value
  129. static const word_type // 8-bit case
  130. digits = std::numeric_limits // --------------------------------------------------------------
  131. <word_type>::digits , // 8 Size of the associated bitsets
  132. divisor = digits , // 8 Divisor to find intervals for values
  133. last = digits-1 , // 7 Last bit (0 based)
  134. shift = log2_<divisor>::value , // 3 To express the division as bit shift
  135. w1 = static_cast<word_type>(1) , // Helps to avoid static_casts for long long
  136. mask = divisor - w1 , // 7=11100000 Helps to express the modulo operation as bit_and
  137. all = ~static_cast<word_type>(0), // 255=11111111 Helps to express a complete associated bitset
  138. top = w1 << (digits-w1) ; // 128=00000001 Value of the most significant bit of associated bitsets
  139. // !> Note: Most signigicant bit on the right.
  140. //]
  141. //[large_bitset_segment_combiner
  142. typedef void (large_bitset::*segment_combiner)(element_type, element_type, bitset_type);
  143. //]
  144. //[large_bitset_bitset_filler
  145. static word_type from_lower_to(word_type bit){return bit==last ? all : (w1<<(bit+w1))-w1;}
  146. static word_type to_upper_from(word_type bit){return bit==last ? top : ~((w1<<bit)-w1); }
  147. //]
  148. //[large_bitset_segment_apply
  149. large_bitset& segment_apply(segment_combiner combine, const interval_type& operand)
  150. {
  151. using namespace boost;
  152. if(icl::is_empty(operand))
  153. return *this;
  154. // same as
  155. element_type base = icl::first(operand) >> shift, // icl::first(operand) / divisor
  156. ceil = icl::last (operand) >> shift; // icl::last (operand) / divisor
  157. word_type base_rest = icl::first(operand) & mask , // icl::first(operand) % divisor
  158. ceil_rest = icl::last (operand) & mask ; // icl::last (operand) % divisor
  159. if(base == ceil) // [first, last] are within one bitset (chunk)
  160. (this->*combine)(base, base+1, bitset_type( to_upper_from(base_rest)
  161. & from_lower_to(ceil_rest)));
  162. else // [first, last] spread over more than one bitset (chunk)
  163. {
  164. element_type mid_low = base_rest == 0 ? base : base+1, // first element of mid part
  165. mid_up = ceil_rest == all ? ceil+1 : ceil ; // last element of mid part
  166. if(base_rest > 0) // Bitset of base interval has to be filled from base_rest to last
  167. (this->*combine)(base, base+1, bitset_type(to_upper_from(base_rest)));
  168. if(ceil_rest < all) // Bitset of ceil interval has to be filled from first to ceil_rest
  169. (this->*combine)(ceil, ceil+1, bitset_type(from_lower_to(ceil_rest)));
  170. if(mid_low < mid_up) // For the middle part all bits have to set.
  171. (this->*combine)(mid_low, mid_up, bitset_type(all));
  172. }
  173. return *this;
  174. }
  175. //]
  176. //[large_bitmap_combiners
  177. void add_(DomainT lo, DomainT up, BitSetT bits){_map += value_type(interval_type::right_open(lo,up), bits);}
  178. void subtract_(DomainT lo, DomainT up, BitSetT bits){_map -= value_type(interval_type::right_open(lo,up), bits);}
  179. void intersect_(DomainT lo, DomainT up, BitSetT bits){_map &= value_type(interval_type::right_open(lo,up), bits);}
  180. void flip_(DomainT lo, DomainT up, BitSetT bits){_map ^= value_type(interval_type::right_open(lo,up), bits);}
  181. //]
  182. //[large_bitmap_impl_map
  183. private:
  184. interval_bitmap_type _map;
  185. //]
  186. };
  187. } // mini
  188. #endif