dynamic_bitset.hpp 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  1. // -----------------------------------------------------------
  2. //
  3. // Copyright (c) 2001-2002 Chuck Allison and Jeremy Siek
  4. // Copyright (c) 2003-2006, 2008 Gennaro Prota
  5. // Copyright (c) 2014 Glen Joseph Fernandes
  6. // (glenjofe@gmail.com)
  7. // Copyright (c) 2018 Evgeny Shulgin
  8. //
  9. // Distributed under the Boost Software License, Version 1.0.
  10. // (See accompanying file LICENSE_1_0.txt or copy at
  11. // http://www.boost.org/LICENSE_1_0.txt)
  12. //
  13. // -----------------------------------------------------------
  14. #ifndef BOOST_DETAIL_DYNAMIC_BITSET_HPP
  15. #define BOOST_DETAIL_DYNAMIC_BITSET_HPP
  16. #include <memory>
  17. #include <cstddef>
  18. #include "boost/config.hpp"
  19. #include "boost/detail/workaround.hpp"
  20. #if ((defined(BOOST_MSVC) && (BOOST_MSVC >= 1600)) || (defined(__clang__) && defined(__c2__)) || (defined(BOOST_INTEL) && defined(_MSC_VER))) && (defined(_M_IX86) || defined(_M_X64))
  21. #include <intrin.h>
  22. #endif
  23. namespace boost {
  24. namespace detail {
  25. namespace dynamic_bitset_impl {
  26. // Gives (read-)access to the object representation
  27. // of an object of type T (3.9p4). CANNOT be used
  28. // on a base sub-object
  29. //
  30. template <typename T>
  31. inline const unsigned char * object_representation (T* p)
  32. {
  33. return static_cast<const unsigned char *>(static_cast<const void *>(p));
  34. }
  35. template<typename T, int amount, int width /* = default */>
  36. struct shifter
  37. {
  38. static void left_shift(T & v) {
  39. amount >= width ? (v = 0)
  40. : (v >>= BOOST_DYNAMIC_BITSET_WRAP_CONSTANT(amount));
  41. }
  42. };
  43. // ------- count function implementation --------------
  44. typedef unsigned char byte_type;
  45. // These two entities
  46. //
  47. // enum mode { access_by_bytes, access_by_blocks };
  48. // template <mode> struct mode_to_type {};
  49. //
  50. // were removed, since the regression logs (as of 24 Aug 2008)
  51. // showed that several compilers had troubles with recognizing
  52. //
  53. // const mode m = access_by_bytes
  54. //
  55. // as a constant expression
  56. //
  57. // * So, we'll use bool, instead of enum *.
  58. //
  59. template <bool value>
  60. struct value_to_type
  61. {
  62. value_to_type() {}
  63. };
  64. const bool access_by_bytes = true;
  65. const bool access_by_blocks = false;
  66. // the table: wrapped in a class template, so
  67. // that it is only instantiated if/when needed
  68. //
  69. template <bool dummy_name = true>
  70. struct count_table { static const byte_type table[]; };
  71. template <>
  72. struct count_table<false> { /* no table */ };
  73. const unsigned int table_width = 8;
  74. template <bool b>
  75. const byte_type count_table<b>::table[] =
  76. {
  77. // Automatically generated by GPTableGen.exe v.1.0
  78. //
  79. 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
  80. 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
  81. 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
  82. 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
  83. 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
  84. 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
  85. 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
  86. 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8
  87. };
  88. // overload for access by bytes
  89. //
  90. template <typename Iterator>
  91. inline std::size_t do_count(Iterator first, std::size_t length,
  92. int /*dummy param*/,
  93. value_to_type<access_by_bytes>* )
  94. {
  95. std::size_t num = 0;
  96. if (length)
  97. {
  98. const byte_type * p = object_representation(&*first);
  99. length *= sizeof(*first);
  100. do {
  101. num += count_table<>::table[*p];
  102. ++p;
  103. --length;
  104. } while (length);
  105. }
  106. return num;
  107. }
  108. // Some platforms have fast popcount operation, that allow us to implement
  109. // counting bits much more efficiently
  110. //
  111. template <typename ValueType>
  112. BOOST_FORCEINLINE std::size_t popcount(ValueType value) BOOST_NOEXCEPT
  113. {
  114. std::size_t num = 0;
  115. while (value) {
  116. num += count_table<>::table[value & ((1u<<table_width) - 1)];
  117. value >>= table_width;
  118. }
  119. return num;
  120. }
  121. #if ((defined(BOOST_MSVC) && (BOOST_MSVC >= 1600)) || (defined(__clang__) && defined(__c2__)) || (defined(BOOST_INTEL) && defined(_MSC_VER))) && (defined(_M_IX86) || defined(_M_X64))
  122. /*
  123. per https://github.com/boostorg/dynamic_bitset/issues/33
  124. this code does not support older cpus properly...
  125. it needs to check for cpuid support to avoid undefined behavior
  126. template <>
  127. BOOST_FORCEINLINE std::size_t popcount<unsigned short>(unsigned short value) BOOST_NOEXCEPT
  128. {
  129. return static_cast<std::size_t>(__popcnt16(value));
  130. }
  131. template <>
  132. BOOST_FORCEINLINE std::size_t popcount<unsigned int>(unsigned int value) BOOST_NOEXCEPT
  133. {
  134. return static_cast<std::size_t>(__popcnt(value));
  135. }
  136. #ifdef _M_X64
  137. template <>
  138. BOOST_FORCEINLINE std::size_t popcount<unsigned __int64>(unsigned __int64 value) BOOST_NOEXCEPT
  139. {
  140. return static_cast<std::size_t>(__popcnt64(value));
  141. }
  142. #endif
  143. */
  144. #elif defined(BOOST_GCC) || defined(__clang__) || (defined(BOOST_INTEL) && defined(__GNUC__))
  145. template <>
  146. BOOST_FORCEINLINE std::size_t popcount<unsigned int>(unsigned int value) BOOST_NOEXCEPT
  147. {
  148. return __builtin_popcount(value);
  149. }
  150. template <>
  151. BOOST_FORCEINLINE std::size_t popcount<unsigned long>(unsigned long value) BOOST_NOEXCEPT
  152. {
  153. return __builtin_popcountl(value);
  154. }
  155. template <>
  156. BOOST_FORCEINLINE std::size_t popcount<boost::ulong_long_type>(boost::ulong_long_type value) BOOST_NOEXCEPT
  157. {
  158. return __builtin_popcountll(value);
  159. }
  160. #endif
  161. // overload for access by blocks
  162. //
  163. template <typename Iterator, typename ValueType>
  164. inline std::size_t do_count(Iterator first, std::size_t length, ValueType,
  165. value_to_type<access_by_blocks>*)
  166. {
  167. std::size_t num = 0;
  168. while (length){
  169. num += popcount<ValueType>(*first);
  170. ++first;
  171. --length;
  172. }
  173. return num;
  174. }
  175. // -------------------------------------------------------
  176. // Some library implementations simply return a dummy
  177. // value such as
  178. //
  179. // size_type(-1) / sizeof(T)
  180. //
  181. // from vector<>::max_size. This tries to get more
  182. // meaningful info.
  183. //
  184. template <typename T>
  185. inline typename T::size_type vector_max_size_workaround(const T & v)
  186. BOOST_NOEXCEPT
  187. {
  188. typedef typename T::allocator_type allocator_type;
  189. const allocator_type& alloc = v.get_allocator();
  190. #if !defined(BOOST_NO_CXX11_ALLOCATOR)
  191. typedef std::allocator_traits<allocator_type> allocator_traits;
  192. const typename allocator_traits::size_type alloc_max =
  193. allocator_traits::max_size(alloc);
  194. #else
  195. const typename allocator_type::size_type alloc_max = alloc.max_size();
  196. #endif
  197. const typename T::size_type container_max = v.max_size();
  198. return alloc_max < container_max ? alloc_max : container_max;
  199. }
  200. // for static_asserts
  201. template <typename T>
  202. struct allowed_block_type {
  203. enum { value = T(-1) > 0 }; // ensure T has no sign
  204. };
  205. template <>
  206. struct allowed_block_type<bool> {
  207. enum { value = false };
  208. };
  209. template <typename T>
  210. struct is_numeric {
  211. enum { value = false };
  212. };
  213. # define BOOST_dynamic_bitset_is_numeric(x) \
  214. template<> \
  215. struct is_numeric< x > { \
  216. enum { value = true }; \
  217. } /**/
  218. BOOST_dynamic_bitset_is_numeric(bool);
  219. BOOST_dynamic_bitset_is_numeric(char);
  220. #if !defined(BOOST_NO_INTRINSIC_WCHAR_T)
  221. BOOST_dynamic_bitset_is_numeric(wchar_t);
  222. #endif
  223. BOOST_dynamic_bitset_is_numeric(signed char);
  224. BOOST_dynamic_bitset_is_numeric(short int);
  225. BOOST_dynamic_bitset_is_numeric(int);
  226. BOOST_dynamic_bitset_is_numeric(long int);
  227. BOOST_dynamic_bitset_is_numeric(unsigned char);
  228. BOOST_dynamic_bitset_is_numeric(unsigned short);
  229. BOOST_dynamic_bitset_is_numeric(unsigned int);
  230. BOOST_dynamic_bitset_is_numeric(unsigned long);
  231. #if defined(BOOST_HAS_LONG_LONG)
  232. BOOST_dynamic_bitset_is_numeric(::boost::long_long_type);
  233. BOOST_dynamic_bitset_is_numeric(::boost::ulong_long_type);
  234. #endif
  235. // intentionally omitted
  236. //BOOST_dynamic_bitset_is_numeric(float);
  237. //BOOST_dynamic_bitset_is_numeric(double);
  238. //BOOST_dynamic_bitset_is_numeric(long double);
  239. #undef BOOST_dynamic_bitset_is_numeric
  240. } // dynamic_bitset_impl
  241. } // namespace detail
  242. } // namespace boost
  243. #endif // include guard