mirror of
https://github.com/metabarcoding/obitools4.git
synced 2026-11-10 01:24:41 +00:00
Implement k-mer counting and sequence handling
Introduces the SeqKmerCounter structure for parallel k-mer counting, refactors sequence reading and writing logic, and adds comprehensive test coverage for various sequence scenarios.
This commit is contained in:
1 parent
e511650f5b
commit
3f0ca993d2
6 files changed
+684
-32
No files matched your search
+23
-22
@@ -16,8 +16,9 @@ import (
|
||||
// Nucleotide encoding: A=00, C=01, G=10, T=11.
|
||||
// The last byte is zero-padded on the low bits if len%4 != 0.
|
||||
type SkmWriter struct {
|
||||
w *bufio.Writer
|
||||
file *os.File
|
||||
w *bufio.Writer
|
||||
file *os.File
|
||||
scratch []byte
|
||||
}
|
||||
|
||||
// NewSkmWriter creates a new SkmWriter writing to the given file path.
|
||||
@@ -32,36 +33,36 @@ func NewSkmWriter(path string) (*SkmWriter, error) {
|
||||
}, nil
|
||||
}
|
||||
|
||||
// appendPacked appends seq to dst packed 2 bits per base (A=00, C=01, G=10,
|
||||
// T=11), four bases per byte, the last byte zero-padded on the low bits.
|
||||
func appendPacked(dst, seq []byte) []byte {
|
||||
for i := 0; i < len(seq); i += 4 {
|
||||
var packed byte
|
||||
for j := 0; j < 4; j++ {
|
||||
packed <<= 2
|
||||
if i+j < len(seq) {
|
||||
packed |= __single_base_code__[seq[i+j]&31]
|
||||
}
|
||||
}
|
||||
dst = append(dst, packed)
|
||||
}
|
||||
return dst
|
||||
}
|
||||
|
||||
// Write encodes a SuperKmer to the .skm file.
|
||||
// The sequence bytes are packed 2 bits per base.
|
||||
func (sw *SkmWriter) Write(sk SuperKmer) error {
|
||||
seq := sk.Sequence
|
||||
seqLen := uint16(len(seq))
|
||||
|
||||
// Write length
|
||||
var lenbuf [2]byte
|
||||
binary.LittleEndian.PutUint16(lenbuf[:], seqLen)
|
||||
binary.LittleEndian.PutUint16(lenbuf[:], uint16(len(sk.Sequence)))
|
||||
if _, err := sw.w.Write(lenbuf[:]); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Encode and write packed sequence (2 bits/base)
|
||||
nBytes := (int(seqLen) + 3) / 4
|
||||
for i := 0; i < nBytes; i++ {
|
||||
var packed byte
|
||||
for j := 0; j < 4; j++ {
|
||||
pos := i*4 + j
|
||||
packed <<= 2
|
||||
if pos < int(seqLen) {
|
||||
packed |= __single_base_code__[seq[pos]&31]
|
||||
}
|
||||
}
|
||||
if err := sw.w.WriteByte(packed); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
sw.scratch = appendPacked(sw.scratch[:0], sk.Sequence)
|
||||
_, err := sw.w.Write(sw.scratch)
|
||||
return err
|
||||
}
|
||||
|
||||
// Close flushes buffered data and closes the underlying file.
|
||||
|
||||
Reference in new issue
Block a user