Conversation
|
Here are some examples from a local GDB session. RunEndEncodedTypeRunEndEncodedType run_end_encoded_type(int32(), utf8());
auto heap_run_end_encoded_type =
run_end_encoded(int32(), utf8());
(gdb) p run_end_encoded_type
$1 = arrow::run_end_encoded(arrow::int32(), arrow::utf8())
(gdb) p *heap_run_end_encoded_type
$2 = (std::__shared_ptr_access<arrow::DataType, (__gnu_cxx::_Lock_policy)2, false, false>::element_type &) @0x555555f52f10:
arrow::run_end_encoded(arrow::int32(), arrow::utf8())RunEndEncodedScalarauto run_end_encoded_scalar_type =
run_end_encoded(int32(), utf8());
RunEndEncodedScalar run_end_encoded_scalar{
MakeScalar("foo"), run_end_encoded_scalar_type};
RunEndEncodedScalar run_end_encoded_scalar_null{
run_end_encoded_scalar_type};
(gdb) p run_end_encoded_scalar
$3 = arrow::RunEndEncodedScalar of value
arrow::StringScalar of size 3, value "foo"
(gdb) p run_end_encoded_scalar_null
$4 = arrow::RunEndEncodedScalar of type
arrow::run_end_encoded(arrow::int32(), arrow::utf8()),
null valueRunEndEncodedArray// Encodes ["foo", "foo", null, null, null].
auto run_end_encoded_run_ends =
SliceArrayFromJSON(int32(), "[2, 5]");
auto run_end_encoded_values =
SliceArrayFromJSON(utf8(), R"(["foo", null])");
auto heap_run_end_encoded_array =
*RunEndEncodedArray::Make(
5, run_end_encoded_run_ends,
run_end_encoded_values);
auto heap_run_end_encoded_array_sliced =
heap_run_end_encoded_array->Slice(1, 3);
(gdb) p *heap_run_end_encoded_array
$5 = (std::__shared_ptr_access<arrow::Array, (__gnu_cxx::_Lock_policy)2, false, false>::element_type &) @0x555555fab440:
arrow::RunEndEncodedArray of type
arrow::run_end_encoded(arrow::int32(), arrow::utf8()),
length 5, offset 0, null count 0
(gdb) p *heap_run_end_encoded_array_sliced
$6 = (std::__shared_ptr_access<arrow::Array, (__gnu_cxx::_Lock_policy)2, false, false>::element_type &) @0x555555f7dd60:
arrow::RunEndEncodedArray of type
arrow::run_end_encoded(arrow::int32(), arrow::utf8()),
length 3, offset 1, null count 0 |
|
The |
| class RunEndEncodedTypeClass(DataTypeClass): | ||
| is_parametric = True | ||
| type_printer = RunEndEncodedTypePrinter | ||
| scalar_printer = BaseListScalarPrinter |
There was a problem hiding this comment.
This (using BaseListScalarPrinter) might work by chance, but I don't think this is conceptually right. Run-end-encoded is not a list type, and a run-end-encoded scalar represents a single child value, not an entire run of values.
(as the tests show, by the way)
There was a problem hiding this comment.
Done, defined a RunEndEncodedScalarPrinter.
c9a6c64 to
36d4c88
Compare
36d4c88 to
326e0ce
Compare
| for i in range(self.length): | ||
| target = bisect_right(run_ends, self.offset + i) | ||
| while physical_index <= target: | ||
| value = next(values, None) | ||
| if value is None: | ||
| return | ||
| physical_index += 1 | ||
| yield self._valid_child(i, value[1]) |
There was a problem hiding this comment.
Bisecting each logical value is inefficient while we can just loop over physical values and run ends in order. Something like:
| for i in range(self.length): | |
| target = bisect_right(run_ends, self.offset + i) | |
| while physical_index <= target: | |
| value = next(values, None) | |
| if value is None: | |
| return | |
| physical_index += 1 | |
| yield self._valid_child(i, value[1]) | |
| run_start = run_ends[self.offset - 1] if self.offset > 0 else 0 | |
| for i in range(self.length): | |
| run_end = run_ends[self.offset + i] | |
| value = next(values, None) | |
| if value is None: | |
| return | |
| for logical_index in range(run_start, run_end): | |
| yield self._valid_child(logical_index, value[1]) | |
| run_start = run_end |
There was a problem hiding this comment.
Thanks! I now use one bisect_right() call, then iterate through the runs in order.
| # E.g. offset=3, length=6 selects bits 3..8 and needs 2 bytes. | ||
| byte_length = math.ceil((bit_offset + length) / 8) |
There was a problem hiding this comment.
I see this fixes a bug, can you add a test that exercises it?
There was a problem hiding this comment.
Sure. I will address these two comments later today.
There was a problem hiding this comment.
The existing BooleanArray slice tests already cover this case:
auto heap_bool_array_sliced_1_9 =
SliceArrayFromJSON(boolean(), json_bool_array, 1, 9);
auto heap_bool_array_sliced_2_6 =
SliceArrayFromJSON(boolean(), json_bool_array, 2, 6);They exercise Bitmap.from_buffer() with non-byte-aligned offsets and ranges that cross byte boundaries.
Before this change, Buffer.bytes_view() ignored the requested length:
if length is None:
length = self.size
mem = gdb.selected_inferior().read_memory(
self.val['data_'] + offset, self.size)It always read self.size bytes. Now it reads the requested length:
mem = gdb.selected_inferior().read_memory(
self.val['data_'] + offset, length)This previously masked the incorrect byte-length calculation in Bitmap.from_buffer(). Since the existing tests already cover this path, I did not add another test case.
Rationale for this change
The Arrow GDB pretty-printers do not support run-end encoded data types.
What changes are included in this PR?
Add GDB pretty-printer support and tests for
run-end encodedtypes, scalars, and arrays.Are these changes tested?
Yes.
Are there any user-facing changes?
No.
gdb_arrow.py#50658