GH-50385: [Ruby] Add bitmap builder for red-arrow-format#50386
Conversation
|
|
There was a problem hiding this comment.
Pull request overview
Adds bitmap builder utilities to red-arrow-format to construct Arrow-compatible bitmaps (with 64-byte padding) for validity and boolean buffers, and migrates the integration JSON reader to use the new builder logic.
Changes:
- Introduce
ArrowFormat::DenseBitmapBuilderandArrowFormat::SparseBitmapBuilder. - Add unit tests for both bitmap builders.
- Update integration JSON reader bitmap construction to use
DenseBitmapBuilder.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 7 comments.
| File | Description |
|---|---|
| ruby/red-arrow-format/lib/arrow-format/bitmap-builder.rb | Adds dense/sparse bitmap builder implementations with 64-byte padding behavior. |
| ruby/red-arrow-format/lib/arrow-format/integration/json-reader.rb | Switches JSON bitmap decoding to use the new dense bitmap builder. |
| ruby/red-arrow-format/test/test-dense-bitmap-builder.rb | Adds unit tests for dense bitmap builder output and padding. |
| ruby/red-arrow-format/test/test-sparse-bitmap-builder.rb | Adds unit tests for sparse bitmap builder output and padding. |
| # or more contributor license agreements. See the NOTICE file | ||
| # distributed with this work for additional information |
| padding_size = buffer_padding_size(@buffer) | ||
| @buffer.append_as_bytes(padding(padding_size)) if padding_size > 0 | ||
| @buffer.freeze | ||
| IO::Buffer.for(@buffer) |
| def flush | ||
| @buffer.append_as_bytes([@byte].pack("C")) | ||
| @n_bits = 0 | ||
| @byte = 0 | ||
| end |
| def finish(size) | ||
| builder = DenseBitmapBuilder.new | ||
| not_set_value = @default | ||
| set_value = !@default | ||
| previous_index = 0 | ||
| @indexes.sort.each do |index| | ||
| previous_index.upto(index - 1) do | ||
| builder.append(not_set_value) | ||
| end | ||
| builder.append(set_value) | ||
| previous_index = index + 1 | ||
| end | ||
| if previous_index.zero? | ||
| n_remains = size | ||
| else | ||
| n_remains = size - previous_index | ||
| end | ||
| n_remains.times do | ||
| builder.append(not_set_value) | ||
| end | ||
| builder.finish | ||
| end |
|
|
||
| class TestDenseBitmapBuilder < Test::Unit::TestCase |
|
|
||
| class TestSparseBitmapBuilder < Test::Unit::TestCase |
| def read_bitmap(bitmap) | ||
| buffer = +"".b | ||
| bitmap.each_slice(8) do |bits| | ||
| byte = 0 | ||
| while bits.size < 8 | ||
| bits << 0 | ||
| end | ||
| bits.reverse_each do |bit| | ||
| byte = (byte << 1) + bit | ||
| end | ||
| buffer << [byte].pack("C") | ||
| builder = DenseBitmapBuilder.new | ||
| bitmap.each do |bit| | ||
| builder.append(bit == 1 ? true : false) | ||
| end |
| @indexes.keys.sort.each do |index| | ||
| previous_index.upto(index - 1) do | ||
| builder.append(not_set_value) | ||
| end | ||
| builder.append(set_value) | ||
| previous_index = index + 1 | ||
| end |
| def set(index) | ||
| @indexes[index] = true | ||
| end |
| data.each_with_index do |value, i| | ||
| if value.nil? | ||
| validity_buffer_builder ||= SparseBitmapBuilder.new(true) | ||
| validity_buffer_builder.set(i) | ||
| values_buffer_builder.append(false) | ||
| elsif value | ||
| values_buffer_builder.append(true) | ||
| else | ||
| values_buffer_builder.append(false) | ||
| end | ||
| n += 1 | ||
| end |
| def finish | ||
| flush if @n_bits > 0 | ||
| padding_size = buffer_padding_size(@buffer) | ||
| @buffer.append_as_bytes(padding(padding_size)) if padding_size > 0 | ||
| @buffer.freeze |
| def flush | ||
| @buffer.append_as_bytes([@byte].pack("C")) | ||
| @n_bits = 0 | ||
| @byte = 0 | ||
| end |
| def finish(size) | ||
| builder = DenseBitmapBuilder.new | ||
| set_value = true | ||
| unset_value = false | ||
| if @unset_indexes.empty? |
|
+1 |
|
After merging your PR, Conbench analyzed the 4 benchmarking runs that have been run so far on merge-commit 6570969. There were no benchmark performance regressions. 🎉 The full Conbench report has more details. It also includes information about 1 possible false positive for unstable benchmarks that are known to sometimes produce them. |
Rationale for this change
It can be used for validity bitmap and boolean array.
What changes are included in this PR?
ArrowFormat::DenseBitmapBuilderArrowFormat::SparseBitmapBuilderArrowFormat::BooleanArray.new(values)Are these changes tested?
Yes.
Are there any user-facing changes?
Yes.