diff --git a/.github/workflows/ci_linux.yml b/.github/workflows/ci_linux.yml index f276256a..6ce1d395 100644 --- a/.github/workflows/ci_linux.yml +++ b/.github/workflows/ci_linux.yml @@ -33,7 +33,7 @@ jobs: strategy: fail-fast: false matrix: - compiler: ["clang-18", "clang-17", "gcc-14", "gcc-13", "gcc-12", "gcc-11", "intel"] + compiler: ["clang-18", "clang-17", "gcc-14", "gcc-13", "gcc-12", "intel"] include: - cxx_flags: "-Wno-interference-size" - compiler: "clang-18" diff --git a/.github/workflows/ci_macos.yml b/.github/workflows/ci_macos.yml index e0e9c89f..09f9d2f3 100644 --- a/.github/workflows/ci_macos.yml +++ b/.github/workflows/ci_macos.yml @@ -33,7 +33,7 @@ jobs: strategy: fail-fast: false matrix: - compiler: ["clang-18", "clang-17", "gcc-14", "gcc-13", "gcc-12", "gcc-11"] + compiler: ["clang-18", "clang-17", "gcc-14", "gcc-13", "gcc-12"] include: - cxx_flags: "-Wno-interference-size" - compiler: "clang-18" diff --git a/.github/workflows/ci_misc.yml b/.github/workflows/ci_misc.yml index 6661f0e1..5e8ea126 100644 --- a/.github/workflows/ci_misc.yml +++ b/.github/workflows/ci_misc.yml @@ -33,7 +33,7 @@ jobs: strategy: fail-fast: false matrix: - compiler: ["clang-18", "gcc-14", "gcc-11", "intel"] + compiler: ["clang-18", "gcc-14", "gcc-12", "intel"] build: ["snippet", "performance", "header"] include: - cxx_flags: "-Wno-interference-size" diff --git a/.github/workflows/ci_utility.yml b/.github/workflows/ci_utility.yml index eeaf1be8..76fef492 100644 --- a/.github/workflows/ci_utility.yml +++ b/.github/workflows/ci_utility.yml @@ -33,7 +33,7 @@ jobs: strategy: fail-fast: false matrix: - compiler: ["clang-18", "clang-17", "gcc-14", "gcc-13", "gcc-12", "gcc-11", "intel"] + compiler: ["clang-18", "clang-17", "gcc-14", "gcc-13", "gcc-12", "intel"] include: - cxx_flags: "-Wno-interference-size" - compiler: "clang-18" diff --git a/doc/setup/index.md b/doc/setup/index.md index 7df1a1ca..be3469ef 100644 --- a/doc/setup/index.md +++ b/doc/setup/index.md @@ -20,7 +20,8 @@ conda install -c bioconda -c conda-forge raptor ### Prerequisites * CMake >= 3.21 -* GCC 11, 12 or 13 (most recent minor version) +* GCC 12, 13 or 14 (most recent minor version) +* Clang 17 or 18 (most recent minor version) * git Refer to the [Seqan3 Setup Tutorial](https://docs.seqan.de/seqan/3-master-user/setup.html) for more in depth diff --git a/include/raptor/build/emplace_iterator.hpp b/include/raptor/build/emplace_iterator.hpp index 6aa447de..3eb09411 100644 --- a/include/raptor/build/emplace_iterator.hpp +++ b/include/raptor/build/emplace_iterator.hpp @@ -32,13 +32,13 @@ class emplace_iterator explicit constexpr emplace_iterator(seqan::hibf::interleaved_bloom_filter & ibf, seqan::hibf::bin_index const idx) : ibf{std::addressof(ibf)}, - index{std::move(idx)} + index{idx} {} /* constexpr */ emplace_iterator & operator=(uint64_t const value) noexcept { assert(ibf != nullptr); - ibf->emplace(std::move(value), index); + ibf->emplace(value, index); return *this; } @@ -65,7 +65,7 @@ class emplace_iterator [[nodiscard]] inline constexpr emplace_iterator emplacer(seqan::hibf::interleaved_bloom_filter & ibf, seqan::hibf::bin_index const idx) { - return emplace_iterator{ibf, std::move(idx)}; + return emplace_iterator{ibf, idx}; } } // namespace raptor diff --git a/include/raptor/threshold/forward_strand_minimiser.hpp b/include/raptor/threshold/forward_strand_minimiser.hpp index ea6af8e3..67f2dbaf 100644 --- a/include/raptor/threshold/forward_strand_minimiser.hpp +++ b/include/raptor/threshold/forward_strand_minimiser.hpp @@ -94,38 +94,45 @@ struct forward_strand_minimiser auto kmer_view = text | seqan3::views::kmer_hash(shape) | std::views::transform(apply_xor); forward_hashes.assign(kmer_view.begin(), kmer_view.end()); + struct kmer + { + uint64_t hash{}; + uint64_t position{}; + + constexpr auto operator<=>(kmer const & other) const = default; + }; + // Stores hash and begin for all k-mers in the window - std::deque> window_hashes; + std::deque window_hashes; // Initialisation. We need to compute all hashes for the first window. for (uint64_t i = 0; i < kmers_per_window; ++i) - window_hashes.emplace_back(forward_hashes[i], i); + window_hashes.emplace_back(kmer{.hash = forward_hashes[i], .position = i}); // The minimum hash is the minimiser. Store the begin position. - auto min = std::min_element(std::begin(window_hashes), std::end(window_hashes)); - minimiser_begin.push_back(min->second); + auto min = std::ranges::min(window_hashes); + minimiser_begin.push_back(min.position); // For the following windows, we remove the first window k-mer (is now not in window) and add the new k-mer // that results from the window shifting. for (uint64_t i = kmers_per_window; i < max_number_of_minimiser; ++i) { - // Already store the new hash without removing the first one. uint64_t const new_hash{forward_hashes[i + kmers_per_window - 1]}; // Already did kmers_per_window - 1 many - window_hashes.emplace_back(new_hash, i); - if (new_hash < min->second) // New hash is the minimum. - { - min = std::prev(std::end(window_hashes)); - minimiser_begin.push_back(min->second); - } - else if (min == std::begin(window_hashes)) // Minimum is the yet-to-be-removed begin of the window. + // There are two conditions when we need to recompute the minimum: + bool const minimiser_leaves_window = window_hashes.front() == min; + bool const new_hash_is_min = new_hash < min.hash; + + // Rolling hash / sliding window + window_hashes.pop_front(); + window_hashes.emplace_back(kmer{.hash = new_hash, .position = i}); + + // Update the minimum + if (new_hash_is_min || minimiser_leaves_window) { - // The first hash will be removed, the last one is caught by the previous if. - min = std::min_element(++std::begin(window_hashes), std::prev(std::end(window_hashes))); - minimiser_begin.push_back(min->second); + min = new_hash_is_min ? window_hashes.back() : std::ranges::min(window_hashes); + minimiser_begin.push_back(min.position); } - - window_hashes.pop_front(); // Remove the first k-mer. } return; } diff --git a/test/include/raptor/test/cli_test.hpp b/test/include/raptor/test/cli_test.hpp index 703f49af..2cf3797b 100644 --- a/test/include/raptor/test/cli_test.hpp +++ b/test/include/raptor/test/cli_test.hpp @@ -384,18 +384,7 @@ struct raptor_base : public cli_test for (auto && hit : std::views::split(line_view.substr(query_prefix.size() + 2u), ',')) { -// GCC 11 does not implement P2210R2, hence GCC 11's split_view is actually a lazy_split_view. -#if defined(__GNUC__) && !defined(__llvm__) && !defined(__INTEL_COMPILER) && (__GNUC__ > 10) && (__GNUC__ < 12) - std::stringstream buf; - for (auto const & inner_view : hit) - { - buf << inner_view; - } - auto view = buf.view(); - std::from_chars(view.data(), view.data() + view.size(), tmp); -#else std::from_chars(hit.data(), hit.data() + hit.size(), tmp); -#endif actual_hits.push_back(tmp); } std::ranges::sort(actual_hits); diff --git a/test/unit/api/threshold.cpp b/test/unit/api/threshold.cpp index 7f4aef0f..67a0ba36 100644 --- a/test/unit/api/threshold.cpp +++ b/test/unit/api/threshold.cpp @@ -116,11 +116,11 @@ TEST(minimiser, logspace_substract) raptor::threshold::threshold const threshold{parameters}; // results for pseudorandom generators are implementation-defined #ifdef _LIBCPP_VERSION - std::vector const expected{1u, 1u, 1u, 1u, 2u, 3u, 4u, 5u, 6u, 7u, 8u, 8u, 9u, - 10u, 11u, 12u, 13u, 14u, 15u, 16u, 17u, 18u, 19u, 21u, 22u}; + std::vector const expected{1u, 1u, 1u, 1u, 2u, 4u, 5u, 6u, 7u, 8u, 9u, 9u, 10u, + 11u, 12u, 13u, 14u, 15u, 16u, 17u, 18u, 19u, 20u, 22u, 23u}; #else - std::vector const expected{1u, 1u, 1u, 1u, 2u, 3u, 4u, 5u, 6u, 6u, 7u, 8u, 9u, - 10u, 11u, 12u, 13u, 13u, 14u, 15u, 16u, 17u, 18u, 20u, 21u}; + std::vector const expected{1u, 1u, 1u, 1u, 2u, 4u, 5u, 6u, 7u, 7u, 8u, 9u, 10u, + 11u, 12u, 13u, 14u, 15u, 16u, 17u, 18u, 19u, 20u, 22u, 23u}; #endif ASSERT_EQ(expected.size(), 37u - 12u); for (size_t i = 12u; i < 37u; ++i)