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-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 <seqan3/std/concepts>
16 
24 
25 namespace seqan3
26 {
27 
28 // ----------------------------------------------------------------------------
29 // configuration
30 // ----------------------------------------------------------------------------
31 
44 template <detail::config_element ... configs_t>
45 class configuration : public std::tuple<configs_t...>
46 {
48  template <detail::config_element ... _configs_t>
49  friend class configuration;
50 
51 public:
54  using base_type = std::tuple<configs_t...>;
55 
57 
60  constexpr configuration() = default;
61  constexpr configuration(configuration const &) = default;
62  constexpr configuration(configuration &&) = default;
63  constexpr configuration & operator=(configuration const &) = default;
64  constexpr configuration & operator=(configuration &&) = default;
65  ~configuration() = default;
66 
72  template <typename config_element_t>
74  requires (!std::same_as<std::remove_cvref_t<config_element_t>, configuration>) &&
75  detail::config_element<std::remove_cvref_t<config_element_t>>
77  constexpr configuration(config_element_t && config_element) :
78  base_type{std::forward<config_element_t>(config_element)}
79  {}
81 
87  constexpr size_t size() const noexcept
88  {
89  return std::tuple_size_v<base_type>;
90  }
91 
122  template <typename alternative_t>
123  constexpr decltype(auto) get_or(alternative_t && alternative) & noexcept
124  {
125  return get_or_impl(*this, alternative, std::forward<alternative_t>(alternative));
126  }
127 
129  template <typename alternative_t>
130  constexpr decltype(auto) get_or(alternative_t && alternative) const & noexcept
131  {
132  return get_or_impl(*this, alternative, std::forward<alternative_t>(alternative));
133  }
134 
136  template <typename alternative_t>
137  constexpr decltype(auto) get_or(alternative_t && alternative) && noexcept
138  {
139  return get_or_impl(std::move(*this), alternative, std::forward<alternative_t>(alternative));
140  }
141 
143  template <typename alternative_t>
144  constexpr decltype(auto) get_or(alternative_t && alternative) const && noexcept
145  {
146  return get_or_impl(std::move(*this), alternative, std::forward<alternative_t>(alternative));
147  }
148 
150  template <typename query_t>
151  static constexpr bool exists() noexcept
152  {
153  return pack_traits::contains<query_t, configs_t...>;
154  }
156  template <template <typename ...> typename query_t>
157  static constexpr bool exists() noexcept
158  {
159  return (pack_traits::find_if<detail::is_same_configuration_f<query_t>::template invoke, configs_t...> > -1);
160  }
162 
182  template <typename other_configuration_t>
186  constexpr auto append(other_configuration_t && other_config) const
187  {
188  if constexpr (detail::config_element<std::remove_cvref_t<other_configuration_t>>)
189  {
191  {
192  std::tuple_cat(static_cast<base_type>(*this),
193  std::tuple{std::forward<other_configuration_t>(other_config)})
194  };
195  }
196  else
197  {
198  // The following type aliases are needed to extract the correct reference and const qualifiers for the
199  // given `other_configuration_t` type (input parameter).
200  // Note the alternative would be to repeat multiple interfaces with `other_config_t &`,
201  // `other_config_t const &`, `other_config_t &&` and `other_config_t const &&`.
202 
203  // Get the actual base tuple type from the other configuration.
204  using other_base_t = typename std::remove_cvref_t<other_configuration_t>::base_type;
205 
206  // The other base tuple type matching the reference type and the const qualifier of the input parameter.
207  using other_base_same_modifier_t = detail::transfer_type_modifier_onto_t<other_configuration_t,
208  other_base_t>;
209 
210  // Form a new seqan3::configuration type with the concatenated configuration element types of this and the
211  // other configuration.
212  using other_configs_list_t = detail::transfer_template_args_onto_t<other_base_t, type_list>;
213  using appended_configuration_t =
214  detail::transfer_template_args_onto_t<list_traits::concat<type_list<configs_t...>,
215  other_configs_list_t>,
216  configuration>;
217 
218  // Concatenate the two configurations using their base tuple types.
219  return appended_configuration_t{std::tuple_cat(static_cast<base_type>(*this),
220  std::forward<other_base_same_modifier_t>(other_config))};
221  }
222  }
223 
228  template <typename query_t>
229  [[nodiscard]] constexpr auto remove() const
231 #if !SEQAN3_WORKAROUND_GCC_95371
232  requires (exists<query_t>())
233 #endif // !SEQAN3_WORKAROUND_GCC_95371
235  {
236  constexpr int index = pack_traits::find<query_t, configs_t...>;
237  return remove_at<index>();
238  }
239 
241  template <template <typename ...> typename query_t>
242  [[nodiscard]] constexpr auto remove() const
244 #if !SEQAN3_WORKAROUND_GCC_95371
245  requires (exists<query_t>())
246 #endif // !SEQAN3_WORKAROUND_GCC_95371
248  {
249  constexpr int index = pack_traits::find_if<detail::is_same_configuration_f<query_t>::template invoke,
250  configs_t...>;
251  return remove_at<index>();
252  }
254 
255 private:
256 
261  template <typename ..._configs_t>
262  explicit constexpr configuration(std::tuple<_configs_t...> const & cfg) : base_type{cfg}
263  {}
264 
266  template <typename ..._configs_t>
267  explicit constexpr configuration(std::tuple<_configs_t...> && cfg) : base_type{std::move(cfg)}
268  {}
270 
280  template <int index>
281  [[nodiscard]] constexpr auto remove_at() const
282  {
283  static_assert((index >= 0) && (index < sizeof...(configs_t)), "Index to remove from config is out of bounds.");
284 
285  auto [head, middle] = tuple_split<index>(static_cast<base_type>(*this));
286  auto tail = tuple_pop_front(middle);
287 
288  using head_list_t = detail::transfer_template_args_onto_t<decltype(head), type_list>;
289  using tail_list_t = detail::transfer_template_args_onto_t<decltype(tail), type_list>;
290  using concat_list_t = list_traits::concat<head_list_t, tail_list_t>;
291  using new_configuration_t = detail::transfer_template_args_onto_t<concat_list_t, configuration>;
292 
293  return new_configuration_t{std::tuple_cat(std::move(head), std::move(tail))};
294  }
296 
314  template <typename this_t, typename query_t, typename alternative_t>
315  static constexpr decltype(auto) get_or_impl(this_t && me,
316  query_t const & SEQAN3_DOXYGEN_ONLY(query),
317  alternative_t && alternative) noexcept
318  {
319  if constexpr (exists<query_t>())
320  {
321  return get<query_t>(std::forward<this_t>(me));
322  }
323  else
324  {
325  using ret_type = remove_rvalue_reference_t<decltype(alternative)>;
326  return static_cast<ret_type>(alternative);
327  }
328  }
329 
331  template <typename this_t,
332  template <typename ...> typename query_template_t, typename ...parameters_t,
333  typename alternative_t>
334  static constexpr decltype(auto) get_or_impl(this_t && me,
335  query_template_t<parameters_t...> const &,
336  alternative_t && alternative) noexcept
337  {
338  if constexpr (exists<query_template_t>())
339  {
340  return get<query_template_t>(std::forward<this_t>(me));
341  }
342  else
343  {
344  using ret_type = remove_rvalue_reference_t<decltype(alternative)>;
345  return static_cast<ret_type>(alternative);
346  }
347  }
348 };
349 
357 template <detail::config_element config_t>
360 
380 template <typename lhs_config_t, typename rhs_config_t>
384 constexpr auto operator|(lhs_config_t && lhs, rhs_config_t && rhs)
385 {
386  if constexpr (detail::config_element<std::remove_cvref_t<lhs_config_t>>)
387  return configuration{std::forward<lhs_config_t>(lhs)}.append(std::forward<rhs_config_t>(rhs));
388  else
389  return std::forward<lhs_config_t>(lhs).append(std::forward<rhs_config_t>(rhs));
390 }
391 
423 template <template <typename ...> class query_t, typename ...configs_t>
424 constexpr auto & get(configuration<configs_t...> & config) noexcept
425 {
426  constexpr auto pos = pack_traits::find_if<detail::is_same_configuration_f<query_t>::template invoke, configs_t...>;
427  static_assert(pos > -1, "Access error: The requested type is not contained.");
428 
429  return get<pos>(config);
430 }
431 
433 template <template <typename ...> class query_t, typename ...configs_t>
434 constexpr auto const & get(configuration<configs_t...> const & config) noexcept
435 {
436  constexpr auto pos = pack_traits::find_if<detail::is_same_configuration_f<query_t>::template invoke, configs_t...>;
437  static_assert(pos > -1, "Access error: The requested type is not contained.");
438 
439  return get<pos>(config);
440 }
441 
443 template <template <typename ...> class query_t, typename ...configs_t>
444 constexpr auto && get(configuration<configs_t...> && config) noexcept
445 {
446  constexpr auto pos = pack_traits::find_if<detail::is_same_configuration_f<query_t>::template invoke, configs_t...>;
447  static_assert(pos > -1, "Access error: The requested type is not contained.");
448 
449  return get<pos>(std::move(config));
450 }
451 
453 template <template <typename ...> class query_t, typename ...configs_t>
454 constexpr auto const && get(configuration<configs_t...> const && config) noexcept
455 {
456  constexpr auto pos = pack_traits::find_if<detail::is_same_configuration_f<query_t>::template invoke, configs_t...>;
457  static_assert(pos > -1, "Access error: The requested type is not contained.");
458 
459  // TODO: change after GCC-7 bug with const && version of get in std::tuple is fixed.
460  // return get<pos>(std::move(config));
461  return std::move(get<pos>(config));
462 }
464 
465 } // namespace seqan3::detail
466 
467 namespace std
468 {
470 
476 template <seqan3::detail::config_element ... configs_t>
477 struct tuple_size<seqan3::configuration<configs_t...>>
478 {
480  static constexpr size_t value = std::tuple_size_v<typename seqan3::configuration<configs_t...>::base_type>;
481 };
482 
488 template <size_t pos, seqan3::detail::config_element ... configs_t>
489 struct tuple_element<pos, seqan3::configuration<configs_t...>>
490 {
492  using type = std::tuple_element_t<pos, typename seqan3::configuration<configs_t...>::base_type>;
493 };
495 } //namespace std
Collection of elements to configure an algorithm.
Definition: configuration.hpp:46
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:186
constexpr size_t size() const noexcept
Returns the number of contained config elements.
Definition: configuration.hpp:87
constexpr auto remove() const
Remove a config element from the configuration.
Definition: configuration.hpp:229
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:123
~configuration()=default
Defaulted.
constexpr configuration(config_element_t &&config_element)
Constructs a configuration from a single configuration element.
Definition: configuration.hpp:77
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:151
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:214
constexpr auto & get(configuration< configs_t... > &config) noexcept
Returns the stored element.
Definition: configuration.hpp:424
meta::list< types... > type_list
Type that contains multiple types, an alias for meta::list.
Definition: type_list.hpp:31
decltype(detail::concat(lists_t{}...)) concat
Join two seqan3::type_list s into one.
Definition: traits.hpp:292
constexpr ptrdiff_t find
Get the index of the first occurrence of a type in a pack.
Definition: traits.hpp:186
constexpr ptrdiff_t find_if
Get the index of the first type in a pack that satisfies the given predicate.
Definition: traits.hpp:209
constexpr bool contains
Whether a type occurs in a pack or not.
Definition: traits.hpp:227
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:68
constexpr auto tuple_pop_front(tuple_t &&t)
Removes the first element of a tuple.
Definition: tuple_utility.hpp:180
auto const move
A view that turns lvalue-references into rvalue-references.
Definition: move.hpp:70
The main SeqAn3 namespace.
Definition: aligned_sequence_concept.hpp:29
SeqAn specific customisations in the standard namespace.
Provides seqan3::pipeable_config_element.
Provides type traits seqan3::detail::transfer_type_modifier_onto.
T tuple_cat(T... args)
T tuple_size_v
Provides utility functions for tuple like interfaces.
Provides seqan3::type_list.
Provides various traits for template packs.