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
24namespace seqan3
25{
26
27// ----------------------------------------------------------------------------
28// configuration
29// ----------------------------------------------------------------------------
30
43template <detail::config_element... configs_t>
44class configuration : public std::tuple<configs_t...>
45{
47 template <detail::config_element... _configs_t>
48 friend class configuration;
49
50public:
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 {
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>,
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
239private:
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
340template <detail::config_element config_t>
343
363template <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>>)
365constexpr 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
404template <template <typename...> class query_t, typename... configs_t>
405constexpr 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
414template <template <typename...> class query_t, typename... configs_t>
415constexpr 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
424template <template <typename...> class query_t, typename... configs_t>
425constexpr 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
434template <template <typename...> class query_t, typename... configs_t>
435constexpr 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
446namespace std
447{
449
455template <seqan3::detail::config_element... configs_t>
456struct 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
467template <size_t pos, seqan3::detail::config_element... configs_t>
468struct 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
constexpr decltype(auto) get_or(alternative_t &&alternative) const &&noexcept
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition: configuration.hpp:141
constexpr size_t size() const noexcept
Returns the number of contained config elements.
Definition: configuration.hpp:84
configuration(config_t) -> configuration< config_t >
Deduces the correct configuration element type from the passed seqan3::pipeable_config_element.
constexpr configuration(config_element_t &&config_element)
Constructs a configuration from a single configuration element.
Definition: configuration.hpp:74
constexpr decltype(auto) get_or(alternative_t &&alternative) &&noexcept
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition: configuration.hpp:134
constexpr configuration(configuration &&)=default
Defaulted.
constexpr auto remove() const
Remove a config element from the configuration.
Definition: configuration.hpp:221
constexpr decltype(auto) get_or(alternative_t &&alternative) &noexcept
Returns the stored configuration element if present otherwise the given alternative.
Definition: configuration.hpp:120
constexpr configuration & operator=(configuration const &)=default
Defaulted.
constexpr configuration & operator=(configuration &&)=default
Defaulted.
~configuration()=default
Defaulted.
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:181
constexpr decltype(auto) get_or(alternative_t &&alternative) const &noexcept
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition: configuration.hpp:127
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:148
friend class configuration
Friend declaration for other instances of the configuration.
Definition: configuration.hpp:48
Provides various auxiliary functions with which parts of the configurations can be checked.
Provides concepts for the configuration classes.
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
decltype(detail::concat(lists_t{}...)) concat
Join two seqan3::type_list s into one.
Definition: traits.hpp:342
constexpr ptrdiff_t find
Get the index of the first occurrence of a type in a pack.
Definition: traits.hpp:182
constexpr ptrdiff_t find_if
Get the index of the first type in a pack that satisfies the given predicate.
Definition: traits.hpp:205
constexpr bool contains
Whether a type occurs in a pack or not.
Definition: 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.