From 1342c83db610a5baf4d24d9f17530fad97d22822 Mon Sep 17 00:00:00 2001 From: Eric Coissac Date: Tue, 10 Mar 2026 15:51:28 +0100 Subject: [PATCH] Use NewBioSequenceOwning to avoid unnecessary sequence copying Replace NewBioSequence with NewBioSequenceOwning in genbank_read.go to take ownership of sequence slices without copying, improving performance. Update biosequence.go to add the new TakeSequence method and NewBioSequenceOwning constructor. --- pkg/obiformats/genbank_read.go | 4 ++-- pkg/obiseq/biosequence.go | 19 +++++++++++++++++++ 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/pkg/obiformats/genbank_read.go b/pkg/obiformats/genbank_read.go index 839134e..53a3057 100644 --- a/pkg/obiformats/genbank_read.go +++ b/pkg/obiformats/genbank_read.go @@ -287,7 +287,7 @@ func GenbankChunkParserRope(source string, rope *PieceOfChunk, if id == "" { log.Warn("Empty id when parsing genbank file") } - sequence := obiseq.NewBioSequence(id, seqDest, defBytes.String()) + sequence := obiseq.NewBioSequenceOwning(id, seqDest, defBytes.String()) sequence.SetSource(source) if withFeatureTable { sequence.SetFeatures(featBytes.Bytes()) @@ -320,7 +320,7 @@ func GenbankChunkParserRope(source string, rope *PieceOfChunk, if id == "" { log.Warn("Empty id when parsing genbank file") } - sequence := obiseq.NewBioSequence(id, seqDest, defBytes.String()) + sequence := obiseq.NewBioSequenceOwning(id, seqDest, defBytes.String()) sequence.SetSource(source) if withFeatureTable { sequence.SetFeatures(featBytes.Bytes()) diff --git a/pkg/obiseq/biosequence.go b/pkg/obiseq/biosequence.go index 628f52c..f3939d8 100644 --- a/pkg/obiseq/biosequence.go +++ b/pkg/obiseq/biosequence.go @@ -120,6 +120,19 @@ func NewBioSequence(id string, return bs } +// NewBioSequenceOwning creates a BioSequence taking ownership of the sequence +// slice without copying it. The caller must not use the slice after this call. +// Use this when the slice was allocated specifically for this sequence. +func NewBioSequenceOwning(id string, + sequence []byte, + definition string) *BioSequence { + bs := NewEmptyBioSequence(0) + bs.SetId(id) + bs.TakeSequence(sequence) + bs.SetDefinition(definition) + return bs +} + // NewBioSequenceWithQualities creates a new BioSequence object with the given id, sequence, definition, and qualities. // // Parameters: @@ -444,6 +457,12 @@ func (s *BioSequence) SetSequence(sequence []byte) { s.sequence = obiutils.InPlaceToLower(CopySlice(sequence)) } +// TakeSequence stores the slice directly without copying, then lowercases in-place. +// The caller must not use the slice after this call. +func (s *BioSequence) TakeSequence(sequence []byte) { + s.sequence = obiutils.InPlaceToLower(sequence) +} + func (s *BioSequence) HasValidSequence() bool { for _, c := range s.sequence { if !((c >= 'a' && c <= 'z') || c == '-' || c == '.' || c == '[' || c == ']') {