Skip to content

Commit 3b39c0f

Browse files
committed
Add know value unpack
1 parent b90dc10 commit 3b39c0f

File tree

1 file changed

+87
-29
lines changed

1 file changed

+87
-29
lines changed

cpp/src/arrow/util/bpacking_test.cc

Lines changed: 87 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -117,12 +117,12 @@ const uint8_t* GetNextAlignedByte(const uint8_t* ptr, std::size_t alignment) {
117117
return ptr + bytes_to_add;
118118
}
119119

120-
struct UnpackingData {
120+
struct TestUnpackSize {
121121
int32_t num_values;
122122
int32_t bit_width;
123123
};
124124

125-
class UnpackingRandomRoundTrip : public ::testing::TestWithParam<UnpackingData> {
125+
class TestUnpack : public ::testing::TestWithParam<TestUnpackSize> {
126126
protected:
127127
template <typename Int>
128128
void TestRoundtripAlignment(UnpackFunc<Int> unpack, std::size_t alignment_offset) {
@@ -132,61 +132,119 @@ class UnpackingRandomRoundTrip : public ::testing::TestWithParam<UnpackingData>
132132
// So we allocate more values than necessary and skip to the next byte with the
133133
// desired (non) alignment to test the proper condition.
134134
constexpr int32_t kExtraValues = sizeof(Int) * 8;
135-
auto const packed = GenerateRandomPackedValues(num_values + kExtraValues, bit_width);
135+
const auto packed = GenerateRandomPackedValues(num_values + kExtraValues, bit_width);
136136
const uint8_t* packed_unaligned =
137137
GetNextAlignedByte(packed.data(), sizeof(Int)) + alignment_offset;
138138

139139
CheckUnpackPackRoundtrip(packed_unaligned, num_values, bit_width, unpack);
140140
}
141141

142142
template <typename Int>
143-
void TestRoundtrip(UnpackFunc<Int> unpack) {
144-
// Aligned test
145-
TestRoundtripAlignment(unpack, 0);
146-
// Unaligned test
147-
TestRoundtripAlignment(unpack, 1);
143+
void TestUnpackZeros(UnpackFunc<Int> unpack) {
144+
auto [num_values, bit_width] = GetParam();
145+
const auto num_bytes = GetNumBytes(num_values, bit_width);
146+
147+
const std::vector<uint8_t> packed(static_cast<std::size_t>(num_bytes), uint8_t{0});
148+
const auto unpacked = UnpackValues(packed.data(), num_values, bit_width, unpack);
149+
150+
const std::vector<Int> expected(static_cast<std::size_t>(num_values), Int{0});
151+
EXPECT_EQ(unpacked, expected);
152+
}
153+
154+
template <typename Int>
155+
void TestUnpackOnes(UnpackFunc<Int> unpack) {
156+
auto [num_values, bit_width] = GetParam();
157+
const auto num_bytes = GetNumBytes(num_values, bit_width);
158+
159+
const std::vector<uint8_t> packed(static_cast<std::size_t>(num_bytes), uint8_t{0xFF});
160+
const auto unpacked = UnpackValues(packed.data(), num_values, bit_width, unpack);
161+
162+
// Generate bit_width ones
163+
Int expected_value = 0;
164+
for (int i = 0; i < bit_width; ++i) {
165+
expected_value = (expected_value << 1) | 1;
166+
}
167+
const std::vector<Int> expected(static_cast<std::size_t>(num_values), expected_value);
168+
EXPECT_EQ(unpacked, expected);
169+
}
170+
171+
template <typename Int>
172+
void TestUnpackAlternating(UnpackFunc<Int> unpack) {
173+
const auto [num_values, bit_width] = GetParam();
174+
const auto num_bytes = GetNumBytes(num_values, bit_width);
175+
176+
const std::vector<uint8_t> packed(static_cast<std::size_t>(num_bytes), uint8_t{0xAA});
177+
const auto unpacked = UnpackValues(packed.data(), num_values, bit_width, unpack);
178+
179+
// Generate alternative bit sequence sratring with either 0 or 1
180+
Int one_zero_value = 0;
181+
Int zero_one_value = 0;
182+
for (int i = 0; i < bit_width; ++i) {
183+
zero_one_value = (zero_one_value << 1) | (i % 2);
184+
one_zero_value = (one_zero_value << 1) | ((i + 1) % 2);
185+
}
186+
187+
std::vector<Int> expected;
188+
if (bit_width % 2 == 0) {
189+
// For even bit_width, the same pattern repeats every time
190+
expected.resize(static_cast<std::size_t>(num_values), one_zero_value);
191+
} else {
192+
// For odd bit_width, we alternate a pattern leading with 0 and 1
193+
for (int i = 0; i < num_values; ++i) {
194+
expected.push_back(i % 2 == 0 ? zero_one_value : one_zero_value);
195+
}
196+
}
197+
EXPECT_EQ(unpacked, expected);
198+
}
199+
200+
template <typename Int>
201+
void TestAll(UnpackFunc<Int> unpack) {
202+
// Known values
203+
TestUnpackZeros(unpack);
204+
TestUnpackOnes(unpack);
205+
TestUnpackAlternating(unpack);
206+
207+
// Roundtrips
208+
TestRoundtripAlignment(unpack, /* alignment_offset= */ 0);
209+
TestRoundtripAlignment(unpack, /* alignment_offset= */ 1);
148210
}
149211
};
150212

151213
INSTANTIATE_TEST_SUITE_P(
152-
MutpliesOf64Values, UnpackingRandomRoundTrip,
153-
::testing::Values(UnpackingData{64, 1}, UnpackingData{128, 1}, UnpackingData{2048, 1},
154-
UnpackingData{64, 31}, UnpackingData{128, 31},
155-
UnpackingData{2048, 31}, UnpackingData{64000, 7},
156-
UnpackingData{64000, 8}, UnpackingData{64000, 13},
157-
UnpackingData{64000, 16}, UnpackingData{64000, 31},
158-
UnpackingData{64000, 32}));
159-
160-
TEST_P(UnpackingRandomRoundTrip, unpack32Default) {
161-
this->TestRoundtrip(&unpack32_default);
162-
}
163-
TEST_P(UnpackingRandomRoundTrip, unpack64Default) {
164-
this->TestRoundtrip(&unpack64_default);
165-
}
214+
MutpliesOf64Values, TestUnpack,
215+
::testing::Values(TestUnpackSize{64, 1}, TestUnpackSize{128, 1},
216+
TestUnpackSize{2048, 1}, TestUnpackSize{64, 31},
217+
TestUnpackSize{128, 31}, TestUnpackSize{2048, 31},
218+
TestUnpackSize{64000, 7}, TestUnpackSize{64000, 8},
219+
TestUnpackSize{64000, 13}, TestUnpackSize{64000, 16},
220+
TestUnpackSize{64000, 31}, TestUnpackSize{64000, 32}));
221+
222+
TEST_P(TestUnpack, unpack32Default) { this->TestAll(&unpack32_default); }
223+
TEST_P(TestUnpack, unpack64Default) { this->TestAll(&unpack64_default); }
166224

167225
#if defined(ARROW_HAVE_RUNTIME_AVX2)
168-
TEST_P(UnpackingRandomRoundTrip, unpack32Avx2) {
226+
TEST_P(TestUnpack, unpack32Avx2) {
169227
if (!CpuInfo::GetInstance()->IsSupported(CpuInfo::AVX2)) {
170228
GTEST_SKIP() << "Test requires AVX2";
171229
}
172-
this->testRoundtrip(&unpack32_avx2);
230+
this->TestAll(&unpack32_avx2);
173231
}
174232
#endif
175233

176234
#if defined(ARROW_HAVE_RUNTIME_AVX512)
177-
TEST_P(UnpackingRandomRoundTrip, unpack32Avx512) {
235+
TEST_P(TestUnpack, unpack32Avx512) {
178236
if (!CpuInfo::GetInstance()->IsSupported(CpuInfo::AVX512)) {
179237
GTEST_SKIP() << "Test requires AVX512";
180238
}
181-
this->testRoundtrip(&unpack32_avx512);
239+
this->TestAll(&unpack32_avx512);
182240
}
183241
#endif
184242

185243
#if defined(ARROW_HAVE_NEON)
186-
TEST_P(UnpackingRandomRoundTrip, unpack32Neon) { this->TestRoundtrip(&unpack32_neon); }
244+
TEST_P(TestUnpack, unpack32Neon) { this->TestAll(&unpack32_neon); }
187245
#endif
188246

189-
TEST_P(UnpackingRandomRoundTrip, unpack32) { this->TestRoundtrip(&unpack32); }
190-
TEST_P(UnpackingRandomRoundTrip, unpack64) { this->TestRoundtrip(&unpack64); }
247+
TEST_P(TestUnpack, unpack32) { this->TestAll(&unpack32); }
248+
TEST_P(TestUnpack, unpack64) { this->TestAll(&unpack64); }
191249

192250
} // namespace arrow::internal

0 commit comments

Comments
 (0)