diff --git a/.github/workflows/ci_linux.yml b/.github/workflows/ci_linux.yml index 1e0c04e3fe..38d11bc3f7 100644 --- a/.github/workflows/ci_linux.yml +++ b/.github/workflows/ci_linux.yml @@ -31,6 +31,12 @@ jobs: fail-fast: true matrix: include: + - name: "clang17 libc++" + compiler: "clang-17" + build: unit + build_type: Release + cxx_flags: "-stdlib=libc++" + - name: "clang17" compiler: "clang-17" build: unit diff --git a/include/seqan3/core/debug_stream.hpp b/include/seqan3/core/debug_stream.hpp index 2c29892d3e..c86dfbd3a1 100644 --- a/include/seqan3/core/debug_stream.hpp +++ b/include/seqan3/core/debug_stream.hpp @@ -21,7 +21,10 @@ //!\cond namespace std { +namespace +{ extern ostream cerr; +} } // namespace std //!\endcond diff --git a/include/seqan3/core/debug_stream/debug_stream_type.hpp b/include/seqan3/core/debug_stream/debug_stream_type.hpp index 36c88e5756..9dae4e382f 100644 --- a/include/seqan3/core/debug_stream/debug_stream_type.hpp +++ b/include/seqan3/core/debug_stream/debug_stream_type.hpp @@ -185,12 +185,17 @@ class debug_stream_type stream->unsetf(flag); } +// fmtflags is an enum in libstdc++ and an unsigned in libc++ +#ifdef _LIBCPP_VERSION + static_assert(std::same_as); +#else //!\copybrief setf() debug_stream_type & operator<<(fmtflags const flag) { setf(flag); return *this; } +#endif //!\} /*!\name Format flags (seqan3::fmtflags2) diff --git a/include/seqan3/io/sam_file/format_bam.hpp b/include/seqan3/io/sam_file/format_bam.hpp index c51f9165ed..92a6859b40 100644 --- a/include/seqan3/io/sam_file/format_bam.hpp +++ b/include/seqan3/io/sam_file/format_bam.hpp @@ -401,8 +401,8 @@ format_bam::read_alignment_record(stream_type & stream, ref_id = core.refID; // field::ref_id } - flag = core.flag; // field::flag - mapq = core.mapq; // field::mapq + flag = core.flag; // field::flag + mapq = static_cast(core.mapq); // field::mapq if (core.pos > -1) // [[likely]] ref_offset = core.pos; // field::ref_offset diff --git a/include/seqan3/io/sequence_file/format_embl.hpp b/include/seqan3/io/sequence_file/format_embl.hpp index 5137c3f4a8..0a58347c35 100644 --- a/include/seqan3/io/sequence_file/format_embl.hpp +++ b/include/seqan3/io/sequence_file/format_embl.hpp @@ -105,12 +105,14 @@ class format_embl id_type & id, qual_type & SEQAN3_DOXYGEN_ONLY(qualities)) { + // Store current position in buffer + // Must happen before constructing the view. + // With libc++, tellg invalidates the I/O buffer. + position_buffer = stream.tellg(); + auto stream_view = detail::istreambuf(stream); auto stream_it = std::ranges::begin(stream_view); - // Store current position in buffer. - position_buffer = stream.tellg(); - std::string idbuffer; std::ranges::copy(stream_view | detail::take_until_or_throw(is_cntrl || is_blank), std::back_inserter(idbuffer)); @@ -195,12 +197,10 @@ class format_embl } else { - detail::consume(stream_view | detail::take_until(is_end)); + detail::consume(stream_view | detail::take_until_or_throw(is_end)); // consume until "//" } - //Jump over // and cntrl - ++stream_it; - ++stream_it; - ++stream_it; + + std::ranges::advance(stream_it, 3u, std::ranges::end(stream_view)); // Skip `//` and potentially '\n' } //!\copydoc sequence_file_output_format::write_sequence_record diff --git a/include/seqan3/io/sequence_file/format_fasta.hpp b/include/seqan3/io/sequence_file/format_fasta.hpp index 98469ff02d..36edf78810 100755 --- a/include/seqan3/io/sequence_file/format_fasta.hpp +++ b/include/seqan3/io/sequence_file/format_fasta.hpp @@ -117,11 +117,13 @@ class format_fasta id_type & id, qual_type & SEQAN3_DOXYGEN_ONLY(qualities)) { - auto stream_view = detail::istreambuf(stream); - // Store current position in buffer + // Must happen before constructing the view. + // With libc++, tellg invalidates the I/O buffer. position_buffer = stream.tellg(); + auto stream_view = detail::istreambuf(stream); + // ID read_id(stream_view, options, id); diff --git a/include/seqan3/io/sequence_file/format_fastq.hpp b/include/seqan3/io/sequence_file/format_fastq.hpp index 4de369a3c4..51e0eb0457 100644 --- a/include/seqan3/io/sequence_file/format_fastq.hpp +++ b/include/seqan3/io/sequence_file/format_fastq.hpp @@ -109,6 +109,11 @@ class format_fastq id_type & id, qual_type & qualities) { + // Store current position in buffer + // Must happen before constructing the view. + // With libc++, tellg invalidates the I/O buffer. + position_buffer = stream.tellg(); + auto stream_view = detail::istreambuf(stream); auto stream_it = std::ranges::begin(stream_view); @@ -117,7 +122,6 @@ class format_fastq size_t sequence_size_after = 0; if constexpr (!detail::decays_to_ignore_v) sequence_size_before = size(sequence); - position_buffer = stream.tellg(); /* ID */ if (*stream_it != '@') // [[unlikely]] diff --git a/include/seqan3/io/sequence_file/format_genbank.hpp b/include/seqan3/io/sequence_file/format_genbank.hpp index ccfd7c6be1..e8e4fd6970 100644 --- a/include/seqan3/io/sequence_file/format_genbank.hpp +++ b/include/seqan3/io/sequence_file/format_genbank.hpp @@ -106,12 +106,14 @@ class format_genbank id_type & id, qual_type & SEQAN3_DOXYGEN_ONLY(qualities)) { + // Store current position in buffer + // Must happen before constructing the view. + // With libc++, tellg invalidates the I/O buffer. + position_buffer = stream.tellg(); + auto stream_view = detail::istreambuf(stream); auto stream_it = std::ranges::begin(stream_view); - // Store current position in buffer. - position_buffer = stream.tellg(); - if (!(std::ranges::equal(stream_view | detail::take_until_or_throw(is_cntrl || is_blank), std::string{"LOCUS"}))) throw parse_error{"An entry has to start with the code word LOCUS."}; @@ -162,8 +164,8 @@ class format_genbank { constexpr auto is_legal_alph = char_is_valid_for; std::ranges::copy( - stream_view | std::views::filter(!(is_space || is_digit)) - | detail::take_until_or_throw_and_consume(is_end) // consume "//" + stream_view | std::views::filter(!(is_space || is_digit)) // ignore whitespace and numbers + | detail::take_until_or_throw(is_end) // until // | std::views::transform( [is_legal_alph](char const c) // enforce legal alphabet { @@ -181,9 +183,10 @@ class format_genbank } else { - detail::consume(stream_view | detail::take_until_or_throw_and_consume(is_end)); // consume until "//" - ++stream_it; // consume "/n" + detail::consume(stream_view | detail::take_until_or_throw(is_end)); // consume until "//" } + + std::ranges::advance(stream_it, 3u, std::ranges::end(stream_view)); // Skip `//` and potentially '\n' } //!\copydoc sequence_file_output_format::write_sequence_record diff --git a/include/seqan3/io/stream/detail/fast_istreambuf_iterator.hpp b/include/seqan3/io/stream/detail/fast_istreambuf_iterator.hpp index 4b3b4fdfc0..be3b7bf87e 100644 --- a/include/seqan3/io/stream/detail/fast_istreambuf_iterator.hpp +++ b/include/seqan3/io/stream/detail/fast_istreambuf_iterator.hpp @@ -229,6 +229,7 @@ class fast_istreambuf_iterator reference operator*() const { assert(stream_buf != nullptr); + assert(stream_buf->gptr() != stream_buf->egptr()); return *stream_buf->gptr(); } diff --git a/include/seqan3/search/configuration/parallel.hpp b/include/seqan3/search/configuration/parallel.hpp index 6badf83c9c..c3464f5588 100644 --- a/include/seqan3/search/configuration/parallel.hpp +++ b/include/seqan3/search/configuration/parallel.hpp @@ -31,7 +31,7 @@ namespace seqan3::search_cfg * * \include test/snippet/search/configuration_parallel.cpp */ -using parallel = - seqan3::detail::parallel_mode>; +using parallel = seqan3::detail::parallel_mode< + std::integral_constant>; } // namespace seqan3::search_cfg diff --git a/include/seqan3/search/detail/search_configurator.hpp b/include/seqan3/search/detail/search_configurator.hpp index 972b1df270..7e5031658c 100644 --- a/include/seqan3/search/detail/search_configurator.hpp +++ b/include/seqan3/search/detail/search_configurator.hpp @@ -244,23 +244,20 @@ algorithm_t search_configurator::configure_hit_strategy(configuration_t const & auto cfg_without_hit = cfg.template remove(); // Apply the correct static configuration element. - return std::visit(multi_invocable{[&](search_cfg::hit_all_best) - { - return next_config_step(cfg_without_hit | search_cfg::hit_all_best{}); - }, - [&](search_cfg::hit_single_best) - { - return next_config_step(cfg_without_hit | search_cfg::hit_single_best{}); - }, - [&](search_cfg::hit_strata const & strata) - { - return next_config_step(cfg_without_hit | strata); - }, - [&](auto) - { - return next_config_step(cfg_without_hit | search_cfg::hit_all{}); - }}, - hit_variant); + if (std::holds_alternative(hit_variant)) + { + return next_config_step(cfg_without_hit | search_cfg::hit_all_best{}); + } + else if (std::holds_alternative(hit_variant)) + { + return next_config_step(cfg_without_hit | search_cfg::hit_single_best{}); + } + else if (std::holds_alternative(hit_variant)) + { + return next_config_step(cfg_without_hit | std::get(hit_variant)); + } + else + return next_config_step(cfg_without_hit | search_cfg::hit_all{}); } else // Already statically configured. { diff --git a/test/unit/alignment/pairwise/edit_distance/proxy_reference_test.cpp b/test/unit/alignment/pairwise/edit_distance/proxy_reference_test.cpp index 8aa3192d39..22b689731a 100644 --- a/test/unit/alignment/pairwise/edit_distance/proxy_reference_test.cpp +++ b/test/unit/alignment/pairwise/edit_distance/proxy_reference_test.cpp @@ -11,17 +11,23 @@ using seqan3::detail::proxy_reference; -namespace std +template +struct remove_reference { + using type = std::remove_reference_t; +}; + template struct remove_reference> { using type = T; }; -} // namespace std + +template +using remove_reference_t = typename remove_reference::type; template -constexpr bool is_const_ref_v = std::is_const_v>; +constexpr bool is_const_ref_v = std::is_const_v>; template using reference_test = ::testing::Test; diff --git a/test/unit/alphabet/views/char_strictly_to_test.cpp b/test/unit/alphabet/views/char_strictly_to_test.cpp index 3001d167dd..0ae6a229a7 100644 --- a/test/unit/alphabet/views/char_strictly_to_test.cpp +++ b/test/unit/alphabet/views/char_strictly_to_test.cpp @@ -79,5 +79,5 @@ TEST(view_char_strictly_to, exception) std::string foo = "ACGPTA"; auto v = foo | seqan3::views::char_strictly_to; - EXPECT_THROW((std::ranges::equal(v, "ACGNTA"_dna5)), seqan3::invalid_char_assignment); + EXPECT_THROW(static_cast(std::ranges::equal(v, "ACGNTA"_dna5)), seqan3::invalid_char_assignment); } diff --git a/test/unit/alphabet/views/validate_char_for_test.cpp b/test/unit/alphabet/views/validate_char_for_test.cpp index d5fb90e1cf..6bd0574176 100644 --- a/test/unit/alphabet/views/validate_char_for_test.cpp +++ b/test/unit/alphabet/views/validate_char_for_test.cpp @@ -79,5 +79,5 @@ TEST(view_validate_char_for, exception) std::string foo = "ACGPTA"; auto v = foo | seqan3::views::validate_char_for; - EXPECT_THROW((std::ranges::equal(v, "ACGNTA"sv)), seqan3::invalid_char_assignment); + EXPECT_THROW(static_cast(std::ranges::equal(v, "ACGNTA"sv)), seqan3::invalid_char_assignment); } diff --git a/test/unit/core/debug_stream_test.cpp b/test/unit/core/debug_stream_test.cpp index 33b4693bb5..902e7d97cd 100644 --- a/test/unit/core/debug_stream_test.cpp +++ b/test/unit/core/debug_stream_test.cpp @@ -286,3 +286,14 @@ TEST(debug_stream_test, byte) o.flush(); EXPECT_EQ(o.str(), "40,244"); } + +TEST(debug_stream_test, integers) +{ + std::ostringstream o{}; + seqan3::debug_stream_type my_stream{o}; + + my_stream << uint8_t{1} << ',' << uint16_t{2} << ',' << uint32_t{3} << ',' << uint64_t{4} << ',' << size_t{5} << ',' + << int8_t{6} << ',' << int16_t{7} << ',' << int32_t{8} << ',' << int64_t{9}; + o.flush(); + EXPECT_EQ(o.str(), "1,2,3,4,5,6,7,8,9"); +} diff --git a/test/unit/io/sequence_file/sequence_file_format_genbank_test.cpp b/test/unit/io/sequence_file/sequence_file_format_genbank_test.cpp index 18af6e72b1..4eb1c318ee 100644 --- a/test/unit/io/sequence_file/sequence_file_format_genbank_test.cpp +++ b/test/unit/io/sequence_file/sequence_file_format_genbank_test.cpp @@ -50,8 +50,7 @@ DEFINITION Homo sapiens mRNA for prepro cortistatin like peptide, complete ACCESSION ID3 ORIGIN 1 ACGTTTA -// -)"}; +//)"}; std::string illegal_alphabet_character_input{ R"(LOCUS ID1 diff --git a/test/unit/test/expect_same_type_test.cpp b/test/unit/test/expect_same_type_test.cpp index 1b5104bb2b..a975812557 100644 --- a/test/unit/test/expect_same_type_test.cpp +++ b/test/unit/test/expect_same_type_test.cpp @@ -161,12 +161,19 @@ TEST(tuple, same_type_pass) TEST(tuple, same_type_fail) { +#ifdef _LIBCPP_VERSION + char const * error_message = "Expected equality of these values:\n" + " decltype(std::tuple{0, .0f, .0, 0u})\n" + " Which is: \"std::__1::tuple\"\n" + " std::tuple\n" + " Which is: \"std::__1::tuple\""; +#else char const * error_message = "Expected equality of these values:\n" " decltype(std::tuple{0, .0f, .0, 0u})\n" " Which is: \"std::tuple\"\n" " std::tuple\n" " Which is: \"std::tuple\""; - +#endif auto && expect_result = seqan3::test::expect_same_type{}("std::type_identity< decltype(std::tuple{0, .0f, .0, 0u})>{}", "std::type_identity< std::tuple>{}", diff --git a/test/unit/test/sequence_generator_test.cpp b/test/unit/test/sequence_generator_test.cpp index debd923057..04cd199c06 100644 --- a/test/unit/test/sequence_generator_test.cpp +++ b/test/unit/test/sequence_generator_test.cpp @@ -21,8 +21,13 @@ TEST(random_sequence_generator, fixed_length) seqan3::test::random_sequence_generator random_sequence_generator{3}; +#ifdef _LIBCPP_VERSION + EXPECT_EQ(random_sequence_generator(random_engine), "GTC"_dna4); + EXPECT_EQ(random_sequence_generator(random_engine), "GAG"_dna4); +#else EXPECT_EQ(random_sequence_generator(random_engine), "TAG"_dna4); EXPECT_EQ(random_sequence_generator(random_engine), "AGC"_dna4); +#endif } // generate (single) variable sized sequence, generates sequence with size ± size_variance. @@ -35,9 +40,15 @@ TEST(random_sequence_generator, variable_length_and_different_random_engines) seqan3::test::random_sequence_generator random_sequence_generator{4, 2}; +#ifdef _LIBCPP_VERSION + EXPECT_EQ(random_sequence_generator(random_engine1), "TCCGTT"_dna5); + EXPECT_EQ(random_sequence_generator(random_engine2), "CGTAAG"_dna5); + EXPECT_EQ(random_sequence_generator(random_engine3), "GA"_dna5); +#else EXPECT_EQ(random_sequence_generator(random_engine1), "CCAN"_dna5); EXPECT_EQ(random_sequence_generator(random_engine2), "NN"_dna5); EXPECT_EQ(random_sequence_generator(random_engine3), "AG"_dna5); +#endif } // generate a collection of variable/fixed sized sequences @@ -54,7 +65,11 @@ TEST(random_sequence_generator, sequence_collection) return random_sequence_generator(random_engine); }); +#ifdef _LIBCPP_VERSION + std::vector resulting_sequences = {"CTACN"_dna5, "AC"_dna5, "CTCGG"_dna5, "GGCANN"_dna5}; +#else std::vector resulting_sequences = {"TA"_dna5, "GANG"_dna5, "TGNTCC"_dna5, "NNGC"_dna5}; +#endif EXPECT_EQ(sequences, resulting_sequences); } @@ -73,9 +88,15 @@ TEST(random_sequence_generator, sequence_pairs) return {random_sequence_generator(random_engine), random_sequence_generator(random_engine)}; }); +#ifdef _LIBCPP_VERSION + std::vector> resulting_pairs{{"CTACN"_dna5, "AC"_dna5}, + {"CTCGG"_dna5, "GGCANN"_dna5}, + {"CACA"_dna5, "CNC"_dna5}}; +#else std::vector> resulting_pairs{{"TA"_dna5, "GANG"_dna5}, {"TGNTCC"_dna5, "NNGC"_dna5}, {"GG"_dna5, "AA"_dna5}}; +#endif EXPECT_EQ(sequence_pairs, resulting_pairs); } diff --git a/test/unit/utility/container/aligned_allocator_test.cpp b/test/unit/utility/container/aligned_allocator_test.cpp index e8d3326c17..a57b75ea52 100644 --- a/test/unit/utility/container/aligned_allocator_test.cpp +++ b/test/unit/utility/container/aligned_allocator_test.cpp @@ -227,6 +227,9 @@ TEST(aligned_allocator, in_list) TEST(aligned_allocator, in_map) { +#ifdef _LIBCPP_VERSION + GTEST_SKIP() << "std::map not aligned in libc++"; +#else constexpr size_t alignment = 16; using key_type = char; using value_type = int; @@ -251,4 +254,5 @@ TEST(aligned_allocator, in_map) EXPECT_EQ(memory_alignment(&*(++it), alignment), 0u); EXPECT_EQ(memory_alignment(&*(++it), alignment), 0u); EXPECT_EQ(++it, container.end()); +#endif } diff --git a/test/unit/utility/detail/type_name_as_string_test.cpp b/test/unit/utility/detail/type_name_as_string_test.cpp index f0b0110897..6014247b4c 100644 --- a/test/unit/utility/detail/type_name_as_string_test.cpp +++ b/test/unit/utility/detail/type_name_as_string_test.cpp @@ -43,7 +43,11 @@ class type_inspection : public ::testing::Test "short*", "double const* const", "foo::bar const &", +#ifdef _LIBCPP_VERSION + "foo::bar>"}; +#else "foo::bar >"}; +#endif public: // Returns the name of the type according to the list of names defined above.