@@ -129,25 +129,43 @@ def each
129129 pos_ptr = FFI ::MemoryPointer . new ( :long_long ) # hts_pos_t
130130 n_ptr = FFI ::MemoryPointer . new ( :int )
131131
132+ # Micro-optimizations:
133+ # - Compute constant struct size once
134+ # - Hoist header reference outside the loop
135+ plp1_size = HTS ::LibHTS ::BamPileup1 . size
136+ header_local = @header
137+
132138 begin
133- while ( base_ptr = HTS ::LibHTS . bam_plp64_auto ( @plp , tid_ptr , pos_ptr , n_ptr ) ) && !base_ptr . null?
139+ loop do
140+ base_ptr = HTS ::LibHTS . bam_plp64_auto ( @plp , tid_ptr , pos_ptr , n_ptr )
141+
142+ # When base_ptr is NULL, check n to distinguish EOF (n == 0) from error (n < 0)
143+ if base_ptr . null?
144+ n = n_ptr . read_int
145+ raise "HTSlib pileup error (bam_plp64_auto)" if n < 0
146+
147+ break
148+ end
149+
134150 tid = tid_ptr . read_int
135151 pos = pos_ptr . read_long_long
136152 n = n_ptr . read_int
137153
138- # Construct alignment entries
139- alignments = if n . zero?
140- [ ]
141- else
142- size = HTS ::LibHTS ::BamPileup1 . size
143- n . times . map do |i |
144- e_ptr = base_ptr + ( i * size )
145- entry = HTS ::LibHTS ::BamPileup1 . new ( e_ptr )
146- PileupRecord . new ( entry , @header )
147- end
148- end
149-
150- yield PileupColumn . new ( tid :, pos :, alignments :)
154+ # Construct alignment entries with minimal allocations
155+ if n . zero?
156+ alignments = [ ]
157+ else
158+ alignments = Array . new ( n )
159+ i = 0
160+ while i < n
161+ e_ptr = base_ptr + ( i * plp1_size )
162+ entry = HTS ::LibHTS ::BamPileup1 . new ( e_ptr )
163+ alignments [ i ] = PileupRecord . new ( entry , header_local )
164+ i += 1
165+ end
166+ end
167+
168+ yield PileupColumn . new ( tid : tid , pos : pos , alignments : alignments )
151169 end
152170 ensure
153171 close
0 commit comments