Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

alphabet_base expects functions instead of look-up tables. #2427

Merged
merged 28 commits into from
Mar 24, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
2d62823
[API] allow alphabet::char_to_rank(chr) to be a function
marehr Feb 24, 2021
93130bf
[MISC] use function in nucleotide_base::valid_char_table
marehr Feb 25, 2021
5d2a2ec
[MISC] use function in aminoacid_base::valid_char_table
marehr Feb 25, 2021
79d591d
[MISC] introduce [rd]na4::char_to_rank function
marehr Feb 24, 2021
7cd9616
[MISC] introduce rna4::rank_to_char function
marehr Feb 25, 2021
56f168c
[MISC] introduce [rd]na5::char_to_rank and dna5::rank_to_char function
marehr Feb 24, 2021
f9b373e
[MISC] introduce rna5::rank_to_char function
marehr Feb 24, 2021
ee8b715
[MISC] introduce [rd]na15::char_to_rank and dna15::rank_to_char function
marehr Feb 25, 2021
9ee7bde
[MISC] introduce rna15::rank_to_char function
marehr Feb 25, 2021
9aada46
[MISC] introduce sam_dna16::{rank_to_char, char_to_rank} function
marehr Feb 25, 2021
8f5f30d
[MISC] introduce dna3bs::{rank_to_char, char_to_rank} function
marehr Feb 25, 2021
e364cca
[MISC] introduce aa10li::{rank_to_char, char_to_rank} function
marehr Feb 25, 2021
05589d7
[MISC] introduce aa10murphy::{rank_to_char, char_to_rank} function
marehr Feb 25, 2021
9d17309
[MISC] introduce aa20::{rank_to_char, char_to_rank} function
marehr Feb 25, 2021
0ed6afb
[MISC] introduce aa27::{rank_to_char, char_to_rank} function
marehr Feb 25, 2021
16028f6
[MISC] introduce cigar_operation::{rank_to_char, char_to_rank} function
marehr Feb 25, 2021
5247a60
[MISC] introduce gap::{rank_to_char, char_to_rank} function
marehr Feb 25, 2021
923751a
[MISC] introduce qualified::rank_to_char function
marehr Feb 25, 2021
fdf35e5
[MISC] introduce quality_base::{rank_to_char, char_to_rank} function
marehr Feb 25, 2021
2298752
[MISC] introduce dot_bracket3::{rank_to_char, char_to_rank} function
marehr Feb 25, 2021
5e973e2
[MISC] introduce dssp9::{rank_to_char, char_to_rank} function
marehr Feb 25, 2021
4da973d
[MISC] introduce wuss::{rank_to_char, char_to_rank} function
marehr Feb 25, 2021
4e13060
[MISC] introduce snippet::my_dna4::{rank_to_char, char_to_rank} function
marehr Feb 25, 2021
adfa0c8
[MISC] introduce snippet::dna2::{rank_to_char, char_to_rank} function
marehr Feb 25, 2021
e4af170
[MISC] introduce snippet::alphabet_base::{rank_to_char, char_to_rank}…
marehr Feb 25, 2021
f120257
[MISC] introduce alphabet_variant::{rank_to_char, char_to_rank} function
marehr Feb 25, 2021
db2b30a
[FIX] gcc10: throws invalid deprecation warnings
marehr Feb 25, 2021
a9ba4d7
[API] deprecate old alphabet::lookup-tables
marehr Feb 24, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 21 additions & 4 deletions doc/cookbook/custom_dna4.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,32 @@ class my_dna4 : public seqan3::nucleotide_base<my_dna4, 4/*alphabet size is 4*/>
using nucleotide_base<my_dna4, 4>::nucleotide_base; // Use constructors of the base class.

private:
// Returns the character representation of rank. This is where rank conversion for to_char() is handled!
static constexpr char_type rank_to_char(rank_type const rank)
{
return rank_to_char_table[rank];
}

// Returns the rank representation of character. This is where char conversion for assign_char() is handled!
static constexpr rank_type char_to_rank(char_type const chr)
{
using index_t = std::make_unsigned_t<char_type>;
return char_to_rank_table[static_cast<index_t>(chr)];
}

private:
// === lookup-table implementation detail ===

// Value to char conversion table.
static constexpr char_type rank_to_char[alphabet_size] {'A', 'C', 'G', 'T'}; // rank 0,1,2,3
static constexpr char_type rank_to_char_table[alphabet_size] {'A', 'C', 'G', 'T'}; // rank 0,1,2,3

// Char-to-value conversion table. This is where char conversion for assign_char() is handled!
static constexpr std::array<rank_type, 256> char_to_rank
// Char-to-value conversion table.
static constexpr std::array<rank_type, 256> char_to_rank_table
{
[] () constexpr
{
std::array<rank_type, 256> conversion_table{}; // By default now, everything has rank 0 which equals `A`.
// By default, everything has rank 0 which equals `A`.
std::array<rank_type, 256> conversion_table{};

conversion_table['C'] = conversion_table['c'] = 1;
conversion_table['G'] = conversion_table['g'] = 2;
Expand Down
32 changes: 27 additions & 5 deletions doc/howto/write_an_alphabet/dna2_derive_from_base.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,40 @@
#include <array> // std::array
#include <seqan3/alphabet/alphabet_base.hpp> // alphabet_base
#include <seqan3/alphabet/concept.hpp> // alphabet concept checks
#include <seqan3/utility/char_operations/transform.hpp> // seqan3::to_lower

// derive from alphabet_base
struct dna2 : public seqan3::alphabet_base<dna2, 2>
{
private:
// make the base class a friend so it can access the tables:
friend seqan3::alphabet_base<dna2, 2>;

// map 0 => 'S' and 1 => 'W'
static constexpr char_type rank_to_char[alphabet_size] {'S', 'W'};
static constexpr char_type rank_to_char(rank_type const rank)
{
// via a lookup table
return rank_to_char_table[rank];
// or via an arithmetic expression
return rank == 1 ? 'W' : 'S';
eseiler marked this conversation as resolved.
Show resolved Hide resolved
}

static constexpr std::array<rank_type, 256> char_to_rank
static constexpr rank_type char_to_rank(char_type const chr)
{
// via a lookup table
using index_t = std::make_unsigned_t<char_type>;
return char_to_rank_table[static_cast<index_t>(chr)];
// or via an arithmetic expression
return seqan3::to_lower(chr) == 'w' ? 1 : 0;
}

private:
// === lookup-table implementation detail ===

// map 0 => 'S' and 1 => 'W'
static constexpr char_type rank_to_char_table[alphabet_size] {'S', 'W'};

static constexpr std::array<rank_type, 256> char_to_rank_table
{
// initialise with an immediately evaluated lambda expression:
[] () constexpr
Expand All @@ -28,9 +53,6 @@ struct dna2 : public seqan3::alphabet_base<dna2, 2>
return ret;
} ()
};

// make the base class a friend so it can access the tables:
friend seqan3::alphabet_base<dna2, 2>;
};

// check the concepts
Expand Down
96 changes: 85 additions & 11 deletions include/seqan3/alphabet/alphabet_base.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,30 @@
#include <seqan3/alphabet/concept.hpp>
#include <seqan3/utility/detail/integer_traits.hpp>

#ifdef SEQAN3_DEPRECATED_310
namespace seqan3::detail
{
//!\cond
// helper concept to deprecate old rank_to_char lookup tables
template <typename alphabet_t>
SEQAN3_CONCEPT has_rank_to_char_table = requires()
{
{ alphabet_t::rank_to_char[0] };
};
//!\endcond

//!\cond
// helper concept to deprecate old char_to_rank lookup tables
template <typename alphabet_t>
SEQAN3_CONCEPT has_char_to_rank_table = requires()
{
{ alphabet_t::char_to_rank[0] };
};
//!\endcond

} // namespace seqan3::detail
#endif // SEQAN3_DEPRECATED_310

namespace seqan3
{

Expand All @@ -35,18 +59,20 @@ namespace seqan3
* seqan3::alphabet, it is purely a way to avoid code duplication.
*
* The base class represents the alphabet value as the rank and automatically deduces the rank type from the size and
* defines all required member functions. The derived type needs to define only the following two tables as static
* member variables (can be private if the base class is befriended):
* defines all required member functions. The derived type needs to define only the following two static
* member functions (can be private if the base class is befriended):
*
* * `static std::array<char_type, alphabet_size> constexpr rank_to_char` that defines for every possible rank value
* the corresponding char value.
* * `static std::array<rank_type, 256> constexpr char_to_rank` that defines for every possible character value the
* corresponding rank value (adapt size if char_type isn't `char`).
* * `static constexpr char_type rank_to_char(rank_type const rank);` that defines for every possible rank value the
* corresponding char value.
* (The implementation can be a lookup-table or an arithmetic expression.)
* * `static constexpr rank_type char_to_rank(char_type const chr);` that defines for every possible character value
* the corresponding rank value (adapt size if char_type isn't `char`).
* (The implementation can be a lookup-table or an arithmetic expression.)
*
* ### Example
*
* This creates an alphabet called `ab` which has size two and the two letters 'A' and 'B':
* \include test/snippet/alphabet/detail/alphabet_base.cpp
* \include test/snippet/alphabet/alphabet_base.cpp
*
* \stableapi{Since version 3.1.}
*/
Expand Down Expand Up @@ -110,10 +136,32 @@ class alphabet_base
//!\cond
requires (!std::same_as<char_t, void>)
//!\endcond
{
#ifdef SEQAN3_DEPRECATED_310
if constexpr (detail::has_rank_to_char_table<derived_type>)
return rank_to_char_table(rank);
else
return derived_type::rank_to_char(rank);
#else // ^^^ before 3.1.0 release / after 3.1.0 release vvv
return derived_type::rank_to_char(rank);
#endif // SEQAN3_DEPRECATED_310
}

#ifdef SEQAN3_DEPRECATED_310
private:

/*!\brief Before SeqAn 3.0.3, we defined derived_type::rank_to_char_table as a lookup table. We relaxed this to be a
* function to give the implementer more freedom.
* \deprecated Define derived_type::rank_to_char_table as a function.
*/
SEQAN3_DEPRECATED_310 static constexpr char_type rank_to_char_table(rank_type const rank) noexcept
{
return derived_type::rank_to_char[rank];
}

public:
#endif // SEQAN3_DEPRECATED_310

/*!\brief Return the letter's numeric value (rank in the alphabet).
*
* \details
Expand All @@ -140,7 +188,7 @@ class alphabet_base
* \{
*/
/*!\brief Assign from a character, implicitly converts invalid characters.
* \param c The character to be assigned.
* \param chr The character to be assigned.
*
* \details
*
Expand All @@ -156,16 +204,42 @@ class alphabet_base
*
* \stableapi{Since version 3.1.}
*/
constexpr derived_type & assign_char(char_type const c) noexcept
constexpr derived_type & assign_char(char_type const chr) noexcept
//!\cond
requires (!std::same_as<char_t, void>)
//!\endcond
{
using index_t = std::make_unsigned_t<char_type>;
rank = derived_type::char_to_rank[static_cast<index_t>(c)];
#ifdef SEQAN3_DEPRECATED_310
if constexpr (detail::has_char_to_rank_table<derived_type>)
rank = char_to_rank_table(chr);
else
rank = derived_type::char_to_rank(chr);
#else // ^^^ before 3.1.0 release / after 3.1.0 release vvv
rank = derived_type::char_to_rank(chr);
#endif // SEQAN3_DEPRECATED_310

return static_cast<derived_type &>(*this);
}

#ifdef SEQAN3_DEPRECATED_310
private:

/*!\brief Before SeqAn 3.0.3, we defined derived_type::char_to_rank as a lookup table. We relaxed this to be a
* function to give the implementer more freedom.
* \deprecated Define derived_type::char_to_rank as a function.
*/
SEQAN3_DEPRECATED_310 static constexpr rank_type char_to_rank_table(char_type const chr) noexcept
{
using index_t = std::make_unsigned_t<char_type>;
#if SEQAN3_WORKAROUND_GCC_99318
# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#endif // SEQAN3_WORKAROUND_GCC_99318
return derived_type::char_to_rank[static_cast<index_t>(chr)];
}

public:
#endif // SEQAN3_DEPRECATED_310

/*!\brief Assign from a numeric value.
* \param c The rank to be assigned.
*
Expand Down
29 changes: 21 additions & 8 deletions include/seqan3/alphabet/aminoacid/aa10li.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -106,9 +106,9 @@ class aa10li : public aminoacid_base<aa10li, 10>
using base_t::base_t;
//!\}

protected:
//!\brief Value to char conversion table.
static constexpr char_type rank_to_char[alphabet_size]
private:
//!\copydoc seqan3::aa27::rank_to_char_table
static constexpr char_type rank_to_char_table[alphabet_size]
{
'A',
'B',
Expand All @@ -119,11 +119,11 @@ class aa10li : public aminoacid_base<aa10li, 10>
'I',
'J',
'K',
'P',
'P'
};

//!\brief Char to value conversion table.
static constexpr std::array<rank_type, 256> char_to_rank
//!\copydoc seqan3::aa27::char_to_rank_table
static constexpr std::array<rank_type, 256> char_to_rank_table
{
[] () constexpr
{
Expand All @@ -136,8 +136,8 @@ class aa10li : public aminoacid_base<aa10li, 10>
// reverse mapping for characters and their lowercase
for (rank_type rnk = 0u; rnk < alphabet_size; ++rnk)
{
ret[static_cast<rank_type>( rank_to_char[rnk]) ] = rnk;
ret[static_cast<rank_type>(to_lower(rank_to_char[rnk]))] = rnk;
ret[static_cast<rank_type>(rank_to_char_table[rnk])] = rnk;
ret[static_cast<rank_type>(to_lower(rank_to_char_table[rnk]))] = rnk;
}

ret['D'] = ret['B']; ret['d'] = ret['B']; // Convert D to B (either D/N).
Expand All @@ -160,6 +160,19 @@ class aa10li : public aminoacid_base<aa10li, 10>
return ret;
}()
};

//!\copydoc seqan3::aa27::char_to_rank
static constexpr rank_type char_to_rank(char_type const chr)
{
using index_t = std::make_unsigned_t<char_type>;
return char_to_rank_table[static_cast<index_t>(chr)];
}
eseiler marked this conversation as resolved.
Show resolved Hide resolved

//!\copydoc seqan3::aa27::rank_to_char
static constexpr char_type rank_to_char(rank_type const rank)
{
return rank_to_char_table[rank];
}
};

// ------------------------------------------------------------------
Expand Down
29 changes: 21 additions & 8 deletions include/seqan3/alphabet/aminoacid/aa10murphy.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -105,9 +105,9 @@ class aa10murphy : public aminoacid_base<aa10murphy, 10>
using base_t::base_t;
//!\}

protected:
//!\brief Value to char conversion table.
static constexpr char_type rank_to_char[alphabet_size]
private:
//!\copydoc seqan3::aa27::rank_to_char_table
static constexpr char_type rank_to_char_table[alphabet_size]
{
'A',
'B',
Expand All @@ -118,11 +118,11 @@ class aa10murphy : public aminoacid_base<aa10murphy, 10>
'I',
'K',
'P',
'S',
'S'
};

//!\brief Char to value conversion table.
static constexpr std::array<rank_type, 256> char_to_rank
//!\copydoc seqan3::aa27::char_to_rank_table
static constexpr std::array<rank_type, 256> char_to_rank_table
{
[] () constexpr
{
Expand All @@ -135,8 +135,8 @@ class aa10murphy : public aminoacid_base<aa10murphy, 10>
// reverse mapping for characters and their lowercase
for (rank_type rnk = 0u; rnk < alphabet_size; ++rnk)
{
ret[static_cast<rank_type>( rank_to_char[rnk]) ] = rnk;
ret[static_cast<rank_type>(to_lower(rank_to_char[rnk]))] = rnk;
ret[static_cast<rank_type>(rank_to_char_table[rnk])] = rnk;
ret[static_cast<rank_type>(to_lower(rank_to_char_table[rnk]))] = rnk;
}

ret['D'] = ret['B']; ret['d'] = ret['B']; // Convert D to B (either D/N).
Expand All @@ -159,6 +159,19 @@ class aa10murphy : public aminoacid_base<aa10murphy, 10>
return ret;
}()
};

//!\copydoc seqan3::aa27::rank_to_char
static constexpr char_type rank_to_char(rank_type const rank)
{
return rank_to_char_table[rank];
}

//!\copydoc seqan3::aa27::char_to_rank
static constexpr rank_type char_to_rank(char_type const chr)
{
using index_t = std::make_unsigned_t<char_type>;
return char_to_rank_table[static_cast<index_t>(chr)];
}
};

// ------------------------------------------------------------------
Expand Down
Loading