SeqAn3
parse_condition_detail.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 
41 #pragma once
42 
43 #include <cctype>
44 #include <stdexcept>
45 #include <string>
46 
47 #include <seqan3/std/concepts>
48 
49 #include <seqan3/alphabet/all.hpp>
52 #include <seqan3/io/exception.hpp>
54 
55 namespace seqan3::detail
56 {
57 
58 // ----------------------------------------------------------------------------
59 // constexpr_pseudo_bitset (could be replaced with constexpr std::bitset or github.com/ClaasBontus/bitset2)
60 // ----------------------------------------------------------------------------
61 
66 template <size_t N>
67 class constexpr_pseudo_bitset : public std::array<bool, N>
68 {
69 private:
71  using base_t = std::array<bool, N>;
72 public:
74  using base_t::base_t;
75 
77  constexpr constexpr_pseudo_bitset operator|(constexpr_pseudo_bitset rhs) const noexcept
78  {
79  for (size_t i = 0; i < N; ++i)
80  rhs[i] = rhs[i] || base_t::operator[](i);
81 
82  return std::move(rhs);
83  }
85  constexpr constexpr_pseudo_bitset operator~() const noexcept
86  {
87  constexpr_pseudo_bitset ret{};
88  for (size_t i = 0; i < N; ++i)
89  ret[i] = !base_t::operator[](i);
90 
91  return ret;
92  }
93 };
94 
95 // ----------------------------------------------------------------------------
96 // condition_message_v
97 // ----------------------------------------------------------------------------
98 
107 template <char op, typename condition_head_t, typename ...condition_ts>
108 inline constexpr_string constexpr condition_message_v
109 {
110  constexpr_string{"("} +
111  (condition_head_t::msg + ... +
112  (constexpr_string{" "} + constexpr_string{{op, op, '\0'}} + constexpr_string{" "} + condition_ts::msg)) +
113  constexpr_string{")"}
114 };
115 
116 // ----------------------------------------------------------------------------
117 // parse_condition_concept
118 // ----------------------------------------------------------------------------
119 
121 template <typename condition_t>
122 class parse_condition_base;
124 
134 template <typename condition_t>
136 concept parse_condition_concept = requires
137 {
139  requires std::is_base_of_v<parse_condition_base<remove_cvref_t<condition_t>>,
140  remove_cvref_t<condition_t>>;
141 
142  std::remove_reference_t<condition_t>::msg;
143 
144  //The msg type can be added with a constexpr_string.
145  { constexpr_string<0>{} + std::remove_reference_t<condition_t>::msg } ->
146  decltype(std::remove_reference_t<condition_t>::msg);
147 };
149 
168 
170 // ----------------------------------------------------------------------------
171 // make_printable
172 // ----------------------------------------------------------------------------
173 
196 template <typename char_type>
197 inline std::string make_printable(char_type const c)
198 {
199  switch (c)
200  {
201  case '\0': return "'\\0'";
202  case '\t': return "'\\t'";
203  case '\n': return "'\\n'";
204  case '\v': return "'\\v'";
205  case '\f': return "'\\f'";
206  case '\r': return "'\\r'";
207  case static_cast<char>(127): return "'DEL'";
208  default:
209  {
210  if ((c >= static_cast<char>(1) && c <= static_cast<char>(8)) ||
211  (c >= static_cast<char>(14) && c <= static_cast<char>(31)))
212  return "'CTRL'";
213  else
214  return {'\'', c, '\''};
215  }
216  }
217 }
218 
219 // ----------------------------------------------------------------------------
220 // parse_condition
221 // ----------------------------------------------------------------------------
222 
224 template <parse_condition_concept... condition_ts>
225  requires sizeof...(condition_ts) >= 2
226 struct parse_condition_combiner;
227 
228 template <parse_condition_concept condition_t>
229 struct parse_condition_negator;
231 
238 template <typename derived_t>
239 class parse_condition_base
240 {
241 private:
242 
244  friend derived_t;
245 
250  constexpr parse_condition_base() = default;
251  constexpr parse_condition_base(parse_condition_base const &) = default;
252  constexpr parse_condition_base(parse_condition_base &&) = default;
253  constexpr parse_condition_base & operator=(parse_condition_base const &) = default;
254  constexpr parse_condition_base & operator=(parse_condition_base &&) = default;
255  ~parse_condition_base() = default;
257 public:
259  using data_t = constexpr_pseudo_bitset<257>; // sizeof(char) plus EOF
260 
265  template <parse_condition_concept rhs_t>
267  constexpr auto operator||(rhs_t const &) const
268  {
269  return parse_condition_combiner<derived_t, rhs_t>{};
270  }
271 
273  constexpr auto operator!() const
274  {
275  return parse_condition_negator<derived_t>{};
276  }
278 
282  template <std::Integral value_t>
284  constexpr bool operator()(value_t const val) const noexcept
285  requires sizeof(value_t) == 1
286  {
287  return derived_t::data[static_cast<unsigned char>(val)];
288  }
289  template <std::Integral value_t>
290  constexpr bool operator()(value_t const val) const noexcept
291  requires sizeof(value_t) != 1
292  {
293  return (static_cast<std::make_unsigned_t<value_t>>(val) < 256) ? operator()(static_cast<uint8_t>(val)) :
294  (static_cast<decltype(EOF)>(val) == EOF) ? derived_t::data[256] : false;
295  }
297 
301  std::string message() const
303  {
304  return derived_t::msg.string();
305  }
307 };
308 
309 // ----------------------------------------------------------------------------
310 // parse_condition_combiner
311 // ----------------------------------------------------------------------------
312 
319 template <parse_condition_concept... condition_ts>
321  requires sizeof...(condition_ts) >= 2
323 struct parse_condition_combiner : public parse_condition_base<parse_condition_combiner<condition_ts...>>
324 {
326  static constexpr auto msg = detail::condition_message_v<'|', condition_ts...>;
327 
329  using base_t = parse_condition_base<parse_condition_combiner<condition_ts...>>;
330 
332  using typename base_t::data_t;
334  static constexpr data_t data = (condition_ts::data | ...);
335 };
336 
343 template <parse_condition_concept condition_t>
344 struct parse_condition_negator : public parse_condition_base<parse_condition_negator<condition_t>>
345 {
347  static constexpr auto msg = constexpr_string{'!'} + condition_t::msg;
348 
350  using base_t = parse_condition_base<parse_condition_negator<condition_t>>;
351 
353  using typename base_t::data_t;
355  static constexpr data_t data = ~condition_t::data;
356 };
357 
358 // ----------------------------------------------------------------------------
359 // is_in_interval_type
360 // ----------------------------------------------------------------------------
361 
370 template <uint8_t interval_first, uint8_t interval_last>
372  requires interval_first <= interval_last
374 struct is_in_interval_type : public parse_condition_base<is_in_interval_type<interval_first, interval_last>>
375 {
377  static constexpr constexpr_string msg = constexpr_string{"is_in_interval<'"} +
378  constexpr_string{interval_first} +
379  constexpr_string{"', '"} +
380  constexpr_string{interval_last} +
381  constexpr_string{"'>"};
382 
384  using base_t = parse_condition_base<is_in_interval_type<interval_first, interval_last>>;
385 
387  using typename base_t::data_t;
389  static constexpr data_t data = [] () constexpr
390  {
391  data_t ret{};
392 
393  for (uint8_t i = interval_first; i <= interval_last; ++i)
394  ret[i] = true;
395 
396  return ret;
397  }();
398 };
399 
400 // ----------------------------------------------------------------------------
401 // is_in_alphabet_type
402 // ----------------------------------------------------------------------------
403 
409 template <alphabet_concept alphabet_t>
410 struct is_in_alphabet_type : public parse_condition_base<is_in_alphabet_type<alphabet_t>>
411 {
412 private:
414  static constexpr std::array<unsigned char, 256> to_upper = [] () constexpr
415  {
416  std::array<unsigned char, 256> ret{};
417 
418  for (size_t i = 0; i < 256; ++i)
419  ret[i] = i;
420 
421  for (size_t i = 'a'; i <= 'z'; ++i)
422  ret[i] = i - 'a' + 'A';
423 
424  return ret;
425  }();
426 
427 public:
429  static constexpr auto msg = constexpr_string{"is_in_alphabet<"} +
430  constexpr_string{detail::get_display_name_v<alphabet_t>} +
431  constexpr_string{">"};
432 
434  using base_t = parse_condition_base<is_in_alphabet_type<alphabet_t>>;
435 
437  using typename base_t::data_t;
439  static constexpr data_t data = [] () constexpr
440  {
441  data_t ret{};
442 
443  for (unsigned char i = 0; i < 255; ++i)
444  ret[i] = to_char(assign_char(alphabet_t{}, i)) == to_upper[i];
445 
446  return ret;
447  }();
448 };
449 
450 // ----------------------------------------------------------------------------
451 // is_char_type
452 // ----------------------------------------------------------------------------
453 
459 template <int char_v>
460 struct is_char_type : public parse_condition_base<is_char_type<char_v>>
461 {
462  static_assert(char_v == EOF || static_cast<uint64_t>(char_v) < 256, "TODO");
463 
465  static constexpr auto msg = constexpr_string{"is_char<'"} +
466  constexpr_string{char_v} +
467  constexpr_string("'>");
468 
469 
470 
472  using base_t = parse_condition_base<is_char_type<char_v>>;
473 
475  using typename base_t::data_t;
477  static constexpr data_t data = [] () constexpr
478  {
479  data_t ret{};
480 
481  if (char_v == EOF)
482  ret[256] = true;
483  else
484  ret[static_cast<uint8_t>(char_v)] = true;
485 
486  return ret;
487  }();
488 };
489 
490 } // namespace seqan3::detail
A constexpr string implementation to manipulate string literals at compile time.
Provides exceptions used in the I/O module.
Specifies whether the given callable is std::RegularInvocable and returns bool.
Meta-header for the alphabet module.
The Concepts library.
Definition: aligned_sequence_concept.hpp:288
Provides various metafunctions on generic types.
auto operator|(validator1_type &&vali1, validator2_type &&vali2)
Enables the chaining of validators. !
Definition: validators.hpp:671
constexpr char_type to_upper(char_type const c) noexcept
Converts &#39;a&#39;-&#39;z&#39; to &#39;A&#39;-&#39;Z&#39; respectively; other characters are returned as is.
Definition: char_operations.hpp:123
constexpr alphabet_type & assign_char(alphabet_type &alph, underlying_char_t< alphabet_type > const chr) requires requires(alphabet_type alph)
Implementation of seqan3::alphabet_concept::assign_char() that delegates to a member function...
Definition: member_exposure.hpp:178
constexpr_string constexpr condition_message_v
Defines a compound seqan3::constexpr_string consisting of all given conditions separated by the opera...
Definition: parse_condition_detail.hpp:109
Static reflection for arbitrary types.
constexpr underlying_char_t< alphabet_type > to_char(alphabet_type const alph) requires requires(alphabet_type alph)
Implementation of seqan3::alphabet_concept::to_char() that delegates to a member function.
Definition: member_exposure.hpp:165