mirror of
https://github.com/espressif/openthread.git
synced 2026-09-07 01:30:11 +00:00
[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:
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user