btllib
seq_reader_multiline_fasta_module.hpp
1#ifndef BTLLIB_SEQ_READER_MULTILINE_FASTA_MODULE_HPP
2#define BTLLIB_SEQ_READER_MULTILINE_FASTA_MODULE_HPP
3
4#include "btllib/cstring.hpp"
5#include "btllib/status.hpp"
6
7#include <cstdlib>
8
9namespace btllib {
10
12class SeqReaderMultilineFastaModule
13{
14
15private:
16 friend class SeqReader;
17
18 enum class Stage
19 {
20 HEADER,
21 SEQ,
22 TRANSITION,
23 };
24
25 Stage stage = Stage::HEADER;
26
27 static bool buffer_valid(const char* buffer, size_t size);
28 template<typename ReaderType, typename RecordType>
29 bool read_buffer(ReaderType& reader, RecordType& record);
30 template<typename ReaderType, typename RecordType>
31 bool read_transition(ReaderType& reader, RecordType& record);
32 template<typename ReaderType, typename RecordType>
33 bool read_file(ReaderType& reader, RecordType& record);
34};
35
36template<typename ReaderType, typename RecordType>
37inline bool
38SeqReaderMultilineFastaModule::read_buffer(ReaderType& reader,
39 RecordType& record)
40{
41 record.header.clear();
42 record.seq.clear();
43 record.qual.clear();
44 if (reader.buffer.start < reader.buffer.end) {
45 int c;
46 for (;;) {
47 switch (stage) {
48 case Stage::HEADER: {
49 if (!reader.readline_buffer_append(record.header)) {
50 return false;
51 }
52 stage = Stage::SEQ;
53 }
54 // fall through
55 case Stage::SEQ: {
56 if (!reader.readline_buffer_append(record.seq)) {
57 return false;
58 }
59 rtrim(record.seq);
60 stage = Stage::TRANSITION;
61 }
62 // fall through
63 case Stage::TRANSITION: {
64 c = reader.getc_buffer();
65 if (c == EOF) {
66 return false;
67 }
68 reader.ungetc_buffer(c);
69 if (c == '>') {
70 stage = Stage::HEADER;
71 return true;
72 }
73 stage = Stage::SEQ;
74 break;
75 }
76 default: {
77 log_error("SeqReader has entered an invalid state.");
78 std::exit(EXIT_FAILURE); // NOLINT(concurrency-mt-unsafe)
79 }
80 }
81 }
82 }
83 return false;
84}
85
86template<typename ReaderType, typename RecordType>
87inline bool
88SeqReaderMultilineFastaModule::read_transition(ReaderType& reader,
89 RecordType& record)
90{
91 if (std::ferror(reader.source) == 0 && std::feof(reader.source) == 0) {
92 const auto p = std::fgetc(reader.source);
93 if (p != EOF) {
94 std::ungetc(p, reader.source);
95 int c;
96 for (;;) {
97 switch (stage) {
98 case Stage::HEADER: {
99 reader.readline_file_append(record.header, reader.source);
100 stage = Stage::SEQ;
101 }
102 // fall through
103 case Stage::SEQ: {
104 reader.readline_file_append(record.seq, reader.source);
105 rtrim(record.seq);
106 stage = Stage::TRANSITION;
107 }
108 // fall through
109 case Stage::TRANSITION: {
110 c = std::fgetc(reader.source);
111 if (c == EOF) {
112 return false;
113 }
114 std::ungetc(c, reader.source);
115 if (c == '>') {
116 stage = Stage::HEADER;
117 return true;
118 }
119 stage = Stage::SEQ;
120 break;
121 }
122 default: {
123 log_error("SeqReader has entered an invalid state.");
124 std::exit(EXIT_FAILURE); // NOLINT(concurrency-mt-unsafe)
125 }
126 }
127 }
128 }
129 }
130 return false;
131}
132
133template<typename ReaderType, typename RecordType>
134inline bool
135SeqReaderMultilineFastaModule::read_file(ReaderType& reader, RecordType& record)
136{
137 if (!reader.file_at_end(reader.source)) {
138 reader.readline_file(record.header, reader.source);
139 int c;
140 reader.readline_file(record.seq, reader.source);
141 rtrim(record.seq);
142 for (;;) {
143 c = std::fgetc(reader.source);
144 if (c == EOF) {
145 return true;
146 }
147 std::ungetc(c, reader.source);
148 if (c == '>') {
149 return true;
150 }
151 reader.readline_file_append(record.seq, reader.source);
152 rtrim(record.seq);
153 }
154 }
155 return false;
156}
158
159} // namespace btllib
160
161#endif
Definition: bloom_filter.hpp:16
void rtrim(std::string &s)
void log_error(const std::string &msg)