ALib C++ Framework
by
Library Version: 2511 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 #"mainpage_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 #"F;ALib.Lang.H".
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 #"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{ (void) val; return sizeof(T) * 8; }
37
38// Doxygen (V1.15) would create identical entries in its tag-file, so those are not reachable.
39// On the other hand, it complains if the methods are not doxed. So, we hide them from doxygen.
40#if DOXYGEN
41/// Inline namespace function that returns a mask with bits set to \c 1 up to the given
42/// binary digit, and bits above to \c 0.
43/// If the parameter \p{TWidth} is greater or equal to the width of the given \p{TIntegral} type, then
44/// all bits are set in the returned value.
45///
46/// \see While this is the fully templated version, with
47/// #"LowerMask(ShiftOpRHS);LowerMask<TIntegral>(ShiftOpRHS)", a run-time version is given.
48///
49/// @tparam TWidth The number of lower bits to set to \c 1.
50/// @tparam TIntegral The integral type to operate on.
51/// @return The requested mask.
52template<ShiftOpRHS TWidth, typename TIntegral>
53constexpr TIntegral LowerMask();
54#else
55template<ShiftOpRHS TWidth, typename TIntegral>
56requires ( std::is_integral<TIntegral>::value && TWidth < bitsof(TIntegral) )
57constexpr TIntegral LowerMask() {
59 using TUnsigned= typename std::make_unsigned<TIntegral>::type;
60 return TIntegral(~(TUnsigned(~TUnsigned(0)) << TWidth) );
62}
63
64template<ShiftOpRHS TWidth, typename TIntegral>
65requires ( std::is_integral<TIntegral>::value && TWidth >= bitsof(TIntegral) )
66constexpr TIntegral LowerMask() { return TIntegral(~TIntegral(0)); }
67
68#endif
69
70/// Inline namespace function that returns a mask with bits set to \c 1 up to the given
71/// binary digit, and bits above to \c 0.
72/// Parameter \p{width} <b>must not be greater or equal</b> to the width of the given
73/// \p{TIntegral} type.
74/// In debug-compilations, an #"alib_mod_assert;error is raised" in that case.
75///
76/// \see A fully templated version usable when the number of bits are known at compile time,
77/// is given with #".LowerMask()".
78///
79/// @tparam TIntegral The integral type to operate on.
80/// @param width The number of lower bits to set in the mask returned.
81/// @return The requested mask.
82template<typename TIntegral>
83requires std::integral<TIntegral>
84constexpr TIntegral LowerMask( ShiftOpRHS width ) {
85 ALIB_ASSERT_ERROR( width < bitsof(TIntegral), "LANG",
86 "Requested mask width wider than integral: {} >= {}", width, bitsof(TIntegral) )
87 using TUnsigned= typename std::make_unsigned<TIntegral>::type;
88 return TIntegral(~(TUnsigned(~TUnsigned(0)) << width ));
89}
90
91// Doxygen (V1.15) would create identical entries in its tag-file, so those are not reachable.
92// On the other hand, it complains if the methods are not doxed. So, we hide them from doxygen.
93#if DOXYGEN
94/// Inline namespace function that returns a mask with bits set to \c 0 up to the given
95/// binary digit, and bits above to \c 1.
96/// If the parameter \p{TWidth} is greater or equal to the width of the given \p{TIntegral} type, then
97/// all bits are set in the returned value.
98///
99/// \see While this is the fully templated version, with
100/// #"UpperMask(ShiftOpRHS);UpperMask<TIntegral>(ShiftOpRHS)", a run-time version is given.
101///
102/// @tparam TWidth The number of lower bits to clear to \c 1.
103/// @tparam TIntegral The integral type to operate on.
104/// @return The requested mask.
105template<ShiftOpRHS TWidth, typename TIntegral>
106requires ( std::is_integral<TIntegral>::value && TWidth < bitsof(TIntegral) )
107constexpr TIntegral UpperMask();
108#else
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
117template<ShiftOpRHS TWidth, typename TIntegral>
118requires ( std::is_integral<TIntegral>::value && TWidth >= bitsof(TIntegral) )
119constexpr TIntegral UpperMask() { return TIntegral(0); }
120#endif
121
122/// Inline namespace function that returns a mask with bits set to \c 0 up to the given
123/// binary digit, and bits above to \c 1.
124/// Parameter \p{width} <b>must not be greater or equal</b> to the width of the given
125/// \p{TIntegral} type.
126/// In debug compilations, an #"alib_mod_assert;error is raised" in that case.
127///
128/// \see A fully templated version usable when the number of bits are known at compile time,
129/// is given with #".UpperMask()"
130///
131/// @tparam TIntegral The integral type to operate on.
132/// @param width The number of lower bits to clear in the mask returned.
133/// @return The requested mask.
134template<typename TIntegral>
135requires std::integral<TIntegral>
136constexpr TIntegral UpperMask( ShiftOpRHS width ) {
137 ALIB_ASSERT_ERROR( width < bitsof(TIntegral), "LANG",
138 "Requested mask width wider than integral: {} >= {}", width, bitsof(TIntegral) )
139 using TUnsigned= typename std::make_unsigned<TIntegral>::type;
140 return TIntegral( (TUnsigned(~TUnsigned(0)) << width) );
141}
142
143/// Inline namespace function that keeps the given number of lower bits and masks the higher ones
144/// out of the given integral value.
145/// If given \p{TWidth} is greater or equal to the width of the given \p{TIntegral} type, then
146/// all bits are returned.
147///
148/// \see While this is the fully templated version and hence explicitly \c constexpr for the
149/// reader of a code, with
150/// #"LowerBits(ShiftOpRHS, TIntegral);LowerBits<TIntegral>(ShiftOpRHS, TIntegral)",
151/// a version is given.
152///
153/// @param value The value to mask.
154/// @tparam TWidth The number of lower bits to keep.
155/// @tparam TIntegral The integral type to operate on (deduced by the compiler).
156/// @return The given value with the upper remaining bits cleared.
157template<ShiftOpRHS TWidth, typename TIntegral>
158requires std::integral<TIntegral>
159constexpr TIntegral LowerBits( TIntegral value ) {
160 if constexpr ( TWidth >= bitsof(TIntegral) )
161 return value;
162 return value & LowerMask<TWidth,TIntegral>( );
163}
164
165/// Inline namespace function that keeps the given number of lower bits and masks the higher ones
166/// out of the given integral value.
167/// Parameter \p{width} <b>must not be greater or equal</b> to the width of the given
168/// \p{TIntegral} type. In debug compilations, an #"alib_mod_assert;error is raised".
169///
170/// \see A fully templated version, usable when the number of bits is known at compile time,
171/// is given with #"LowerBits(TIntegral)".
172///
173/// @param width The number of lower bits to keep.
174/// @param value The value to mask.
175/// @tparam TIntegral The integral type to operate on (deduced by the compiler).
176/// @return The given value with the upper remaining bits cleared.
177template<typename TIntegral>
178requires std::integral<TIntegral>
179constexpr TIntegral LowerBits( ShiftOpRHS width, TIntegral value )
180{ return value & LowerMask<TIntegral>( width ); }
181
182/// Returns logarithm base 2 for the size in bits of the template given integral type.<p>
183/// Precisely, this function returns:
184/// - 3 for 8-bit types,
185/// - 4 for 16-bit types,
186/// - 5 for 32-bit types,
187/// - 6 for 64-bit types, and
188/// - 7 for 128-bit types.
189/// @tparam TIntegral The integral type to count bits in.
190/// @return The number of bits needed to count the bits of type \p{TIntegral}.
191template<typename TIntegral>
192requires std::integral<TIntegral>
193constexpr int
195 static_assert(bitsof(TIntegral) <= 128, "Integrals larger than 128 are not supported.");
196 if constexpr (bitsof(TIntegral) == 32) return 5;
197 if constexpr (bitsof(TIntegral) == 64) return 7;
198 if constexpr (bitsof(TIntegral) == 8) return 3;
199 if constexpr (bitsof(TIntegral) == 16) return 4;
200 return 8;
201}
202
203/// Returns the number of bits set in an integral value.
204/// Internally, this method uses C++20 library function <c>std::popcount</c>.
205/// @tparam TIntegral The integral type to operate on.
206/// @param value The value to test.
207/// @return The number of bits set in a value.
208template<typename TIntegral>
209requires std::integral<TIntegral>
210constexpr int BitCount( TIntegral value )
211{ return std::popcount( static_cast<typename std::make_unsigned<TIntegral>::type>( value ) ); }
212
213/// Returns the number of the leading 0-bits in an integral type.
214/// Internally, this method uses C++20 library function <c>std::countl_zero</c>.
215///
216/// \attention
217/// This function must not be called with a \p{value} of <c>0</c>!
218/// In debug-compilations, this method #"alib_mod_assert;raises an ALib error" in this case,
219/// while in release-compilations, the result is <em>'undefined'</em>.
220/// With function #"MSB0", an alternative is given which returns \c 0 if the input is \c 0.
221///
222/// @tparam TIntegral The integral type to operate on.
223/// @param value The value to test. Must not be \c 0.
224/// @return The highest bit set in \p{value}.
225template<typename TIntegral>
226requires std::integral<TIntegral>
227constexpr int CLZ( TIntegral value ) {
228 #if ALIB_DEBUG && !ALIB_DEBUG_ASSERTION_PRINTABLES
229 ALIB_ASSERT_ERROR( value != 0, "LANG",
230 "Illegal value 0 passed to MSB(). Use MSB0() if 0 values need to be handled." )
231 #endif
232 return std::countl_zero( static_cast<typename std::make_unsigned<TIntegral>::type>( value ) );
233}
234
235
236/// Variant of #"CLZ" which tests the given parameter \p{value} on \c 0 and returns
237/// <c>sizeof(TIntegral) * 8</c> in this case.
238/// Otherwise, returns the result of #"CLZ".
239///
240/// @tparam TIntegral The integral type to operate on.
241/// @param value The value to test. May be \c 0, which results to the number of bits in
242/// \p{TIntegral}.
243/// @return The number of leading zero-bits in \p{value}.
244template<typename TIntegral>
245requires std::integral<TIntegral>
246constexpr int CLZ0( TIntegral value) {
247 if( value == 0 )
248 return bitsof(TIntegral);
249 return CLZ(value);
250}
251
252/// Returns the number of the trailing 0-bits in an integral type.
253/// Internally, this method uses C++20 library function <c>std::countr_zero</c>.
254///
255/// \attention
256/// This function must not be called with a \p{value} of <c>0</c>!
257/// In debug-compilations, this method #"alib_mod_assert;raises an ALib error" in this case,
258/// while in release-compilations, the result is <em>'undefined'</em>.
259/// With function #"CTZ0", an alternative is given which returns \c 0 if the input is \c 0.
260///
261/// @tparam TIntegral The integral type to operate on.
262/// @param value The value to test. Must not be \c 0.
263/// @return The lowest bit set in \p{value}.
264template<typename TIntegral>
265requires std::integral<TIntegral>
266constexpr int CTZ( TIntegral value ) {
267 ALIB_ASSERT_ERROR( value != 0, "LANG",
268 "Illegal value 0 passed to MSB(). Use MSB0() if 0 values need to be handled." )
269 return std::countr_zero( static_cast<typename std::make_unsigned<TIntegral>::type>( value ) );
270}
271
272/// Variant of #"CTZ" which tests given parameter \p{value} on \c 0 and returns
273/// <c>sizeof(TIntegral) * 8</c> in this case.
274/// Otherwise, returns the result of #"CLZ".
275///
276/// @tparam TIntegral The integral type to operate on.
277/// @param value The value to test. May be \c 0, which results to the number of bits in
278/// \p{TIntegral}.
279/// @return The number of trailing zero-bits in \p{value}. In case the given value is \c 0,
280/// <c>sizeof(Tintegral) * 8</c> is returned.
281template<typename TIntegral>
282requires std::integral<TIntegral>
283constexpr int CTZ0( TIntegral value ) {
284 if( value == 0 )
285 return bitsof(TIntegral);
286 return CTZ(value);
287}
288
289/// Returns the number of the most significant bit in an integral type.
290/// Internally, this method uses #"CLZ" and returns
291///
292/// int(sizeof(TIntegral)) * 8 - CLZ(value)
293///
294/// \attention
295/// This function must not be called with a \p{value} of <c>0</c>!
296/// In debug-compilations, this method #"alib_mod_assert;raises an ALib error" in this case,
297/// while in release-compilations, the result is <em>'undefined'</em>.
298/// With function #"MSB0", an alternative is given which returns \c 0 if the input is \c 0.
299///
300/// \note A corresponding function "LSB", to receive the least significant bit is not given.
301/// Instead, use <c>CTZ() + 1</c>.
302///
303/// @tparam TIntegral The integral type to operate on.
304/// @param value The value to test. Must not be \c 0.
305/// @return The highest bit set in \p{value}. The numbering starts with \c 1 and ends with
306/// <c>sizeof(Tintegral) * 8</c>.
307template<typename TIntegral>
308requires std::integral<TIntegral>
309constexpr int MSB( TIntegral value) {
310 #if ALIB_DEBUG && !ALIB_DEBUG_ASSERTION_PRINTABLES
311 ALIB_ASSERT_ERROR( value != 0, "LANG",
312 "Illegal value 0 passed to MSB(). Use MSB0() if 0 values need to be handled." )
313 #endif
314 return bitsof(TIntegral) - CLZ(value);
315}
316
317/// Variant of #"MSB" which tests given parameter \p{value} on \c 0 and returns \c 0 in this
318/// case. Otherwise, returns the result of #"MSB".
319///
320/// @tparam TIntegral The integral type to operate on.
321/// @param value The value to test. May be \c 0, which results to \c 0.
322/// @return The highest bit set in \p{value}. The numbering starts with \c 1 and ends with
323/// <c>sizeof(Tintegral)* 8</c>. If \p{value} is \c 0, hence no bit is set,
324/// \c 0 is returned.
325template<typename TIntegral>
326requires std::integral<TIntegral>
327constexpr int MSB0( TIntegral value) {
328 if( value == 0 )
329 return 0;
330 return MSB(value);
331}
332#include "ALib.Lang.CIMethods.H"
333}} // namespace [alib::lang]
#define ALIB_ALLOW_INTEGRAL_CONSTANT_OVERFLOW
Definition alib.inl:656
#define bitsof(type)
Definition alib.inl:1509
#define ALIB_POP_ALLOWANCE
Definition alib.inl:673
#define ALIB_EXPORT
Definition alib.inl:562
#define ALIB_ASSERT_ERROR(cond, domain,...)
Definition alib.inl:1144
constexpr TIntegral LowerMask()
int ShiftOpRHS
Definition bits.inl:20
constexpr int Log2OfSize()
Definition bits.inl:194
constexpr int BitCount(TIntegral value)
Definition bits.inl:210
constexpr int bitsofval(const T &val)
Definition bits.inl:35
constexpr int CLZ0(TIntegral value)
Definition bits.inl:246
constexpr int MSB0(TIntegral value)
Definition bits.inl:327
constexpr int CTZ(TIntegral value)
Definition bits.inl:266
constexpr int MSB(TIntegral value)
Definition bits.inl:309
constexpr int CTZ0(TIntegral value)
Definition bits.inl:283
constexpr int CLZ(TIntegral value)
Definition bits.inl:227
constexpr TIntegral LowerBits(TIntegral value)
Definition bits.inl:159
constexpr TIntegral UpperMask()