mirror of
https://github.com/espressif/openthread.git
synced 2026-07-30 15:47:46 +00:00
[bit-utils] add CountMatchingBits utility function (#11893)
This change introduces a new utility function `CountMatchingBits()` to calculate the number of matching leading bits between two byte arrays. This new fn replaces the now-removed `Ip6::Prefix::MatchLength()`. The previous implementation was specific to the `Ip6::Prefix` class. The new generic function is placed in `common/bit_utils` and is used to update `Ip6::Prefix`, `Ip6::Address`, `Ip4::Cidr`, and `PrefixTlv`. A new unit test `test_bit_utils` is added with comprehensive tests for the new function. The existing tests for `CountBitsInMask` are also moved into this new test file.
This commit is contained in:
@@ -394,6 +394,7 @@ openthread_core_files = [
|
||||
"common/binary_search.cpp",
|
||||
"common/binary_search.hpp",
|
||||
"common/bit_set.hpp",
|
||||
"common/bit_utils.cpp",
|
||||
"common/bit_utils.hpp",
|
||||
"common/callback.hpp",
|
||||
"common/clearable.hpp",
|
||||
|
||||
@@ -103,6 +103,7 @@ set(COMMON_SOURCES
|
||||
coap/coap_secure.cpp
|
||||
common/appender.cpp
|
||||
common/binary_search.cpp
|
||||
common/bit_utils.cpp
|
||||
common/crc.cpp
|
||||
common/data.cpp
|
||||
common/error.cpp
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright (c) 2025, The OpenThread Authors.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the copyright holder nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* This file includes implementation of bit manipulation utility functions.
|
||||
*/
|
||||
|
||||
#include "bit_utils.hpp"
|
||||
|
||||
#include "common/code_utils.hpp"
|
||||
#include "common/num_utils.hpp"
|
||||
|
||||
namespace ot {
|
||||
|
||||
uint16_t CountMatchingBits(const uint8_t *aFirst, const uint8_t *aSecond, uint16_t aMaxBitLength)
|
||||
{
|
||||
uint16_t remainingLen = aMaxBitLength;
|
||||
uint16_t matchedLen = 0;
|
||||
uint8_t diffMask = 0;
|
||||
|
||||
while (remainingLen > 0)
|
||||
{
|
||||
uint16_t len = Min<uint16_t>(remainingLen, kBitsPerByte);
|
||||
|
||||
diffMask = (aFirst[0] ^ aSecond[0]);
|
||||
|
||||
if (diffMask != 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
matchedLen += len;
|
||||
remainingLen -= len;
|
||||
aFirst++;
|
||||
aSecond++;
|
||||
}
|
||||
|
||||
VerifyOrExit(diffMask != 0);
|
||||
|
||||
while (remainingLen > 0)
|
||||
{
|
||||
if ((diffMask & 0x80) != 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
diffMask <<= 1;
|
||||
matchedLen++;
|
||||
remainingLen--;
|
||||
}
|
||||
|
||||
exit:
|
||||
return matchedLen;
|
||||
}
|
||||
|
||||
} // namespace ot
|
||||
@@ -84,6 +84,24 @@ template <typename UintType> uint8_t CountBitsInMask(UintType aMask)
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Counts the number of consecutive matching bits between two byte arrays.
|
||||
*
|
||||
* This function compares two byte arrays bit-by-bit, starting from the most significant bit (MSB) of the first byte
|
||||
* in each array. The comparison proceeds until a mismatch is found or until a maximum of @p aMaxBitLength bits have
|
||||
* been successfully compared.
|
||||
*
|
||||
* It is the caller's responsibility to ensure that both @p aFirst and @p aSecond point to buffers large enough to
|
||||
* contain at least @p aMaxBitLength bits.
|
||||
*
|
||||
* @param[in] aFirst A pointer to the first byte array to compare.
|
||||
* @param[in] aSecond A pointer to the second byte array to compare.
|
||||
* @param[in] aMaxBitLength The maximum number of bits to compare from the start of the arrays.
|
||||
*
|
||||
* @return The number of consecutive matching bits.
|
||||
*/
|
||||
uint16_t CountMatchingBits(const uint8_t *aFirst, const uint8_t *aSecond, uint16_t aMaxBitLength);
|
||||
|
||||
/**
|
||||
* Sets the specified bit in a given integer to 1.
|
||||
*
|
||||
|
||||
@@ -191,8 +191,7 @@ Cidr::InfoString Cidr::ToString(void) const
|
||||
|
||||
bool Cidr::operator==(const Cidr &aOther) const
|
||||
{
|
||||
return (mLength == aOther.mLength) &&
|
||||
(Ip6::Prefix::MatchLength(GetBytes(), aOther.GetBytes(), Ip4::Address::kSize) >= mLength);
|
||||
return (mLength == aOther.mLength) && (CountMatchingBits(GetBytes(), aOther.GetBytes(), mLength) >= mLength);
|
||||
}
|
||||
|
||||
void Cidr::Set(const uint8_t *aAddress, uint8_t aLength)
|
||||
|
||||
@@ -69,19 +69,19 @@ bool Prefix::IsUniqueLocal(void) const { return (mLength >= 7) && ((mPrefix.mFie
|
||||
|
||||
bool Prefix::IsEqual(const uint8_t *aPrefixBytes, uint8_t aPrefixLength) const
|
||||
{
|
||||
return (mLength == aPrefixLength) && (MatchLength(GetBytes(), aPrefixBytes, GetBytesSize()) >= mLength);
|
||||
return (mLength == aPrefixLength) && (CountMatchingBits(GetBytes(), aPrefixBytes, mLength) >= mLength);
|
||||
}
|
||||
|
||||
bool Prefix::ContainsPrefix(const Prefix &aSubPrefix) const
|
||||
{
|
||||
return (mLength >= aSubPrefix.mLength) &&
|
||||
(MatchLength(GetBytes(), aSubPrefix.GetBytes(), aSubPrefix.GetBytesSize()) >= aSubPrefix.GetLength());
|
||||
(CountMatchingBits(GetBytes(), aSubPrefix.GetBytes(), aSubPrefix.GetLength()) >= aSubPrefix.GetLength());
|
||||
}
|
||||
|
||||
bool Prefix::ContainsPrefix(const NetworkPrefix &aSubPrefix) const
|
||||
{
|
||||
return (mLength >= NetworkPrefix::kLength) &&
|
||||
(MatchLength(GetBytes(), aSubPrefix.m8, NetworkPrefix::kSize) >= NetworkPrefix::kLength);
|
||||
(CountMatchingBits(GetBytes(), aSubPrefix.m8, NetworkPrefix::kLength) >= NetworkPrefix::kLength);
|
||||
}
|
||||
|
||||
void Prefix::Tidy(void)
|
||||
@@ -102,17 +102,18 @@ void Prefix::Tidy(void)
|
||||
|
||||
bool Prefix::operator==(const Prefix &aOther) const
|
||||
{
|
||||
return (mLength == aOther.mLength) && (MatchLength(GetBytes(), aOther.GetBytes(), GetBytesSize()) >= GetLength());
|
||||
return (mLength == aOther.mLength) &&
|
||||
(CountMatchingBits(GetBytes(), aOther.GetBytes(), GetLength()) >= GetLength());
|
||||
}
|
||||
|
||||
bool Prefix::operator<(const Prefix &aOther) const
|
||||
{
|
||||
bool isSmaller;
|
||||
uint8_t minLength;
|
||||
uint8_t matchedLength;
|
||||
bool isSmaller;
|
||||
uint8_t minLength;
|
||||
uint16_t matchedLength;
|
||||
|
||||
minLength = Min(GetLength(), aOther.GetLength());
|
||||
matchedLength = MatchLength(GetBytes(), aOther.GetBytes(), SizeForLength(minLength));
|
||||
matchedLength = CountMatchingBits(GetBytes(), aOther.GetBytes(), minLength);
|
||||
|
||||
if (matchedLength >= minLength)
|
||||
{
|
||||
@@ -126,35 +127,6 @@ exit:
|
||||
return isSmaller;
|
||||
}
|
||||
|
||||
uint8_t Prefix::MatchLength(const uint8_t *aPrefixA, const uint8_t *aPrefixB, uint8_t aMaxSize)
|
||||
{
|
||||
uint8_t matchedLength = 0;
|
||||
|
||||
OT_ASSERT(aMaxSize <= Address::kSize);
|
||||
|
||||
for (uint8_t i = 0; i < aMaxSize; i++)
|
||||
{
|
||||
uint8_t diff = aPrefixA[i] ^ aPrefixB[i];
|
||||
|
||||
if (diff == 0)
|
||||
{
|
||||
matchedLength += kBitsPerByte;
|
||||
}
|
||||
else
|
||||
{
|
||||
while ((diff & 0x80) == 0)
|
||||
{
|
||||
matchedLength++;
|
||||
diff <<= 1;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return matchedLength;
|
||||
}
|
||||
|
||||
bool Prefix::IsValidNat64PrefixLength(uint8_t aLength)
|
||||
{
|
||||
return (aLength == 32) || (aLength == 40) || (aLength == 48) || (aLength == 56) || (aLength == 64) ||
|
||||
@@ -381,12 +353,12 @@ void Address::SetToIp4Mapped(const Ip4::Address &aIp4Address)
|
||||
|
||||
bool Address::MatchesPrefix(const Prefix &aPrefix) const
|
||||
{
|
||||
return Prefix::MatchLength(mFields.m8, aPrefix.GetBytes(), aPrefix.GetBytesSize()) >= aPrefix.GetLength();
|
||||
return CountMatchingBits(mFields.m8, aPrefix.GetBytes(), aPrefix.GetLength()) >= aPrefix.GetLength();
|
||||
}
|
||||
|
||||
bool Address::MatchesPrefix(const uint8_t *aPrefix, uint8_t aPrefixLength) const
|
||||
{
|
||||
return Prefix::MatchLength(mFields.m8, aPrefix, Prefix::SizeForLength(aPrefixLength)) >= aPrefixLength;
|
||||
return CountMatchingBits(mFields.m8, aPrefix, aPrefixLength) >= aPrefixLength;
|
||||
}
|
||||
|
||||
void Address::SetPrefix(const NetworkPrefix &aNetworkPrefix) { mFields.mComponents.mNetworkPrefix = aNetworkPrefix; }
|
||||
@@ -455,7 +427,7 @@ uint8_t Address::GetScope(void) const
|
||||
|
||||
uint8_t Address::PrefixMatch(const Address &aOther) const
|
||||
{
|
||||
return Prefix::MatchLength(mFields.m8, aOther.mFields.m8, sizeof(Address));
|
||||
return static_cast<uint8_t>(CountMatchingBits(mFields.m8, aOther.mFields.m8, BitSizeOf(Address)));
|
||||
}
|
||||
|
||||
bool Address::MatchesFilter(TypeFilter aFilter) const
|
||||
|
||||
@@ -258,17 +258,6 @@ public:
|
||||
*/
|
||||
static uint8_t SizeForLength(uint8_t aLength) { return BytesForBitSize(aLength); }
|
||||
|
||||
/**
|
||||
* Returns the number of IPv6 prefix bits that match.
|
||||
*
|
||||
* @param[in] aPrefixA A pointer to a byte array containing a first prefix.
|
||||
* @param[in] aPrefixB A pointer to a byte array containing a second prefix.
|
||||
* @param[in] aMaxSize Number of bytes of the two prefixes.
|
||||
*
|
||||
* @returns The number of prefix bits that match.
|
||||
*/
|
||||
static uint8_t MatchLength(const uint8_t *aPrefixA, const uint8_t *aPrefixB, uint8_t aMaxSize);
|
||||
|
||||
/**
|
||||
* Indicates whether or not a given prefix length is valid for use as a NAT64 prefix.
|
||||
*
|
||||
|
||||
@@ -680,8 +680,7 @@ public:
|
||||
bool IsEqual(const uint8_t *aPrefix, uint8_t aPrefixLength) const
|
||||
{
|
||||
return (aPrefixLength == mPrefixLength) &&
|
||||
(Ip6::Prefix::MatchLength(GetPrefix(), aPrefix, Ip6::Prefix::SizeForLength(aPrefixLength)) >=
|
||||
mPrefixLength);
|
||||
(CountMatchingBits(GetPrefix(), aPrefix, aPrefixLength) >= mPrefixLength);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -201,6 +201,7 @@ ot_unit_test(address_sanitizer)
|
||||
ot_unit_test(aes)
|
||||
ot_unit_test(array)
|
||||
ot_unit_test(binary_search)
|
||||
ot_unit_test(bit_utils)
|
||||
ot_unit_test(checksum)
|
||||
ot_unit_test(child)
|
||||
ot_unit_test(child_table)
|
||||
|
||||
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
* Copyright (c) 2025, The OpenThread Authors.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the copyright holder nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <openthread/config.h>
|
||||
|
||||
#include "test_platform.h"
|
||||
#include "test_util.hpp"
|
||||
|
||||
#include "common/bit_utils.hpp"
|
||||
|
||||
namespace ot {
|
||||
|
||||
void TestCountBitsInMask(void)
|
||||
{
|
||||
VerifyOrQuit(CountBitsInMask<uint8_t>(0) == 0);
|
||||
VerifyOrQuit(CountBitsInMask<uint8_t>(1) == 1);
|
||||
VerifyOrQuit(CountBitsInMask<uint8_t>(2) == 1);
|
||||
VerifyOrQuit(CountBitsInMask<uint8_t>(3) == 2);
|
||||
VerifyOrQuit(CountBitsInMask<uint8_t>(4) == 1);
|
||||
VerifyOrQuit(CountBitsInMask<uint8_t>(7) == 3);
|
||||
VerifyOrQuit(CountBitsInMask<uint8_t>(11) == 3);
|
||||
VerifyOrQuit(CountBitsInMask<uint8_t>(15) == 4);
|
||||
VerifyOrQuit(CountBitsInMask<uint8_t>(0x11) == 2);
|
||||
VerifyOrQuit(CountBitsInMask<uint8_t>(0xef) == 7);
|
||||
VerifyOrQuit(CountBitsInMask<uint8_t>(0xff) == 8);
|
||||
|
||||
VerifyOrQuit(CountBitsInMask<uint16_t>(0) == 0);
|
||||
VerifyOrQuit(CountBitsInMask<uint16_t>(0xff00) == 8);
|
||||
VerifyOrQuit(CountBitsInMask<uint16_t>(0xff) == 8);
|
||||
VerifyOrQuit(CountBitsInMask<uint16_t>(0xaa55) == 8);
|
||||
VerifyOrQuit(CountBitsInMask<uint16_t>(0xffff) == 16);
|
||||
|
||||
printf("TestCountBitsInMask() passed\n");
|
||||
}
|
||||
|
||||
void TestCountMatchingBitsAllCombinations(void)
|
||||
{
|
||||
// This test iterates through all possible byte combinations and
|
||||
// bit-lengths (0-8). It calculates the expected matched length
|
||||
// by exhaustively checking bits one-by-one and then verifies
|
||||
// that `CountMatchingBits()` returns the correct length.
|
||||
|
||||
uint8_t firstByte = 0;
|
||||
|
||||
do
|
||||
{
|
||||
uint8_t secondByte = 0;
|
||||
|
||||
do
|
||||
{
|
||||
for (uint8_t blen = 0; blen <= 8; blen++)
|
||||
{
|
||||
uint16_t matchedLen = 0;
|
||||
|
||||
for (uint8_t i = 0; i < blen; i++)
|
||||
{
|
||||
uint8_t bit = (0x80 >> i);
|
||||
|
||||
if ((firstByte & bit) != (secondByte & bit))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
matchedLen++;
|
||||
}
|
||||
|
||||
VerifyOrQuit(CountMatchingBits(&firstByte, &secondByte, blen) == matchedLen);
|
||||
}
|
||||
|
||||
secondByte++;
|
||||
} while (secondByte != 0);
|
||||
|
||||
firstByte++;
|
||||
|
||||
} while (firstByte != 0);
|
||||
|
||||
printf("TestCountMatchingBitsAllCombinations() passed\n");
|
||||
}
|
||||
|
||||
void TestCountMatchingBitsExamples(void)
|
||||
{
|
||||
struct TestCase
|
||||
{
|
||||
uint8_t mFirst[3];
|
||||
uint8_t mSecond[3];
|
||||
uint8_t mBitLength;
|
||||
uint8_t mExpectedMatchedLength;
|
||||
};
|
||||
|
||||
static const TestCase kTestCases[] = {
|
||||
{{0x00, 0x00, 0x00}, {0x00, 0x11, 0x22}, 0, 0}, {{0x6d, 0x13, 0xb0}, {0x6d, 0x13, 0xb0}, 20, 20},
|
||||
{{0x6d, 0x13, 0xb0}, {0x6d, 0x13, 0xbf}, 20, 20}, {{0x6d, 0x13, 0xb0}, {0x6d, 0x13, 0xa0}, 20, 19},
|
||||
{{0x6d, 0xa3, 0xb0}, {0x6d, 0xa3, 0xa0}, 20, 19}, {{0x77, 0xa3, 0x25}, {0x77, 0xa3, 0xa5}, 20, 16},
|
||||
{{0x77, 0xa3, 0x25}, {0x77, 0xa3, 0x65}, 20, 17}, {{0x77, 0xa3, 0x25}, {0x77, 0xa3, 0x05}, 20, 18},
|
||||
{{0x77, 0xa3, 0x25}, {0x77, 0xa3, 0x05}, 18, 18}, {{0x77, 0xa3, 0x25}, {0x77, 0xa3, 0x05}, 17, 17},
|
||||
};
|
||||
|
||||
for (const TestCase &testCase : kTestCases)
|
||||
{
|
||||
uint16_t matchedLen = CountMatchingBits(testCase.mFirst, testCase.mSecond, testCase.mBitLength);
|
||||
|
||||
VerifyOrQuit(matchedLen == testCase.mExpectedMatchedLength);
|
||||
}
|
||||
|
||||
printf("TestCountMatchingBitsExamples() passed\n");
|
||||
}
|
||||
|
||||
} // namespace ot
|
||||
|
||||
int main(void)
|
||||
{
|
||||
ot::TestCountBitsInMask();
|
||||
ot::TestCountMatchingBitsAllCombinations();
|
||||
ot::TestCountMatchingBitsExamples();
|
||||
|
||||
printf("All tests passed\n");
|
||||
return 0;
|
||||
}
|
||||
@@ -178,24 +178,6 @@ void TestNumUtils(void)
|
||||
VerifyOrQuit(DivideAndRoundUp<uint8_t>(10, 10) == 1);
|
||||
VerifyOrQuit(DivideAndRoundUp<uint8_t>(11, 10) == 2);
|
||||
|
||||
VerifyOrQuit(CountBitsInMask<uint8_t>(0) == 0);
|
||||
VerifyOrQuit(CountBitsInMask<uint8_t>(1) == 1);
|
||||
VerifyOrQuit(CountBitsInMask<uint8_t>(2) == 1);
|
||||
VerifyOrQuit(CountBitsInMask<uint8_t>(3) == 2);
|
||||
VerifyOrQuit(CountBitsInMask<uint8_t>(4) == 1);
|
||||
VerifyOrQuit(CountBitsInMask<uint8_t>(7) == 3);
|
||||
VerifyOrQuit(CountBitsInMask<uint8_t>(11) == 3);
|
||||
VerifyOrQuit(CountBitsInMask<uint8_t>(15) == 4);
|
||||
VerifyOrQuit(CountBitsInMask<uint8_t>(0x11) == 2);
|
||||
VerifyOrQuit(CountBitsInMask<uint8_t>(0xef) == 7);
|
||||
VerifyOrQuit(CountBitsInMask<uint8_t>(0xff) == 8);
|
||||
|
||||
VerifyOrQuit(CountBitsInMask<uint16_t>(0) == 0);
|
||||
VerifyOrQuit(CountBitsInMask<uint16_t>(0xff00) == 8);
|
||||
VerifyOrQuit(CountBitsInMask<uint16_t>(0xff) == 8);
|
||||
VerifyOrQuit(CountBitsInMask<uint16_t>(0xaa55) == 8);
|
||||
VerifyOrQuit(CountBitsInMask<uint16_t>(0xffff) == 16);
|
||||
|
||||
printf("TestNumUtils() passed\n");
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user