[
https://issues.apache.org/jira/browse/ARROW-15678?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=17539142#comment-17539142
]
Kouhei Sutou commented on ARROW-15678:
--------------------------------------
How about using template to distinct implementation for each architecture?
{noformat}
diff --git a/cpp/src/arrow/compute/kernels/codegen_internal.h
b/cpp/src/arrow/compute/kernels/codegen_internal.h
index fa50427bc3..a4bd0eb586 100644
--- a/cpp/src/arrow/compute/kernels/codegen_internal.h
+++ b/cpp/src/arrow/compute/kernels/codegen_internal.h
@@ -710,8 +710,8 @@ struct ScalarUnaryNotNullStateful {
Datum* out) {
Status st = Status::OK();
ArrayData* out_arr = out->mutable_array();
- FirstTimeBitmapWriter out_writer(out_arr->buffers[1]->mutable_data(),
- out_arr->offset, out_arr->length);
+ FirstTimeBitmapWriter<> out_writer(out_arr->buffers[1]->mutable_data(),
+ out_arr->offset, out_arr->length);
VisitArrayValuesInline<Arg0Type>(
arg0,
[&](Arg0Value v) {
diff --git a/cpp/src/arrow/compute/kernels/row_encoder.cc
b/cpp/src/arrow/compute/kernels/row_encoder.cc
index 10a1f4cda5..26316ec315 100644
--- a/cpp/src/arrow/compute/kernels/row_encoder.cc
+++ b/cpp/src/arrow/compute/kernels/row_encoder.cc
@@ -42,7 +42,7 @@ Status KeyEncoder::DecodeNulls(MemoryPool* pool, int32_t
length, uint8_t** encod
ARROW_ASSIGN_OR_RAISE(*null_bitmap, AllocateBitmap(length, pool));
uint8_t* validity = (*null_bitmap)->mutable_data();
- FirstTimeBitmapWriter writer(validity, 0, length);
+ FirstTimeBitmapWriter<> writer(validity, 0, length);
for (int32_t i = 0; i < length; ++i) {
if (encoded_bytes[i][0] == kValidByte) {
writer.Set();
diff --git a/cpp/src/arrow/compute/kernels/scalar_set_lookup.cc
b/cpp/src/arrow/compute/kernels/scalar_set_lookup.cc
index 7d8d2edc4b..433df0f1b7 100644
--- a/cpp/src/arrow/compute/kernels/scalar_set_lookup.cc
+++ b/cpp/src/arrow/compute/kernels/scalar_set_lookup.cc
@@ -353,8 +353,8 @@ struct IsInVisitor {
const auto& state = checked_cast<const
SetLookupState<Type>&>(*ctx->state());
ArrayData* output = out->mutable_array();
- FirstTimeBitmapWriter writer(output->buffers[1]->mutable_data(),
output->offset,
- output->length);
+ FirstTimeBitmapWriter<> writer(output->buffers[1]->mutable_data(),
output->offset,
+ output->length);
VisitArrayDataInline<Type>(
this->data,
diff --git a/cpp/src/arrow/compute/kernels/scalar_string_ascii.cc
b/cpp/src/arrow/compute/kernels/scalar_string_ascii.cc
index 611601cab8..da7de1c277 100644
--- a/cpp/src/arrow/compute/kernels/scalar_string_ascii.cc
+++ b/cpp/src/arrow/compute/kernels/scalar_string_ascii.cc
@@ -1456,7 +1456,7 @@ struct MatchSubstringImpl {
[&matcher](const void* raw_offsets, const uint8_t* data, int64_t
length,
int64_t output_offset, uint8_t* output) {
const offset_type* offsets = reinterpret_cast<const
offset_type*>(raw_offsets);
- FirstTimeBitmapWriter bitmap_writer(output, output_offset, length);
+ FirstTimeBitmapWriter<> bitmap_writer(output, output_offset, length);
for (int64_t i = 0; i < length; ++i) {
const char* current_data = reinterpret_cast<const char*>(data +
offsets[i]);
int64_t current_length = offsets[i + 1] - offsets[i];
diff --git a/cpp/src/arrow/util/bit_util_benchmark.cc
b/cpp/src/arrow/util/bit_util_benchmark.cc
index 258fd27785..66a81b4e04 100644
--- a/cpp/src/arrow/util/bit_util_benchmark.cc
+++ b/cpp/src/arrow/util/bit_util_benchmark.cc
@@ -386,7 +386,7 @@ static void BitmapWriter(benchmark::State& state) {
}
static void FirstTimeBitmapWriter(benchmark::State& state) {
- BenchmarkBitmapWriter<internal::FirstTimeBitmapWriter>(state,
state.range(0));
+ BenchmarkBitmapWriter<internal::FirstTimeBitmapWriter<>>(state,
state.range(0));
}
struct GenerateBitsFunctor {
diff --git a/cpp/src/arrow/util/bit_util_test.cc
b/cpp/src/arrow/util/bit_util_test.cc
index 6c2aff4fbe..9b9f19feb1 100644
--- a/cpp/src/arrow/util/bit_util_test.cc
+++ b/cpp/src/arrow/util/bit_util_test.cc
@@ -832,14 +832,14 @@ TEST(FirstTimeBitmapWriter, NormalOperation) {
const uint8_t fill_byte = static_cast<uint8_t>(fill_byte_int);
{
uint8_t bitmap[] = {fill_byte, fill_byte, fill_byte, fill_byte};
- auto writer = internal::FirstTimeBitmapWriter(bitmap, 0, 12);
+ auto writer = internal::FirstTimeBitmapWriter<>(bitmap, 0, 12);
WriteVectorToWriter(writer, {0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 0, 1});
// {0b00110110, 0b1010, 0, 0}
ASSERT_BYTES_EQ(bitmap, {0x36, 0x0a});
}
{
uint8_t bitmap[] = {fill_byte, fill_byte, fill_byte, fill_byte};
- auto writer = internal::FirstTimeBitmapWriter(bitmap, 4, 12);
+ auto writer = internal::FirstTimeBitmapWriter<>(bitmap, 4, 12);
WriteVectorToWriter(writer, {0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 0, 1});
// {0b00110110, 0b1010, 0, 0}
ASSERT_BYTES_EQ(bitmap, {static_cast<uint8_t>(0x60 | (fill_byte &
0x0f)), 0xa3});
@@ -848,15 +848,15 @@ TEST(FirstTimeBitmapWriter, NormalOperation) {
{
uint8_t bitmap[] = {fill_byte, fill_byte, fill_byte, fill_byte};
{
- auto writer = internal::FirstTimeBitmapWriter(bitmap, 0, 6);
+ auto writer = internal::FirstTimeBitmapWriter<>(bitmap, 0, 6);
WriteVectorToWriter(writer, {0, 1, 1, 0, 1, 1});
}
{
- auto writer = internal::FirstTimeBitmapWriter(bitmap, 6, 3);
+ auto writer = internal::FirstTimeBitmapWriter<>(bitmap, 6, 3);
WriteVectorToWriter(writer, {0, 0, 0});
}
{
- auto writer = internal::FirstTimeBitmapWriter(bitmap, 9, 3);
+ auto writer = internal::FirstTimeBitmapWriter<>(bitmap, 9, 3);
WriteVectorToWriter(writer, {1, 0, 1});
}
ASSERT_BYTES_EQ(bitmap, {0x36, 0x0a});
@@ -864,23 +864,23 @@ TEST(FirstTimeBitmapWriter, NormalOperation) {
{
uint8_t bitmap[] = {fill_byte, fill_byte, fill_byte, fill_byte};
{
- auto writer = internal::FirstTimeBitmapWriter(bitmap, 4, 0);
+ auto writer = internal::FirstTimeBitmapWriter<>(bitmap, 4, 0);
WriteVectorToWriter(writer, {});
}
{
- auto writer = internal::FirstTimeBitmapWriter(bitmap, 4, 6);
+ auto writer = internal::FirstTimeBitmapWriter<>(bitmap, 4, 6);
WriteVectorToWriter(writer, {0, 1, 1, 0, 1, 1});
}
{
- auto writer = internal::FirstTimeBitmapWriter(bitmap, 10, 3);
+ auto writer = internal::FirstTimeBitmapWriter<>(bitmap, 10, 3);
WriteVectorToWriter(writer, {0, 0, 0});
}
{
- auto writer = internal::FirstTimeBitmapWriter(bitmap, 13, 0);
+ auto writer = internal::FirstTimeBitmapWriter<>(bitmap, 13, 0);
WriteVectorToWriter(writer, {});
}
{
- auto writer = internal::FirstTimeBitmapWriter(bitmap, 13, 3);
+ auto writer = internal::FirstTimeBitmapWriter<>(bitmap, 13, 3);
WriteVectorToWriter(writer, {1, 0, 1});
}
ASSERT_BYTES_EQ(bitmap, {static_cast<uint8_t>(0x60 | (fill_byte &
0x0f)), 0xa3});
@@ -900,8 +900,8 @@ TEST(FirstTimeBitmapWriter,
AppendWordOffsetOverwritesCorrectBitsOnExistingByte)
auto check_append = [](const std::string& expected_bits, int64_t offset) {
std::vector<uint8_t> valid_bits = {0x00};
constexpr int64_t kBitsAfterAppend = 8;
- internal::FirstTimeBitmapWriter writer(valid_bits.data(), offset,
- /*length=*/(8 * valid_bits.size())
- offset);
+ internal::FirstTimeBitmapWriter<> writer(valid_bits.data(), offset,
+ /*length=*/(8 *
valid_bits.size()) - offset);
writer.AppendWord(/*word=*/0xFF, /*number_of_bits=*/kBitsAfterAppend -
offset);
writer.Finish();
EXPECT_EQ(BitmapToString(valid_bits, kBitsAfterAppend), expected_bits);
@@ -918,8 +918,8 @@ TEST(FirstTimeBitmapWriter,
AppendWordOffsetOverwritesCorrectBitsOnExistingByte)
auto check_with_set = [](const std::string& expected_bits, int64_t offset) {
std::vector<uint8_t> valid_bits = {0x1};
constexpr int64_t kBitsAfterAppend = 8;
- internal::FirstTimeBitmapWriter writer(valid_bits.data(), offset,
- /*length=*/(8 * valid_bits.size())
- offset);
+ internal::FirstTimeBitmapWriter<> writer(valid_bits.data(), offset,
+ /*length=*/(8 *
valid_bits.size()) - offset);
writer.AppendWord(/*word=*/0xFF, /*number_of_bits=*/kBitsAfterAppend -
offset);
writer.Finish();
EXPECT_EQ(BitmapToString(valid_bits, kBitsAfterAppend), expected_bits);
@@ -936,8 +936,8 @@ TEST(FirstTimeBitmapWriter,
AppendWordOffsetOverwritesCorrectBitsOnExistingByte)
auto check_with_preceding = [](const std::string& expected_bits, int64_t
offset) {
std::vector<uint8_t> valid_bits = {0xFF};
constexpr int64_t kBitsAfterAppend = 8;
- internal::FirstTimeBitmapWriter writer(valid_bits.data(), offset,
- /*length=*/(8 * valid_bits.size())
- offset);
+ internal::FirstTimeBitmapWriter<> writer(valid_bits.data(), offset,
+ /*length=*/(8 *
valid_bits.size()) - offset);
writer.AppendWord(/*word=*/0xFF, /*number_of_bits=*/kBitsAfterAppend -
offset);
writer.Finish();
EXPECT_EQ(BitmapToString(valid_bits, kBitsAfterAppend), expected_bits);
@@ -954,8 +954,8 @@ TEST(FirstTimeBitmapWriter,
AppendWordOffsetOverwritesCorrectBitsOnExistingByte)
TEST(FirstTimeBitmapWriter, AppendZeroBitsHasNoImpact) {
std::vector<uint8_t> valid_bits(/*count=*/1, 0);
- internal::FirstTimeBitmapWriter writer(valid_bits.data(), /*start_offset=*/1,
- /*length=*/valid_bits.size() * 8);
+ internal::FirstTimeBitmapWriter<> writer(valid_bits.data(),
/*start_offset=*/1,
+ /*length=*/valid_bits.size() * 8);
writer.AppendWord(/*word=*/0xFF, /*number_of_bits=*/0);
writer.AppendWord(/*word=*/0xFF, /*number_of_bits=*/0);
writer.AppendWord(/*word=*/0x01, /*number_of_bits=*/1);
@@ -966,8 +966,8 @@ TEST(FirstTimeBitmapWriter, AppendZeroBitsHasNoImpact) {
TEST(FirstTimeBitmapWriter, AppendLessThanByte) {
{
std::vector<uint8_t> valid_bits(/*count*/ 8, 0);
- internal::FirstTimeBitmapWriter writer(valid_bits.data(),
/*start_offset=*/1,
- /*length=*/8);
+ internal::FirstTimeBitmapWriter<> writer(valid_bits.data(),
/*start_offset=*/1,
+ /*length=*/8);
writer.AppendWord(0xB, 4);
writer.Finish();
EXPECT_EQ(BitmapToString(valid_bits, /*bit_count=*/8), "01101000");
@@ -975,8 +975,8 @@ TEST(FirstTimeBitmapWriter, AppendLessThanByte) {
{
// Test with all bits initially set.
std::vector<uint8_t> valid_bits(/*count*/ 8, 0xFF);
- internal::FirstTimeBitmapWriter writer(valid_bits.data(),
/*start_offset=*/1,
- /*length=*/8);
+ internal::FirstTimeBitmapWriter<> writer(valid_bits.data(),
/*start_offset=*/1,
+ /*length=*/8);
writer.AppendWord(0xB, 4);
writer.Finish();
EXPECT_EQ(BitmapToString(valid_bits, /*bit_count=*/8), "11101000");
@@ -986,8 +986,8 @@ TEST(FirstTimeBitmapWriter, AppendLessThanByte) {
TEST(FirstTimeBitmapWriter, AppendByteThenMore) {
{
std::vector<uint8_t> valid_bits(/*count*/ 8, 0);
- internal::FirstTimeBitmapWriter writer(valid_bits.data(),
/*start_offset=*/0,
- /*length=*/9);
+ internal::FirstTimeBitmapWriter<> writer(valid_bits.data(),
/*start_offset=*/0,
+ /*length=*/9);
writer.AppendWord(0xC3, 8);
writer.AppendWord(0x01, 1);
writer.Finish();
@@ -995,8 +995,8 @@ TEST(FirstTimeBitmapWriter, AppendByteThenMore) {
}
{
std::vector<uint8_t> valid_bits(/*count*/ 8, 0xFF);
- internal::FirstTimeBitmapWriter writer(valid_bits.data(),
/*start_offset=*/0,
- /*length=*/9);
+ internal::FirstTimeBitmapWriter<> writer(valid_bits.data(),
/*start_offset=*/0,
+ /*length=*/9);
writer.AppendWord(0xC3, 8);
writer.AppendWord(0x01, 1);
writer.Finish();
@@ -1012,8 +1012,8 @@ TEST(FirstTimeBitmapWriter,
AppendWordShiftsBitsCorrectly) {
ASSERT_GE(offset, 8);
std::vector<uint8_t> valid_bits(/*count=*/10, preset_buffer_bits ? 0xFF :
0);
valid_bits[0] = 0x99;
- internal::FirstTimeBitmapWriter writer(valid_bits.data(), offset,
- /*length=*/(9 * sizeof(kPattern)) -
offset);
+ internal::FirstTimeBitmapWriter<> writer(valid_bits.data(), offset,
+ /*length=*/(9 * sizeof(kPattern))
- offset);
writer.AppendWord(/*word=*/kPattern, /*number_of_bits=*/64);
writer.Finish();
EXPECT_EQ(valid_bits[0], 0x99); // shouldn't get changed.
@@ -1051,15 +1051,15 @@ TEST(TestAppendBitmap,
AppendWordOnlyAppropriateBytesWritten) {
uint64_t bitmap = 0x1FF;
{
- internal::FirstTimeBitmapWriter writer(valid_bits.data(),
/*start_offset=*/1,
- /*length=*/(8 * valid_bits.size())
- 1);
+ internal::FirstTimeBitmapWriter<> writer(valid_bits.data(),
/*start_offset=*/1,
+ /*length=*/(8 *
valid_bits.size()) - 1);
writer.AppendWord(bitmap, /*number_of_bits*/ 7);
writer.Finish();
EXPECT_THAT(valid_bits, ElementsAreArray(std::vector<uint8_t>{0xFE,
0x00}));
}
{
- internal::FirstTimeBitmapWriter writer(valid_bits.data(),
/*start_offset=*/1,
- /*length=*/(8 * valid_bits.size())
- 1);
+ internal::FirstTimeBitmapWriter<> writer(valid_bits.data(),
/*start_offset=*/1,
+ /*length=*/(8 *
valid_bits.size()) - 1);
writer.AppendWord(bitmap, /*number_of_bits*/ 8);
writer.Finish();
EXPECT_THAT(valid_bits, ElementsAreArray(std::vector<uint8_t>{0xFE,
0x03}));
diff --git a/cpp/src/arrow/util/bitmap_writer.h
b/cpp/src/arrow/util/bitmap_writer.h
index 65d0d188d7..7a70b16f15 100644
--- a/cpp/src/arrow/util/bitmap_writer.h
+++ b/cpp/src/arrow/util/bitmap_writer.h
@@ -21,6 +21,8 @@
#include <cstring>
#include "arrow/util/bit_util.h"
+#include "arrow/util/config.h"
+#include "arrow/util/dispatch.h"
#include "arrow/util/endian.h"
#include "arrow/util/macros.h"
@@ -78,6 +80,7 @@ class BitmapWriter {
int64_t byte_offset_;
};
+template <DispatchLevel level = ARROW_COMPILE_TIME_DISPATCH_LEVEL>
class FirstTimeBitmapWriter {
// Like BitmapWriter, but any bit values *following* the bits written
// might be clobbered. It is hence faster than BitmapWriter, and can
diff --git a/cpp/src/arrow/util/config.h.cmake
b/cpp/src/arrow/util/config.h.cmake
index 55bc2d0100..1ecb4f39f3 100644
--- a/cpp/src/arrow/util/config.h.cmake
+++ b/cpp/src/arrow/util/config.h.cmake
@@ -36,6 +36,8 @@
#define ARROW_PACKAGE_KIND "@ARROW_PACKAGE_KIND@"
+#define ARROW_COMPILE_TIME_DISPATCH_LEVEL
::arrow::internal::DispatchLevel::@ARROW_SIMD_LEVEL@
+
#cmakedefine ARROW_COMPUTE
#cmakedefine ARROW_CSV
#cmakedefine ARROW_CUDA
diff --git a/cpp/src/arrow/util/dispatch.h b/cpp/src/arrow/util/dispatch.h
index fae9293f9e..d6f4dbb028 100644
--- a/cpp/src/arrow/util/dispatch.h
+++ b/cpp/src/arrow/util/dispatch.h
@@ -33,6 +33,7 @@ enum class DispatchLevel : int {
SSE4_2,
AVX2,
AVX512,
+ BMI2,
NEON,
MAX
};
@@ -105,6 +106,8 @@ class DynamicDispatch {
return cpu_info->IsSupported(CpuInfo::AVX2);
case DispatchLevel::AVX512:
return cpu_info->IsSupported(CpuInfo::AVX512);
+ case DispatchLevel::BMI2:
+ return cpu_info->IsSupported(CpuInfo::BMI2);
default:
return false;
}
diff --git a/cpp/src/parquet/encoding.cc b/cpp/src/parquet/encoding.cc
index af0e543c3e..34f0eef3b5 100644
--- a/cpp/src/parquet/encoding.cc
+++ b/cpp/src/parquet/encoding.cc
@@ -348,8 +348,8 @@ class PlainEncoder<BooleanType> : public EncoderImpl,
virtual public BooleanEnco
} else {
auto n_valid = bit_util::BytesForBits(data.length() - data.null_count());
PARQUET_THROW_NOT_OK(sink_.Reserve(n_valid));
- ::arrow::internal::FirstTimeBitmapWriter writer(sink_.mutable_data(),
- sink_.length(), n_valid);
+ ::arrow::internal::FirstTimeBitmapWriter<> writer(sink_.mutable_data(),
+ sink_.length(),
n_valid);
for (int64_t i = 0; i < data.length(); i++) {
if (data.IsValid(i)) {
diff --git a/cpp/src/parquet/level_comparison_avx2.cc
b/cpp/src/parquet/level_comparison_avx2.cc
index b33eb2e295..521cf96520 100644
--- a/cpp/src/parquet/level_comparison_avx2.cc
+++ b/cpp/src/parquet/level_comparison_avx2.cc
@@ -16,7 +16,9 @@
// under the License.
#define PARQUET_IMPL_NAMESPACE avx2
+#define PARQUET_DISPATCH_LEVEL ::arrow::internal::DispatchLevel::AVX2
#include "parquet/level_comparison_inc.h"
+#undef PARQUET_DISPATCH_LEVEL
#undef PARQUET_IMPL_NAMESPACE
namespace parquet {
diff --git a/cpp/src/parquet/level_conversion.cc
b/cpp/src/parquet/level_conversion.cc
index ffdca476dd..ab440af95a 100644
--- a/cpp/src/parquet/level_conversion.cc
+++ b/cpp/src/parquet/level_conversion.cc
@@ -28,7 +28,9 @@
#include "parquet/level_comparison.h"
#define PARQUET_IMPL_NAMESPACE standard
+#define PARQUET_DISPATCH_LEVEL ARROW_COMPILE_TIME_DISPATCH_LEVEL
#include "parquet/level_conversion_inc.h"
+#undef PARQUET_DISPATCH_LEVEL
#undef PARQUET_IMPL_NAMESPACE
namespace parquet {
@@ -43,7 +45,7 @@ void DefRepLevelsToListInfo(const int16_t* def_levels, const
int16_t* rep_levels
int64_t num_def_levels, LevelInfo level_info,
ValidityBitmapInputOutput* output, OffsetType*
offsets) {
OffsetType* orig_pos = offsets;
- optional<::arrow::internal::FirstTimeBitmapWriter> valid_bits_writer;
+ optional<::arrow::internal::FirstTimeBitmapWriter<>> valid_bits_writer;
if (output->valid_bits) {
valid_bits_writer.emplace(output->valid_bits, output->valid_bits_offset,
output->values_read_upper_bound);
diff --git a/cpp/src/parquet/level_conversion_bmi2.cc
b/cpp/src/parquet/level_conversion_bmi2.cc
index 274d54e503..679d01d0c9 100644
--- a/cpp/src/parquet/level_conversion_bmi2.cc
+++ b/cpp/src/parquet/level_conversion_bmi2.cc
@@ -17,7 +17,9 @@
#include "parquet/level_conversion.h"
#define PARQUET_IMPL_NAMESPACE bmi2
+#define PARQUET_DISPATCH_LEVEL ::arrow::internal::DispatchLevel::BMI2
#include "parquet/level_conversion_inc.h"
+#undef PARQUET_DISPATCH_LEVEL
#undef PARQUET_IMPL_NAMESPACE
namespace parquet {
diff --git a/cpp/src/parquet/level_conversion_inc.h
b/cpp/src/parquet/level_conversion_inc.h
index 710d2f6237..4b5a9def80 100644
--- a/cpp/src/parquet/level_conversion_inc.h
+++ b/cpp/src/parquet/level_conversion_inc.h
@@ -296,7 +296,10 @@ static constexpr int64_t kExtractBitsSize = 8 *
sizeof(extract_bitmap_t);
template <bool has_repeated_parent>
int64_t DefLevelsBatchToBitmap(const int16_t* def_levels, const int64_t
batch_size,
int64_t upper_bound_remaining, LevelInfo
level_info,
- ::arrow::internal::FirstTimeBitmapWriter*
writer) {
+#ifndef PARQUET_DISPATCH_LEVEL
+#error "PARQUET_DISPATCH_LEVEL must be defined"
+#endif
+
::arrow::internal::FirstTimeBitmapWriter<PARQUET_DISPATCH_LEVEL>* writer) {
DCHECK_LE(batch_size, kExtractBitsSize);
// Greater than level_info.def_level - 1 implies >= the def_level
@@ -330,7 +333,7 @@ int64_t DefLevelsBatchToBitmap(const int16_t* def_levels,
const int64_t batch_si
template <bool has_repeated_parent>
void DefLevelsToBitmapSimd(const int16_t* def_levels, int64_t num_def_levels,
LevelInfo level_info, ValidityBitmapInputOutput*
output) {
- ::arrow::internal::FirstTimeBitmapWriter writer(
+ ::arrow::internal::FirstTimeBitmapWriter<PARQUET_DISPATCH_LEVEL> writer(
output->valid_bits,
/*start_offset=*/output->valid_bits_offset,
/*length=*/output->values_read_upper_bound);
{noformat}
> [C++][CI] a crossbow job with MinRelSize enabled
> ------------------------------------------------
>
> Key: ARROW-15678
> URL: https://issues.apache.org/jira/browse/ARROW-15678
> Project: Apache Arrow
> Issue Type: Improvement
> Components: C++, Continuous Integration
> Reporter: Jonathan Keane
> Priority: Blocker
> Labels: pull-request-available
> Fix For: 9.0.0
>
> Time Spent: 13h
> Remaining Estimate: 0h
>
--
This message was sent by Atlassian Jira
(v8.20.7#820007)