lichray created this revision.
lichray added reviewers: mclow.lists, EricWF.
Herald added a subscriber: mgorny.

Progress: std::to_chars for integers
Missing: std::from_chars

References:
 https://wg21.link/p0067r5
 https://wg21.link/p0682r1


Repository:
  rCXX libc++

https://reviews.llvm.org/D41458

Files:
  .gitignore
  include/charconv
  include/support/itoa/
  include/support/itoa/itoa.h
  lib/CMakeLists.txt
  src/support/itoa/
  src/support/itoa/itoa.cpp
  test/std/utilities/charconv/
  test/std/utilities/charconv/charconv.to.chars/
  test/std/utilities/charconv/charconv.to.chars/integral.bool.fail.cpp
  test/std/utilities/charconv/charconv.to.chars/integral.pass.cpp

Index: test/std/utilities/charconv/charconv.to.chars/integral.pass.cpp
===================================================================
--- /dev/null
+++ test/std/utilities/charconv/charconv.to.chars/integral.pass.cpp
@@ -0,0 +1,87 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+// <charconv>
+
+// to_chars_result to_chars(char* first, char* last, Integral value,
+//                          int base = 10)
+
+#include "charconv_test_helpers.h"
+
+template <typename T>
+struct test_basics : to_chars_test_base<T>
+{
+    using to_chars_test_base<T>::test;
+    using to_chars_test_base<T>::test_value;
+
+    void operator()()
+    {
+
+        test(0, "0");
+        test(42, "42");
+        test(32768, "32768");
+        test(0, "0", 10);
+        test(42, "42", 10);
+        test(32768, "32768", 10);
+        test(0xf, "f", 16);
+        test(0xdeadbeaf, "deadbeaf", 16);
+        test(0755, "755", 8);
+
+        for (int b = 2; b < 37; ++b)
+        {
+            using xl = std::numeric_limits<T>;
+
+            test_value(1, b);
+            test_value(xl::lowest(), b);
+            test_value((xl::max)(), b);
+            test_value((xl::max)() / 2, b);
+        }
+    }
+};
+
+template <typename T>
+struct test_signed : to_chars_test_base<T>
+{
+    using to_chars_test_base<T>::test;
+    using to_chars_test_base<T>::test_value;
+
+    void operator()()
+    {
+        test(-1, "-1");
+        test(-12, "-12");
+        test(-1, "-1", 10);
+        test(-12, "-12", 10);
+        test(-21734634, "-21734634", 10);
+        test(-2647, "-101001010111", 2);
+        test(-0xcc1, "-cc1", 16);
+
+        for (int b = 2; b < 37; ++b)
+        {
+            using xl = std::numeric_limits<T>;
+
+            test_value(0, b);
+            test_value(xl::lowest(), b);
+            test_value((xl::max)(), b);
+        }
+    }
+};
+
+int
+main()
+{
+    auto all_signed =
+        type_list<char, signed char, short, int, long, long long>();
+    auto all_unsigned = type_list<unsigned char, unsigned short, unsigned int,
+                                  unsigned long, unsigned long long>();
+    auto integrals = concat(all_signed, all_unsigned);
+
+    run<test_basics>(integrals);
+    run<test_signed>(all_signed);
+}
Index: test/std/utilities/charconv/charconv.to.chars/integral.bool.fail.cpp
===================================================================
--- /dev/null
+++ test/std/utilities/charconv/charconv.to.chars/integral.bool.fail.cpp
@@ -0,0 +1,30 @@
+//===----------------------------------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+// <charconv>
+
+// In
+//
+// to_chars_result to_chars(char* first, char* last, Integral value,
+//                          int base = 10)
+//
+// Integral cannot be bool.
+
+#include <charconv>
+
+int main()
+{
+    using std::to_chars;
+    char buf[10];
+    bool lv = true;
+
+    to_chars(buf, buf + sizeof(buf), false);   // expected-error {{call to deleted function}}
+    to_chars(buf, buf + sizeof(buf), lv, 16);  // expected-error {{call to deleted function}}
+}
Index: src/support/itoa/itoa.cpp
===================================================================
--- /dev/null
+++ src/support/itoa/itoa.cpp
@@ -0,0 +1,296 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#include <support/itoa/itoa.h>
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+namespace __itoa
+{
+
+static const char cDigitsLut[200] = {
+    '0', '0', '0', '1', '0', '2', '0', '3', '0', '4', '0', '5', '0', '6', '0',
+    '7', '0', '8', '0', '9', '1', '0', '1', '1', '1', '2', '1', '3', '1', '4',
+    '1', '5', '1', '6', '1', '7', '1', '8', '1', '9', '2', '0', '2', '1', '2',
+    '2', '2', '3', '2', '4', '2', '5', '2', '6', '2', '7', '2', '8', '2', '9',
+    '3', '0', '3', '1', '3', '2', '3', '3', '3', '4', '3', '5', '3', '6', '3',
+    '7', '3', '8', '3', '9', '4', '0', '4', '1', '4', '2', '4', '3', '4', '4',
+    '4', '5', '4', '6', '4', '7', '4', '8', '4', '9', '5', '0', '5', '1', '5',
+    '2', '5', '3', '5', '4', '5', '5', '5', '6', '5', '7', '5', '8', '5', '9',
+    '6', '0', '6', '1', '6', '2', '6', '3', '6', '4', '6', '5', '6', '6', '6',
+    '7', '6', '8', '6', '9', '7', '0', '7', '1', '7', '2', '7', '3', '7', '4',
+    '7', '5', '7', '6', '7', '7', '7', '8', '7', '9', '8', '0', '8', '1', '8',
+    '2', '8', '3', '8', '4', '8', '5', '8', '6', '8', '7', '8', '8', '8', '9',
+    '9', '0', '9', '1', '9', '2', '9', '3', '9', '4', '9', '5', '9', '6', '9',
+    '7', '9', '8', '9', '9'};
+
+char*
+__u32toa(uint32_t value, char* buffer)
+{
+
+    if (value < 10000)
+    {
+        const uint32_t d1 = (value / 100) << 1;
+        const uint32_t d2 = (value % 100) << 1;
+
+        if (value >= 1000)
+            *buffer++ = cDigitsLut[d1];
+        if (value >= 100)
+            *buffer++ = cDigitsLut[d1 + 1];
+        if (value >= 10)
+            *buffer++ = cDigitsLut[d2];
+        *buffer++ = cDigitsLut[d2 + 1];
+    }
+    else if (value < 100000000)
+    {
+        // value = bbbbcccc
+        const uint32_t b = value / 10000;
+        const uint32_t c = value % 10000;
+
+        const uint32_t d1 = (b / 100) << 1;
+        const uint32_t d2 = (b % 100) << 1;
+
+        const uint32_t d3 = (c / 100) << 1;
+        const uint32_t d4 = (c % 100) << 1;
+
+        if (value >= 10000000)
+            *buffer++ = cDigitsLut[d1];
+        if (value >= 1000000)
+            *buffer++ = cDigitsLut[d1 + 1];
+        if (value >= 100000)
+            *buffer++ = cDigitsLut[d2];
+        *buffer++ = cDigitsLut[d2 + 1];
+
+        *buffer++ = cDigitsLut[d3];
+        *buffer++ = cDigitsLut[d3 + 1];
+        *buffer++ = cDigitsLut[d4];
+        *buffer++ = cDigitsLut[d4 + 1];
+    }
+    else
+    {
+        // value = aabbbbcccc in decimal
+
+        const uint32_t a = value / 100000000;  // 1 to 42
+        value %= 100000000;
+
+        if (a >= 10)
+        {
+            const unsigned i = a << 1;
+            *buffer++ = cDigitsLut[i];
+            *buffer++ = cDigitsLut[i + 1];
+        }
+        else
+            *buffer++ = static_cast<char>('0' + static_cast<char>(a));
+
+        const uint32_t b = value / 10000;  // 0 to 9999
+        const uint32_t c = value % 10000;  // 0 to 9999
+
+        const uint32_t d1 = (b / 100) << 1;
+        const uint32_t d2 = (b % 100) << 1;
+
+        const uint32_t d3 = (c / 100) << 1;
+        const uint32_t d4 = (c % 100) << 1;
+
+        *buffer++ = cDigitsLut[d1];
+        *buffer++ = cDigitsLut[d1 + 1];
+        *buffer++ = cDigitsLut[d2];
+        *buffer++ = cDigitsLut[d2 + 1];
+        *buffer++ = cDigitsLut[d3];
+        *buffer++ = cDigitsLut[d3 + 1];
+        *buffer++ = cDigitsLut[d4];
+        *buffer++ = cDigitsLut[d4 + 1];
+    }
+    return buffer;
+}
+
+char*
+__u64toa(uint64_t value, char* buffer)
+{
+    const uint64_t kTen8 = 100000000;
+    const uint64_t kTen9 = kTen8 * 10;
+    const uint64_t kTen10 = kTen8 * 100;
+    const uint64_t kTen11 = kTen8 * 1000;
+    const uint64_t kTen12 = kTen8 * 10000;
+    const uint64_t kTen13 = kTen8 * 100000;
+    const uint64_t kTen14 = kTen8 * 1000000;
+    const uint64_t kTen15 = kTen8 * 10000000;
+    const uint64_t kTen16 = kTen8 * kTen8;
+
+    if (value < kTen8)
+    {
+        uint32_t v = static_cast<uint32_t>(value);
+        if (v < 10000)
+        {
+            const uint32_t d1 = (v / 100) << 1;
+            const uint32_t d2 = (v % 100) << 1;
+
+            if (v >= 1000)
+                *buffer++ = cDigitsLut[d1];
+            if (v >= 100)
+                *buffer++ = cDigitsLut[d1 + 1];
+            if (v >= 10)
+                *buffer++ = cDigitsLut[d2];
+            *buffer++ = cDigitsLut[d2 + 1];
+        }
+        else
+        {
+            // value = bbbbcccc
+            const uint32_t b = v / 10000;
+            const uint32_t c = v % 10000;
+
+            const uint32_t d1 = (b / 100) << 1;
+            const uint32_t d2 = (b % 100) << 1;
+
+            const uint32_t d3 = (c / 100) << 1;
+            const uint32_t d4 = (c % 100) << 1;
+
+            if (value >= 10000000)
+                *buffer++ = cDigitsLut[d1];
+            if (value >= 1000000)
+                *buffer++ = cDigitsLut[d1 + 1];
+            if (value >= 100000)
+                *buffer++ = cDigitsLut[d2];
+            *buffer++ = cDigitsLut[d2 + 1];
+
+            *buffer++ = cDigitsLut[d3];
+            *buffer++ = cDigitsLut[d3 + 1];
+            *buffer++ = cDigitsLut[d4];
+            *buffer++ = cDigitsLut[d4 + 1];
+        }
+    }
+    else if (value < kTen16)
+    {
+        const uint32_t v0 = static_cast<uint32_t>(value / kTen8);
+        const uint32_t v1 = static_cast<uint32_t>(value % kTen8);
+
+        const uint32_t b0 = v0 / 10000;
+        const uint32_t c0 = v0 % 10000;
+
+        const uint32_t d1 = (b0 / 100) << 1;
+        const uint32_t d2 = (b0 % 100) << 1;
+
+        const uint32_t d3 = (c0 / 100) << 1;
+        const uint32_t d4 = (c0 % 100) << 1;
+
+        const uint32_t b1 = v1 / 10000;
+        const uint32_t c1 = v1 % 10000;
+
+        const uint32_t d5 = (b1 / 100) << 1;
+        const uint32_t d6 = (b1 % 100) << 1;
+
+        const uint32_t d7 = (c1 / 100) << 1;
+        const uint32_t d8 = (c1 % 100) << 1;
+
+        if (value >= kTen15)
+            *buffer++ = cDigitsLut[d1];
+        if (value >= kTen14)
+            *buffer++ = cDigitsLut[d1 + 1];
+        if (value >= kTen13)
+            *buffer++ = cDigitsLut[d2];
+        if (value >= kTen12)
+            *buffer++ = cDigitsLut[d2 + 1];
+        if (value >= kTen11)
+            *buffer++ = cDigitsLut[d3];
+        if (value >= kTen10)
+            *buffer++ = cDigitsLut[d3 + 1];
+        if (value >= kTen9)
+            *buffer++ = cDigitsLut[d4];
+        if (value >= kTen8)
+            *buffer++ = cDigitsLut[d4 + 1];
+
+        *buffer++ = cDigitsLut[d5];
+        *buffer++ = cDigitsLut[d5 + 1];
+        *buffer++ = cDigitsLut[d6];
+        *buffer++ = cDigitsLut[d6 + 1];
+        *buffer++ = cDigitsLut[d7];
+        *buffer++ = cDigitsLut[d7 + 1];
+        *buffer++ = cDigitsLut[d8];
+        *buffer++ = cDigitsLut[d8 + 1];
+    }
+    else
+    {
+        const uint32_t a = static_cast<uint32_t>(value / kTen16);  // 1 to 1844
+        value %= kTen16;
+
+        if (a < 10)
+            *buffer++ = static_cast<char>('0' + static_cast<char>(a));
+        else if (a < 100)
+        {
+            const uint32_t i = a << 1;
+            *buffer++ = cDigitsLut[i];
+            *buffer++ = cDigitsLut[i + 1];
+        }
+        else if (a < 1000)
+        {
+            *buffer++ = static_cast<char>('0' + static_cast<char>(a / 100));
+
+            const uint32_t i = (a % 100) << 1;
+            *buffer++ = cDigitsLut[i];
+            *buffer++ = cDigitsLut[i + 1];
+        }
+        else
+        {
+            const uint32_t i = (a / 100) << 1;
+            const uint32_t j = (a % 100) << 1;
+            *buffer++ = cDigitsLut[i];
+            *buffer++ = cDigitsLut[i + 1];
+            *buffer++ = cDigitsLut[j];
+            *buffer++ = cDigitsLut[j + 1];
+        }
+
+        const uint32_t v0 = static_cast<uint32_t>(value / kTen8);
+        const uint32_t v1 = static_cast<uint32_t>(value % kTen8);
+
+        const uint32_t b0 = v0 / 10000;
+        const uint32_t c0 = v0 % 10000;
+
+        const uint32_t d1 = (b0 / 100) << 1;
+        const uint32_t d2 = (b0 % 100) << 1;
+
+        const uint32_t d3 = (c0 / 100) << 1;
+        const uint32_t d4 = (c0 % 100) << 1;
+
+        const uint32_t b1 = v1 / 10000;
+        const uint32_t c1 = v1 % 10000;
+
+        const uint32_t d5 = (b1 / 100) << 1;
+        const uint32_t d6 = (b1 % 100) << 1;
+
+        const uint32_t d7 = (c1 / 100) << 1;
+        const uint32_t d8 = (c1 % 100) << 1;
+
+        *buffer++ = cDigitsLut[d1];
+        *buffer++ = cDigitsLut[d1 + 1];
+        *buffer++ = cDigitsLut[d2];
+        *buffer++ = cDigitsLut[d2 + 1];
+        *buffer++ = cDigitsLut[d3];
+        *buffer++ = cDigitsLut[d3 + 1];
+        *buffer++ = cDigitsLut[d4];
+        *buffer++ = cDigitsLut[d4 + 1];
+        *buffer++ = cDigitsLut[d5];
+        *buffer++ = cDigitsLut[d5 + 1];
+        *buffer++ = cDigitsLut[d6];
+        *buffer++ = cDigitsLut[d6 + 1];
+        *buffer++ = cDigitsLut[d7];
+        *buffer++ = cDigitsLut[d7 + 1];
+        *buffer++ = cDigitsLut[d8];
+        *buffer++ = cDigitsLut[d8 + 1];
+    }
+
+    return buffer;
+}
+
+}  // namespace __itoa
+
+_LIBCPP_END_NAMESPACE_STD
Index: lib/CMakeLists.txt
===================================================================
--- lib/CMakeLists.txt
+++ lib/CMakeLists.txt
@@ -2,7 +2,7 @@
 
 # Get sources
 # FIXME: Don't use glob here
-file(GLOB LIBCXX_SOURCES ../src/*.cpp)
+file(GLOB LIBCXX_SOURCES ../src/*.cpp ../src/support/itoa/*.cpp)
 if(WIN32)
   file(GLOB LIBCXX_WIN32_SOURCES ../src/support/win32/*.cpp)
   list(APPEND LIBCXX_SOURCES ${LIBCXX_WIN32_SOURCES})
Index: include/support/itoa/itoa.h
===================================================================
--- /dev/null
+++ include/support/itoa/itoa.h
@@ -0,0 +1,115 @@
+// -*- C++ -*-
+//===--------------------- support/itoa/itoa.h ----------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBCPP_SUPPORT_ITOA_ITOA_H
+#define _LIBCPP_SUPPORT_ITOA_ITOA_H
+
+#include <__config>
+#include <type_traits>
+#include <limits>
+#include <stdint.h>
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+namespace __itoa
+{
+
+#if __has_builtin(__builtin_clzll)
+
+inline _LIBCPP_INLINE_VISIBILITY auto
+__u64digits10(uint64_t __x) -> int
+{
+    constexpr uint64_t __pow10[] = {
+        UINT64_C(0),
+        UINT64_C(10),
+        UINT64_C(100),
+        UINT64_C(1000),
+        UINT64_C(10000),
+        UINT64_C(100000),
+        UINT64_C(1000000),
+        UINT64_C(10000000),
+        UINT64_C(100000000),
+        UINT64_C(1000000000),
+        UINT64_C(10000000000),
+        UINT64_C(100000000000),
+        UINT64_C(1000000000000),
+        UINT64_C(10000000000000),
+        UINT64_C(100000000000000),
+        UINT64_C(1000000000000000),
+        UINT64_C(10000000000000000),
+        UINT64_C(100000000000000000),
+        UINT64_C(1000000000000000000),
+        UINT64_C(10000000000000000000),
+    };
+
+    auto __t = (64 - __builtin_clzll(__x | 1)) * 1233 >> 12;
+    return __t - (__x < __pow10[__t]) + 1;
+}
+
+inline _LIBCPP_INLINE_VISIBILITY auto
+__u32digits10(uint32_t __x) -> int
+{
+    constexpr uint32_t __pow10[] = {
+        UINT32_C(0),          UINT32_C(10),       UINT32_C(100),
+        UINT32_C(1000),       UINT32_C(10000),    UINT32_C(100000),
+        UINT32_C(1000000),    UINT32_C(10000000), UINT32_C(100000000),
+        UINT32_C(1000000000),
+    };
+
+    auto __t = (32 - __builtin_clz(__x | 1)) * 1233 >> 12;
+    return __t - (__x < __pow10[__t]) + 1;
+}
+
+#endif
+
+extern _LIBCPP_FUNC_VIS char* __u64toa(uint64_t __value, char* __buffer);
+extern _LIBCPP_FUNC_VIS char* __u32toa(uint32_t __value, char* __buffer);
+
+template <typename _Tp, typename = void>
+struct _LIBCPP_HIDDEN traits
+{
+    static constexpr int digits = numeric_limits<_Tp>::digits10 + 1;
+
+#if __has_builtin(__builtin_clzll)
+    static _LIBCPP_INLINE_VISIBILITY auto width(_Tp __v) -> int
+    {
+        return __u64digits10(__v);
+    }
+#endif
+
+    static _LIBCPP_INLINE_VISIBILITY auto convert(_Tp __v, char* __p) -> char*
+    {
+        return __u64toa(__v, __p);
+    }
+};
+
+template <typename _Tp>
+struct _LIBCPP_HIDDEN traits<_Tp, decltype(void(uint32_t{declval<_Tp>()}))>
+{
+    static constexpr int digits = numeric_limits<_Tp>::digits10 + 1;
+
+#if __has_builtin(__builtin_clzll)
+    static _LIBCPP_INLINE_VISIBILITY auto width(_Tp __v) -> int
+    {
+        return __u32digits10(__v);
+    }
+#endif
+
+    static _LIBCPP_INLINE_VISIBILITY auto convert(_Tp __v, char* __p) -> char*
+    {
+        return __u32toa(__v, __p);
+    }
+};
+
+}  // namespace __itoa
+
+_LIBCPP_END_NAMESPACE_STD
+
+#endif  // _LIBCPP_SUPPORT_ITOA_ITOA_H
Index: include/charconv
===================================================================
--- /dev/null
+++ include/charconv
@@ -0,0 +1,259 @@
+// -*- C++ -*-
+//===------------------------------ charconv ------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBCPP_CHARCONV
+#define _LIBCPP_CHARCONV
+
+/*
+    charconv synopsis
+
+namespace std {
+
+  // floating-point format for primitive numerical conversion
+  enum class chars_format {
+    scientific = unspecified,
+    fixed = unspecified,
+    hex = unspecified,
+    general = fixed | scientific
+  };
+
+  // 23.20.2, primitive numerical output conversion
+  struct to_chars_result {
+    char* ptr;
+    errc ec;
+  };
+
+  to_chars_result to_chars(char* first, char* last, see below value,
+                           int base = 10);
+
+  to_chars_result to_chars(char* first, char* last, float value);
+  to_chars_result to_chars(char* first, char* last, double value);
+  to_chars_result to_chars(char* first, char* last, long double value);
+
+  to_chars_result to_chars(char* first, char* last, float value,
+                           chars_format fmt);
+  to_chars_result to_chars(char* first, char* last, double value,
+                           chars_format fmt);
+  to_chars_result to_chars(char* first, char* last, long double value,
+                           chars_format fmt);
+
+  to_chars_result to_chars(char* first, char* last, float value,
+                           chars_format fmt, int precision);
+  to_chars_result to_chars(char* first, char* last, double value,
+                           chars_format fmt, int precision);
+  to_chars_result to_chars(char* first, char* last, long double value,
+                           chars_format fmt, int precision);
+
+  // 23.20.3, primitive numerical input conversion
+  struct from_chars_result {
+    const char* ptr;
+    errc ec;
+  };
+
+  from_chars_result from_chars(const char* first, const char* last,
+                               see below& value, int base = 10);
+
+  from_chars_result from_chars(const char* first, const char* last,
+                               float& value,
+                               chars_format fmt = chars_format::general);
+  from_chars_result from_chars(const char* first, const char* last,
+                               double& value,
+                               chars_format fmt = chars_format::general);
+  from_chars_result from_chars(const char* first, const char* last,
+                               long double& value,
+                               chars_format fmt = chars_format::general);
+
+} // namespace std
+
+*/
+
+#include <__errc>
+#include <support/itoa/itoa.h>
+#include <string.h>
+
+#include <__debug>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+#pragma GCC system_header
+#endif
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+enum class _LIBCPP_ENUM_VIS chars_format
+{
+    scientific = 0x1,
+    fixed = 0x2,
+    hex = 0x4,
+    general = fixed | scientific
+};
+
+struct _LIBCPP_TYPE_VIS to_chars_result
+{
+    char* ptr;
+    errc ec;
+};
+
+struct _LIBCPP_TYPE_VIS from_chars_result
+{
+    const char* ptr;
+    errc ec;
+};
+
+void to_chars(char*, char*, bool, int = 10) = delete;
+void from_chars(const char*, const char*, bool, int = 10) = delete;
+
+template <typename _Tp>
+inline _LIBCPP_INLINE_VISIBILITY auto
+__complement(_Tp __x) -> _Tp
+{
+    static_assert(is_unsigned<_Tp>::value, "cast to unsigned first");
+    return _Tp(~__x + 1);
+}
+
+template <typename _Tp>
+inline _LIBCPP_INLINE_VISIBILITY auto
+__to_unsigned(_Tp __x) -> typename make_unsigned<_Tp>::type
+{
+    return static_cast<typename make_unsigned<_Tp>::type>(__x);
+}
+
+template <typename _Tp>
+inline _LIBCPP_INLINE_VISIBILITY auto
+__to_chars_itoa(char* __first, char* __last, _Tp __value, true_type)
+    -> to_chars_result
+{
+    auto __x = __to_unsigned(__value);
+    if (__value < 0 && __first != __last)
+    {
+        *__first++ = '-';
+        __x = __complement(__x);
+    }
+
+    return __to_chars_itoa(__first, __last, __x, false_type());
+}
+
+template <typename _Tp>
+inline _LIBCPP_INLINE_VISIBILITY auto
+__to_chars_itoa(char* __first, char* __last, _Tp __value, false_type)
+    -> to_chars_result
+{
+    using __tx = __itoa::traits<_Tp>;
+    auto __diff = __last - __first;
+
+#if __has_builtin(__builtin_clzll)
+    if (__tx::digits <= __diff || __tx::width(__value) <= __diff)
+        return {__tx::convert(__value, __first), {}};
+    else
+        return {__last, errc::value_too_large};
+#else
+    if (__tx::digits <= __diff)
+        return {__tx::convert(__value, __first), {}};
+    else
+    {
+        char __buf[__tx::digits];
+        auto __p = __tx::convert(__value, __buf);
+        auto __len = __p - __buf;
+        if (__len <= __diff)
+        {
+            memcpy(__first, __buf, __len);
+            return {__first + __len, {}};
+        }
+        else
+            return {__last, errc::value_too_large};
+    }
+#endif
+}
+
+template <typename _Tp>
+inline _LIBCPP_INLINE_VISIBILITY auto
+__to_chars_integral(char* __first, char* __last, _Tp __value, int __base,
+                    true_type) -> to_chars_result
+{
+    auto __x = __to_unsigned(__value);
+    if (__value < 0 && __first != __last)
+    {
+        *__first++ = '-';
+        __x = __complement(__x);
+    }
+
+    return __to_chars_integral(__first, __last, __x, __base, false_type());
+}
+
+template <typename _Tp>
+inline _LIBCPP_INLINE_VISIBILITY auto
+__to_chars_integral(char* __first, char* __last, _Tp __value, int __base,
+                    false_type) -> to_chars_result
+{
+    if (__base == 10)
+        return __to_chars_itoa(__first, __last, __value, false_type());
+
+    // XXX assuming ASCII-compatible basic character sets
+    auto __gen_digit = [](_Tp __c) {
+        return char(__c + (__c < 10 ? '0' : 'a' - 10));
+    };
+
+    auto __reverse_buffer = [](char* __first, char* __last) {
+        for (; __first < --__last; ++__first)
+            _VSTD::iter_swap(__first, __last);
+    };
+
+    auto __p = __first;
+    while (__p != __last)
+    {
+        auto __c = __value % __base;
+        __value /= __base;
+        *__p++ = __gen_digit(__c);
+        if (__value == 0)
+            break;
+    }
+
+    if (__value != 0 || __p == __first)
+        return {__p, errc::value_too_large};
+    else
+    {
+        __reverse_buffer(__first, __p);
+        return {__p, {}};
+    }
+}
+
+template <typename _Tp,
+          typename enable_if<is_integral<_Tp>::value, int>::type = 0>
+inline _LIBCPP_INLINE_VISIBILITY auto
+to_chars(char* __first, char* __last, _Tp __value) -> to_chars_result
+{
+    return __to_chars_itoa(__first, __last, __value, is_signed<_Tp>());
+}
+
+template <typename _Tp,
+          typename enable_if<is_integral<_Tp>::value, int>::type = 0>
+inline _LIBCPP_INLINE_VISIBILITY auto
+to_chars(char* __first, char* __last, _Tp __value, int __base)
+    -> to_chars_result
+{
+    _LIBCPP_ASSERT(2 <= __base && __base <= 36, "base not in [2, 36]");
+    return __to_chars_integral(__first, __last, __value, __base,
+                               is_signed<_Tp>());
+}
+
+template <typename _Tp,
+          typename enable_if<is_integral<_Tp>::value, int>::type = 0>
+inline _LIBCPP_INLINE_VISIBILITY auto
+from_chars(const char* __first, const char* __last, _Tp& __value)
+    -> from_chars_result;
+
+template <typename _Tp,
+          typename enable_if<is_integral<_Tp>::value, int>::type = 0>
+inline _LIBCPP_INLINE_VISIBILITY auto
+from_chars(const char* __first, const char* __last, _Tp& __value, int __base)
+    -> from_chars_result;
+
+_LIBCPP_END_NAMESPACE_STD
+
+#endif  // _LIBCPP_CHARCONV
Index: .gitignore
===================================================================
--- .gitignore
+++ .gitignore
@@ -4,6 +4,11 @@
 
 # C extensions
 *.so
+*.core
+
+# Vim
+*~
+.*.swp
 
 # Distribution / packaging
 .Python
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to