diff --git a/CHANGELOG.md b/CHANGELOG.md index 55eadc8b17..7a4260f5fa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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:** diff --git a/doc/about/customisation/index.md b/doc/about/customisation/index.md index 07e4826438..34bc08727b 100644 --- a/doc/about/customisation/index.md +++ b/doc/about/customisation/index.md @@ -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: diff --git a/doc/howto/write_an_alphabet/index.md b/doc/howto/write_an_alphabet/index.md index 1a2e457408..06451fb98a 100644 --- a/doc/howto/write_an_alphabet/index.md +++ b/doc/howto/write_an_alphabet/index.md @@ -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 @@ -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 @@ -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! + diff --git a/include/seqan3/alphabet/adaptation/char.hpp b/include/seqan3/alphabet/adaptation/char.hpp index 98b387cc81..3d2ebab753 100644 --- a/include/seqan3/alphabet/adaptation/char.hpp +++ b/include/seqan3/alphabet/adaptation/char.hpp @@ -27,103 +27,81 @@ #include +#include #include #include namespace seqan3::detail { -//!\addtogroup adaptation -//!\{ - //!\brief Whether a type is `char`, `char16_t`, `char32_t` or `wchar_t` (type trait). -template > -constexpr bool is_char_adaptation_v = std::Same || - std::Same || - std::Same || - std::Same; -//!\} +//!\ingroup adaptation +template +constexpr bool is_char_adaptation_v = std::Same || + std::Same || + std::Same || + std::Same; } // 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 //!\cond - requires seqan3::detail::is_char_adaptation_v +template +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}; -} -/*!\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 //!\cond - requires seqan3::detail::is_char_adaptation_v + requires detail::is_char_adaptation_v //!\endcond -constexpr char_type to_char(char_type const chr) noexcept +struct alphabet { - 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}; -/*!\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 -//!\cond - requires seqan3::detail::is_char_adaptation_v -//!\endcond -constexpr auto to_rank(char_type const chr) noexcept -{ - return static_cast<::seqan3::detail::min_viable_uint_t>(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 -//!\cond - requires detail::is_char_adaptation_v -//!\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>(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 -//!\cond - requires detail::is_char_adaptation_v -//!\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 diff --git a/include/seqan3/alphabet/adaptation/uint.hpp b/include/seqan3/alphabet/adaptation/uint.hpp index 96337eba5c..73754b2ad7 100644 --- a/include/seqan3/alphabet/adaptation/uint.hpp +++ b/include/seqan3/alphabet/adaptation/uint.hpp @@ -27,107 +27,84 @@ #include +#include #include #include namespace seqan3::detail { -//!\addtogroup adaptation -//!\{ - //!\brief Whether a type is `uint8_t`, `uint16_t` or `uint32_t`. -template > -constexpr bool is_uint_adaptation_v = std::Same || - std::Same || - std::Same; -//!\} +//!\ingroup adaptation +template +constexpr bool is_uint_adaptation_v = std::Same || + std::Same || + std::Same; } // 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 //!\cond - requires ::seqan3::detail::is_uint_adaptation_v +template +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}; -} -/*!\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 //!\cond - requires detail::is_uint_adaptation_v + requires seqan3::detail::is_uint_adaptation_v //!\endcond -constexpr auto to_char(uint_type const intgr) noexcept +struct alphabet { - if constexpr (std::Same) - return static_cast(intgr); - else if constexpr (std::Same) - return static_cast(intgr); - else - return static_cast(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}; -/*!\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 -//!\cond - requires detail::is_uint_adaptation_v -//!\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) + return static_cast(intgr); + else if constexpr (std::Same) + return static_cast(intgr); + else + return static_cast(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 -//!\cond - requires detail::is_uint_adaptation_v -//!\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 -//!\cond - requires detail::is_uint_adaptation_v -//!\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 diff --git a/include/seqan3/alphabet/cigar/cigar.hpp b/include/seqan3/alphabet/cigar/cigar.hpp index ac483525ed..d443f384e1 100644 --- a/include/seqan3/alphabet/cigar/cigar.hpp +++ b/include/seqan3/alphabet/cigar/cigar.hpp @@ -12,6 +12,7 @@ #pragma once +#include #include #include #include diff --git a/include/seqan3/alphabet/concept.hpp b/include/seqan3/alphabet/concept.hpp index 9c4e12cf2d..74600795be 100644 --- a/include/seqan3/alphabet/concept.hpp +++ b/include/seqan3/alphabet/concept.hpp @@ -12,8 +12,6 @@ #pragma once -#include -#include #include #include #include @@ -23,20 +21,67 @@ #include #include +// ============================================================================ +// forwards +// ============================================================================ + +namespace seqan3::custom +{ + +/*!\brief A type that can be specialised to provide customisation point implementations so that third party types + * model alphabet concepts. + * \tparam t The type you wish to specialise for. + * \ingroup alphabet + * + * \details + * + * For examples of when and how you can make use of this type, please see \link about_customisation the page on + * customisation \endlink and the \link howto_write_an_alphabet_custom section on third party types \endlink in + * the Alphabet HowTo. + * + * Please note that by default the `t const`, `t &` and `t const &` specialisations of this class inherit the + * specialisation for `t` so you usually only need to provide a specialisation for `t`. + * + * \note Only use this, if you cannot provide respective functions in your namespace. + */ +template +struct alphabet +{}; + +//!\cond +template +struct alphabet : alphabet +{}; + +template +struct alphabet : alphabet +{}; + +template +struct alphabet : alphabet +{}; +//!\endcond + +} // namespace seqan3::custom + // ============================================================================ // to_rank() // ============================================================================ -namespace seqan3::detail::adl::only +namespace seqan3::detail::adl_only { +//!\brief Poison-pill overload to prevent non-ADL forms of unqualified lookup. +template +void to_rank(args_t ...) = delete; + //!\brief Functor definition for seqan3::to_rank. struct to_rank_fn { private: - SEQAN3_CPO_IMPL(2, to_rank(v) ) // ADL - SEQAN3_CPO_IMPL(1, seqan3::custom::to_rank(v) ) // customisation namespace - SEQAN3_CPO_IMPL(0, v.to_rank() ) // member + SEQAN3_CPO_IMPL(2, seqan3::custom::alphabet::to_rank(v)) // explicit customisation + SEQAN3_CPO_IMPL(1, to_rank(v) ) // ADL + SEQAN3_CPO_IMPL(0, v.to_rank() ) // member public: //!\brief Operator definition. @@ -55,7 +100,7 @@ struct to_rank_fn } }; -} // namespace seqan3::detail::adl::only +} // namespace seqan3::detail::adl_only namespace seqan3 { @@ -75,8 +120,8 @@ namespace seqan3 * * It acts as a wrapper and looks for three possible implementations (in this order): * - * 1. A free function `to_rank(your_type const a)` in the namespace of your type (or as `friend`). - * 2. A free function `to_rank(your_type const a)` in `namespace seqan3::custom`. + * 1. A static member function `to_rank(your_type const a)` of the class `seqan3::custom::alphabet`. + * 2. A free function `to_rank(your_type const a)` in the namespace of your type (or as `friend`). * 3. A member function called `to_rank()`. * * Functions are only considered for one of the above cases if they are marked `noexcept` (`constexpr` is not required, @@ -96,7 +141,7 @@ namespace seqan3 * This is a customisation point (see \ref about_customisation). To specify the behaviour for your own alphabet type, * simply provide one of the three functions specified above. */ -inline constexpr auto to_rank = detail::adl::only::to_rank_fn{}; +inline constexpr auto to_rank = detail::adl_only::to_rank_fn{}; //!\} //!\brief The `rank_type` of the semi-alphabet; defined as the return type of seqan3::to_rank. @@ -113,17 +158,21 @@ using alphabet_rank_t = decltype(seqan3::to_rank(std::declval +void assign_rank_to(args_t ...) = delete; + //!\brief Functor definition for seqan3::assign_rank_to. //!\ingroup alphabet struct assign_rank_to_fn { private: - SEQAN3_CPO_IMPL(2, (assign_rank_to(args..., v) )) // ADL - SEQAN3_CPO_IMPL(1, (seqan3::custom::assign_rank_to(args..., v) )) // customisation namespace - SEQAN3_CPO_IMPL(0, (v.assign_rank(args...) )) // member + SEQAN3_CPO_IMPL(2, (seqan3::custom::alphabet::assign_rank_to(args..., v))) // explicit customisation + SEQAN3_CPO_IMPL(1, (assign_rank_to(args..., v) )) // ADL + SEQAN3_CPO_IMPL(0, (v.assign_rank(args...) )) // member public: //!\brief Operator definition. @@ -142,7 +191,7 @@ struct assign_rank_to_fn } }; -} // namespace seqan3::detail::adl::only +} // namespace seqan3::detail::adl_only namespace seqan3 { @@ -164,10 +213,10 @@ namespace seqan3 * * It acts as a wrapper and looks for three possible implementations (in this order): * - * 1. A free function `assign_rank_to(rank_type const chr, your_type & a)` in the namespace of your + * 1. A static member function `assign_rank_to(rank_type const chr, your_type & a)` of the class + * `seqan3::custom::alphabet`. + * 2. A free function `assign_rank_to(rank_type const chr, your_type & a)` in the namespace of your * type (or as `friend`). - * 2. A free function `assign_rank_to(rank_type const chr, your_type & a)` in - * `namespace seqan3::custom`. * 3. A member function called `assign_rank(rank_type const chr)` (not `assign_rank_to`). * * Functions are only considered for one of the above cases if they are marked `noexcept` (`constexpr` is not required, @@ -188,7 +237,7 @@ namespace seqan3 * This is a customisation point (see \ref about_customisation). To specify the behaviour for your own alphabet type, * simply provide one of the three functions specified above. */ -inline constexpr auto assign_rank_to = detail::adl::only::assign_rank_to_fn{}; +inline constexpr auto assign_rank_to = detail::adl_only::assign_rank_to_fn{}; //!\} } // namespace seqan3 @@ -196,16 +245,20 @@ inline constexpr auto assign_rank_to = detail::adl::only::assign_rank_to_fn{}; // to_char() // ============================================================================ -namespace seqan3::detail::adl::only +namespace seqan3::detail::adl_only { +//!\brief Poison-pill overload to prevent non-ADL forms of unqualified lookup. +template +void to_char(args_t ...) = delete; + //!\brief Functor definition for seqan3::to_char. struct to_char_fn { private: - SEQAN3_CPO_IMPL(2, to_char(v) ) // ADL - SEQAN3_CPO_IMPL(1, seqan3::custom::to_char(v) ) // customisation namespace - SEQAN3_CPO_IMPL(0, v.to_char() ) // member + SEQAN3_CPO_IMPL(2, seqan3::custom::alphabet::to_char(v)) // explicit customisation + SEQAN3_CPO_IMPL(1, to_char(v) ) // ADL + SEQAN3_CPO_IMPL(0, v.to_char() ) // member public: //!\brief Operator definition. @@ -223,7 +276,7 @@ struct to_char_fn } }; -} // namespace seqan3::detail::adl::only +} // namespace seqan3::detail::adl_only namespace seqan3 { @@ -244,8 +297,8 @@ namespace seqan3 * * It acts as a wrapper and looks for three possible implementations (in this order): * + * 2. A static member function `to_char(your_type const a)` of the class `seqan3::custom::alphabet`. * 1. A free function `to_char(your_type const a)` in the namespace of your type (or as `friend`). - * 2. A free function `to_char(your_type const a)` in `namespace seqan3::custom`. * 3. A member function called `to_char()`. * * Functions are only considered for one of the above cases if they are marked `noexcept` (`constexpr` is not required, @@ -265,7 +318,7 @@ namespace seqan3 * This is a customisation point (see \ref about_customisation). To specify the behaviour for your own alphabet type, * simply provide one of the three functions specified above. */ -inline constexpr auto to_char = detail::adl::only::to_char_fn{}; +inline constexpr auto to_char = detail::adl_only::to_char_fn{}; //!\} //!\brief The `char_type` of the alphabet; defined as the return type of seqan3::to_char. @@ -282,23 +335,21 @@ using alphabet_char_t = decltype(seqan3::to_char(std::declval +void assign_char_to(args_t ...) = delete; + //!\brief Functor definition for seqan3::assign_char_to. //!\ingroup alphabet struct assign_char_to_fn { private: - SEQAN3_CPO_IMPL(2, (assign_char_to(args..., v) )) // ADL - SEQAN3_CPO_IMPL(1, (seqan3::custom::assign_char_to(args..., v) )) // customisation namespace - SEQAN3_CPO_IMPL(0, (v.assign_char(args...) )) // member + SEQAN3_CPO_IMPL(2, (seqan3::custom::alphabet::assign_char_to(args..., v))) // explicit customisation + SEQAN3_CPO_IMPL(1, (assign_char_to(args..., v) )) // ADL + SEQAN3_CPO_IMPL(0, (v.assign_char(args...) )) // member public: //!\brief Operator definition. @@ -317,7 +368,7 @@ struct assign_char_to_fn } }; -} // namespace seqan3::detail::adl::only +} // namespace seqan3::detail::adl_only namespace seqan3 { @@ -339,10 +390,10 @@ namespace seqan3 * * It acts as a wrapper and looks for three possible implementations (in this order): * - * 1. A free function `assign_char_to(char_type const chr, your_type & a)` in the namespace of your + * 1. A static member function `assign_char_to(char_type const chr, your_type & a)` + * of the class `seqan3::custom::alphabet`. + * 2. A free function `assign_char_to(char_type const chr, your_type & a)` in the namespace of your * type (or as `friend`). - * 2. A free function `assign_char_to(char_type const chr, your_type & a)` in - * `namespace seqan3::custom`. * 3. A member function called `assign_char(char_type const chr)` (not `assign_char_to`). * * Functions are only considered for one of the above cases if they are marked `noexcept` (`constexpr` is not required, @@ -363,7 +414,7 @@ namespace seqan3 * This is a customisation point (see \ref about_customisation). To specify the behaviour for your own alphabet type, * simply provide one of the three functions specified above. */ -inline constexpr auto assign_char_to = detail::adl::only::assign_char_to_fn{}; +inline constexpr auto assign_char_to = detail::adl_only::assign_char_to_fn{}; //!\} } // namespace seqan3 @@ -371,31 +422,30 @@ inline constexpr auto assign_char_to = detail::adl::only::assign_char_to_fn{}; // char_is_valid_for() // ============================================================================ -namespace seqan3::custom +namespace seqan3::detail::adl_only { -//!\cond -void char_is_valid_for(); // forward -//!\endcond -} // seqan3::custom -namespace seqan3::detail::adl::only -{ +//!\brief Poison-pill overload to prevent non-ADL forms of unqualified lookup. +template +void char_is_valid_for(args_t ...) = delete; + /*!\brief Functor definition for seqan3::char_is_valid_for. * \tparam alph_t The alphabet type being queried. - * \tparam s_alph_t `alph_t` with cvref removed and possibly wrapped in std::type_identity; never user-provide this! * \ingroup alphabet */ -template >, - remove_cvref_t, - std::type_identity>> +template struct char_is_valid_for_fn { private: - SEQAN3_CPO_IMPL(3, (char_is_valid_for(v, s_alph_t{}) )) // ADL - SEQAN3_CPO_IMPL(2, (seqan3::custom::char_is_valid_for(v, s_alph_t{}) )) // customisation ns - SEQAN3_CPO_IMPL(1, (deferred_type_t, decltype(v)>::char_is_valid(v) )) // member - SEQAN3_CPO_IMPL(0, (to_char(assign_char_to(v, s_alph_t{})) == v )) // fallback + //!\brief `alph_t` with cvref removed and possibly wrapped in std::type_identity. + using s_alph_t = std::conditional_t>, + remove_cvref_t, + std::type_identity>; + + SEQAN3_CPO_IMPL(3, (deferred_type_t, decltype(v)>::char_is_valid(v))) // expl. cst. + SEQAN3_CPO_IMPL(2, (char_is_valid_for(v, s_alph_t{}) )) // ADL + SEQAN3_CPO_IMPL(1, (deferred_type_t, decltype(v)>::char_is_valid(v) )) // member + SEQAN3_CPO_IMPL(0, (seqan3::to_char(seqan3::assign_char_to(v, s_alph_t{})) == v )) // fallback public: //!\brief Operator definition. @@ -414,7 +464,7 @@ struct char_is_valid_for_fn } }; -} // namespace seqan3::detail::adl::only +} // namespace seqan3::detail::adl_only namespace seqan3 { @@ -437,14 +487,13 @@ namespace seqan3 * * It acts as a wrapper and looks for three possible implementations (in this order): * - * 1. A free function `char_is_valid_for(char_type const chr, your_type const &)` in the namespace of your + * 1. A static member function `char_is_valid(char_type const chr)` of the class `seqan3::custom::alphabet`. + * 2. A free function `char_is_valid_for(char_type const chr, your_type const &)` in the namespace of your * type (or as `friend`). - * 2. A free function `char_is_valid_for(char_type const chr, your_type const &)` in - * `namespace seqan3::custom`. * 3. A `static` member function called `char_is_valid(char_type)` (not `char_is_valid_for`). * * Functions are only considered for one of the above cases if they are marked `noexcept` (`constexpr` is not required, - * but recommended) and if the returned type is convertible to `bool`. For 1. and 2. the value of the second argument + * but recommended) and if the returned type is convertible to `bool`. For 2. the value of the second argument * to the function shall be ignored, it is only used to select the function via * [argument-dependent lookup](https://en.cppreference.com/w/cpp/language/adl). * @@ -454,7 +503,7 @@ namespace seqan3 * * *Note* that if the alphabet type with cvref removed is not std::is_nothrow_default_constructible, this function * object will instead look for `char_is_valid_for(char_type const chr, std::type_identity const &)` - * with the same semantics. In that case the "fallback" above also does not work and you are required to provide + * in case 2. In that case the "fallback" above also does not work and you are required to provide * such an implementation. * * ### Example @@ -470,7 +519,7 @@ template //!\cond requires requires { { to_char(std::declval()) }; } // to_char() is required by some defs //!\endcond -inline constexpr auto char_is_valid_for = detail::adl::only::char_is_valid_for_fn{}; +inline constexpr auto char_is_valid_for = detail::adl_only::char_is_valid_for_fn{}; //!\} } // namespace seqan3 @@ -478,7 +527,7 @@ inline constexpr auto char_is_valid_for = detail::adl::only::char_is_valid_for_f // assign_char_strictly_to() // ============================================================================ -namespace seqan3::detail::adl::only +namespace seqan3::detail::adl_only { //!\brief Functor definition for seqan3::assign_char_strictly_to. @@ -517,7 +566,7 @@ struct assign_char_strictly_to_fn } }; -} // namespace seqan3::detail::adl::only +} // namespace seqan3::detail::adl_only namespace seqan3 { @@ -546,7 +595,7 @@ namespace seqan3 * \include test/snippet/alphabet/assign_char_strictly_to.cpp * */ -inline constexpr auto assign_char_strictly_to = detail::adl::only::assign_char_strictly_to_fn{}; +inline constexpr auto assign_char_strictly_to = detail::adl_only::assign_char_strictly_to_fn{}; //!\} } // namespace seqan3 @@ -554,24 +603,30 @@ inline constexpr auto assign_char_strictly_to = detail::adl::only::assign_char_s // alphabet_size // ============================================================================ -namespace seqan3::detail::adl::only +namespace seqan3::detail::adl_only { + +//!\brief Poison-pill overload to prevent non-ADL forms of unqualified lookup. +template +void alphabet_size(args_t ...) = delete; + /*!\brief Functor definition used indirectly by for seqan3::detail::alphabet_size. * \tparam alph_t The type being queried. - * \tparam s_alph_t `alph_t` with cvref removed and possibly wrapped in std::type_identity; never user-provide this! * \ingroup alphabet */ -template > && - seqan3::is_constexpr_default_constructible_v>, - remove_cvref_t, - std::type_identity>> +template struct alphabet_size_fn { private: - SEQAN3_CPO_IMPL(2, (alphabet_size(v) )) // ADL - SEQAN3_CPO_IMPL(1, (seqan3::custom::alphabet_size(v) )) // customisation namespace - SEQAN3_CPO_IMPL(0, (deferred_type_t, decltype(v)>::alphabet_size )) // member + //!\brief `alph_t` with cvref removed and possibly wrapped in std::type_identity. + using s_alph_t = std::conditional_t> && + seqan3::is_constexpr_default_constructible_v>, + remove_cvref_t, + std::type_identity>; + + SEQAN3_CPO_IMPL(2, (deferred_type_t, decltype(v)>::alphabet_size)) // expl. cst. + SEQAN3_CPO_IMPL(1, (alphabet_size(v) )) // ADL + SEQAN3_CPO_IMPL(0, (deferred_type_t, decltype(v)>::alphabet_size )) // member public: //!\brief Operator definition. @@ -601,7 +656,7 @@ template inline constexpr auto alphabet_size_obj = alphabet_size_fn{}; //!\endcond -} // namespace seqan3::detail::adl::only +} // namespace seqan3::detail::adl_only namespace seqan3 { @@ -616,14 +671,13 @@ namespace seqan3 * * It is only defined for types that provide one of the following (checked in this order): * - * 1. A free function `alphabet_size(your_type const &)` in the namespace of your type (or as `friend`) that + * 3. A `static constexpr` data member of `seqan3::custom::alphabet` called `alphabet_size`. + * 2. A free function `alphabet_size(your_type const &)` in the namespace of your type (or as `friend`) that * returns the size. - * 2. A free function `alphabet_size(your_type const &)` in `namespace seqan3::custom` that returns - * the size. - * 3. A `static constexpr` data member called `alphabet_size` that is the size. + * 3. A `static constexpr` data member of `your_type` called `alphabet_size`. * * Functions are only considered for one of the above cases if they are marked `noexcept` **and** `constexpr` and - * if the returned type models std::Integral. For 1. and 2. the value of the argument to the function shall be + * if the returned type models std::Integral. For 2. the value of the argument to the function shall be * ignored, the argument is only used to select the function via * [argument-dependent lookup](https://en.cppreference.com/w/cpp/language/adl). * @@ -631,7 +685,7 @@ namespace seqan3 * * *Note* that if the (semi-)alphabet type with cvref removed is not std::is_nothrow_default_constructible or not * seqan3::is_constexpr_default_constructible, this object will instead look for - * `alphabet_size(std::type_identity const &)` with the same semantics (in cases 1. and 2.). + * `alphabet_size(std::type_identity const &)` with the same semantics (in case 2.). * * ### Example * @@ -647,10 +701,10 @@ namespace seqan3 */ template //!\cond - requires requires { { detail::adl::only::alphabet_size_fn{} }; } && - requires { { detail::adl::only::alphabet_size_obj() }; } // ICE workarounds + requires requires { { detail::adl_only::alphabet_size_fn{} }; } && + requires { { detail::adl_only::alphabet_size_obj() }; } // ICE workarounds //!\endcond -inline constexpr auto alphabet_size = detail::adl::only::alphabet_size_obj(); +inline constexpr auto alphabet_size = detail::adl_only::alphabet_size_obj(); // ============================================================================ // Semialphabet diff --git a/include/seqan3/alphabet/nucleotide/concept.hpp b/include/seqan3/alphabet/nucleotide/concept.hpp index 279b882cd2..8213753b59 100644 --- a/include/seqan3/alphabet/nucleotide/concept.hpp +++ b/include/seqan3/alphabet/nucleotide/concept.hpp @@ -16,33 +16,24 @@ #include #include -// ============================================================================ -// forwards -// ============================================================================ - -//!\cond -namespace seqan3::custom -{ - -void complement(); - -} // namespace seqan3::custom -//!\endcond - // ============================================================================ // complement() // ============================================================================ -namespace seqan3::detail::adl::only +namespace seqan3::detail::adl_only { +//!\brief Poison-pill overload to prevent non-ADL forms of unqualified lookup. +template +void complement(args_t ...) = delete; + //!\brief Functor definition for seqan3::complement. struct complement_fn { private: - SEQAN3_CPO_IMPL(2, complement(v) ) // ADL - SEQAN3_CPO_IMPL(1, seqan3::custom::complement(v) ) // customisation namespace - SEQAN3_CPO_IMPL(0, v.complement() ) // member + SEQAN3_CPO_IMPL(2, seqan3::custom::alphabet::complement(v)) // explicit customisation + SEQAN3_CPO_IMPL(1, complement(v) ) // ADL + SEQAN3_CPO_IMPL(0, v.complement() ) // member public: //!\brief Operator definition. @@ -61,7 +52,7 @@ struct complement_fn } }; -} // namespace seqan3::detail::adl::only +} // namespace seqan3::detail::adl_only namespace seqan3 { @@ -81,8 +72,8 @@ namespace seqan3 * * It acts as a wrapper and looks for three possible implementations (in this order): * - * 1. A free function `complement(your_type const a)` in the namespace of your type (or as `friend`). - * 2. A free function `complement(your_type const a)` in `namespace seqan3::custom`. + * 1. A static member function `complement(your_type const a)` of the class `seqan3::custom::alphabet`. + * 2. A free function `complement(your_type const a)` in the namespace of your type (or as `friend`). * 3. A member function called `complement()`. * * Functions are only considered for one of the above cases if they are marked `noexcept` (`constexpr` is not required, @@ -99,7 +90,7 @@ namespace seqan3 * This is a customisation point (see \ref about_customisation). To specify the behaviour for your own alphabet type, * simply provide one of the three functions specified above. */ -inline constexpr auto complement = detail::adl::only::complement_fn{}; +inline constexpr auto complement = detail::adl_only::complement_fn{}; //!\} // ============================================================================ diff --git a/include/seqan3/alphabet/quality/concept.hpp b/include/seqan3/alphabet/quality/concept.hpp index dd2cb1e9e7..b7a2b849d7 100644 --- a/include/seqan3/alphabet/quality/concept.hpp +++ b/include/seqan3/alphabet/quality/concept.hpp @@ -15,34 +15,24 @@ #include -// ============================================================================ -// forwards -// ============================================================================ - -//!\cond -namespace seqan3::custom -{ - -void to_phred(); -void assign_phred_to(); - -} // namespace seqan3::custom -//!\endcond - // ============================================================================ // to_phred() // ============================================================================ -namespace seqan3::detail::adl::only +namespace seqan3::detail::adl_only { +//!\brief Poison-pill overload to prevent non-ADL forms of unqualified lookup. +template +void to_phred(args_t ...) = delete; + //!\brief Functor definition for seqan3::to_phred. struct to_phred_fn { private: - SEQAN3_CPO_IMPL(2, to_phred(v) ) // ADL - SEQAN3_CPO_IMPL(1, seqan3::custom::to_phred(v) ) // customisation namespace - SEQAN3_CPO_IMPL(0, v.to_phred() ) // member + SEQAN3_CPO_IMPL(2, seqan3::custom::alphabet::to_phred(v)) // explicit customisation + SEQAN3_CPO_IMPL(1, to_phred(v) ) // ADL + SEQAN3_CPO_IMPL(0, v.to_phred() ) // member public: //!\brief Operator definition. @@ -61,7 +51,7 @@ struct to_phred_fn } }; -} // namespace seqan3::detail::adl::only +} // namespace seqan3::detail::adl_only namespace seqan3 { @@ -82,14 +72,12 @@ namespace seqan3 * * It acts as a wrapper and looks for three possible implementations (in this order): * - * 1. A free function `to_phred(your_type const a)` in the namespace of your type (or as `friend`). - * The function must be marked `noexcept` (`constexpr` is not required, but recommended) and the - * return type be of the respective phred representation (usually a small integral type). - * 2. A free function `to_phred(your_type const a)` in `namespace seqan3::custom`. - * The same restrictions apply as above. + * 1. A static member function `to_phred(your_type const a)` of the class `seqan3::custom::alphabet`. + * 2. A free function `to_phred(your_type const a)` in the namespace of your type (or as `friend`). * 3. A member function called `to_phred()`. - * It must be marked `noexcept` (`constexpr` is not required, but recommended) and the return type be of - * the respective rank representation. + * + * Functions are only considered for one of the above cases if they are marked `noexcept` (`constexpr` is not required, + * but recommended) and if the returned type is convertible to `size_t`. * * Every quality alphabet type must provide one of the above. * @@ -98,7 +86,7 @@ namespace seqan3 * This is a customisation point (see \ref about_customisation). To specify the behaviour for your own alphabet type, * simply provide one of the three functions specified above. */ -inline constexpr auto to_phred = detail::adl::only::to_phred_fn{}; +inline constexpr auto to_phred = detail::adl_only::to_phred_fn{}; //!\} /*!\brief The `phred_type` of the alphabet; defined as the return type of seqan3::to_phred. @@ -116,17 +104,21 @@ using alphabet_phred_t = decltype(seqan3::to_phred(std::declval() // assign_phred_to() // ============================================================================ -namespace seqan3::detail::adl::only +namespace seqan3::detail::adl_only { +//!\brief Poison-pill overload to prevent non-ADL forms of unqualified lookup. +template +void assign_phred_to(args_t ...) = delete; + //!\brief Functor definition for seqan3::assign_phred_to. //!\ingroup quality struct assign_phred_to_fn { private: - SEQAN3_CPO_IMPL(2, (assign_phred_to(args..., v) )) // ADL - SEQAN3_CPO_IMPL(1, (seqan3::custom::assign_phred_to(args..., v) )) // customisation namespace - SEQAN3_CPO_IMPL(0, (v.assign_phred(args...) )) // member + SEQAN3_CPO_IMPL(2, (seqan3::custom::alphabet::assign_phred_to(args..., v))) // explicit customisation + SEQAN3_CPO_IMPL(1, (assign_phred_to(args..., v) )) // ADL + SEQAN3_CPO_IMPL(0, (v.assign_phred(args...) )) // member public: //!\brief Operator definition for lvalues. @@ -157,7 +149,7 @@ struct assign_phred_to_fn } }; -} // namespace seqan3::detail::adl::only +} // namespace seqan3::detail::adl_only namespace seqan3 { @@ -177,15 +169,14 @@ namespace seqan3 * * It acts as a wrapper and looks for three possible implementations (in this order): * - * 1. A free function `assign_phred_to(phred_type const chr, your_type & a)` in the namespace of your type + * 1. A static member function `assign_phred_to(phred_type const chr, your_type & a)` + * of the class `seqan3::custom::alphabet`. + * 2. A free function `assign_phred_to(phred_type const chr, your_type & a)` in the namespace of your type * (or as `friend`). - * The function must be marked `noexcept` (`constexpr` is not required, but recommended) and the - * return type be `your_type &`. - * 2. A free function `assign_phred_to(phred_type const chr, your_type & a)` in - * `namespace seqan3::custom`. The same restrictions apply as above. * 3. A member function called `assign_phred(phred_type const chr)` (not `assign_phred_to`). - * It must be marked `noexcept` (`constexpr` is not required, but recommended) and the return type be - * `your_type &`. + * + * Functions are only considered for one of the above cases if they are marked `noexcept` (`constexpr` is not required, + * but recommended) and if the returned type is `your_type &`. * * Every writable quality alphabet type must provide one of the above. *Note* that temporaries of `your_type` * are handled by this function object and **do not** require an additional overload. @@ -195,7 +186,7 @@ namespace seqan3 * This is a customisation point (see \ref about_customisation). To specify the behaviour for your own alphabet type, * simply provide one of the three functions specified above. */ -inline constexpr auto assign_phred_to = detail::adl::only::assign_phred_to_fn{}; +inline constexpr auto assign_phred_to = detail::adl_only::assign_phred_to_fn{}; //!\} } // namespace seqan3 diff --git a/include/seqan3/alphabet/structure/concept.hpp b/include/seqan3/alphabet/structure/concept.hpp index 906dea5493..73dc89c21a 100644 --- a/include/seqan3/alphabet/structure/concept.hpp +++ b/include/seqan3/alphabet/structure/concept.hpp @@ -18,37 +18,24 @@ #include #include -// ============================================================================ -// forwards -// ============================================================================ - -//!\cond -namespace seqan3::custom -{ - -void is_pair_open(); -void is_pair_close(); -void is_unpaired(); -void max_pseudoknot_depth(); -void pseudoknot_id(); - -} // namespace seqan3::custom -//!\endcond - // ============================================================================ // is_pair_open() // ============================================================================ -namespace seqan3::detail::adl::only +namespace seqan3::detail::adl_only { +//!\brief Poison-pill overload to prevent non-ADL forms of unqualified lookup. +template +void is_pair_open(args_t ...) = delete; + //!\brief Functor definition for seqan3::is_pair_open. struct is_pair_open_fn { private: - SEQAN3_CPO_IMPL(2, is_pair_open(v) ) // ADL - SEQAN3_CPO_IMPL(1, seqan3::custom::is_pair_open(v) ) // customisation namespace - SEQAN3_CPO_IMPL(0, v.is_pair_open() ) // member + SEQAN3_CPO_IMPL(2, seqan3::custom::alphabet::is_pair_open(v)) // explicit customisation + SEQAN3_CPO_IMPL(1, is_pair_open(v) ) // ADL + SEQAN3_CPO_IMPL(0, v.is_pair_open() ) // member public: //!\brief Operator definition. @@ -67,7 +54,7 @@ struct is_pair_open_fn } }; -} // namespace seqan3::detail::adl::only +} // namespace seqan3::detail::adl_only namespace seqan3 { @@ -87,14 +74,12 @@ namespace seqan3 * * It acts as a wrapper and looks for three possible implementations (in this order): * - * 1. A free function `is_pair_open(your_type const a)` in the namespace of your type (or as `friend`). - * The function must be marked `noexcept` (`constexpr` is not required, but recommended) and the - * return type be `bool`. - * 2. A free function `is_pair_open(your_type const a)` in `namespace seqan3::custom`. - * The same restrictions apply as above. + * 1. A static member function `is_pair_open(your_type const a)` of the class `seqan3::custom::alphabet`. + * 2. A free function `is_pair_open(your_type const a)` in the namespace of your type (or as `friend`). * 3. A member function called `is_pair_open()`. - * It must be marked `noexcept` (`constexpr` is not required, but recommended) and the return type be - * `bool`. + * + * Functions are only considered for one of the above cases if they are marked `noexcept` (`constexpr` is not required, + * but recommended) and if the returned type is `bool. * * Every RNA structure alphabet type must provide one of the above. * @@ -107,7 +92,7 @@ namespace seqan3 * This is a customisation point (see \ref about_customisation). To specify the behaviour for your own alphabet type, * simply provide one of the three functions specified above. */ -inline constexpr auto is_pair_open = detail::adl::only::is_pair_open_fn{}; +inline constexpr auto is_pair_open = detail::adl_only::is_pair_open_fn{}; //!\} } // namespace seqan3 @@ -116,16 +101,20 @@ inline constexpr auto is_pair_open = detail::adl::only::is_pair_open_fn{}; // is_pair_close() // ============================================================================ -namespace seqan3::detail::adl::only +namespace seqan3::detail::adl_only { +//!\brief Poison-pill overload to prevent non-ADL forms of unqualified lookup. +template +void is_pair_close(args_t ...) = delete; + //!\brief Functor definition for seqan3::is_pair_close. struct is_pair_close_fn { private: - SEQAN3_CPO_IMPL(2, is_pair_close(v) ) // ADL - SEQAN3_CPO_IMPL(1, seqan3::custom::is_pair_close(v) ) // customisation namespace - SEQAN3_CPO_IMPL(0, v.is_pair_close() ) // member + SEQAN3_CPO_IMPL(2, seqan3::custom::alphabet::is_pair_close(v)) // explicit customisation + SEQAN3_CPO_IMPL(1, is_pair_close(v) ) // ADL + SEQAN3_CPO_IMPL(0, v.is_pair_close() ) // member public: //!\brief Operator definition. @@ -144,7 +133,7 @@ struct is_pair_close_fn } }; -} // namespace seqan3::detail::adl::only +} // namespace seqan3::detail::adl_only namespace seqan3 { @@ -164,14 +153,12 @@ namespace seqan3 * * It acts as a wrapper and looks for three possible implementations (in this order): * - * 1. A free function `is_pair_close(your_type const a)` in the namespace of your type (or as `friend`). - * The function must be marked `noexcept` (`constexpr` is not required, but recommended) and the - * return type be `bool`. - * 2. A free function `is_pair_close(your_type const a)` in `namespace seqan3::custom`. - * The same restrictions apply as above. + * 1. A static member function `is_pair_close(your_type const a)` of the class `seqan3::custom::alphabet`. + * 2. A free function `is_pair_close(your_type const a)` in the namespace of your type (or as `friend`). * 3. A member function called `is_pair_close()`. - * It must be marked `noexcept` (`constexpr` is not required, but recommended) and the return type be - * `bool`. + * + * Functions are only considered for one of the above cases if they are marked `noexcept` (`constexpr` is not required, + * but recommended) and if the returned type is `bool. * * Every RNA structure alphabet type must provide one of the above. * @@ -184,7 +171,7 @@ namespace seqan3 * This is a customisation point (see \ref about_customisation). To specify the behaviour for your own alphabet type, * simply provide one of the three functions specified above. */ -inline constexpr auto is_pair_close = detail::adl::only::is_pair_close_fn{}; +inline constexpr auto is_pair_close = detail::adl_only::is_pair_close_fn{}; //!\} } // namespace seqan3 @@ -193,16 +180,20 @@ inline constexpr auto is_pair_close = detail::adl::only::is_pair_close_fn{}; // is_unpaired() // ============================================================================ -namespace seqan3::detail::adl::only +namespace seqan3::detail::adl_only { +//!\brief Poison-pill overload to prevent non-ADL forms of unqualified lookup. +template +void is_unpaired(args_t ...) = delete; + //!\brief Functor definition for seqan3::is_unpaired. struct is_unpaired_fn { private: - SEQAN3_CPO_IMPL(2, is_unpaired(v) ) // ADL - SEQAN3_CPO_IMPL(1, seqan3::custom::is_unpaired(v) ) // customisation namespace - SEQAN3_CPO_IMPL(0, v.is_unpaired() ) // member + SEQAN3_CPO_IMPL(2, seqan3::custom::alphabet::is_unpaired(v)) // explicit customisation + SEQAN3_CPO_IMPL(1, is_unpaired(v) ) // ADL + SEQAN3_CPO_IMPL(0, v.is_unpaired() ) // member public: //!\brief Operator definition. @@ -221,7 +212,7 @@ struct is_unpaired_fn } }; -} // namespace seqan3::detail::adl::only +} // namespace seqan3::detail::adl_only namespace seqan3 { @@ -241,14 +232,12 @@ namespace seqan3 * * It acts as a wrapper and looks for three possible implementations (in this order): * - * 1. A free function `is_unpaired(your_type const a)` in the namespace of your type (or as `friend`). - * The function must be marked `noexcept` (`constexpr` is not required, but recommended) and the - * return type be `bool`. - * 2. A free function `is_unpaired(your_type const a)` in `namespace seqan3::custom`. - * The same restrictions apply as above. + * 1. A static member function `is_unpaired(your_type const a)` of the class `seqan3::custom::alphabet`. + * 2. A free function `is_unpaired(your_type const a)` in the namespace of your type (or as `friend`). * 3. A member function called `is_unpaired()`. - * It must be marked `noexcept` (`constexpr` is not required, but recommended) and the return type be - * `bool`. + * + * Functions are only considered for one of the above cases if they are marked `noexcept` (`constexpr` is not required, + * but recommended) and if the returned type is `bool. * * Every RNA structure alphabet type must provide one of the above. * @@ -261,7 +250,7 @@ namespace seqan3 * This is a customisation point (see \ref about_customisation). To specify the behaviour for your own alphabet type, * simply provide one of the three functions specified above. */ -inline constexpr auto is_unpaired = detail::adl::only::is_unpaired_fn{}; +inline constexpr auto is_unpaired = detail::adl_only::is_unpaired_fn{}; //!\} } // namespace seqan3 @@ -270,9 +259,13 @@ inline constexpr auto is_unpaired = detail::adl::only::is_unpaired_fn{}; // max_pseudoknot_depth // ============================================================================ -namespace seqan3::detail::adl::only +namespace seqan3::detail::adl_only { +//!\brief Poison-pill overload to prevent non-ADL forms of unqualified lookup. +template +void max_pseudoknot_depth(args_t ...) = delete; + /*!\brief Functor definition for seqan3::max_pseudoknot_depth. * \tparam alph_t The type being queried. * \tparam s_alph_t `alph_t` with cvref removed and possibly wrapped in std::type_identity; never user-provide this! @@ -286,9 +279,9 @@ template , decltype(v)>::max_pseudoknot_depth )) // member + SEQAN3_CPO_IMPL(2, (deferred_type_t, decltype(v)>::max_pseudoknot_depth)) // custom + SEQAN3_CPO_IMPL(1, (max_pseudoknot_depth(v) )) // ADL + SEQAN3_CPO_IMPL(0, (deferred_type_t, decltype(v)>::max_pseudoknot_depth )) // member public: //!\brief Operator definition. @@ -316,7 +309,7 @@ template inline constexpr auto max_pseudoknot_depth_obj = max_pseudoknot_depth_fn{}; //!\endcond -} // namespace seqan3::detail::adl::only +} // namespace seqan3::detail::adl_only namespace seqan3 { @@ -342,13 +335,14 @@ namespace seqan3 * * It acts as a wrapper and looks for three possible implementations (in this order): * - * 1. A free function `max_pseudoknot_depth(your_type const)` in the namespace of your type (or as `friend`). - * The function must be marked `constexpr` and `noexcept` and the return type must be convertible to `size_t`. - * The value of the argument to the function shall be ignored, it is only used to select the function via - * [argument-dependent lookup](https://en.cppreference.com/w/cpp/language/adl). - * 2. A free function `max_pseudoknot_depth(your_type const)` in `namespace seqan3::custom`. - * The same restrictions apply as above. - * 3. A `static constexpr` data member of a type implicitly convertible to `size_t` called `max_pseudoknot_depth`. + * 1. A static member variable `max_pseudoknot_depth` of the class `seqan3::custom::alphabet`. + * 2. A free function `max_pseudoknot_depth(your_type const)` in the namespace of your type (or as `friend`). + * 3. A static member variable `max_pseudoknot_depth` of the class `your_type`. + * + * Functions/variables are only considered for one of the above cases if they are marked `noexcept` **and** `constexpr` and + * if the returned type is convertible to `size_t`. For 2. the value of the argument to the function shall be + * ignored, the argument is only used to select the function via + * [argument-dependent lookup](https://en.cppreference.com/w/cpp/language/adl). * * Every RNA structure alphabet type must provide one of the above. * @@ -364,10 +358,10 @@ namespace seqan3 */ template //!\cond - requires requires { { detail::adl::only::max_pseudoknot_depth_fn{} }; } && - requires { { detail::adl::only::max_pseudoknot_depth_obj() }; } + requires requires { { detail::adl_only::max_pseudoknot_depth_fn{} }; } && + requires { { detail::adl_only::max_pseudoknot_depth_obj() }; } //!\endcond -inline constexpr auto max_pseudoknot_depth = detail::adl::only::max_pseudoknot_depth_obj(); +inline constexpr auto max_pseudoknot_depth = detail::adl_only::max_pseudoknot_depth_obj(); } // namespace seqan3 @@ -375,16 +369,20 @@ inline constexpr auto max_pseudoknot_depth = detail::adl::only::max_pseudoknot_d // pseudoknot_id() // ============================================================================ -namespace seqan3::detail::adl::only +namespace seqan3::detail::adl_only { +//!\brief Poison-pill overload to prevent non-ADL forms of unqualified lookup. +template +void pseudoknot_id(args_t ...) = delete; + //!\brief Functor definition for seqan3::pseudoknot_id. struct pseudoknot_id_fn { private: - SEQAN3_CPO_IMPL(2, pseudoknot_id(v) ) // ADL - SEQAN3_CPO_IMPL(1, seqan3::custom::pseudoknot_id(v) ) // customisation namespace - SEQAN3_CPO_IMPL(0, v.pseudoknot_id() ) // member + SEQAN3_CPO_IMPL(2, seqan3::custom::alphabet::pseudoknot_id(v)) // explicit customisation + SEQAN3_CPO_IMPL(1, pseudoknot_id(v) ) // ADL + SEQAN3_CPO_IMPL(0, v.pseudoknot_id() ) // member public: //!\brief Operator definition. @@ -403,7 +401,7 @@ struct pseudoknot_id_fn } }; -} // namespace seqan3::detail::adl::only +} // namespace seqan3::detail::adl_only namespace seqan3 { @@ -425,14 +423,12 @@ namespace seqan3 * * It acts as a wrapper and looks for three possible implementations (in this order): * - * 1. A free function `pseudoknot_id(your_type const a)` in the namespace of your type (or as `friend`). - * The function must be marked `noexcept` (`constexpr` is not required, but recommended) and the - * return type must be convertible to `size_t`. - * 2. A free function `pseudoknot_id(your_type const a)` in `namespace seqan3::custom`. - * The same restrictions apply as above. - * 3. A member function called `pseudoknot_id()`. - * It must be marked `noexcept` (`constexpr` is not required, but recommended) and the return type - * must be convertible to `size_t`. + * 1. A static member function `pseudoknot_id(your_type const a)` of the class `seqan3::custom::alphabet`. + * 2. A free function `pseudoknot_id(your_type const a)` in the namespace of your type (or as `friend`). + * 3. A member function of `your_type` called `pseudoknot_id()`. + * + * Functions are only considered for one of the above cases if they are marked `noexcept` (`constexpr` is not required, + * but recommended) and the return type is convertible to `size_t`. * * Every RNA structure alphabet type must provide one of the above. * @@ -445,7 +441,7 @@ namespace seqan3 * This is a customisation point (see \ref about_customisation). To specify the behaviour for your own alphabet type, * simply provide one of the three functions specified above. */ -inline constexpr auto pseudoknot_id = detail::adl::only::pseudoknot_id_fn{}; +inline constexpr auto pseudoknot_id = detail::adl_only::pseudoknot_id_fn{}; //!\} } // namespace seqan3 diff --git a/include/seqan3/core/detail/debug_stream_range.hpp b/include/seqan3/core/detail/debug_stream_range.hpp index 2254b67311..6502fd40d8 100644 --- a/include/seqan3/core/detail/debug_stream_range.hpp +++ b/include/seqan3/core/detail/debug_stream_range.hpp @@ -12,6 +12,7 @@ #pragma once +#include #include #include #include diff --git a/include/seqan3/io/sequence_file/format_fasta.hpp b/include/seqan3/io/sequence_file/format_fasta.hpp index 287675ead0..5d35652bfa 100644 --- a/include/seqan3/io/sequence_file/format_fasta.hpp +++ b/include/seqan3/io/sequence_file/format_fasta.hpp @@ -18,6 +18,7 @@ #include #include +#include #include #include #include diff --git a/include/seqan3/io/sequence_file/format_fastq.hpp b/include/seqan3/io/sequence_file/format_fastq.hpp index 5451287a09..ddf8860484 100644 --- a/include/seqan3/io/sequence_file/format_fastq.hpp +++ b/include/seqan3/io/sequence_file/format_fastq.hpp @@ -23,6 +23,7 @@ #include #include +#include #include #include #include diff --git a/include/seqan3/io/structure_file/format_vienna.hpp b/include/seqan3/io/structure_file/format_vienna.hpp index 8c93fe8edc..89238c2ca3 100644 --- a/include/seqan3/io/structure_file/format_vienna.hpp +++ b/include/seqan3/io/structure_file/format_vienna.hpp @@ -28,6 +28,7 @@ #include #include +#include #include #include #include diff --git a/test/unit/alphabet/CMakeLists.txt b/test/unit/alphabet/CMakeLists.txt index e3333482db..5baf56526a 100644 --- a/test/unit/alphabet/CMakeLists.txt +++ b/test/unit/alphabet/CMakeLists.txt @@ -3,4 +3,5 @@ seqan3_test(alphabet_cereal_test.cpp) seqan3_test(alphabet_hash_test.cpp) seqan3_test(custom_alphabet_test.cpp) seqan3_test(custom_alphabet2_test.cpp) +seqan3_test(custom_alphabet3_test.cpp) seqan3_test(debug_stream_alphabet_test.cpp) diff --git a/test/unit/alphabet/composite/alphabet_variant_test.cpp b/test/unit/alphabet/composite/alphabet_variant_test.cpp index dd755e98e4..771a183110 100644 --- a/test/unit/alphabet/composite/alphabet_variant_test.cpp +++ b/test/unit/alphabet/composite/alphabet_variant_test.cpp @@ -9,6 +9,7 @@ #include +#include #include #include #include diff --git a/test/unit/alphabet/custom_alphabet3_test.cpp b/test/unit/alphabet/custom_alphabet3_test.cpp new file mode 100644 index 0000000000..25ee65e69e --- /dev/null +++ b/test/unit/alphabet/custom_alphabet3_test.cpp @@ -0,0 +1,81 @@ +// ----------------------------------------------------------------------------------------------------- +// Copyright (c) 2006-2019, Knut Reinert & Freie Universität Berlin +// Copyright (c) 2016-2019, Knut Reinert & MPI für molekulare Genetik +// This file may be used, modified and/or redistributed under the terms of the 3-clause BSD-License +// shipped with this file and also available at: https://github.com/seqan/seqan3/blob/master/LICENSE.md +// ----------------------------------------------------------------------------------------------------- + +#include + +#include "alphabet_test_template.hpp" +#include "alphabet_constexpr_test_template.hpp" + +// Tests the capabilities of the explicit alphabet customisation + +//![third_party_type] +#include // for size_t +#include // for seqan3::Alphabet + +// this is from some other library: +namespace third_party_ns +{ + +enum class third_party_type +{ + ZERO, + ONE, + TWO +}; + +} // namespace third_party_ns + +// ------------------------------------------------------------------------------------ + +// this is in your code (no namespace): +template <> +struct seqan3::custom::alphabet +{ + + static constexpr size_t alphabet_size = 3; + + static constexpr size_t to_rank(third_party_ns::third_party_type const a) noexcept + { + return static_cast(a); + } + + static constexpr third_party_ns::third_party_type & assign_rank_to(size_t const r, third_party_ns::third_party_type & a) noexcept + { + switch (r) + { + case 0: a = third_party_ns::third_party_type::ZERO; return a; + case 1: a = third_party_ns::third_party_type::ONE; return a; + default: a = third_party_ns::third_party_type::TWO; return a; + } + } + + static constexpr char to_char(third_party_ns::third_party_type const a) noexcept + { + switch (a) + { + case third_party_ns::third_party_type::ZERO: return '0'; + case third_party_ns::third_party_type::ONE: return '1'; + default: return '2'; + } + } + + static constexpr third_party_ns::third_party_type & assign_char_to(char const c, third_party_ns::third_party_type & a) noexcept + { + switch (c) + { + case '0': a = third_party_ns::third_party_type::ZERO; return a; + case '1': a = third_party_ns::third_party_type::ONE; return a; + default: a = third_party_ns::third_party_type::TWO; return a; + } + } +}; + +static_assert(seqan3::Alphabet); +//![third_party_type] + +INSTANTIATE_TYPED_TEST_CASE_P(third_party_type, alphabet, third_party_ns::third_party_type); +INSTANTIATE_TYPED_TEST_CASE_P(third_party_type, alphabet_constexpr, third_party_ns::third_party_type); diff --git a/test/unit/alphabet/debug_stream_alphabet_test.cpp b/test/unit/alphabet/debug_stream_alphabet_test.cpp index 8ed766a608..af37601eb0 100644 --- a/test/unit/alphabet/debug_stream_alphabet_test.cpp +++ b/test/unit/alphabet/debug_stream_alphabet_test.cpp @@ -32,5 +32,5 @@ TYPED_TEST(debug_stream_test, alphabet) o.flush(); EXPECT_EQ(o.str().size(), 1u); - EXPECT_EQ(to_char(o.str()[0]), 'C'); + EXPECT_EQ(o.str()[0], 'C'); }