SeqAn3
charconv_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 
35 // ============================================================================
36 // LLVM Release License
37 // ============================================================================
38 // University of Illinois/NCSA
39 // Open Source License
40 //
41 // Copyright (c) 2003-2018 University of Illinois at Urbana-Champaign.
42 // All rights reserved.
43 //
44 // Developed by:
45 // LLVM Team
46 // University of Illinois at Urbana-Champaign
47 // http://llvm.org
48 //
49 // Permission is hereby granted, free of charge, to any person obtaining a copy of
50 // this software and associated documentation files (the "Software"), to deal with
51 // the Software without restriction, including without limitation the rights to
52 // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
53 // of the Software, and to permit persons to whom the Software is furnished to do
54 // so, subject to the following conditions:
55 //
56 // * Redistributions of source code must retain the above copyright notice,
57 // this list of conditions and the following disclaimers.
58 // * Redistributions in binary form must reproduce the above copyright notice,
59 // this list of conditions and the following disclaimers in the
60 // documentation and/or other materials provided with the distribution.
61 // * Neither the names of the LLVM Team, University of Illinois at
62 // Urbana-Champaign, nor the names of its contributors may be used to
63 // endorse or promote products derived from this Software without specific
64 // prior written permission.
65 //
66 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
67 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
68 // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
69 // CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
70 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
71 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE
72 // SOFTWARE.
73 // ============================================================================
74 
81 #pragma once
82 
83 #include <cstdlib>
84 #include <type_traits>
85 #include <limits>
86 #include <cstdint>
87 #include <cstring>
88 #include <cmath>
89 #include <cerrno>
90 
93 #include <seqan3/std/concepts>
94 
95 namespace seqan3::detail
96 {
97 
99 // implementation detail taken from LLVM
100 static constexpr uint64_t pow10_64[] =
101 {
102  UINT64_C(0),
103  UINT64_C(10),
104  UINT64_C(100),
105  UINT64_C(1000),
106  UINT64_C(10000),
107  UINT64_C(100000),
108  UINT64_C(1000000),
109  UINT64_C(10000000),
110  UINT64_C(100000000),
111  UINT64_C(1000000000),
112  UINT64_C(10000000000),
113  UINT64_C(100000000000),
114  UINT64_C(1000000000000),
115  UINT64_C(10000000000000),
116  UINT64_C(100000000000000),
117  UINT64_C(1000000000000000),
118  UINT64_C(10000000000000000),
119  UINT64_C(100000000000000000),
120  UINT64_C(1000000000000000000),
121  UINT64_C(10000000000000000000),
122 };
123 
124 static constexpr uint32_t pow10_32[] =
125 {
126  UINT32_C(0), UINT32_C(10), UINT32_C(100),
127  UINT32_C(1000), UINT32_C(10000), UINT32_C(100000),
128  UINT32_C(1000000), UINT32_C(10000000), UINT32_C(100000000),
129  UINT32_C(1000000000),
130 };
131 
132 static constexpr char cDigitsLut[200] = {
133  '0', '0', '0', '1', '0', '2', '0', '3', '0', '4', '0', '5', '0', '6', '0',
134  '7', '0', '8', '0', '9', '1', '0', '1', '1', '1', '2', '1', '3', '1', '4',
135  '1', '5', '1', '6', '1', '7', '1', '8', '1', '9', '2', '0', '2', '1', '2',
136  '2', '2', '3', '2', '4', '2', '5', '2', '6', '2', '7', '2', '8', '2', '9',
137  '3', '0', '3', '1', '3', '2', '3', '3', '3', '4', '3', '5', '3', '6', '3',
138  '7', '3', '8', '3', '9', '4', '0', '4', '1', '4', '2', '4', '3', '4', '4',
139  '4', '5', '4', '6', '4', '7', '4', '8', '4', '9', '5', '0', '5', '1', '5',
140  '2', '5', '3', '5', '4', '5', '5', '5', '6', '5', '7', '5', '8', '5', '9',
141  '6', '0', '6', '1', '6', '2', '6', '3', '6', '4', '6', '5', '6', '6', '6',
142  '7', '6', '8', '6', '9', '7', '0', '7', '1', '7', '2', '7', '3', '7', '4',
143  '7', '5', '7', '6', '7', '7', '7', '8', '7', '9', '8', '0', '8', '1', '8',
144  '2', '8', '3', '8', '4', '8', '5', '8', '6', '8', '7', '8', '8', '8', '9',
145  '9', '0', '9', '1', '9', '2', '9', '3', '9', '4', '9', '5', '9', '6', '9',
146  '7', '9', '8', '9', '9'};
147 
148 template <typename T>
149 inline char* append1(char* buffer, T i)
150 {
151  *buffer = '0' + static_cast<char>(i);
152  return buffer + 1;
153 }
154 
155 template <typename T>
156 inline char* append2(char* buffer, T i)
157 {
158  memcpy(buffer, &cDigitsLut[(i)*2], 2);
159  return buffer + 2;
160 }
161 
162 template <typename T>
163 inline char* append3(char* buffer, T i)
164 {
165  return append2(append1(buffer, (i) / 100), (i) % 100);
166 }
167 
168 template <typename T>
169 inline char* append4(char* buffer, T i)
170 {
171  return append2(append2(buffer, (i) / 100), (i) % 100);
172 }
173 
174 char* u32toa(uint32_t value, char* buffer)
175 {
176  if (value < 10000)
177  {
178  if (value < 100)
179  {
180  if (value < 10)
181  buffer = append1(buffer, value);
182  else
183  buffer = append2(buffer, value);
184  }
185  else
186  {
187  if (value < 1000)
188  buffer = append3(buffer, value);
189  else
190  buffer = append4(buffer, value);
191  }
192  }
193  else if (value < 100000000)
194  {
195  // value = bbbbcccc
196  const uint32_t b = value / 10000;
197  const uint32_t c = value % 10000;
198 
199  if (value < 1000000)
200  {
201  if (value < 100000)
202  buffer = append1(buffer, b);
203  else
204  buffer = append2(buffer, b);
205  }
206  else
207  {
208  if (value < 10000000)
209  buffer = append3(buffer, b);
210  else
211  buffer = append4(buffer, b);
212  }
213 
214  buffer = append4(buffer, c);
215  }
216  else
217  {
218  // value = aabbbbcccc in decimal
219  const uint32_t a = value / 100000000; // 1 to 42
220  value %= 100000000;
221 
222  if (a < 10)
223  buffer = append1(buffer, a);
224  else
225  buffer = append2(buffer, a);
226 
227  buffer = append4(buffer, value / 10000);
228  buffer = append4(buffer, value % 10000);
229  }
230 
231  return buffer;
232 }
233 
234 char* u64toa(uint64_t value, char* buffer)
235 {
236  if (value < 100000000)
237  {
238  uint32_t v = static_cast<uint32_t>(value);
239  if (v < 10000)
240  {
241  if (v < 100)
242  {
243  if (v < 10)
244  buffer = append1(buffer, v);
245  else
246  buffer = append2(buffer, v);
247  }
248  else
249  {
250  if (v < 1000)
251  buffer = append3(buffer, v);
252  else
253  buffer = append4(buffer, v);
254  }
255  }
256  else
257  {
258  // value = bbbbcccc
259  const uint32_t b = v / 10000;
260  const uint32_t c = v % 10000;
261 
262  if (v < 1000000)
263  {
264  if (v < 100000)
265  buffer = append1(buffer, b);
266  else
267  buffer = append2(buffer, b);
268  }
269  else
270  {
271  if (v < 10000000)
272  buffer = append3(buffer, b);
273  else
274  buffer = append4(buffer, b);
275  }
276 
277  buffer = append4(buffer, c);
278  }
279  }
280  else if (value < 10000000000000000)
281  {
282  const uint32_t v0 = static_cast<uint32_t>(value / 100000000);
283  const uint32_t v1 = static_cast<uint32_t>(value % 100000000);
284 
285  const uint32_t b0 = v0 / 10000;
286  const uint32_t c0 = v0 % 10000;
287 
288  if (v0 < 1000000)
289  {
290  if (v0 < 100000)
291  buffer = append1(buffer, b0);
292  else
293  buffer = append2(buffer, b0);
294  }
295  else
296  {
297  if (v0 < 10000000)
298  buffer = append3(buffer, b0);
299  else
300  buffer = append4(buffer, b0);
301  }
302 
303  buffer = append4(buffer, c0);
304  buffer = append4(buffer, v1 / 10000);
305  buffer = append4(buffer, v1 % 10000);
306  }
307  else
308  {
309  const uint32_t a =
310  static_cast<uint32_t>(value / 10000000000000000); // 1 to 1844
311  value %= 10000000000000000;
312 
313  if (a < 100)
314  {
315  if (a < 10)
316  buffer = append1(buffer, a);
317  else
318  buffer = append2(buffer, a);
319  }
320  else
321  {
322  if (a < 1000)
323  buffer = append3(buffer, a);
324  else
325  buffer = append4(buffer, a);
326  }
327 
328  const uint32_t v0 = static_cast<uint32_t>(value / 100000000);
329  const uint32_t v1 = static_cast<uint32_t>(value % 100000000);
330  buffer = append4(buffer, v0 / 10000);
331  buffer = append4(buffer, v0 % 10000);
332  buffer = append4(buffer, v1 / 10000);
333  buffer = append4(buffer, v1 % 10000);
334  }
335 
336  return buffer;
337 }
338 
339 template <typename value_type, typename = void>
340 struct traits_base
341 {
342  using type = uint64_t;
343 
344  static int width(value_type v)
345  {
346  auto t = (64 - __builtin_clzll(v | 1)) * 1233 >> 12;
347  return t - (v < pow10_64[t]) + 1;
348  }
349 
350  static char* convert(value_type v, char* p)
351  {
352  return u64toa(v, p);
353  }
354 
355  static auto& pow() { return pow10_64; }
356 };
357 
358 template <typename value_type>
359 struct traits_base<value_type, decltype(void(uint32_t{std::declval<value_type>()}))>
360 {
361  using type = uint32_t;
362 
363  static int width(value_type v)
364  {
365  auto t = (32 - __builtin_clz(v | 1)) * 1233 >> 12;
366  return t - (v < pow10_32[t]) + 1;
367  }
368 
369  static char* convert(value_type v, char* p)
370  {
371  return u32toa(v, p);
372  }
373 
374  static auto& pow() { return pow10_32; }
375 };
376 
377 template <typename value_type>
378 inline bool mul_overflowed(unsigned char a, value_type b, unsigned char& r)
379 {
380  auto c = a * b;
381  r = c;
382  return c > (std::numeric_limits<unsigned char>::max)();
383 }
384 
385 template <typename value_type>
386 inline bool mul_overflowed(unsigned short a, value_type b, unsigned short& r)
387 {
388  auto c = a * b;
389  r = c;
390  return c > (std::numeric_limits<unsigned short>::max)();
391 }
392 
393 template <typename value_type>
394 inline bool mul_overflowed(value_type a, value_type b, value_type & r)
395 {
396  static_assert(std::is_unsigned<value_type>::value, "");
397  return __builtin_mul_overflow(a, b, &r);
398 }
399 
400 template <typename value_type, typename _Up>
401 inline bool mul_overflowed(value_type a, _Up b, value_type & r)
402 {
403  return mul_overflowed(a, static_cast<value_type>(b), r);
404 }
405 
406 template <typename value_type>
407 struct traits : traits_base<value_type>
408 {
409  static constexpr int digits = std::numeric_limits<value_type>::digits10 + 1;
410  using traits_base<value_type>::pow;
411  using typename traits_base<value_type>::type;
412 
413  // precondition: at least one non-zero character available
414  static char const*
415  read(char const* p, char const* ep, type& a, type& b)
416  {
417  type cprod[digits];
418  int j = digits - 1;
419  int i = digits;
420  do
421  {
422  if (!('0' <= *p && *p <= '9'))
423  break;
424  cprod[--i] = *p++ - '0';
425  } while (p != ep && i != 0);
426 
427  a = inner_product(cprod + i + 1, cprod + j, pow() + 1,
428  cprod[i]);
429  if (mul_overflowed(cprod[j], pow()[j - i], b))
430  --p;
431  return p;
432  }
433 
434  template <typename _It1, typename _It2, class _Up>
435  static _Up
436  inner_product(_It1 first1, _It1 last1, _It2 first2, _Up init)
437  {
438  for (; first1 < last1; ++first1, ++first2)
439  init = init + *first1 * *first2;
440  return init;
441  }
442 };
443 
444 template <typename value_type>
445 inline value_type complement(value_type x)
446 {
447  static_assert(std::UnsignedIntegral<value_type>, "cast to unsigned first");
448  return value_type(~x + 1);
449 }
450 
451 template <typename value_type>
452 inline auto to_unsigned(value_type x)
453 {
454  return static_cast<std::make_unsigned_t<value_type>>(x);
455 }
456 
457 template <typename value_type>
458 inline std::to_chars_result to_chars_itoa(char* first, char* last, value_type value, std::false_type)
459 {
460  using tx = traits<value_type>;
461  auto diff = last - first;
462 
463  if (tx::digits <= diff || tx::width(value) <= diff)
464  return {tx::convert(value, first), {}};
465  else
466  return {last, std::errc::value_too_large};
467 }
468 
469 template <typename value_type>
470 inline std::to_chars_result to_chars_itoa(char* first, char* last, value_type value, std::true_type)
471 {
472  auto x = to_unsigned(value);
473  if (value < 0 && first != last)
474  {
475  *first++ = '-';
476  x = complement(x);
477  }
478 
479  return to_chars_itoa(first, last, x, std::false_type());
480 }
481 
482 template <typename value_type>
483 inline std::to_chars_result to_chars_integral(char* first, char* last, value_type value, int base,
484  std::true_type)
485 {
486  auto x = to_unsigned(value);
487  if (value < 0 && first != last)
488  {
489  *first++ = '-';
490  x = complement(x);
491  }
492 
493  return to_chars_integral(first, last, x, base, std::false_type());
494 }
495 
496 template <typename value_type>
497 inline std::to_chars_result to_chars_integral(char* first, char* last, value_type value, int base,
498  std::false_type)
499 {
500  if (base == 10)
501  return to_chars_itoa(first, last, value, std::false_type());
502 
503  auto p = last;
504  while (p != first)
505  {
506  auto c = value % base;
507  value /= base;
508  *--p = "0123456789abcdefghijklmnopqrstuvwxyz"[c];
509  if (value == 0)
510  break;
511  }
512 
513  auto len = last - p;
514  if (value != 0 || !len)
515  return {last, std::errc::value_too_large};
516  else
517  {
518  memmove(first, p, len);
519  return {first + len, {}};
520  }
521 }
522 
523 template <typename _It, typename value_type, typename _Fn, typename... _Ts>
524 inline std::from_chars_result sign_combinator(_It first, _It last, value_type & value, _Fn f, _Ts... args)
525 {
526  using tl = std::numeric_limits<value_type>;
527  decltype(to_unsigned(value)) x;
528 
529  bool neg = (first != last && *first == '-');
530  auto r = f(neg ? first + 1 : first, last, x, args...);
531 
532  switch (r.ec)
533  {
534  case std::errc::invalid_argument:
535  return {first, r.ec};
536  case std::errc::result_out_of_range:
537  return r;
538  default:
539  break;
540  }
541 
542  if (neg)
543  {
544  if (x <= complement(to_unsigned(tl::min())))
545  {
546  x = complement(x);
547  memcpy(&value, &x, sizeof(x));
548  return r;
549  }
550  }
551  else
552  {
553  if (x <= (tl::max)())
554  {
555  value = x;
556  return r;
557  }
558  }
559 
560  return {r.ptr, std::errc::result_out_of_range};
561 }
562 
563 template <typename value_type>
564 inline bool in_pattern(value_type c)
565 {
566  return '0' <= c && c <= '9';
567 }
568 
569 struct in_pattern_result
570 {
571  bool ok;
572  int val;
573 
574  explicit operator bool() const { return ok; }
575 };
576 
577 template <typename value_type>
578 inline in_pattern_result in_pattern(value_type c, int base)
579 {
580  if (base <= 10)
581  return {'0' <= c && c < '0' + base, c - '0'};
582  else if (in_pattern(c))
583  return {true, c - '0'};
584  else if ('a' <= c && c < 'a' + base - 10)
585  return {true, c - 'a' + 10};
586  else
587  return {'A' <= c && c < 'A' + base - 10, c - 'A' + 10};
588 }
589 
590 template <typename _It, typename value_type, typename _Fn, typename... _Ts>
591 inline std::from_chars_result subject_seq_combinator(_It first, _It last, value_type & value, _Fn f, _Ts... args)
592 {
593  auto find_non_zero = [](_It first, _It last)
594  {
595  for (; first != last; ++first)
596  if (*first != '0')
597  break;
598  return first;
599  };
600 
601  auto p = find_non_zero(first, last);
602  if (p == last || !in_pattern(*p, args...))
603  {
604  if (p == first)
605  return {first, std::errc::invalid_argument};
606  else
607  {
608  value = 0;
609  return {p, {}};
610  }
611  }
612 
613  auto r = f(p, last, value, args...);
614  if (r.ec == std::errc::result_out_of_range)
615  {
616  for (; r.ptr != last; ++r.ptr)
617  {
618  if (!in_pattern(*r.ptr, args...))
619  break;
620  }
621  }
622 
623  return r;
624 }
625 
626 template <typename value_type, std::enable_if_t<std::is_unsigned<value_type>::value, int> = 0>
628 from_chars_atoi(char const * first, char const * last, value_type & value)
629 {
630  using tx = traits<value_type>;
631  using output_type = typename tx::type;
632 
633  return subject_seq_combinator(first, last, value,
634  [](char const * first, char const * last, value_type & value) -> std::from_chars_result
635  {
636  output_type a, b;
637  auto p = tx::read(first, last, a, b);
638  if (p == last || !in_pattern(*p))
639  {
640  output_type m = (std::numeric_limits<value_type>::max)();
641  if (m >= a && m - a >= b)
642  {
643  value = a + b;
644  return {p, {}};
645  }
646  }
647  return {p, std::errc::result_out_of_range};
648  });
649 }
650 
651 template <std::SignedIntegral value_type>
652 inline std::from_chars_result from_chars_atoi(char const * first, char const * last, value_type & value)
653 {
654  using t = decltype(to_unsigned(value));
655  return sign_combinator(first, last, value, from_chars_atoi<t>);
656 }
657 
658 template <std::UnsignedIntegral value_type>
659 inline std::from_chars_result from_chars_integral(char const * first, char const * last, value_type & value, int base)
660 {
661  if (base == 10)
662  return from_chars_atoi(first, last, value);
663 
664  return subject_seq_combinator(first, last, value,
665  [] (char const * p, char const * last, value_type & value, int base) -> std::from_chars_result
666  {
667  using tl = std::numeric_limits<value_type>;
668  auto digits = tl::digits / log2f(float(base));
669  value_type a = in_pattern(*p++, base).val, b = 0;
670 
671  for (int i = 1; p != last; ++i, ++p)
672  {
673  if (auto c = in_pattern(*p, base))
674  {
675  if (i < digits - 1)
676  a = a * base + c.val;
677  else
678  {
679  if (!mul_overflowed(a, base, a))
680  ++p;
681  b = c.val;
682  break;
683  }
684  }
685  else
686  break;
687  }
688 
689  if (p == last || !in_pattern(*p, base))
690  {
691  if ((tl::max)() - a >= b)
692  {
693  value = a + b;
694  return {p, {}};
695  }
696  }
697  return {p, std::errc::result_out_of_range};
698  },
699  base);
700 }
701 
702 template <std::SignedIntegral value_type>
703 inline std::from_chars_result from_chars_integral(char const * first, char const * last, value_type & value, int base)
704 {
705  using t = decltype(to_unsigned(value));
706  return sign_combinator(first, last, value, from_chars_integral<t>, base);
707 }
709 
711 template <seqan3::floating_point_concept value_type>
712 inline std::from_chars_result from_chars_floating_point(char const * first,
713  char const * last,
714  value_type & value,
716 {
717  // The locale issue:
718  // std::from_chars is documented to be locale independent. The accepted patterns
719  // are identical to the one used by strtod in the defailt ("C") locale.
720  //
721  // The functions strto[d/f/ld] used here are locale dependent but
722  // setting the locale manually by std::setlocale is not thread safe.
723  // So for the time being this workaround is locale dependent.
724  if (*first == '+') // + is permitted in function strto[d/f/ld] but not in from_chars
725  return {last, std::errc::invalid_argument};
726 
727  float tmp{};
728  ptrdiff_t constexpr buffer_size = 10000;
729  char hex_buffer[buffer_size];
730  char * start;
731  char * end;
732 
733  if (fmt != std::chars_format::general)
734  {
735  bool exponent_is_present{false};
736  for (auto it = first; it != last; ++it)
737  {
738  if (seqan3::is_char<'e'>(*it) || seqan3::is_char<'E'>(*it))
739  {
740  exponent_is_present = true;
741  break;
742  }
743  }
744 
745  if (fmt == std::chars_format::scientific &&
746  !exponent_is_present)
747  return {last, std::errc::invalid_argument};
748 
749  if (fmt == std::chars_format::fixed &&
750  exponent_is_present)
751  return {last, std::errc::invalid_argument};
752  }
753 
754  // If hex format is explicitly expected, the 0x prefix is not allowed in the
755  // the original sequence according to the std::from_chars cppreference
756  // documentation.
757  // In order to use strto[f/d/ld], the prefix must be prepended to achieve
758  // correct parsing. This will also automatically lead to an error if the
759  // original sequence did contain a 0x prefix and thus reflect the correct
760  // requirements of std::from_chars.
761  if (fmt == std::chars_format::hex)
762  {
763  hex_buffer[0] = '0';
764  hex_buffer[1] = 'x';
765  for (unsigned i = 0; i < std::min(buffer_size - 2, last - first); ++i)
766  hex_buffer[i+2] = first[i];
767 
768  start = &hex_buffer[0];
769  end = &hex_buffer[0] + sizeof(hex_buffer);
770  }
771  else
772  {
773  start = const_cast<char *>(first);
774  end = const_cast<char *>(last);
775  }
776 
777  if constexpr (std::Same<std::remove_reference_t<value_type>, float>)
778  {
779  tmp = strtof(start, &end);
780  }
781  if constexpr (std::Same<std::remove_reference_t<value_type>, double>)
782  {
783  tmp = strtod(start, &end);
784  }
785  if constexpr (std::Same<std::remove_reference_t<value_type>, long double>)
786  {
787  tmp = strtold(start, &end);
788  }
789 
790  if (errno == ERANGE)
791  {
792  return {last, std::errc::result_out_of_range};
793  }
794  else if (tmp == 0 && end == first)
795  {
796  return {last, std::errc::invalid_argument};
797  }
798 
799  // Success.
800  value = tmp;
801  return {last, {}};
802 }
803 
804 } // namespace seqan3::detail
auto const convert
A view that converts each element in the input range (implicitly or via static_cast).
Definition: convert.hpp:89
Provides concepts for core language types and relations that don&#39;t have concepts in C++20 (yet)...
Result type of std::to_chars.
Definition: charconv:66
constexpr nucleotide_type complement(nucleotide_type const alph) requires requires(nucleotide_type alph)
Implementation of seqan3::nucleotide_concept::complement() that delegates to a member function...
Definition: member_exposure.hpp:220
Fixed number of digits for precision.
Result type of std::from_chars.
Definition: charconv:74
Hexadecimal notation. Ff specified in from_chars, prefix 0x,0X,x is not allowed.
The Concepts library.
chars_format
A BitmaskType used to specify floating-point formatting for std::to_chars and std::from_chars.
Definition: charconv:82
The concept std::Same<T, U> is satisfied if and only if T and U denote the same type.
Definition: aligned_sequence_concept.hpp:288
Provides C++20 additions to the type_traits header.
Scientific notation, e.g. 3.991E-0003.
General use case.
Provides parse conditions for tokenization.
The concept std::UnsignedIntegral is satisfied if and only if T is an integral type and std::is_signe...
::ranges::end end
Alias for ranges::end. Returns an iterator to the end of a range.
Definition: ranges:190