Skip to content

Commit

Permalink
Merge branch 'hotfix/iteration'
Browse files Browse the repository at this point in the history
  • Loading branch information
CiaranOMara committed Apr 17, 2020
2 parents 0e0908f + b440bc3 commit 060349b
Show file tree
Hide file tree
Showing 7 changed files with 113 additions and 8 deletions.
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name = "XAM"
uuid = "d759349c-bcba-11e9-07c2-5b90f8f05f7c"
authors = ["Kenta Sato <[email protected]>", "Ben J. Ward <[email protected]>", "Ciarán O'Mara <[email protected]>"]
version = "0.2.2"
version = "0.2.3"

[deps]
Automa = "67c07d97-cdcb-5c2c-af73-a7f9c32a568b"
Expand Down
1 change: 1 addition & 0 deletions docs/src/man/hts-files.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ In-place reading reuses a pre-allocated object for every record and less memory
reader = open(BAM.Reader, "data.bam")
record = BAM.Record()
while !eof(reader)
empty!(record)
read!(reader, record)
# do something
end
Expand Down
7 changes: 3 additions & 4 deletions src/bam/reader.jl
Original file line number Diff line number Diff line change
Expand Up @@ -72,12 +72,11 @@ function Base.seekstart(reader::Reader)
seek(reader.stream, reader.start_offset)
end

function Base.iterate(reader::Reader, rec=Record())
if eof(reader)
function Base.iterate(reader::Reader, nextone = Record())
if BioGenerics.IO.tryread!(reader, nextone) === nothing
return nothing
end
read!(reader, rec)
return copy(rec), rec
return copy(nextone), empty!(nextone)
end

# Initialize a BAM reader by reading the header section.
Expand Down
29 changes: 29 additions & 0 deletions src/bam/record.jl
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,19 @@ function Base.convert(::Type{Record}, data::Vector{UInt8})
return record
end

function Base.:(==)(a::Record, b::Record)
return a.block_size == b.block_size &&
a.refid == b.refid &&
a.pos == b.pos &&
a.bin_mq_nl == b.bin_mq_nl &&
a.flag_nc == b.flag_nc &&
a.l_seq == b.l_seq &&
a.next_refid == b.next_refid &&
a.next_pos == b.next_pos &&
a.tlen == b.tlen &&
a.data[1:data_size(a)] == b.data[1:data_size(b)]
end

function Base.copy(record::Record)
copy = Record()
copy.block_size = record.block_size
Expand All @@ -63,6 +76,22 @@ function Base.copy(record::Record)
return copy
end

function Base.empty!(record::Record)
record.block_size = 0
record.refid = 0
record.pos = 0
record.bin_mq_nl = 0
record.flag_nc = 0
record.l_seq = 0
record.next_refid = 0
record.next_pos = 0
record.tlen = 0

#Note: data will be overwritten and indexed using data_size.

return record
end

function Base.show(io::IO, record::Record)
print(io, summary(record), ':')
if isfilled(record)
Expand Down
15 changes: 13 additions & 2 deletions src/sam/reader.jl
Original file line number Diff line number Diff line change
Expand Up @@ -81,9 +81,20 @@ function index!(record::Record)
return record
end

function Base.read!(rdr::Reader, rec::Record)
function Base.iterate(reader::Reader, nextone::Record = Record())
if BioGenerics.IO.tryread!(reader, nextone) === nothing
return nothing
end
return copy(nextone), empty!(nextone)
end

empty!(rec.fields) #Note: data is pushed to the fields field, and other field data is overwritten. #TODO: distinguish for inplace reading pattern.
"""
read!(rdr::Reader, rec::Record)
Read a `Record` into `rec`; overwriting or adding to existing field values.
It is assumed that `rec` is already initialized or empty.
"""
function Base.read!(rdr::Reader, rec::Record)

cs, ln, f = readrecord!(rdr.state.stream, rec, (rdr.state.state, rdr.state.linenum))

Expand Down
23 changes: 22 additions & 1 deletion src/sam/record.jl
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,23 @@ function Base.convert(::Type{Record}, str::AbstractString)
return Record(Vector{UInt8}(str))
end

function Base.:(==)(a::Record, b::Record)
return a.filled == b.filled &&
a.qname == b.qname &&
a.flag == b.flag &&
a.rname == b.rname &&
a.pos == b.pos &&
a.mapq == b.mapq &&
a.cigar == b.cigar &&
a.rnext == b.rnext &&
a.pnext == b.pnext &&
a.tlen == b.tlen &&
a.seq == b.seq &&
a.qual == b.qual &&
a.fields == b.fields &&
a.data[a.filled] == b.data[b.filled]
end

function Base.show(io::IO, record::Record)
print(io, summary(record), ':')
if isfilled(record)
Expand Down Expand Up @@ -554,7 +571,7 @@ end
# Helper Functions
# ----------------

function initialize!(record::Record)
function Base.empty!(record::Record)
record.filled = 1:0
record.qname = 1:0
record.flag = 1:0
Expand All @@ -571,6 +588,10 @@ function initialize!(record::Record)
return record
end

function initialize!(record::Record) #TODO: deprecate.
return empty!(record)
end

function checkfilled(record::Record)
if !isfilled(record)
throw(ArgumentError("unfilled SAM record"))
Expand Down
44 changes: 44 additions & 0 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,29 @@ end
end
end
end

@testset "In-Place-Reading Pattern" begin

file_sam = joinpath(samdir, "ce#5b.sam")

records = open(collect, SAM.Reader, file_sam)

reader = open(SAM.Reader, file_sam)
record = SAM.Record()
i = 0
while !eof(reader)
empty!(record) # Reset the record.
read!(reader, record)

i = i + 1

@test records[i] == record

end

close(reader)

end
end

@testset "BAM" begin
Expand Down Expand Up @@ -414,6 +437,27 @@ end
end
end

@testset "In-Place-Reading Pattern" begin

file_bam = joinpath(bamdir, "ce#5b.bam")

records = open(collect, BAM.Reader, file_bam)

reader = open(BAM.Reader, file_bam)
record = BAM.Record()
i = 0
while !eof(reader)
empty!(record) # Reset the record.
read!(reader, record)

i = i + 1
@test records[i] == record
end

close(reader)

end

@testset "Random access" begin
filepath = joinpath(bamdir, "GSE25840_GSM424320_GM06985_gencode_spliced.head.bam")
reader = open(BAM.Reader, filepath, index=filepath * ".bai")
Expand Down

2 comments on commit 060349b

@CiaranOMara
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@BioJuliaBot register

@BioJuliaBot
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Registration pull request created: BioJulia/BioJuliaRegistry/67

After the above pull request is merged, it is recommended that a tag is created on this repository for the registered package version.

This will be done automatically if Julia TagBot is installed, or can be done manually through the github interface, or via:

git tag -a v0.2.3 -m "<description of version>" 060349bd2be1320d360d5892802513696324736a
git push origin v0.2.3

Please sign in to comment.