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