btllib
 All Classes Namespaces Functions Variables
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 
9 namespace btllib {
10 
12 class SeqReaderMultilineFastaModule
13 {
14 
15 private:
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 
36 template<typename ReaderType, typename RecordType>
37 inline bool
38 SeqReaderMultilineFastaModule::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 
86 template<typename ReaderType, typename RecordType>
87 inline bool
88 SeqReaderMultilineFastaModule::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  const auto ret = std::ungetc(p, reader.source);
95  check_error(ret == EOF, "SeqReaderMultilineFastaModule: ungetc failed.");
96  int c;
97  for (;;) {
98  switch (stage) {
99  case Stage::HEADER: {
100  reader.readline_file_append(record.header, reader.source);
101  stage = Stage::SEQ;
102  }
103  // fall through
104  case Stage::SEQ: {
105  reader.readline_file_append(record.seq, reader.source);
106  rtrim(record.seq);
107  stage = Stage::TRANSITION;
108  }
109  // fall through
110  case Stage::TRANSITION: {
111  c = std::fgetc(reader.source);
112  if (c == EOF) {
113  return false;
114  }
115  const auto ret = std::ungetc(c, reader.source);
116  check_error(ret == EOF,
117  "SeqReaderMultilineFastaModule: ungetc failed.");
118  if (c == '>') {
119  stage = Stage::HEADER;
120  return true;
121  }
122  stage = Stage::SEQ;
123  break;
124  }
125  default: {
126  log_error("SeqReader has entered an invalid state.");
127  std::exit(EXIT_FAILURE); // NOLINT(concurrency-mt-unsafe)
128  }
129  }
130  }
131  }
132  }
133  return false;
134 }
135 
136 template<typename ReaderType, typename RecordType>
137 inline bool
138 SeqReaderMultilineFastaModule::read_file(ReaderType& reader, RecordType& record)
139 {
140  if (!reader.file_at_end(reader.source)) {
141  reader.readline_file(record.header, reader.source);
142  int c;
143  reader.readline_file(record.seq, reader.source);
144  rtrim(record.seq);
145  for (;;) {
146  c = std::fgetc(reader.source);
147  if (c == EOF) {
148  return true;
149  }
150  const auto ret = std::ungetc(c, reader.source);
151  check_error(ret == EOF, "SeqReaderMultilineFastaModule: ungetc failed.");
152  if (c == '>') {
153  return true;
154  }
155  reader.readline_file_append(record.seq, reader.source);
156  rtrim(record.seq);
157  }
158  }
159  return false;
160 }
162 
163 } // namespace btllib
164 
165 #endif
void rtrim(std::string &s)
void check_error(bool condition, const std::string &msg)
void log_error(const std::string &msg)