Skip to content

Commit e9e2d06

Browse files
committed
[DOC] Cookbook entry on auto-vectorizable dna4.
1 parent febd0f4 commit e9e2d06

File tree

2 files changed

+83
-0
lines changed

2 files changed

+83
-0
lines changed

doc/cookbook/index.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,3 +198,13 @@ This will use `4` threads by default and can be adjusted by setting `seqan3::con
198198
the desired value:
199199

200200
\snippet doc/cookbook/compression_threads.cpp example
201+
202+
# Auto vectorized dna4 complement
203+
204+
Our alphabet seqan3::dna4 cannot be easily auto-vectorized by the compiler.
205+
206+
See discussion here: https://github.com/seqan/seqan3/issues/1970
207+
208+
You can add your own alphabet that is auto-vectorizable in some use cases:
209+
210+
\include doc/cookbook/simdyfyable_alphabet_complement.cpp
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
#include <seqan3/alphabet/nucleotide/nucleotide_base.hpp>
2+
#include <seqan3/alphabet/nucleotide/rna4.hpp>
3+
4+
class simd_dna4 : public seqan3::nucleotide_base<simd_dna4, 256>
5+
{
6+
private:
7+
using base_t = nucleotide_base<simd_dna4, 256>;
8+
9+
friend base_t;
10+
//!\cond \brief Befriend seqan3::alphabet_base.
11+
friend base_t::base_t;
12+
//!\endcond
13+
friend seqan3::rna4;
14+
15+
public:
16+
constexpr simd_dna4() noexcept = default;
17+
constexpr simd_dna4(simd_dna4 const &) noexcept = default;
18+
constexpr simd_dna4(simd_dna4 &&) noexcept = default;
19+
constexpr simd_dna4 & operator=(simd_dna4 const &) noexcept = default;
20+
constexpr simd_dna4 & operator=(simd_dna4 &&) noexcept = default;
21+
~simd_dna4() noexcept = default;
22+
23+
using base_t::base_t;
24+
25+
template <std::same_as<seqan3::rna4> t> // template parameter t to accept incomplete type
26+
constexpr simd_dna4(t const & r) noexcept
27+
{
28+
assign_rank(r.to_rank());
29+
}
30+
31+
static uint8_t constexpr alphabet_size = 4;
32+
33+
constexpr simd_dna4 & assign_rank(rank_type const c) noexcept
34+
{
35+
base_t::assign_rank(c == 0 ? 'A' : (c == 1 ? 'C' : (c == 2 ? 'G' : 'T')));
36+
return *this;
37+
}
38+
39+
constexpr simd_dna4 & assign_char(char_type const c) noexcept
40+
{
41+
base_t::assign_rank(c);
42+
return *this;
43+
}
44+
45+
constexpr char_type to_char() const noexcept
46+
{
47+
return base_t::to_rank();
48+
}
49+
50+
constexpr rank_type to_rank() const noexcept
51+
{
52+
char_type c{to_char()};
53+
char_type upper_char = c & 0b0101'1111; // to_upper
54+
rank_type rank{};
55+
rank = (upper_char == 'T') * 3 + (upper_char == 'G') * 2 + (upper_char == 'C');
56+
return rank;
57+
}
58+
59+
constexpr simd_dna4 complement() const noexcept
60+
{
61+
char_type rank{to_char()};
62+
rank ^= rank % 2 ? ('C' ^ 'G') : ('A' ^ 'T');
63+
64+
simd_dna4 ret{};
65+
static_cast<base_t &>(ret).assign_rank(rank);
66+
return ret;
67+
}
68+
};
69+
70+
int main()
71+
{
72+
// ...
73+
}

0 commit comments

Comments
 (0)