diff --git a/include/seqan3/alignment/aligned_sequence/aligned_sequence_concept.hpp b/include/seqan3/alignment/aligned_sequence/aligned_sequence_concept.hpp index 8906fd00d9..a21a4bb948 100644 --- a/include/seqan3/alignment/aligned_sequence/aligned_sequence_concept.hpp +++ b/include/seqan3/alignment/aligned_sequence/aligned_sequence_concept.hpp @@ -208,11 +208,13 @@ SEQAN3_CONCEPT aligned_sequence = requires { typename detail::unaligned_seq_t; } && requires (t v, detail::unaligned_seq_t unaligned) { - { insert_gap(v, std::ranges::begin(v)) } -> std::ranges::iterator_t; // global functions for generic usability - { insert_gap(v, std::ranges::begin(v), 2) } -> std::ranges::iterator_t; - { erase_gap(v, std::ranges::begin(v)) } -> std::ranges::iterator_t; - { erase_gap(v, std::ranges::begin(v), std::ranges::end(v)) } -> std::ranges::iterator_t; - { assign_unaligned(v, unaligned) } -> void; + // global functions for generic usability + SEQAN3_RETURN_TYPE_CONTRAINT(insert_gap(v, std::ranges::begin(v)), std::same_as, std::ranges::iterator_t); + SEQAN3_RETURN_TYPE_CONTRAINT(insert_gap(v, std::ranges::begin(v), 2), std::same_as, std::ranges::iterator_t); + SEQAN3_RETURN_TYPE_CONTRAINT(erase_gap(v, std::ranges::begin(v)), std::same_as, std::ranges::iterator_t); + SEQAN3_RETURN_TYPE_CONTRAINT(erase_gap(v, std::ranges::begin(v), std::ranges::end(v)), + std::same_as, std::ranges::iterator_t); + SEQAN3_RETURN_TYPE_CONTRAINT(assign_unaligned(v, unaligned), std::same_as, void); }; //!\endcond diff --git a/include/seqan3/alignment/matrix/detail/two_dimensional_matrix_iterator_concept.hpp b/include/seqan3/alignment/matrix/detail/two_dimensional_matrix_iterator_concept.hpp index be87c251d5..866727e3dc 100644 --- a/include/seqan3/alignment/matrix/detail/two_dimensional_matrix_iterator_concept.hpp +++ b/include/seqan3/alignment/matrix/detail/two_dimensional_matrix_iterator_concept.hpp @@ -106,14 +106,14 @@ SEQAN3_CONCEPT two_dimensional_matrix_iterator = { it.coordinate() }; { cit.coordinate() }; - requires std::same_as &>; - requires std::same_as>; - requires std::same_as>; - requires std::same_as &>; - requires std::same_as>; - requires std::same_as>; - requires std::same_as; - requires std::same_as; + SEQAN3_RETURN_TYPE_CONTRAINT(it += offset, std::same_as, std::remove_reference_t &); + SEQAN3_RETURN_TYPE_CONTRAINT(it + offset, std::same_as, std::remove_reference_t); + SEQAN3_RETURN_TYPE_CONTRAINT(offset + it, std::same_as, std::remove_reference_t); + SEQAN3_RETURN_TYPE_CONTRAINT(it -= offset, std::same_as, std::remove_reference_t &); + SEQAN3_RETURN_TYPE_CONTRAINT(it - offset, std::same_as, std::remove_reference_t); + SEQAN3_RETURN_TYPE_CONTRAINT(cit - offset, std::same_as, std::remove_reference_t); + SEQAN3_RETURN_TYPE_CONTRAINT(it.coordinate(), std::same_as, matrix_coordinate); + SEQAN3_RETURN_TYPE_CONTRAINT(cit.coordinate(), std::same_as, matrix_coordinate); }; //!\endcond } // namespace seqan3::detail diff --git a/include/seqan3/alignment/matrix/matrix_concept.hpp b/include/seqan3/alignment/matrix/matrix_concept.hpp index a5faa31a98..74b1311dce 100644 --- a/include/seqan3/alignment/matrix/matrix_concept.hpp +++ b/include/seqan3/alignment/matrix/matrix_concept.hpp @@ -58,17 +58,23 @@ SEQAN3_CONCEPT matrix = requires(remove_cvref_t m) /*!\fn size_type cols() const noexcept; * \brief The number of columns in the matrix. */ - { m.cols() } -> typename remove_cvref_t::size_type; + //!\cond + SEQAN3_RETURN_TYPE_CONTRAINT(m.cols(), std::same_as, typename remove_cvref_t::size_type); + //!\endcond /*!\fn size_type rows() const noexcept; * \brief The number of rows in the matrix. */ - { m.rows() } -> typename remove_cvref_t::size_type; + //!\cond + SEQAN3_RETURN_TYPE_CONTRAINT(m.rows(), std::same_as, typename remove_cvref_t::size_type); + //!\endcond /*!\fn reference at(matrix_coordinate coordinate) noexcept; * \brief A reference to the entry of the matrix at the given coordinate. */ - { m.at(matrix_coordinate{}) } -> typename remove_cvref_t::reference; + //!\cond + SEQAN3_RETURN_TYPE_CONTRAINT(m.at(matrix_coordinate{}), std::same_as, typename remove_cvref_t::reference); + //!\endcond //!\cond }; diff --git a/include/seqan3/alphabet/concept.hpp b/include/seqan3/alphabet/concept.hpp index ae35d6baf7..af8b23beb0 100644 --- a/include/seqan3/alphabet/concept.hpp +++ b/include/seqan3/alphabet/concept.hpp @@ -455,7 +455,7 @@ struct char_is_valid_for_fn { { impl(priority_tag<3>{}, a, dummy{}) }; requires noexcept(impl(priority_tag<3>{}, a)); - requires std::convertible_to{}, a)), bool>; + SEQAN3_RETURN_TYPE_CONTRAINT(impl(priority_tag<3>{}, a), std::convertible_to, bool); } //!\endcond constexpr bool operator()(alphabet_char_t const a) const noexcept @@ -539,8 +539,8 @@ struct assign_char_strictly_to_fn //!\cond requires requires (alph_t a, seqan3::alphabet_char_t r) { - { seqan3::assign_char_to(r, a) } -> alph_t; - { seqan3::char_is_valid_for(r) } -> bool; + SEQAN3_RETURN_TYPE_CONTRAINT(seqan3::assign_char_to(r, a), std::convertible_to, alph_t); + SEQAN3_RETURN_TYPE_CONTRAINT(seqan3::char_is_valid_for(r), std::same_as, bool); } //!\endcond decltype(auto) operator()(seqan3::alphabet_char_t const r, alph_t & a) const @@ -556,8 +556,8 @@ struct assign_char_strictly_to_fn //!\cond requires requires (alph_t a, seqan3::alphabet_char_t r) { - { seqan3::assign_char_to(r, a) } -> alph_t; - { seqan3::char_is_valid_for(r) } -> bool; + SEQAN3_RETURN_TYPE_CONTRAINT(seqan3::assign_char_to(r, a), std::convertible_to, alph_t); + SEQAN3_RETURN_TYPE_CONTRAINT(seqan3::char_is_valid_for(r), std::same_as, bool); } //!\endcond auto operator()(seqan3::alphabet_char_t const r, alph_t && a) const diff --git a/include/seqan3/argument_parser/validators.hpp b/include/seqan3/argument_parser/validators.hpp index 844600dab9..4250bc4686 100644 --- a/include/seqan3/argument_parser/validators.hpp +++ b/include/seqan3/argument_parser/validators.hpp @@ -85,8 +85,8 @@ SEQAN3_CONCEPT validator = std::copyable> && { typename std::remove_reference_t::option_value_type; - { validator(value) } -> void; - { validator.get_help_page_message() } -> std::string; + SEQAN3_RETURN_TYPE_CONTRAINT(validator(value), std::same_as, void); + SEQAN3_RETURN_TYPE_CONTRAINT(validator.get_help_page_message(), std::same_as, std::string); }; //!\endcond diff --git a/include/seqan3/core/char_operations/predicate_detail.hpp b/include/seqan3/core/char_operations/predicate_detail.hpp index 272a28857c..7fdf85aec1 100644 --- a/include/seqan3/core/char_operations/predicate_detail.hpp +++ b/include/seqan3/core/char_operations/predicate_detail.hpp @@ -114,8 +114,8 @@ SEQAN3_CONCEPT char_predicate = requires std::remove_reference_t::msg; //The msg type can be added with a std::string. - { std::string{} + std::remove_reference_t::msg } -> - decltype(std::remove_reference_t::msg); + SEQAN3_RETURN_TYPE_CONTRAINT(std::string{} + std::remove_reference_t::msg, + std::convertible_to, decltype(std::remove_reference_t::msg)); }; //!\endcond diff --git a/include/seqan3/core/concept/tuple.hpp b/include/seqan3/core/concept/tuple.hpp index a083424b7b..ed85c1ce58 100644 --- a/include/seqan3/core/concept/tuple.hpp +++ b/include/seqan3/core/concept/tuple.hpp @@ -33,7 +33,7 @@ namespace seqan3::detail template SEQAN3_CONCEPT tuple_size = requires (tuple_t v) { - { std::tuple_size::value } -> size_t; + SEQAN3_RETURN_TYPE_CONTRAINT(std::tuple_size::value, std::convertible_to, size_t); }; //!\endcond @@ -49,14 +49,19 @@ SEQAN3_CONCEPT tuple_get = requires (tuple_t & v, tuple_t const & v_c) requires std::tuple_size_v > 0; typename std::tuple_element<0, tuple_t>::type; - { get<0>(v) } -> typename std::tuple_element<0, tuple_t>::type; + + SEQAN3_RETURN_TYPE_CONTRAINT(get<0>(v), std::convertible_to, typename std::tuple_element<0, tuple_t>::type); // requires weakly_assignable_from(v)), typename std::tuple_element<0, tuple_t>::type>; //TODO check that the previous returns something that can be assigned to - // unfortunately std::assignable_from requires lvalue-reference, but we want to accept xvalues too (returned proxies) - { get<0>(v_c) } -> typename std::tuple_element<0, tuple_t>::type; - { get<0>(std::move(v)) } -> typename std::tuple_element<0, tuple_t>::type; + // unfortunately std::assignable_from requires lvalue-reference, but we want to accept xvalues too (returned + // proxies) + SEQAN3_RETURN_TYPE_CONTRAINT(get<0>(v_c), std::convertible_to, typename std::tuple_element<0, tuple_t>::type); + SEQAN3_RETURN_TYPE_CONTRAINT(get<0>(std::move(v)), + std::convertible_to, typename std::tuple_element<0, tuple_t>::type); // TODO: The return type for std::tuple is wrong until gcc-8.0, for gcc > 8.0 this is fixed. { get<0>(std::move(v_c)) };// -> typename std::tuple_element<0, tuple_t>::type const &&; + // SEQAN3_RETURN_TYPE_CONTRAINT(get<0>(std::move(v_c)), + // std::convertible_to, typename std::tuple_element<0, tuple_t>::type const &&); }; //!\endcond diff --git a/include/seqan3/core/platform.hpp b/include/seqan3/core/platform.hpp index 0fa5bce09c..a040712b4e 100644 --- a/include/seqan3/core/platform.hpp +++ b/include/seqan3/core/platform.hpp @@ -49,6 +49,15 @@ # error "SeqAn3 requires C++ Concepts, either vie the TS (flag: -fconcepts) or via C++20 (flag: -std=c++2a / -std=c++20)." #endif +//!\brief Same as writing `{expression} -> concept_name` in a concept definition. +#if defined(__GNUC__) && (__GNUC__ < 10) +# define SEQAN3_RETURN_TYPE_CONTRAINT(expression, concept_name, ...) \ + {expression}; requires concept_name +#else +# define SEQAN3_RETURN_TYPE_CONTRAINT(expression, concept_name, ...) \ + {expression} -> concept_name<__VA_ARGS__> +#endif + // filesystem [required] #if !__has_include() # if !__has_include() diff --git a/include/seqan3/core/simd/concept.hpp b/include/seqan3/core/simd/concept.hpp index 4e4601a4e4..f50610088e 100644 --- a/include/seqan3/core/simd/concept.hpp +++ b/include/seqan3/core/simd/concept.hpp @@ -40,25 +40,31 @@ SEQAN3_CONCEPT simd_concept = requires (simd_t a, simd_t b) requires std::integral>::max_length)>; // assume array access that returns a scalar_type type - { a[0] } -> typename simd_traits>::scalar_type; + SEQAN3_RETURN_TYPE_CONTRAINT(a[0], std::convertible_to, typename simd_traits>::scalar_type); // require comparison operators - requires std::same_as>::mask_type>; - requires std::same_as>::mask_type>; - requires std::same_as>::mask_type>; - requires std::same_as b), typename simd_traits>::mask_type>; - requires std::same_as>::mask_type>; - requires std::same_as= b), typename simd_traits>::mask_type>; + SEQAN3_RETURN_TYPE_CONTRAINT(a == b, + std::same_as, typename simd_traits>::mask_type); + SEQAN3_RETURN_TYPE_CONTRAINT(a != b, + std::same_as, typename simd_traits>::mask_type); + SEQAN3_RETURN_TYPE_CONTRAINT(a < b, + std::same_as, typename simd_traits>::mask_type); + SEQAN3_RETURN_TYPE_CONTRAINT(a > b, + std::same_as, typename simd_traits>::mask_type); + SEQAN3_RETURN_TYPE_CONTRAINT(a <= b, + std::same_as, typename simd_traits>::mask_type); + SEQAN3_RETURN_TYPE_CONTRAINT(a >= b, + std::same_as, typename simd_traits>::mask_type); // require arithmetic operators - requires std::same_as>; - requires std::same_as>; - requires std::same_as>; - requires std::same_as>; - requires std::same_as &>; - requires std::same_as &>; - requires std::same_as &>; - requires std::same_as &>; + SEQAN3_RETURN_TYPE_CONTRAINT(a + b, std::same_as, std::remove_reference_t); + SEQAN3_RETURN_TYPE_CONTRAINT(a - b, std::same_as, std::remove_reference_t); + SEQAN3_RETURN_TYPE_CONTRAINT(a * b, std::same_as, std::remove_reference_t); + SEQAN3_RETURN_TYPE_CONTRAINT(a / b, std::same_as, std::remove_reference_t); + SEQAN3_RETURN_TYPE_CONTRAINT(a += b, std::same_as, std::remove_reference_t &); + SEQAN3_RETURN_TYPE_CONTRAINT(a -= b, std::same_as, std::remove_reference_t &); + SEQAN3_RETURN_TYPE_CONTRAINT(a *= b, std::same_as, std::remove_reference_t &); + SEQAN3_RETURN_TYPE_CONTRAINT(a /= b, std::same_as, std::remove_reference_t &); }; //!\endcond diff --git a/include/seqan3/io/alignment_file/output_format_concept.hpp b/include/seqan3/io/alignment_file/output_format_concept.hpp index 577e74454e..40f2bec7d3 100644 --- a/include/seqan3/io/alignment_file/output_format_concept.hpp +++ b/include/seqan3/io/alignment_file/output_format_concept.hpp @@ -95,25 +95,25 @@ SEQAN3_CONCEPT alignment_file_output_format = { t::file_extensions; - { v.write_alignment_record(stream, - options, - header, - seq, - qual, - id, - offset, - ref_seq, - ref_id, - ref_offset, - align, - cigar, - flag, - mapq, - mate, - tag_dict, - e_value, - bit_score - ) } -> void; + SEQAN3_RETURN_TYPE_CONTRAINT(v.write_alignment_record(stream, + options, + header, + seq, + qual, + id, + offset, + ref_seq, + ref_id, + ref_offset, + align, + cigar, + flag, + mapq, + mate, + tag_dict, + e_value, + bit_score), + std::same_as, void); }; //!\endcond diff --git a/include/seqan3/io/sequence_file/input_format_concept.hpp b/include/seqan3/io/sequence_file/input_format_concept.hpp index e7ceffe57f..c026f60cbe 100644 --- a/include/seqan3/io/sequence_file/input_format_concept.hpp +++ b/include/seqan3/io/sequence_file/input_format_concept.hpp @@ -78,9 +78,10 @@ SEQAN3_CONCEPT sequence_file_input_format = requires (detail::sequence_file_inpu { t::file_extensions; - { v.read_sequence_record(f, options, seq, id, qual) } -> void; - { v.read_sequence_record(f, options, seq_qual, id, seq_qual) } -> void; - { v.read_sequence_record(f, options, std::ignore, std::ignore, std::ignore) } -> void; + SEQAN3_RETURN_TYPE_CONTRAINT(v.read_sequence_record(f, options, seq, id, qual), std::same_as, void); + SEQAN3_RETURN_TYPE_CONTRAINT(v.read_sequence_record(f, options, seq_qual, id, seq_qual), std::same_as, void); + SEQAN3_RETURN_TYPE_CONTRAINT(v.read_sequence_record(f, options, std::ignore, std::ignore, std::ignore), + std::same_as, void); }; //!\endcond diff --git a/include/seqan3/io/sequence_file/output_format_concept.hpp b/include/seqan3/io/sequence_file/output_format_concept.hpp index fdc32a80e7..af74111cb6 100644 --- a/include/seqan3/io/sequence_file/output_format_concept.hpp +++ b/include/seqan3/io/sequence_file/output_format_concept.hpp @@ -77,9 +77,10 @@ SEQAN3_CONCEPT sequence_file_output_format = requires (detail::sequence_file_out { t::file_extensions; - { v.write_sequence_record(f, options, seq, id, qual) } -> void; - { v.write_sequence_record(f, options, std::ignore, id, std::ignore) } -> void; - { v.write_sequence_record(f, options, std::ignore, std::ignore, std::ignore) } -> void; + SEQAN3_RETURN_TYPE_CONTRAINT(v.write_sequence_record(f, options, seq, id, qual), std::same_as, void); + SEQAN3_RETURN_TYPE_CONTRAINT(v.write_sequence_record(f, options, std::ignore, id, std::ignore), std::same_as, void); + SEQAN3_RETURN_TYPE_CONTRAINT(v.write_sequence_record(f, options, std::ignore, std::ignore, std::ignore), + std::same_as, void); // the last is required to be compile time valid, but should always throw at run-time. }; //!\endcond diff --git a/include/seqan3/io/stream/concept.hpp b/include/seqan3/io/stream/concept.hpp index 6d58507143..2b153963c9 100644 --- a/include/seqan3/io/stream/concept.hpp +++ b/include/seqan3/io/stream/concept.hpp @@ -12,6 +12,7 @@ #pragma once +#include #include #include @@ -38,8 +39,10 @@ SEQAN3_CONCEPT output_stream_over = std::is_base_of_v::pos_type; typename std::remove_reference_t::off_type; - { os << val } -> std::basic_ostream::char_type, - typename std::remove_reference_t::traits_type> &; + SEQAN3_RETURN_TYPE_CONTRAINT(os << val, + std::same_as, + std::basic_ostream::char_type, + typename std::remove_reference_t::traits_type> &); }; template @@ -105,8 +108,11 @@ SEQAN3_CONCEPT input_stream_over = std::is_base_of_v::pos_type; typename std::remove_reference_t::off_type; - { is >> val } -> std::basic_istream::char_type, - typename std::remove_reference_t::traits_type> &; + + SEQAN3_RETURN_TYPE_CONTRAINT(is >> val, + std::same_as, + std::basic_istream::char_type, + typename std::remove_reference_t::traits_type> &); }; template diff --git a/include/seqan3/io/structure_file/input_format_concept.hpp b/include/seqan3/io/structure_file/input_format_concept.hpp index ecf95b56ca..8d582e7dcd 100644 --- a/include/seqan3/io/structure_file/input_format_concept.hpp +++ b/include/seqan3/io/structure_file/input_format_concept.hpp @@ -84,17 +84,54 @@ SEQAN3_CONCEPT structure_file_input_format = requires(detail::structure_file_inp { t::file_extensions; - { v.read_structure_record(f, options, seq, id, bpp, structure, - energy, react, react_err, comment, offset) } -> void; - - { v.read_structure_record(f, options, seq, id, bpp, std::ignore, - std::ignore, std::ignore, std::ignore, std::ignore, std::ignore) } -> void; - - { v.read_structure_record(f, options, structured_seq, id, std::ignore, structured_seq, - energy, std::ignore, std::ignore, std::ignore, std::ignore) } -> void; - - { v.read_structure_record(f, options, std::ignore, std::ignore, std::ignore, std::ignore, - std::ignore, std::ignore, std::ignore, std::ignore, std::ignore) } -> void; + SEQAN3_RETURN_TYPE_CONTRAINT(v.read_structure_record(f, + options, + seq, + id, + bpp, + structure, + energy, + react, + react_err, + comment, + offset), + std::same_as, void); + SEQAN3_RETURN_TYPE_CONTRAINT(v.read_structure_record(f, + options, + seq, + id, + bpp, + std::ignore, + std::ignore, + std::ignore, + std::ignore, + std::ignore, + std::ignore), + std::same_as, void); + SEQAN3_RETURN_TYPE_CONTRAINT(v.read_structure_record(f, + options, + structured_seq, + id, + std::ignore, + structured_seq, + energy, + std::ignore, + std::ignore, + std::ignore, + std::ignore), + std::same_as, void); + SEQAN3_RETURN_TYPE_CONTRAINT(v.read_structure_record(f, + options, + std::ignore, + std::ignore, + std::ignore, + std::ignore, + std::ignore, + std::ignore, + std::ignore, + std::ignore, + std::ignore), + std::same_as, void); // the last is required to be compile time valid, but should always throw at run-time. }; //!\endcond diff --git a/include/seqan3/io/structure_file/output_format_concept.hpp b/include/seqan3/io/structure_file/output_format_concept.hpp index 8862ae8b4f..c36c418531 100644 --- a/include/seqan3/io/structure_file/output_format_concept.hpp +++ b/include/seqan3/io/structure_file/output_format_concept.hpp @@ -83,14 +83,54 @@ SEQAN3_CONCEPT structure_file_output_format = requires(detail::structure_file_ou { t::file_extensions; - { v.write_structure_record(f, options, seq, id, bpp, structure, - energy, react, react_err, comment, offset) } -> void; - { v.write_structure_record(f, options, seq, id, bpp, std::ignore, - std::ignore, std::ignore, std::ignore, std::ignore, std::ignore) } -> void; - { v.write_structure_record(f, options, structured_seq, id, std::ignore, structured_seq, - energy, std::ignore, std::ignore, std::ignore, std::ignore) } -> void; - { v.write_structure_record(f, options, std::ignore, std::ignore, std::ignore, std::ignore, - std::ignore, std::ignore, std::ignore, std::ignore, std::ignore) } -> void; + SEQAN3_RETURN_TYPE_CONTRAINT(v.write_structure_record(f, + options, + seq, + id, + bpp, + structure, + energy, + react, + react_err, + comment, + offset), + std::same_as, void); + SEQAN3_RETURN_TYPE_CONTRAINT(v.write_structure_record(f, + options, + seq, + id, + bpp, + std::ignore, + std::ignore, + std::ignore, + std::ignore, + std::ignore, + std::ignore), + std::same_as, void); + SEQAN3_RETURN_TYPE_CONTRAINT(v.write_structure_record(f, + options, + structured_seq, + id, + std::ignore, + structured_seq, + energy, + std::ignore, + std::ignore, + std::ignore, + std::ignore), + std::same_as, void); + SEQAN3_RETURN_TYPE_CONTRAINT(v.write_structure_record(f, + options, + std::ignore, + std::ignore, + std::ignore, + std::ignore, + std::ignore, + std::ignore, + std::ignore, + std::ignore, + std::ignore), + std::same_as, void); // the last is required to be compile time valid, but should always throw at run-time. }; //!\endcond diff --git a/include/seqan3/range/container/concept.hpp b/include/seqan3/range/container/concept.hpp index adc4c863bd..5ba0559fde 100644 --- a/include/seqan3/range/container/concept.hpp +++ b/include/seqan3/range/container/concept.hpp @@ -87,7 +87,8 @@ SEQAN3_CONCEPT container = requires (type val, type val2, type const cval, typen /* typename type::iterator; requires std::forward_iterator; - { it } -> typename type::const_iterator; // NOTE check whether iterator is const convertible + // NOTE check whether iterator is const convertible + SEQAN3_RETURN_TYPE_CONTRAINT(it, std::same_as, typename type::const_iterator); typename type::const_iterator; requires std::forward_iterator; @@ -104,27 +105,27 @@ SEQAN3_CONCEPT container = requires (type val, type val2, type const cval, typen >; */ // methods and operator - { type{} } -> type; // default constructor - { type{type{}} } -> type; // copy/move constructor - { val = val2 } -> type &; // assignment - { (&val)->~type() }; // destructor - - { val.begin() } -> typename type::iterator; - { val.end() } -> typename type::iterator; - { cval.begin() } -> typename type::const_iterator; - { cval.end() } -> typename type::const_iterator; - { val.cbegin() } -> typename type::const_iterator; - { val.cend() } -> typename type::const_iterator; + SEQAN3_RETURN_TYPE_CONTRAINT(type{}, std::same_as, type); // default constructor + SEQAN3_RETURN_TYPE_CONTRAINT(type{type{}}, std::same_as, type); // copy/move constructor + SEQAN3_RETURN_TYPE_CONTRAINT(val = val2, std::same_as, type &); // assignment + { (&val)->~type() }; // destructor + + SEQAN3_RETURN_TYPE_CONTRAINT(val.begin(), std::same_as, typename type::iterator); + SEQAN3_RETURN_TYPE_CONTRAINT(val.end(), std::same_as, typename type::iterator); + SEQAN3_RETURN_TYPE_CONTRAINT(cval.begin(), std::same_as, typename type::const_iterator); + SEQAN3_RETURN_TYPE_CONTRAINT(cval.end(), std::same_as, typename type::const_iterator); + SEQAN3_RETURN_TYPE_CONTRAINT(val.cbegin(), std::same_as, typename type::const_iterator); + SEQAN3_RETURN_TYPE_CONTRAINT(val.cend(), std::same_as, typename type::const_iterator); requires !std::equality_comparable || std::equality_comparable; - { val.swap(val2) } -> void; - { swap(val, val2) } -> void; - { std::swap(val, val2) } -> void; + SEQAN3_RETURN_TYPE_CONTRAINT(val.swap(val2), std::same_as, void); + SEQAN3_RETURN_TYPE_CONTRAINT(swap(val, val2), std::same_as, void); + SEQAN3_RETURN_TYPE_CONTRAINT(std::swap(val, val2), std::same_as, void); - { val.size() } -> typename type::size_type; - { val.max_size() } -> typename type::size_type; - { val.empty() } -> bool; + SEQAN3_RETURN_TYPE_CONTRAINT(val.size(), std::same_as, typename type::size_type); + SEQAN3_RETURN_TYPE_CONTRAINT(val.max_size(), std::same_as, typename type::size_type); + SEQAN3_RETURN_TYPE_CONTRAINT(val.empty(), std::same_as, bool); }; //!\endcond @@ -150,7 +151,7 @@ SEQAN3_CONCEPT sequence_container = requires (type val, type val2, type const cv { type{typename type::size_type{}, typename type::value_type{}} }; { type{val2.begin(), val2.end()} }; // NOTE that this could be any input iterator: { type{std::initializer_list{}} }; - { val = std::initializer_list{} } -> type &; + SEQAN3_RETURN_TYPE_CONTRAINT(val = std::initializer_list{}, std::same_as, type &); // assignment NOTE return type is type & for std::string and void for other stl containers: { val.assign(val2.begin(), val2.end()) }; @@ -159,30 +160,35 @@ SEQAN3_CONCEPT sequence_container = requires (type val, type val2, type const cv // modify container // TODO: how do you model this? - // { val.emplace(typename type::const_iterator{}, ? } -> typename type::iterator; - { val.insert(val.cbegin(), val2.front()) } -> typename type::iterator; - { val.insert(val.cbegin(), typename type::value_type{}) } -> typename type::iterator; - { val.insert(val.cbegin(), typename type::size_type{}, typename type::value_type{})} -> typename type::iterator; - { val.insert(val.cbegin(), val2.begin(), val2.end()) } -> typename type::iterator; + // SEQAN3_RETURN_TYPE_CONTRAINT(val.emplace(typename type::const_iterator{}, ?), + // std::same_as, typename type::iterator); + SEQAN3_RETURN_TYPE_CONTRAINT(val.insert(val.cbegin(), val2.front()), std::same_as, typename type::iterator); + SEQAN3_RETURN_TYPE_CONTRAINT(val.insert(val.cbegin(), typename type::value_type{}), + std::same_as, typename type::iterator); + SEQAN3_RETURN_TYPE_CONTRAINT(val.insert(val.cbegin(), typename type::size_type{}, typename type::value_type{}), + std::same_as, typename type::iterator); + SEQAN3_RETURN_TYPE_CONTRAINT(val.insert(val.cbegin(), val2.begin(), val2.end()), + std::same_as, typename type::iterator); requires detail::is_basic_string_v || requires(type val) { // TODO this function is not defined on strings (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=83328) - { val.insert(val.cbegin(), std::initializer_list{}) } -> typename type::iterator; + SEQAN3_RETURN_TYPE_CONTRAINT(val.insert(val.cbegin(), std::initializer_list{}), + std::same_as, typename type::iterator); }; - { val.erase(val.cbegin()) } -> typename type::iterator; - { val.erase(val.cbegin(), val.cend()) } -> typename type::iterator; + SEQAN3_RETURN_TYPE_CONTRAINT(val.erase(val.cbegin()), std::same_as, typename type::iterator); + SEQAN3_RETURN_TYPE_CONTRAINT(val.erase(val.cbegin(), val.cend()), std::same_as, typename type::iterator); - { val.push_back(val.front()) } -> void; - { val.push_back(typename type::value_type{}) } -> void; - { val.pop_back() } -> void; - { val.clear() } -> void; + SEQAN3_RETURN_TYPE_CONTRAINT(val.push_back(val.front()), std::same_as, void); + SEQAN3_RETURN_TYPE_CONTRAINT(val.push_back(typename type::value_type{}), std::same_as, void); + SEQAN3_RETURN_TYPE_CONTRAINT(val.pop_back(), std::same_as, void); + SEQAN3_RETURN_TYPE_CONTRAINT(val.clear(), std::same_as, void); // access container - { val.front() } -> typename type::reference; - { cval.front() } -> typename type::const_reference; - { val.back() } -> typename type::reference; - { cval.back() } -> typename type::const_reference; + SEQAN3_RETURN_TYPE_CONTRAINT(val.front(), std::same_as, typename type::reference); + SEQAN3_RETURN_TYPE_CONTRAINT(cval.front(), std::same_as, typename type::const_reference); + SEQAN3_RETURN_TYPE_CONTRAINT(val.back(), std::same_as, typename type::reference); + SEQAN3_RETURN_TYPE_CONTRAINT(cval.back(), std::same_as, typename type::const_reference); }; //!\endcond @@ -207,12 +213,12 @@ SEQAN3_CONCEPT random_access_container = requires (type val) requires sequence_container; // access container - { val[0] } -> typename type::reference; - { val.at(0) } -> typename type::reference; + SEQAN3_RETURN_TYPE_CONTRAINT(val[0], std::same_as, typename type::reference); + SEQAN3_RETURN_TYPE_CONTRAINT(val.at(0), std::same_as, typename type::reference); // modify container - { val.resize(0) } -> void; - { val.resize(0, typename type::value_type{}) } -> void; + SEQAN3_RETURN_TYPE_CONTRAINT(val.resize(0), std::same_as, void); + SEQAN3_RETURN_TYPE_CONTRAINT(val.resize(0, typename type::value_type{}), std::same_as, void); }; //!\endcond @@ -232,9 +238,9 @@ SEQAN3_CONCEPT reservible_container = requires (type val) { requires random_access_container; - { val.capacity() } -> typename type::size_type; - { val.reserve(0) } -> void; - { val.shrink_to_fit() } -> void; + SEQAN3_RETURN_TYPE_CONTRAINT(val.capacity(), std::same_as, typename type::size_type); + SEQAN3_RETURN_TYPE_CONTRAINT(val.reserve(0), std::same_as, void); + SEQAN3_RETURN_TYPE_CONTRAINT(val.shrink_to_fit(), std::same_as, void); }; //!\endcond diff --git a/include/seqan3/range/detail/inherited_iterator_base.hpp b/include/seqan3/range/detail/inherited_iterator_base.hpp index fb99589e19..bb18a755bf 100644 --- a/include/seqan3/range/detail/inherited_iterator_base.hpp +++ b/include/seqan3/range/detail/inherited_iterator_base.hpp @@ -207,7 +207,7 @@ class inherited_iterator_base : public std::conditional_t()++) && noexcept(derived_t(std::declval()))) //!\cond - requires requires (base_t_ i) { i++; requires std::same_as; } && + requires requires (base_t_ i) { i++; SEQAN3_RETURN_TYPE_CONTRAINT(i++, std::same_as, base_t_); } && std::constructible_from //!\endcond { diff --git a/include/seqan3/search/fm_index/concept.hpp b/include/seqan3/search/fm_index/concept.hpp index c178879c20..fd4ff77805 100644 --- a/include/seqan3/search/fm_index/concept.hpp +++ b/include/seqan3/search/fm_index/concept.hpp @@ -40,10 +40,10 @@ SEQAN3_CONCEPT sdsl_index = requires (t sdsl_index) { typename t::size_type; - { sdsl_index.size() } -> typename t::size_type; + SEQAN3_RETURN_TYPE_CONTRAINT(sdsl_index.size(), std::same_as, typename t::size_type); { sdsl_index[0] }; // suffix array access - { sdsl_index.comp2char[0] } -> uint8_t; - { sdsl_index.char2comp[0] } -> uint8_t; + SEQAN3_RETURN_TYPE_CONTRAINT(sdsl_index.comp2char[0], std::same_as, uint8_t); + SEQAN3_RETURN_TYPE_CONTRAINT(sdsl_index.char2comp[0], std::same_as, uint8_t); { sdsl_index.sigma }; { sdsl_index.C[0] }; @@ -112,10 +112,10 @@ SEQAN3_CONCEPT fm_index_specialisation = std::semiregular && requires (t inde { t(text) }; }; - { index.cursor() } -> typename t::cursor_type; + SEQAN3_RETURN_TYPE_CONTRAINT(index.cursor(), std::same_as, typename t::cursor_type); - { index.size() } -> typename t::size_type; - { index.empty() } -> bool; + SEQAN3_RETURN_TYPE_CONTRAINT(index.size(), std::same_as, typename t::size_type); + SEQAN3_RETURN_TYPE_CONTRAINT(index.empty(), std::same_as, bool); }; //!\endcond /*!\name Requirements for seqan3::fm_index_specialisation @@ -164,18 +164,19 @@ SEQAN3_CONCEPT fm_index_cursor_specialisation = std::semiregular && requires std::vector>, std::vector> const text) { - { cur.extend_right() } -> bool; - { cur.extend_right(c) } -> bool; - { cur.extend_right(seq) } -> bool; - { cur.cycle_back() } -> bool; - { cur.path_label(text) } -> auto; + SEQAN3_RETURN_TYPE_CONTRAINT(cur.extend_right(), std::same_as, bool); + SEQAN3_RETURN_TYPE_CONTRAINT(cur.extend_right(c), std::same_as, bool); + SEQAN3_RETURN_TYPE_CONTRAINT(cur.extend_right(seq), std::same_as, bool); + SEQAN3_RETURN_TYPE_CONTRAINT(cur.cycle_back(), std::same_as, bool); + { cur.path_label(text) }; }; - { cur.last_rank() } -> typename t::size_type; - { cur.query_length() } -> typename t::size_type; - { cur.count() } -> typename t::size_type; - { cur.locate() } -> std::vector>; - { cur.lazy_locate() } -> auto; + SEQAN3_RETURN_TYPE_CONTRAINT(cur.last_rank(), std::same_as, typename t::size_type); + SEQAN3_RETURN_TYPE_CONTRAINT(cur.query_length(), std::same_as, typename t::size_type); + SEQAN3_RETURN_TYPE_CONTRAINT(cur.count(), std::same_as, typename t::size_type); + SEQAN3_RETURN_TYPE_CONTRAINT(cur.locate(), + std::same_as, std::vector>); + { cur.lazy_locate() }; }; //!\endcond /*!\name Requirements for seqan3::fm_index_cursor_specialisation @@ -211,8 +212,8 @@ SEQAN3_CONCEPT bi_fm_index_specialisation = fm_index_specialisation && requir // NOTE: circular dependency // requires bi_fm_index_cursor_specialisation; - { index.fwd_begin() } -> typename t::fwd_cursor_type; - { index.rev_begin() } -> typename t::rev_cursor_type; + SEQAN3_RETURN_TYPE_CONTRAINT(index.fwd_begin(), std::same_as, typename t::fwd_cursor_type); + SEQAN3_RETURN_TYPE_CONTRAINT(index.rev_begin(), std::same_as, typename t::rev_cursor_type); }; //!\endcond /*!\name Requirements for seqan3::bi_fm_index_specialisation @@ -252,10 +253,10 @@ SEQAN3_CONCEPT bi_fm_index_cursor_specialisation = fm_index_cursor_specialisatio typename t::index_type::alphabet_type const c, std::vector const seq) { - { cur.extend_left() } -> bool; - { cur.extend_left(c) } -> bool; - { cur.extend_left(seq) } -> bool; - { cur.cycle_front() } -> bool; + SEQAN3_RETURN_TYPE_CONTRAINT(cur.extend_left(), std::same_as, bool); + SEQAN3_RETURN_TYPE_CONTRAINT(cur.extend_left(c), std::same_as, bool); + SEQAN3_RETURN_TYPE_CONTRAINT(cur.extend_left(seq), std::same_as, bool); + SEQAN3_RETURN_TYPE_CONTRAINT(cur.cycle_front(), std::same_as, bool); }; }; diff --git a/test/unit/range/iterator_test_template.hpp b/test/unit/range/iterator_test_template.hpp index 5eb953188f..a629d484da 100644 --- a/test/unit/range/iterator_test_template.hpp +++ b/test/unit/range/iterator_test_template.hpp @@ -47,8 +47,9 @@ struct iterator_fixture : public ::testing::Test template SEQAN3_CONCEPT has_expect_equal_member_function = requires(t & a) { - requires std::same_as; + SEQAN3_RETURN_TYPE_CONTRAINT(t::expect_eq(*std::ranges::begin(a.test_range), + *std::ranges::begin(a.expected_range)), + std::same_as, void); }; // Delegates to the test fixture member function `expect_eq` if available and falls back to EXPECT_EQ otherwise.