Skip to content

Commit

Permalink
[feature] views::char_strictly_to
Browse files Browse the repository at this point in the history
  • Loading branch information
h-2 committed Nov 30, 2021
1 parent b30f4c7 commit 35000bb
Show file tree
Hide file tree
Showing 5 changed files with 180 additions and 0 deletions.
80 changes: 80 additions & 0 deletions include/seqan3/alphabet/views/char_strictly_to.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
// -----------------------------------------------------------------------------------------------------
// Copyright (c) 2006-2021, Knut Reinert & Freie Universität Berlin
// Copyright (c) 2016-2021, Knut Reinert & MPI für molekulare Genetik
// This file may be used, modified and/or redistributed under the terms of the 3-clause BSD-License
// shipped with this file and also available at: https://github.com/seqan/seqan3/blob/master/LICENSE.md
// -----------------------------------------------------------------------------------------------------

/*!\file
* \brief Provides seqan3::views::char_strictly_to.
* \author Hannes Hauswedell <hannes.hauswedell AT fu-berlin.de>
*/

#pragma once

#include <seqan3/std/ranges>

#include <seqan3/alphabet/concept.hpp>
#include <seqan3/utility/type_traits/basic.hpp>
#include <seqan3/utility/views/deep.hpp>

namespace seqan3::views
{
/*!\brief A view over an alphabet, given a range of characters.
* \tparam urng_t The type of the range being processed. See below for requirements. [template parameter is
* omitted in pipe notation]
* \tparam alphabet_t The alphabet to convert to; must satisfy seqan3::alphabet.
* \param[in] urange The range being processed. [parameter is omitted in pipe notation]
* \returns A range of converted elements. See below for the properties of the returned range.
* \throws seqan3::invalid_char_assignment if an invalid character is encountered.
* \ingroup alphabet_views
*
* \details
*
* \header_file{seqan3/alphabet/views/char_strictly_to.hpp}
*
* This view differs from seqan3::views::chars_to in that it throws an exception if an invalid character conversion
* happens. See seqan3::char_strictly_to for more details.
*
* ### View properties
*
* This view is a **deep view**. Given a range-of-range as input (as opposed to just a range), it will apply
* the transformation on the innermost range (instead of the outermost range).
*
* | Concepts and traits | `urng_t` (underlying range type) | `rrng_t` (returned range type) |
* |----------------------------------|:-------------------------------------:|:------------------------------:|
* | std::ranges::input_range | *required* | *preserved* |
* | std::ranges::forward_range | | *preserved* |
* | std::ranges::bidirectional_range | | *preserved* |
* | std::ranges::random_access_range | | *preserved* |
* | std::ranges::contiguous_range | | *lost* |
* | | | |
* | std::ranges::viewable_range | *required* | *guaranteed* |
* | std::ranges::view | | *guaranteed* |
* | std::ranges::sized_range | | *preserved* |
* | std::ranges::common_range | | *preserved* |
* | std::ranges::output_range | | *lost* |
* | std::semiregular | | *preserved* |
* | seqan3::const_iterable_range | | *preserved* |
* | | | |
* | std::ranges::range_reference_t | seqan3::alphabet_char_t<alphabet_t> | `alphabet_t` |
*
* See the \link views views submodule documentation \endlink for detailed descriptions of the view properties.
*
* ### Example
*
* \include test/snippet/alphabet/views/char_strictly_to.cpp
* \hideinitializer
*
* \experimentalapi{Experimental since version 3.2.}
*/
template <alphabet alphabet_type>
inline auto const char_strictly_to = deep{std::views::transform([] (auto const in)
{
static_assert(std::common_reference_with<decltype(in), alphabet_char_t<alphabet_type>>,
"The innermost value type must have a common reference to underlying char type of alphabet_type.");
// call element-wise assign_char from the alphabet
return assign_char_strictly_to(in, alphabet_type{});
})};

} // namespace seqan3::views
16 changes: 16 additions & 0 deletions test/snippet/alphabet/views/char_strictly_to.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#include <seqan3/alphabet/nucleotide/dna4.hpp>
#include <seqan3/alphabet/views/char_strictly_to.hpp>
#include <seqan3/core/debug_stream.hpp>

int main()
{
std::string_view str{"ACTTTGATAN"};
try
{
seqan3::debug_stream << (str | seqan3::views::char_strictly_to<seqan3::dna4>); // ACTTTGATA
}
catch (seqan3::invalid_char_assignment const &)
{
seqan3::debug_stream << "\n[ERROR] Invalid char!\n"; // Will throw on parsing 'N'
}
}
2 changes: 2 additions & 0 deletions test/snippet/alphabet/views/char_strictly_to.err
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
ACTTTGATA
[ERROR] Invalid char!
1 change: 1 addition & 0 deletions test/unit/alphabet/views/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
add_subdirectories()

seqan3_test(char_to_test.cpp)
seqan3_test(char_strictly_to_test.cpp)
seqan3_test(complement_test.cpp)
seqan3_test(rank_to_test.cpp)
seqan3_test(to_char_test.cpp)
Expand Down
81 changes: 81 additions & 0 deletions test/unit/alphabet/views/char_strictly_to_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
// -----------------------------------------------------------------------------------------------------
// Copyright (c) 2006-2021, Knut Reinert & Freie Universität Berlin
// Copyright (c) 2016-2021, Knut Reinert & MPI für molekulare Genetik
// This file may be used, modified and/or redistributed under the terms of the 3-clause BSD-License
// shipped with this file and also available at: https://github.com/seqan/seqan3/blob/master/LICENSE.md
// -----------------------------------------------------------------------------------------------------

#include <gtest/gtest.h>

#include <seqan3/std/algorithm>
#include <iostream>
#include <seqan3/std/ranges>

#include <seqan3/alphabet/detail/debug_stream_alphabet.hpp>
#include <seqan3/alphabet/nucleotide/dna5.hpp>
#include <seqan3/alphabet/views/char_strictly_to.hpp>
#include <seqan3/test/expect_range_eq.hpp>
#include <seqan3/utility/range/concept.hpp>

using seqan3::operator""_dna5;

TEST(view_char_strictly_to, basic)
{
std::string vec{"ACTTTGATA"};
seqan3::dna5_vector cmp{"ACTTTGATA"_dna5};

// pipe notation
EXPECT_RANGE_EQ(cmp, vec | seqan3::views::char_strictly_to<seqan3::dna5>);

// function notation
EXPECT_RANGE_EQ(cmp, seqan3::views::char_strictly_to<seqan3::dna5>(vec));

// combinability
seqan3::dna5_vector cmp2{"ATAGTTTCA"_dna5};
EXPECT_RANGE_EQ(cmp2, vec | seqan3::views::char_strictly_to<seqan3::dna5> | std::views::reverse);
}

TEST(view_char_strictly_to, deep_view)
{
std::vector<std::string> foo{"ACGTA", "TGCAT"};

auto v = foo | seqan3::views::char_strictly_to<seqan3::dna5>;

ASSERT_EQ(std::ranges::size(v), 2u);
EXPECT_RANGE_EQ(v[0], "ACGTA"_dna5);
EXPECT_RANGE_EQ(v[1], "TGCAT"_dna5);
}

TEST(view_char_strictly_to, concepts)
{
std::string vec{"ACTTTGATA"};
EXPECT_TRUE(std::ranges::input_range<decltype(vec)>);
EXPECT_TRUE(std::ranges::forward_range<decltype(vec)>);
EXPECT_TRUE(std::ranges::bidirectional_range<decltype(vec)>);
EXPECT_TRUE(std::ranges::random_access_range<decltype(vec)>);
EXPECT_FALSE(std::ranges::view<decltype(vec)>);
EXPECT_TRUE(std::ranges::sized_range<decltype(vec)>);
EXPECT_TRUE(std::ranges::common_range<decltype(vec)>);
EXPECT_TRUE(seqan3::const_iterable_range<decltype(vec)>);
EXPECT_TRUE((std::ranges::output_range<decltype(vec), char>));

auto v1 = vec | seqan3::views::char_strictly_to<seqan3::dna5>;
EXPECT_TRUE(std::ranges::input_range<decltype(v1)>);
EXPECT_TRUE(std::ranges::forward_range<decltype(v1)>);
EXPECT_TRUE(std::ranges::bidirectional_range<decltype(v1)>);
EXPECT_TRUE(std::ranges::random_access_range<decltype(v1)>);
EXPECT_TRUE(std::ranges::view<decltype(v1)>);
EXPECT_TRUE(std::ranges::sized_range<decltype(v1)>);
EXPECT_TRUE(std::ranges::common_range<decltype(v1)>);
EXPECT_TRUE(seqan3::const_iterable_range<decltype(v1)>);
EXPECT_FALSE((std::ranges::output_range<decltype(v1), seqan3::dna5>));
EXPECT_FALSE((std::ranges::output_range<decltype(v1), char>));
}

TEST(view_char_strictly_to, exception)
{
std::string foo = "ACGPTA";

auto v = foo | seqan3::views::char_strictly_to<seqan3::dna5>;
EXPECT_THROW((std::ranges::equal(v, "ACGNTA"_dna5)), seqan3::invalid_char_assignment);
}

0 comments on commit 35000bb

Please sign in to comment.