cuSBF
Loading...
Searching...
No Matches
fastx_sequence_scan.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <cstdint>
4#include <string>
5#include <string_view>
6#include <utility>
7#include <vector>
8
9#include <cusbf/Alphabet.cuh>
11
12namespace cusbf::detail {
13
16 const char* begin;
17 const char* end;
18};
19
21[[nodiscard]] inline constexpr bool fastx_is_sequence_whitespace(char ch) noexcept {
22 return ch == '\n' || ch == '\r' || ch == ' ' || ch == '\t';
23}
24
33[[nodiscard]] inline std::vector<fastx_sequence_extent> fastx_fasta_extents(std::string_view data) {
34 std::vector<fastx_sequence_extent> extents;
35 size_t sequence = std::string_view::npos;
36 size_t header = data.find('>');
37 while (header != std::string_view::npos) {
38 if (header != 0 && data[header - 1] != '\n' && data[header - 1] != '\r') {
39 header = data.find('>', header + 1);
40 continue;
41 }
42 if (sequence != std::string_view::npos && header > sequence) {
43 extents.push_back({data.data() + sequence, data.data() + header});
44 }
45 auto const end = fastx_line_end(data, header);
46 sequence = end < data.size() ? end + 1 : data.size();
47 header = data.find('>', sequence);
48 }
49 if (sequence != std::string_view::npos && sequence < data.size()) {
50 extents.push_back({data.data() + sequence, data.data() + data.size()});
51 }
52 return extents;
53}
54
64 std::string prefix;
65 std::vector<std::string_view> segments;
67};
68
69namespace {
70
71inline bool scan_step_back(
72 std::vector<fastx_sequence_extent> const& extents, size_t& extent, const char*& position
73) {
74 if (position > extents[extent].begin) {
75 --position;
76 return true;
77 }
78 if (extent > 0) {
79 --extent;
80 position = extents[extent].end - 1;
81 return true;
82 }
83 return false;
84}
85
86inline bool scan_step_forward(
87 std::vector<fastx_sequence_extent> const& extents, size_t& extent, const char*& position
88) {
89 if (position + 1 < extents[extent].end) {
90 ++position;
91 return true;
92 }
93 if (extent + 1 < extents.size()) {
94 ++extent;
95 position = extents[extent].begin;
96 return true;
97 }
98 return false;
99}
100
101} // namespace
102
113[[nodiscard]] inline std::vector<fastx_sequence_span> fastx_split_sequence_spans(
114 std::vector<fastx_sequence_extent> const& extents, uint32_t seed_bases, uint32_t count
115) {
116 std::vector<fastx_sequence_span> spans;
117 if (extents.empty() || count == 0U) {
118 return spans;
119 }
120 size_t total = 0;
121 for (auto const& extent : extents) {
122 total += static_cast<size_t>(extent.end - extent.begin);
123 }
124 if (total == 0) {
125 return spans;
126 }
127 if (static_cast<size_t>(count) > total) {
128 count = static_cast<uint32_t>(total);
129 }
130 auto const per = total / count + (total % count != 0U);
131 spans.reserve(count);
132
133 for (uint32_t t = 0; t < count; ++t) {
134 auto const span_begin = static_cast<size_t>(t) * per;
135 if (span_begin >= total) {
136 break;
137 }
138 auto const span_end = span_begin + per < total ? span_begin + per : total;
139
142
143 // Locate the extent and offset of the span start.
144 size_t extent = 0;
145 size_t offset = span_begin;
146 while (extent < extents.size() &&
147 offset >= static_cast<size_t>(extents[extent].end - extents[extent].begin)) {
148 offset -= static_cast<size_t>(extents[extent].end - extents[extent].begin);
149 ++extent;
150 }
151
152 // Seed: walk back up to seed_bases valid bases (or until an invalid base / EOF).
153 size_t seed_extent = extent;
154 const char* seed_start = extents[extent].begin + offset;
155 {
156 size_t e = extent;
157 const char* q = seed_start;
159 while (collected < seed_bases && scan_step_back(extents, e, q)) {
160 auto const ch = *q;
162 continue;
163 }
165 seed_extent = e;
166 seed_start = q;
168 break;
169 }
170 ++collected;
171 seed_extent = e;
172 seed_start = q;
173 }
174 }
175
176 // Materialise the prefix from the seed start to the span start.
177 {
178 size_t e = seed_extent;
179 const char* q = seed_start;
180 const char* target = extents[extent].begin + offset;
181 while (e < extent || q < target) {
182 if (q >= extents[e].end) {
183 ++e;
184 q = extents[e].begin;
185 continue;
186 }
187 span.prefix.push_back(*q);
188 ++q;
189 }
190 }
191
192 // Collect the span's segments.
193 {
194 size_t remaining = span_end - span_begin;
195 const char* q = extents[extent].begin + offset;
196 size_t e = extent;
197 while (remaining > 0 && e < extents.size()) {
198 auto const limit = static_cast<size_t>(extents[e].end - q);
199 auto const step = limit < remaining ? limit : remaining;
200 span.segments.emplace_back(q, step);
201 remaining -= step;
202 if (remaining > 0) {
203 ++e;
204 if (e < extents.size()) {
205 q = extents[e].begin;
206 }
207 }
208 }
209 }
210
211 spans.push_back(std::move(span));
212 }
213 return spans;
214}
215
216} // namespace cusbf::detail
constexpr bool fastx_is_sequence_whitespace(char ch) noexcept
True for bytes that FASTA sequence consumers conventionally skip between bases.
size_t fastx_line_end(std::string_view data, size_t position)
consteval bool separatorPositionAlwaysEncodesInvalid(char *input, uint64_t separatorPosition, uint64_t index)
Recursively tests whether placing the separator byte at any position in an input of valid bytes alway...
Definition Alphabet.cuh:37
std::vector< fastx_sequence_span > fastx_split_sequence_spans(std::vector< fastx_sequence_extent > const &extents, uint32_t seed_bases, uint32_t count)
Splits the combined FASTA sequence stream into count contiguous spans.
std::vector< fastx_sequence_extent > fastx_fasta_extents(std::string_view data)
Collects the sequence extents of every FASTA record in data.
constexpr __host__ __device__ static __forceinline__ uint8_t encode(const char *input)
Maps one byte to a 2-bit symbol index, or invalidSymbol.
Definition Alphabet.cuh:132
static constexpr uint8_t invalidSymbol
Sentinel returned by encode for invalid input bytes.
Definition Alphabet.cuh:119
A contiguous run of sequence bytes (record header lines excluded).
One parallel scan span of the combined FASTA sequence stream.
std::vector< std::string_view > segments