Imported Upstream version 1.64.0
[platform/upstream/boost.git] / boost / multiprecision / detail / bitscan.hpp
1 ///////////////////////////////////////////////////////////////
2 //  Copyright 2013 John Maddock. Distributed under the Boost
3 //  Software License, Version 1.0. (See accompanying file
4 //  LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_
5 //
6 // Comparison operators for cpp_int_backend:
7 //
8 #ifndef BOOST_MP_DETAIL_BITSCAN_HPP
9 #define BOOST_MP_DETAIL_BITSCAN_HPP
10
11 #include <boost/detail/endian.hpp>
12
13 #if (defined(BOOST_MSVC) || (defined(__clang__) && defined(__c2__)) || (defined(BOOST_INTEL) && defined(_MSC_VER))) && (defined(_M_IX86) || defined(_M_X64))
14 #include <intrin.h>
15 #endif
16
17 namespace boost{ namespace multiprecision{ namespace detail{
18
19 template <class Unsigned>
20 inline unsigned find_lsb(Unsigned mask, const mpl::int_<0>&)
21 {
22    unsigned result = 0;
23    while(!(mask & 1u))
24    {
25       mask >>= 1;
26       ++result;
27    }
28    return result;
29 }
30
31 template <class Unsigned>
32 inline unsigned find_msb(Unsigned mask, const mpl::int_<0>&)
33 {
34    unsigned index = 0;
35    while(mask)
36    {
37       ++index;
38       mask >>= 1;
39    }
40    return --index;
41 }
42
43 #if (defined(BOOST_MSVC) || (defined(__clang__) && defined(__c2__)) || (defined(BOOST_INTEL) && defined(_MSC_VER))) && (defined(_M_IX86) || defined(_M_X64))
44
45 #pragma intrinsic(_BitScanForward,_BitScanReverse)
46
47 BOOST_FORCEINLINE unsigned find_lsb(unsigned long mask, const mpl::int_<1>&)
48 {
49    unsigned long result;
50    _BitScanForward(&result, mask);
51    return result;
52 }
53
54 BOOST_FORCEINLINE unsigned find_msb(unsigned long mask, const mpl::int_<1>&)
55 {
56    unsigned long result;
57    _BitScanReverse(&result, mask);
58    return result;
59 }
60 #ifdef _M_X64
61
62 #pragma intrinsic(_BitScanForward64,_BitScanReverse64)
63
64 BOOST_FORCEINLINE unsigned find_lsb(unsigned __int64 mask, const mpl::int_<2>&)
65 {
66    unsigned long result;
67    _BitScanForward64(&result, mask);
68    return result;
69 }
70 template <class Unsigned>
71 BOOST_FORCEINLINE unsigned find_msb(Unsigned mask, const mpl::int_<2>&)
72 {
73    unsigned long result;
74    _BitScanReverse64(&result, mask);
75    return result;
76 }
77 #endif
78
79 template <class Unsigned>
80 BOOST_FORCEINLINE unsigned find_lsb(Unsigned mask)
81 {
82    typedef typename make_unsigned<Unsigned>::type ui_type;
83    typedef typename mpl::if_c<
84       sizeof(Unsigned) <= sizeof(unsigned long),
85       mpl::int_<1>,
86 #ifdef _M_X64
87       typename mpl::if_c<
88          sizeof(Unsigned) <= sizeof(__int64),
89          mpl::int_<2>,
90          mpl::int_<0>
91       >::type
92 #else
93       mpl::int_<0>
94 #endif
95    >::type tag_type;
96    return find_lsb(static_cast<ui_type>(mask), tag_type());
97 }
98
99 template <class Unsigned>
100 BOOST_FORCEINLINE unsigned find_msb(Unsigned mask)
101 {
102    typedef typename make_unsigned<Unsigned>::type ui_type;
103    typedef typename mpl::if_c<
104       sizeof(Unsigned) <= sizeof(unsigned long),
105       mpl::int_<1>,
106 #ifdef _M_X64
107       typename mpl::if_c<
108          sizeof(Unsigned) <= sizeof(__int64),
109          mpl::int_<2>,
110          mpl::int_<0>
111       >::type
112 #else
113       mpl::int_<0>
114 #endif
115    >::type tag_type;
116    return find_msb(static_cast<ui_type>(mask), tag_type());
117 }
118
119 #elif defined(BOOST_GCC) || defined(__clang__) || (defined(BOOST_INTEL) && defined(__GNUC__))
120
121 BOOST_FORCEINLINE unsigned find_lsb(unsigned mask, mpl::int_<1> const&)
122 {
123    return __builtin_ctz(mask);
124 }
125 BOOST_FORCEINLINE unsigned find_lsb(unsigned long mask, mpl::int_<2> const&)
126 {
127    return __builtin_ctzl(mask);
128 }
129 BOOST_FORCEINLINE unsigned find_lsb(boost::ulong_long_type mask, mpl::int_<3> const&)
130 {
131    return __builtin_ctzll(mask);
132 }
133 BOOST_FORCEINLINE unsigned find_msb(unsigned mask, mpl::int_<1> const&)
134 {
135    return sizeof(unsigned) * CHAR_BIT - 1 - __builtin_clz(mask);
136 }
137 BOOST_FORCEINLINE unsigned find_msb(unsigned long mask, mpl::int_<2> const&)
138 {
139    return sizeof(unsigned long) * CHAR_BIT - 1 - __builtin_clzl(mask);
140 }
141 BOOST_FORCEINLINE unsigned find_msb(boost::ulong_long_type mask, mpl::int_<3> const&)
142 {
143    return sizeof(boost::ulong_long_type) * CHAR_BIT - 1 - __builtin_clzll(mask);
144 }
145 #ifdef BOOST_HAS_INT128
146 BOOST_FORCEINLINE unsigned find_msb(unsigned __int128 mask, mpl::int_<0> const&)
147 {
148    union { unsigned __int128 v; boost::uint64_t sv[2]; } val;
149    val.v = mask;
150 #ifdef BOOST_LITTLE_ENDIAN
151    if(val.sv[1])
152       return find_msb(val.sv[1], mpl::int_<3>()) + 64;
153    return find_msb(val.sv[0], mpl::int_<3>());
154 #else
155    if(val.sv[0])
156       return find_msb(val.sv[0], mpl::int_<3>()) + 64;
157    return find_msb(val.sv[1], mpl::int_<3>());
158 #endif
159 }
160 BOOST_FORCEINLINE unsigned find_lsb(unsigned __int128 mask, mpl::int_<0> const&)
161 {
162    union { unsigned __int128 v; boost::uint64_t sv[2]; } val;
163    val.v = mask;
164 #ifdef BOOST_LITTLE_ENDIAN
165    if(val.sv[0] == 0)
166       return find_lsb(val.sv[1], mpl::int_<3>()) + 64;
167    return find_lsb(val.sv[0], mpl::int_<3>());
168 #else
169    if(val.sv[1] == 0)
170       return find_lsb(val.sv[0], mpl::int_<3>()) + 64;
171    return find_lsb(val.sv[1], mpl::int_<3>());
172 #endif
173 }
174 #endif
175
176 template <class Unsigned>
177 BOOST_FORCEINLINE unsigned find_lsb(Unsigned mask)
178 {
179    typedef typename make_unsigned<Unsigned>::type ui_type;
180    typedef typename mpl::if_c<
181       sizeof(Unsigned) <= sizeof(unsigned),
182       mpl::int_<1>,
183       typename mpl::if_c<
184          sizeof(Unsigned) <= sizeof(unsigned long),
185          mpl::int_<2>,
186          typename mpl::if_c<
187             sizeof(Unsigned) <= sizeof(boost::ulong_long_type),
188             mpl::int_<3>,
189             mpl::int_<0>
190          >::type
191       >::type
192    >::type tag_type;
193    return find_lsb(static_cast<ui_type>(mask), tag_type());
194 }
195 template <class Unsigned>
196 BOOST_FORCEINLINE unsigned find_msb(Unsigned mask)
197 {
198    typedef typename make_unsigned<Unsigned>::type ui_type;
199    typedef typename mpl::if_c<
200       sizeof(Unsigned) <= sizeof(unsigned),
201       mpl::int_<1>,
202       typename mpl::if_c<
203          sizeof(Unsigned) <= sizeof(unsigned long),
204          mpl::int_<2>,
205          typename mpl::if_c<
206             sizeof(Unsigned) <= sizeof(boost::ulong_long_type),
207             mpl::int_<3>,
208             mpl::int_<0>
209          >::type
210       >::type
211    >::type tag_type;
212    return find_msb(static_cast<ui_type>(mask), tag_type());
213 }
214 #elif defined(BOOST_INTEL)
215 BOOST_FORCEINLINE unsigned find_lsb(unsigned mask, mpl::int_<1> const&)
216 {
217    return _bit_scan_forward(mask);
218 }
219 BOOST_FORCEINLINE unsigned find_msb(unsigned mask, mpl::int_<1> const&)
220 {
221    return _bit_scan_reverse(mask);
222 }
223 template <class Unsigned>
224 BOOST_FORCEINLINE unsigned find_lsb(Unsigned mask)
225 {
226    typedef typename make_unsigned<Unsigned>::type ui_type;
227    typedef typename mpl::if_c<
228       sizeof(Unsigned) <= sizeof(unsigned),
229       mpl::int_<1>,
230       mpl::int_<0>
231    >::type tag_type;
232    return find_lsb(static_cast<ui_type>(mask), tag_type());
233 }
234 template <class Unsigned>
235 BOOST_FORCEINLINE unsigned find_msb(Unsigned mask)
236 {
237    typedef typename make_unsigned<Unsigned>::type ui_type;
238    typedef typename mpl::if_c<
239       sizeof(Unsigned) <= sizeof(unsigned),
240       mpl::int_<1>,
241       mpl::int_<0>
242    >::type tag_type;
243    return find_msb(static_cast<ui_type>(mask), tag_type());
244 }
245 #else
246 template <class Unsigned>
247 BOOST_FORCEINLINE unsigned find_lsb(Unsigned mask)
248 {
249    return find_lsb(mask, mpl::int_<0>());
250 }
251 template <class Unsigned>
252 BOOST_FORCEINLINE unsigned find_msb(Unsigned mask)
253 {
254    return find_msb(mask, mpl::int_<0>());
255 }
256 #endif
257
258 }}}
259
260 #endif
261