3#include <cuda/std/cstdint>
45 for (uint32_t base = 0; base < k; ++base) {
46 result = (result << 2U) | static_cast<uint64_t>(
static_cast<uint8_t
>(
packed & 3U) ^ 2U);
52 x = ((x & 0xCCCCCCCCCCCCCCCCULL) >> 2U) | ((x & 0x3333333333333333ULL) << 2U);
53 x = ((x & 0xF0F0F0F0F0F0F0F0ULL) >> 4U) | ((x & 0x0F0F0F0F0F0F0F0FULL) << 4U);
54 x = ((x & 0xFF00FF00FF00FF00ULL) >> 8U) | ((x & 0x00FF00FF00FF00FFULL) << 8U);
55 x = ((x & 0xFFFF0000FFFF0000ULL) >> 16U) | ((x & 0x0000FFFF0000FFFFULL) << 16U);
56 x = (x >> 32U) | (x << 32U);
58 auto const mask = (k == 32) ? ~uint64_t{0} : ((1ULL << (2U * k)) - 1ULL);
59 return (x ^ 0xAAAAAAAAAAAAAAAAULL) & mask;
76inline bool span_step_back(
77 std::vector<fastx_sequence_extent>
const& extents,
81 if (position > extents[extent].begin) {
87 position = extents[extent].end - 1;
93inline bool span_step_forward(
94 std::vector<fastx_sequence_extent>
const& extents,
98 if (position + 1 < extents[extent].end) {
102 if (extent + 1 < extents.size()) {
104 position = extents[extent].begin;
123 std::vector<fastx_sequence_extent>
const& extents,
127 std::vector<fastx_sequence_span> spans;
128 if (extents.empty() ||
count == 0U) {
132 for (
auto const& extent : extents) {
133 total +=
static_cast<size_t>(extent.end - extent.begin);
142 spans.reserve(
count);
144 for (uint32_t t = 0; t <
count; ++t) {
145 auto const span_begin =
static_cast<size_t>(t) * per;
146 if (span_begin >=
total) {
149 auto const span_end = span_begin + per <
total ? span_begin + per :
total;
156 size_t offset = span_begin;
157 while (extent < extents.size() &&
158 offset >=
static_cast<size_t>(extents[extent].end - extents[extent].begin)) {
159 offset -=
static_cast<size_t>(extents[extent].end - extents[extent].begin);
164 size_t seed_extent = extent;
165 char const* seed_start = extents[extent].begin + offset;
168 char const* q = seed_start;
169 uint32_t collected = 0;
170 while (collected < seed_bases && span_step_back(extents, e, q)) {
178 span_step_forward(extents, seed_extent, seed_start);
189 size_t e = seed_extent;
190 char const* q = seed_start;
191 char const* target = extents[extent].begin + offset;
192 while (e < extent || q < target) {
193 if (q >= extents[e].end) {
195 q = extents[e].begin;
198 span.
prefix.push_back(*q);
205 size_t remaining = span_end - span_begin;
206 char const* q = extents[extent].begin + offset;
208 while (remaining > 0 && e < extents.size()) {
209 auto const limit =
static_cast<size_t>(extents[e].end - q);
210 auto const step = limit < remaining ? limit : remaining;
211 span.
segments.emplace_back(q, step);
215 if (e < extents.size()) {
216 q = extents[e].begin;
222 spans.push_back(std::move(span));
248 if (encoded == 0xffu) {
249 if (window_len < k && window_len > 0) {
257 window = ((window << 2U) | encoded) & mask;
258 if (window_len < k) {
261 if (window_len == k) {
263 result.
kmers.push_back(window > rev ? window : rev);
289 std::string
const& path,
291 unsigned threads = std::thread::hardware_concurrency()
294 auto& extents = source->extents;
300 static constexpr char record_boundary =
'N';
301 if (extents.size() > 1) {
302 std::vector<fastx_sequence_extent> separated;
303 separated.reserve(extents.size() * 2 - 1);
304 for (
auto const& extent : extents) {
305 if (!separated.empty()) separated.push_back({&record_boundary, &record_boundary + 1});
306 separated.push_back(extent);
308 extents = std::move(separated);
312 for (
auto const& extent : extents) {
313 total +=
static_cast<uint64_t
>(extent.end - extent.begin);
316 unsigned worker_count = 1;
317 if (
total >= (uint64_t{1} << 20)) {
318 auto const available = threads > 0 ? threads : 1U;
319 worker_count = available > 0 ? available : 1U;
324 auto const mask = (k >= 32) ? ~uint64_t{0} : ((1ULL << (2U * k)) - 1ULL);
325 std::vector<span_result> partials(spans.size());
326 auto const per_thread =
total / spans.size() + (
total % spans.size() != 0U);
327 for (
auto& partial : partials) {
328 partial.kmers.reserve(per_thread / 2U + 64U);
331 std::vector<std::thread> workers;
332 workers.reserve(spans.size());
333 for (
size_t t = 0; t < spans.size(); ++t) {
334 workers.emplace_back([&, t] {
336 uint32_t window_len = 0;
338 for (
char ch : spans[t].prefix) {
341 for (
auto const& segment : spans[t].segments) {
342 if (segment.data() == &record_boundary) {
347 for (
char ch : segment) {
348 consume_byte(ch, k, mask, partials[t], window, window_len);
353 for (
auto& worker : workers) {
358 uint64_t total_valid = 0;
359 for (
auto const& partial : partials) {
360 result.
bases += partial.bases;
361 total_valid += partial.valid_kmers;
362 result.invalid_windows += partial.invalid_windows;
364 result.valid_kmers = total_valid;
368 result.kmers.reserve(total_valid);
369 for (
auto& partial : partials) {
372 std::make_move_iterator(partial.kmers.begin()),
373 std::make_move_iterator(partial.kmers.end())
375 partial.kmers = std::vector<uint64_t>{};
#define CUDDL_TRY(expr)
Propagates a cuddl::Result failure from the enclosing function (GNU statement expression).
Result< fasta_parse_result > parse_fasta(std::string const &path, uint32_t k, unsigned threads=std::thread::hardware_concurrency())
Parses a FASTA/FASTQ file's sequence bases into packed canonical k-mers of length k.
constexpr uint64_t reverse_complement(uint64_t packed, uint32_t k) noexcept
Reverse-complements a packed k-mer (2 bits per base) with bit-parallel reversal.
constexpr bool fastx_is_sequence_whitespace(char ch) noexcept
True for bytes that FASTA sequence consumers conventionally skip between bases.
__global__ uint32_t const uint32_t const uint32_t const uint32_t uint32_t size_t size_t uint32_t SearchResult * packed
Result< std::unique_ptr< fastx_sequence_file > > load_fastx_sequence_file(std::string const &path, decompression_source source={}, bool defer_fasta=false, bool read=false, uint32_t pack_k=0)
void consume_byte(char ch, uint32_t k, uint64_t mask, span_result &result, uint64_t &window, uint32_t &window_len)
Feeds one byte of sequence through the DDL rolling-window extraction.
constexpr uint8_t encode_base(char base) noexcept
Maps one DNA byte to its 2-bit symbol (A=0, C=1, T=2, G=3) or 0xff when invalid.
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.
detail::fasta_parse_result fasta_parse_result
Result of parsing one FASTA/FASTQ file into packed canonical k-mers.
Fallible API result: cuda::std::expected<T, Error> with cuDDL factories.
Result of parsing one FASTA/FASTQ file into packed canonical k-mers.
std::vector< uint64_t > kmers
Packed canonical k-mers from all records, treated as one combined genome.
uint64_t bases
Total valid sequence bases read.
uint64_t invalid_windows
Number of partial windows broken by an invalid base before reaching length k.
uint64_t valid_kmers
Number of k-mers emitted (one per rolling window of k valid bases).
One parallel scan span of the combined FASTA sequence stream.
std::vector< std::string_view > segments
One worker's rolling-window state and output.
std::vector< uint64_t > kmers