From 551a776eb3d60d8c228e514a36b5acd951109a1f Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Mon, 24 Aug 2026 14:58:06 -0700 Subject: [PATCH] [bit-utils] replace endian-specific bit helpers with template version (#13531) This commit replaces the separate endian-specific bit-manipulation helpers (`ReadBitsBigEndian`, `ReadBitsLittleEndian`, `UpdateBitsBigEndian`, and `UpdateBitsLittleEndian`) with generic template functions `ReadBitsIn()` and `UpdateBitsIn()`. --- src/core/common/bit_utils.hpp | 73 +++++++------------------------ src/core/mac/mac_header_ie.hpp | 11 +++-- src/core/meshcop/meshcop_tlvs.hpp | 8 ++-- src/core/net/ip6_headers.hpp | 28 ++++++------ 4 files changed, 40 insertions(+), 80 deletions(-) diff --git a/src/core/common/bit_utils.hpp b/src/core/common/bit_utils.hpp index c7323affc..eddc1c29e 100644 --- a/src/core/common/bit_utils.hpp +++ b/src/core/common/bit_utils.hpp @@ -259,85 +259,42 @@ UintType ReadBits(UintType aBits) } /** - * Writes a value to a specified bit-field within a little-endian integer and returns the modified integer in - * little-endian format. + * Writes a value to a specified bit-field within an integer encoded with a given byte ordering and returns the + * modified integer in the same encoding. * + * @tparam kEncoding The byte-order encoding (big-endian or little-endian). * @tparam UintType The value type (MUST be `uint8_t`, `uint16_t`, `uint32_t`, or `uint64_t`). * @tparam kMask The bitmask indicating the field to modify (must not be zero). The mask must be pre-shifted. * @tparam kOffset The bit offset of the field. If not provided, this is computed from @p kMask. * - * @param[in] aBits The original integer value in little-endian format. + * @param[in] aBits The original integer value in @p kEncoding format. * @param[in] aValue The value to write into the field (it should not be pre-shifted). * - * @returns The updated integer in little-endian format. + * @returns The updated integer in @p kEncoding format. */ -template -UintType UpdateBitsLittleEndian(UintType aBits, UintType aValue) +template +UintType UpdateBitsIn(UintType aBits, UintType aValue) { - static_assert(TypeTraits::IsUint::kValue, "UintType must be an unsigned int (8, 16, 32, or 64 bit len)"); - - return LittleEndian::HostSwap((LittleEndian::HostSwap(aBits) & ~kMask) | - ((aValue << kOffset) & kMask)); + return HostSwap( + UpdateBits(HostSwap(aBits), aValue)); } /** - * Writes a value to a specified bit-field within a big-endian integer and returns the modified integer in big-endian - * format. - * - * @tparam UintType The value type (MUST be `uint8_t`, `uint16_t`, `uint32_t`, or `uint64_t`). - * @tparam kMask The bitmask indicating the field to modify (must not be zero). The mask must be pre-shifted. - * @tparam kOffset The bit offset of the field. If not provided, this is computed from @p kMask. - * - * @param[in] aBits The original integer value in big-endian format. - * @param[in] aValue The value to write into the field (it should not be pre-shifted). - * - * @returns The updated integer in big-endian format. - */ -template -UintType UpdateBitsBigEndian(UintType aBits, UintType aValue) -{ - static_assert(TypeTraits::IsUint::kValue, "UintType must be an unsigned int (8, 16, 32, or 64 bit len)"); - - return BigEndian::HostSwap((BigEndian::HostSwap(aBits) & ~kMask) | - ((aValue << kOffset) & kMask)); -} - -/** - * Reads the value of a specified bit-field from a little-endian integer. + * Reads the value of a specified bit-field from an integer encoded with a given byte ordering. * + * @tparam kEncoding The byte-order encoding (big-endian or little-endian). * @tparam UintType The value type (MUST be `uint8_t`, `uint16_t`, `uint32_t`, or `uint64_t`). * @tparam kMask The bitmask indicating the field to read (must not be zero). The mask must be pre-shifted. * @tparam kOffset The bit offset of the field. If not provided, this is computed from @p kMask. * - * @param[in] aBits The integer value in little-endian format to read from. + * @param[in] aBits The integer value in @p kEncoding format to read from. * * @returns The value from the bit-field (shifted to start at bit 0). */ -template -UintType ReadBitsLittleEndian(UintType aBits) +template +UintType ReadBitsIn(UintType aBits) { - static_assert(TypeTraits::IsUint::kValue, "UintType must be an unsigned int (8, 16, 32, or 64 bit len)"); - - return (LittleEndian::HostSwap(aBits) & kMask) >> kOffset; -} - -/** - * Reads the value of a specified bit-field from a big-endian integer. - * - * @tparam UintType The value type (MUST be `uint8_t`, `uint16_t`, `uint32_t`, or `uint64_t`). - * @tparam kMask The bitmask indicating the field to read (must not be zero). The mask must be pre-shifted. - * @tparam kOffset The bit offset of the field. If not provided, this is computed from @p kMask. - * - * @param[in] aBits The integer value in big-endian format to read from. - * - * @returns The value from the bit-field (shifted to start at bit 0). - */ -template -UintType ReadBitsBigEndian(UintType aBits) -{ - static_assert(TypeTraits::IsUint::kValue, "UintType must be an unsigned int (8, 16, 32, or 64 bit len)"); - - return (BigEndian::HostSwap(aBits) & kMask) >> kOffset; + return ReadBits(HostSwap(aBits)); } } // namespace ot diff --git a/src/core/mac/mac_header_ie.hpp b/src/core/mac/mac_header_ie.hpp index 9da8b243f..550084cca 100644 --- a/src/core/mac/mac_header_ie.hpp +++ b/src/core/mac/mac_header_ie.hpp @@ -68,14 +68,17 @@ public: * * @returns the IE Element ID. */ - uint8_t GetId(void) const { return static_cast(ReadBitsLittleEndian(mLenIdType)); } + uint8_t GetId(void) const { return static_cast(ReadBitsIn(mLenIdType)); } /** * Returns the IE content length. * * @returns the IE content length. */ - uint8_t GetLength(void) const { return static_cast(ReadBitsLittleEndian(mLenIdType)); } + uint8_t GetLength(void) const + { + return static_cast(ReadBitsIn(mLenIdType)); + } /** * Returns the total size of the Header IE (descriptor header plus content length) in bytes. @@ -168,8 +171,8 @@ private: static constexpr uint16_t kLenMask = 0x007f << 0; static constexpr uint16_t kIdMask = 0x00ff << 7; - void SetId(uint8_t aId) { mLenIdType = UpdateBitsLittleEndian(mLenIdType, aId); } - void SetLength(uint8_t aLength) { mLenIdType = UpdateBitsLittleEndian(mLenIdType, aLength); } + void SetId(uint8_t aId) { mLenIdType = UpdateBitsIn(mLenIdType, aId); } + void SetLength(uint8_t aLen) { mLenIdType = UpdateBitsIn(mLenIdType, aLen); } uint16_t mLenIdType; } OT_TOOL_PACKED_END; diff --git a/src/core/meshcop/meshcop_tlvs.hpp b/src/core/meshcop/meshcop_tlvs.hpp index 7fea36bab..cebe8775e 100644 --- a/src/core/meshcop/meshcop_tlvs.hpp +++ b/src/core/meshcop/meshcop_tlvs.hpp @@ -833,7 +833,7 @@ public: * * @returns The Build value. */ - uint16_t GetBuild(void) const { return ReadBitsBigEndian(mBuildRevision); } + uint16_t GetBuild(void) const { return ReadBitsIn(mBuildRevision); } /** * Sets the Build value. @@ -842,7 +842,7 @@ public: */ void SetBuild(uint16_t aBuild) { - mBuildRevision = UpdateBitsBigEndian(mBuildRevision, aBuild); + mBuildRevision = UpdateBitsIn(mBuildRevision, aBuild); } /** @@ -852,7 +852,7 @@ public: */ uint8_t GetRevision(void) const { - return static_cast(ReadBitsBigEndian(mBuildRevision)); + return static_cast(ReadBitsIn(mBuildRevision)); } /** @@ -862,7 +862,7 @@ public: */ void SetRevision(uint8_t aRevision) { - mBuildRevision = UpdateBitsBigEndian(mBuildRevision, static_cast(aRevision)); + mBuildRevision = UpdateBitsIn(mBuildRevision, aRevision); } /** diff --git a/src/core/net/ip6_headers.hpp b/src/core/net/ip6_headers.hpp index 946ad5ec7..2d44d1081 100644 --- a/src/core/net/ip6_headers.hpp +++ b/src/core/net/ip6_headers.hpp @@ -142,7 +142,7 @@ public: */ uint8_t GetTrafficClass(void) const { - return static_cast(ReadBitsBigEndian(mVerTcFlow.m16[0])); + return static_cast(ReadBitsIn(mVerTcFlow.m16[0])); } /** @@ -152,8 +152,7 @@ public: */ void SetTrafficClass(uint8_t aTc) { - mVerTcFlow.m16[0] = - UpdateBitsBigEndian(mVerTcFlow.m16[0], static_cast(aTc)); + mVerTcFlow.m16[0] = UpdateBitsIn(mVerTcFlow.m16[0], aTc); } /** @@ -163,7 +162,7 @@ public: */ uint8_t GetDscp(void) const { - return static_cast(ReadBitsBigEndian(mVerTcFlow.m16[0])); + return static_cast(ReadBitsIn(mVerTcFlow.m16[0])); } /** @@ -173,7 +172,7 @@ public: */ void SetDscp(uint8_t aDscp) { - mVerTcFlow.m16[0] = UpdateBitsBigEndian(mVerTcFlow.m16[0], static_cast(aDscp)); + mVerTcFlow.m16[0] = UpdateBitsIn(mVerTcFlow.m16[0], aDscp); } /** @@ -195,14 +194,17 @@ public: * * @returns The Flow value. */ - uint32_t GetFlow(void) const { return ReadBitsBigEndian(mVerTcFlow.m32); } + uint32_t GetFlow(void) const { return ReadBitsIn(mVerTcFlow.m32); } /** * Sets the 20-bit Flow field in IPv6 header. * * @param[in] aFlow The Flow value. */ - void SetFlow(uint32_t aFlow) { mVerTcFlow.m32 = UpdateBitsBigEndian(mVerTcFlow.m32, aFlow); } + void SetFlow(uint32_t aFlow) + { + mVerTcFlow.m32 = UpdateBitsIn(mVerTcFlow.m32, aFlow); + } /** * Returns the IPv6 Payload Length value. @@ -671,7 +673,7 @@ public: * * @returns The Fragment Offset value. */ - uint16_t GetOffset(void) const { return ReadBitsBigEndian(mOffsetMore); } + uint16_t GetOffset(void) const { return ReadBitsIn(mOffsetMore); } /** * Sets the Fragment Offset value. @@ -680,9 +682,7 @@ public: */ void SetOffset(uint16_t aOffset) { - uint16_t tmp = BigEndian::HostSwap16(mOffsetMore); - WriteBits(tmp, aOffset); - mOffsetMore = BigEndian::HostSwap16(tmp); + mOffsetMore = UpdateBitsIn(mOffsetMore, aOffset); } /** @@ -690,17 +690,17 @@ public: * * @returns The M flag value. */ - bool IsMoreFlagSet(void) const { return BigEndian::HostSwap16(mOffsetMore) & kMoreFlag; } + bool IsMoreFlagSet(void) const { return ReadBitsIn(mOffsetMore); } /** * Clears the M flag value. */ - void ClearMoreFlag(void) { mOffsetMore = BigEndian::HostSwap16(BigEndian::HostSwap16(mOffsetMore) & ~kMoreFlag); } + void ClearMoreFlag(void) { mOffsetMore = UpdateBitsIn(mOffsetMore, 0); } /** * Sets the M flag value. */ - void SetMoreFlag(void) { mOffsetMore = BigEndian::HostSwap16(BigEndian::HostSwap16(mOffsetMore) | kMoreFlag); } + void SetMoreFlag(void) { mOffsetMore = UpdateBitsIn(mOffsetMore, 1); } /** * Returns the frame identification.