File: writer.d

package info (click to toggle)
sambamba 1.0%2Bdfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 3,528 kB
  • sloc: sh: 220; python: 166; ruby: 147; makefile: 103
file content (116 lines) | stat: -rw-r--r-- 3,877 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
module bio.std.sff.writer;

import bio.std.sff.constants;
import bio.std.sff.utils.roundup;

import bio.core.utils.stream;
import contrib.undead.stream;
import std.system;

/// Class for outputting SFF files
class SffWriter {

    /// Create new writer.
    this(string filename, string flow_order, string key_sequence) 
    {
        _filename = filename;
        _flow_order = flow_order;
        _key_seq = key_sequence;

        auto f = new bio.core.utils.stream.File(filename, "wb+");
        auto stream = new BufferedStream(f, 1024576);
        _endian_stream = new EndianStream(stream, Endian.bigEndian);

        writeHeader();
    }

    /// Flow order
    string flow_order() @property const {
        return _flow_order;
    }

    /// Key sequence
    string key_sequence() @property const {
        return _key_seq;
    }

    /// Add a read to the end of file
    void append(R)(R sff_read) {
        // compute read_header_length
        ushort exact_read_header_length = cast(ushort)(16 + sff_read.name.length);
        ushort read_header_length = roundup(exact_read_header_length);

        _endian_stream.write(read_header_length);
        _endian_stream.write(cast(ushort)sff_read.name.length);
        _endian_stream.write(cast(uint)sff_read.bases.length);
        _endian_stream.write(sff_read.clip_qual_left);
        _endian_stream.write(sff_read.clip_qual_right);
        _endian_stream.write(sff_read.clip_adapter_left);
        _endian_stream.write(sff_read.clip_adapter_right);
        _endian_stream.writeExact(sff_read.name.ptr, sff_read.name.length);
        for (size_t i = 0; i < read_header_length - exact_read_header_length; ++i)
            _endian_stream.write(cast(ubyte)0);

        for (size_t i = 0; i < _flow_order.length; ++i)
            _endian_stream.write(sff_read.flowgram_values[i]);

        auto n_bases = sff_read.bases.length;
        _endian_stream.writeExact(sff_read.flow_index_per_base.ptr, n_bases);
        _endian_stream.writeExact(sff_read.bases.ptr, n_bases);
        _endian_stream.writeExact(sff_read.quality_scores.ptr, n_bases);

        auto k = 2 * _flow_order.length + 3 * n_bases;
        auto padding = roundup(k) - k;
        
        for (size_t i = 0; i < padding; ++i)
            _endian_stream.write(cast(ubyte)0);

        ++_n_reads;
    }

    /// Flush all buffers and update number of reads in the file header
    void finish() {
        updateNumberOfReads();
        _endian_stream.close();
    }

    private {
        string _filename;
        string _flow_order;
        string _key_seq;
        Stream _endian_stream;

        uint _n_reads;

        ushort _exact_header_len() @property const {
            return cast(ushort)(31 + _flow_order.length + _key_seq.length);
        }

        ushort _header_len() @property const {
            return roundup(_exact_header_len);
        }

        void writeHeader() {
            _endian_stream.write(SFF_MAGIC);
            _endian_stream.writeExact(SFF_VERSION.ptr, 4);
            _endian_stream.write(0UL);
            _endian_stream.write(0U);
            _endian_stream.write(_n_reads);
            _endian_stream.write(_header_len);
            _endian_stream.write(cast(ushort)_key_seq.length);
            _endian_stream.write(cast(ushort)_flow_order.length);
            _endian_stream.write(cast(ubyte)1);
            _endian_stream.writeExact(_flow_order.ptr, _flow_order.length);
            _endian_stream.writeExact(_key_seq.ptr, _key_seq.length);
            for (size_t i = 0; i < _header_len - _exact_header_len; ++i)
                _endian_stream.write(cast(ubyte)0);
        }

        void updateNumberOfReads() {
            auto old_pos = _endian_stream.position;
            _endian_stream.position = 20;
            _endian_stream.write(_n_reads);
            _endian_stream.position = old_pos;
        }
    }
}