Skip to content

Commit

Permalink
[MISC] various fixes related to alphabet CPOs
Browse files Browse the repository at this point in the history
  • Loading branch information
h-2 committed Sep 3, 2019
1 parent 8c875f3 commit 1abf2c5
Show file tree
Hide file tree
Showing 18 changed files with 489 additions and 394 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ If possible, provide tooling that performs the changes, e.g. a shell-script.

## API changes

* **Customising for third party types has changes slightly:**
You are only affected if you added types to `seqan3::custom::`.
Please see [About Customisation](http://docs.seqan.de/seqan/3-master-user/about_customisation.html).

#### Argument parser

* **Changed class signature of input/output file validators:**
Expand Down
14 changes: 10 additions & 4 deletions doc/about/customisation/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,16 @@ To customise one of our customisation points, do one of the following:

* Provide functionality as members *or* inside the namespace of your type (will be picked up via
[argument dependent lookup](https://en.cppreference.com/w/cpp/language/adl)).
* If you adapt a third party's type and you cannot add to that type's namespace, provide functionality inside the
namespace `seqan3::custom` (this is the "upload namespace").
* **Never** add names (types, functions, variables...) to namespace `seqan3` and never explicitly specialise one
of our templates or overload one of our functions.
* If you adapt a third party's type and you cannot add to that type's namespace, you can specialise the
respective template in `seqan3::custom` for that type and provide the needed functionality as static members of
that specialisation (this is an "upload space" for specialisations).

\warning
**Never** add anything (types, functions, variables...) to namespace `seqan3` and never explicitly specialise one
of our templates (except those in seqan3::custom) or overload one of our functions.

The \link howto_write_an_alphabet HowTo on creating your own alphabet \endlink provides many examples of how to
satisfy the requirements of customisation point objects.

More technical background on this topic can be found here:

Expand Down
12 changes: 11 additions & 1 deletion doc/howto/write_an_alphabet/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ your type also model these concepts.
\snippet dna2_alphabet.cpp writable_alphabet
\endsolution

At this point the seqan3::Alphabet concept should be modelled successfully and even seqan3::WritableAlphabet
At this point the seqan3::Alphabet concept should be modelled successfully and even seqan3::WritableAlphabet
is fine because we implemented `assign_char` and `char_is_valid`.
\snippet dna2_alphabet.cpp writable_alphabet_concept

Expand All @@ -157,6 +157,15 @@ without defining the (in)equality and comparison operators. Opposed to the examp
to model the functionality.
\snippet test/unit/alphabet/custom_alphabet_test.cpp my_alph

## Adaptation of a third party type {#howto_write_an_alphabet_custom}

This example is similar to the previous one, but assuming that you cannot add anything to the namespace of
the type that you wish to adapt.
In that case, you need to specialise the seqan3::custom::alphabet class template and provide the required functionality
as static members.

\snippet test/unit/alphabet/custom_alphabet3_test.cpp third_party_type

## Implementation of a non-default-constructible class

This is an example of a custom alphabet that is not default-constructible and that has a non-default overload for
Expand All @@ -174,3 +183,4 @@ from '1', 't' and 'T' for value 1 as well as from '0', 'f' and 'F' for value 0.
\note
You should really make your alphabet types [no-throw-default-constructible](\ref std::is_nothrow_default_constructible)
if you can!

128 changes: 53 additions & 75 deletions include/seqan3/alphabet/adaptation/char.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,103 +27,81 @@

#include <limits>

#include <seqan3/core/detail/customisation_point.hpp>
#include <seqan3/core/detail/int_types.hpp>
#include <seqan3/std/concepts>

namespace seqan3::detail
{
//!\addtogroup adaptation
//!\{

//!\brief Whether a type is `char`, `char16_t`, `char32_t` or `wchar_t` (type trait).
template <typename type, typename type_no_ref = std::remove_reference_t<type>>
constexpr bool is_char_adaptation_v = std::Same<type_no_ref, char> ||
std::Same<type_no_ref, char16_t> ||
std::Same<type_no_ref, char32_t> ||
std::Same<type_no_ref, wchar_t>;
//!\}
//!\ingroup adaptation
template <typename type>
constexpr bool is_char_adaptation_v = std::Same<type, char> ||
std::Same<type, char16_t> ||
std::Same<type, char32_t> ||
std::Same<type, wchar_t>;
} // namespace seqan3::detail

namespace seqan3::custom
{

/*!\name Free function wrappers for the char alphabet adaptation
* \brief For `char`, `char16_t` and `char32_t` do conversion to/from uint types.
* \ingroup adaptation
* \{
*/

/*!\brief Return the number of values the char type can take.
* \tparam char_type One of `char`, `char16_t`, `char32_t` or `wchar_t`.
* \param chr The parameters actual value is ignored.
* \returns The respective sizes (e.g. 256 for `char`).
*/
template <typename char_type>
//!\cond
requires seqan3::detail::is_char_adaptation_v<char_type>
template <typename type>
struct alphabet;
//!\endcond
constexpr auto alphabet_size(char_type const & SEQAN3_DOXYGEN_ONLY(chr)) noexcept
{
return detail::min_viable_uint_t<detail::size_in_values_v<char_type>>{detail::size_in_values_v<char_type>};
}

/*!\brief Converting char to char is no-op (it will just return the value you pass in).
/*!\brief Alphabet specific customisations for builtin char types.
* \tparam char_type One of `char`, `char16_t`, `char32_t` or `wchar_t`.
* \param chr The alphabet letter that you wish to convert to char (no-op).
* \returns `chr`.
* \ingroup adaptation
*/
template <typename char_type>
//!\cond
requires seqan3::detail::is_char_adaptation_v<char_type>
requires detail::is_char_adaptation_v<char_type>
//!\endcond
constexpr char_type to_char(char_type const chr) noexcept
struct alphabet<char_type>
{
return chr;
}
//!\brief The number of values the char type can take (e.g. 256 for `char`).
static constexpr auto alphabet_size =
detail::min_viable_uint_t<detail::size_in_values_v<char_type>>{detail::size_in_values_v<char_type>};

/*!\brief Convert char to rank by casting to an unsigned integral type of same size.
* \tparam char_type One of `char`, `char16_t`, `char32_t` or `wchar_t`.
* \param chr The alphabet letter that you wish to convert to rank.
* \returns The letter's value in the alphabet's rank type (usually a `uint*_t`).
*/
template <typename char_type>
//!\cond
requires seqan3::detail::is_char_adaptation_v<char_type>
//!\endcond
constexpr auto to_rank(char_type const chr) noexcept
{
return static_cast<::seqan3::detail::min_viable_uint_t<alphabet_size(char_type{}) - 1>>(chr);
}
/*!\brief Converting char to char is no-op (it will just return the value you pass in).
* \param[in] chr The alphabet letter that you wish to convert to char (no-op).
* \returns `chr`.
*/
static constexpr char_type to_char(char_type const chr) noexcept
{
return chr;
}

/*!\brief Assign a char to the char type (same as calling `=`).
* \tparam char_type One of `char`, `char16_t`, `char32_t` or `wchar_t`.
* \param chr The alphabet letter that you wish to assign to.
* \param chr2 The `char` value you wish to assign.
* \returns A reference to the alphabet letter you passed in.
*/
template <typename char_type>
//!\cond
requires detail::is_char_adaptation_v<char_type>
//!\endcond
constexpr char_type & assign_char_to(char_type const chr2, char_type & chr) noexcept
{
return chr = chr2;
}
/*!\brief Convert char to rank by casting to an unsigned integral type of same size.
* \param[in] chr The alphabet letter that you wish to convert to rank.
* \returns The letter's value in the alphabet's rank type (usually a `uint*_t`).
*/
static constexpr auto to_rank(char_type const chr) noexcept
{
return static_cast<detail::min_viable_uint_t<alphabet_size - 1>>(chr);
}

/*!\brief Assigning a rank to a char is the same as assigning it a numeric value.
* \tparam char_type One of `char`, `char16_t`, `char32_t` or `wchar_t`.
* \param chr The alphabet letter that you wish to assign to.
* \param rank The `rank` value you wish to assign.
* \returns A reference to the alphabet letter you passed in.
*/
template <typename char_type>
//!\cond
requires detail::is_char_adaptation_v<char_type>
//!\endcond
constexpr char_type & assign_rank_to(decltype(to_rank(char_type{})) const rank, char_type & chr) noexcept
{
return chr = rank;
}
//!\}
/*!\brief Assign a char to the char type (same as calling `=`).
* \param[in] chr2 The `char` value you wish to assign.
* \param[in,out] chr The alphabet letter that you wish to assign to.
* \returns A reference to the alphabet letter you passed in.
*/
static constexpr char_type & assign_char_to(char_type const chr2, char_type & chr) noexcept
{
return chr = chr2;
}

/*!\brief Assigning a rank to a char is the same as assigning it a numeric value.
* \param[in] rank The `rank` value you wish to assign.
* \param[in,out] chr The alphabet letter that you wish to assign to.
* \returns A reference to the alphabet letter you passed in.
*/
static constexpr char_type & assign_rank_to(decltype(alphabet::to_rank(char_type{})) const rank,
char_type & chr) noexcept
{
return chr = rank;
}
};

} // namespace seqan3::custom
137 changes: 57 additions & 80 deletions include/seqan3/alphabet/adaptation/uint.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,107 +27,84 @@

#include <limits>

#include <seqan3/core/detail/customisation_point.hpp>
#include <seqan3/core/detail/int_types.hpp>
#include <seqan3/std/concepts>

namespace seqan3::detail
{
//!\addtogroup adaptation
//!\{

//!\brief Whether a type is `uint8_t`, `uint16_t` or `uint32_t`.
template <typename type, typename type2 = std::remove_reference_t<type>>
constexpr bool is_uint_adaptation_v = std::Same<type2, uint8_t> ||
std::Same<type2, uint16_t> ||
std::Same<type2, uint32_t>;
//!\}
//!\ingroup adaptation
template <typename type>
constexpr bool is_uint_adaptation_v = std::Same<type, uint8_t> ||
std::Same<type, uint16_t> ||
std::Same<type, uint32_t>;
} // namespace seqan3::detail

namespace seqan3::custom
{

/*!\name Free function wrappers for the uint alphabet adaptation
* \brief For `uint8_t`, `uint16_t` and `uint32_t` do conversion to/from char types.
* \ingroup adaptation
* \{
*/

/*!\brief Return the number of values the uint type can take.
* \tparam uint_type One of `uint8_t`, `uint16_t` or `uint32_t`.
* \param intgr The parameter's actual value is ignored.
* \returns The respective size (e.g. 256 for `uint8_t`).
*/
template <typename uint_type>
//!\cond
requires ::seqan3::detail::is_uint_adaptation_v<uint_type>
template <typename type>
struct alphabet;
//!\endcond
constexpr auto alphabet_size(uint_type const & SEQAN3_DOXYGEN_ONLY(intgr)) noexcept
{
return detail::min_viable_uint_t<detail::size_in_values_v<uint_type>>{detail::size_in_values_v<uint_type>};
}

/*!\brief Converting uint to char casts to a character type of same size.
* \tparam uint_type One of `uint8_t`, `uint16_t` or `uint32_t`.
* \param intgr The alphabet letter that you wish to convert to char.
* \returns The letter's value in the alphabet's rank type (usually `uint`).
/*!\brief Alphabet specific customisations for unsigned integral types.
* \tparam uint_type Any of `uint8_t`, `uint16_t` and `uint32_t`.
* \ingroup adaptation
*/
template <typename uint_type>
//!\cond
requires detail::is_uint_adaptation_v<uint_type>
requires seqan3::detail::is_uint_adaptation_v<uint_type>
//!\endcond
constexpr auto to_char(uint_type const intgr) noexcept
struct alphabet<uint_type>
{
if constexpr (std::Same<uint_type, uint8_t>)
return static_cast<char>(intgr);
else if constexpr (std::Same<uint_type, uint16_t>)
return static_cast<char16_t>(intgr);
else
return static_cast<char32_t>(intgr);
}
//!\brief Return the number of values the uint type can take (e.g. 256 for `uint8_t`).
static constexpr auto alphabet_size =
detail::min_viable_uint_t<detail::size_in_values_v<uint_type>>{detail::size_in_values_v<uint_type>};

/*!\brief Converting uint to rank is a no-op (it will just return the value you pass in).
* \tparam uint_type One of `uint8_t`, `uint16_t` or `uint32_t`.
* \param intgr The alphabet letter that you wish to convert to rank.
* \returns `intgr`.
*/
template <typename uint_type>
//!\cond
requires detail::is_uint_adaptation_v<uint_type>
//!\endcond
constexpr uint_type to_rank(uint_type const intgr) noexcept
{
return intgr;
}
/*!\brief Converting uint to char casts to a character type of same size.
* \param[in] intgr The alphabet letter that you wish to convert to char.
* \returns The letter's value in the alphabet's rank type (usually `uint`).
*/
static constexpr auto to_char(uint_type const intgr) noexcept
{
if constexpr (std::Same<uint_type, uint8_t>)
return static_cast<char>(intgr);
else if constexpr (std::Same<uint_type, uint16_t>)
return static_cast<char16_t>(intgr);
else
return static_cast<char32_t>(intgr);
}

/*!\brief Assign from a character type via implicit or explicit cast.
* \tparam uint_type One of `uint8_t`, `uint16_t` or `uint32_t`.
* \param intgr The alphabet letter that you wish to assign to.
* \param chr The `char` value you wish to assign.
* \returns A reference to the alphabet letter you passed in.
*/
template <typename uint_type>
//!\cond
requires detail::is_uint_adaptation_v<uint_type>
//!\endcond
constexpr uint_type & assign_char_to(decltype(to_char(uint_type{})) const chr, uint_type & intgr) noexcept
{
return intgr = chr;
}
/*!\brief Converting uint to rank is a no-op (it will just return the value you pass in).
* \param[in] intgr The alphabet letter that you wish to convert to rank.
* \returns `intgr`.
*/
static constexpr uint_type to_rank(uint_type const intgr) noexcept
{
return intgr;
}

/*!\brief Assign a rank to to the uint (same as calling `=`).
* \tparam uint_type One of `uint8_t`, `uint16_t` or `uint32_t`.
* \param intgr The alphabet letter that you wish to assign to.
* \param intgr2 The `rank` value you wish to assign.
* \returns A reference to the alphabet letter you passed in.
*/
template <typename uint_type>
//!\cond
requires detail::is_uint_adaptation_v<uint_type>
//!\endcond
constexpr uint_type & assign_rank_to(uint_type const intgr2, uint_type & intgr) noexcept
{
return intgr = intgr2;
}
/*!\brief Assign from a character type via implicit or explicit cast.
* \param[in] chr The `char` value you wish to assign.
* \param[in,out] intgr The alphabet letter that you wish to assign to.
* \returns A reference to the alphabet letter you passed in.
*/
static constexpr uint_type & assign_char_to(decltype(to_char(uint_type{})) const chr, uint_type & intgr) noexcept
{
return intgr = chr;
}

/*!\brief Assign a rank to to the uint (same as calling `=`).
* \param[in] intgr2 The `rank` value you wish to assign.
* \param[in,out] intgr The alphabet letter that you wish to assign to.
* \returns A reference to the alphabet letter you passed in.
*/
static constexpr uint_type & assign_rank_to(uint_type const intgr2, uint_type & intgr) noexcept
{
return intgr = intgr2;
}
};

//!\}
} // namespace seqan3::custom
1 change: 1 addition & 0 deletions include/seqan3/alphabet/cigar/cigar.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

#pragma once

#include <seqan3/alphabet/adaptation/uint.hpp>
#include <seqan3/alphabet/cigar/cigar_op.hpp>
#include <seqan3/alphabet/composite/alphabet_tuple_base.hpp>
#include <seqan3/core/detail/debug_stream_type.hpp>
Expand Down

0 comments on commit 1abf2c5

Please sign in to comment.