<|start_filename|>test/snippet/release/3.0.0_read-fasta-and-print-entities.cpp<|end_filename|>
//![main]
#include <seqan3/core/debug_stream.hpp>
#include <seqan3/io/sequence_file/input.hpp>

int main()
{
    seqan3::sequence_file_input fin{"my.fasta"};

    // iterate over every record in the file and split it into fields:
    for (auto & [ seq, id, qual ] : fin)
    {
        // print the fields:
        seqan3::debug_stream << "ID:  " << id << '\n';
        seqan3::debug_stream << "SEQ: " << seq << '\n';
        seqan3::debug_stream << "QUAL:" << qual << '\n'; // qual is empty for FastA files
    }
}
//![main]

#include <seqan3/test/snippet/create_temporary_snippet_file.hpp>
// std::filesystem::current_path() / "my.fasta" will be deleted after the execution
seqan3::test::create_temporary_snippet_file my_fastq{"my.fasta", "\n"};


<|start_filename|>include/seqan3/search/search_result.hpp<|end_filename|>
// -----------------------------------------------------------------------------------------------------
// Copyright (c) 2006-2021, <NAME> & Freie Universität Berlin
// Copyright (c) 2016-2021, <NAME> & 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::search_result.
 * \author <NAME> <enrico.seiler AT fu-berlin.de>
 * \author <NAME> <svenja.mehringer AT fu-berlin.de>
 */

#pragma once

#include <seqan3/std/concepts>
#include <exception>

#include <seqan3/core/configuration/configuration.hpp>
#include <seqan3/core/debug_stream/debug_stream_type.hpp>
#include <seqan3/core/detail/empty_type.hpp>
#include <seqan3/core/detail/template_inspection.hpp>
#include <seqan3/search/fm_index/concept.hpp>
#include <seqan3/search/fm_index/bi_fm_index_cursor.hpp>
#include <seqan3/search/fm_index/fm_index_cursor.hpp>

namespace seqan3::detail
{
// forward declaration
template <typename search_configuration_t>
#if !SEQAN3_WORKAROUND_GCC_93467
    requires is_type_specialisation_of_v<search_configuration_t, configuration>
#endif // !SEQAN3_WORKAROUND_GCC_93467
struct policy_search_result_builder;
} // namespace seqan3::detail

namespace seqan3
{

/*!\brief The result class generated by the seqan3::seach algorithm.
 * \ingroup search
 * \tparam query_id_type The type of the query_id; must model std::integral.
 * \tparam cursor_type The type of the cursor; must model seqan3::detail::template_specialisation_of a
 * seqan3::fm_index_cursor or a seqan3::bi_fm_index_cursor
 * \tparam reference_id_type The type of the reference_id; must model std::integral.
 * \tparam reference_begin_position_type The type of the reference_begin_position; must model std::integral.
 *
 * \if DEV
 * \note If the information is not available, the respective data type is seqan3::detail::empty_type.
 * \endif
 *
 * The seqan3::search algorithm returns a range of hits. A single hit is stored in a seqan3::search_result.
 * By default, the search result contains the query id, the reference id where the query matched and the begin
 * position in the reference where the query sequence starts to match the reference sequence.
 * Those information can be accessed via the respective member functions.
 *
 * The following member functions exist:
 *
 * * seqan3::search_result::query_id()
 * * seqan3::search_result::index_cursor()
 * * seqan3::search_result::reference_id()
 * * seqan3::search_result::reference_begin_position()
 *
 * Note that the index cursor is not included in a hit by default. If you are trying to use the respective member
 * function, a static_assert will prevent you from doing so. You can configure the result of the search with the
 * \ref search_configuration_subsection_output "output configuration".
 */
template <typename query_id_type,
          typename cursor_type,
          typename reference_id_type,
          typename reference_begin_position_type>
//!\cond
    requires (std::integral<query_id_type> || std::same_as<query_id_type, detail::empty_type>) &&
             (detail::template_specialisation_of<cursor_type, fm_index_cursor> ||
                     detail::template_specialisation_of<cursor_type, bi_fm_index_cursor> ||
                     std::same_as<cursor_type, detail::empty_type>) &&
             (std::integral<reference_id_type> || std::same_as<reference_id_type, detail::empty_type>) &&
             (std::integral<reference_begin_position_type> || std::same_as<reference_begin_position_type,
                                                                           detail::empty_type>)
//!\endcond
class search_result
{
private:
    //!\brief Stores the query_id of the search result.
    query_id_type query_id_{};
    //!\brief Stores the cursor of the search result.
    cursor_type cursor_{};
    //!\brief Stores the reference_id of the search result.
    reference_id_type reference_id_{};
    //!\brief Stores the reference_begin_position of the search result.
    reference_begin_position_type reference_begin_position_{};

    // Grant the policy access to private constructors.
    template <typename search_configuration_t>
    #if !SEQAN3_WORKAROUND_GCC_93467
    //!\cond
        requires detail::is_type_specialisation_of_v<search_configuration_t, configuration>
    //!\endcond
    #endif // !SEQAN3_WORKAROUND_GCC_93467
    friend struct detail::policy_search_result_builder;

public:
    /*!\name Constructors, destructor and assignment
     * \{
     */
    search_result() = default; //!< Defaulted.
    search_result(search_result const &) = default; //!< Defaulted.
    search_result(search_result &&) = default; //!< Defaulted.
    search_result & operator=(search_result const &) = default; //!< Defaulted.
    search_result & operator=(search_result &&) = default; //!< Defaulted.
    ~search_result() = default; //!< Defaulted.

    //!\}

    /*!\name Accessors
     * \brief Functions to access elements of the search result.
     * \{
     */
    //!\brief Returns the id of the query which produced this search result.
    constexpr auto query_id() const noexcept
    {
        static_assert(!std::same_as<query_id_type, detail::empty_type>,
                      "You tried to access the query_id but it was not selected in the output "
                      "configuration of the search.");

        return query_id_;
    }

    /*!\brief Returns the index cursor pointing to the suffix array range where the query was found.
     * \sa seqan3::fm_index_cursor
     * \sa seqan3::bi_fm_index_cursor
     */
    constexpr auto index_cursor() const noexcept(!(std::same_as<cursor_type, detail::empty_type>))
    {
        static_assert(!std::same_as<cursor_type, detail::empty_type>,
                      "You tried to access the index cursor but it was not selected in the output "
                      "configuration of the search.");

        return cursor_;
    }

    /*!\brief Returns the reference id where the query was found.
     *
     * \details
     * The reference id is an arithmetic value that corresponds to the index of the reference text in the index.
     * The order is determined on construction of the index.
     */
    constexpr auto reference_id() const noexcept(!(std::same_as<reference_id_type, detail::empty_type>))
    {
        static_assert(!std::same_as<reference_id_type, detail::empty_type>,
                      "You tried to access the reference id but it was not selected in the output "
                      "configuration of the search.");

        return reference_id_;
    }

    //!\brief Returns the reference begin positions where the query was found in the reference text (at `reference id`).
    constexpr auto reference_begin_position() const
        noexcept(!(std::same_as<reference_begin_position_type, detail::empty_type>))
    {
        static_assert(!std::same_as<reference_begin_position_type, detail::empty_type>,
                      "You tried to access the reference begin position but it was not selected in the "
                      "output configuration of the search.");

        return reference_begin_position_;
    }
    //!\}

    /*!\name Comparison
     * \{
     */
    //!\brief Returns whether `lhs` and `rhs` are the same.
    friend bool operator==(search_result const & lhs, search_result const & rhs) noexcept
    {
        bool equality = lhs.query_id_ == rhs.query_id_;
        if constexpr (!std::is_same_v<cursor_type, detail::empty_type>)
            equality &= lhs.cursor_ == rhs.cursor_;
        if constexpr (!std::is_same_v<reference_id_type, detail::empty_type>)
            equality &= lhs.reference_id_ == rhs.reference_id_;
        if constexpr (!std::is_same_v<reference_begin_position_type, detail::empty_type>)
            equality &= lhs.reference_begin_position_ == rhs.reference_begin_position_;

        return equality;
    }

    //!\brief Returns whether `lhs` and `rhs` are not the same.
    friend bool operator!=(search_result const & lhs, search_result const & rhs) noexcept
    {
        return !(lhs == rhs);
    }
    //!\}
};

/*!\brief Print the seqan3::search_result to seqan3::debug_stream.
 * \tparam char_t The underlying character type of the seqan3::debug_stream_type.
 * \tparam search_result_t A specialization of seqan3::search_result.
 * \param stream The stream.
 * \param result The search result to print.
 * \relates seqan3::debug_stream_type
 */
template <typename char_t, typename search_result_t>
//!\cond
    requires detail::is_type_specialisation_of_v<std::remove_cvref_t<search_result_t>, search_result>
//!\endcond
inline debug_stream_type<char_t> & operator<<(debug_stream_type<char_t> & stream, search_result_t && result)
{
    using result_type_list = detail::transfer_template_args_onto_t<std::remove_cvref_t<search_result_t>, type_list>;

    stream << "<";
    if constexpr (!std::same_as<list_traits::at<0, result_type_list>, detail::empty_type>)
        stream << "query_id:" << result.query_id();
    if constexpr (!std::same_as<list_traits::at<1, result_type_list>, detail::empty_type>)
        stream << ", index cursor is present";
    if constexpr (!std::same_as<list_traits::at<2, result_type_list>, detail::empty_type>)
        stream << ", reference_id:" << result.reference_id();
    if constexpr (!std::same_as<list_traits::at<3, result_type_list>, detail::empty_type>)
        stream << ", reference_pos:" << result.reference_begin_position();
    stream << ">";

    return stream;
}

} // namespace seqan3


<|start_filename|>include/seqan3/core/range/detail/inherited_iterator_base.hpp<|end_filename|>
// -----------------------------------------------------------------------------------------------------
// Copyright (c) 2006-2021, <NAME> & Freie Universität Berlin
// Copyright (c) 2016-2021, <NAME> & 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 the seqan3::detail::inherited_iterator_base template.
 * \author <NAME> <hannes.hauswedell AT fu-berlin.de>
 */

#pragma once

#include <cassert>
#include <seqan3/std/iterator>
#include <type_traits>

#include <seqan3/core/detail/empty_type.hpp>
#include <seqan3/core/detail/iterator_traits.hpp>

namespace seqan3::detail
{

/*!\brief A CRTP base template for creating iterators that inherit from other iterators.
 * \tparam derived_t The CRTP specialisation.
 * \tparam base_t    The type to inherit from; must satisfy std::input_or_output_iterator.
 * \implements std::input_or_output_iterator
 * \ingroup core_range
 *
 * \details
 *
 * This template enables you to inherit from another iterator and just overload those functions
 * that you wish to change.
 *
 * Note that many of this class's members assume that the derived type is constructible from the base type.
 *
 * ### Example
 *
 * You may want to have an iterator that skips those elements in an int-vector that are not divisable by two:
 *
 * \snippet test/unit/core/range/detail/inherited_iterator_base_test.cpp inherited_iterator_base desired
 *
 * You could define it like this:
 *
 * \snippet test/unit/core/range/detail/inherited_iterator_base_test.cpp inherited_iterator_base def
 */
template <typename derived_t, std::input_or_output_iterator base_t>
class inherited_iterator_base : public std::conditional_t<std::is_pointer_v<base_t> || !std::semiregular<base_t>,
                                                          empty_type,
                                                          base_t>,
                                public maybe_inherited_iterator_category<base_t>
{
private:
    //!\brief Whether this iterator inherits or wraps.
    static constexpr bool wrap_base = std::is_pointer_v<base_t> || !std::semiregular<base_t>;
public:
    /*!\name Associated types
     * \brief All are derived from the base_t.
     * \{
     */

    //!\brief The difference type.
    using difference_type = std::iter_difference_t<base_t>;
    //!\brief The value type.
    using value_type = std::iter_value_t<base_t>;
    //!\brief The reference type.
    using reference = std::iter_reference_t<base_t>;
    //!\brief The pointer type.
    using pointer = detail::iter_pointer_t<base_t>;
#if SEQAN3_DOXYGEN_ONLY(1)0
    //!\brief The iterator category tag.
    using iterator_category = maybe_present;
#endif // SEQAN3_DOXYGEN_ONLY(1)0
    //!\brief The iterator concept tag.
    using iterator_concept = detail::iterator_concept_tag_t<base_t>;
    //!\}

    /*!\name Constructors, destructor and assignment
     * \brief The exception specification is explicitly "inherited" to also work for pointers as base.
     * \{
     */
    constexpr inherited_iterator_base()
        noexcept(std::is_nothrow_default_constructible_v<base_t>)                       = default; //!< Defaulted.
    constexpr inherited_iterator_base(inherited_iterator_base const & rhs)
        noexcept(std::is_nothrow_copy_constructible_v<base_t>)                          = default; //!< Defaulted.
    constexpr inherited_iterator_base(inherited_iterator_base && rhs)
        noexcept(std::is_nothrow_move_constructible_v<base_t>)                          = default; //!< Defaulted.
    constexpr inherited_iterator_base & operator=(inherited_iterator_base const & rhs)
        noexcept(std::is_nothrow_copy_assignable_v<base_t>)                             = default; //!< Defaulted.
    constexpr inherited_iterator_base & operator=(inherited_iterator_base && rhs)
        noexcept(std::is_nothrow_move_assignable_v<base_t>)                             = default; //!< Defaulted.
    ~inherited_iterator_base()
        noexcept(std::is_nothrow_destructible_v<base_t>)                                = default; //!< Defaulted.

    //!\brief Delegate to base class if inheriting from non-pointer iterator.
    constexpr inherited_iterator_base(base_t it) noexcept(std::is_nothrow_move_constructible_v<base_t>)
    //!\cond
        requires (!wrap_base)
    //!\endcond
        : base_t{std::move(it)}
    {}

    //!\brief Initialise member if deriving from pointer.
    constexpr inherited_iterator_base(base_t it) noexcept
    //!\cond
        requires wrap_base
    //!\endcond
        : member{std::move(it)}
    {}
    //!\}

    //!\brief Get a copy of the base.
    constexpr base_t base() const &
    //!\cond
        requires std::copyable<base_t>
    //!\endcond
    {
        return as_base();
    }

    //!\brief Returns an [rvalue](https://en.cppreference.com/w/cpp/language/value_category) of the base.
    constexpr base_t base() &&
    {
        return std::move(as_base());
    }

    /*!\name Comparison operators
     * \brief Unless specialised in derived_type, all operators perform base_t's operator and cast to derived_t.
     * \{
     */

    //!\brief Checks whether `*this` is equal to `rhs`.
    constexpr bool operator==(derived_t const & rhs) const
        noexcept(noexcept(std::declval<base_t &>() == std::declval<base_t &>()))
    //!\cond
        requires std::equality_comparable<base_t>
    //!\endcond
    {
        return base() == rhs.base();
    }

    //!\brief Checks whether `*this` is not equal to `rhs`.
    constexpr bool operator!=(derived_t const & rhs) const
        noexcept(noexcept(std::declval<base_t &>() == std::declval<base_t &>()))
    //!\cond
        requires std::equality_comparable<base_t>
    //!\endcond
    {
        return !(*this == rhs);
    }

    //!\brief Checks whether `*this` is less than `rhs`.
    constexpr bool operator<(derived_t const & rhs) const
        noexcept(noexcept(std::declval<base_t &>() < std::declval<base_t &>()))
    //!\cond
        requires std::totally_ordered<base_t>
    //!\endcond
    {
        return base() < rhs.base();
    }

    //!\brief Checks whether `*this` is greater than `rhs`.
    constexpr bool operator>(derived_t const & rhs) const
        noexcept(noexcept(std::declval<base_t &>() > std::declval<base_t &>()))
    //!\cond
        requires std::totally_ordered<base_t>
    //!\endcond
    {
        return base() > rhs.base();
    }

    //!\brief Checks whether `*this` is less than or equal to `rhs`.
    constexpr bool operator<=(derived_t const & rhs) const
        noexcept(noexcept(std::declval<base_t &>() > std::declval<base_t &>()))
    //!\cond
        requires std::totally_ordered<base_t>
    //!\endcond
    {
        return !(*this > rhs);
    }

    //!\brief Checks whether `*this` is greater than or equal to `rhs`.
    constexpr bool operator>=(derived_t const & rhs) const
        noexcept(noexcept(std::declval<base_t &>() < std::declval<base_t &>()))
    //!\cond
        requires std::totally_ordered<base_t>
    //!\endcond
    {
        return !(*this < rhs);
    }
    //!\}

    /*!\name Arithmetic operators
     * \brief Unless specialised in derived_type, all operators perform base_t's operator and cast to derived_t.
     * \{
    */
    //!\brief Pre-increment, return updated iterator.
    //!\cond
    template <typename base_t_ = base_t>
    //!\endcond
    constexpr derived_t & operator++() noexcept(noexcept(++std::declval<base_t &>()))
    //!\cond
        requires requires (base_t_ i) { ++i; }
    //!\endcond
    {
        ++as_base();
        return *this_derived();
    }

    //!\brief Post-increment of input iterators that do not return a copy of themselves but `void` or a proxy type.
    //!\cond
    template <typename base_t_ = base_t>
    //!\endcond
    constexpr auto operator++(int) noexcept(noexcept(std::declval<base_t &>()++))
    //!\cond
        requires requires (base_t_ i) { i++; requires !std::same_as<decltype(i++), base_t_>; }
    //!\endcond
    {
        return as_base()++;
    }

    //!\brief Post-increment, return previous iterator state.
    //!\cond
    template <typename base_t_ = base_t>
    //!\endcond
    constexpr derived_t operator++(int) noexcept(noexcept(std::declval<base_t &>()++) &&
                                                 noexcept(derived_t(std::declval<base_t &>())))
    //!\cond
        requires requires (base_t_ i) { i++; SEQAN3_RETURN_TYPE_CONSTRAINT(i++, std::same_as, base_t_); } &&
                 std::constructible_from<derived_t, base_t_>
    //!\endcond
    {
        return derived_t{as_base()++};
    }

    //!\brief Pre-decrement, return updated iterator.
    //!\cond
    template <typename base_t_ = base_t>
    //!\endcond
    constexpr derived_t & operator--() noexcept(noexcept(--std::declval<base_t &>()))
    //!\cond
        requires requires (base_t_ i) { --i; }
    //!\endcond
    {
        --as_base();
        return *this_derived();
    }

    //!\brief Post-decrement, return previous iterator state.
    //!\cond
    template <typename base_t_ = base_t>
    //!\endcond
    constexpr derived_t operator--(int) noexcept(noexcept(std::declval<base_t &>()--) &&
                                                 noexcept(derived_t{std::declval<base_t &>()}))
    //!\cond
        requires requires (base_t_ i) { i--; } && std::constructible_from<derived_t, base_t_>
    //!\endcond
    {
        return derived_t{as_base()--};
    }

    //!\brief Move iterator to the right.
    //!\cond
    template <typename base_t_ = base_t>
    //!\endcond
    constexpr derived_t & operator+=(difference_type const skip) noexcept(noexcept(std::declval<base_t &>() += skip))
    //!\cond
        requires requires (base_t_ i, difference_type const n) { i += n; }
    //!\endcond
    {
        as_base() += skip;
        return *this_derived();
    }

    //!\brief Returns an iterator which is advanced by `skip` positions.
    //!\cond
    template <typename base_t_ = base_t>
    //!\endcond
    constexpr derived_t operator+(difference_type const skip) const
        noexcept(noexcept(std::declval<base_t &>() + skip) && noexcept(derived_t{std::declval<base_t &>()}))
    //!\cond
        requires requires (base_t_ const i, difference_type const n) { i + n; } &&
                 std::constructible_from<derived_t, base_t_>
    //!\endcond
    {
        return derived_t{as_base() + skip};
    }

    //!\brief Non-member operator+ delegates to non-friend operator+.
    constexpr friend derived_t operator+(difference_type const skip, derived_t const & it)
        noexcept(noexcept(skip + std::declval<base_t const &>()))
    //!\cond
        requires requires (base_t const i, difference_type const n) { n + i; } &&
                 std::constructible_from<derived_t, base_t>
    //!\endcond
    {
        return it + skip;
    }

    //!\brief Decrement iterator by skip.
    //!\cond
    template <typename base_t_ = base_t>
    //!\endcond
    constexpr derived_t & operator-=(difference_type const skip) noexcept(noexcept(std::declval<base_t &>() -= skip))
    //!\cond
        requires requires (base_t_ i, difference_type const n) { i -= n; }
    //!\endcond
    {
        as_base() -= skip;
        return *this_derived();
    }

    //!\brief Return decremented copy of this iterator.
    //!\cond
    template <typename base_t_ = base_t>
    //!\endcond
    constexpr derived_t operator-(difference_type const skip) const
        noexcept(noexcept(std::declval<base_t const &>() - skip) && noexcept(derived_t(std::declval<base_t &>())))
    //!\cond
        requires requires (base_t_ i, difference_type const n) { i - n; } &&
                 std::constructible_from<derived_t, base_t_>
    //!\endcond
    {
        return derived_t{as_base() - skip};
    }

    //!\brief Return offset between this and remote iterator's position.
    constexpr difference_type operator-(derived_t const & rhs) const
        noexcept(noexcept(std::declval<base_t &>() - std::declval<base_t &>()))
    //!\cond
        requires std::sized_sentinel_for<base_t, base_t>
    //!\endcond
    {
        return as_base() - rhs.as_base();
    }
    //!\}

    /*!\name Reference/Dereference operators
     * \{
     */
    //!\brief Dereference operator returns element currently pointed at.
    constexpr reference operator*() noexcept(noexcept(*std::declval<base_t &>()))
    //!\cond
        requires std::indirectly_readable<base_t>
    //!\endcond
    {
        return *as_base();
    }

    //!\brief Dereference operator returns element currently pointed at.
    constexpr decltype(auto) operator*() const noexcept(noexcept(*std::declval<base_t const &>()))
    //!\cond
        requires std::indirectly_readable<base_t>
    //!\endcond
    {
        return *as_base();
    }

    //!\brief Return pointer to this iterator.
    constexpr pointer operator->() noexcept(noexcept(*std::declval<base_t &>()))
    //!\cond
        requires std::input_iterator<base_t>
    //!\endcond
    {
        return &as_base();
    }

    //!\brief Return pointer to this iterator.
    constexpr decltype(auto) operator->() const noexcept(noexcept(*std::declval<base_t const &>()))
    //!\cond
        requires std::input_iterator<base_t>
    //!\endcond
    {
        return &as_base();
    }

    //!\brief Return underlying container value currently pointed at.
    //!\cond
    template <typename base_t_ = base_t>
    //!\endcond
    constexpr decltype(auto) operator[](std::make_signed_t<difference_type> const n)
        noexcept(noexcept(std::declval<base_t &>()[0]))
    //!\cond
        requires requires (base_t_ i, difference_type const n) { i[n]; }
    //!\endcond
    {
        return as_base()[n];
    }

    //!\brief Return underlying container value currently pointed at.
    //!\cond
    template <typename base_t_ = base_t>
    //!\endcond
    constexpr decltype(auto) operator[](std::make_signed_t<difference_type> const n) const
        noexcept(noexcept(std::declval<base_t const &>()[0]))
    //!\cond
        requires requires (base_t_ const i, difference_type const n) { i[n]; }
    //!\endcond
    {
        return as_base()[n];
    }
    //!\}

private:
    //!\brief If the base is a pointer, we wrap it instead of inheriting.
    std::conditional_t<wrap_base, base_t, empty_type> member;

    //!\brief Befriend the derived type so it can access the private members.
    friend derived_t;

    //!\brief Cast this to base type.
    constexpr base_t & as_base() & noexcept
    {
        if constexpr (wrap_base)
            return member;
        else
            return *this;
    }

    //!\copydoc as_base
    constexpr base_t const & as_base() const & noexcept
    {
        if constexpr (wrap_base)
            return member;
        else
            return *this;
    }

    //!\brief Cast this to derived type.
    constexpr derived_t * this_derived()
    {
        return static_cast<derived_t*>(this);
    }

    //!\copydoc this_derived
    constexpr derived_t const * this_derived() const
    {
        return static_cast<derived_t const *>(this);
    }
};

} // namespace seqan3::detail


<|start_filename|>include/seqan3/io/sequence_file/format_embl.hpp<|end_filename|>
// -----------------------------------------------------------------------------------------------------
// Copyright (c) 2006-2021, <NAME> & Freie Universität Berlin
// Copyright (c) 2016-2021, <NAME> & 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 the seqan3::format_embl.
 * \author <NAME> <mitra.darvish AT fu-berlin.de>
 */

#pragma once

#include <seqan3/std/algorithm>
#include <iterator>
#include <seqan3/std/ranges>
#include <string>
#include <string_view>
#include <vector>

#include <seqan3/alphabet/concept.hpp>
#include <seqan3/alphabet/nucleotide/dna5.hpp>
#include <seqan3/alphabet/views/char_to.hpp>
#include <seqan3/alphabet/views/to_char.hpp>
#include <seqan3/core/range/detail/misc.hpp>
#include <seqan3/core/range/type_traits.hpp>
#include <seqan3/io/detail/misc.hpp>
#include <seqan3/io/sequence_file/input_format_concept.hpp>
#include <seqan3/io/sequence_file/input_options.hpp>
#include <seqan3/io/sequence_file/output_format_concept.hpp>
#include <seqan3/io/sequence_file/output_options.hpp>
#include <seqan3/io/stream/detail/fast_ostreambuf_iterator.hpp>
#include <seqan3/io/views/detail/istreambuf_view.hpp>
#include <seqan3/io/views/detail/take_line_view.hpp>
#include <seqan3/io/views/detail/take_until_view.hpp>
#include <seqan3/utility/char_operations/predicate.hpp>
#include <seqan3/utility/detail/type_name_as_string.hpp>
#include <seqan3/utility/views/repeat_n.hpp>

namespace seqan3
{
/*!\brief The EMBL format.
 * \implements seqan3::sequence_file_input_format
 * \implements seqan3::sequence_file_output_format
 * \ingroup io_sequence_file
 *
 * \details
 *
 * ### Introduction
 *
 * embl is the format used in ENA sequence records. See the
 * (ftp://ftp.ebi.ac.uk/pub/databases/embl/doc/usrman.txt) for a an in-depth description of the format.
 *
 * ### fields_specialisation
 *
 * The embl format provides the fields seqan3::field::seq and seqan3::field::id. Both fields are required when writing.
 *
 * ### Implementation notes
 *
 * When reading the ID-line, the ID is read until the stream encounters a ';'. Unless, the option truncate_ids is set to
 * true, then the id is read until it either sees a blank, ';' or a new line. When the option
 * "embl_genbank_complete_header" is set to true (Default: false) the whole header is read into the id.
 *
 * When writing the ID-line, the sequence length is appended.
 *
 * All other identifiers apart from 'ID' and 'SQ' are currently ignored.
 *
 * Passed qualities to either the read or write function are ignored.
 *
 */
class format_embl
{
public:
    /*!\name Constructors, destructor and assignment
     * \{
     */
    format_embl() noexcept = default; //!< Defaulted.
    format_embl(format_embl const &) noexcept = default; //!< Defaulted.
    format_embl & operator=(format_embl const &) noexcept = default; //!< Defaulted.
    format_embl(format_embl &&) noexcept = default; //!< Defaulted.
    format_embl & operator=(format_embl &&) noexcept = default; //!< Defaulted.
    ~format_embl() noexcept = default; //!< Defaulted.

    //!\}

    //!\brief The valid file extensions for this format; note that you can modify this value.
    static inline std::vector<std::string> file_extensions
    {
        { "embl" },
    };

protected:
    //!\copydoc sequence_file_input_format::read_sequence_record
    template <typename stream_type,     // constraints checked by file
              typename seq_legal_alph_type,
              typename stream_pos_type,
              typename seq_type,        // other constraints checked inside function
              typename id_type,
              typename qual_type>
    void read_sequence_record(stream_type & stream,
                              sequence_file_input_options<seq_legal_alph_type> const & options,
                              stream_pos_type & position_buffer,
                              seq_type    & sequence,
                              id_type     & id,
                              qual_type   & SEQAN3_DOXYGEN_ONLY(qualities))
    {
        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::cpp20::back_inserter(idbuffer));
        if (idbuffer != "ID")
            throw parse_error{"An entry has to start with the code word ID."};

        if constexpr (!detail::decays_to_ignore_v<id_type>)
        {
            if (options.embl_genbank_complete_header)
            {
                std::ranges::copy(idbuffer | views::char_to<std::ranges::range_value_t<id_type>>, std::cpp20::back_inserter(id));
                do
                {
                    std::ranges::copy(stream_view | detail::take_until_or_throw(is_char<'S'>)
                                                  | views::char_to<std::ranges::range_value_t<id_type>>,
                                 std::cpp20::back_inserter(id));
                    id.push_back(*stream_it);
                    ++stream_it;
                } while (*stream_it != 'Q');
                id.pop_back(); // remove 'S' from id
                idbuffer = "SQ";
            }
            else
            {
                // ID
                detail::consume(stream_view | detail::take_until(!is_blank));

                // read id
                if (options.truncate_ids)
                {
                    std::ranges::copy(stream_view | detail::take_until_or_throw(is_blank || is_char<';'> || is_cntrl)
                                                  | views::char_to<std::ranges::range_value_t<id_type>>,
                                 std::cpp20::back_inserter(id));
                }
                else
                {
                    std::ranges::copy(stream_view | detail::take_until_or_throw(is_char<';'>)
                                                  | views::char_to<std::ranges::range_value_t<id_type>>,
                                 std::cpp20::back_inserter(id));
                }
            }
        }

        // Jump to sequence
        if (idbuffer !="SQ")
        {
            do
            {
                detail::consume(stream_view | detail::take_until_or_throw(is_char<'S'>));
                ++stream_it;
            } while (*stream_it != 'Q');
        }
        detail::consume(stream_view | detail::take_line_or_throw); //Consume line with infos to sequence

        // Sequence
        auto constexpr is_end = is_char<'/'> ;
        if constexpr (!detail::decays_to_ignore_v<seq_type>)
        {
            auto seq_view = stream_view | std::views::filter(!(is_space || is_digit)) // ignore whitespace and numbers
                                        | detail::take_until_or_throw(is_end);   // until //

            auto constexpr is_legal_alph = char_is_valid_for<seq_legal_alph_type>;
            std::ranges::copy(seq_view | std::views::transform([is_legal_alph] (char const c) // enforce legal alphabet
                                    {
                                        if (!is_legal_alph(c))
                                        {
                                            throw parse_error{std::string{"Encountered an unexpected letter: "} +
                                                              "char_is_valid_for<" +
                                                              detail::type_name_as_string<seq_legal_alph_type> +
                                                              "> evaluated to false on " +
                                                              detail::make_printable(c)};
                                        }
                                        return c;
                                    })
                                  | views::char_to<std::ranges::range_value_t<seq_type>>,         // convert to actual target alphabet
                         std::cpp20::back_inserter(sequence));
        }
        else
        {
            detail::consume(stream_view | detail::take_until(is_end));
        }
        //Jump over // and cntrl
        ++stream_it;
        ++stream_it;
        ++stream_it;
    }

    //!\copydoc sequence_file_output_format::write_sequence_record
    template <typename stream_type,     // constraints checked by file
              typename seq_type,        // other constraints checked inside function
              typename id_type,
              typename qual_type>
    void write_sequence_record(stream_type                          & stream,
                               sequence_file_output_options const   & options,
                               seq_type                             && sequence,
                               id_type                              && id,
                               qual_type                            && SEQAN3_DOXYGEN_ONLY(qualities))
    {
        seqan3::detail::fast_ostreambuf_iterator stream_it{*stream.rdbuf()};

        [[maybe_unused]] size_t sequence_size = 0;

        if constexpr (!detail::decays_to_ignore_v<seq_type>)
            sequence_size = std::ranges::distance(sequence);

        // ID
        if constexpr (detail::decays_to_ignore_v<id_type>)
        {
            throw std::logic_error{"The ID field may not be set to ignore when writing embl files."};
        }
        else
        {
            if (ranges::empty(id)) //[[unlikely]]
                throw std::runtime_error{"The ID field may not be empty when writing embl files."};

            if (options.embl_genbank_complete_header)
            {
                stream_it.write_range(id);
            }
            else
            {
                stream_it.write_range(std::string_view{"ID "});
                stream_it.write_range(id);
                stream_it.write_range(std::string_view{"; "});
                stream_it.write_number(sequence_size);
                stream_it.write_range(std::string_view{" BP.\n"});
            }
        }

        // Sequence
        if constexpr (detail::decays_to_ignore_v<seq_type>) // sequence
        {
            throw std::logic_error{"The SEQ field may not be set to ignore when writing embl files."};
        }
        else
        {
            if (std::ranges::empty(sequence)) //[[unlikely]]
                throw std::runtime_error{"The SEQ field may not be empty when writing embl files."};

            // write beginning of sequence record
            stream_it.write_range(std::string_view{"SQ Sequence "});
            stream_it.write_number(sequence_size);
            stream_it.write_range(std::string_view{" BP;\n"});

            // write sequence in chunks of 60 bp's with a space after 10 bp's
            auto char_sequence = sequence | views::to_char;
            auto it = std::ranges::begin(char_sequence);
            size_t written_chars{0};
            uint8_t chunk_size{10u};

            while (it != std::ranges::end(char_sequence))
            {
                auto current_end = it;
                size_t steps = std::ranges::advance(current_end, chunk_size, std::ranges::end(char_sequence));

                using subrange_t = std::ranges::subrange<decltype(it), decltype(it), std::ranges::subrange_kind::sized>;
                it = stream_it.write_range(subrange_t{it, current_end, chunk_size - steps});
                stream_it = ' ';
                written_chars += chunk_size;

                if (written_chars % 60 == 0)
                {
                    stream_it.write_number(written_chars);
                    stream_it.write_end_of_line(options.add_carriage_return);
                }
            }

            // fill last line
            auto characters_in_last_line = sequence_size % 60;
            auto number_of_padding_needed = 65 - characters_in_last_line - characters_in_last_line / chunk_size;
            stream_it.write_range(views::repeat_n(' ', number_of_padding_needed));
            stream_it.write_number(sequence_size);
            stream_it.write_end_of_line(options.add_carriage_return);

            // write end-of-record-symbol
            stream_it.write_range(std::string_view{"//"});
            stream_it.write_end_of_line(options.add_carriage_return);
        }
    }
};

} // namespace seqan


<|start_filename|>include/seqan3/search/dream_index/all.hpp<|end_filename|>
// -----------------------------------------------------------------------------------------------------
// Copyright (c) 2006-2021, <NAME> & Freie Universität Berlin
// Copyright (c) 2016-2021, <NAME> & 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
 * \author <NAME> <enrico.seiler AT fu-berlin.de>
  * \brief Meta-header for the \link search_dream_index Search / DREAM Index submodule \endlink.
 */

#pragma once

#include <seqan3/search/dream_index/interleaved_bloom_filter.hpp>

/*!\defgroup search_dream_index DREAM Index
 * \brief Provides seqan3:interleaved_bloom_filter.
 * \ingroup search
 * \see search
 */


<|start_filename|>include/seqan3/alignment/configuration/align_config_method.hpp<|end_filename|>
// -----------------------------------------------------------------------------------------------------
// Copyright (c) 2006-2021, <NAME> & Freie Universität Berlin
// Copyright (c) 2016-2021, <NAME> & 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 global and local alignment configurations.
 * \author <NAME> <joshua.kim AT fu-berlin.de>
 * \author <NAME> <rene.rahn AT fu-berlin.de>
 * \author <NAME> <j.winkler AT fu-berlin.de>
 * \author <NAME> <w.vandertoorn AT fu-berlin.de>
 */

#pragma once

#include <seqan3/alignment/configuration/detail.hpp>
#include <seqan3/core/configuration/pipeable_config_element.hpp>
#include <seqan3/core/detail/empty_type.hpp>
#include <seqan3/core/detail/strong_type.hpp>

namespace seqan3::align_cfg
{

/*!\brief Sets the local alignment method.
 * \ingroup alignment_configuration
 *
 * \details
 *
 * The alignment algorithm can be categorised in different methods. For example, the
 * \ref seqan3::align_cfg::method_local "local" and the
 * \ref seqan3::align_cfg::method_global "global" alignment are two different methods, while the semi-global alignment
 * is a variation of the global alignment. This differentiation makes it possible to define a subset of configurations
 * that can work with a particular method. Since it is not possible to guess what the desired method for a user is,
 * there is no default and this configuration must always be provided for the alignment algorithm.
 *
 * ### Example
 *
 * \include test/snippet/alignment/configuration/align_cfg_method_local.cpp
 */
class method_local : private pipeable_config_element
{
public:
    /*!\name Constructors, destructor and assignment
     * \{
     */
    method_local() = default; //!< Defaulted.
    method_local(method_local const &) = default; //!< Defaulted.
    method_local(method_local &&) = default; //!< Defaulted.
    method_local & operator=(method_local const &) = default; //!< Defaulted.
    method_local & operator=(method_local &&) = default; //!< Defaulted.
    ~method_local() = default; //!< Defaulted.

    //!\}

    //!\privatesection
    //!\brief An internal id used to check for a valid alignment configuration.
    static constexpr seqan3::detail::align_config_id id{seqan3::detail::align_config_id::local};
};

/*!\brief A strong type representing free_end_gaps_sequence1_leading of the seqan3::align_cfg::method_global.
 * \ingroup alignment_configuration
 */
struct free_end_gaps_sequence1_leading : public seqan3::detail::strong_type<bool, free_end_gaps_sequence1_leading>
{
    //!\brief The type of the strong type base class.
    using base_t = seqan3::detail::strong_type<bool, free_end_gaps_sequence1_leading>;
    using base_t::base_t; // Import the base class constructors
};

/*!\brief A strong type representing free_end_gaps_sequence2_leading of the seqan3::align_cfg::method_global.
 * \ingroup alignment_configuration
 */
struct free_end_gaps_sequence2_leading : public seqan3::detail::strong_type<bool, free_end_gaps_sequence2_leading>
{
    //!\brief The type of the strong type base class.
    using base_t = seqan3::detail::strong_type<bool, free_end_gaps_sequence2_leading>;
    using base_t::base_t; // Import the base class constructors
};

/*!\brief A strong type representing free_end_gaps_sequence1_trailing of the seqan3::align_cfg::method_global.
 * \ingroup alignment_configuration
 */
struct free_end_gaps_sequence1_trailing : public seqan3::detail::strong_type<bool, free_end_gaps_sequence1_trailing>
{
    //!\brief The type of the strong type base class.
    using base_t = seqan3::detail::strong_type<bool, free_end_gaps_sequence1_trailing>;
    using base_t::base_t; // Import the base class constructors
};

/*!\brief A strong type representing free_end_gaps_sequence2_trailing of the seqan3::align_cfg::method_global.
 * \ingroup alignment_configuration
 */
struct free_end_gaps_sequence2_trailing : public seqan3::detail::strong_type<bool, free_end_gaps_sequence2_trailing>
{
    //!\brief The type of the strong type base class.
    using base_t = seqan3::detail::strong_type<bool, free_end_gaps_sequence2_trailing>;
    using base_t::base_t; // Import the base class constructors
};

/*!\brief Sets the global alignment method.
 * \ingroup alignment_configuration
 * \copydetails seqan3::align_cfg::method_local
 */
class method_global : private pipeable_config_element
{
public:
    /*!\name Constructors, destructor and assignment
     * \{
     */
    method_global() = default; //!< Defaulted.
    method_global(method_global const &) = default; //!< Defaulted.
    method_global(method_global &&) = default; //!< Defaulted.
    method_global & operator=(method_global const &) = default; //!< Defaulted.
    method_global & operator=(method_global &&) = default; //!< Defaulted.
    ~method_global() = default; //!< Defaulted.

    /*!\brief Construct method_global with a specific free end gap configuration.
     * \param[in] free_sequence1_leading An instance of seqan3::align_cfg::free_end_gaps_sequence1_leading that
     *                                   indicates whether leading gaps in sequence1 should be free (not penalised).
     * \param[in] free_sequence2_leading An instance of seqan3::align_cfg::free_end_gaps_sequence2_leading that
     *                                   indicates whether leading gaps in sequence2 should be free (not penalised).
     * \param[in] free_sequence1_trailing An instance of seqan3::align_cfg::free_end_gaps_sequence1_trailing that
     *                                   indicates whether trailing gaps in sequence1 should be free (not penalised).
     * \param[in] free_sequence2_trailing An instance of seqan3::align_cfg::free_end_gaps_sequence2_trailing that
     *                                   indicates whether trailing gaps in sequence2 should be free (not penalised).
     */
    constexpr method_global(seqan3::align_cfg::free_end_gaps_sequence1_leading free_sequence1_leading,
                            seqan3::align_cfg::free_end_gaps_sequence2_leading free_sequence2_leading,
                            seqan3::align_cfg::free_end_gaps_sequence1_trailing free_sequence1_trailing,
                            seqan3::align_cfg::free_end_gaps_sequence2_trailing free_sequence2_trailing) noexcept :
        free_end_gaps_sequence1_leading{free_sequence1_leading.get()},
        free_end_gaps_sequence2_leading{free_sequence2_leading.get()},
        free_end_gaps_sequence1_trailing{free_sequence1_trailing.get()},
        free_end_gaps_sequence2_trailing{free_sequence2_trailing.get()}
    {}
    //!\}

    //!\brief If set to `true`, leading gaps in sequence1 are not penalised when computing the optimal alignment.
    bool free_end_gaps_sequence1_leading{false};
    //!\brief If set to `true`, leading gaps in sequence2 are not penalised when computing the optimal alignment.
    bool free_end_gaps_sequence2_leading{false};
    //!\brief If set to `true`, trailing gaps in sequence1 are not penalised when computing the optimal alignment.
    bool free_end_gaps_sequence1_trailing{false};
    //!\brief If set to `true`, trailing gaps in sequence2 are not penalised when computing the optimal alignment.
    bool free_end_gaps_sequence2_trailing{false};

    //!\privatesection
    //!\brief An internal id used to check for a valid alignment configuration.
    static constexpr seqan3::detail::align_config_id id{seqan3::detail::align_config_id::global};
};

} // namespace seqan3::align_cfg


<|start_filename|>include/seqan3/alphabet/composite/all.hpp<|end_filename|>
// -----------------------------------------------------------------------------------------------------
// Copyright (c) 2006-2021, <NAME> & Freie Universität Berlin
// Copyright (c) 2016-2021, <NAME> & 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
 * \author <NAME> <marcel.ehrhardt AT fu-berlin.de>
 * \brief Meta-header for the \link alphabet_composite Alphabet / Composite submodule \endlink.
 */
#pragma once

#include <seqan3/alphabet/composite/alphabet_tuple_base.hpp>
#include <seqan3/alphabet/composite/alphabet_variant.hpp>
#include <seqan3/alphabet/composite/semialphabet_any.hpp>

/*!\defgroup alphabet_composite Composite
 * \brief Provides templates for combining existing alphabets into new alphabet types.
 * \ingroup alphabet
 * \see alphabet
 *
 * \details
 *
 * ### Introduction
 *
 * This module provides various class templates that allow you to combine existing alphabets into new ones. For example,
 * you can add new characters to existing alphabets by using seqan3::alphabet_variant or combine alphabets with quality
 * information by using seqan3::alphabet_tuple_base.
 *
 * We have currently three major composite alphabets:
 * * seqan3::alphabet_tuple_base which can be used to create a std::tuple like object that still models
 *   seqan3::alphabet.
 * * seqan3::alphabet_variant which roughly corresponds to the Union of the given types. It behaves similar to
 *   std::variant, but also models seqan3::alphabet.
 * * seqan3::semialphabet_any which type erases other alphabets of the same size and allows again transformation to
 *   alphabets of the same size by copying the rank.
 */


<|start_filename|>include/seqan3/io/structure_file/input_format_concept.hpp<|end_filename|>
// -----------------------------------------------------------------------------------------------------
// Copyright (c) 2006-2021, <NAME> & Freie Universität Berlin
// Copyright (c) 2016-2021, <NAME> & 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::structure_file_input_format.
 * \author <NAME> <j.winkler AT fu-berlin.de>
 */

#pragma once

#include <fstream>
#include <set>
#include <string>
#include <utility>
#include <vector>

#include <seqan3/alphabet/nucleotide/rna5.hpp>
#include <seqan3/alphabet/structure/structured_rna.hpp>
#include <seqan3/alphabet/structure/wuss.hpp>
#include <seqan3/io/structure_file/input_options.hpp>
#include <seqan3/utility/type_list/type_list.hpp>

namespace seqan3::detail
{

/*!\brief Internal class used to expose the actual format interface to read structure records from the file.
 * \ingroup io_structure_file
 *
 * \tparam format_type The type of the format to be exposed.
 *
 * \details
 *
 * Exposes the protected member function `read_structure_record` from the given `format_type`, such that the file can
 * call the proper function for the selected format.
 */
template <typename format_type>
struct structure_file_input_format_exposer : public format_type
{
public:
    // Can't use `using format_type::read_structure_record` as it produces a hard failure in the format concept check
    // for types that do not model the format concept, i.e. don't offer the proper read_structure_record interface.
    //!\brief Forwards to the seqan3::structure_file_input_format::read_structure_record interface.
    template <typename ...ts>
    void read_structure_record(ts && ...args)
    {
        format_type::read_structure_record(std::forward<ts>(args)...);
    }
};

} // namespace seqan3::detail

namespace seqan3
{

/*!\interface seqan3::structure_file_input_format <>
 * \brief The generic concept for structure file in formats.
 * \ingroup io_structure_file
 *
 * \details
 *
 * The details of this concept are only relevant to developers who wish to implement their own format.
 * The requirements for this concept are given as related functions and type traits.
 * Types that satisfy this concept are shown as "implementing this interface".
 */
//!\cond
template <typename t>
SEQAN3_CONCEPT structure_file_input_format = requires(detail::structure_file_input_format_exposer<t> & v,
                                                      std::ifstream & f,
                                                      structure_file_input_options<rna5, false> & options,
                                                      rna5_vector & seq,
                                                      std::string & id,
                                                      std::vector<std::set<std::pair<double, size_t>>> & bpp,
                                                      std::vector<wuss51> & structure,
                                                      std::vector<structured_rna<rna5, wuss51>> & structured_seq,
                                                      double energy,
                                                      double react,
                                                      double react_err,
                                                      std::string & comment,
                                                      size_t offset)
{
    t::file_extensions;

    SEQAN3_RETURN_TYPE_CONSTRAINT(v.read_structure_record(f,
                                                          options,
                                                          seq,
                                                          id,
                                                          bpp,
                                                          structure,
                                                          energy,
                                                          react,
                                                          react_err,
                                                          comment,
                                                          offset),
                                  std::same_as, void);
    SEQAN3_RETURN_TYPE_CONSTRAINT(v.read_structure_record(f,
                                                          options,
                                                          seq,
                                                          id,
                                                          bpp,
                                                          std::ignore,
                                                          std::ignore,
                                                          std::ignore,
                                                          std::ignore,
                                                          std::ignore,
                                                          std::ignore),
                                  std::same_as, void);
    SEQAN3_RETURN_TYPE_CONSTRAINT(v.read_structure_record(f,
                                                          options,
                                                          structured_seq,
                                                          id,
                                                          std::ignore,
                                                          structured_seq,
                                                          energy,
                                                          std::ignore,
                                                          std::ignore,
                                                          std::ignore,
                                                          std::ignore),
                                  std::same_as, void);
    SEQAN3_RETURN_TYPE_CONSTRAINT(v.read_structure_record(f,
                                                          options,
                                                          std::ignore,
                                                          std::ignore,
                                                          std::ignore,
                                                          std::ignore,
                                                          std::ignore,
                                                          std::ignore,
                                                          std::ignore,
                                                          std::ignore,
                                                          std::ignore),
                                  std::same_as, void);
    // the last is required to be compile time valid, but should always throw at run-time.
};
//!\endcond

/*!\name Requirements for seqan3::structure_file_input_format
 * \brief You can expect these **members** on all types that implement seqan3::structure_file_input_format.
 * \memberof seqan3::structure_file_input_format
 * \{
 */
/*!\fn void read_structure_record(stream_type & stream,
 *                                structure_file_input_options<seq_legal_alph_type, structured_seq_combined> const & options,
 *                                seq_type & seq,
 *                                id_type & id,
 *                                bpp_type & bpp,
 *                                structure_type & structure,
 *                                energy_type & energy,
 *                                react_type & react,
 *                                react_type & react_err,
 *                                comment_type & comment,
 *                                offset_type & offset)
 * \brief Read from the specified stream and back-insert into the given field buffers.
 * \tparam stream_type      Input stream, must satisfy seqan3::input_stream_over with `char`.
 * \tparam seq_type         Type of the seqan3::field::seq input; must satisfy std::ranges::output_range
 * over a seqan3::alphabet.
 * \tparam id_type          Type of the seqan3::field::id input; must satisfy std::ranges::output_range
 * over a seqan3::alphabet.
 * \tparam bpp_type         Type of the seqan3::field::bpp input; must satisfy std::ranges::output_range
 * over a set of pair of types satisfying std::is_floating_point and std::numeric_limits::is_integer, respectively.
 * \tparam structure_type   Type of the seqan3::field::structure input; must satisfy std::ranges::output_range
 * over a seqan3::rna_structure_alphabet.
 * \tparam energy_type      Type of the seqan3::field::energy input; must satisfy std::is_floating_point.
 * \tparam react_type       Type of the seqan3::field::react and seqan3::field::react_err input;
 * must satisfy std::is_floating_point.
 * \tparam comment_type     Type of the seqan3::field::comment input; must satisfy std::ranges::output_range
 * over a seqan3::alphabet.
 * \tparam offset_type      Type of the seqan3::field::offset input; must satisfy std::numeric_limits::is_integer.
 * \param[in,out] stream    The input stream to read from.
 * \param[in]     options   File specific options passed to the format.
 * \param[out]    seq       The buffer for seqan3::field::seq input, i.e. the "sequence".
 * \param[out]    id        The buffer for seqan3::field::id input, e.g. the header line.
 * \param[out]    bpp       The buffer for seqan3::field::bpp input.
 * \param[out]    structure The buffer for seqan3::field::structure input.
 * \param[out]    energy    The buffer for seqan3::field::energy input.
 * \param[out]    react     The buffer for seqan3::field::react input.
 * \param[out]    react_err The buffer for seqan3::field::react_err input.
 * \param[out]    comment   The buffer for seqan3::field::comment input.
 * \param[out]    offset    The buffer for seqan3::field::offset input.
 *
 * \details
 *
 * ### Additional requirements
 *
 *   * The function must also accept std::ignore as parameter for any of the fields.
 *     [This is enforced by the concept checker!]
 *   * In this case the data read for that field shall be discarded by the format.
 *   * Instead of passing the fields seqan3::field::seq and seqan3::field::structure, you may also pass
 *     seqan3::field::structured_seq to both parameters. If you do, the std::ranges::range_value_t of the argument must be
 *     a specialisation of seqan3::structured_rna and the second template parameter to
 *     seqan3::structure_file_input_options must be set to true.
 */
 /*!\var static inline std::vector<std::string> seqan3::structure_file_input_format::file_extensions
 * \brief The format type is required to provide a vector of all supported file extensions.
 */
//!\}

} // namespace seqan3

namespace seqan3::detail
{

/*!\brief Auxiliary value metafuncton that checks whether a type is a seqan3::type_list and all types meet
 * seqan3::structure_file_input_format [default is false].
 * \ingroup core
 * \see seqan3::type_list_specialisationOfstructure_file_input_formats
 */
template <typename t>
constexpr bool is_type_list_of_structure_file_input_formats_v = false;

/*!\brief Auxiliary value metafuncton that checks whether a type is a seqan3::type_list and all types meet
 * seqan3::structure_file_input_format [overload].
 * \ingroup core
 * \see seqan3::type_list_specialisationOfstructure_file_input_formats
 */
template <typename ...ts>
constexpr bool is_type_list_of_structure_file_input_formats_v<type_list<ts...>>
                = (structure_file_input_format<ts> && ...);

/*!\brief Auxiliary concept that checks whether a type is a seqan3::type_list and all types meet
 * seqan3::structure_file_input_format.
 * \ingroup core
 * \see seqan3::is_type_list_of_structure_file_formats_v
 */
template <typename t>
SEQAN3_CONCEPT type_list_of_structure_file_input_formats = is_type_list_of_structure_file_input_formats_v<t>;
} // namespace seqan3::detail


<|start_filename|>include/seqan3/utility/parallel/all.hpp<|end_filename|>
// -----------------------------------------------------------------------------------------------------
// Copyright (c) 2006-2021, <NAME> & Freie Universität Berlin
// Copyright (c) 2016-2021, <NAME> & 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 Meta-header for the \cond DEV \link utility_parallel Utility / Parallel submodule \endlink \endcond.
 * \author <NAME> <rene.rahn AT fu-berlin.de>
 */

#pragma once

//!\cond DEV

/*!\defgroup utility_parallel Parallel
 * \brief This module contains types and utilities for concurrent execution of algorithms in SeqAn.
 * \ingroup utility
 * \see utility
 *
 * \details
 *
 * ### Execution policies
 *
 * Here are currently only implementations which are part of detail and therefore not of interest for the common user.
 *
 * ### Concurrency support
 *
 * This module contains helper classes to synchronise threads in concurrent environments.
 */
//!\endcond

 #include <seqan3/utility/parallel/detail/latch.hpp>
 #include <seqan3/utility/parallel/detail/reader_writer_manager.hpp>
 #include <seqan3/utility/parallel/detail/spin_delay.hpp>


<|start_filename|>test/snippet/io/sequence_file/sequence_file_output_template_deduction.cpp<|end_filename|>
#include <seqan3/test/snippet/create_temporary_snippet_file.hpp>
// std::filesystem::current_path() / "my.fasta" will be deleted after the execution
seqan3::test::create_temporary_snippet_file my_fasta{"my.fasta", ""};

//![main]
#include <seqan3/std/filesystem>

#include <seqan3/io/sequence_file/output.hpp>

int main()
{
    auto fasta_file = std::filesystem::current_path() / "my.fasta";

    // FastA format detected, std::ofstream opened for file
    seqan3::sequence_file_output fin{fasta_file};
}
//![main]


<|start_filename|>include/seqan3/search/configuration/output.hpp<|end_filename|>
// -----------------------------------------------------------------------------------------------------
// Copyright (c) 2006-2021, <NAME> & Freie Universität Berlin
// Copyright (c) 2016-2021, <NAME> & 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 the configuration for the content of the search result.
 * \author <NAME> <christopher.pockrandt AT fu-berlin.de>
 * \author <NAME> <rene.rahn AT fu-berlin.de>
 * \author <NAME> <svenja.mehringer AT fu-berlin.de>
 */

#pragma once

#include <seqan3/core/configuration/configuration.hpp>
#include <seqan3/core/configuration/pipeable_config_element.hpp>
#include <seqan3/core/detail/empty_type.hpp>
#include <seqan3/search/configuration/detail.hpp>

namespace seqan3::search_cfg
{

/*!\brief Include the query_id in the seqan3::search_result returned by a call to seqan3::search.
 * \ingroup search_configuration
 * \sa \ref search_configuration_subsection_output "Section on Output"
 */
class output_query_id : private pipeable_config_element
{
public:
    /*!\name Constructors, destructor and assignment
     * \{
     */
    constexpr output_query_id() = default; //!< Defaulted.
    constexpr output_query_id(output_query_id const &) = default; //!< Defaulted.
    constexpr output_query_id(output_query_id &&) = default; //!< Defaulted.
    constexpr output_query_id & operator=(output_query_id const &) = default; //!< Defaulted.
    constexpr output_query_id & operator=(output_query_id &&) = default; //!< Defaulted.
    ~output_query_id() = default; //!< Defaulted.

    //!\}

    //!\privatesection
    //!\brief Internal id to check for consistent configuration settings.
    static constexpr detail::search_config_id id{detail::search_config_id::output_query_id};
};

/*!\brief Include the reference_id in the seqan3::search_result returned by a call to seqan3::search.
 * \ingroup search_configuration
 * \sa \ref search_configuration_subsection_output "Section on Output"
 */
class output_reference_id : private pipeable_config_element
{
public:
    /*!\name Constructors, destructor and assignment
     * \{
     */
    constexpr output_reference_id() = default; //!< Defaulted.
    constexpr output_reference_id(output_reference_id const &) = default; //!< Defaulted.
    constexpr output_reference_id(output_reference_id &&) = default; //!< Defaulted.
    constexpr output_reference_id & operator=(output_reference_id const &) = default; //!< Defaulted.
    constexpr output_reference_id & operator=(output_reference_id &&) = default; //!< Defaulted.
    ~output_reference_id() = default; //!< Defaulted.

    //!\}

    //!\privatesection
    //!\brief Internal id to check for consistent configuration settings.
    static constexpr detail::search_config_id id{detail::search_config_id::output_reference_id};
};

/*!\brief Include the reference_begin_position in the seqan3::search_result returned by a call to seqan3::search.
 * \ingroup search_configuration
 * \sa \ref search_configuration_subsection_output "Section on Output"
 */
class output_reference_begin_position : private pipeable_config_element
{
public:
    /*!\name Constructors, destructor and assignment
     * \{
     */
    constexpr output_reference_begin_position() = default; //!< Defaulted.
    constexpr output_reference_begin_position(output_reference_begin_position const &) = default; //!< Defaulted.
    constexpr output_reference_begin_position(output_reference_begin_position &&) = default; //!< Defaulted.
    constexpr output_reference_begin_position & operator=(output_reference_begin_position const &) = default; //!< Defaulted.
    constexpr output_reference_begin_position & operator=(output_reference_begin_position &&) = default; //!< Defaulted.
    ~output_reference_begin_position() = default; //!< Defaulted.

    //!\}

    //!\privatesection
    //!\brief Internal id to check for consistent configuration settings.
    static constexpr detail::search_config_id id{detail::search_config_id::output_reference_begin_position};
};

/*!\brief Include the index_cursor in the seqan3::search_result returned by a call to seqan3::search.
 * \ingroup search_configuration
 * \sa \ref search_configuration_subsection_output "Section on Output"
 */
class output_index_cursor : private pipeable_config_element
{
public:
    /*!\name Constructors, destructor and assignment
     * \{
     */
    constexpr output_index_cursor() = default; //!< Defaulted.
    constexpr output_index_cursor(output_index_cursor const &) = default; //!< Defaulted.
    constexpr output_index_cursor(output_index_cursor &&) = default; //!< Defaulted.
    constexpr output_index_cursor & operator=(output_index_cursor const &) = default; //!< Defaulted.
    constexpr output_index_cursor & operator=(output_index_cursor &&) = default; //!< Defaulted.
    ~output_index_cursor() = default; //!< Defaulted.

    //!\}

    //!\privatesection
    //!\brief Internal id to check for consistent configuration settings.
    static constexpr detail::search_config_id id{detail::search_config_id::output_index_cursor};
};

} // namespace seqan3::search_cfg


<|start_filename|>include/seqan3/search/configuration/max_error.hpp<|end_filename|>
// -----------------------------------------------------------------------------------------------------
// Copyright (c) 2006-2021, <NAME> & Freie Universität Berlin
// Copyright (c) 2016-2021, <NAME> & 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 the configuration for maximum number of errors for all error types.
 * \author <NAME> <christopher.pockrandt AT fu-berlin.de>
 * \author <NAME> <rene.rahn AT fu-berlin.de>
 * \author <NAME> <lydia.buntrock AT fu-berlin.de>
 */

#pragma once

#include <variant>

#include <seqan3/core/configuration/pipeable_config_element.hpp>
#include <seqan3/search/configuration/detail.hpp>
#include <seqan3/search/configuration/max_error_common.hpp>
#include <seqan3/search/detail/search_common.hpp>

namespace seqan3::search_cfg
{
/*!\brief Configuration element that represents the number or rate of total errors.
 * \ingroup search_configuration
 *
 * \details
 * This configuration element can be used to determine the number or rate of total errors that are supported.
 *
 * ### Example
 * \include test/snippet/search/configuration_error.cpp
 */
class max_error_total : private pipeable_config_element
{
public:
    //!\brief The error count or error rate.
    std::variant<error_count, error_rate> error{error_count{0}};

    /*!\name Constructors, destructor and assignment
     * \{
     */
    max_error_total() = default; //!< Defaulted.
    max_error_total(max_error_total const &) = default; //!< Defaulted.
    max_error_total(max_error_total &&) = default; //!< Defaulted.
    max_error_total & operator=(max_error_total const &) = default; //!< Defaulted.
    max_error_total & operator=(max_error_total &&) = default; //!< Defaulted.
    ~max_error_total() = default; //!< Defaulted.

    /*!\brief Initialises the total error with the given seqan3::search_cfg::error_count.
     * \param[in] error The maximal number of total errors allowed in the search.
     */
    explicit max_error_total(error_count error) : error{std::move(error)}
    {}

    /*!\brief Initialises the total error with the given seqan3::search_cfg::error_rate.
     * \param[in] error The maximal total error rate allowed in the search.
     */
    explicit max_error_total(error_rate error) : error{std::move(error)}
    {}
    //!\}

    //!\privatesection
    //!\brief Internal id to check for consistent configuration settings.
    static constexpr detail::search_config_id id{detail::search_config_id::max_error_total};
};

/*!\brief Configuration element that represents the number or rate of substitution errors.
 * \ingroup search_configuration
 *
 * \details
 * This configuration element can be used to determine the number or rate of substitution errors that are supported.
 * A substitution corresponds to diverging bases between text and query for a certain position.
 *
 * ### Example
 * \include test/snippet/search/configuration_error.cpp
 */
class max_error_substitution : private pipeable_config_element
{
public:
    //!\brief The error count or error rate.
    std::variant<error_count, error_rate> error{error_count{0}};

    /*!\name Constructors, destructor and assignment
     * \{
     */
    max_error_substitution() = default; //!< Defaulted.
    max_error_substitution(max_error_substitution const &) = default; //!< Defaulted.
    max_error_substitution(max_error_substitution &&) = default; //!< Defaulted.
    max_error_substitution & operator=(max_error_substitution const &) = default; //!< Defaulted.
    max_error_substitution & operator=(max_error_substitution &&) = default; //!< Defaulted.
    ~max_error_substitution() = default; //!< Defaulted.

    /*!\brief Initialises the substitution error with the given seqan3::search_cfg::error_count.
     * \param[in] error The maximal number of substitution errors allowed in the search.
     */
    explicit max_error_substitution(error_count error) : error{std::move(error)}
    {}

    /*!\brief Initialises the substitution error with the given seqan3::search_cfg::error_rate.
     * \param[in] error The maximal error rate for substitutions allowed in the search.
     */
    explicit max_error_substitution(error_rate error) : error{std::move(error)}
    {}
    //!\}

    //!\privatesection
    //!\brief Internal id to check for consistent configuration settings.
    static constexpr detail::search_config_id id{detail::search_config_id::max_error_substitution};
};

/*!\brief Configuration element that represents the number or rate of insertion errors.
 * \ingroup search_configuration
 *
 * \details
 * This configuration element can be used to determine the number or rate of insertion errors that are supported.
 * An insertion corresponds to a base inserted into the query that does not occur in the text at the position.
 *
 * ### Example
 * \include test/snippet/search/configuration_error.cpp
 */
class max_error_insertion : private pipeable_config_element
{
public:
    //!\brief The error count or error rate.
    std::variant<error_count, error_rate> error{error_count{0}};

    /*!\name Constructors, destructor and assignment
     * \{
     */
    max_error_insertion() = default; //!< Defaulted.
    max_error_insertion(max_error_insertion const &) = default; //!< Defaulted.
    max_error_insertion(max_error_insertion &&) = default; //!< Defaulted.
    max_error_insertion & operator=(max_error_insertion const &) = default; //!< Defaulted.
    max_error_insertion & operator=(max_error_insertion &&) = default; //!< Defaulted.
    ~max_error_insertion() = default; //!< Defaulted.

    /*!\brief Initialises the insertion error with the given seqan3::search_cfg::error_count.
     * \param[in] error The maximal number of insertion errors allowed in the search.
     */
    explicit max_error_insertion(error_count error) : error{std::move(error)}
    {}

    /*!\brief Initialises the insertion error with the given seqan3::search_cfg::error_rate.
     * \param[in] error The maximal error rate for insertions allowed in the search.
     */
    explicit max_error_insertion(error_rate error) : error{std::move(error)}
    {}
    //!\}

    //!\privatesection
    //!\brief Internal id to check for consistent configuration settings.
    static constexpr detail::search_config_id id{detail::search_config_id::max_error_insertion};
};

/*!\brief Configuration element that represents the number or rate of deletion errors.
 * \ingroup search_configuration
 *
 * \details
 * This configuration element can be used to determine the number or rate of deletion errors that are supported.
 * A deletion corresponds to a base deleted from the query sequence that does occur in the text.
 * Deletions at the beginning and at the end of the sequence are not considered during a search.
 *
 * ### Example
 * \include test/snippet/search/configuration_error.cpp
 */
class max_error_deletion : private pipeable_config_element
{
public:
    //!\brief The error count or error rate.
    std::variant<error_count, error_rate> error{error_count{0}};

    /*!\name Constructors, destructor and assignment
     * \{
     */
    max_error_deletion() = default; //!< Defaulted.
    max_error_deletion(max_error_deletion const &) = default; //!< Defaulted.
    max_error_deletion(max_error_deletion &&) = default; //!< Defaulted.
    max_error_deletion & operator=(max_error_deletion const &) = default; //!< Defaulted.
    max_error_deletion & operator=(max_error_deletion &&) = default; //!< Defaulted.
    ~max_error_deletion() = default; //!< Defaulted.

    /*!\brief Initialises the deletion error with the given seqan3::search_cfg::error_count.
     * \param[in] error The maximal number of deletion errors allowed in the search.
     */
    explicit max_error_deletion(error_count error) : error{std::move(error)}
    {}

    /*!\brief Initialises the deletion error with the given seqan3::search_cfg::error_rate.
     * \param[in] error The maximal error rate for deletions allowed in the search.
     */
    explicit max_error_deletion(error_rate error) : error{std::move(error)}
    {}
    //!\}

    //!\privatesection
    //!\brief Internal id to check for consistent configuration settings.
    static constexpr detail::search_config_id id{detail::search_config_id::max_error_deletion};
};

} // namespace seqan3::search_cfg


<|start_filename|>include/seqan3/utility/simd/views/all.hpp<|end_filename|>
// -----------------------------------------------------------------------------------------------------
// Copyright (c) 2006-2021, <NAME> & Freie Universität Berlin
// Copyright (c) 2016-2021, <NAME> & 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 Meta-header for the \cond DEV \link utility_simd_views Utility / SIMD / Views submodule \endlink \endcond.
 * \author <NAME> <marcel.ehrhardt AT fu-berlin.de>
 */

#pragma once

#include <seqan3/utility/simd/views/iota_simd.hpp>
#include <seqan3/utility/simd/views/to_simd.hpp>

//!\cond DEV

/*!\defgroup utility_simd_views Views
 * \brief SIMD related views.
 * \ingroup utility_simd
 * \see utility_simd
 */

//!\endcond


<|start_filename|>include/seqan3/core/configuration/pipeable_config_element.hpp<|end_filename|>
// -----------------------------------------------------------------------------------------------------
// Copyright (c) 2006-2021, <NAME> & Freie Universität Berlin
// Copyright (c) 2016-2021, <NAME> & 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::pipeable_config_element.
 * \author <NAME> <rene.rahn AT fu-berlin.de>
 * \author <NAME> <j.winkler AT fu-berlin.de>
 */

#pragma once

#include <seqan3/core/platform.hpp>

namespace seqan3
{

/*!\brief Adds pipe interface to configuration elements.
 * \ingroup core_configuration
 *
 * \details
 *
 * An empty base class which is used by the algorithm configurations to be identified as a configuration element and
 * to compose an algorithm configuration using the pipe-operator.
 */
struct pipeable_config_element
{};

} // namespace seqan3


<|start_filename|>include/seqan3/core/debug_stream/tuple.hpp<|end_filename|>
// -----------------------------------------------------------------------------------------------------
// Copyright (c) 2006-2021, <NAME> & Freie Universität Berlin
// Copyright (c) 2016-2021, <NAME> & 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
 * \author <NAME> <hannes.hauswedell AT fu-berlin.de>
 * \brief Provides seqan3::debug_stream and related types.
 */

#pragma once

#include <seqan3/std/concepts>
#include <seqan3/std/ranges>

#include <seqan3/alphabet/concept.hpp>
#include <seqan3/core/debug_stream/debug_stream_type.hpp>
#include <seqan3/utility/tuple/concept.hpp>

namespace seqan3
{
/*!\name Formatted output overloads
 * \{
 */
} // namespace seqan3

namespace seqan3::detail
{

//!\brief Helper function to print elements of a tuple separately.
template <typename char_t, typename tuple_t, std::size_t ...I>
void print_tuple(debug_stream_type<char_t> & s, tuple_t && t, std::index_sequence<I...> const &)
{
    using std::get;
    s << '(';
    ((s << (I == 0 ? "" : ",") << get<I>(t)), ...);
    s << ')';
}

/*!\interface seqan3::detail::debug_streamable_tuple <>
 * \brief A helper concept to avoid ambiguous overloads with the debug stream operator for alignments.
 * \ingroup core_debug_stream
 * \tparam tuple_t The tuple type to print to the seqan3::detail::debug_stream_type.
 *
 * \details
 *
 * This concept requires that the given type is a seqan3::tuple_like type but neither an std::ranges::input_range nor
 * an alphabet (see seqan3::alphabet_tuple_base).
 */
//!\cond
template <typename tuple_t>
SEQAN3_CONCEPT debug_streamable_tuple = !std::ranges::input_range<tuple_t> &&
                                        !alphabet<tuple_t> &&  // exclude alphabet_tuple_base
                                        tuple_like<std::remove_cvref_t<tuple_t>>;
//!\endcond
} // namespace seqan3::detail

namespace seqan3
{

/*!\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.
 * \param t The tuple.
 * \relates seqan3::debug_stream_type
 */
template <typename char_t, typename tuple_t>
//!\cond
    requires (detail::debug_streamable_tuple<tuple_t>)
//!\endcond
inline debug_stream_type<char_t> & operator<<(debug_stream_type<char_t> & s, tuple_t && t)
{
    detail::print_tuple(s, std::forward<tuple_t>(t),
                        std::make_index_sequence<std::tuple_size_v<std::remove_cvref_t<tuple_t>>>{});
    return s;
}

//!\}

} // namespace seqan3
