Commit 5fc9d571 authored by Lucian Grijincu's avatar Lucian Grijincu Committed by Facebook Github Bot 7

folly: ubsan: redo BitsTest (no macros) and fix DCHECK in test

Reviewed By: meyering

Differential Revision: D3283226

fbshipit-source-id: 7ae2ec7741ca53c494e8325e30f2995a241674c0
parent aabeca71
...@@ -193,8 +193,11 @@ struct Bits { ...@@ -193,8 +193,11 @@ struct Bits {
static constexpr UnderlyingType zero = UnderlyingType(0); static constexpr UnderlyingType zero = UnderlyingType(0);
static constexpr UnderlyingType one = UnderlyingType(1); static constexpr UnderlyingType one = UnderlyingType(1);
using UnsignedType = typename std::make_unsigned<UnderlyingType>::type;
static constexpr UnderlyingType ones(size_t count) { static constexpr UnderlyingType ones(size_t count) {
return count < bitsPerBlock ? (one << count) - 1 : ~zero; return (count < bitsPerBlock)
? static_cast<UnderlyingType>((UnsignedType{1} << count) - 1)
: ~zero;
} }
}; };
...@@ -224,7 +227,10 @@ inline void Bits<T, Traits>::set(T* p, size_t bitStart, size_t count, ...@@ -224,7 +227,10 @@ inline void Bits<T, Traits>::set(T* p, size_t bitStart, size_t count,
UnderlyingType value) { UnderlyingType value) {
DCHECK_LE(count, sizeof(UnderlyingType) * 8); DCHECK_LE(count, sizeof(UnderlyingType) * 8);
size_t cut = bitsPerBlock - count; size_t cut = bitsPerBlock - count;
DCHECK_EQ(value, value << cut >> cut); if (cut != 8 * sizeof(UnderlyingType)) {
using U = typename std::make_unsigned<UnderlyingType>::type;
DCHECK_EQ(value, UnderlyingType(U(value) << cut) >> cut);
}
size_t idx = blockIndex(bitStart); size_t idx = blockIndex(bitStart);
size_t offset = bitOffset(bitStart); size_t offset = bitOffset(bitStart);
if (std::is_signed<UnderlyingType>::value) { if (std::is_signed<UnderlyingType>::value) {
...@@ -266,6 +272,10 @@ inline bool Bits<T, Traits>::test(const T* p, size_t bit) { ...@@ -266,6 +272,10 @@ inline bool Bits<T, Traits>::test(const T* p, size_t bit) {
template <class T, class Traits> template <class T, class Traits>
inline auto Bits<T, Traits>::get(const T* p, size_t bitStart, size_t count) inline auto Bits<T, Traits>::get(const T* p, size_t bitStart, size_t count)
-> UnderlyingType { -> UnderlyingType {
if (count == 0) {
return UnderlyingType{};
}
DCHECK_LE(count, sizeof(UnderlyingType) * 8); DCHECK_LE(count, sizeof(UnderlyingType) * 8);
size_t idx = blockIndex(bitStart); size_t idx = blockIndex(bitStart);
size_t offset = bitOffset(bitStart); size_t offset = bitOffset(bitStart);
......
...@@ -250,34 +250,61 @@ T testValue(int bits) { ...@@ -250,34 +250,61 @@ T testValue(int bits) {
CHECK_LE(value, std::numeric_limits<T>::max()); CHECK_LE(value, std::numeric_limits<T>::max());
return static_cast<T>(value); return static_cast<T>(value);
} }
} // anonymous namespace
template <size_t N>
void accSize(size_t& w) {
for (size_t s = 0; s <= N; ++s) {
w += s;
}
}
template <size_t N, typename T, bool NEG, bool aligned>
void testSetLoop(size_t& w, size_t bufSize, uint8_t* buf) {
for (size_t s = 0; s <= N; ++s) {
CHECK_LE(s + w, 8 * bufSize) << s << ' ' << w << ' ' << bufSize;
testSet<aligned>(buf, w, s, testValue<T, NEG>(s));
EXPECT_EQ((testValue<T, NEG>(s)), (testGet<aligned, T>(buf, w, s))) << s;
w += s;
}
}
template <size_t N, typename T, bool NEG, bool aligned>
void testGetLoop(size_t& r, size_t bufSize, uint8_t* buf) {
for (size_t s = 0; s <= N; ++s) {
CHECK_LE(s + r, 8 * bufSize);
EXPECT_EQ((testValue<T, NEG>(s)), (testGet<aligned, T>(buf, r, s))) << s;
r += s;
}
} }
template <bool aligned> template <bool aligned>
void testConcatenation() { void testConcatenation() {
// concatenate fields of length 1, 2, 3, ... 64, all unsigned, storing 2/3s // concatenate fields of length 1, 2, 3, ... 64, all unsigned, storing 2/3s
// the maximum value in each. // the maximum value in each.
#define EACH_UNSIGNED_SIZE(MACRO, ARG) \
MACRO(8, uint8_t, ARG) \
MACRO(16, uint16_t, ARG) \
MACRO(32, uint32_t, ARG) \
MACRO(64, uint64_t, ARG)
#define EACH_SIGNED_SIZE(MACRO, ARG) \
MACRO(7, int8_t, ARG) \
MACRO(15, int16_t, ARG) \
MACRO(31, int32_t, ARG) \
MACRO(63, int64_t, ARG)
// calculate how much buffer size we need // calculate how much buffer size we need
size_t bufSize = 0; size_t bufSize = 0;
{ {
size_t w = 0; size_t w = 0;
#define SIZE_TEST(N, T, NEG) \ // Unsigned
for (size_t s = 0; s <= N; ++s) { \ accSize<8>(w);
w += s; \ accSize<16>(w);
} accSize<32>(w);
EACH_UNSIGNED_SIZE(SIZE_TEST, false) accSize<64>(w);
EACH_SIGNED_SIZE(SIZE_TEST, false)
EACH_SIGNED_SIZE(SIZE_TEST, true) // Signed NEG=false
#undef SIZE_TEST accSize<7>(w);
accSize<15>(w);
accSize<31>(w);
accSize<63>(w);
// Signed NEG=true
accSize<7>(w);
accSize<15>(w);
accSize<31>(w);
accSize<63>(w);
bufSize = w; bufSize = w;
} }
// bits->bytes, rounding up // bits->bytes, rounding up
...@@ -288,32 +315,45 @@ void testConcatenation() { ...@@ -288,32 +315,45 @@ void testConcatenation() {
uint8_t *buf = buffer.data(); uint8_t *buf = buffer.data();
{ {
size_t w = 0; size_t w = 0;
#define WRITE_TEST(N, T, NEG) \ // Unsigned
for (size_t s = 0; s <= N; ++s) { \ testSetLoop<8, uint8_t, false, aligned>(w, bufSize, buf);
CHECK_LE(s + w, 8 * bufSize); \ testSetLoop<16, uint16_t, false, aligned>(w, bufSize, buf);
testSet<aligned>(buf, w, s, testValue<T, NEG>(s)); \ testSetLoop<32, uint32_t, false, aligned>(w, bufSize, buf);
EXPECT_EQ((testValue<T, NEG>(s)), (testGet<aligned, T>(buf, w, s))) << s; \ testSetLoop<64, uint64_t, false, aligned>(w, bufSize, buf);
w += s; \
} // Signed NEG=false
EACH_UNSIGNED_SIZE(WRITE_TEST, false) testSetLoop<7, int8_t, false, aligned>(w, bufSize, buf);
EACH_SIGNED_SIZE(WRITE_TEST, false) testSetLoop<15, int16_t, false, aligned>(w, bufSize, buf);
EACH_SIGNED_SIZE(WRITE_TEST, true) testSetLoop<31, int32_t, false, aligned>(w, bufSize, buf);
#undef WRITE_TEST testSetLoop<63, int64_t, false, aligned>(w, bufSize, buf);
// Signed NEG=true
testSetLoop<7, int8_t, true, aligned>(w, bufSize, buf);
testSetLoop<15, int16_t, true, aligned>(w, bufSize, buf);
testSetLoop<31, int32_t, true, aligned>(w, bufSize, buf);
testSetLoop<63, int64_t, true, aligned>(w, bufSize, buf);
} }
{ {
size_t r = 0; size_t r = 0;
#define READ_TEST(N, T, NEG) \ // Unsigned
for (size_t s = 0; s <= N; ++s) { \ testGetLoop<8, uint8_t, false, aligned>(r, bufSize, buf);
CHECK_LE(s + r, 8 * bufSize); \ testGetLoop<16, uint16_t, false, aligned>(r, bufSize, buf);
EXPECT_EQ((testValue<T, NEG>(s)), (testGet<aligned, T>(buf, r, s))) << s; \ testGetLoop<32, uint32_t, false, aligned>(r, bufSize, buf);
r += s; \ testGetLoop<64, uint64_t, false, aligned>(r, bufSize, buf);
}
EACH_UNSIGNED_SIZE(READ_TEST, false) // Signed NEG=false
EACH_SIGNED_SIZE(READ_TEST, false) testGetLoop<7, int8_t, false, aligned>(r, bufSize, buf);
EACH_SIGNED_SIZE(READ_TEST, true) testGetLoop<15, int16_t, false, aligned>(r, bufSize, buf);
#undef READ_TEST testGetLoop<31, int32_t, false, aligned>(r, bufSize, buf);
testGetLoop<63, int64_t, false, aligned>(r, bufSize, buf);
// Signed NEG=true
testGetLoop<7, int8_t, true, aligned>(r, bufSize, buf);
testGetLoop<15, int16_t, true, aligned>(r, bufSize, buf);
testGetLoop<31, int32_t, true, aligned>(r, bufSize, buf);
testGetLoop<63, int64_t, true, aligned>(r, bufSize, buf);
} }
#undef EACH_UNSIGNED_SIZE
} }
TEST(Bits, ConcatenationUnalignedUnsigned) { testConcatenation<false>(); } TEST(Bits, ConcatenationUnalignedUnsigned) { testConcatenation<false>(); }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment