Skip to content

Commit

Permalink
[MISC] use new CPO-way to define seqan3::assign_phred_to
Browse files Browse the repository at this point in the history
  • Loading branch information
marehr committed Mar 23, 2021
1 parent e616011 commit 33d83c0
Showing 1 changed file with 68 additions and 35 deletions.
103 changes: 68 additions & 35 deletions include/seqan3/alphabet/quality/concept.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -111,42 +111,75 @@ namespace seqan3::detail::adl_only
template <typename ...args_t>
void assign_phred_to(args_t ...) = delete;

//!\brief Functor definition for seqan3::assign_phred_to.
//!\brief seqan3::detail::customisation_point_object (CPO) definition for seqan3::assign_phred_to.
//!\ingroup quality
struct assign_phred_to_fn
struct assign_phred_to_cpo : public detail::customisation_point_object<assign_phred_to_cpo, 2>
{
public:
SEQAN3_CPO_IMPL(2, (seqan3::custom::alphabet<decltype(v)>::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.
template <typename alph_t>
//!\cond
requires requires (seqan3::alphabet_phred_t<alph_t> const p, alph_t & a)
{ { impl(priority_tag<2>{}, a, p) }; }
//!\endcond
constexpr alph_t & operator()(seqan3::alphabet_phred_t<alph_t> const p, alph_t & a) const noexcept
{
static_assert(noexcept(impl(priority_tag<2>{}, a, p)),
"Only overloads that are marked noexcept are picked up by seqan3::assign_phred_to().");
static_assert(std::same_as<alph_t &, decltype(impl(priority_tag<2>{}, a, p))>,
"The return type of your assign_phred_to() implementation must be 'alph_t &'.");

return impl(priority_tag<2>{}, a, p);
}

//!\brief Operator definition for rvalues.
template <typename alph_t>
//!\cond
requires requires (seqan3::alphabet_phred_t<alph_t> const p, alph_t & a)
{ { impl(priority_tag<2>{}, a, p) }; } && (!std::is_lvalue_reference_v<alph_t>)
//!\endcond
constexpr alph_t operator()(seqan3::alphabet_phred_t<alph_t> const p, alph_t && a) const noexcept
{
return (*this)(p, a); // call above function but return by value
}
//!\brief CRTP base class seqan3::detail::customisation_point_object.
using base_t = detail::customisation_point_object<assign_phred_to_cpo, 2>;
//!\brief Only this class is allowed to import the constructors from #base_t. (CRTP safety idiom)
using base_t::base_t;

/*!\brief CPO overload (1. out of 3 checks): explicit customisation via `seqan3::custom::alphabet`
* \tparam alphabet_t The type of the alphabet.
* \param phred The Phred to assign the alphabet to.
* \param alphabet The alphabet the Phred is assigned to.
*
* \details
*
* We don't perfect-forward `alphabet` when calling `assign_phred_to(phred, alphabet)`, because we assume that the
* static member function is only defined for lvalue-references.
*
* We static_cast<alphabet_t> (instead of std::forward) the result of the CPO overload expression, since we want to
* return an explicit copy of it if the forwarding reference of the alphabet is a rvalue-reference.
*/
template <typename alphabet_t>
static constexpr auto SEQAN3_CPO_OVERLOAD(priority_tag<2>,
seqan3::alphabet_phred_t<alphabet_t> const phred,
alphabet_t && alphabet)
(
/*return*/ static_cast<alphabet_t>(seqan3::custom::alphabet<alphabet_t>::assign_phred_to(phred, alphabet)) /*;*/
);

/*!\brief CPO overload (2. out of 3 checks): argument dependent lookup (ADL), i.e.
* `assign_phred_to(phred, alphabet)`
* \tparam alphabet_t The type of the alphabet.
* \param phred The Phred to assign the alphabet to.
* \param alphabet The alphabet the Phred is assigned to.
*
* \details
*
* We don't perfect-forward `alphabet` when calling `assign_phred_to(phred, alphabet)`, because we assume that the
* ADL function is only defined for lvalue-references.
*
* We static_cast<alphabet_t> (instead of std::forward) the result of the CPO overload expression, since we want to
* return an explicit copy of it if the forwarding reference of the alphabet is a rvalue-reference.
*/
template <typename alphabet_t>
static constexpr auto SEQAN3_CPO_OVERLOAD(priority_tag<1>,
seqan3::alphabet_phred_t<alphabet_t> const phred,
alphabet_t && alphabet)
(
/*return*/ static_cast<alphabet_t>(assign_phred_to(phred, alphabet)) /*;*/
);

/*!\brief CPO overload (3. out of 3 checks): member access, i.e. `alphabet.assign_phred(phred)`
* \tparam alphabet_t The type of the alphabet.
* \param phred The Phred to assign the alphabet to.
* \param alphabet The alphabet the Phred is assigned to.
*
* \details
*
* We static_cast<alphabet_t> (instead of std::forward) the result of the CPO overload expression, since we want to
* return an explicit copy of it if the forwarding reference of the alphabet is a rvalue-reference.
*/
template <typename alphabet_t>
static constexpr auto SEQAN3_CPO_OVERLOAD(priority_tag<0>,
seqan3::alphabet_phred_t<alphabet_t> const phred,
alphabet_t && alphabet)
(
/*return*/ static_cast<alphabet_t>(alphabet.assign_phred(phred)) /*;*/
);
};

} // namespace seqan3::detail::adl_only
Expand Down Expand Up @@ -186,7 +219,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_cpo{};
//!\}

} // namespace seqan3
Expand Down

0 comments on commit 33d83c0

Please sign in to comment.