btllib
Loading...
Searching...
No Matches
indexlr.hpp
1#ifndef BTLLIB_INDEXLR_HPP
2#define BTLLIB_INDEXLR_HPP
3
4#include "btllib/bloom_filter.hpp"
5#include "btllib/nthash.hpp"
6#include "btllib/order_queue.hpp"
7#include "btllib/seq_reader.hpp"
8#include "btllib/status.hpp"
9#include "btllib/util.hpp"
10
11#include <algorithm>
12#include <atomic>
13#include <cstdlib>
14#include <cstring>
15#include <functional>
16#include <iostream>
17#include <limits>
18#include <memory>
19#include <string>
20#include <thread>
21#include <vector>
22
23namespace btllib {
24
26{
27
28public:
29 /* Has to be a struct and not an enum because:
30 * 1) Non-class enums are not name qualified and can collide
31 * 2) class enums can't be implicitly converted into integers
32 */
33 struct Flag
34 {
36 static const unsigned NO_ID = 1;
38 static const unsigned BX = 2;
40 static const unsigned SEQ = 4;
43 static const unsigned FILTER_IN = 8;
48 static const unsigned FILTER_OUT = 16;
50 static const unsigned SHORT_MODE = 32;
52 static const unsigned LONG_MODE = 64;
54 static const unsigned QUAL = 128;
55 };
56
57 bool output_id() const { return bool(~flags & Flag::NO_ID); }
58 bool output_bx() const { return bool(flags & Flag::BX); }
59 bool output_seq() const { return bool(flags & Flag::SEQ); }
60 bool output_qual() const { return bool(flags & Flag::QUAL); }
61 bool filter_in() const { return bool(flags & Flag::FILTER_IN); }
62 bool filter_out() const { return bool(flags & Flag::FILTER_OUT); }
63 bool short_mode() const { return bool(flags & Flag::SHORT_MODE); }
64 bool long_mode() const { return bool(flags & Flag::LONG_MODE); }
65
66 struct Minimizer
67 {
68 Minimizer() = default;
69
70 Minimizer(uint64_t min_hash,
71 uint64_t out_hash,
72 size_t pos,
73 bool forward,
74 std::string seq)
75 : min_hash(min_hash)
76 , out_hash(out_hash)
77 , pos(pos)
78 , forward(forward)
79 , seq(std::move(seq))
80 {
81 }
82
83 Minimizer(uint64_t min_hash,
84 uint64_t out_hash,
85 size_t pos,
86 bool forward,
87 std::string seq,
88 std::string qual)
89 : min_hash(min_hash)
90 , out_hash(out_hash)
91 , pos(pos)
92 , forward(forward)
93 , seq(std::move(seq))
94 , qual(std::move(qual))
95 {
96 }
97 Minimizer(uint64_t min_hash,
98 uint64_t out_hash,
99 size_t pos,
100 bool forward,
101 std::string seq,
102 std::vector<uint64_t> all_hashes)
103 : min_hash(min_hash)
104 , out_hash(out_hash)
105 , pos(pos)
106 , forward(forward)
107 , seq(std::move(seq))
108 , all_hashes(std::move(all_hashes))
109 {
110 }
111
112 Minimizer(uint64_t min_hash,
113 uint64_t out_hash,
114 size_t pos,
115 bool forward,
116 std::string seq,
117 std::string qual,
118 std::vector<uint64_t> all_hashes)
119 : min_hash(min_hash)
120 , out_hash(out_hash)
121 , pos(pos)
122 , forward(forward)
123 , seq(std::move(seq))
124 , qual(std::move(qual))
125 , all_hashes(std::move(all_hashes))
126 {
127 }
128
129 uint64_t min_hash = 0, out_hash = 0;
130 size_t pos = 0;
131 bool forward = false;
132 std::string seq;
133 std::string qual;
134 std::vector<uint64_t> all_hashes;
135 };
136
137 using HashedKmer = Minimizer;
138
139 struct Record
140 {
141 Record() {}
142
143 Record(size_t num,
144 std::string id,
145 std::string barcode,
146 size_t readlen,
147 std::vector<Minimizer> minimizers)
148 : num(num)
149 , id(std::move(id))
150 , barcode(std::move(barcode))
151 , readlen(readlen)
152 , minimizers(std::move(minimizers))
153 {
154 }
155
156 size_t num = 0;
157 std::string id;
158 std::string barcode;
159 size_t readlen = 0;
160 std::vector<Minimizer> minimizers;
161
162 operator bool() const
163 {
164 return !id.empty() || !barcode.empty() || !minimizers.empty();
165 }
166 };
167
172 Record read();
173
193 Indexlr(std::string seqfile,
194 size_t k,
195 size_t w,
196 unsigned flags = 0,
197 unsigned threads = 5,
198 bool verbose = false,
199 const btllib::BloomFilter& bf1 = Indexlr::dummy_bf(),
200 const btllib::BloomFilter& bf2 = Indexlr::dummy_bf());
201
202 Indexlr(std::string seqfile,
203 size_t k,
204 size_t w,
205 size_t q,
206 unsigned flags = 0,
207 unsigned threads = 5,
208 bool verbose = false,
209 const btllib::BloomFilter& bf1 = Indexlr::dummy_bf(),
210 const btllib::BloomFilter& bf2 = Indexlr::dummy_bf());
211
212 ~Indexlr();
213
214 void close() noexcept;
215
216 static const size_t MAX_SIMULTANEOUS_INDEXLRS = 256;
217
220 class RecordIterator
221 {
222 public:
223 void operator++() { record = indexlr.read(); }
224 bool operator!=(const RecordIterator& i)
225 {
226 return bool(record) || bool(i.record);
227 }
228 Record operator*() { return std::move(record); }
229 // For wrappers
230 Record next()
231 {
232 auto val = operator*();
233 operator++();
234 return val;
235 }
236
237 private:
238 friend Indexlr;
239
240 RecordIterator(Indexlr& indexlr, bool end)
241 : indexlr(indexlr)
242 {
243 if (!end) {
244 operator++();
245 }
246 }
247
248 Indexlr& indexlr;
249 Record record;
250 };
252
253 RecordIterator begin() { return RecordIterator(*this, false); }
254 RecordIterator end() { return RecordIterator(*this, true); }
255
256private:
257 static std::string extract_barcode(const std::string& id,
258 const std::string& comment);
259 static void filter_hashed_kmer(Indexlr::HashedKmer& hk,
260 bool filter_in,
261 bool filter_out,
262 const BloomFilter& filter_in_bf,
263 const BloomFilter& filter_out_bf);
264
265 static void filter_kmer_qual(Indexlr::HashedKmer& hk,
266 const std::string& kmer_qual,
267 size_t q);
268 static size_t calc_kmer_quality(const std::string& qual);
269
270 static void calc_minimizer(
271 const std::vector<Indexlr::HashedKmer>& hashed_kmers_buffer,
272 const Indexlr::Minimizer*& min_current,
273 size_t idx,
274 ssize_t& min_idx_left,
275 ssize_t& min_idx_right,
276 ssize_t& min_pos_prev,
277 size_t w,
278 std::vector<Indexlr::Minimizer>& minimizers);
279 std::vector<Minimizer> minimize(const std::string& seq,
280 const std::string& qual) const;
281
282 const std::string seqfile;
283 const size_t k, w;
284 size_t q;
285 const unsigned flags;
286 const bool verbose;
287 const long id;
288 std::atomic<bool> closed{ false };
289
290 static const BloomFilter& dummy_bf()
291 {
292 static const BloomFilter var;
293 return var;
294 }
295
296 const std::reference_wrapper<const BloomFilter> filter_in_bf;
297 const std::reference_wrapper<const BloomFilter> filter_out_bf;
298 bool filter_in_enabled;
299 bool filter_out_enabled;
300
301 SeqReader reader;
302 OrderQueueMPSC<Record> output_queue;
303
304 using OutputQueueType = decltype(output_queue);
305 static std::unique_ptr<OutputQueueType::Block>* ready_blocks_array()
306 {
307 thread_local static std::unique_ptr<decltype(output_queue)::Block>
308 var[MAX_SIMULTANEOUS_INDEXLRS];
309 return var;
310 }
311
312 static long* ready_blocks_owners()
313 {
314 thread_local static long var[MAX_SIMULTANEOUS_INDEXLRS] = { 0 };
315 return var;
316 }
317
318 static size_t* ready_blocks_current()
319 {
320 thread_local static size_t var[MAX_SIMULTANEOUS_INDEXLRS] = { 0 };
321 return var;
322 }
323
324 static std::atomic<long>& last_id()
325 {
326 static std::atomic<long> var(0);
327 return var;
328 }
329
330 class Worker
331 {
332 public:
333 void start() { t = std::thread(do_work, this); }
334 void join() { t.join(); }
335 void set_id(const int id) { this->id = id; }
336
337 Worker& operator=(const Worker& worker) = delete;
338 Worker& operator=(Worker&& worker) = delete;
339
340 Worker(Indexlr& indexlr)
341 : indexlr(indexlr)
342 {
343 }
344 Worker(const Worker& worker)
345 : Worker(worker.indexlr)
346 {
347 }
348 Worker(Worker&& worker) noexcept
349 : Worker(worker.indexlr)
350 {
351 }
352
353 private:
354 void work();
355 static void do_work(Worker* worker) { worker->work(); }
356
357 int id = -1;
358 Indexlr& indexlr;
359 std::thread t;
360 };
361
362 std::vector<Worker> workers;
363 Barrier end_barrier;
364 std::mutex last_block_num_mutex;
365 uint64_t last_block_num = 0;
366 bool last_block_num_valid = false;
367};
368
369// Constructor for Indexlr class when q is specified
370inline Indexlr::Indexlr(std::string seqfile,
371 const size_t k,
372 const size_t w,
373 const size_t q,
374 const unsigned flags,
375 const unsigned threads,
376 const bool verbose,
377 const BloomFilter& bf1,
378 const BloomFilter& bf2)
379 : seqfile(std::move(seqfile))
380 , k(k)
381 , w(w)
382 , q(q)
383 , flags(flags)
384 , verbose(verbose)
385 , id(++last_id())
386 , filter_in_bf(filter_in() ? bf1 : Indexlr::dummy_bf())
387 , filter_out_bf(filter_out() ? filter_in() ? bf2 : bf1 : Indexlr::dummy_bf())
388 , filter_in_enabled(filter_in())
389 , filter_out_enabled(filter_out())
390 , reader(this->seqfile,
391 short_mode() ? SeqReader::Flag::SHORT_MODE
392 : SeqReader::Flag::LONG_MODE)
393 , output_queue(reader.get_buffer_size(), reader.get_block_size())
394 , workers(std::vector<Worker>(threads, Worker(*this)))
395 , end_barrier(threads)
396{
397 check_error(!short_mode() && !long_mode(),
398 "Indexlr: no mode selected, either short or long mode flag must "
399 "be provided.");
400 check_error(short_mode() && long_mode(),
401 "Indexlr: short and long mode are mutually exclusive.");
402 check_error(threads == 0,
403 "Indexlr: Number of processing threads cannot be 0.");
404 int id_counter = 0;
405 for (auto& worker : workers) {
406 worker.set_id(id_counter++);
407 worker.start();
408 }
409}
410
411// Constructor for Indexlr class when q is not specified
412inline Indexlr::Indexlr(std::string seqfile,
413 const size_t k,
414 const size_t w,
415 const unsigned flags,
416 const unsigned threads,
417 const bool verbose,
418 const BloomFilter& bf1,
419 const BloomFilter& bf2)
420 : Indexlr(std::move(seqfile), k, w, 0, flags, threads, verbose, bf1, bf2)
421{
422}
423
424inline Indexlr::~Indexlr()
425{
426 close();
427}
428
429inline void
430Indexlr::close() noexcept
431{
432 bool closed_expected = false;
433 if (closed.compare_exchange_strong(closed_expected, true)) {
434 try {
435 reader.close();
436 output_queue.close();
437 for (auto& worker : workers) {
438 worker.join();
439 }
440 } catch (const std::system_error& e) {
441 log_error("Indexlr thread join failure: " + std::string(e.what()));
442 std::exit(EXIT_FAILURE); // NOLINT(concurrency-mt-unsafe)
443 }
444 }
445}
446
447// Minimerize a sequence: Find the minimizers of a vector of hash values
448// representing a sequence.
449/* Algorithm
450v is a vector of non-negative integers
451w is the window size
452Invariants
453 0 < w <= v.size() - 1
454 0 <= l <= r <= v.size() - 1
455Initial conditions
456 M = NIL Final set of minimizers, empty initially
457 min = -1 Minimum element
458 i = -1 Index of minimum element
459 prev = -1 Index of previous minimum element
460 l = 0 Index of left end of window
461 r = l + w - 1 Index of right end of window
462Computation
463At each window, if the previous minimum is out of scope, find the new,
464right-most, minimum or else, check with only the right-most element to determine
465if that is the new minimum. A minimizer is added to the final vector only if
466it's index has changed. for each window of v bounded by [l, r] if (i < l) i =
467index of minimum element in [l, r], furthest from l. else if (v[r] <= v[i]) i =
468r min = v[i] if (i != prev) { prev = i M <- M + m
469 }
470 l = l + 1 Move window's left bound by one element
471 r = l + w - 1 Set window's right bound
472}*/
473
474inline std::string
475Indexlr::extract_barcode(const std::string& id, const std::string& comment)
476{
477 const static std::string barcode_prefix = "BX:Z:";
478 if (startswith(comment, barcode_prefix)) {
479 const auto space_pos = comment.find(' ');
480 if (space_pos != std::string::npos) {
481 return comment.substr(barcode_prefix.size(),
482 space_pos - barcode_prefix.size());
483 }
484 return comment.substr(barcode_prefix.size());
485 }
486 const auto pound_pos = id.find('#');
487 if (pound_pos != std::string::npos) {
488 const auto slash_pos = id.find('/');
489 if (slash_pos > pound_pos) {
490 return id.substr(pound_pos + 1, slash_pos - (pound_pos + 1));
491 }
492 }
493 return "NA";
494}
495
496inline void
497Indexlr::filter_hashed_kmer(Indexlr::HashedKmer& hk,
498 bool filter_in,
499 bool filter_out,
500 const BloomFilter& filter_in_bf,
501 const BloomFilter& filter_out_bf)
502{
503 if (!filter_in && !filter_out) {
504 return;
505 }
506
507 bool use_all = (filter_in ? filter_in_bf.get_hash_num()
508 : filter_out_bf.get_hash_num()) > 1;
509
510 auto check_contains = [&](const BloomFilter& bf) {
511 if (use_all) {
512 return bf.contains(hk.all_hashes);
513 } else {
514 return bf.contains({ hk.min_hash });
515 }
516 };
517
518 if (filter_in && filter_out) {
519 if (!check_contains(filter_in_bf) || check_contains(filter_out_bf)) {
520 hk.min_hash = std::numeric_limits<uint64_t>::max();
521 }
522 } else if (filter_in) {
523 if (!check_contains(filter_in_bf)) {
524 hk.min_hash = std::numeric_limits<uint64_t>::max();
525 }
526 } else if (filter_out) {
527 if (check_contains(filter_out_bf)) {
528 hk.min_hash = std::numeric_limits<uint64_t>::max();
529 }
530 }
531}
532
533inline void
534Indexlr::filter_kmer_qual(Indexlr::HashedKmer& hk,
535 const std::string& kmer_qual,
536 size_t q)
537{
538 if (calc_kmer_quality(kmer_qual) < q) {
539 hk.min_hash = std::numeric_limits<uint64_t>::max();
540 }
541}
542
543inline size_t
544Indexlr::calc_kmer_quality(const std::string& qual)
545{
546 // convert the quality scores to integers
547 std::vector<int> qual_ints;
548 const int thirty_three = 33;
549 qual_ints.reserve(qual.size());
550 for (auto c : qual) {
551 qual_ints.push_back(c - thirty_three);
552 }
553 // calculate the mean (potential improvement: use other statistics)
554 size_t sum = 0;
555 for (auto q : qual_ints) {
556 sum += q;
557 }
558 return (sum / qual_ints.size());
559}
560
561inline void
562Indexlr::calc_minimizer(
563 const std::vector<Indexlr::HashedKmer>& hashed_kmers_buffer,
564 const Indexlr::Minimizer*& min_current,
565 const size_t idx,
566 ssize_t& min_idx_left,
567 ssize_t& min_idx_right,
568 ssize_t& min_pos_prev,
569 const size_t w,
570 std::vector<Indexlr::Minimizer>& minimizers)
571{
572 min_idx_left = ssize_t(idx + 1 - w);
573 min_idx_right = ssize_t(idx + 1);
574 const auto& min_left =
575 hashed_kmers_buffer[min_idx_left % hashed_kmers_buffer.size()];
576 const auto& min_right =
577 hashed_kmers_buffer[(min_idx_right - 1) % hashed_kmers_buffer.size()];
578
579 if (min_current == nullptr || min_current->pos < min_left.pos) {
580 min_current = &min_left;
581 // Use of operator '<=' returns the minimum that is furthest from left.
582 for (ssize_t i = min_idx_left; i < min_idx_right; i++) {
583 const auto& min_i = hashed_kmers_buffer[i % hashed_kmers_buffer.size()];
584 if (min_i.min_hash <= min_current->min_hash) {
585 min_current = &min_i;
586 }
587 }
588 } else if (min_right.min_hash <= min_current->min_hash) {
589 min_current = &min_right;
590 }
591 if (ssize_t(min_current->pos) > min_pos_prev &&
592 min_current->min_hash != std::numeric_limits<uint64_t>::max()) {
593 min_pos_prev = ssize_t(min_current->pos);
594 minimizers.push_back(*min_current);
595 }
596}
597
598inline std::vector<Indexlr::Minimizer>
599Indexlr::minimize(const std::string& seq, const std::string& qual) const
600{
601 if ((k > seq.size()) || (w > seq.size() - k + 1)) {
602 return {};
603 }
604 std::vector<Minimizer> minimizers;
605 minimizers.reserve(2 * (seq.size() - k + 1) / w);
606 std::vector<HashedKmer> hashed_kmers_buffer(w + 1);
607 ssize_t min_idx_left, min_idx_right, min_pos_prev = -1;
608 const Minimizer* min_current = nullptr;
609 size_t idx = 0;
610 size_t bf_num_hashes = 0;
611 if (!filter_in() && !filter_out()) {
612 bf_num_hashes = 1;
613 } else if (filter_in()) {
614 bf_num_hashes = filter_in_bf.get().get_hash_num();
615 } else {
616 bf_num_hashes = filter_out_bf.get().get_hash_num();
617 }
618
619 size_t nthash_num_hashes = std::max(static_cast<size_t>(2), bf_num_hashes);
620
621 for (NtHash nh(seq, nthash_num_hashes, k); nh.roll(); ++idx) {
622 auto& hk = hashed_kmers_buffer[idx % hashed_kmers_buffer.size()];
623 if (bf_num_hashes == 1) {
624 hk = HashedKmer(nh.hashes()[0],
625 nh.hashes()[1],
626 nh.get_pos(),
627 nh.get_forward_hash() <= nh.get_reverse_hash(),
628 output_seq() ? seq.substr(nh.get_pos(), k) : "",
629 output_qual() ? qual.substr(nh.get_pos(), k) : "");
630
631 } else {
632 hk = HashedKmer(
633 nh.hashes()[0],
634 nh.hashes()[1],
635 nh.get_pos(),
636 nh.get_forward_hash() <= nh.get_reverse_hash(),
637 output_seq() ? seq.substr(nh.get_pos(), k) : "",
638 output_qual() ? qual.substr(nh.get_pos(), k) : "",
639 std::vector<uint64_t>(nh.hashes(), nh.hashes() + bf_num_hashes));
640 }
641
642 filter_hashed_kmer(
643 hk, filter_in(), filter_out(), filter_in_bf.get(), filter_out_bf.get());
644
645 if (q > 0) {
646 filter_kmer_qual(hk, qual.substr(nh.get_pos(), k), q);
647 }
648
649 if (idx + 1 >= w) {
650 calc_minimizer(hashed_kmers_buffer,
651 min_current,
652 idx,
653 min_idx_left,
654 min_idx_right,
655 min_pos_prev,
656 w,
657 minimizers);
658 }
659 }
660 return minimizers;
661}
662
663inline Indexlr::Record
665{
666 if (ready_blocks_owners()[id % MAX_SIMULTANEOUS_INDEXLRS] != id) {
667 ready_blocks_array()[id % MAX_SIMULTANEOUS_INDEXLRS] =
668 std::unique_ptr< // NOLINT(modernize-make-unique)
669 decltype(output_queue)::Block>(
670 new decltype(output_queue)::Block(reader.get_block_size()));
671 ready_blocks_owners()[id % MAX_SIMULTANEOUS_INDEXLRS] = id;
672 ready_blocks_current()[id % MAX_SIMULTANEOUS_INDEXLRS] = 0;
673 }
674 auto& block = *(ready_blocks_array()[id % MAX_SIMULTANEOUS_INDEXLRS]);
675 auto& current = ready_blocks_current()[id % MAX_SIMULTANEOUS_INDEXLRS];
676 if (current >= block.count) {
677 block.count = 0;
678 output_queue.read(block);
679 if (block.count == 0) {
680 output_queue.close();
681 block = decltype(output_queue)::Block(reader.get_block_size());
682 return Record();
683 }
684 current = 0;
685 }
686 return std::move(block.data[current++]);
687}
688
689inline void
690Indexlr::Worker::work()
691{
692 decltype(indexlr.output_queue)::Block output_block(
693 indexlr.reader.get_block_size());
694 uint64_t last_block_num = 0;
695 bool last_block_num_valid = false;
696 for (;;) {
697 auto input_block = indexlr.reader.read_block();
698 if (input_block.count == 0) {
699 break;
700 }
701
702 output_block.num = input_block.num;
703 for (size_t idx = 0; idx < input_block.count; idx++) {
704 Record record;
705 auto& reader_record = input_block.data[idx];
706 record.num = reader_record.num;
707 if (indexlr.output_bx()) {
708 record.barcode =
709 indexlr.extract_barcode(reader_record.id, reader_record.comment);
710 }
711 if (indexlr.output_id()) {
712 record.id = std::move(reader_record.id);
713 }
714
715 record.readlen = reader_record.seq.size();
716
717 check_info(indexlr.verbose && indexlr.k > record.readlen,
718 "Indexlr: skipped seq " + std::to_string(record.num) +
719 " on line " +
720 std::to_string(record.num * (indexlr.reader.get_format() ==
721 SeqReader::Format::FASTA
722 ? 2
723 : 4) +
724 2) +
725 "; k (" + std::to_string(indexlr.k) + ") > seq length (" +
726 std::to_string(record.readlen) + ")");
727
728 check_info(indexlr.verbose && indexlr.w > record.readlen - indexlr.k + 1,
729 "Indexlr: skipped seq " + std::to_string(record.num) +
730 " on line " +
731 std::to_string(record.num * (indexlr.reader.get_format() ==
732 SeqReader::Format::FASTA
733 ? 2
734 : 4) +
735 2) +
736 "; w (" + std::to_string(indexlr.w) + ") > # of hashes (" +
737 std::to_string(record.readlen - indexlr.k + 1) + ")");
738
739 if (indexlr.k <= record.readlen &&
740 indexlr.w <= record.readlen - indexlr.k + 1) {
741 record.minimizers =
742 indexlr.minimize(reader_record.seq, reader_record.qual);
743 } else {
744 record.minimizers = {};
745 }
746
747 output_block.data[output_block.count++] = std::move(record);
748 }
749 if (output_block.count > 0) {
750 last_block_num = output_block.num;
751 last_block_num_valid = true;
752 indexlr.output_queue.write(output_block);
753 output_block.count = 0;
754 }
755 }
756 if (last_block_num_valid) {
757 std::unique_lock<std::mutex> lock(indexlr.last_block_num_mutex);
758 indexlr.last_block_num = std::max(indexlr.last_block_num, last_block_num);
759 indexlr.last_block_num_valid = true;
760 lock.unlock();
761 }
762 indexlr.end_barrier.wait();
763 if (last_block_num_valid && indexlr.last_block_num_valid &&
764 last_block_num == indexlr.last_block_num) {
765 output_block.num = last_block_num + 1;
766 indexlr.output_queue.write(output_block);
767 } else if (!indexlr.last_block_num_valid && id == 0) {
768 output_block.num = 0;
769 indexlr.output_queue.write(output_block);
770 }
771}
772
773} // namespace btllib
774
775#endif
Definition bloom_filter.hpp:73
Definition indexlr.hpp:26
Indexlr(std::string seqfile, size_t k, size_t w, unsigned flags=0, unsigned threads=5, bool verbose=false, const btllib::BloomFilter &bf1=Indexlr::dummy_bf(), const btllib::BloomFilter &bf2=Indexlr::dummy_bf())
Definition indexlr.hpp:412
RecordIterator begin()
Definition indexlr.hpp:253
Record read()
Definition indexlr.hpp:664
OrderQueueMPMC< Record >::Block read_block()
Definition aahash.hpp:12
void check_error(bool condition, const std::string &msg)
void log_error(const std::string &msg)
bool startswith(std::string s, std::string prefix)
void check_info(bool condition, const std::string &msg)
Definition indexlr.hpp:34
static const unsigned BX
Definition indexlr.hpp:38
static const unsigned SEQ
Definition indexlr.hpp:40
static const unsigned LONG_MODE
Definition indexlr.hpp:52
static const unsigned QUAL
Definition indexlr.hpp:54
static const unsigned FILTER_IN
Definition indexlr.hpp:43
static const unsigned FILTER_OUT
Definition indexlr.hpp:48
static const unsigned NO_ID
Definition indexlr.hpp:36
static const unsigned SHORT_MODE
Definition indexlr.hpp:50
Definition indexlr.hpp:67
Definition indexlr.hpp:140