1 // -----------------------------------------------------------
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 // Copyright (c) 2019 Andrey Semashev
10 // Distributed under the Boost Software License, Version 1.0.
11 // (See accompanying file LICENSE_1_0.txt or copy at
12 // http://www.boost.org/LICENSE_1_0.txt)
14 // -----------------------------------------------------------
16 #ifndef BOOST_DETAIL_DYNAMIC_BITSET_HPP
17 #define BOOST_DETAIL_DYNAMIC_BITSET_HPP
21 #include "boost/config.hpp"
22 #include "boost/detail/workaround.hpp"
24 #if ((defined(BOOST_MSVC) && (BOOST_MSVC >= 1600)) || (defined(__clang__) && defined(__c2__)) || (defined(BOOST_INTEL) && defined(_MSC_VER))) && (defined(_M_IX86) || defined(_M_X64))
31 namespace dynamic_bitset_impl {
35 BOOST_STATIC_CONSTEXPR T value = static_cast<T>(-1);
39 BOOST_CONSTEXPR_OR_CONST T max_limit<T>::value;
41 // Gives (read-)access to the object representation
42 // of an object of type T (3.9p4). CANNOT be used
43 // on a base sub-object
46 inline const unsigned char * object_representation (T* p)
48 return static_cast<const unsigned char *>(static_cast<const void *>(p));
51 template<typename T, int amount, int width /* = default */>
54 static void left_shift(T & v) {
55 amount >= width ? (v = 0)
56 : (v >>= BOOST_DYNAMIC_BITSET_WRAP_CONSTANT(amount));
60 // ------- count function implementation --------------
62 typedef unsigned char byte_type;
66 // enum mode { access_by_bytes, access_by_blocks };
67 // template <mode> struct mode_to_type {};
69 // were removed, since the regression logs (as of 24 Aug 2008)
70 // showed that several compilers had troubles with recognizing
72 // const mode m = access_by_bytes
74 // as a constant expression
76 // * So, we'll use bool, instead of enum *.
83 const bool access_by_bytes = true;
84 const bool access_by_blocks = false;
87 // the table: wrapped in a class template, so
88 // that it is only instantiated if/when needed
90 template <bool dummy_name = true>
91 struct count_table { static const byte_type table[]; };
94 struct count_table<false> { /* no table */ };
97 const unsigned int table_width = 8;
99 const byte_type count_table<b>::table[] =
101 // Automatically generated by GPTableGen.exe v.1.0
103 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,
104 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,
105 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,
106 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,
107 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,
108 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,
109 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,
110 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
114 // Some platforms have fast popcount operation, that allow us to implement
115 // counting bits much more efficiently
117 template <typename ValueType>
118 BOOST_FORCEINLINE std::size_t popcount(ValueType value) BOOST_NOEXCEPT
120 std::size_t num = 0u;
122 num += count_table<>::table[value & ((1u<<table_width) - 1)];
123 value >>= table_width;
128 #if (((defined(BOOST_MSVC) && (BOOST_MSVC >= 1600)) || (defined(__clang__) && defined(__c2__)) || (defined(BOOST_INTEL) && defined(_MSC_VER))) && (defined(_M_IX86) || defined(_M_X64))) \
129 && (defined(__POPCNT__) || defined(__AVX__))
132 BOOST_FORCEINLINE std::size_t popcount<unsigned short>(unsigned short value) BOOST_NOEXCEPT
134 return static_cast<std::size_t>(__popcnt16(value));
138 BOOST_FORCEINLINE std::size_t popcount<unsigned int>(unsigned int value) BOOST_NOEXCEPT
140 return static_cast<std::size_t>(__popcnt(value));
144 BOOST_FORCEINLINE std::size_t popcount<unsigned __int64>(unsigned __int64 value) BOOST_NOEXCEPT
147 return static_cast<std::size_t>(__popcnt64(value));
149 return static_cast<std::size_t>(__popcnt(static_cast< unsigned int >(value))) + static_cast<std::size_t>(__popcnt(static_cast< unsigned int >(value >> 32)));
153 #elif defined(BOOST_GCC) || defined(__clang__) || (defined(BOOST_INTEL) && defined(__GNUC__))
155 // Note: gcc builtins are implemented by compiler runtime when the target CPU may not support the necessary instructions
157 BOOST_FORCEINLINE std::size_t popcount<unsigned short>(unsigned short value) BOOST_NOEXCEPT
159 return static_cast<unsigned int>(__builtin_popcount(static_cast<unsigned int>(value)));
163 BOOST_FORCEINLINE std::size_t popcount<unsigned int>(unsigned int value) BOOST_NOEXCEPT
165 return static_cast<unsigned int>(__builtin_popcount(value));
169 BOOST_FORCEINLINE std::size_t popcount<unsigned long>(unsigned long value) BOOST_NOEXCEPT
171 return static_cast<unsigned int>(__builtin_popcountl(value));
175 BOOST_FORCEINLINE std::size_t popcount<boost::ulong_long_type>(boost::ulong_long_type value) BOOST_NOEXCEPT
177 return static_cast<unsigned int>(__builtin_popcountll(value));
182 // overload for access by blocks
184 template <typename Iterator, typename ValueType>
185 inline std::size_t do_count(Iterator first, std::size_t length, ValueType,
186 value_to_type<access_by_blocks>*)
188 std::size_t num1 = 0u, num2 = 0u;
189 while (length >= 2u) {
190 num1 += popcount<ValueType>(*first);
192 num2 += popcount<ValueType>(*first);
198 num1 += popcount<ValueType>(*first);
203 // overload for access by bytes
205 template <typename Iterator>
206 inline std::size_t do_count(Iterator first, std::size_t length,
208 value_to_type<access_by_bytes>*)
211 const byte_type* p = object_representation(&*first);
212 length *= sizeof(*first);
214 return do_count(p, length, static_cast<byte_type>(0u),
215 static_cast< value_to_type<access_by_blocks>* >(0));
221 // -------------------------------------------------------
224 // Some library implementations simply return a dummy
227 // size_type(-1) / sizeof(T)
229 // from vector<>::max_size. This tries to get more
232 template <typename T>
233 inline typename T::size_type vector_max_size_workaround(const T & v)
236 typedef typename T::allocator_type allocator_type;
238 const allocator_type& alloc = v.get_allocator();
240 #if !defined(BOOST_NO_CXX11_ALLOCATOR)
241 typedef std::allocator_traits<allocator_type> allocator_traits;
243 const typename allocator_traits::size_type alloc_max =
244 allocator_traits::max_size(alloc);
246 const typename allocator_type::size_type alloc_max = alloc.max_size();
249 const typename T::size_type container_max = v.max_size();
251 return alloc_max < container_max ? alloc_max : container_max;
254 // for static_asserts
255 template <typename T>
256 struct allowed_block_type {
257 enum { value = T(-1) > 0 }; // ensure T has no sign
261 struct allowed_block_type<bool> {
262 enum { value = false };
266 template <typename T>
268 enum { value = false };
271 # define BOOST_dynamic_bitset_is_numeric(x) \
273 struct is_numeric< x > { \
274 enum { value = true }; \
277 BOOST_dynamic_bitset_is_numeric(bool);
278 BOOST_dynamic_bitset_is_numeric(char);
280 #if !defined(BOOST_NO_INTRINSIC_WCHAR_T)
281 BOOST_dynamic_bitset_is_numeric(wchar_t);
284 BOOST_dynamic_bitset_is_numeric(signed char);
285 BOOST_dynamic_bitset_is_numeric(short int);
286 BOOST_dynamic_bitset_is_numeric(int);
287 BOOST_dynamic_bitset_is_numeric(long int);
289 BOOST_dynamic_bitset_is_numeric(unsigned char);
290 BOOST_dynamic_bitset_is_numeric(unsigned short);
291 BOOST_dynamic_bitset_is_numeric(unsigned int);
292 BOOST_dynamic_bitset_is_numeric(unsigned long);
294 #if defined(BOOST_HAS_LONG_LONG)
295 BOOST_dynamic_bitset_is_numeric(::boost::long_long_type);
296 BOOST_dynamic_bitset_is_numeric(::boost::ulong_long_type);
299 // intentionally omitted
300 //BOOST_dynamic_bitset_is_numeric(float);
301 //BOOST_dynamic_bitset_is_numeric(double);
302 //BOOST_dynamic_bitset_is_numeric(long double);
304 #undef BOOST_dynamic_bitset_is_numeric
306 } // dynamic_bitset_impl
307 } // namespace detail
311 #endif // include guard