ALib C++ Library
Library Version: 2412 R0
Documentation generated by doxygen
Loading...
Searching...
No Matches
bits.hpp
Go to the documentation of this file.
1//==================================================================================================
2/// \file
3/// This header file is part of the \aliblong. It does not belong to an \alibmod and is
4/// included in any \alibdist.
5///
6/// \emoji :copyright: 2013-2024 A-Worx GmbH, Germany.
7/// Published under \ref mainpage_license "Boost Software License".
8//==================================================================================================
9#ifndef HPP_ALIB_LANG_BITS
10#define HPP_ALIB_LANG_BITS 1
11#pragma once
13#include "alib/lang/tmp.hpp"
14#if defined(_WIN32)
15# include <intrin.h>
16#endif
17#include <iterator>
18#if ALIB_CPP_STANDARD >= 20
19# include <bit>
20#endif
21
22
24
25namespace alib {
26
27/// This namespace holds types and functions, which are very close to the C++ language itself.
28/// The availability of most of the entities found here, is \b not related to the inclusion of
29/// a certain \alibmod within the \alibdist chosen. Instead, the corresponding header files
30/// are \ref alib_manual_modules_common_files "always included" when compiling \alib.
31///
32/// With the inclusion of \alib_basecamp in the \alibdist, type \alib{lang;Camp} is found, which is
33/// used to organize the library in respect to resource management and bootstrapping.
34/// Furthermore, this very special "Camp-Module" adds sub-namespaces
35/// - \ref alib::lang::basecamp,
36/// - \ref alib::lang::format,
37/// - \ref alib::lang::resources and
38/// - \ref alib::lang::system
39///
40/// to this namespace, as well as a few other basic language-related types like
41/// \alib{lang::Exception}.
42///
43/// # Reference Documentation #
44namespace lang {
45/// The C++ language defines the right-hand-side argument of bit shift operations to be of
46/// type <c>int</c>. To increase code readability we define this type explicitly.
47using ShiftOpRHS = int;
48
49#define bitsof(type) static_cast<int>(sizeof(type) * 8)
50
51/// Like C++ keyword <c>sizeof</c> but returns the number of bits of the type of the given value.
52/// The return type is <c>int</c> instead of <c>size_t</c>, which satisfies \alib code conventions.
53///
54/// \note To improve code readability, namely to a) indicate that this is an inlined, constant
55/// expression and b) to indicate that this is just using keyword <c>sizeof</c>,
56/// as an exception from the rules, this function is spelled in lower case.
57///
58/// \see Macro \ref bitsof "bitsof(type)", which works directly on the type.
59///
60/// @param val The (sample) value to deduce the type from. Otherwise ignored.
61/// @tparam T The type to receive the size in bits from.
62/// @return The size of \p{TIntegral} in bits.
63template<typename T> inline constexpr int bitsofval(const T& val)
64{
65 (void) val; return sizeof(T) * 8;
66}
67
68#if DOXYGEN
69 /// Inline namespace function that returns a mask with bits set to \c 1 up to the given
70 /// binary digit, and bits above to \c 0.
71 /// If parameter \p TWidth is greater or equal to the width of the given \p TIntegral type, then
72 /// all bits are set in the returned value.
73 ///
74 /// \see While this is the fully templated version, with
75 /// #alib::lang::LowerMask<TIntegral>(ShiftOpRHS), a run-time version is given.
76 ///
77 /// @tparam TWidth The number of lower bits to set to \c 1.
78 /// @tparam TIntegral The integral type to operate on.
79 /// @return The requested mask.
80 template<ShiftOpRHS TWidth, typename TIntegral>
81 inline constexpr
82 TIntegral LowerMask();
83#else
84
85 template<ShiftOpRHS TWidth, typename TIntegral>
86 ATMP_T_IF(TIntegral, std::is_integral<TIntegral>::value && TWidth >= bitsof(TIntegral) )
87 inline constexpr
88 LowerMask()
89 {
90 return TIntegral(~TIntegral(0));
91 }
92
93 template<ShiftOpRHS TWidth, typename TIntegral>
94 ATMP_T_IF(TIntegral, std::is_integral<TIntegral>::value && TWidth < bitsof(TIntegral) )
95 inline constexpr
96 LowerMask()
97 {
99 using TUnsigned= typename std::make_unsigned<TIntegral>::type;
100 return TIntegral(~(TUnsigned(~TUnsigned(0)) << TWidth) );
102 }
103#endif
104
105#if DOXYGEN
106 /// Inline namespace function that returns a mask with bits set to \c 1 up to the given
107 /// binary digit, and bits above to \c 0.
108 /// Parameter \p width <b>must not be greater or equal</b> to the width of the given
109 /// \p TIntegral type. In debug compilations, an assertion is raised in that case.
110 ///
111 /// \see A fully templated version usable when the number of bits are known at compile time,
112 /// is given with #LowerMask<ShiftOpRHS,typename>().
113 ///
114 /// @tparam TIntegral The integral type to operate on.
115 /// @param width The number of lower bits to set in the mask returned.
116 /// @return The requested mask.
117 template<typename TIntegral>
118 inline constexpr
119 TIntegral LowerMask( ShiftOpRHS width );
120#else
121 template<typename TIntegral>
122 ATMP_T_IF(TIntegral, std::is_integral<TIntegral>::value )
123 inline
124 constexpr
125 LowerMask( ShiftOpRHS width )
126 {
127 ALIB_ASSERT_ERROR( width < bitsof(TIntegral), "ALIB/BITS",
128 "Requested mask width wider than integral: ", width )
129 using TUnsigned= typename std::make_unsigned<TIntegral>::type;
130 return TIntegral(~(TUnsigned(~TUnsigned(0)) << width ));
131 }
132#endif
133
134#if DOXYGEN
135 /// Inline namespace function that returns a mask with bits set to \c 0 up to the given
136 /// binary digit, and bits above to \c 1.
137 /// If parameter \p TWidth is greater or equal to the width of the given \p TIntegral type, then
138 /// all bits are set in the returned value.
139 ///
140 /// \see While this is the fully templated version, with
141 /// #alib::lang::UpperMask<TIntegral>(ShiftOpRHS), a run-time version is given.
142 ///
143 /// @tparam TWidth The number of lower bits to clear to \c 1.
144 /// @tparam TIntegral The integral type to operate on.
145 /// @return The requested mask.
146 template<ShiftOpRHS TWidth, typename TIntegral>
147 inline constexpr
148 TIntegral UpperMask();
149#else
150
151 template<ShiftOpRHS TWidth, typename TIntegral>
152 ATMP_T_IF(TIntegral, std::is_integral<TIntegral>::value && TWidth >= bitsof(TIntegral))
153 inline constexpr
154 UpperMask()
155 {
156 return TIntegral(0);
157 }
158 template<ShiftOpRHS TWidth, typename TIntegral>
159 ATMP_T_IF(TIntegral, std::is_integral<TIntegral>::value && TWidth < bitsof(TIntegral) )
160 inline constexpr
161 UpperMask()
162 {
163 using TUnsigned= typename std::make_unsigned<TIntegral>::type;
164 return TIntegral((TUnsigned(~TUnsigned(0)) << TWidth));
165 }
166#endif
167
168#if DOXYGEN
169 /// Inline namespace function that returns a mask with bits set to \c 0 up to the given
170 /// binary digit, and bits above to \c 1.
171 /// Parameter \p width <b>must not be greater or equal</b> to the width of the given
172 /// \p TIntegral type. In debug compilations, an assertion is raised in that case.
173 ///
174 /// \see A fully templated version usable when the number of bits are known at compile time,
175 /// is given with #UpperMask<ShiftOpRHS,typename>().
176 ///
177 /// @tparam TIntegral The integral type to operate on.
178 /// @param width The number of lower bits to clear in the mask returned.
179 /// @return The requested mask.
180 template<typename TIntegral>
181 inline constexpr
182 TIntegral UpperMask( ShiftOpRHS width );
183#else
184 template<typename TIntegral>
185 ATMP_T_IF(TIntegral, std::is_integral<TIntegral>::value )
186 inline constexpr
187 UpperMask( ShiftOpRHS width )
188 {
189 ALIB_ASSERT_ERROR( width < bitsof(TIntegral), "ALIB/BITS",
190 "Requested mask width wider than integral: ", width )
191 using TUnsigned= typename std::make_unsigned<TIntegral>::type;
192 return TIntegral( (TUnsigned(~TUnsigned(0)) << width) );
193 }
194#endif
195
196#if DOXYGEN
197 /// Inline namespace function that keeps the given number of lower bits and masks the higher ones
198 /// out of the given integral value.
199 /// If parameter \p TWidth is greater or equal to the width of the given \p TIntegral type, then
200 /// all bits are returned.
201 ///
202 /// \see While this is the fully templated version and hence explicitly constexpression for the
203 /// reader of a code, with
204 /// #alib::lang::LowerBits<TIntegral>(lang::ShiftOpRHS,TIntegral), a version is given.
205 ///
206 /// @param value The value to mask.
207 /// @tparam TWidth The number of lower bits to keep.
208 /// @tparam TIntegral The integral type to operate on (deduced by the compiler).
209 /// @return The given value with the upper remaining bits cleared.
210 template<ShiftOpRHS TWidth, typename TIntegral> inline constexpr TIntegral LowerBits( TIntegral value );
211#else
212 template<ShiftOpRHS TWidth, typename TIntegral>
213 ATMP_T_IF(TIntegral, std::is_integral<TIntegral>::value )
214 inline constexpr
215 LowerBits( TIntegral value )
216 {
217 if constexpr ( TWidth >= bitsof(TIntegral) )
218 return value;
219 return value & LowerMask<TWidth,TIntegral>( );
220 }
221#endif
222
223#if DOXYGEN
224 /// Inline namespace function that keeps the given number of lower bits and masks the higher ones
225 /// out of the given integral value.
226 /// Parameter \p width <b>must not be greater or equal</b> to the width of the given
227 /// \p TIntegral type. In debug compilations, an assertion is raised.
228 ///
229 /// \see A fully templated version usable when the number of bits are known at compile time,
230 /// is given with #LowerBits<ShiftOpRHS,TIntegral>().
231 ///
232 /// @param width The number of lower bits to keep.
233 /// @param value The value to mask.
234 /// @tparam TIntegral The integral type to operate on (deduced by the compiler).
235 /// @return The given value with the upper remaining bits cleared.
236 template<typename TIntegral> inline constexpr TIntegral LowerBits( ShiftOpRHS width, TIntegral value );
237#else
238
239 template<typename TIntegral>
240 ATMP_T_IF(TIntegral, std::is_integral<TIntegral>::value )
241 inline constexpr
242 LowerBits( ShiftOpRHS width, TIntegral value )
243 {
244 return value & LowerMask<TIntegral>( width );
245 }
246#endif
247
248#if DOXYGEN
249 /// Returns the logarithm base 2 for the size in bits of the template given integral type.<p>
250 /// Precisely, this function returns:
251 /// - 3 for 8-bit types,
252 /// - 4 for 16-bit types,
253 /// - 5 for 32-bit types,
254 /// - 6 for 64-bit types and
255 /// - 7 for 128-bit types.
256 /// @tparam TIntegral The integral type to count bits in.
257 /// @return The number of bits needed to count the bits of type \p TIntegral.
258 template<typename TIntegral> inline constexpr int Log2OfSize();
259#else
260 template<typename TIntegral>
261 ATMP_T_IF(int, std::is_integral<TIntegral>::value )
262 inline constexpr
263 Log2OfSize()
264 {
265 static_assert( bitsof(TIntegral) <= 128, "Integrals larger than 128 are not supported.");
266 if constexpr (bitsof(TIntegral) == 32) return 5;
267 if constexpr (bitsof(TIntegral) == 64) return 7;
268 if constexpr (bitsof(TIntegral) == 8) return 3;
269 if constexpr (bitsof(TIntegral) == 16) return 4;
270 return 8;
271 }
272#endif
273
274#if DOXYGEN
275 /// Returns the number of bits set in an integral value.
276 /// Internally, this method uses:
277 /// - On gcc/clang: builtin method \c __builtin_popcount (and variations) which translate to a
278 /// single assembly instruction, and a constexpression in case \p value is known at compile-time.
279 /// - With MS-compilers, intrinsic \c popcount is used.
280 /// - On other platforms, the number is evaluated programmatically.
281 ///
282 /// @tparam TIntegral The integral type to operate on.
283 /// @param value The value to test.
284 /// @return The number of bits set in a value.
285 template<typename TIntegral> constexpr int BitCount( TIntegral value );
286#else
287
288 // a magical popcount function stolen from the internet
289 namespace { inline int countBitsFast(uint32_t n)
290 {
291 n = (n & 0x55555555u) + ((n >> 1) & 0x55555555u);
292 n = (n & 0x33333333u) + ((n >> 2) & 0x33333333u);
293 n = (n & 0x0f0f0f0fu) + ((n >> 4) & 0x0f0f0f0fu);
294 n = (n & 0x00ff00ffu) + ((n >> 8) & 0x00ff00ffu);
295 n = (n & 0x0000ffffu) + ((n >>16) & 0x0000ffffu);
296 return int(n);
297 }} // anonymous namespace
298
299
300 template<typename TIntegral>
301 ATMP_T_IF(int, std::is_integral<TIntegral>::value )
303 constexpr
304 BitCount( TIntegral value )
305 {
306 #if ALIB_CPP_STANDARD >= 20
307 return std::popcount( static_cast<typename std::make_unsigned<TIntegral>::type>( value ) );
308 #elif defined(_WIN64)
309 using TUnsigned = typename std::make_unsigned<TIntegral>::type;
310 if constexpr (bitsof(TIntegral) <= 32 )
311 return __popcnt (static_cast<TUnsigned>( value ));
312 return int(__popcnt64 (static_cast<TUnsigned>( value )));
313 #elif defined(__has_builtin) && __has_builtin( __builtin_popcount )
314 using TUnsigned = typename std::make_unsigned<TIntegral>::type;
315
316 if constexpr (sizeof(TIntegral) == sizeof(long long)) return int(__builtin_popcountll( TUnsigned(value) ));
317 if constexpr (sizeof(TIntegral) == sizeof(long )) return int(__builtin_popcountl ( TUnsigned(value) ));
318 if constexpr (sizeof(TIntegral) == sizeof(int )) return int(__builtin_popcount ( TUnsigned(value) ));
319 return int(__builtin_popcountll( static_cast<unsigned long long>(value)));
320 #else
321 if constexpr (bitsof(TIntegral) <= 32)
322 return countBitsFast(uint32_t(value));
323 return countBitsFast(uint32_t(value) & 0xFFFFFFFF)
324 + countBitsFast(uint32_t(value >> 32));
325 #endif
326 }
327#endif // DOXYGEN
328
329#if DOXYGEN
330 /// Returns the number of the leading 0-bits in an integral type.
331 /// Internally, this method uses:
332 /// - On gcc/clang: builtin methods \c __builtin_clz (or variations) which translate to a
333 /// single assembly instruction, and a constexpression in case \p value is known at compile-time.
334 /// - With MS-compilers, intrinsics \c _BitScanReverse or \c _BitScanReverse64 is used.
335 /// - On other platforms, a binary search is performed.
336 ///
337 /// \attention
338 /// This function must not be called with a \p value of <c>0</c>!
339 /// In debug-compilations, this method raises an \alib assertion in this case, while in
340 /// release-compilations, the result is <em>'undefined'</em>.
341 /// With function \ref MSB0, an alternative is given which returns \c 0 if the input is \c 0.
342 ///
343 /// @tparam TIntegral The integral type to operate on.
344 /// @param value The value to test. Must not be \c 0.
345 /// @return The highest bit set in \p value.
346 template<typename TIntegral> constexpr int CLZ( TIntegral value );
347#else
348 template<typename TIntegral>
349 ATMP_T_IF(int, std::is_integral<TIntegral>::value )
350 constexpr inline
351 CLZ( TIntegral value )
352 {
353 ALIB_ASSERT_ERROR( value != 0, "ALIB/BITS",
354 "Illegal value 0 passed to MSB(). Use MSB0() if 0 values need to be handled." )
355
356 #if ALIB_CPP_STANDARD >= 20
357 return std::countl_zero( static_cast<typename std::make_unsigned<TIntegral>::type>( value ) );
358
359 #elif defined(_WIN64)
360 unsigned long bitScanResult;
361 if constexpr (bitsof(TIntegral) <= 32 )
362 {
363 _BitScanReverse( &bitScanResult, static_cast<unsigned long>(value) );
364 return bitsof(TIntegral) - bitsof(unsigned long) + 31 - bitScanResult;
365 }
366 else
367 {
368 _BitScanReverse64( &bitScanResult, uint64_t(value) );
369 return bitsof(TIntegral) - bitsof(uint64_t) + 63 - bitScanResult;
370 }
371 #elif defined(__has_builtin) && __has_builtin( __builtin_clz ) \
372 && __has_builtin( __builtin_clzl ) \
373 && __has_builtin( __builtin_clzll )
374 if constexpr (sizeof(TIntegral) == sizeof(int )) return int(__builtin_clz ( static_cast<unsigned int >(value) ));
375 if constexpr (sizeof(TIntegral) == sizeof(long )) return int(__builtin_clzl ( static_cast<unsigned long >(value) ));
376 if constexpr (sizeof(TIntegral) == sizeof(long long)) return int(__builtin_clzll( static_cast<unsigned long long>(value) ));
377 return bitsof(TIntegral) - bitsof(int) + int(__builtin_clz ( static_cast<unsigned int >(value) ));
378 #else
379 // Do it manually using binary search:
380 ShiftOpRHS msb= bitsof(TIntegral) -1;
381 ShiftOpRHS l= 0;
382 ShiftOpRHS r= bitsof(TIntegral);
383 while( l <= r )
384 {
385 ShiftOpRHS mid= (l + r) / 2;
386 if( (TIntegral(1) << mid) > value )
387 {
388 msb= mid -1;
389 r= mid - 1;
390 }
391 else
392 l= mid + 1;
393 }
394 return bitsof(TIntegral) -1 - msb;
395 #endif
396 }
397#endif
398
399#if DOXYGEN
400 /// Variant of \ref CLZ which tests given parameter \p value on \c 0 and returns
401 /// <c>sizeof(TIntegral) * 8</c> in this case.
402 /// Otherwise, returns the result of \ref CLZ.
403 ///
404 /// @tparam TIntegral The integral type to operate on.
405 /// @param value The value to test. May be \c 0, which results to the number of bits in
406 /// \p TIntegral.
407 /// @return The number of leading zero-bits in \p value.
408 template<typename TIntegral> constexpr int CLZ0( TIntegral value);
409#else
410 template<typename TIntegral>
411 ATMP_T_IF(int, std::is_integral<TIntegral>::value )
412 constexpr inline
413 CLZ0( TIntegral value)
414 {
415 if( value == 0 )
416 return bitsof(TIntegral);
417 return CLZ(value);
418 }
419#endif
420
421#if DOXYGEN
422 /// Returns the number of the trailing 0-bits in an integral type.
423 /// Internally, this method uses:
424 /// - On gcc/clang: builtin methods \c __builtin_ctz (and variations) which translate to a
425 /// single assembly instruction, and a constexpression in case \p value is known at compile-time.
426 /// - With MS-compilers, intrinsics \c _BitScanForward or \c _BitScanForward64 is used.
427 /// - On other platforms, a binary search is performed.
428 ///
429 /// \attention
430 /// This function must not be called with a \p value of <c>0</c>!
431 /// In debug-compilations, this method raises an \alib assertion in this case, while in
432 /// release-compilations, the result is <em>'undefined'</em>.
433 /// With function \ref CTZ0, an alternative is given which returns \c 0 if the input is \c 0.
434 ///
435 /// @tparam TIntegral The integral type to operate on.
436 /// @param value The value to test. Must not be \c 0.
437 /// @return The lowest bit set in \p value.
438 template<typename TIntegral> constexpr int CTZ( TIntegral value );
439#else
440 template<typename TIntegral>
441 ATMP_T_IF(int, std::is_integral<TIntegral>::value )
443 CTZ( TIntegral value )
444 {
445 ALIB_ASSERT_ERROR( value != 0, "ALIB/BITS",
446 "Illegal value 0 passed to MSB(). Use MSB0() if 0 values need to be handled." )
447
448 #if ALIB_CPP_STANDARD >= 20
449 return std::countr_zero( static_cast<typename std::make_unsigned<TIntegral>::type>( value ) );
450
451 #elif defined(_WIN64)
452 unsigned long bitScanResult;
453 if constexpr (bitsof(TIntegral) <= 32 )
454 {
455 _BitScanForward( &bitScanResult, static_cast<unsigned long>(value) );
456 return bitScanResult;
457 }
458 _BitScanForward64( &bitScanResult, uint64_t(value) );
459 return bitScanResult;
460
461#elif defined(__has_builtin) && __has_builtin( __builtin_ctz ) \
462 && __has_builtin( __builtin_ctzl ) \
463 && __has_builtin( __builtin_ctzll )
464 if constexpr (sizeof(TIntegral) == sizeof(int )) return int(__builtin_ctz ( static_cast<unsigned int >(value) ));
465 if constexpr (sizeof(TIntegral) == sizeof(long )) return int(__builtin_ctzl ( static_cast<unsigned long >(value) ));
466 if constexpr (sizeof(TIntegral) == sizeof(long long)) return int(__builtin_ctzll( static_cast<unsigned long long>(value) ));
467 return int(__builtin_ctz ( static_cast<unsigned int >(value) ));
468#else
469 // Do it manually using binary search:
470 int result= 0;
471 int width= bitsof(TIntegral) / 2;
472 TIntegral mask= LowerMask<TIntegral>(width);
473 while( width )
474 {
475 if( (value & mask) == 0 )
476 {
477 result+= width;
478 value>>= width;
479 }
480 width/=2;
481 mask>>= width;
482 }
483 return result;
484#endif
485 }
486#endif
487
488#if DOXYGEN
489 /// Variant of \ref CTZ which tests given parameter \p value on \c 0 and returns
490 /// <c>sizeof(TIntegral) * 8</c> in this case.
491 /// Otherwise, returns the result of \ref CLZ.
492 ///
493 /// @tparam TIntegral The integral type to operate on.
494 /// @param value The value to test. May be \c 0, which results to the number of bits in
495 /// \p TIntegral.
496 /// @return The number of trailing zero-bits in \p value. In case the given value is \c 0,
497 /// <c>sizeof(Tintegral) * 8</c> is returned.
498 ///
499 template<typename TIntegral> constexpr int CTZ0( TIntegral value);
500#else
501 template<typename TIntegral>
502 ATMP_T_IF(int, std::is_integral<TIntegral>::value )
503 constexpr inline
504 CTZ0( TIntegral value)
505 {
506 if( value == 0 )
507 return bitsof(TIntegral);
508 return CTZ(value);
509 }
510#endif
511
512#if DOXYGEN
513 /// Returns the number of the most significant bit in an integral type.
514 /// Internally, this method uses \alib{lang;CLZ} and returns
515 ///
516 /// int(sizeof(TIntegral)) * 8 - CLZ(value)
517 ///
518 /// \attention
519 /// This function must not be called with a \p value of <c>0</c>!
520 /// In debug-compilations, this method raises an \alib assertion in this case, while in
521 /// release-compilations, the result is <em>'undefined'</em>.
522 /// With function \ref MSB0, an alternative is given which returns \c 0 if the input is \c 0.
523 ///
524 /// \note A corresponding function "LSB", to receive the least significant bit is not given.
525 /// Instead, use <c>CTZ() + 1</c>.
526 ///
527 ///
528 /// @tparam TIntegral The integral type to operate on.
529 /// @param value The value to test. Must not be \c 0.
530 /// @return The highest bit set in \p value. The numbering starts with \c 1 and ends with
531 /// <c>sizeof(Tintegral) * 8</c>.
532 template<typename TIntegral> constexpr int MSB( TIntegral value);
533#else
534 template<typename TIntegral>
535 ATMP_T_IF(int, std::is_integral<TIntegral>::value )
536 constexpr inline
537 MSB( TIntegral value)
538 {
539 ALIB_ASSERT_ERROR( value != 0, "ALIB/BITS",
540 "Illegal value 0 passed to MSB(). Use MSB0() if 0 values need to be handled." )
541 return bitsof(TIntegral) - CLZ(value);
542 }
543#endif
544
545#if DOXYGEN
546 /// Variant of \ref MSB which tests given parameter \p value on \c 0 and returns \c 0 in this
547 /// case. Otherwise, returns the result of \ref MSB.
548 ///
549 /// @tparam TIntegral The integral type to operate on.
550 /// @param value The value to test. May be \c 0, which results to \c 0.
551 /// @return The highest bit set in \p value. The numbering starts with \c 1 and ends with
552 /// <c>sizeof(Tintegral)* 8</c>. If \p{value} is \c 0, hence no bit is set,
553 /// \c 0 is returned.
554 template<typename TIntegral> constexpr int MSB0( TIntegral value);
555#else
556
557 template<typename TIntegral>
558 ATMP_T_IF(int, std::is_integral<TIntegral>::value )
560 constexpr
561 MSB0( TIntegral value)
562 {
563 if( value == 0 )
564 return 0;
565 return MSB(value);
566 }
567#endif
568}} // namespace [alib::lang]
569
571
572#endif // HPP_ALIB_LANG_BITS
573
#define bitsof(type)
Definition bits.hpp:49
#define ALIB_WARNINGS_IGNORE_INTEGRAL_CONSTANT_OVERFLOW
Definition alib.hpp:829
#define ALIB_WARNINGS_RESTORE
Definition alib.hpp:849
#define ALIB_FORCE_INLINE
Definition alib.hpp:650
#define ALIB_ASSERT_ERROR(cond,...)
Definition alib.hpp:1271
#define ATMP_T_IF(T, Cond)
Definition tmp.hpp:49
constexpr int bitsofval(const T &val)
Definition bits.hpp:63
constexpr int BitCount(TIntegral value)
constexpr int CLZ(TIntegral value)
constexpr TIntegral LowerMask()
constexpr int MSB0(TIntegral value)
constexpr int Log2OfSize()
constexpr int CLZ0(TIntegral value)
constexpr int MSB(TIntegral value)
constexpr int CTZ0(TIntegral value)
constexpr int CTZ(TIntegral value)
constexpr TIntegral LowerBits(TIntegral value)
constexpr TIntegral UpperMask()
Definition alib.cpp:69
int ShiftOpRHS
Type alias in namespace alib.