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