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


##########
ruby/red-arrow-format/lib/arrow-format/array.rb:
##########
@@ -64,18 +66,28 @@ def empty?
       @size.zero?
     end
 
+    def ==(other)
+      return false unless other.is_a?(self.class)
+      return false unless @size == other.size
+      return true if @validity_buffer.nil? and other.validity_buffer.nil?
+      if @offset == other.offset and @validity_buffer == other.validity_buffer

Review Comment:
   `ArrowFormat::Array#==` currently only compares the validity buffer/bitmap 
(and even returns true when both validity buffers are nil), so for 
non-PrimitiveArray subclasses (e.g. VariableSizeBinaryArray, StructArray, etc.) 
two arrays with different values but the same null layout can be considered 
equal. Also, `ArrowFormat::Array` now includes `Enumerable` but doesn’t define 
`#each`, so calling `each`/`map` on those subclasses will raise `NoMethodError` 
unless they override `each`.



##########
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#==` uses `zip(other).all?`, which materializes an 
intermediate array of pairs (potentially huge) before checking `all?`. If 
`Array#==` is updated to compare element values, the current `super(other)` 
call would also end up doing redundant work; this method can do its own 
type/size check and then compare elements in a streaming way.



##########
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

Review Comment:
   `Bitmap#==` uses `zip(other).all?`, which allocates an intermediate array of 
pairs proportional to the bitmap length. This can cause significant memory 
usage for large bitmaps; compare in a streaming loop instead.



-- 
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