SeqAn3  3.0.3
The Modern C++ library for sequence analysis.
search.hpp
Go to the documentation of this file.
1 // -----------------------------------------------------------------------------------------------------
2 // Copyright (c) 2006-2021, Knut Reinert & Freie Universität Berlin
3 // Copyright (c) 2016-2021, 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 <seqan3/std/algorithm>
16 #include <seqan3/std/ranges>
17 
30 
31 namespace seqan3::detail
32 {
36 struct search_configuration_validator
37 {
42  template <typename query_t>
43  static void validate_query_type()
44  {
45  using pure_query_t = std::remove_cvref_t<query_t>;
46  if constexpr(range_dimension_v<pure_query_t> == 1u)
47  {
48  static_assert(std::ranges::random_access_range<pure_query_t>,
49  "The query sequence must model random_access_range.");
50  static_assert(std::ranges::sized_range<pure_query_t>, "The query sequence must model sized_range.");
51  }
52  else
53  {
54  static_assert(std::ranges::forward_range<pure_query_t>, "The query collection must model forward_range.");
55  static_assert(std::ranges::sized_range<pure_query_t>, "The query collection must model sized_range.");
56  static_assert(std::ranges::random_access_range<std::ranges::range_value_t<pure_query_t>>,
57  "Elements of the query collection must model random_access_range.");
58  static_assert(std::ranges::sized_range<std::ranges::range_value_t<pure_query_t>>,
59  "Elements of the query collection must model sized_range.");
60  }
61  }
62 };
63 } // namespace seqan3::detail
64 
65 namespace seqan3
66 {
67 
101 template <typename index_t,
102  std::ranges::forward_range queries_t,
103  typename configuration_t = decltype(search_cfg::default_configuration)>
105  requires std::ranges::forward_range<std::ranges::range_reference_t<queries_t>> &&
106  std::same_as<range_innermost_value_t<queries_t>, typename index_t::alphabet_type>
108 inline auto search(queries_t && queries,
109  index_t const & index,
110  configuration_t const & cfg = search_cfg::default_configuration)
111 {
112  auto updated_cfg = detail::search_configurator::add_defaults(cfg);
113 
114  detail::search_configuration_validator::validate_query_type<queries_t>();
115 
116  size_t queries_size = std::ranges::distance(queries);
117  auto indexed_queries = views::zip(std::views::iota(size_t{0}, queries_size), queries);
118 
119  using indexed_queries_t = decltype(indexed_queries);
120 
121  using query_t = std::ranges::range_reference_t<indexed_queries_t>;
122  auto [algorithm, complete_config] = detail::search_configurator::configure_algorithm<query_t>(updated_cfg, index);
123 
124  using complete_configuration_t = decltype(complete_config);
125  using traits_t = detail::search_traits<complete_configuration_t>;
126  using algorithm_result_t = typename traits_t::search_result_type;
127  using execution_handler_t = std::conditional_t<
128  complete_configuration_t::template exists<search_cfg::parallel>(),
129  detail::execution_handler_parallel,
130  detail::execution_handler_sequential>;
131 
132  // Select the execution handler for the search configuration.
133  auto select_execution_handler = [&] ()
134  {
135  if constexpr (std::same_as<execution_handler_t, detail::execution_handler_parallel>)
136  {
137  auto thread_count = get<search_cfg::parallel>(complete_config).thread_count;
138  if (!thread_count)
139  throw std::runtime_error{"You must configure the number of threads in seqan3::search_cfg::parallel."};
140 
141  return execution_handler_t{*thread_count};
142  }
143  else
144  {
145  return execution_handler_t{};
146  }
147  };
148 
149  // Finally, choose between two way execution returning an algorithm range or calling a user callback on every hit.
150  if constexpr (traits_t::has_user_callback)
151  {
152  select_execution_handler().bulk_execute(algorithm,
153  indexed_queries,
154  get<search_cfg::on_result>(complete_config).callback);
155  }
156  else
157  {
158  using executor_t = detail::algorithm_executor_blocking<indexed_queries_t,
159  decltype(algorithm),
160  algorithm_result_t,
161  execution_handler_t>;
162 
163  return algorithm_result_generator_range{executor_t{std::move(indexed_queries),
164  std::move(algorithm),
165  algorithm_result_t{},
166  select_execution_handler()}};
167  }
168 }
169 
171 // Convert query sequence if it does not match the alphabet type of the index.
173 template <typename index_t,
174  std::ranges::forward_range queries_t,
175  typename configuration_t = decltype(search_cfg::default_configuration)>
176  requires std::ranges::forward_range<std::ranges::range_reference_t<queries_t>> &&
177  (!std::same_as<range_innermost_value_t<queries_t>, typename index_t::alphabet_type>)
178 inline auto search(queries_t && queries,
179  index_t const & index,
180  configuration_t const & cfg = search_cfg::default_configuration)
181 {
182  static_assert(std::convertible_to<range_innermost_value_t<queries_t>, typename index_t::alphabet_type>,
183  "The alphabet of the text collection must be convertible to the alphabet of the index.");
184 
185  if constexpr (range_dimension_v<queries_t> == 2u)
186  return search(queries | views::deep{views::convert<typename index_t::alphabet_type>}, index, cfg);
187  else
188  return search(queries | views::convert<typename index_t::alphabet_type>, index, cfg);
189 }
190 
191 // Overload for a single query (not a collection of queries)
193 template <typename index_t,
194  std::ranges::forward_range query_t,
195  typename configuration_t = decltype(search_cfg::default_configuration)>
196 inline auto search(query_t && query,
197  index_t const & index,
198  configuration_t const & cfg = search_cfg::default_configuration)
199 {
200  return search(std::views::single(std::forward<query_t>(query)), index, cfg);
201 }
202 
204 template <typename index_t, typename configuration_t = decltype(search_cfg::default_configuration)>
205 inline auto search(char const * const queries,
206  index_t const & index,
207  configuration_t const & cfg = search_cfg::default_configuration)
208 {
209  return search(std::string_view{queries}, index, cfg);
210 }
211 
213 template <typename index_t, typename configuration_t = decltype(search_cfg::default_configuration)>
214 inline auto search(std::initializer_list<char const * const> const & queries,
215  index_t const & index,
216  configuration_t const & cfg = search_cfg::default_configuration)
217 {
219  query.reserve(std::ranges::size(queries));
220  std::ranges::for_each(queries, [&query] (char const * const q) { query.push_back(std::string_view{q}); });
221  return search(std::move(query) | detail::persist, index, cfg);
222 }
224 
226 
227 } // namespace seqan3
Provides seqan3::detail::algorithm_executor_blocking.
Provides seqan3::detail::algorithm_result_generator_range.
Adaptations of algorithms from the Ranges TS.
An input range over the algorithm results generated by the underlying algorithm executor.
Definition: algorithm_result_generator_range.hpp:44
Provides seqan3::configuration and utility functions.
Provides the default configuration for the seqan3::search() interface.
const configuration default_configuration
The default configuration: Compute all exact matches.
Definition: default_configuration.hpp:32
auto search(queries_t &&queries, index_t const &index, configuration_t const &cfg=search_cfg::default_configuration)
Search a query or a range of queries in an index.
Definition: search.hpp:108
@ single
The text is a single range.
Definition: concept.hpp:83
constexpr size_t size
The size of a type pack.
Definition: traits.hpp:151
constexpr auto zip
A zip view.
Definition: zip.hpp:29
auto const move
A view that turns lvalue-references into rvalue-references.
Definition: move.hpp:74
The main SeqAn3 namespace.
Definition: aligned_sequence_concept.hpp:29
Provides seqan3::search_cfg::on_result.
Provides seqan3::search_cfg::parallel configuration.
Provides seqan3::detail::persist.
T push_back(T... args)
Adaptations of concepts from the Ranges TS.
T reserve(T... args)
Provides seqan3::detail::search_configurator.
Provides seqan3::detail::search_traits.
Provides seqan3::views::convert.
Provides seqan3::views::deep.
Provides seqan3::views::zip.