ALib C++ Library
Library Version: 2510 R0
Documentation generated by doxygen
Loading...
Searching...
No Matches
bits.inl
Go to the documentation of this file.
1//==================================================================================================
2/// \file
3/// This header-file is part of module \alib_lang of the \aliblong.
4///
5/// \emoji :copyright: 2013-2025 A-Worx GmbH, Germany.
6/// Published under \ref mainpage_license "Boost Software License".
7//==================================================================================================
8ALIB_EXPORT namespace alib {
10
11/// This namespace holds types and functions of the module \alib_lang, which are very close to
12/// the C++ language itself.
13/// The entities found here are always included in any \alibbuild and are accessed by
14/// including the header \implude{Lang}.
15///
16/// # Reference Documentation #
17namespace lang {
18/// The C++ language defines the right-hand-side argument of bit shift operations to be of
19/// type <c>int</c>. To increase code readability we define this type explicitly.
20using ShiftOpRHS = int;
21
22
23/// Like C++ keyword <c>sizeof</c> but returns the number of bits of the type of the given value.
24/// The return type is <c>int</c> instead of <c>size_t</c>, which satisfies \alib code conventions.
25///
26/// \note To improve code readability, namely to a) indicate that this is an inlined, constant
27/// expression and b) to indicate that this is just using keyword <c>sizeof</c>,
28/// as an exception from the rules, this function is spelled in lower case.
29///
30/// \see Macro \ref bitsof "bitsof(type)", which works directly on the type.
31///
32/// @param val The (sample) value to deduce the type from. Otherwise ignored.
33/// @tparam T The type to receive the size in bits from.
34/// @return The size of \p{TIntegral} in bits.
35template<typename T> inline constexpr int bitsofval(const T& val)
36{
37 (void) val; return sizeof(T) * 8;
38}
39
40/// Inline namespace function that returns a mask with bits set to \c 1 up to the given
41/// binary digit, and bits above to \c 0.
42/// If parameter \p TWidth is greater or equal to the width of the given \p TIntegral type, then
43/// all bits are set in the returned value.
44///
45/// \see While this is the fully templated version, with
46/// #alib::lang::LowerMask<TIntegral>(ShiftOpRHS), a run-time version is given.
47///
48/// @tparam TWidth The number of lower bits to set to \c 1.
49/// @tparam TIntegral The integral type to operate on.
50/// @return The requested mask.
51template<ShiftOpRHS TWidth, typename TIntegral>
52requires ( std::is_integral<TIntegral>::value && TWidth < bitsof(TIntegral) )
53constexpr TIntegral LowerMask()
54{
56 using TUnsigned= typename std::make_unsigned<TIntegral>::type;
57 return TIntegral(~(TUnsigned(~TUnsigned(0)) << TWidth) );
59}
60
61/// Overloaded version handling bit-overflow.
62/// \see
63/// - Original version of this function.
64/// - While this is the fully templated version, with
65/// #alib::lang::LowerMask<TIntegral>(ShiftOpRHS), a run-time version is given.
66///
67/// @tparam TWidth The number of lower bits to set to \c 1.
68/// @tparam TIntegral The integral type to operate on.
69/// @return The requested mask.
70template<ShiftOpRHS TWidth, typename TIntegral>
71requires ( std::is_integral<TIntegral>::value && TWidth >= bitsof(TIntegral) )
72constexpr TIntegral LowerMask() { return TIntegral(~TIntegral(0)); }
73
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/// Parameter \p{width} <b>must not be greater or equal</b> to the width of the given
78/// \p{TIntegral} type.
79/// In debug-compilations, an \ref alib_mod_assert "error is raised" in that case.
80///
81/// \see A fully templated version usable when the number of bits are known at compile time,
82/// is given with #LowerMask<ShiftOpRHS,typename>().
83///
84/// @tparam TIntegral The integral type to operate on.
85/// @param width The number of lower bits to set in the mask returned.
86/// @return The requested mask.
87template<typename TIntegral>
88requires std::integral<TIntegral>
89constexpr TIntegral LowerMask( ShiftOpRHS width )
90{
91 ALIB_ASSERT_ERROR( width < bitsof(TIntegral), "ALIB/BITS",
92 "Requested mask width wider than integral: {} >= {}", width, bitsof(TIntegral) )
93 using TUnsigned= typename std::make_unsigned<TIntegral>::type;
94 return TIntegral(~(TUnsigned(~TUnsigned(0)) << width ));
95}
96
97
98/// Inline namespace function that returns a mask with bits set to \c 0 up to the given
99/// binary digit, and bits above to \c 1.
100/// If parameter \p TWidth is greater or equal to the width of the given \p TIntegral type, then
101/// all bits are set in the returned value.
102///
103/// \see While this is the fully templated version, with
104/// #alib::lang::UpperMask<TIntegral>(ShiftOpRHS), a run-time version is given.
105///
106/// @tparam TWidth The number of lower bits to clear to \c 1.
107/// @tparam TIntegral The integral type to operate on.
108/// @return The requested mask.
109template<ShiftOpRHS TWidth, typename TIntegral>
110requires ( std::is_integral<TIntegral>::value && TWidth < bitsof(TIntegral) )
111constexpr TIntegral UpperMask()
112{
113 using TUnsigned= typename std::make_unsigned<TIntegral>::type;
114 return TIntegral((TUnsigned(~TUnsigned(0)) << TWidth));
115}
116
117/// Overloaded version handling bit-overflow.
118/// \see
119/// - Original version of this function.
120/// - While this is the fully templated version, with
121/// #alib::lang::UpperMask<TIntegral>(ShiftOpRHS), a run-time version is given.
122///
123/// @tparam TWidth The number of lower bits to set to \c 1.
124/// @tparam TIntegral The integral type to operate on.
125/// @return The requested mask.
126template<ShiftOpRHS TWidth, typename TIntegral>
127requires ( std::is_integral<TIntegral>::value && TWidth >= bitsof(TIntegral) )
128constexpr TIntegral UpperMask() { return TIntegral(0); }
129
130
131/// Inline namespace function that returns a mask with bits set to \c 0 up to the given
132/// binary digit, and bits above to \c 1.
133/// Parameter \p width <b>must not be greater or equal</b> to the width of the given
134/// \p TIntegral type.
135/// In debug compilations, an \ref alib_mod_assert "error is raised" in that case.
136///
137/// \see A fully templated version usable when the number of bits are known at compile time,
138/// is given with #UpperMask<ShiftOpRHS,typename>().
139///
140/// @tparam TIntegral The integral type to operate on.
141/// @param width The number of lower bits to clear in the mask returned.
142/// @return The requested mask.
143template<typename TIntegral>
144requires std::integral<TIntegral>
145constexpr TIntegral UpperMask( ShiftOpRHS width )
146{
147 ALIB_ASSERT_ERROR( width < bitsof(TIntegral), "ALIB/BITS",
148 "Requested mask width wider than integral: {} >= {}", width, bitsof(TIntegral) )
149 using TUnsigned= typename std::make_unsigned<TIntegral>::type;
150 return TIntegral( (TUnsigned(~TUnsigned(0)) << width) );
151}
152
153
154/// Inline namespace function that keeps the given number of lower bits and masks the higher ones
155/// out of the given integral value.
156/// If parameter \p TWidth is greater or equal to the width of the given \p TIntegral type, then
157/// all bits are returned.
158///
159/// \see While this is the fully templated version and hence explicitly constexpression for the
160/// reader of a code, with
161/// #alib::lang::LowerBits<TIntegral>(lang::ShiftOpRHS,TIntegral), a version is given.
162///
163/// @param value The value to mask.
164/// @tparam TWidth The number of lower bits to keep.
165/// @tparam TIntegral The integral type to operate on (deduced by the compiler).
166/// @return The given value with the upper remaining bits cleared.
167template<ShiftOpRHS TWidth, typename TIntegral>
168requires std::integral<TIntegral>
169constexpr TIntegral LowerBits( TIntegral value )
170{
171 if constexpr ( TWidth >= bitsof(TIntegral) )
172 return value;
173 return value & LowerMask<TWidth,TIntegral>( );
174}
175
176/// Inline namespace function that keeps the given number of lower bits and masks the higher ones
177/// out of the given integral value.
178/// Parameter \p width <b>must not be greater or equal</b> to the width of the given
179/// \p TIntegral type. In debug compilations, an \ref alib_mod_assert "error is raised".
180///
181/// \see A fully templated version usable when the number of bits are known at compile time,
182/// is given with #LowerBits<ShiftOpRHS,TIntegral>().
183///
184/// @param width The number of lower bits to keep.
185/// @param value The value to mask.
186/// @tparam TIntegral The integral type to operate on (deduced by the compiler).
187/// @return The given value with the upper remaining bits cleared.
188template<typename TIntegral>
189requires std::integral<TIntegral>
190constexpr TIntegral LowerBits( ShiftOpRHS width, TIntegral value )
191{ return value & LowerMask<TIntegral>( width ); }
192
193/// Returns logarithm base 2 for the size in bits of the template given integral type.<p>
194/// Precisely, this function returns:
195/// - 3 for 8-bit types,
196/// - 4 for 16-bit types,
197/// - 5 for 32-bit types,
198/// - 6 for 64-bit types, and
199/// - 7 for 128-bit types.
200/// @tparam TIntegral The integral type to count bits in.
201/// @return The number of bits needed to count the bits of type \p TIntegral.
202template<typename TIntegral>
203requires std::integral<TIntegral>
204constexpr int
206{
207 static_assert(bitsof(TIntegral) <= 128, "Integrals larger than 128 are not supported.");
208 if constexpr (bitsof(TIntegral) == 32) return 5;
209 if constexpr (bitsof(TIntegral) == 64) return 7;
210 if constexpr (bitsof(TIntegral) == 8) return 3;
211 if constexpr (bitsof(TIntegral) == 16) return 4;
212 return 8;
213}
214
215/// Returns the number of bits set in an integral value.
216/// Internally, this method uses C++20 library function <c>std::popcount</c>.
217/// @tparam TIntegral The integral type to operate on.
218/// @param value The value to test.
219/// @return The number of bits set in a value.
220template<typename TIntegral>
221requires std::integral<TIntegral>
222constexpr int BitCount( TIntegral value )
223{ return std::popcount( static_cast<typename std::make_unsigned<TIntegral>::type>( value ) ); }
224
225/// Returns the number of the leading 0-bits in an integral type.
226/// Internally, this method uses C++20 library function <c>std::countl_zero</c>.
227///
228/// \attention
229/// This function must not be called with a \p value of <c>0</c>!
230/// In debug-compilations, this method \ref alib_mod_assert "raises an ALib error" in this case,
231/// while in release-compilations, the result is <em>'undefined'</em>.
232/// With function \ref MSB0, an alternative is given which returns \c 0 if the input is \c 0.
233///
234/// @tparam TIntegral The integral type to operate on.
235/// @param value The value to test. Must not be \c 0.
236/// @return The highest bit set in \p value.
237template<typename TIntegral>
238requires std::integral<TIntegral>
239constexpr int CLZ( TIntegral value )
240{
241 #if ALIB_DEBUG && !ALIB_DEBUG_ASSERTION_PRINTABLES
242 ALIB_ASSERT_ERROR( value != 0, "ALIB/BITS",
243 "Illegal value 0 passed to MSB(). Use MSB0() if 0 values need to be handled." )
244 #endif
245 return std::countl_zero( static_cast<typename std::make_unsigned<TIntegral>::type>( value ) );
246}
247
248
249/// Variant of \ref CLZ which tests the given parameter \p value on \c 0 and returns
250/// <c>sizeof(TIntegral) * 8</c> in this case.
251/// Otherwise, returns the result of \ref CLZ.
252///
253/// @tparam TIntegral The integral type to operate on.
254/// @param value The value to test. May be \c 0, which results to the number of bits in
255/// \p TIntegral.
256/// @return The number of leading zero-bits in \p value.
257template<typename TIntegral>
258requires std::integral<TIntegral>
259constexpr int CLZ0( TIntegral value)
260{
261 if( value == 0 )
262 return bitsof(TIntegral);
263 return CLZ(value);
264}
265
266/// Returns the number of the trailing 0-bits in an integral type.
267/// Internally, this method uses C++20 library function <c>std::countr_zero</c>.
268///
269/// \attention
270/// This function must not be called with a \p value of <c>0</c>!
271/// In debug-compilations, this method \ref alib_mod_assert "raises an ALib error" in this case,
272/// while in release-compilations, the result is <em>'undefined'</em>.
273/// With function \ref CTZ0, an alternative is given which returns \c 0 if the input is \c 0.
274///
275/// @tparam TIntegral The integral type to operate on.
276/// @param value The value to test. Must not be \c 0.
277/// @return The lowest bit set in \p value.
278template<typename TIntegral>
279requires std::integral<TIntegral>
280constexpr int CTZ( TIntegral value )
281{
282 ALIB_ASSERT_ERROR( value != 0, "ALIB/BITS",
283 "Illegal value 0 passed to MSB(). Use MSB0() if 0 values need to be handled." )
284 return std::countr_zero( static_cast<typename std::make_unsigned<TIntegral>::type>( value ) );
285}
286
287/// Variant of \ref CTZ which tests given parameter \p value on \c 0 and returns
288/// <c>sizeof(TIntegral) * 8</c> in this case.
289/// Otherwise, returns the result of \ref CLZ.
290///
291/// @tparam TIntegral The integral type to operate on.
292/// @param value The value to test. May be \c 0, which results to the number of bits in
293/// \p TIntegral.
294/// @return The number of trailing zero-bits in \p value. In case the given value is \c 0,
295/// <c>sizeof(Tintegral) * 8</c> is returned.
296template<typename TIntegral>
297requires std::integral<TIntegral>
298constexpr int CTZ0( TIntegral value )
299{
300 if( value == 0 )
301 return bitsof(TIntegral);
302 return CTZ(value);
303}
304
305/// Returns the number of the most significant bit in an integral type.
306/// Internally, this method uses \alib{lang;CLZ} and returns
307///
308/// int(sizeof(TIntegral)) * 8 - CLZ(value)
309///
310/// \attention
311/// This function must not be called with a \p value of <c>0</c>!
312/// In debug-compilations, this method \ref alib_mod_assert "raises an ALib error" in this case,
313/// while in release-compilations, the result is <em>'undefined'</em>.
314/// With function \ref MSB0, an alternative is given which returns \c 0 if the input is \c 0.
315///
316/// \note A corresponding function "LSB", to receive the least significant bit is not given.
317/// Instead, use <c>CTZ() + 1</c>.
318///
319/// @tparam TIntegral The integral type to operate on.
320/// @param value The value to test. Must not be \c 0.
321/// @return The highest bit set in \p value. The numbering starts with \c 1 and ends with
322/// <c>sizeof(Tintegral) * 8</c>.
323template<typename TIntegral>
324requires std::integral<TIntegral>
325constexpr int MSB( TIntegral value)
326{
327 #if ALIB_DEBUG && !ALIB_DEBUG_ASSERTION_PRINTABLES
328 ALIB_ASSERT_ERROR( value != 0, "ALIB/BITS",
329 "Illegal value 0 passed to MSB(). Use MSB0() if 0 values need to be handled." )
330 #endif
331 return bitsof(TIntegral) - CLZ(value);
332}
333
334/// Variant of \ref MSB which tests given parameter \p value on \c 0 and returns \c 0 in this
335/// case. Otherwise, returns the result of \ref MSB.
336///
337/// @tparam TIntegral The integral type to operate on.
338/// @param value The value to test. May be \c 0, which results to \c 0.
339/// @return The highest bit set in \p value. The numbering starts with \c 1 and ends with
340/// <c>sizeof(Tintegral)* 8</c>. If \p{value} is \c 0, hence no bit is set,
341/// \c 0 is returned.
342template<typename TIntegral>
343requires std::integral<TIntegral>
344constexpr int MSB0( TIntegral value)
345{
346 if( value == 0 )
347 return 0;
348 return MSB(value);
349}
350#include "ALib.Lang.CIMethods.H"
351}} // namespace [alib::lang]
352
353
354
#define bitsof(type)
Definition alib.inl:1418
#define ALIB_WARNINGS_IGNORE_INTEGRAL_CONSTANT_OVERFLOW
Definition alib.inl:685
#define ALIB_WARNINGS_RESTORE
Definition alib.inl:705
#define ALIB_EXPORT
Definition alib.inl:488
#define ALIB_ASSERT_ERROR(cond, domain,...)
Definition alib.inl:1049
constexpr int Log2OfSize()
Definition bits.inl:205
constexpr int MSB(TIntegral value)
Definition bits.inl:325
constexpr int CTZ0(TIntegral value)
Definition bits.inl:298
constexpr int CLZ(TIntegral value)
Definition bits.inl:239
int ShiftOpRHS
Definition bits.inl:20
constexpr TIntegral LowerBits(TIntegral value)
Definition bits.inl:169
constexpr int bitsofval(const T &val)
Definition bits.inl:35
constexpr TIntegral UpperMask()
Definition bits.inl:111
constexpr int MSB0(TIntegral value)
Definition bits.inl:344
constexpr int CLZ0(TIntegral value)
Definition bits.inl:259
constexpr int CTZ(TIntegral value)
Definition bits.inl:280
constexpr TIntegral LowerMask()
Definition bits.inl:53
constexpr int BitCount(TIntegral value)
Definition bits.inl:222