3434#ifndef NUM_UTILS_HPP_
3535#define NUM_UTILS_HPP_
3636
37+ #include " common/encoding.hpp"
3738#include " common/numeric_limits.hpp"
3839#include " common/type_traits.hpp"
3940
@@ -241,7 +242,7 @@ inline unsigned long ToUlong(uint32_t aUint32) { return static_cast<unsigned lon
241242/* *
242243 * Counts the number of `1` bits in the binary representation of a given unsigned int bit-mask value.
243244 *
244- * @tparam UintType The unsigned int type (MUST be `uint8_t`, uint16_t`, uint32_t`, or `uint64_t`).
245+ * @tparam UintType The unsigned int type (MUST be `uint8_t`, ` uint16_t`, ` uint32_t`, or `uint64_t`).
245246 *
246247 * @param[in] aMask A bit mask.
247248 *
@@ -264,6 +265,259 @@ template <typename UintType> uint8_t CountBitsInMask(UintType aMask)
264265 return count;
265266}
266267
268+ /* *
269+ * Sets the specified bit of the given integer to 1.
270+ *
271+ * @tparam UintType The value type (MUST be `uint8_t`, `uint16_t`, `uint32_t`, or `uint64_t`).
272+ *
273+ * @param[in,out] aBits The integer to set the bit.
274+ * @param[in] aBitOffset The bit offset to set. The bit offset starts with zero corresponding to the
275+ * least-significant bit.
276+ */
277+ template <typename UintType> void SetBit (UintType &aBits, uint8_t aBitOffset)
278+ {
279+ static_assert (TypeTraits::IsSame<UintType, uint8_t >::kValue || TypeTraits::IsSame<UintType, uint16_t >::kValue ||
280+ TypeTraits::IsSame<UintType, uint32_t >::kValue || TypeTraits::IsSame<UintType, uint64_t >::kValue ,
281+ " UintType must be `uint8_t`, `uint16_t`, `uint32_t`, or `uint64_t`" );
282+
283+ aBits = aBits | (static_cast <UintType>(1 ) << aBitOffset);
284+ }
285+
286+ /* *
287+ * Clears the specified bit of the given integer.
288+ *
289+ * @tparam UintType The value type (MUST be `uint8_t`, `uint16_t`, `uint32_t`, or `uint64_t`).
290+ *
291+ * @param[in,out] aBits The integer to clear the bit.
292+ * @param[in] aBitOffset The bit offset to clear. The bit offset starts with zero corresponding to the
293+ * least-significant bit.
294+ */
295+ template <typename UintType> void ClearBit (UintType &aBits, uint8_t aBitOffset)
296+ {
297+ static_assert (TypeTraits::IsSame<UintType, uint8_t >::kValue || TypeTraits::IsSame<UintType, uint16_t >::kValue ||
298+ TypeTraits::IsSame<UintType, uint32_t >::kValue || TypeTraits::IsSame<UintType, uint64_t >::kValue ,
299+ " UintType must be `uint8_t`, `uint16_t`, `uint32_t`, or `uint64_t`" );
300+
301+ aBits = aBits & (~(static_cast <UintType>(1 ) << aBitOffset));
302+ }
303+
304+ /* *
305+ * Gets the value of the specified bit of the given integer.
306+ *
307+ * @tparam UintType The value type (MUST be `uint8_t`, `uint16_t`, `uint32_t`, or `uint64_t`).
308+ *
309+ * @param[in] aBits The integer to get the bit.
310+ * @param[in] aBitOffset The bit offset to get. The bit offset starts with zero corresponding to the
311+ * least-significant bit.
312+ *
313+ * @returns The value of the specified bit.
314+ */
315+ template <typename UintType> bool GetBit (UintType aBits, uint8_t aBitOffset)
316+ {
317+ static_assert (TypeTraits::IsSame<UintType, uint8_t >::kValue || TypeTraits::IsSame<UintType, uint16_t >::kValue ||
318+ TypeTraits::IsSame<UintType, uint32_t >::kValue || TypeTraits::IsSame<UintType, uint64_t >::kValue ,
319+ " UintType must be `uint8_t`, `uint16_t`, `uint32_t`, or `uint64_t`" );
320+
321+ return (aBits & (static_cast <UintType>(1 ) << aBitOffset)) != 0 ;
322+ }
323+
324+ /* *
325+ * Writes the specified bit of the given integer to the given value (0 or 1).
326+ *
327+ * @tparam UintType The value type (MUST be `uint8_t`, `uint16_t`, `uint32_t`, or `uint64_t`).
328+ *
329+ * @param[in,out] aBits The integer to write the bit.
330+ * @param[in] aBitOffset The bit offset to get. The bit offset starts with zero corresponding to the
331+ * least-significant bit.
332+ * @param[in] aValue The value to write.
333+ */
334+ template <typename UintType> void WriteBit (UintType &aBits, uint8_t aBitOffset, bool aValue)
335+ {
336+ static_assert (TypeTraits::IsSame<UintType, uint8_t >::kValue || TypeTraits::IsSame<UintType, uint16_t >::kValue ||
337+ TypeTraits::IsSame<UintType, uint32_t >::kValue || TypeTraits::IsSame<UintType, uint64_t >::kValue ,
338+ " UintType must be `uint8_t`, `uint16_t`, `uint32_t`, or `uint64_t`" );
339+
340+ if (aValue)
341+ {
342+ SetBit<UintType>(aBits, aBitOffset);
343+ }
344+ else
345+ {
346+ ClearBit<UintType>(aBits, aBitOffset);
347+ }
348+ }
349+
350+ /* *
351+ * Gets the offset of the lowest non-zero bit in the given mask.
352+ *
353+ * @tparam UintType The value type (MUST be `uint8_t`, `uint16_t`, `uint32_t`, or `uint64_t`).
354+ *
355+ * @param[in] aMask The mask (MUST not be 0) to calculate the offset of the lowest non-zero bit.
356+ *
357+ * @returns The offset of the lowest non-zero bit in the mask.
358+ */
359+ template <typename UintType> inline constexpr uint8_t BitOffsetOfMask (UintType aMask)
360+ {
361+ static_assert (TypeTraits::IsSame<UintType, uint8_t >::kValue || TypeTraits::IsSame<UintType, uint16_t >::kValue ||
362+ TypeTraits::IsSame<UintType, uint32_t >::kValue || TypeTraits::IsSame<UintType, uint64_t >::kValue ,
363+ " UintType must be `uint8_t`, `uint16_t`, `uint32_t`, or `uint64_t`" );
364+
365+ return (aMask & 0x1 ) ? 0 : (1 + BitOffsetOfMask<UintType>(aMask >> 1 ));
366+ }
367+
368+ /* *
369+ * Writes the specified bits of the given integer to the given value.
370+ *
371+ * @tparam UintType The value type (MUST be `uint8_t`, `uint16_t`, `uint32_t`, or `uint64_t`).
372+ * @tparam kMask The bit mask (MUST not be 0) to write. The @p kMask must be provided in a shifted form.
373+ * @tparam kOffset The bit offset to write. The default @p kOffset is computed from the given @p kMask.
374+ *
375+ * @param[in,out] aBits The integer to write the bits.
376+ * @param[in] aValue The value to write.
377+ */
378+ template <typename UintType, UintType kMask , UintType kOffset = BitOffsetOfMask(kMask )>
379+ void WriteBits (UintType &aBits, UintType aValue)
380+ {
381+ static_assert (TypeTraits::IsSame<UintType, uint8_t >::kValue || TypeTraits::IsSame<UintType, uint16_t >::kValue ||
382+ TypeTraits::IsSame<UintType, uint32_t >::kValue || TypeTraits::IsSame<UintType, uint64_t >::kValue ,
383+ " UintType must be `uint8_t`, `uint16_t`, `uint32_t`, or `uint64_t`" );
384+
385+ aBits = ((aBits & ~kMask ) | ((aValue << kOffset ) & kMask ));
386+ }
387+
388+ /* *
389+ * Writes the specified bits of the given integer to the given value and returns the updated integer.
390+ *
391+ * @tparam UintType The value type (MUST be `uint8_t`, `uint16_t`, `uint32_t`, or `uint64_t`).
392+ * @tparam kMask The bit mask (MUST not be 0) to write. The @p kMask must be provided in a shifted form.
393+ * @tparam kOffset The bit offset to write. The default @p kOffset is computed from the given @p kMask.
394+ *
395+ * @param[in] aBits The integer to write the bits.
396+ * @param[in] aValue The value to write.
397+ *
398+ * @returns The updated integer.
399+ */
400+ template <typename UintType, UintType kMask , UintType kOffset = BitOffsetOfMask(kMask )>
401+ UintType UpdateBits (UintType aBits, UintType aValue)
402+ {
403+ static_assert (TypeTraits::IsSame<UintType, uint8_t >::kValue || TypeTraits::IsSame<UintType, uint16_t >::kValue ||
404+ TypeTraits::IsSame<UintType, uint32_t >::kValue || TypeTraits::IsSame<UintType, uint64_t >::kValue ,
405+ " UintType must be `uint8_t`, `uint16_t`, `uint32_t`, or `uint64_t`" );
406+
407+ return ((aBits & ~kMask ) | ((aValue << kOffset ) & kMask ));
408+ }
409+
410+ /* *
411+ * Read the value of the specified bits of the given integer.
412+ *
413+ * @tparam UintType The value type (MUST be `uint8_t`, `uint16_t`, `uint32_t`, or `uint64_t`).
414+ * @tparam kMask The bit mask (MUST not be 0) to write. The @p kMask must be provided in a shifted form.
415+ * @tparam kOffset The bit offset to write. The default @p kOffset is computed from the given @p kMask.
416+ *
417+ * @param[in] aBits The integer to read the bits.
418+ *
419+ * @returns The value of the specified bits.
420+ */
421+ template <typename UintType, UintType kMask , UintType kOffset = BitOffsetOfMask(kMask )>
422+ UintType ReadBits (UintType aBits)
423+ {
424+ static_assert (TypeTraits::IsSame<UintType, uint8_t >::kValue || TypeTraits::IsSame<UintType, uint16_t >::kValue ||
425+ TypeTraits::IsSame<UintType, uint32_t >::kValue || TypeTraits::IsSame<UintType, uint64_t >::kValue ,
426+ " UintType must be `uint8_t`, `uint16_t`, `uint32_t`, or `uint64_t`" );
427+
428+ return (aBits & kMask ) >> kOffset ;
429+ }
430+
431+ /* *
432+ * Writes the specified bits of the given integer stored in little-endian format to the given value and returns the
433+ * updated integer stored in little-endian format.
434+ *
435+ * @tparam UintType The value type (MUST be `uint16_t`, `uint32_t`, or `uint64_t`).
436+ * @tparam kMask The bit mask (MUST not be 0) to write. The @p kMask must be provided in a shifted form.
437+ * @tparam kOffset The bit offset to write. The default @p kOffset is computed from the given @p kMask.
438+ *
439+ * @param[in] aBits The integer to write the bits.
440+ * @param[in] aValue The value to write.
441+ *
442+ * @returns The updated integer.
443+ */
444+ template <typename UintType, UintType kMask , UintType kOffset = BitOffsetOfMask(kMask )>
445+ UintType UpdateBitsLittleEndian (UintType aBits, UintType aValue)
446+ {
447+ static_assert (TypeTraits::IsSame<UintType, uint16_t >::kValue || TypeTraits::IsSame<UintType, uint32_t >::kValue ||
448+ TypeTraits::IsSame<UintType, uint64_t >::kValue ,
449+ " UintType must be `uint16_t`, `uint32_t`, or `uint64_t`" );
450+
451+ return LittleEndian::HostSwap<UintType>((LittleEndian::HostSwap<UintType>(aBits) & ~kMask ) |
452+ ((aValue << kOffset ) & kMask ));
453+ }
454+
455+ /* *
456+ * Writes the specified bits of the given integer stored in big-endian format to the given value and returns the updated
457+ * integer stored in big-endian format.
458+ *
459+ * @tparam UintType The value type (MUST be `uint16_t`, `uint32_t`, or `uint64_t`).
460+ * @tparam kMask The bit mask (MUST not be 0) to write. The @p kMask must be provided in a shifted form.
461+ * @tparam kOffset The bit offset to write. The default @p kOffset is computed from the given @p kMask.
462+ *
463+ * @param[in] aBits A pointer to the integer to write the bits.
464+ * @param[in] aValue The value to write.
465+ *
466+ * @returns The updated integer.
467+ */
468+ template <typename UintType, UintType kMask , UintType kOffset = BitOffsetOfMask(kMask )>
469+ UintType UpdateBitsBigEndian (UintType aBits, UintType aValue)
470+ {
471+ static_assert (TypeTraits::IsSame<UintType, uint16_t >::kValue || TypeTraits::IsSame<UintType, uint32_t >::kValue ||
472+ TypeTraits::IsSame<UintType, uint64_t >::kValue ,
473+ " UintType must be `uint16_t`, `uint32_t`, or `uint64_t`" );
474+
475+ return BigEndian::HostSwap<UintType>((BigEndian::HostSwap<UintType>(aBits) & ~kMask ) |
476+ ((aValue << kOffset ) & kMask ));
477+ }
478+
479+ /* *
480+ * Read the value of the specified bits of the given integer stored in little-endian format.
481+ *
482+ * @tparam UintType The value type (MUST be `uint16_t`, `uint32_t`, or `uint64_t`).
483+ * @tparam kMask The bit mask (MUST not be 0) to write. The @p kMask must be provided in a shifted form.
484+ * @tparam kOffset The bit offset to write. The default @p kOffset is computed from the given @p kMask.
485+ *
486+ * @param[in] aBits The integer stored in little-endian format to read the bits.
487+ *
488+ * @returns The value of the specified bits.
489+ */
490+ template <typename UintType, UintType kMask , UintType kOffset = BitOffsetOfMask(kMask )>
491+ UintType ReadBitsLittleEndian (UintType aBits)
492+ {
493+ static_assert (TypeTraits::IsSame<UintType, uint16_t >::kValue || TypeTraits::IsSame<UintType, uint32_t >::kValue ||
494+ TypeTraits::IsSame<UintType, uint64_t >::kValue ,
495+ " UintType must be `uint16_t`, `uint32_t`, or `uint64_t`" );
496+
497+ return (LittleEndian::HostSwap<UintType>(aBits) & kMask ) >> kOffset ;
498+ }
499+
500+ /* *
501+ * Read the value of the specified bits of the given integer stored in big-endian format.
502+ *
503+ * @tparam UintType The value type (MUST be `uint16_t`, `uint32_t`, or `uint64_t`).
504+ * @tparam kMask The bit mask (MUST not be 0) to write. The @p kMask must be provided in a shifted form.
505+ * @tparam kOffset The bit offset to write. The default @p kOffset is computed from the given @p kMask.
506+ *
507+ * @param[in] aBits The integer stored in big-endian format to read the bits.
508+ *
509+ * @returns The value of the specified bits.
510+ */
511+ template <typename UintType, UintType kMask , UintType kOffset = BitOffsetOfMask(kMask )>
512+ UintType ReadBitsBigEndian (UintType aBits)
513+ {
514+ static_assert (TypeTraits::IsSame<UintType, uint16_t >::kValue || TypeTraits::IsSame<UintType, uint32_t >::kValue ||
515+ TypeTraits::IsSame<UintType, uint64_t >::kValue ,
516+ " UintType must be `uint16_t`, `uint32_t`, or `uint64_t`" );
517+
518+ return (BigEndian::HostSwap<UintType>(aBits) & kMask ) >> kOffset ;
519+ }
520+
267521} // namespace ot
268522
269523#endif // NUM_UTILS_HPP_
0 commit comments