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