Copilot commented on code in PR #50433:
URL: https://github.com/apache/arrow/pull/50433#discussion_r3548913535


##########
ruby/red-arrow-format/lib/arrow-format/array.rb:
##########
@@ -64,18 +66,28 @@ def empty?
       @size.zero?
     end
 
+    def ==(other)

Review Comment:
   `Array#==` currently only compares validity bitmaps (and uses `and` in a 
modifier form), which can both produce false positives for non-primitive arrays 
(e.g., `VariableSizeBinaryArray` values are ignored) and can raise if one side 
has `@validity_buffer.nil?` while the other has a non-nil validity buffer 
(because `validity_bitmap` is built from `nil`). To make equality content-based 
across all `ArrowFormat::Array` subclasses, compare enumerated values and 
provide a default `each` implementation in the base class.



##########
ruby/red-arrow-format/lib/arrow-format/bitmap.rb:
##########
@@ -19,10 +19,21 @@ module ArrowFormat
   class Bitmap
     include Enumerable
 
-    def initialize(buffer, offset, n_values)
+    attr_reader :offset
+    attr_reader :size
+    alias_method :length, :size
+    def initialize(buffer, offset, size)
       @buffer = buffer
       @offset = offset
-      @n_values = n_values
+      @size = size
+    end
+
+    def ==(other)
+      return false unless other.is_a?(self.class)
+      return false unless @size == other.size
+      zip(other).all? do |bit, other_bit|
+        bit == other_bit
+      end
     end

Review Comment:
   `Bitmap#==` uses `zip(other).all?`, which builds an intermediate array of 
pairs. You can avoid the allocation by using `zip` with a block and 
early-returning on mismatch.



##########
ruby/red-arrow-format/lib/arrow-format/array.rb:
##########
@@ -192,15 +213,47 @@ def to_a
       apply_validity(@values_buffer.values(@type.buffer_type, offset, @size))
     end
 
+    def each(&block)
+      return to_enum(__method__) {@size} unless block_given?
+
+      each_value = Enumerator.new(@size) do |yielder|
+        offset = element_size * @offset
+        @values_buffer.each(@type.buffer_type, offset, @size) do |_, value|
+          yielder << value
+        end
+      end
+      if @validity_buffer.nil?
+        each_value.each(&block)
+      else
+        validity_bitmap.zip(each_value) do |is_valid, value|
+          if is_valid
+            yield(value)
+          else
+            yield(nil)
+          end
+        end
+      end
+    end
+
     def each_buffer
-      return to_enum(__method__) unless block_given?
+      return to_enum(__method__) {2} unless block_given?
 
       yield(slice_bitmap_buffer(:validity, @validity_buffer))
       yield(slice_fixed_element_size_buffer(:values,
                                             @values_buffer,
                                             element_size))
     end
 
+    def ==(other)
+      return false unless super(other)
+      if @offset == other.offset and @values_buffer == other.values_buffer
+        return true
+      end
+      zip(other).all? do |value, other_value|
+        value == other_value
+      end
+    end

Review Comment:
   `PrimitiveArray#==` currently uses `zip(other).all?`, which allocates an 
intermediate array of pairs for the whole array. You can keep the 
buffer-identity fast path, then delegate to `Array#==` (which will use the 
optimized `PrimitiveArray#each`) to avoid the allocation.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to