SeqAn3  3.1.0-rc.1
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  {
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.
212  using appended_configuration_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>;
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 configuration(std::tuple< _configs_t... > const &cfg)
Constructs from std::tuple.
Definition: configuration.hpp:257
constexpr configuration(std::tuple< _configs_t... > &&cfg)
Constructs from std::tuple.
Definition: configuration.hpp:262
constexpr auto remove_at() const
Remove a config element from the configuration.
Definition: configuration.hpp:276
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.
static constexpr decltype(auto) get_or_impl(this_t &&me, query_t const &query, alternative_t &&alternative) noexcept
Internal implementation of the get_or interace.
Definition: configuration.hpp:310
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
The Concepts 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: concept.hpp:212
constexpr auto & get(configuration< configs_t... > &config) noexcept
Returns the stored element.
Definition: configuration.hpp:419
typename transfer_template_args_onto< source_type, target_template >::type transfer_template_args_onto_t
Shortcut for seqan3::detail::transfer_template_args_onto (transformation_trait shortcut).
Definition: template_inspection.hpp:77
constexpr auto tuple_pop_front(tuple_t &&t)
Removes the first element of a tuple.
Definition: pop_front.hpp:42
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
Concept for an algorithm configuration element.
Subconcept definition for seqan3::tuple_like to test for std::tuple_size-interface.
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.
Helper meta function to check if a template type is contained in a seqan3::configuration.
Definition: configuration_utility.hpp:33
Type that contains multiple types.
Definition: type_list.hpp:29
std::tuple_element_t< pos, typename seqan3::configuration< configs_t... >::base_type > type
The type of the config at position pos
Definition: configuration.hpp:487
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.