SeqAn3  3.0.3
The Modern C++ library for sequence analysis.
configuration.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/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>
73  requires (!std::same_as<std::remove_cvref_t<config_element_t>, configuration>) &&
74  detail::config_element<std::remove_cvref_t<config_element_t>>
76  constexpr configuration(config_element_t && config_element) :
77  base_type{std::forward<config_element_t>(config_element)}
78  {}
80 
86  constexpr size_t size() const noexcept
87  {
88  return std::tuple_size_v<base_type>;
89  }
90 
121  template <typename alternative_t>
122  constexpr decltype(auto) get_or(alternative_t && alternative) & noexcept
123  {
124  return get_or_impl(*this, alternative, std::forward<alternative_t>(alternative));
125  }
126 
128  template <typename alternative_t>
129  constexpr decltype(auto) get_or(alternative_t && alternative) const & noexcept
130  {
131  return get_or_impl(*this, alternative, std::forward<alternative_t>(alternative));
132  }
133 
135  template <typename alternative_t>
136  constexpr decltype(auto) get_or(alternative_t && alternative) && noexcept
137  {
138  return get_or_impl(std::move(*this), alternative, std::forward<alternative_t>(alternative));
139  }
140 
142  template <typename alternative_t>
143  constexpr decltype(auto) get_or(alternative_t && alternative) const && noexcept
144  {
145  return get_or_impl(std::move(*this), alternative, std::forward<alternative_t>(alternative));
146  }
147 
149  template <typename query_t>
150  static constexpr bool exists() noexcept
151  {
152  return pack_traits::contains<query_t, configs_t...>;
153  }
155  template <template <typename ...> typename query_t>
156  static constexpr bool exists() noexcept
157  {
158  return (pack_traits::find_if<detail::is_same_configuration_f<query_t>::template invoke, configs_t...> > -1);
159  }
161 
181  template <typename other_configuration_t>
185  constexpr auto append(other_configuration_t && other_config) const
186  {
187  if constexpr (detail::config_element<std::remove_cvref_t<other_configuration_t>>)
188  {
190  {
191  std::tuple_cat(static_cast<base_type>(*this),
192  std::tuple{std::forward<other_configuration_t>(other_config)})
193  };
194  }
195  else
196  {
197  // The following type aliases are needed to extract the correct reference and const qualifiers for the
198  // given `other_configuration_t` type (input parameter).
199  // Note the alternative would be to repeat multiple interfaces with `other_config_t &`,
200  // `other_config_t const &`, `other_config_t &&` and `other_config_t const &&`.
201 
202  // Get the actual base tuple type from the other configuration.
203  using other_base_t = typename std::remove_cvref_t<other_configuration_t>::base_type;
204 
205  // The other base tuple type matching the reference type and the const qualifier of the input parameter.
206  using other_base_same_modifier_t = detail::transfer_type_modifier_onto_t<other_configuration_t,
207  other_base_t>;
208 
209  // Form a new seqan3::configuration type with the concatenated configuration element types of this and the
210  // other configuration.
211  using other_configs_list_t = detail::transfer_template_args_onto_t<other_base_t, type_list>;
212  using appended_configuration_t =
213  detail::transfer_template_args_onto_t<list_traits::concat<type_list<configs_t...>,
214  other_configs_list_t>,
215  configuration>;
216 
217  // Concatenate the two configurations using their base tuple types.
218  return appended_configuration_t{std::tuple_cat(static_cast<base_type>(*this),
219  std::forward<other_base_same_modifier_t>(other_config))};
220  }
221  }
222 
227  template <typename query_t>
228  [[nodiscard]] constexpr auto remove() const
230  requires (exists<query_t>())
232  {
233  constexpr int index = pack_traits::find<query_t, configs_t...>;
234  return remove_at<index>();
235  }
236 
238  template <template <typename ...> typename query_t>
239  [[nodiscard]] constexpr auto remove() const
241  requires (exists<query_t>())
243  {
244  constexpr int index = pack_traits::find_if<detail::is_same_configuration_f<query_t>::template invoke,
245  configs_t...>;
246  return remove_at<index>();
247  }
249 
250 private:
251 
256  template <typename ..._configs_t>
257  explicit constexpr configuration(std::tuple<_configs_t...> const & cfg) : base_type{cfg}
258  {}
259 
261  template <typename ..._configs_t>
262  explicit constexpr configuration(std::tuple<_configs_t...> && cfg) : base_type{std::move(cfg)}
263  {}
265 
275  template <int index>
276  [[nodiscard]] constexpr auto remove_at() const
277  {
278  static_assert((index >= 0) && (index < sizeof...(configs_t)), "Index to remove from config is out of bounds.");
279 
280  auto [head, middle] = tuple_split<index>(static_cast<base_type>(*this));
281  auto tail = tuple_pop_front(middle);
282 
283  using head_list_t = detail::transfer_template_args_onto_t<decltype(head), type_list>;
284  using tail_list_t = detail::transfer_template_args_onto_t<decltype(tail), type_list>;
285  using concat_list_t = list_traits::concat<head_list_t, tail_list_t>;
286  using new_configuration_t = detail::transfer_template_args_onto_t<concat_list_t, configuration>;
287 
288  return new_configuration_t{std::tuple_cat(std::move(head), std::move(tail))};
289  }
291 
309  template <typename this_t, typename query_t, typename alternative_t>
310  static constexpr decltype(auto) get_or_impl(this_t && me,
311  query_t const & SEQAN3_DOXYGEN_ONLY(query),
312  alternative_t && alternative) noexcept
313  {
314  if constexpr (exists<query_t>())
315  {
316  return get<query_t>(std::forward<this_t>(me));
317  }
318  else
319  {
320  using ret_type = remove_rvalue_reference_t<decltype(alternative)>;
321  return static_cast<ret_type>(alternative);
322  }
323  }
324 
326  template <typename this_t,
327  template <typename ...> typename query_template_t, typename ...parameters_t,
328  typename alternative_t>
329  static constexpr decltype(auto) get_or_impl(this_t && me,
330  query_template_t<parameters_t...> const &,
331  alternative_t && alternative) noexcept
332  {
333  if constexpr (exists<query_template_t>())
334  {
335  return get<query_template_t>(std::forward<this_t>(me));
336  }
337  else
338  {
339  using ret_type = remove_rvalue_reference_t<decltype(alternative)>;
340  return static_cast<ret_type>(alternative);
341  }
342  }
343 };
344 
352 template <detail::config_element config_t>
355 
375 template <typename lhs_config_t, typename rhs_config_t>
379 constexpr auto operator|(lhs_config_t && lhs, rhs_config_t && rhs)
380 {
381  if constexpr (detail::config_element<std::remove_cvref_t<lhs_config_t>>)
382  return configuration{std::forward<lhs_config_t>(lhs)}.append(std::forward<rhs_config_t>(rhs));
383  else
384  return std::forward<lhs_config_t>(lhs).append(std::forward<rhs_config_t>(rhs));
385 }
386 
418 template <template <typename ...> class query_t, typename ...configs_t>
419 constexpr auto & get(configuration<configs_t...> & config) noexcept
420 {
421  constexpr auto pos = pack_traits::find_if<detail::is_same_configuration_f<query_t>::template invoke, configs_t...>;
422  static_assert(pos > -1, "Access error: The requested type is not contained.");
423 
424  return get<pos>(config);
425 }
426 
428 template <template <typename ...> class query_t, typename ...configs_t>
429 constexpr auto const & get(configuration<configs_t...> const & config) noexcept
430 {
431  constexpr auto pos = pack_traits::find_if<detail::is_same_configuration_f<query_t>::template invoke, configs_t...>;
432  static_assert(pos > -1, "Access error: The requested type is not contained.");
433 
434  return get<pos>(config);
435 }
436 
438 template <template <typename ...> class query_t, typename ...configs_t>
439 constexpr auto && get(configuration<configs_t...> && config) noexcept
440 {
441  constexpr auto pos = pack_traits::find_if<detail::is_same_configuration_f<query_t>::template invoke, configs_t...>;
442  static_assert(pos > -1, "Access error: The requested type is not contained.");
443 
444  return get<pos>(std::move(config));
445 }
446 
448 template <template <typename ...> class query_t, typename ...configs_t>
449 constexpr auto const && get(configuration<configs_t...> const && config) noexcept
450 {
451  constexpr auto pos = pack_traits::find_if<detail::is_same_configuration_f<query_t>::template invoke, configs_t...>;
452  static_assert(pos > -1, "Access error: The requested type is not contained.");
453 
454  // TODO: change after GCC-7 bug with const && version of get in std::tuple is fixed.
455  // return get<pos>(std::move(config));
456  return std::move(get<pos>(config));
457 }
459 
460 } // namespace seqan3::detail
461 
462 namespace std
463 {
465 
471 template <seqan3::detail::config_element ... configs_t>
472 struct tuple_size<seqan3::configuration<configs_t...>>
473 {
475  static constexpr size_t value = std::tuple_size_v<typename seqan3::configuration<configs_t...>::base_type>;
476 };
477 
483 template <size_t pos, seqan3::detail::config_element ... configs_t>
484 struct tuple_element<pos, seqan3::configuration<configs_t...>>
485 {
487  using type = std::tuple_element_t<pos, typename seqan3::configuration<configs_t...>::base_type>;
488 };
490 } //namespace std
Collection of elements to configure an algorithm.
Definition: configuration.hpp:45
constexpr auto append(other_configuration_t &&other_config) const
Returns a new configuration by appending the given configuration to the current one.
Definition: configuration.hpp:185
constexpr size_t size() const noexcept
Returns the number of contained config elements.
Definition: configuration.hpp:86
constexpr auto remove() const
Remove a config element from the configuration.
Definition: configuration.hpp:228
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:122
~configuration()=default
Defaulted.
constexpr configuration(config_element_t &&config_element)
Constructs a configuration from a single configuration element.
Definition: configuration.hpp:76
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:150
friend class configuration
Friend declaration for other instances of the configuration.
Definition: configuration.hpp:48
The Concepts library.
Provides various auxiliary functions with which parts of the configurations can be checked.
Provides concepts for the configuration classes.
Provides type traits for working with templates.
constexpr bool is_config_element_combineable_v
Helper variable template to test if a configuration element is combineable with another configuration...
Definition: concept.hpp:212
constexpr auto & get(configuration< configs_t... > &config) noexcept
Returns the stored element.
Definition: configuration.hpp:419
decltype(detail::concat(lists_t{}...)) concat
Join two seqan3::type_list s into one.
Definition: traits.hpp:329
constexpr ptrdiff_t find
Get the index of the first occurrence of a type in a pack.
Definition: traits.hpp:187
constexpr ptrdiff_t find_if
Get the index of the first type in a pack that satisfies the given predicate.
Definition: traits.hpp:210
constexpr bool contains
Whether a type occurs in a pack or not.
Definition: traits.hpp:228
typename remove_rvalue_reference< t >::type remove_rvalue_reference_t
Return the input type with && removed, but lvalue references preserved (transformation_trait shortcut...
Definition: basic.hpp:69
constexpr auto tuple_pop_front(tuple_t &&t)
Removes the first element of a tuple.
Definition: pop_front.hpp:42
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
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:429
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 seqan3::detail::transfer_type_modifier_onto.
T tuple_cat(T... args)
T tuple_size_v
Provides seqan3::type_list.