From 5c7ed74066d0a16d72efdc493c7ea09d37857eb4 Mon Sep 17 00:00:00 2001 From: marehr Date: Fri, 29 Dec 2023 18:26:17 +0100 Subject: [PATCH] FEATURE: add seqan3::default_printer This PR will resolve seqan/product_backlog#63. This issue is a long-standing open to-do of mine. I hope that you can take it over and push it over the finishing line. The state of the current PR is just a draft of an idea. I'll comment on multiple code locations to point out the advantages of the new design. # The old design The major idea of the design is due to the following observation: > We use overload resolution and in particular overload ordering via concepts to determine the order in which we should print Just to give a small example (the more down, the more specialized): ```cpp std::cout //-printable [1] < seqan3::tuple_like // [4] < std::ranges::input_range // [2] < std::vector // [3] < seqan3::sequence // [3] < char * // [2] std::cout //-printable [1] < char // [5] < seqan3::tuple_like // [4] < seqan3::alphabet // [5] < seqan3::mask // [6] ``` NOTE: that using concepts as overload resolution always uses a partially ordered set, which can be depicted by as a [Hasse Diagram](https://en.wikipedia.org/wiki/Hasse_diagram), and by using the except clauses via `requires` we give it a total order. # The new design ### Before anything, note that the new design does not break any existing code. As existing `seqan3::debugstream << ` overloads, still take place in overload resolution. The idea is simple: * Have a list of printers. * The order of the printers dictates in which order an object should be printed. * We allow that multiple printers might be viable to print a type. * Each `printer` either has a function object / lambda `print` or not; depending on whether the `printer` can print that `type` or not (implemented by [template specialization](https://en.cppreference.com/w/cpp/language/template_specialization)) * We can explicitly use `printer` in other printer's, if we know that only that overload should be used, So put together: For a given type, ask every printer in order whether it can print that type and the first one to answer yes, is the selected printer. ---- [1] If all overloads do not work, use `std::ostream` https://github.com/seqan/seqan3/blob/6b681fb2eae5ab2997d293e99fc6a7f869a20316/include/seqan3/core/debug_stream/debug_stream_type.hpp#L242-L247 [2] Use this for all `std::ranges::input_range`s except if type is something like `std::filesystem` (type == range_value_t) or `char *` https://github.com/seqan/seqan3/blob/6b681fb2eae5ab2997d293e99fc6a7f869a20316/include/seqan3/core/debug_stream/range.hpp#L96-L98 https://github.com/seqan/seqan3/blob/6b681fb2eae5ab2997d293e99fc6a7f869a20316/include/seqan3/core/debug_stream/range.hpp#L38-L45 [3] Same as [2] where value_type is an alphabet but only if the alphabet is not an `unsigned int` (this condition has no test case?!) https://github.com/seqan/seqan3/blob/6b681fb2eae5ab2997d293e99fc6a7f869a20316/include/seqan3/core/debug_stream/range.hpp#L138-L141 [4] Use this for all `std::tuple`-like types except if it is a `std::ranges::input_range` (what is a tuple and ranges at the same time?!) and an `seqan3::alphabet` (basically `seqan3::alphabet_tuple_base` derived types) https://github.com/seqan/seqan3/blob/6b681fb2eae5ab2997d293e99fc6a7f869a20316/include/seqan3/core/debug_stream/tuple.hpp#L53-L56 [5] Use this for all `seqan3::alphabet`s except if it can be printed by `std::cout` (like `char`) https://github.com/seqan/seqan3/blob/6b681fb2eae5ab2997d293e99fc6a7f869a20316/include/seqan3/alphabet/detail/debug_stream_alphabet.hpp#L30-L32 [6] Type must be `seqan3::semialphabet` and `seqan3::mask` https://github.com/seqan/seqan3/blob/6b681fb2eae5ab2997d293e99fc6a7f869a20316/include/seqan3/alphabet/detail/debug_stream_alphabet.hpp#L46-L48 --- .../debug_stream_alignment.hpp | 13 ++ .../advanceable_alignment_coordinate.hpp | 14 +++ .../alignment/matrix/detail/debug_matrix.hpp | 15 +++ .../matrix/detail/trace_directions.hpp | 13 ++ .../alignment/pairwise/alignment_result.hpp | 19 +++ include/seqan3/alphabet/cigar/cigar.hpp | 2 + .../alphabet/detail/debug_stream_alphabet.hpp | 24 ++++ include/seqan3/argument_parser/auxiliary.hpp | 2 + include/seqan3/core/debug_stream/byte.hpp | 2 + .../core/debug_stream/debug_stream_type.hpp | 67 ++++++++++ .../core/debug_stream/default_printer.hpp | 117 ++++++++++++++++++ include/seqan3/core/debug_stream/optional.hpp | 29 +++++ include/seqan3/core/debug_stream/range.hpp | 57 +++++++++ include/seqan3/core/debug_stream/tuple.hpp | 14 +++ include/seqan3/core/debug_stream/variant.hpp | 2 + include/seqan3/core/detail/strong_type.hpp | 2 + include/seqan3/io/sam_file/sam_flag.hpp | 2 + include/seqan3/search/search_result.hpp | 2 + .../utility/container/dynamic_bitset.hpp | 2 + .../utility/simd/detail/debug_stream_simd.hpp | 2 + test/snippet/search/kmer_index/shape.cpp | 16 +++ test/unit/io/record_test.cpp | 2 + test/unit/search/helper.hpp | 2 + test/unit/test/pretty_printing_test.cpp | 4 + 24 files changed, 424 insertions(+) create mode 100644 include/seqan3/core/debug_stream/default_printer.hpp diff --git a/include/seqan3/alignment/aligned_sequence/debug_stream_alignment.hpp b/include/seqan3/alignment/aligned_sequence/debug_stream_alignment.hpp index ed8bcac612..2308758240 100644 --- a/include/seqan3/alignment/aligned_sequence/debug_stream_alignment.hpp +++ b/include/seqan3/alignment/aligned_sequence/debug_stream_alignment.hpp @@ -104,17 +104,30 @@ namespace seqan3 * * \return The given stream to which the alignment representation is appended. */ +#if 0 template requires (detail::debug_streamable_tuple && detail::all_model_aligned_seq>>) inline debug_stream_type & operator<<(debug_stream_type & stream, alignment_t && alignment) { +#else +template + requires (tuple_like> && detail::all_model_aligned_seq>>) +struct alignment_printer +{ + constexpr static auto print = [](auto & stream, auto && alignment) + { constexpr size_t sequence_count = std::tuple_size_v>; static_assert(sequence_count >= 2, "An alignment requires at least two sequences."); detail::stream_alignment(stream, alignment, std::make_index_sequence{}); + }; +}; +#endif +#if 0 return stream; } +#endif } // namespace seqan3 diff --git a/include/seqan3/alignment/matrix/detail/advanceable_alignment_coordinate.hpp b/include/seqan3/alignment/matrix/detail/advanceable_alignment_coordinate.hpp index 31f16c1653..143eb7a3af 100644 --- a/include/seqan3/alignment/matrix/detail/advanceable_alignment_coordinate.hpp +++ b/include/seqan3/alignment/matrix/detail/advanceable_alignment_coordinate.hpp @@ -307,13 +307,27 @@ namespace seqan3 * * Prints the alignment coordinate as a tuple. */ +#if 0 template requires detail::is_value_specialisation_of_v, detail::advanceable_alignment_coordinate> inline debug_stream_type & operator<<(debug_stream_type & s, coordinate_type && c) { +#else +template + requires detail::is_value_specialisation_of_v, + detail::advanceable_alignment_coordinate> +struct advanceable_alignment_coordinate_printer +{ + constexpr static auto print = [](auto & s, coordinate_type const & c) + { s << std::tie(c.first, c.second); + }; +}; +#endif +#if 0 return s; } +#endif } // namespace seqan3 diff --git a/include/seqan3/alignment/matrix/detail/debug_matrix.hpp b/include/seqan3/alignment/matrix/detail/debug_matrix.hpp index 96264f3bc6..90a03ab411 100644 --- a/include/seqan3/alignment/matrix/detail/debug_matrix.hpp +++ b/include/seqan3/alignment/matrix/detail/debug_matrix.hpp @@ -479,17 +479,31 @@ namespace seqan3 * * This prints out an alignment matrix which can be a score matrix or a trace matrix. */ +#if 0 template inline debug_stream_type & operator<<(debug_stream_type & s, alignment_matrix_t && matrix) { +#else +template + requires detail::matrix> +struct alignment_matrix_printer +{ + constexpr static auto print = [](auto & s, auto && matrix) + { detail::debug_matrix debug{std::forward(matrix)}; std::stringstream sstream{}; debug.stream_matrix(sstream, s.flags2()); s << sstream.str(); + }; +}; +#endif +#if 0 return s; } +#endif +#if 0 //!\overload template requires detail::debug_stream_range_guard && detail::matrix @@ -497,5 +511,6 @@ inline debug_stream_type & operator<<(debug_stream_type & s, ali { return s << detail::debug_matrix{std::forward(matrix)}; } +#endif } // namespace seqan3 diff --git a/include/seqan3/alignment/matrix/detail/trace_directions.hpp b/include/seqan3/alignment/matrix/detail/trace_directions.hpp index 9163978560..241b83fc86 100644 --- a/include/seqan3/alignment/matrix/detail/trace_directions.hpp +++ b/include/seqan3/alignment/matrix/detail/trace_directions.hpp @@ -75,9 +75,17 @@ inline constexpr bool add_enum_bitwise_operators inline debug_stream_type & operator<<(debug_stream_type & s, detail::trace_directions const trace) { +#else +template + requires std::is_same_v, detail::trace_directions> +struct trace_directions_printer +{ + constexpr static auto print = [](auto & s, detail::trace_directions const trace) + { static char const * unicode[32]{"↺", "↖", "↑", "↖↑", "⇡", "↖⇡", "↑⇡", "↖↑⇡", "←", "↖←", "↑←", "↖↑←", "⇡←", "↖⇡←", "↑⇡←", "↖↑⇡←", "⇠", "↖⇠", "↑⇠", "↖↑⇠", "⇡⇠", "↖⇡⇠", "↑⇡⇠", "↖↑⇡⇠", "←⇠", "↖←⇠", "↑←⇠", "↖↑←⇠", "⇡←⇠", "↖⇡←⇠", "↑⇡←⇠", "↖↑⇡←⇠"}; @@ -90,7 +98,12 @@ inline debug_stream_type & operator<<(debug_stream_type & s, det auto const & trace_dir = is_unicode ? unicode : csv; s << trace_dir[static_cast(trace)]; + }; +}; +#endif +#if 0 return s; } +#endif } // namespace seqan3 diff --git a/include/seqan3/alignment/pairwise/alignment_result.hpp b/include/seqan3/alignment/pairwise/alignment_result.hpp index bed73123db..61d8e8ff6e 100644 --- a/include/seqan3/alignment/pairwise/alignment_result.hpp +++ b/include/seqan3/alignment/pairwise/alignment_result.hpp @@ -412,10 +412,24 @@ namespace seqan3 * \param[in] result The alignment result to print. * \relates seqan3::debug_stream_type */ +#if 0 template requires detail::is_type_specialisation_of_v, alignment_result> inline debug_stream_type & operator<<(debug_stream_type & stream, alignment_result_t && result) { +#else +template + requires (!std::is_same_v>) +struct alignment_result_printer : public alignment_result_printer> +{ +}; + +template +struct alignment_result_printer> +{ + constexpr static auto print = [](auto & stream, alignment_result const & result) + { + using alignment_result_t = alignment_result; using disabled_t = std::nullopt_t *; using result_data_t = typename detail::alignment_result_value_type_accessor>::type; @@ -451,6 +465,11 @@ inline debug_stream_type & operator<<(debug_stream_type & stream append_to_stream("\nalignment:\n", result.alignment()); stream << '}'; + }; +}; +#endif +#if 0 return stream; } +#endif } // namespace seqan3 diff --git a/include/seqan3/alphabet/cigar/cigar.hpp b/include/seqan3/alphabet/cigar/cigar.hpp index 5b24ba41af..5ec4e5205d 100644 --- a/include/seqan3/alphabet/cigar/cigar.hpp +++ b/include/seqan3/alphabet/cigar/cigar.hpp @@ -210,6 +210,7 @@ class cigar : public alphabet_tuple_base inline debug_stream_type & operator<<(debug_stream_type & s, cigar const c) @@ -217,6 +218,7 @@ inline debug_stream_type & operator<<(debug_stream_type & s, cig s << c.to_string(); return s; } +#endif inline namespace literals { diff --git a/include/seqan3/alphabet/detail/debug_stream_alphabet.hpp b/include/seqan3/alphabet/detail/debug_stream_alphabet.hpp index c85a41d4f1..32a6268fdf 100644 --- a/include/seqan3/alphabet/detail/debug_stream_alphabet.hpp +++ b/include/seqan3/alphabet/detail/debug_stream_alphabet.hpp @@ -18,6 +18,7 @@ namespace seqan3 { +#if 0 /*!\name Formatted output overloads * \{ */ @@ -33,10 +34,22 @@ inline debug_stream_type & operator<<(debug_stream_type & s, alp { return s << to_char(l); } +#else +template + requires alphabet +struct alphabet_printer +{ + constexpr static auto print = [](auto & s, alphabet_t l) + { + s << to_char(l); + }; +}; +#endif // forward declare seqan3::mask class mask; +#if 0 /*!\brief Overload for the seqan3::mask alphabet. * \tparam char_t Type char type of the debug_stream. * \param s The seqan3::debug_stream. @@ -51,5 +64,16 @@ inline debug_stream_type & operator<<(debug_stream_type & s, alp } //!\} +#else +template + requires std::same_as, mask> +struct mask_printer +{ + constexpr static auto print = [](auto & s, alphabet_t const l) + { + s << (l == std::remove_cvref_t{} ? "UNMASKED" : "MASKED"); + }; +}; +#endif } // namespace seqan3 diff --git a/include/seqan3/argument_parser/auxiliary.hpp b/include/seqan3/argument_parser/auxiliary.hpp index 53fb59b96d..f94df10669 100644 --- a/include/seqan3/argument_parser/auxiliary.hpp +++ b/include/seqan3/argument_parser/auxiliary.hpp @@ -222,6 +222,7 @@ concept argument_parser_compatible_option = * This searches the seqan3::enumeration_names of the respective type for the value \p op and prints the * respective string if found or '\' if the value cannot be found in the map. */ +#if 1 template requires named_enumeration> inline debug_stream_type & operator<<(debug_stream_type & s, option_type && op) @@ -234,6 +235,7 @@ inline debug_stream_type & operator<<(debug_stream_type & s, opt return s << ""; } +#endif //!\} /*!\brief Used to further specify argument_parser options/flags. diff --git a/include/seqan3/core/debug_stream/byte.hpp b/include/seqan3/core/debug_stream/byte.hpp index cbcec8479e..4342ac259a 100644 --- a/include/seqan3/core/debug_stream/byte.hpp +++ b/include/seqan3/core/debug_stream/byte.hpp @@ -28,6 +28,7 @@ namespace seqan3 * \param[in] arg The std::byte. * \relates seqan3::debug_stream_type */ +#if 1 template requires std::same_as, std::byte> inline debug_stream_type & operator<<(debug_stream_type & s, byte_type && arg) @@ -35,6 +36,7 @@ inline debug_stream_type & operator<<(debug_stream_type & s, byt s << std::to_integer(arg); return s; } +#endif //!\} diff --git a/include/seqan3/core/debug_stream/debug_stream_type.hpp b/include/seqan3/core/debug_stream/debug_stream_type.hpp index 2671f49df8..740fb7ff53 100644 --- a/include/seqan3/core/debug_stream/debug_stream_type.hpp +++ b/include/seqan3/core/debug_stream/debug_stream_type.hpp @@ -13,8 +13,10 @@ #pragma once #include +#include #include +#include namespace seqan3 { @@ -124,7 +126,22 @@ class debug_stream_type */ //!\brief Forwards to the underlying stream object. template +#if 0 friend debug_stream_type & operator<<(debug_stream_type & s, t && v); +#else + friend debug_stream_type & operator<<(debug_stream_type & s, t && v) + { + using t_ = std::remove_cvref_t; + + if constexpr(default_printer::is_printable) { + default_printer::print(s, v); + } else { + std::string const msg = std::string{"debug_stream has no print overload for type: "} + typeid(v).name(); + throw std::runtime_error{msg}; + } + return s; + } +#endif //!\brief This overloads enables forwarding std::endl and other manipulators. debug_stream_type & operator<<(std::ostream & (*fp)(std::ostream &)) @@ -133,6 +150,7 @@ class debug_stream_type return *this; } +#if 0 //!\cond debug_stream_type & operator<<(int8_t const v) { @@ -151,6 +169,15 @@ class debug_stream_type *stream << v; return *this; } +#else + + template + friend struct debug_stream_printer; + + template + friend struct std_printer; + +#endif //!\endcond //!\} @@ -189,6 +216,7 @@ class debug_stream_type #ifdef _LIBCPP_VERSION static_assert(std::same_as); #else +#if 0 //!\copybrief setf() debug_stream_type & operator<<(fmtflags const flag) { @@ -197,6 +225,7 @@ class debug_stream_type } #endif //!\} +#endif /*!\name Format flags (seqan3::fmtflags2) * \brief SeqAn specific debug flags for the debug stream. @@ -227,6 +256,7 @@ class debug_stream_type flgs2 &= ~flag; } +#if 0 //!\copybrief setf() debug_stream_type & operator<<(fmtflags2 const flag) { @@ -234,6 +264,7 @@ class debug_stream_type return *this; } //!\} +#endif private: //!\brief Pointer to the output stream. @@ -243,6 +274,41 @@ class debug_stream_type fmtflags2 flgs2{fmtflags2::default_}; }; +template + requires (std::is_same_v, int8_t> || std::is_same_v, uint8_t> || std::is_same_v, fmtflags2>) +struct debug_stream_printer +{ + struct print_fn + { + template + constexpr void operator()(stream_t & s, int8_t const v) const + { + if ((s.flags2() & fmtflags2::small_int_as_number) == fmtflags2::small_int_as_number) + *s.stream << static_cast(v); + else + *s.stream << v; + } + + template + constexpr void operator()(stream_t & s, uint8_t const v) const + { + if ((s.flags2() & fmtflags2::small_int_as_number) == fmtflags2::small_int_as_number) + *s.stream << static_cast(v); + else + *s.stream << v; + } + + template + constexpr void operator()(stream_t & s, fmtflags2 const flag) const + { + s.setf(flag); + } + }; + + static constexpr print_fn print{}; +}; + +#if 0 //!\brief Forwards to the underlying stream object. template debug_stream_type & operator<<(debug_stream_type & s, t && v) @@ -250,5 +316,6 @@ debug_stream_type & operator<<(debug_stream_type & s, t && v) (*s.stream) << v; return s; } +#endif } // namespace seqan3 diff --git a/include/seqan3/core/debug_stream/default_printer.hpp b/include/seqan3/core/debug_stream/default_printer.hpp new file mode 100644 index 0000000000..7c682e04e0 --- /dev/null +++ b/include/seqan3/core/debug_stream/default_printer.hpp @@ -0,0 +1,117 @@ +#pragma once + +#include +#include +#include + +#include + +namespace seqan3 +{ + +struct no_printer_found{}; +template struct advanceable_alignment_coordinate_printer {}; +template struct alignment_matrix_printer {}; +template struct alignment_printer {}; +template struct alignment_result_printer {}; +template struct alphabet_printer {}; +template struct debug_stream_printer {}; +template struct input_range_printer {}; +template struct integer_sequence_printer {}; +template struct integral_printer {}; +template struct mask_printer {}; +template struct optional_printer {}; +template struct sequence_printer {}; +template struct std_printer {}; +template struct char_sequence_printer {}; +template struct trace_directions_printer {}; +template struct tuple_printer {}; + +template +concept printable = requires() { { printer_t::print }; }; + +template + requires requires(std::ostream & cout, type_t value) + { + {cout << value}; + } +struct std_printer +{ + static constexpr auto print = [](auto & s, auto && value) + { + *s.stream << std::forward(value); + }; +}; + +template + requires std::integral> +struct integral_printer +{ + static constexpr auto print = [](auto & s, auto const value) + { + // note that we assume here that we always can print all std::integral's, + // but this is not correct since std::cout << char32_t{5}; is not possible. + // since char32_t is also an alphabet, we avoid infinite recursion here. + if constexpr(printable>) + std_printer::print(s, value); + else + static_assert(std::same_as, "This type is not printable."); + }; +}; + +template typename ...printers_t> +struct printer_order +{ + template + static constexpr std::ptrdiff_t find_index() + { + std::ptrdiff_t i = 0; + return ((printable ? false : ++i) && ...) ? -1 : i; + } + + template ...>()> + using printer_for_t = std::tuple_element_t< + i == -1 ? sizeof...(printers_t) : i, + std::tuple..., no_printer_found>>; + + // std::tuple<...> list of all printers that can print type_t + // NOTE: printer_order<...> might be nicer but is more complicated to write + template + using printers_for_t = decltype(std::tuple_cat(std::conditional_t>, std::tuple>, std::tuple<>>{}...)); + + template + static constexpr bool is_printable = printable>; + + static constexpr auto print = [](auto & s, auto && arg) + { + using printer_t = printer_for_t; + printer_t::print(s, std::forward(arg)); + }; +}; + +struct default_printer : printer_order< + debug_stream_printer, + + alignment_result_printer, // type seqan3::alignment_result<> + alignment_printer, // concept seqan3::tuple_like<> + advanceable_alignment_coordinate_printer, // type seqan3::detail::advanceable_alignment_coordinate<> + alignment_matrix_printer, // concept seqan3::detail::matrix<> + trace_directions_printer, // type seqan3::detail::trace_directions + + mask_printer, // type seqan3::mask + integral_printer, // concept std::integral + // NOTE: alphabet_printer needs the integral_printer overload, otherwise might have infinite recursion due to char and uint beeing an alphabet + alphabet_printer, // concept seqan3::alphabet + + char_sequence_printer, // concept std::range::input_range<> with char value_type + integer_sequence_printer, // concept std::range::input_range<> with std::integral value_type + sequence_printer, // concept seqan3::sequence<>, i.e. std::range::input_range<> with seqan3::alphabet value_type + input_range_printer, // concept std::range::input_range<> + + optional_printer, // type std::optional<> or std::nullopt_t + tuple_printer, // concept seqan3::tuple_like<> + std_printer // anything that can be printed by std::ostream +> +{}; + +} // namespace seqan3 diff --git a/include/seqan3/core/debug_stream/optional.hpp b/include/seqan3/core/debug_stream/optional.hpp index 637e791fde..5e5b74d05a 100644 --- a/include/seqan3/core/debug_stream/optional.hpp +++ b/include/seqan3/core/debug_stream/optional.hpp @@ -29,6 +29,7 @@ namespace seqan3 * \param[in] arg This is std::nullopt. * \relates seqan3::debug_stream_type */ +#if 0 template inline debug_stream_type & operator<<(debug_stream_type & s, std::nullopt_t SEQAN3_DOXYGEN_ONLY(arg)) { @@ -52,6 +53,34 @@ inline debug_stream_type & operator<<(debug_stream_type & s, opt s << ""; return s; } +#else +template + requires (!std::is_same_v>) +struct optional_printer : public optional_printer> +{ +}; + +template <> +struct optional_printer +{ + constexpr static auto print = [](auto & s, std::nullopt_t SEQAN3_DOXYGEN_ONLY(arg)) + { + s << ""; + }; +}; + +template +struct optional_printer> +{ + constexpr static auto print = [](auto & s, auto && arg) + { + if (arg.has_value()) + s << *arg; + else + s << ""; + }; +}; +#endif //!\} diff --git a/include/seqan3/core/debug_stream/range.hpp b/include/seqan3/core/debug_stream/range.hpp index d56cd132f7..09d1fb6fdf 100644 --- a/include/seqan3/core/debug_stream/range.hpp +++ b/include/seqan3/core/debug_stream/range.hpp @@ -93,12 +93,27 @@ namespace seqan3 * to avoid ambiguous function calls. * \endif */ +#if 0 template inline debug_stream_type & operator<<(debug_stream_type & s, rng_t && r) requires detail::debug_stream_range_guard { +#else + +// e.g. std::filesystem +template +concept nonrecursive_range = !std::same_as>, std::remove_cvref_t>; + +template + requires std::ranges::input_range && nonrecursive_range +struct input_range_printer +{ + constexpr static auto print = [](auto & s, auto && r) + { +#if 0 static_assert(detail::reference_type_is_streamable_v, "The reference type of the passed range cannot be streamed into the debug_stream."); +#endif s << '['; auto b = std::ranges::begin(r); @@ -115,9 +130,14 @@ inline debug_stream_type & operator<<(debug_stream_type & s, rng ++b; } s << ']'; + }; +}; +#endif +#if 0 return s; } +#endif /*!\brief All biological sequences can be printed to the seqan3::debug_stream. * \tparam sequence_t Type of the (biological) sequence to be printed; must model seqan3::sequence. @@ -135,15 +155,52 @@ inline debug_stream_type & operator<<(debug_stream_type & s, rng * to avoid ambiguous function calls. * \endif */ +#if 0 template inline debug_stream_type & operator<<(debug_stream_type & s, sequence_t && sequence) requires detail::debug_stream_range_guard && (!detail::is_uint_adaptation_v>>) { +#else +template + requires sequence +struct sequence_printer +{ + constexpr static auto print = [](auto & s, auto && sequence) + { for (auto && chr : sequence) s << chr; + }; +}; +#endif +#if 0 return s; } +#endif + +// basically same as is_char_adaptation_v +template +static constexpr bool is_char_type_v = std::same_as || std::same_as || std::same_as || std::same_as; + +template + requires std::ranges::input_range && (is_char_type_v>>) +struct char_sequence_printer +{ + constexpr static auto print = [](auto & s, auto && sequence) + { + if constexpr(std::is_pointer_v>) + return std_printer::print(s, sequence); + + for (auto && chr : sequence) + s << chr; + }; +}; + +template + requires std::ranges::input_range && std::integral>> +struct integer_sequence_printer : public input_range_printer +{ +}; //!\} diff --git a/include/seqan3/core/debug_stream/tuple.hpp b/include/seqan3/core/debug_stream/tuple.hpp index e4430e6a57..a25a3943bf 100644 --- a/include/seqan3/core/debug_stream/tuple.hpp +++ b/include/seqan3/core/debug_stream/tuple.hpp @@ -60,6 +60,7 @@ std::ranges::input_range && !alphabet && // exclude alphabet_t namespace seqan3 { +#if 0 /*!\brief All tuples can be printed by printing their elements separately. * \tparam tuple_t Type of the tuple to be printed; must model seqan3::tuple_like. * \param s The seqan3::debug_stream. @@ -70,11 +71,24 @@ template requires (detail::debug_streamable_tuple) inline debug_stream_type & operator<<(debug_stream_type & s, tuple_t && t) { +#else +template + requires tuple_like +struct tuple_printer +{ + constexpr static auto print = [](auto & s, auto && t) + { + using tuple_t = decltype(t); detail::print_tuple(s, std::forward(t), std::make_index_sequence>>{}); + }; +}; +#endif +#if 0 return s; } +#endif //!\} diff --git a/include/seqan3/core/debug_stream/variant.hpp b/include/seqan3/core/debug_stream/variant.hpp index 1d7ba97760..a4badc597e 100644 --- a/include/seqan3/core/debug_stream/variant.hpp +++ b/include/seqan3/core/debug_stream/variant.hpp @@ -33,6 +33,7 @@ namespace seqan3 * * Note that in case the variant is valueless(_by_exception), nothing is printed. */ +#if 1 template requires detail::is_type_specialisation_of_v, std::variant> inline debug_stream_type & operator<<(debug_stream_type & s, variant_type && v) @@ -48,6 +49,7 @@ inline debug_stream_type & operator<<(debug_stream_type & s, var s << ""; return s; } +#endif //!\} diff --git a/include/seqan3/core/detail/strong_type.hpp b/include/seqan3/core/detail/strong_type.hpp index 8cbbdfc7b6..67fcaba296 100644 --- a/include/seqan3/core/detail/strong_type.hpp +++ b/include/seqan3/core/detail/strong_type.hpp @@ -475,12 +475,14 @@ class strong_type * * \returns `stream_t &` A reference to the given stream. */ +#if 1 template debug_stream_type & operator<<(debug_stream_type & stream, strong_type_t && value) { stream << value.get(); return stream; } +#endif //!\} } // namespace seqan3::detail diff --git a/include/seqan3/io/sam_file/sam_flag.hpp b/include/seqan3/io/sam_file/sam_flag.hpp index e2c938dda7..6dde134f54 100644 --- a/include/seqan3/io/sam_file/sam_flag.hpp +++ b/include/seqan3/io/sam_file/sam_flag.hpp @@ -103,10 +103,12 @@ inline constexpr bool add_enum_bitwise_operators = true; * \param flag The flag to print. * \relates seqan3::debug_stream_type */ +#if 1 template inline debug_stream_type & operator<<(debug_stream_type & stream, sam_flag const flag) { return stream << static_cast(flag); } +#endif } // namespace seqan3 diff --git a/include/seqan3/search/search_result.hpp b/include/seqan3/search/search_result.hpp index a55c546f73..2587489a73 100644 --- a/include/seqan3/search/search_result.hpp +++ b/include/seqan3/search/search_result.hpp @@ -191,6 +191,7 @@ class search_result * \param result The search result to print. * \relates seqan3::debug_stream_type */ +#if 1 template requires detail::is_type_specialisation_of_v, search_result> inline debug_stream_type & operator<<(debug_stream_type & stream, search_result_t && result) @@ -210,5 +211,6 @@ inline debug_stream_type & operator<<(debug_stream_type & stream return stream; } +#endif } // namespace seqan3 diff --git a/include/seqan3/utility/container/dynamic_bitset.hpp b/include/seqan3/utility/container/dynamic_bitset.hpp index c8a2b097be..7e9247ee10 100644 --- a/include/seqan3/utility/container/dynamic_bitset.hpp +++ b/include/seqan3/utility/container/dynamic_bitset.hpp @@ -1939,6 +1939,7 @@ class dynamic_bitset * * \experimentalapi{Experimental since version 3.1.} */ +#if 1 template friend debug_stream_type & operator<<(debug_stream_type & s, dynamic_bitset arg) { @@ -1946,6 +1947,7 @@ class dynamic_bitset | ranges::to()); return s; } +#endif //!\} //!\cond DEV diff --git a/include/seqan3/utility/simd/detail/debug_stream_simd.hpp b/include/seqan3/utility/simd/detail/debug_stream_simd.hpp index 30fbd9d5bb..4cb3843fd2 100644 --- a/include/seqan3/utility/simd/detail/debug_stream_simd.hpp +++ b/include/seqan3/utility/simd/detail/debug_stream_simd.hpp @@ -23,6 +23,7 @@ namespace seqan3 /*!\brief Overload for debug_stream for simd types. * \ingroup utility_simd */ +#if 1 template requires simd::simd_concept> inline debug_stream_type & operator<<(debug_stream_type & s, simd_t && simd) @@ -37,5 +38,6 @@ inline debug_stream_type & operator<<(debug_stream_type & s, sim s << array; return s; } +#endif } // namespace seqan3 diff --git a/test/snippet/search/kmer_index/shape.cpp b/test/snippet/search/kmer_index/shape.cpp index 363abf9183..c3d355b9a3 100644 --- a/test/snippet/search/kmer_index/shape.cpp +++ b/test/snippet/search/kmer_index/shape.cpp @@ -5,6 +5,22 @@ using namespace seqan3::literals; +#if 1 +// this case is fun, as seqan3::shape has no explicit std::cout/debug_stream overload. +// * if we have +// printer_order +// the std::cout overload of seqan3::dynamic_bitset will win as it is the most specific +// seqan3::debug_stream << s0; will print 11111 +// * if we have +// printer_order +// the input_range_printer will win since seqan3::dynamic_bitset is an input_range +// seqan3::debug_stream << s0; will print [1,1,1,1,1] +// +// Interestingly seqan3::dynamic_bitset has also an debug_stream overload, but this one will +// only be active if the type is seqan3::dynamic_bitset +// seqan3::debug_stream << (seqan3::dynamic_bitset<58>&)s0; will print 1'1111 +#endif + int main() { seqan3::shape s0{seqan3::ungapped{5}}; // represents "11111", i.e. ungapped 5-mer diff --git a/test/unit/io/record_test.cpp b/test/unit/io/record_test.cpp index 5dede3aba7..75153de114 100644 --- a/test/unit/io/record_test.cpp +++ b/test/unit/io/record_test.cpp @@ -24,12 +24,14 @@ using default_fields = seqan3::fields inline debug_stream_type & operator<<(debug_stream_type & stream, field f) { stream << "(f) << ">"; return stream; } +#endif } // namespace seqan3 // ---------------------------------------------------------------------------- diff --git a/test/unit/search/helper.hpp b/test/unit/search/helper.hpp index c4b550b3d1..874faf3344 100644 --- a/test/unit/search/helper.hpp +++ b/test/unit/search/helper.hpp @@ -18,6 +18,7 @@ namespace seqan3 { +#if 1 template inline debug_stream_type & operator<<(debug_stream_type & s, seqan3::fm_index_cursor const &) { @@ -30,6 +31,7 @@ inline debug_stream_type & operator<<(debug_stream_type & s, { return s << ("bi_fm_index_cursor"); } +#endif template std::vector> uniquify(result_range_t && result_range) diff --git a/test/unit/test/pretty_printing_test.cpp b/test/unit/test/pretty_printing_test.cpp index f618ec95cf..74dfad43ef 100644 --- a/test/unit/test/pretty_printing_test.cpp +++ b/test/unit/test/pretty_printing_test.cpp @@ -121,6 +121,7 @@ struct my_type namespace seqan3 { +#if 1 template requires std::same_as, detail::my_type> inline debug_stream_type & operator<<(debug_stream_type & s, my_type && m) @@ -128,6 +129,7 @@ inline debug_stream_type & operator<<(debug_stream_type & s, my_ s << m.str; return s; } +#endif } // namespace seqan3 @@ -144,6 +146,7 @@ namespace seqan3 struct your_type : public detail::my_type {}; +#if 1 template requires std::same_as, ::seqan3::your_type> inline debug_stream_type & operator<<(debug_stream_type & s, your_type && m) @@ -151,6 +154,7 @@ inline debug_stream_type & operator<<(debug_stream_type & s, you s << m.str; return s; } +#endif } // namespace seqan3