SeqAn3  3.0.3
The Modern C++ library for sequence analysis.
slice.hpp
Go to the documentation of this file.
1 // -----------------------------------------------------------------------------------------------------
2 // Copyright (c) 2006-2020, Knut Reinert & Freie Universität Berlin
3 // Copyright (c) 2016-2020, Knut Reinert & MPI für molekulare Genetik
4 // This file may be used, modified and/or redistributed under the terms of the 3-clause BSD-License
5 // shipped with this file and also available at: https://github.com/seqan/seqan3/blob/master/LICENSE.md
6 // -----------------------------------------------------------------------------------------------------
7 
13 #pragma once
14 
15 #include <stdexcept>
16 
17 #include <seqan3/io/exception.hpp>
18 #include <seqan3/range/concept.hpp>
23 #include <seqan3/std/concepts>
24 #include <seqan3/std/iterator>
25 #include <seqan3/std/ranges>
26 #include <seqan3/std/span>
27 #include <seqan3/std/type_traits>
28 
29 namespace seqan3::detail
30 {
31 
32 // ============================================================================
33 // slice_fn (adaptor definition)
34 // ============================================================================
35 
37 struct slice_fn
38 {
40  constexpr auto operator()(ptrdiff_t begin_pos, ptrdiff_t end_pos) const noexcept
41  {
42  return detail::adaptor_from_functor{*this, begin_pos, end_pos};
43  }
44 
48  template <std::ranges::viewable_range urng_t>
49  constexpr auto operator()(urng_t && urange,
50  std::ranges::range_difference_t<urng_t> begin_pos,
51  std::ranges::range_difference_t<urng_t> end_pos) const
52  {
53  using position_t = std::ranges::range_difference_t<urng_t>;
54  if constexpr (std::ranges::sized_range<urng_t>)
55  {
56  position_t urange_size = static_cast<position_t>(std::ranges::size(urange));
57 
58  begin_pos = std::min(begin_pos, urange_size);
59  end_pos = std::min(end_pos, urange_size);
60  }
61  position_t target_size = end_pos - begin_pos;
62 
63  if (end_pos < begin_pos)
64  throw std::invalid_argument{"end_pos argument to seqan3::views::slice must be >= the begin_pos argument."};
65 
66  // SEQAN3_WORKAROUND_GCC_100139 == 1 if std::views::{take, drop} does not type reduce (e.g. keep in type
67  // std::basic_string_view, std::span, std::ranges::subrange).
68  // See https://github.com/seqan/seqan3/pull/2540/files#r617575294
69 #if SEQAN3_WORKAROUND_GCC_100139
70  // string_view
71  if constexpr (is_type_specialisation_of_v<std::remove_cvref_t<urng_t>, std::basic_string_view>)
72  {
73  return urange.substr(begin_pos, static_cast<size_t>(target_size));
74  }
75  // string const &
76  else if constexpr (is_type_specialisation_of_v<std::remove_cvref_t<urng_t>, std::basic_string> &&
78  {
79  return std::basic_string_view{std::ranges::data(urange) + begin_pos, static_cast<size_t>(target_size)};
80  }
81  // contiguous
82  else if constexpr (std::ranges::borrowed_range<urng_t> &&
83  std::ranges::contiguous_range<urng_t> &&
84  std::ranges::sized_range<urng_t>)
85  {
86  return std::span{std::ranges::data(urange) + begin_pos, static_cast<size_t>(target_size)};
87  }
88  // random_access
89  else if constexpr (std::ranges::borrowed_range<urng_t> &&
90  std::ranges::random_access_range<urng_t> &&
91  std::ranges::sized_range<urng_t>)
92  {
93  return std::ranges::subrange<std::ranges::iterator_t<urng_t>, std::ranges::iterator_t<urng_t>>
94  {
95  std::ranges::begin(urange) + begin_pos,
96  std::ranges::begin(urange) + end_pos,
97  static_cast<size_t>(target_size)
98  };
99  }
100  // std::views::drop
101  else
102  {
103  // urange | drop | take
104  return std::views::take(std::views::drop(std::forward<urng_t>(urange), begin_pos), target_size);
105  }
106 #else // ^^^ workaround / no workaround vvv
107  // urange | type_reduce | drop | take
108  return std::views::take(std::views::drop(seqan3::views::type_reduce(std::forward<urng_t>(urange)),
109  begin_pos),
110  target_size);
111 #endif // SEQAN3_WORKAROUND_GCC_100139
112  }
113 };
114 
115 } // namespace seqan3::detail
116 
117 // ============================================================================
118 // views::slice (adaptor instance definition)
119 // ============================================================================
120 
121 namespace seqan3::views
122 {
123 
191 inline constexpr auto slice = detail::slice_fn{};
192 
194 
195 } // namespace seqan3::views
T begin(T... args)
The Concepts library.
Provides seqan3::views::drop.
typename decltype(detail::split_after< i >(list_t{}))::first_type take
Return a seqan3::type_list of the first n types in the input type list.
Definition: traits.hpp:331
typename decltype(detail::split_after< i >(list_t{}))::second_type drop
Return a seqan3::type_list of the types in the input type list, except the first n.
Definition: traits.hpp:351
constexpr size_t size
The size of a type pack.
Definition: traits.hpp:150
constexpr auto slice
A view adaptor that returns a half-open interval on the underlying range.
Definition: slice.hpp:191
constexpr auto type_reduce
A view adaptor that behaves like std::views::all, but type erases certain ranges.
Definition: type_reduce.hpp:158
Provides exceptions used in the I/O module.
T is_const_v
Provides C++20 additions to the <iterator> header.
T min(T... args)
The SeqAn namespace for views.
Definition: char_to.hpp:22
Additional non-standard concepts for ranges.
Adaptations of concepts from the Ranges TS.
Provides std::span from the C++20 standard library.
Provides seqan3::views::take.
Provides seqan3::views::type_reduce.
Provides C++20 additions to the type_traits header.