diff --git a/CHANGELOG.md b/CHANGELOG.md index fdd0581a0df..cde55478965 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -64,6 +64,8 @@ Note that 3.1.0 will be the first API stable release and interfaces in this rele * The `seqan3::begin()`, `seqan3::end()`, `seqan3::cbegin()`, `seqan3::cend()`, `seqan3::size()`, `seqan3::empty()` functions have been deprecated: Use `std::ranges::{begin|end|cbegin|cend|size|empty}()` instead ([\#1663](https://github.com/seqan/seqan3/pull/1663)). + * Added size() function to `seqan3::views::kmer_hash` + ([\#1722](https://github.com/seqan/seqan3/pull/1722)). #### Search @@ -175,8 +177,6 @@ Note that 3.1.0 will be the first API stable release and interfaces in this rele ([\#1410](https://github.com/seqan/seqan3/pull/1410)). * Renamed `seqan3::views::all` to `seqan3::views::type_reduce` ([\#1410](https://github.com/seqan/seqan3/pull/1410)). -* Added size() function to `seqan3::views::kmer_hash` - ([\#1722](https://github.com/seqan/seqan3/pull/1722)). #### Search diff --git a/include/seqan3/range/views/kmer_hash.hpp b/include/seqan3/range/views/kmer_hash.hpp index 2d7f189e0e7..36e5656d897 100644 --- a/include/seqan3/range/views/kmer_hash.hpp +++ b/include/seqan3/range/views/kmer_hash.hpp @@ -179,12 +179,12 @@ class kmer_hash_view : public std::ranges::view_interface * \returns Size of range. */ auto size() const + //!\cond requires std::ranges::sized_range + //!\endcond { - auto range_size{std::ranges::size(urange)}; - if (range_size >= shape_.size()) - return range_size - shape_.size() + 1; - return decltype(range_size){0}; + using size_type = decltype(std::ranges::size(urange)); + return std::max(std::ranges::size(urange) + 1, shape_.size()) - shape_.size(); } }; diff --git a/test/unit/range/views/view_kmer_hash_test.cpp b/test/unit/range/views/view_kmer_hash_test.cpp index bd3545aba56..7a114151cbd 100644 --- a/test/unit/range/views/view_kmer_hash_test.cpp +++ b/test/unit/range/views/view_kmer_hash_test.cpp @@ -30,7 +30,10 @@ static constexpr auto prefix_until_first_thymine = seqan3::views::take_until([] { return x == 'T'_dna4; }); template -class kmer_hash_test: public ::testing::Test {}; +class kmer_hash_ungapped_test: public ::testing::Test {}; + +template +class kmer_hash_gapped_test: public ::testing::Test {}; using underlying_range_types = ::testing::Types, std::vector const, @@ -41,44 +44,56 @@ using underlying_range_types = ::testing::Types, std::forward_list, std::forward_list const>; -TYPED_TEST_SUITE(kmer_hash_test, underlying_range_types, ); +TYPED_TEST_SUITE(kmer_hash_ungapped_test, underlying_range_types, ); +TYPED_TEST_SUITE(kmer_hash_gapped_test, underlying_range_types, ); -TYPED_TEST(kmer_hash_test, ungapped_combined_with_container) +TYPED_TEST(kmer_hash_ungapped_test, combined_with_container) { - TypeParam text1{'A'_dna4, 'C'_dna4, 'G'_dna4, 'T'_dna4, 'A'_dna4, 'G'_dna4, 'C'_dna4}; // ACGTAGC - result_t ungapped1{6, 27, 44, 50, 9}; - TypeParam text2{'A'_dna4, 'A'_dna4, 'A'_dna4, 'A'_dna4, 'A'_dna4}; // AAAAA - result_t ungapped2{0,0,0}; - TypeParam text3{'A'_dna4, 'C'_dna4}; // AC - result_t ungapped3{}; - TypeParam text4{'A'_dna4, 'C'_dna4, 'G'_dna4}; // AC - result_t ungapped4{6}; - - EXPECT_EQ(ungapped1, text1 | ungapped_view | seqan3::views::to); - EXPECT_EQ(ungapped2, text2 | ungapped_view | seqan3::views::to); - EXPECT_EQ(ungapped3, text3 | ungapped_view | seqan3::views::to); - EXPECT_EQ(ungapped4, text4 | ungapped_view | seqan3::views::to); - EXPECT_EQ(ungapped4, text1 | prefix_until_first_thymine | ungapped_view | seqan3::views::to); + { + TypeParam text1{'A'_dna4, 'C'_dna4, 'G'_dna4, 'T'_dna4, 'A'_dna4, 'G'_dna4, 'C'_dna4}; // ACGTAGC + result_t ungapped1{6, 27, 44, 50, 9}; + EXPECT_EQ(ungapped1, text1 | ungapped_view | seqan3::views::to); + EXPECT_EQ(result_t{6}, text1 | prefix_until_first_thymine | ungapped_view | seqan3::views::to); + } + { + TypeParam text2{'A'_dna4, 'A'_dna4, 'A'_dna4, 'A'_dna4, 'A'_dna4}; // AAAAA + result_t ungapped2{0, 0, 0}; + EXPECT_EQ(ungapped2, text2 | ungapped_view | seqan3::views::to); + } + { + TypeParam text3{'A'_dna4, 'C'_dna4}; // AC + EXPECT_EQ(result_t{}, text3 | ungapped_view | seqan3::views::to); + } + { + TypeParam text4{'A'_dna4, 'C'_dna4, 'G'_dna4}; // AC + EXPECT_EQ(result_t{6}, text4 | ungapped_view | seqan3::views::to); + } } -TYPED_TEST(kmer_hash_test, gapped_combined_with_container) +TYPED_TEST(kmer_hash_gapped_test, combined_with_container) { - TypeParam text1{'A'_dna4, 'C'_dna4, 'G'_dna4, 'T'_dna4, 'A'_dna4, 'G'_dna4, 'C'_dna4}; // ACGTAGC - result_t gapped1{2, 7, 8, 14, 1}; - TypeParam text2{'A'_dna4, 'A'_dna4, 'A'_dna4, 'A'_dna4, 'A'_dna4}; // AAAAA - result_t gapped2{0,0,0}; - TypeParam text3{'A'_dna4, 'C'_dna4}; // AC - result_t gapped3{}; - TypeParam text4{'A'_dna4, 'C'_dna4, 'G'_dna4}; // AC - result_t gapped4{2}; - EXPECT_EQ(gapped1, text1 | gapped_view | seqan3::views::to); - EXPECT_EQ(gapped2, text2 | gapped_view | seqan3::views::to); - EXPECT_EQ(gapped3, text3 | gapped_view | seqan3::views::to); - EXPECT_EQ(gapped4, text4 | gapped_view | seqan3::views::to); - EXPECT_EQ(gapped4, text1 | prefix_until_first_thymine| gapped_view | seqan3::views::to); + { + TypeParam text1{'A'_dna4, 'C'_dna4, 'G'_dna4, 'T'_dna4, 'A'_dna4, 'G'_dna4, 'C'_dna4}; // ACGTAGC + result_t gapped1{2, 7, 8, 14, 1}; + EXPECT_EQ(gapped1, text1 | gapped_view | seqan3::views::to); + EXPECT_EQ(result_t{2}, text1 | prefix_until_first_thymine| gapped_view | seqan3::views::to); + } + { + TypeParam text2{'A'_dna4, 'A'_dna4, 'A'_dna4, 'A'_dna4, 'A'_dna4}; // AAAAA + result_t gapped2{0, 0, 0}; + EXPECT_EQ(gapped2, text2 | gapped_view | seqan3::views::to); + } + { + TypeParam text3{'A'_dna4, 'C'_dna4}; // AC + EXPECT_EQ(result_t{}, text3 | gapped_view | seqan3::views::to); + } + { + TypeParam text4{'A'_dna4, 'C'_dna4, 'G'_dna4}; // AC + EXPECT_EQ(result_t{2}, text4 | gapped_view | seqan3::views::to); + } } -TYPED_TEST(kmer_hash_test, ungapped_concepts) +TYPED_TEST(kmer_hash_ungapped_test, concepts) { TypeParam text{'A'_dna4, 'C'_dna4, 'G'_dna4, 'T'_dna4}; // ACGT auto v1 = text | ungapped_view; @@ -86,6 +101,7 @@ TYPED_TEST(kmer_hash_test, ungapped_concepts) EXPECT_TRUE(std::ranges::forward_range); EXPECT_EQ(std::ranges::bidirectional_range, std::ranges::bidirectional_range); EXPECT_EQ(std::ranges::random_access_range, std::ranges::random_access_range); + EXPECT_FALSE(std::ranges::contiguous_range); EXPECT_TRUE(std::ranges::view); EXPECT_EQ(std::ranges::sized_range, std::ranges::sized_range); EXPECT_FALSE(std::ranges::common_range); @@ -93,7 +109,7 @@ TYPED_TEST(kmer_hash_test, ungapped_concepts) EXPECT_FALSE((std::ranges::output_range)); } -TYPED_TEST(kmer_hash_test, gapped_concepts) +TYPED_TEST(kmer_hash_gapped_test, concepts) { TypeParam text{'A'_dna4, 'C'_dna4, 'G'_dna4, 'T'_dna4}; // ACGT auto v1 = text | gapped_view; @@ -101,6 +117,7 @@ TYPED_TEST(kmer_hash_test, gapped_concepts) EXPECT_TRUE(std::ranges::forward_range); EXPECT_EQ(std::ranges::bidirectional_range, std::ranges::bidirectional_range); EXPECT_EQ(std::ranges::random_access_range, std::ranges::random_access_range); + EXPECT_FALSE(std::ranges::contiguous_range); EXPECT_TRUE(std::ranges::view); EXPECT_EQ(std::ranges::sized_range, std::ranges::sized_range); EXPECT_FALSE(std::ranges::common_range); @@ -108,7 +125,7 @@ TYPED_TEST(kmer_hash_test, gapped_concepts) EXPECT_FALSE((std::ranges::output_range)); } -TYPED_TEST(kmer_hash_test, invalid_sizes) +TYPED_TEST(kmer_hash_ungapped_test, invalid_sizes) { TypeParam text1{'A'_dna4, 'A'_dna4, 'A'_dna4, 'A'_dna4, 'A'_dna4}; EXPECT_NO_THROW(text1 | seqan3::views::kmer_hash(seqan3::ungapped{32})); @@ -129,7 +146,7 @@ TYPED_TEST(kmer_hash_test, invalid_sizes) } // https://github.com/seqan/seqan3/issues/1614 -TEST(kmer_hash_test, issue1614) +TEST(kmer_hash_ungapped_test, issue1614) { std::vector sequence{"TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT"_dna5}; EXPECT_EQ(sequence | seqan3::views::kmer_hash(seqan3::ungapped{25}) | seqan3::views::to>, @@ -137,7 +154,7 @@ TEST(kmer_hash_test, issue1614) } // https://github.com/seqan/seqan3/issues/1643 -TEST(kmer_hash_test, issue1643) +TEST(kmer_hash_ungapped_test, issue1643) { std::vector text_23_elements{"ACGATCGATCGTAGCTACTGAGC"_dna4}; @@ -153,14 +170,19 @@ TEST(kmer_hash_test, issue1643) } // https://github.com/seqan/seqan3/issues/1719 -TEST(kmer_hash_test, issue1719) +TYPED_TEST(kmer_hash_ungapped_test, issue1719) { - uint64_t const expected = 0; - std::vector sequence{""_dna5}; - auto v = sequence | seqan3::views::kmer_hash(seqan3::ungapped{25}); - EXPECT_EQ(expected, v.size()); - - std::vector sequence2{"ACGATCGATCGTAGCTACTGAGC"_dna5}; - auto v2 = sequence2 | seqan3::views::kmer_hash(seqan3::ungapped{25}); - EXPECT_EQ(expected, v2.size()); + if constexpr (std::ranges::sized_range) + { + TypeParam sequence{}; + auto v = sequence | seqan3::views::kmer_hash(seqan3::ungapped{8}); + EXPECT_EQ(0u, v.size()); + + TypeParam sequence2{'A'_dna4, 'C'_dna4, 'G'_dna4, 'T'_dna4, 'A'_dna4, 'G'_dna4, 'C'_dna4}; + auto v2 = sequence2 | seqan3::views::kmer_hash(seqan3::ungapped{8}); + EXPECT_EQ(0u, v2.size()); + + auto v3 = sequence2 | seqan3::views::kmer_hash(seqan3::ungapped{4}); + EXPECT_EQ(4u, v3.size()); + } }