[libcxx-commits] [libcxx] a15ae41 - [libc++] Make to_chars base 10 header only.

Mark de Wever via libcxx-commits libcxx-commits at lists.llvm.org
Wed Jun 1 23:00:37 PDT 2022


Author: Mark de Wever
Date: 2022-06-02T08:00:31+02:00
New Revision: a15ae4139ceaa03c74089b727d91e39e772a94fb

URL: https://github.com/llvm/llvm-project/commit/a15ae4139ceaa03c74089b727d91e39e772a94fb
DIFF: https://github.com/llvm/llvm-project/commit/a15ae4139ceaa03c74089b727d91e39e772a94fb.diff

LOG: [libc++] Make to_chars base 10 header only.

The functions to_chars and from_chars should offer 128-bit support. This
is the first step to implement 128-bit version of to_chars. Before
implementing 128-bit support the current code will be polished.

This moves the code from the dylib to the header in prepartion of

P2291 "Add Constexpr Modifiers to Functions to_chars and from_chars for
Integral Types in <charconv> Header"

Note some more cleanups will be done in follow-up commits
- Remove the _LIBCPP_AVAILABILITY_TO_CHARS from to_chars. With all code
  in the header the availablilty macro is no longer needed. This
  requires enabling the unit tests for additional platforms.
- The code in the dylib can switch to using the header implementation.
  This allows removing the code duplicated in the header and the dylib.

Reviewed By: #libc, ldionne

Differential Revision: https://reviews.llvm.org/D125704

Added: 
    libcxx/include/__charconv/tables.h
    libcxx/include/__charconv/to_chars_base_10.h

Modified: 
    libcxx/include/CMakeLists.txt
    libcxx/include/charconv
    libcxx/include/module.modulemap
    libcxx/src/charconv.cpp
    libcxx/test/libcxx/private_headers.verify.cpp

Removed: 
    


################################################################################
diff  --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index bf1c41e05c2b5..4931ec8faae9d 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -139,6 +139,8 @@ set(files
   __bsd_locale_fallbacks.h
   __charconv/chars_format.h
   __charconv/from_chars_result.h
+  __charconv/tables.h
+  __charconv/to_chars_base_10.h
   __charconv/to_chars_result.h
   __chrono/calendar.h
   __chrono/convert_to_timespec.h

diff  --git a/libcxx/include/__charconv/tables.h b/libcxx/include/__charconv/tables.h
new file mode 100644
index 0000000000000..c9cceee825f24
--- /dev/null
+++ b/libcxx/include/__charconv/tables.h
@@ -0,0 +1,51 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBCPP___CHARCONV_TABLES
+#define _LIBCPP___CHARCONV_TABLES
+
+#include <__config>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+#  pragma GCC system_header
+#endif
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+#ifndef _LIBCPP_CXX03_LANG
+
+namespace __itoa {
+
+template <class = void>
+struct __digits_base_10 {
+  static const char __value[200];
+};
+
+template <class _Tp>
+const char __digits_base_10<_Tp>::__value[200] = {
+    // clang-format off
+    '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'};
+// clang-format on
+
+} // namespace __itoa
+
+#endif // _LIBCPP_CXX03_LANG
+
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP___CHARCONV_TABLES

diff  --git a/libcxx/include/__charconv/to_chars_base_10.h b/libcxx/include/__charconv/to_chars_base_10.h
new file mode 100644
index 0000000000000..3f689ec1050f9
--- /dev/null
+++ b/libcxx/include/__charconv/to_chars_base_10.h
@@ -0,0 +1,128 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBCPP___CHARCONV_TO_CHARS_BASE_10_H
+#define _LIBCPP___CHARCONV_TO_CHARS_BASE_10_H
+
+#include <__charconv/tables.h>
+#include <__config>
+#include <cstdint>
+#include <cstring>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+#  pragma GCC system_header
+#endif
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+#ifndef _LIBCPP_CXX03_LANG
+
+namespace __itoa {
+
+template <class _Tp>
+_LIBCPP_HIDE_FROM_ABI char* __append1(char* __buffer, _Tp __value) noexcept {
+  *__buffer = '0' + static_cast<char>(__value);
+  return __buffer + 1;
+}
+
+template <class _Tp>
+_LIBCPP_HIDE_FROM_ABI char* __append2(char* __buffer, _Tp __value) noexcept {
+  std::memcpy(__buffer, &__digits_base_10<>::__value[(__value)*2], 2);
+  return __buffer + 2;
+}
+
+template <class _Tp>
+_LIBCPP_HIDE_FROM_ABI char* __append3(char* __buffer, _Tp __value) noexcept {
+  return __itoa::__append2(__itoa::__append1(__buffer, (__value) / 100), (__value) % 100);
+}
+
+template <class _Tp>
+_LIBCPP_HIDE_FROM_ABI char* __append4(char* __buffer, _Tp __value) noexcept {
+  return __itoa::__append2(__itoa::__append2(__buffer, (__value) / 100), (__value) % 100);
+}
+
+template <class _Tp>
+_LIBCPP_HIDE_FROM_ABI char* __append2_no_zeros(char* __buffer, _Tp __value) noexcept {
+  if (__value < 10)
+    return __itoa::__append1(__buffer, __value);
+  else
+    return __itoa::__append2(__buffer, __value);
+}
+
+template <class _Tp>
+_LIBCPP_HIDE_FROM_ABI char* __append4_no_zeros(char* __buffer, _Tp __value) noexcept {
+  if (__value < 100)
+    return __itoa::__append2_no_zeros(__buffer, __value);
+  else if (__value < 1000)
+    return __itoa::__append3(__buffer, __value);
+  else
+    return __itoa::__append4(__buffer, __value);
+}
+
+template <class _Tp>
+_LIBCPP_HIDE_FROM_ABI char* __append8_no_zeros(char* __buffer, _Tp __value) noexcept {
+  if (__value < 10000)
+    __buffer = __itoa::__append4_no_zeros(__buffer, __value);
+  else {
+    __buffer = __itoa::__append4_no_zeros(__buffer, __value / 10000);
+    __buffer = __itoa::__append4(__buffer, __value % 10000);
+  }
+  return __buffer;
+}
+
+_LIBCPP_HIDE_FROM_ABI inline char* __base_10_u32(uint32_t __value, char* __buffer) noexcept {
+  if (__value < 100000000)
+    __buffer = __itoa::__append8_no_zeros(__buffer, __value);
+  else {
+    // __value = aabbbbcccc in decimal
+    const uint32_t __a = __value / 100000000; // 1 to 42
+    __value %= 100000000;
+
+    __buffer = __itoa::__append2_no_zeros(__buffer, __a);
+    __buffer = __itoa::__append4(__buffer, __value / 10000);
+    __buffer = __itoa::__append4(__buffer, __value % 10000);
+  }
+
+  return __buffer;
+}
+
+_LIBCPP_HIDE_FROM_ABI inline char* __base_10_u64(uint64_t __value, char* __buffer) noexcept {
+  if (__value < 100000000)
+    __buffer = __itoa::__append8_no_zeros(__buffer, static_cast<uint32_t>(__value));
+  else if (__value < 10000000000000000) {
+    const uint32_t __v0 = static_cast<uint32_t>(__value / 100000000);
+    const uint32_t __v1 = static_cast<uint32_t>(__value % 100000000);
+
+    __buffer = __itoa::__append8_no_zeros(__buffer, __v0);
+    __buffer = __itoa::__append4(__buffer, __v1 / 10000);
+    __buffer = __itoa::__append4(__buffer, __v1 % 10000);
+  } else {
+    const uint32_t __a = static_cast<uint32_t>(__value / 10000000000000000); // 1 to 1844
+    __value %= 10000000000000000;
+
+    __buffer = __itoa::__append4_no_zeros(__buffer, __a);
+
+    const uint32_t __v0 = static_cast<uint32_t>(__value / 100000000);
+    const uint32_t __v1 = static_cast<uint32_t>(__value % 100000000);
+    __buffer = __itoa::__append4(__buffer, __v0 / 10000);
+    __buffer = __itoa::__append4(__buffer, __v0 % 10000);
+    __buffer = __itoa::__append4(__buffer, __v1 / 10000);
+    __buffer = __itoa::__append4(__buffer, __v1 % 10000);
+  }
+
+  return __buffer;
+}
+
+} // namespace __itoa
+
+#endif // _LIBCPP_CXX03_LANG
+
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP___CHARCONV_TO_CHARS_BASE_10_H

diff  --git a/libcxx/include/charconv b/libcxx/include/charconv
index d5e485a367513..8b80d5b07b36f 100644
--- a/libcxx/include/charconv
+++ b/libcxx/include/charconv
@@ -82,6 +82,8 @@ namespace std {
 #include <__bits>
 #include <__charconv/chars_format.h>
 #include <__charconv/from_chars_result.h>
+#include <__charconv/tables.h>
+#include <__charconv/to_chars_base_10.h>
 #include <__charconv/to_chars_result.h>
 #include <__config>
 #include <__debug>
@@ -105,11 +107,6 @@ _LIBCPP_BEGIN_NAMESPACE_STD
 
 #ifndef _LIBCPP_CXX03_LANG
 
-namespace __itoa {
-_LIBCPP_AVAILABILITY_TO_CHARS _LIBCPP_FUNC_VIS char* __u64toa(uint64_t __value, char* __buffer) noexcept;
-_LIBCPP_AVAILABILITY_TO_CHARS _LIBCPP_FUNC_VIS char* __u32toa(uint32_t __value, char* __buffer) noexcept;
-} // namespace __itoa
-
 to_chars_result to_chars(char*, char*, bool, int = 10) = delete;
 from_chars_result from_chars(const char*, const char*, bool, int = 10) = delete;
 
@@ -160,7 +157,7 @@ struct _LIBCPP_HIDDEN __traits_base
     _LIBCPP_AVAILABILITY_TO_CHARS
     static _LIBCPP_HIDE_FROM_ABI char* __convert(_Tp __v, char* __p)
     {
-        return __u64toa(__v, __p);
+        return __itoa::__base_10_u64(__v, __p);
     }
 
     static _LIBCPP_HIDE_FROM_ABI decltype(__pow10_64)& __pow() { return __pow10_64; }
@@ -181,7 +178,7 @@ struct _LIBCPP_HIDDEN
     _LIBCPP_AVAILABILITY_TO_CHARS
     static _LIBCPP_HIDE_FROM_ABI char* __convert(_Tp __v, char* __p)
     {
-        return __u32toa(__v, __p);
+        return __itoa::__base_10_u32(__v, __p);
     }
 
     static _LIBCPP_HIDE_FROM_ABI decltype(__pow10_32)& __pow() { return __pow10_32; }

diff  --git a/libcxx/include/module.modulemap b/libcxx/include/module.modulemap
index ba1d0ffd49f6c..e24c38704a56a 100644
--- a/libcxx/include/module.modulemap
+++ b/libcxx/include/module.modulemap
@@ -403,6 +403,8 @@ module std [system] {
     module __charconv {
       module chars_format      { private header "__charconv/chars_format.h" }
       module from_chars_result { private header "__charconv/from_chars_result.h" }
+      module tables            { private header "__charconv/tables.h" }
+      module to_chars_base_10  { private header "__charconv/to_chars_base_10.h" }
       module to_chars_result   { private header "__charconv/to_chars_result.h" }
     }
 

diff  --git a/libcxx/src/charconv.cpp b/libcxx/src/charconv.cpp
index 9537b42de7fc3..2e5e80934fe69 100644
--- a/libcxx/src/charconv.cpp
+++ b/libcxx/src/charconv.cpp
@@ -85,7 +85,7 @@ append8_no_zeros(char* buffer, T v) noexcept
     return buffer;
 }
 
-char*
+_LIBCPP_FUNC_VIS char*
 __u32toa(uint32_t value, char* buffer) noexcept
 {
     if (value < 100000000)
@@ -106,7 +106,7 @@ __u32toa(uint32_t value, char* buffer) noexcept
     return buffer;
 }
 
-char*
+_LIBCPP_FUNC_VIS char*
 __u64toa(uint64_t value, char* buffer) noexcept
 {
     if (value < 100000000)

diff  --git a/libcxx/test/libcxx/private_headers.verify.cpp b/libcxx/test/libcxx/private_headers.verify.cpp
index 121e4d9d98778..78e4b61a19381 100644
--- a/libcxx/test/libcxx/private_headers.verify.cpp
+++ b/libcxx/test/libcxx/private_headers.verify.cpp
@@ -173,6 +173,8 @@ END-SCRIPT
 #include <__bits> // expected-error@*:* {{use of private header from outside its module: '__bits'}}
 #include <__charconv/chars_format.h> // expected-error@*:* {{use of private header from outside its module: '__charconv/chars_format.h'}}
 #include <__charconv/from_chars_result.h> // expected-error@*:* {{use of private header from outside its module: '__charconv/from_chars_result.h'}}
+#include <__charconv/tables.h> // expected-error@*:* {{use of private header from outside its module: '__charconv/tables.h'}}
+#include <__charconv/to_chars_base_10.h> // expected-error@*:* {{use of private header from outside its module: '__charconv/to_chars_base_10.h'}}
 #include <__charconv/to_chars_result.h> // expected-error@*:* {{use of private header from outside its module: '__charconv/to_chars_result.h'}}
 #include <__chrono/calendar.h> // expected-error@*:* {{use of private header from outside its module: '__chrono/calendar.h'}}
 #include <__chrono/convert_to_timespec.h> // expected-error@*:* {{use of private header from outside its module: '__chrono/convert_to_timespec.h'}}


        


More information about the libcxx-commits mailing list