SeqAn3  3.2.0
The Modern C++ library for sequence analysis.
configuration.hpp
Go to the documentation of this file.
1 // -----------------------------------------------------------------------------------------------------
2 // Copyright (c) 2006-2022, Knut Reinert & Freie Universität Berlin
3 // Copyright (c) 2016-2022, 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 <concepts>
16 
23 
24 namespace seqan3
25 {
26 
27 // ----------------------------------------------------------------------------
28 // configuration
29 // ----------------------------------------------------------------------------
30 
43 template <detail::config_element... configs_t>
44 class configuration : public std::tuple<configs_t...>
45 {
47  template <detail::config_element... _configs_t>
48  friend class configuration;
49 
50 public:
53  using base_type = std::tuple<configs_t...>;
54 
56 
59  constexpr configuration() = default;
60  constexpr configuration(configuration const &) = default;
61  constexpr configuration(configuration &&) = default;
62  constexpr configuration & operator=(configuration const &) = default;
63  constexpr configuration & operator=(configuration &&) = default;
64  ~configuration() = default;
65 
71  template <typename config_element_t>
72  requires (!std::same_as<std::remove_cvref_t<config_element_t>, configuration>)
73  && detail::config_element<std::remove_cvref_t<config_element_t>>
74  constexpr configuration(config_element_t && config_element) :
75  base_type{std::forward<config_element_t>(config_element)}
76  {}
78 
84  constexpr size_t size() const noexcept
85  {
86  return std::tuple_size_v<base_type>;
87  }
88 
119  template <typename alternative_t>
120  constexpr decltype(auto) get_or(alternative_t && alternative) & noexcept
121  {
122  return get_or_impl(*this, alternative, std::forward<alternative_t>(alternative));
123  }
124 
126  template <typename alternative_t>
127  constexpr decltype(auto) get_or(alternative_t && alternative) const & noexcept
128  {
129  return get_or_impl(*this, alternative, std::forward<alternative_t>(alternative));
130  }
131 
133  template <typename alternative_t>
134  constexpr decltype(auto) get_or(alternative_t && alternative) && noexcept
135  {
136  return get_or_impl(std::move(*this), alternative, std::forward<alternative_t>(alternative));
137  }
138 
140  template <typename alternative_t>
141  constexpr decltype(auto) get_or(alternative_t && alternative) const && noexcept
142  {
143  return get_or_impl(std::move(*this), alternative, std::forward<alternative_t>(alternative));
144  }
145 
147  template <typename query_t>
148  static constexpr bool exists() noexcept
149  {
150  return pack_traits::contains<query_t, configs_t...>;
151  }
153  template <template <typename...> typename query_t>
154  static constexpr bool exists() noexcept
155  {
156  return (pack_traits::find_if<detail::is_same_configuration_f<query_t>::template invoke, configs_t...> > -1);
157  }
159 
179  template <typename other_configuration_t>
180  requires (is_config_element_combineable_v<configs_t, std::remove_cvref_t<other_configuration_t>> && ...)
181  constexpr auto append(other_configuration_t && other_config) const
182  {
183  if constexpr (detail::config_element<std::remove_cvref_t<other_configuration_t>>)
184  {
185  return configuration<configs_t..., std::remove_cvref_t<other_configuration_t>>{
186  std::tuple_cat(static_cast<base_type>(*this),
187  std::tuple{std::forward<other_configuration_t>(other_config)})};
188  }
189  else
190  {
191  // The following type aliases are needed to extract the correct reference and const qualifiers for the
192  // given `other_configuration_t` type (input parameter).
193  // Note the alternative would be to repeat multiple interfaces with `other_config_t &`,
194  // `other_config_t const &`, `other_config_t &&` and `other_config_t const &&`.
195 
196  // Get the actual base tuple type from the other configuration.
197  using other_base_t = typename std::remove_cvref_t<other_configuration_t>::base_type;
198 
199  // The other base tuple type matching the reference type and the const qualifier of the input parameter.
200  using other_base_same_modifier_t =
201  detail::transfer_type_modifier_onto_t<other_configuration_t, other_base_t>;
202 
203  // Form a new seqan3::configuration type with the concatenated configuration element types of this and the
204  // other configuration.
205  using other_configs_list_t = detail::transfer_template_args_onto_t<other_base_t, type_list>;
206  using appended_configuration_t = detail::transfer_template_args_onto_t<
207  list_traits::concat<type_list<configs_t...>, other_configs_list_t>,
208  configuration>;
209 
210  // Concatenate the two configurations using their base tuple types.
211  return appended_configuration_t{
212  std::tuple_cat(static_cast<base_type>(*this), std::forward<other_base_same_modifier_t>(other_config))};
213  }
214  }
215 
220  template <typename query_t>
221  [[nodiscard]] constexpr auto remove() const
222  requires (exists<query_t>())
223  {
224  constexpr int index = pack_traits::find<query_t, configs_t...>;
225  return remove_at<index>();
226  }
227 
229  template <template <typename...> typename query_t>
230  [[nodiscard]] constexpr auto remove() const
231  requires (exists<query_t>())
232  {
233  constexpr int index =
234  pack_traits::find_if<detail::is_same_configuration_f<query_t>::template invoke, configs_t...>;
235  return remove_at<index>();
236  }
238 
239 private:
244  template <typename... _configs_t>
245  explicit constexpr configuration(std::tuple<_configs_t...> const & cfg) : base_type{cfg}
246  {}
247 
249  template <typename... _configs_t>
250  explicit constexpr configuration(std::tuple<_configs_t...> && cfg) : base_type{std::move(cfg)}
251  {}
253 
263  template <int index>
264  [[nodiscard]] constexpr auto remove_at() const
265  {
266  static_assert((index >= 0) && (index < sizeof...(configs_t)), "Index to remove from config is out of bounds.");
267 
268  auto [head, middle] = tuple_split<index>(static_cast<base_type>(*this));
269  auto tail = tuple_pop_front(middle);
270 
271  using head_list_t = detail::transfer_template_args_onto_t<decltype(head), type_list>;
272  using tail_list_t = detail::transfer_template_args_onto_t<decltype(tail), type_list>;
273  using concat_list_t = list_traits::concat<head_list_t, tail_list_t>;
274  using new_configuration_t = detail::transfer_template_args_onto_t<concat_list_t, configuration>;
275 
276  return new_configuration_t{std::tuple_cat(std::move(head), std::move(tail))};
277  }
279 
297  template <typename this_t, typename query_t, typename alternative_t>
298  static constexpr decltype(auto)
299  get_or_impl(this_t && me, query_t const & SEQAN3_DOXYGEN_ONLY(query), alternative_t && alternative) noexcept
300  {
301  if constexpr (exists<query_t>())
302  {
303  return get<query_t>(std::forward<this_t>(me));
304  }
305  else
306  {
307  using ret_type = remove_rvalue_reference_t<decltype(alternative)>;
308  return static_cast<ret_type>(alternative);
309  }
310  }
311 
313  template <typename this_t,
314  template <typename...>
315  typename query_template_t,
316  typename... parameters_t,
317  typename alternative_t>
318  static constexpr decltype(auto)
319  get_or_impl(this_t && me, query_template_t<parameters_t...> const &, alternative_t && alternative) noexcept
320  {
321  if constexpr (exists<query_template_t>())
322  {
323  return get<query_template_t>(std::forward<this_t>(me));
324  }
325  else
326  {
327  using ret_type = remove_rvalue_reference_t<decltype(alternative)>;
328  return static_cast<ret_type>(alternative);
329  }
330  }
331 };
332 
340 template <detail::config_element config_t>
343 
363 template <typename lhs_config_t, typename rhs_config_t>
364  requires (is_config_element_combineable_v<std::remove_cvref_t<lhs_config_t>, std::remove_cvref_t<rhs_config_t>>)
365 constexpr auto operator|(lhs_config_t && lhs, rhs_config_t && rhs)
366 {
367  if constexpr (detail::config_element<std::remove_cvref_t<lhs_config_t>>)
368  return configuration{std::forward<lhs_config_t>(lhs)}.append(std::forward<rhs_config_t>(rhs));
369  else
370  return std::forward<lhs_config_t>(lhs).append(std::forward<rhs_config_t>(rhs));
371 }
372 
404 template <template <typename...> class query_t, typename... configs_t>
405 constexpr auto & get(configuration<configs_t...> & config) noexcept
406 {
407  constexpr auto pos = pack_traits::find_if<detail::is_same_configuration_f<query_t>::template invoke, configs_t...>;
408  static_assert(pos > -1, "Access error: The requested type is not contained.");
409 
410  return get<pos>(config);
411 }
412 
414 template <template <typename...> class query_t, typename... configs_t>
415 constexpr auto const & get(configuration<configs_t...> const & config) noexcept
416 {
417  constexpr auto pos = pack_traits::find_if<detail::is_same_configuration_f<query_t>::template invoke, configs_t...>;
418  static_assert(pos > -1, "Access error: The requested type is not contained.");
419 
420  return get<pos>(config);
421 }
422 
424 template <template <typename...> class query_t, typename... configs_t>
425 constexpr auto && get(configuration<configs_t...> && config) noexcept
426 {
427  constexpr auto pos = pack_traits::find_if<detail::is_same_configuration_f<query_t>::template invoke, configs_t...>;
428  static_assert(pos > -1, "Access error: The requested type is not contained.");
429 
430  return get<pos>(std::move(config));
431 }
432 
434 template <template <typename...> class query_t, typename... configs_t>
435 constexpr auto const && get(configuration<configs_t...> const && config) noexcept
436 {
437  constexpr auto pos = pack_traits::find_if<detail::is_same_configuration_f<query_t>::template invoke, configs_t...>;
438  static_assert(pos > -1, "Access error: The requested type is not contained.");
439 
440  return get<pos>(std::move(config));
441 }
443 
444 } // namespace seqan3
445 
446 namespace std
447 {
449 
455 template <seqan3::detail::config_element... configs_t>
456 struct tuple_size<seqan3::configuration<configs_t...>>
457 {
459  static constexpr size_t value = std::tuple_size_v<typename seqan3::configuration<configs_t...>::base_type>;
460 };
461 
467 template <size_t pos, seqan3::detail::config_element... configs_t>
468 struct tuple_element<pos, seqan3::configuration<configs_t...>>
469 {
471  using type = std::tuple_element_t<pos, typename seqan3::configuration<configs_t...>::base_type>;
472 };
474 } //namespace std
Collection of elements to configure an algorithm.
Definition: configuration.hpp:45
requires(!std::same_as< std::remove_cvref_t< config_element_t >, configuration >) &&detail
Constructs a configuration from a single configuration element.
Definition: configuration.hpp:72
constexpr size_t size() const noexcept
Returns the number of contained config elements.
Definition: configuration.hpp:83
requires(is_config_element_combineable_v< std::remove_cvref_t< lhs_config_t >, std::remove_cvref_t< rhs_config_t >>) const expr auto operator|(lhs_config_t &&lhs
Combines two configurations and/or configuration elements forming a new seqan3::configuration.
configuration(config_t) -> configuration< config_t >
Deduces the correct configuration element type from the passed seqan3::pipeable_config_element.
constexpr configuration(configuration &&)=default
Defaulted.
constexpr configuration & operator=(configuration const &)=default
Defaulted.
constexpr decltype(auto) get_or(alternative_t &&alternative) &noexcept
Returns the stored configuration element if present otherwise the given alternative.
Definition: configuration.hpp:119
~configuration()=default
Defaulted.
constexpr auto remove() const requires(exists< query_t >())
Remove a config element from the configuration.
Definition: configuration.hpp:220
constexpr configuration & operator=(configuration &&)=default
Defaulted.
constexpr configuration(configuration const &)=default
Defaulted.
constexpr configuration()=default
Defaulted.
static constexpr bool exists() noexcept
Checks if the given type exists in the tuple.
Definition: configuration.hpp:147
friend class configuration
Friend declaration for other instances of the configuration.
Definition: configuration.hpp:48
The <concepts> header from C++20's standard library.
Provides various auxiliary functions with which parts of the configurations can be checked.
Provides concepts for the configuration classes.
constexpr bool is_config_element_combineable_v
Helper variable template to test if a configuration element is combineable with another configuration...
Definition: core/configuration/detail/concept.hpp:212
constexpr auto & get(configuration< configs_t... > &config) noexcept
Returns the stored element.
Definition: configuration.hpp:405
constexpr auto tuple_pop_front(tuple_t &&t)
Removes the first element of a tuple.
Definition: pop_front.hpp:42
constexpr ptrdiff_t find
Get the index of the first occurrence of a type in a pack.
Definition: type_pack/traits.hpp:182
constexpr ptrdiff_t find_if
Get the index of the first type in a pack that satisfies the given predicate.
Definition: type_pack/traits.hpp:205
constexpr bool contains
Whether a type occurs in a pack or not.
Definition: type_pack/traits.hpp:223
The main SeqAn3 namespace.
Definition: aligned_sequence_concept.hpp:29
constexpr auto const & get(configuration< configs_t... > const &config) noexcept
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition: configuration.hpp:415
SeqAn specific customisations in the standard namespace.
Provides seqan3::tuple_pop_front.
Type that contains multiple types.
Definition: type_list.hpp:29
Provides type traits for working with templates.
Provides type traits seqan3::detail::transfer_type_modifier_onto.
T tuple_cat(T... args)
T tuple_size_v
Provides seqan3::type_list.