SeqAn3
utility.hpp
Go to the documentation of this file.
1 // ============================================================================
2 // SeqAn - The Library for Sequence Analysis
3 // ============================================================================
4 //
5 // Copyright (c) 2006-2018, Knut Reinert & Freie Universitaet Berlin
6 // Copyright (c) 2016-2018, Knut Reinert & MPI Molekulare Genetik
7 // All rights reserved.
8 //
9 // Redistribution and use in source and binary forms, with or without
10 // modification, are permitted provided that the following conditions are met:
11 //
12 // * Redistributions of source code must retain the above copyright
13 // notice, this list of conditions and the following disclaimer.
14 // * Redistributions in binary form must reproduce the above copyright
15 // notice, this list of conditions and the following disclaimer in the
16 // documentation and/or other materials provided with the distribution.
17 // * Neither the name of Knut Reinert or the FU Berlin nor the names of
18 // its contributors may be used to endorse or promote products derived
19 // from this software without specific prior written permission.
20 //
21 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 // ARE DISCLAIMED. IN NO EVENT SHALL KNUT REINERT OR THE FU BERLIN BE LIABLE
25 // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27 // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
31 // DAMAGE.
32 //
33 // ============================================================================
34 
40 #pragma once
41 
42 #include <meta/meta.hpp>
43 
46 
47 namespace seqan3::align_cfg
48 {
49 
66 enum struct id : uint8_t
67 {
69  gap,
73  score,
75  global,
77  output,
79  max_error,
81  band
84  ,SIZE
86 };
87 
88 } // namespace seqan3::align_cfg
89 
90 namespace seqan3::detail
91 {
92 // ----------------------------------------------------------------------------
93 // SEQAN3_INVALID_CONFIG
94 // ----------------------------------------------------------------------------
95 
97 // A common error message for testing valid configuration combinations.
98 #define SEQAN3_INVALID_CONFIG(e) "Configuration error: The configuration <" #e "> is not combinable with " \
99  "one of the previous config elements. Please see the documentation to get "\
100  "more information about which configurations can be combined."
101 
103 // ----------------------------------------------------------------------------
104 // on_align_config
105 // ----------------------------------------------------------------------------
106 
132 template <align_cfg::id e>
133 struct on_align_config
134 {
138  template <config_element_concept t>
139  using invoke = std::false_type;
140 };
141 
142 // ----------------------------------------------------------------------------
143 // align_config_type_to_id
144 // ----------------------------------------------------------------------------
145 
151 template <config_element_concept config_element_t>
152 struct align_config_type_to_id
153 {
155  static constexpr align_cfg::id value = align_cfg::id::SIZE;
156 };
157 
160 template <config_element_concept config_element_t>
161 inline constexpr align_cfg::id align_config_type_to_id_v = align_config_type_to_id<config_element_t>::value;
162 
163 // ----------------------------------------------------------------------------
164 // align_config_validation_matrix
165 // ----------------------------------------------------------------------------
166 
177 inline constexpr std::array<std::array<bool, static_cast<uint8_t>(align_cfg::id::SIZE)>,
178  static_cast<uint8_t>(align_cfg::id::SIZE)> align_config_validation_matrix =
179 {
180  // gap s_ends score global output m_err band
181  { { false, true, true, true, true, true, true }, // gap
182  { true, false, true, true, true, true, true }, // sequence_ends
183  { true, true, false, true, true, true, true }, // score
184  { true, true, true, false, true, true, true }, // global
185  { true, true, true, true, false, true, true }, // output
186  { true, true, true, true, true, false, true }, // max_error
187  { true, true, true, true, true, true, false } } // band
188 };
189 
200 template <align_cfg::id query, typename configuration_t>
202  requires is_algorithm_configuration_v<remove_cvref_t<configuration_t>>
204 struct invalid_alignment_configuration
205 {
206 protected:
207 
211  template <typename target_t>
212  struct invoke
213  {
215  static constexpr uint8_t pos1 = static_cast<uint8_t>(query);
217  static constexpr uint8_t pos2 = static_cast<uint8_t>(align_config_type_to_id_v<remove_cvref_t<target_t>>);
218 
219  static_assert(pos1 != static_cast<uint8_t>(align_cfg::id::SIZE),
220  "Unknown align_cfg::id! "
221  "Did you use an unknown config or did you forget to specialize align_config_type_to_id?");
222  static_assert(pos2 != static_cast<uint8_t>(align_cfg::id::SIZE),
223  "Unknown align_cfg::id! "
224  "Did you use an unknown config or did you forget to specialize align_config_type_to_id?");
225 
227  using type = std::conditional_t<align_config_validation_matrix[pos1][pos2], std::false_type, std::true_type>;
228  };
229 
231  using target_list_t = tuple_type_list_t<typename remove_cvref_t<configuration_t>::base_type>;
233  using tail_list_t = meta::find_if<meta::reverse<target_list_t>, meta::quote_trait<invoke>>;
235  using final_list_t = std::conditional_t<meta::empty<tail_list_t>::value, type_list<void>, tail_list_t>;
236 
237 public:
238 
240  using type = meta::front<final_list_t>;
241 };
242 
245 template <align_cfg::id query, typename configuration_t>
247  requires is_algorithm_configuration_v<remove_cvref_t<configuration_t>>
249 using invalid_alignment_configuration_t = typename invalid_alignment_configuration<query, configuration_t>::type;
250 
260 template <align_cfg::id query, typename configuration_t>
262  requires is_algorithm_configuration_v<remove_cvref_t<configuration_t>>
264 struct is_valid_alignment_configuration :
265  public std::is_same<invalid_alignment_configuration_t<query, configuration_t>, void>
266 {};
267 
270 template <align_cfg::id query, typename configuration_t>
272  requires is_algorithm_configuration_v<remove_cvref_t<configuration_t>>
274 inline constexpr bool is_valid_alignment_configuration_v =
275  is_valid_alignment_configuration<query, configuration_t>::value;
276 
284 template <align_cfg::id e, typename configuration_t>
286  requires is_algorithm_configuration_v<remove_cvref_t<configuration_t>>
288 struct has_align_cfg
289 {
290 protected:
292  using target_list_t = tuple_type_list_t<typename remove_cvref_t<configuration_t>::base_type>;
294  using tail_list_t = meta::find_if<target_list_t, on_align_config<e>>;
295 
296 public:
297 
301  using type = std::conditional_t<(meta::size<tail_list_t>::value > 0),
302  std::true_type,
303  std::false_type>;
305  static constexpr bool value = type::value;
306 };
307 
314 template <align_cfg::id e, typename configuration_t>
316  requires is_algorithm_configuration_v<remove_cvref_t<configuration_t>>
318 inline constexpr bool has_align_cfg_v = has_align_cfg<e, configuration_t>::value;
319 
320 } // namespace seqan3::detail
321 
322 namespace seqan3
323 {
324 
340 template <align_cfg::id e, typename ... cfg_elements_t>
342  requires detail::has_align_cfg_v<e, detail::configuration<cfg_elements_t...>>
344 constexpr auto & get(detail::configuration<cfg_elements_t...> & cfg) noexcept
345 {
346  using type_list_t = detail::tuple_type_list_t<typename detail::configuration<cfg_elements_t...>::base_type>;
347 
348  constexpr size_t pos = meta::size<type_list_t>::value -
349  meta::size<meta::find_if<type_list_t, detail::on_align_config<e>>>::value;
350 
351  static_assert(static_cast<int8_t>(e) < static_cast<int8_t>(align_cfg::id::SIZE),
352  "Did you forget to update align_cfg::id::SIZE value?");
353  static_assert(pos < meta::size<type_list_t>::value,
354  "The specified config element is not contained in the configuration.");
355 
356  return get<pos>(cfg).value;
357 }
358 
360 template <align_cfg::id e, typename ... cfg_elements_t>
362  requires detail::has_align_cfg_v<e, detail::configuration<cfg_elements_t...>>
364 constexpr auto const & get(detail::configuration<cfg_elements_t...> const & cfg) noexcept
365 {
366  using type_list_t = detail::tuple_type_list_t<typename detail::configuration<cfg_elements_t...>::base_type>;
367  constexpr size_t pos = meta::size<type_list_t>::value -
368  meta::size<meta::find_if<type_list_t, detail::on_align_config<e>>>::value;
369 
370  static_assert(static_cast<int8_t>(e) < static_cast<int8_t>(align_cfg::id::SIZE),
371  "Did you forget to update align_cfg::id::SIZE value?");
372  static_assert(pos < meta::size<type_list_t>::value,
373  "The specified config element is not contained in the configuration.");
374 
375  return get<pos>(cfg).value;
376 }
377 
379 template <align_cfg::id e, typename ... cfg_elements_t>
381  requires detail::has_align_cfg_v<e, detail::configuration<cfg_elements_t...>>
383 constexpr auto && get(detail::configuration<cfg_elements_t...> && cfg) noexcept
384 {
385  using type_list_t = detail::tuple_type_list_t<typename detail::configuration<cfg_elements_t...>::base_type>;
386  constexpr size_t pos = meta::size<type_list_t>::value -
387  meta::size<meta::find_if<type_list_t, detail::on_align_config<e>>>::value;
388 
389  static_assert(static_cast<int8_t>(e) < static_cast<int8_t>(align_cfg::id::SIZE),
390  "Did you forget to update align_cfg::id::SIZE value?");
391  static_assert(pos < meta::size<type_list_t>::value,
392  "The specified config element is not contained in the configuration.");
393 
394  return get<pos>(std::move(cfg)).value;
395 }
396 
398 template <align_cfg::id e, typename ... cfg_elements_t>
400  requires detail::has_align_cfg_v<e, detail::configuration<cfg_elements_t...>>
402 constexpr auto const && get(detail::configuration<cfg_elements_t...> const && cfg) noexcept
403 {
404  using type_list_t = detail::tuple_type_list_t<typename detail::configuration<cfg_elements_t...>::base_type>;
405  constexpr size_t pos = meta::size<type_list_t>::value -
406  meta::size<meta::find_if<type_list_t, detail::on_align_config<e>>>::value;
407 
408  static_assert(static_cast<int8_t>(e) < static_cast<int8_t>(align_cfg::id::SIZE),
409  "Did you forget to update align_cfg::id::SIZE value?");
410  static_assert(pos < meta::size<type_list_t>::value,
411  "The specified config element is not contained in the configuration.");
412 
413  return std::move(get<pos>(cfg).value); // TODO remove std::move when g++7 is fixed
414 }
416 } // namespace seqan3
Identifier for global alignment configuration.
Identifier for output configuration.
Identifier for free ends configuration.
The main SeqAn3 namespace.
Definition: aligned_sequence_concept.hpp:58
A special sub namespace for the alignment configurations.
Definition: align_config_band.hpp:151
Identifier for max_error configuration.
Identifier for score configuration.
Identifier for gap configuration.
Definition: aligned_sequence_concept.hpp:288
id
Specifies an id for every configuration element.
Definition: utility.hpp:66
meta::list< types... > type_list
Type that contains multiple types, an alias for meta::list.
Definition: type_list.hpp:54
Provides seqan3::detail::configuration and utility functions.
Static reflection for arbitrary types.