You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
	
	
		
			85 lines
		
	
	
		
			2.4 KiB
		
	
	
	
		
			C++
		
	
			
		
		
	
	
			85 lines
		
	
	
		
			2.4 KiB
		
	
	
	
		
			C++
		
	
// -*- c++ -*-
 | 
						|
#pragma once
 | 
						|
 | 
						|
#include <type_traits>
 | 
						|
#include <system_error>
 | 
						|
 | 
						|
namespace std
 | 
						|
{
 | 
						|
 | 
						|
  // TODO: non base-10
 | 
						|
 | 
						|
  struct from_chars_result
 | 
						|
  {
 | 
						|
    const char* ptr;
 | 
						|
    std::errc ec;
 | 
						|
  };
 | 
						|
 | 
						|
  inline constexpr bool _IsSpace(char c) noexcept
 | 
						|
  { return (c >= 9 && c <= 13) || c == ' '; }
 | 
						|
 | 
						|
  template <typename T, typename = std::enable_if_t<std::is_integral_v<T>>>
 | 
						|
  std::from_chars_result from_chars(const char* begin, const char* end,
 | 
						|
                                    T& value)
 | 
						|
  {
 | 
						|
    bool minus = false;
 | 
						|
    while (begin < end && _IsSpace(*begin)) ++begin;
 | 
						|
    if (begin >= end) return { end, errc::invalid_argument };
 | 
						|
    if constexpr (std::is_signed_v<T>)
 | 
						|
      if (*begin == '-')
 | 
						|
      {
 | 
						|
        minus = true;
 | 
						|
        ++begin;
 | 
						|
      }
 | 
						|
 | 
						|
    bool was = false, err = false;;
 | 
						|
    T out{};
 | 
						|
    for (; begin < end && (*begin >= '0' && *begin <= '9'); ++begin)
 | 
						|
    {
 | 
						|
      was = true;
 | 
						|
      T tmp;
 | 
						|
      if (__builtin_mul_overflow(out, 10, &tmp) ||
 | 
						|
          __builtin_add_overflow(tmp, (*begin - '0'), &out))
 | 
						|
        err = true;
 | 
						|
    }
 | 
						|
    if (!was) return { begin, errc::invalid_argument };
 | 
						|
    if (minus && __builtin_sub_overflow(0, out, &out)) err = true;
 | 
						|
 | 
						|
    if (!err) value = out;
 | 
						|
    return { begin, err ? errc::result_out_of_range : errc() };
 | 
						|
  }
 | 
						|
 | 
						|
 | 
						|
  struct to_chars_result
 | 
						|
  {
 | 
						|
    char* ptr;
 | 
						|
    std::errc ec;
 | 
						|
  };
 | 
						|
 | 
						|
  to_chars_result to_chars(char*, char*, bool) = delete;
 | 
						|
  template <typename T, typename = std::enable_if_t<std::is_integral_v<T>>>
 | 
						|
  to_chars_result to_chars(char* begin, char* end, T value)
 | 
						|
  {
 | 
						|
    if (end - begin <= 1) return { end, errc::value_too_large };
 | 
						|
    std::make_unsigned_t<T> uval;
 | 
						|
    if (value < 0) { *begin++ = '-'; uval = -value; }
 | 
						|
    else uval = value;
 | 
						|
 | 
						|
    // On error, returns a value of type to_chars_result holding
 | 
						|
    // std::errc::value_too_large in ec, a copy of the value last in ptr, and
 | 
						|
    // leaves the contents of the range [first, last) in unspecified state.
 | 
						|
    // => so we can construct it in a temporary buffer and only copy back if
 | 
						|
    // everything is alright
 | 
						|
    char buf[std::numeric_limits<T>::digits10+1];
 | 
						|
    auto p = buf + std::numeric_limits<T>::digits10;
 | 
						|
    *p = '0';
 | 
						|
    if (uval) { ++p; for (; uval; uval /= 10) *--p = '0' + uval % 10; }
 | 
						|
 | 
						|
    const auto len = buf + std::numeric_limits<T>::digits10+1 - p;
 | 
						|
    if (len > end-begin) return { end, errc::value_too_large };
 | 
						|
    ::memcpy(begin, p, len);
 | 
						|
    return { begin + len, errc() };
 | 
						|
  }
 | 
						|
 | 
						|
}
 |