[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<kEncoding, ...>()` and
`UpdateBitsIn<kEncoding, ...>()`.
This commit is contained in:
Abtin Keshavarzian
2026-08-24 14:58:06 -07:00
committed by GitHub
parent 3e54d9cf37
commit 551a776eb3
4 changed files with 40 additions and 80 deletions
+15 -58
View File
@@ -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 <typename UintType, UintType kMask, UintType kOffset = BitOffsetOfMask(kMask)>
UintType UpdateBitsLittleEndian(UintType aBits, UintType aValue)
template <Encoding kEncoding, typename UintType, UintType kMask, UintType kOffset = BitOffsetOfMask(kMask)>
UintType UpdateBitsIn(UintType aBits, UintType aValue)
{
static_assert(TypeTraits::IsUint<UintType>::kValue, "UintType must be an unsigned int (8, 16, 32, or 64 bit len)");
return LittleEndian::HostSwap<UintType>((LittleEndian::HostSwap<UintType>(aBits) & ~kMask) |
((aValue << kOffset) & kMask));
return HostSwap<kEncoding, UintType>(
UpdateBits<UintType, kMask, kOffset>(HostSwap<kEncoding, UintType>(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 <typename UintType, UintType kMask, UintType kOffset = BitOffsetOfMask(kMask)>
UintType UpdateBitsBigEndian(UintType aBits, UintType aValue)
{
static_assert(TypeTraits::IsUint<UintType>::kValue, "UintType must be an unsigned int (8, 16, 32, or 64 bit len)");
return BigEndian::HostSwap<UintType>((BigEndian::HostSwap<UintType>(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 <typename UintType, UintType kMask, UintType kOffset = BitOffsetOfMask(kMask)>
UintType ReadBitsLittleEndian(UintType aBits)
template <Encoding kEncoding, typename UintType, UintType kMask, UintType kOffset = BitOffsetOfMask(kMask)>
UintType ReadBitsIn(UintType aBits)
{
static_assert(TypeTraits::IsUint<UintType>::kValue, "UintType must be an unsigned int (8, 16, 32, or 64 bit len)");
return (LittleEndian::HostSwap<UintType>(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 <typename UintType, UintType kMask, UintType kOffset = BitOffsetOfMask(kMask)>
UintType ReadBitsBigEndian(UintType aBits)
{
static_assert(TypeTraits::IsUint<UintType>::kValue, "UintType must be an unsigned int (8, 16, 32, or 64 bit len)");
return (BigEndian::HostSwap<UintType>(aBits) & kMask) >> kOffset;
return ReadBits<UintType, kMask, kOffset>(HostSwap<kEncoding, UintType>(aBits));
}
} // namespace ot
+7 -4
View File
@@ -68,14 +68,17 @@ public:
*
* @returns the IE Element ID.
*/
uint8_t GetId(void) const { return static_cast<uint8_t>(ReadBitsLittleEndian<uint16_t, kIdMask>(mLenIdType)); }
uint8_t GetId(void) const { return static_cast<uint8_t>(ReadBitsIn<kLittleEndian, uint16_t, kIdMask>(mLenIdType)); }
/**
* Returns the IE content length.
*
* @returns the IE content length.
*/
uint8_t GetLength(void) const { return static_cast<uint8_t>(ReadBitsLittleEndian<uint16_t, kLenMask>(mLenIdType)); }
uint8_t GetLength(void) const
{
return static_cast<uint8_t>(ReadBitsIn<kLittleEndian, uint16_t, kLenMask>(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<uint16_t, kIdMask>(mLenIdType, aId); }
void SetLength(uint8_t aLength) { mLenIdType = UpdateBitsLittleEndian<uint16_t, kLenMask>(mLenIdType, aLength); }
void SetId(uint8_t aId) { mLenIdType = UpdateBitsIn<kLittleEndian, uint16_t, kIdMask>(mLenIdType, aId); }
void SetLength(uint8_t aLen) { mLenIdType = UpdateBitsIn<kLittleEndian, uint16_t, kLenMask>(mLenIdType, aLen); }
uint16_t mLenIdType;
} OT_TOOL_PACKED_END;
+4 -4
View File
@@ -833,7 +833,7 @@ public:
*
* @returns The Build value.
*/
uint16_t GetBuild(void) const { return ReadBitsBigEndian<uint16_t, kBuildMask>(mBuildRevision); }
uint16_t GetBuild(void) const { return ReadBitsIn<kBigEndian, uint16_t, kBuildMask>(mBuildRevision); }
/**
* Sets the Build value.
@@ -842,7 +842,7 @@ public:
*/
void SetBuild(uint16_t aBuild)
{
mBuildRevision = UpdateBitsBigEndian<uint16_t, kBuildMask>(mBuildRevision, aBuild);
mBuildRevision = UpdateBitsIn<kBigEndian, uint16_t, kBuildMask>(mBuildRevision, aBuild);
}
/**
@@ -852,7 +852,7 @@ public:
*/
uint8_t GetRevision(void) const
{
return static_cast<uint8_t>(ReadBitsBigEndian<uint16_t, kRevMask>(mBuildRevision));
return static_cast<uint8_t>(ReadBitsIn<kBigEndian, uint16_t, kRevMask>(mBuildRevision));
}
/**
@@ -862,7 +862,7 @@ public:
*/
void SetRevision(uint8_t aRevision)
{
mBuildRevision = UpdateBitsBigEndian<uint16_t, kRevMask>(mBuildRevision, static_cast<uint16_t>(aRevision));
mBuildRevision = UpdateBitsIn<kBigEndian, uint16_t, kRevMask>(mBuildRevision, aRevision);
}
/**
+14 -14
View File
@@ -142,7 +142,7 @@ public:
*/
uint8_t GetTrafficClass(void) const
{
return static_cast<uint8_t>(ReadBitsBigEndian<uint16_t, kTrafficClassMask>(mVerTcFlow.m16[0]));
return static_cast<uint8_t>(ReadBitsIn<kBigEndian, uint16_t, kTrafficClassMask>(mVerTcFlow.m16[0]));
}
/**
@@ -152,8 +152,7 @@ public:
*/
void SetTrafficClass(uint8_t aTc)
{
mVerTcFlow.m16[0] =
UpdateBitsBigEndian<uint16_t, kTrafficClassMask>(mVerTcFlow.m16[0], static_cast<uint16_t>(aTc));
mVerTcFlow.m16[0] = UpdateBitsIn<kBigEndian, uint16_t, kTrafficClassMask>(mVerTcFlow.m16[0], aTc);
}
/**
@@ -163,7 +162,7 @@ public:
*/
uint8_t GetDscp(void) const
{
return static_cast<uint8_t>(ReadBitsBigEndian<uint16_t, kDscpMask>(mVerTcFlow.m16[0]));
return static_cast<uint8_t>(ReadBitsIn<kBigEndian, uint16_t, kDscpMask>(mVerTcFlow.m16[0]));
}
/**
@@ -173,7 +172,7 @@ public:
*/
void SetDscp(uint8_t aDscp)
{
mVerTcFlow.m16[0] = UpdateBitsBigEndian<uint16_t, kDscpMask>(mVerTcFlow.m16[0], static_cast<uint16_t>(aDscp));
mVerTcFlow.m16[0] = UpdateBitsIn<kBigEndian, uint16_t, kDscpMask>(mVerTcFlow.m16[0], aDscp);
}
/**
@@ -195,14 +194,17 @@ public:
*
* @returns The Flow value.
*/
uint32_t GetFlow(void) const { return ReadBitsBigEndian<uint32_t, kFlowMask>(mVerTcFlow.m32); }
uint32_t GetFlow(void) const { return ReadBitsIn<kBigEndian, uint32_t, kFlowMask>(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<uint32_t, kFlowMask>(mVerTcFlow.m32, aFlow); }
void SetFlow(uint32_t aFlow)
{
mVerTcFlow.m32 = UpdateBitsIn<kBigEndian, uint32_t, kFlowMask>(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<uint16_t, kOffsetMask>(mOffsetMore); }
uint16_t GetOffset(void) const { return ReadBitsIn<kBigEndian, uint16_t, kOffsetMask>(mOffsetMore); }
/**
* Sets the Fragment Offset value.
@@ -680,9 +682,7 @@ public:
*/
void SetOffset(uint16_t aOffset)
{
uint16_t tmp = BigEndian::HostSwap16(mOffsetMore);
WriteBits<uint16_t, kOffsetMask>(tmp, aOffset);
mOffsetMore = BigEndian::HostSwap16(tmp);
mOffsetMore = UpdateBitsIn<kBigEndian, uint16_t, kOffsetMask>(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<kBigEndian, uint16_t, kMoreFlag>(mOffsetMore); }
/**
* Clears the M flag value.
*/
void ClearMoreFlag(void) { mOffsetMore = BigEndian::HostSwap16(BigEndian::HostSwap16(mOffsetMore) & ~kMoreFlag); }
void ClearMoreFlag(void) { mOffsetMore = UpdateBitsIn<kBigEndian, uint16_t, kMoreFlag>(mOffsetMore, 0); }
/**
* Sets the M flag value.
*/
void SetMoreFlag(void) { mOffsetMore = BigEndian::HostSwap16(BigEndian::HostSwap16(mOffsetMore) | kMoreFlag); }
void SetMoreFlag(void) { mOffsetMore = UpdateBitsIn<kBigEndian, uint16_t, kMoreFlag>(mOffsetMore, 1); }
/**
* Returns the frame identification.