[libcxx-commits] [libcxx] [libc++] Move the ctype_base implementation to the locale base API (PR #224251)

Nikolas Klauser via libcxx-commits libcxx-commits at lists.llvm.org
Thu Sep 17 03:00:24 PDT 2026


https://github.com/philnik777 created https://github.com/llvm/llvm-project/pull/224251

`ctype_base` consists mostly of libc-specific configuration. Moving it to a base class in the locale base API significantly simplifies things.


>From 534effab0e37cc58850cfa2fed9de064331d567c Mon Sep 17 00:00:00 2001
From: Nikolas Klauser <nikolasklauser at berlin.de>
Date: Fri, 11 Sep 2026 12:56:22 +0200
Subject: [PATCH] [libc++] Move the ctype_base implementation to the locale
 base API

---
 libcxx/include/CMakeLists.txt                 |   1 +
 libcxx/include/__locale_dir/ctype_base.h      | 146 +-----------------
 libcxx/include/__locale_dir/locale_base_api.h |  70 ++++++++-
 libcxx/include/__locale_dir/support/aix.h     |  26 +++-
 .../include/__locale_dir/support/bsd_like.h   |  48 +++++-
 .../__locale_dir/support/default/rune_table.h | 139 +++++++++++++++++
 libcxx/include/__locale_dir/support/fuchsia.h |   3 +-
 libcxx/include/__locale_dir/support/linux.h   |  36 ++++-
 .../include/__locale_dir/support/llvm_libc.h  |   3 +-
 libcxx/include/__locale_dir/support/newlib.h  |  35 ++++-
 libcxx/include/__locale_dir/support/openbsd.h |   3 +-
 libcxx/include/__locale_dir/support/windows.h |  28 +++-
 libcxx/include/module.modulemap.in            |   1 +
 libcxx/src/locale.cpp                         | 120 +-------------
 14 files changed, 376 insertions(+), 283 deletions(-)
 create mode 100644 libcxx/include/__locale_dir/support/default/rune_table.h

diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index 99c3bd8b72aa8..21f0109b80e52 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -558,6 +558,7 @@ set(files
   __locale_dir/support/apple.h
   __locale_dir/support/bsd_like.h
   __locale_dir/support/default/get_c_locale.h
+  __locale_dir/support/default/rune_table.h
   __locale_dir/support/freebsd.h
   __locale_dir/support/fuchsia.h
   __locale_dir/support/linux.h
diff --git a/libcxx/include/__locale_dir/ctype_base.h b/libcxx/include/__locale_dir/ctype_base.h
index 63eaa3c86b0ab..3817ff614ef77 100644
--- a/libcxx/include/__locale_dir/ctype_base.h
+++ b/libcxx/include/__locale_dir/ctype_base.h
@@ -26,152 +26,8 @@
 _LIBCPP_BEGIN_NAMESPACE_STD
 _LIBCPP_BEGIN_EXPLICIT_ABI_ANNOTATIONS
 
-class _LIBCPP_EXPORTED_FROM_ABI ctype_base {
+class _LIBCPP_EXPORTED_FROM_ABI ctype_base : public __locale::__ctype_base {
 public:
-#  if _LIBCPP_PROVIDES_DEFAULT_RUNE_TABLE
-  typedef unsigned long mask;
-  static const mask space  = 1 << 0;
-  static const mask print  = 1 << 1;
-  static const mask cntrl  = 1 << 2;
-  static const mask upper  = 1 << 3;
-  static const mask lower  = 1 << 4;
-  static const mask alpha  = 1 << 5;
-  static const mask digit  = 1 << 6;
-  static const mask punct  = 1 << 7;
-  static const mask xdigit = 1 << 8;
-  static const mask blank  = 1 << 9;
-#    if defined(__BIONIC__)
-  // Historically this was a part of regex_traits rather than ctype_base. The
-  // historical value of the constant is preserved for ABI compatibility.
-  static const mask __regex_word = 0x8000;
-#    else
-  static const mask __regex_word = 1 << 10;
-#    endif // defined(__BIONIC__)
-#  elif defined(__GLIBC__)
-  typedef unsigned short mask;
-  _LIBCPP_DIAGNOSTIC_PUSH
-  _LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wmodules-ambiguous-internal-linkage")
-  static const mask space  = _ISspace;
-  static const mask print  = _ISprint;
-  static const mask cntrl  = _IScntrl;
-  static const mask upper  = _ISupper;
-  static const mask lower  = _ISlower;
-  static const mask alpha  = _ISalpha;
-  static const mask digit  = _ISdigit;
-  static const mask punct  = _ISpunct;
-  static const mask xdigit = _ISxdigit;
-  static const mask blank  = _ISblank;
-  _LIBCPP_DIAGNOSTIC_POP
-#    if defined(__mips__) || defined(_LIBCPP_BIG_ENDIAN)
-  static const mask __regex_word = static_cast<mask>(_ISbit(15));
-#    else
-  static const mask __regex_word = 0x80;
-#    endif
-#  elif defined(_WIN32)
-  typedef unsigned short mask;
-  static const mask space        = _SPACE;
-  static const mask print        = _BLANK | _PUNCT | _ALPHA | _DIGIT;
-  static const mask cntrl        = _CONTROL;
-  static const mask upper        = _UPPER;
-  static const mask lower        = _LOWER;
-  static const mask alpha        = _ALPHA;
-  static const mask digit        = _DIGIT;
-  static const mask punct        = _PUNCT;
-  static const mask xdigit       = _HEX;
-  static const mask blank        = _BLANK;
-  static const mask __regex_word = 0x4000; // 0x8000 and 0x0100 and 0x00ff are used
-#    define _LIBCPP_CTYPE_MASK_IS_COMPOSITE_PRINT
-#    define _LIBCPP_CTYPE_MASK_IS_COMPOSITE_ALPHA
-#  elif defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__)
-#    ifdef __APPLE__
-  typedef uint32_t mask;
-#    elif defined(__FreeBSD__)
-  typedef unsigned long mask;
-#    elif defined(__NetBSD__)
-  typedef unsigned short mask;
-#    endif
-  static const mask space  = _CTYPE_S;
-  static const mask print  = _CTYPE_R;
-  static const mask cntrl  = _CTYPE_C;
-  static const mask upper  = _CTYPE_U;
-  static const mask lower  = _CTYPE_L;
-  static const mask alpha  = _CTYPE_A;
-  static const mask digit  = _CTYPE_D;
-  static const mask punct  = _CTYPE_P;
-  static const mask xdigit = _CTYPE_X;
-
-#    if defined(__NetBSD__)
-  static const mask blank = _CTYPE_BL;
-  // NetBSD defines classes up to 0x2000
-  // see sys/ctype_bits.h, _CTYPE_Q
-  static const mask __regex_word = 0x8000;
-#    else
-  static const mask blank        = _CTYPE_B;
-  static const mask __regex_word = 0x80;
-#    endif
-#  elif defined(_AIX)
-  typedef unsigned int mask;
-  static const mask space        = _ISSPACE;
-  static const mask print        = _ISPRINT;
-  static const mask cntrl        = _ISCNTRL;
-  static const mask upper        = _ISUPPER;
-  static const mask lower        = _ISLOWER;
-  static const mask alpha        = _ISALPHA;
-  static const mask digit        = _ISDIGIT;
-  static const mask punct        = _ISPUNCT;
-  static const mask xdigit       = _ISXDIGIT;
-  static const mask blank        = _ISBLANK;
-  static const mask __regex_word = 0x8000;
-#  elif _LIBCPP_LIBC_NEWLIB
-  // Same type as Newlib's _ctype_ array in newlib/libc/include/ctype.h.
-  typedef char mask;
-  // In case char is signed, static_cast is needed to avoid warning on
-  // positive value becomming negative.
-  static const mask space  = static_cast<mask>(_S);
-  static const mask print  = static_cast<mask>(_P | _U | _L | _N | _B);
-  static const mask cntrl  = static_cast<mask>(_C);
-  static const mask upper  = static_cast<mask>(_U);
-  static const mask lower  = static_cast<mask>(_L);
-  static const mask alpha  = static_cast<mask>(_U | _L);
-  static const mask digit  = static_cast<mask>(_N);
-  static const mask punct  = static_cast<mask>(_P);
-  static const mask xdigit = static_cast<mask>(_X | _N);
-  static const mask blank  = static_cast<mask>(_B);
-  // mask is already fully saturated, use a different type in regex_type_traits.
-  static const unsigned short __regex_word = 0x100;
-#    define _LIBCPP_CTYPE_MASK_IS_COMPOSITE_PRINT
-#    define _LIBCPP_CTYPE_MASK_IS_COMPOSITE_ALPHA
-#    define _LIBCPP_CTYPE_MASK_IS_COMPOSITE_XDIGIT
-#  elif defined(__MVS__)
-#    if defined(__NATIVE_ASCII_F)
-  typedef unsigned int mask;
-  static const mask space  = _ISSPACE_A;
-  static const mask print  = _ISPRINT_A;
-  static const mask cntrl  = _ISCNTRL_A;
-  static const mask upper  = _ISUPPER_A;
-  static const mask lower  = _ISLOWER_A;
-  static const mask alpha  = _ISALPHA_A;
-  static const mask digit  = _ISDIGIT_A;
-  static const mask punct  = _ISPUNCT_A;
-  static const mask xdigit = _ISXDIGIT_A;
-  static const mask blank  = _ISBLANK_A;
-#    else
-  typedef unsigned short mask;
-  static const mask space  = __ISSPACE;
-  static const mask print  = __ISPRINT;
-  static const mask cntrl  = __ISCNTRL;
-  static const mask upper  = __ISUPPER;
-  static const mask lower  = __ISLOWER;
-  static const mask alpha  = __ISALPHA;
-  static const mask digit  = __ISDIGIT;
-  static const mask punct  = __ISPUNCT;
-  static const mask xdigit = __ISXDIGIT;
-  static const mask blank  = __ISBLANK;
-#    endif
-  static const mask __regex_word = 0x8000;
-#  else
-#    error unknown rune table for this platform -- do you mean to define _LIBCPP_PROVIDES_DEFAULT_RUNE_TABLE?
-#  endif
   static const mask alnum = alpha | digit;
   static const mask graph = alnum | punct;
 
diff --git a/libcxx/include/__locale_dir/locale_base_api.h b/libcxx/include/__locale_dir/locale_base_api.h
index 14ff9d8a45b56..c86832e562ac1 100644
--- a/libcxx/include/__locale_dir/locale_base_api.h
+++ b/libcxx/include/__locale_dir/locale_base_api.h
@@ -50,6 +50,29 @@
 // #define _LIBCPP_ALL_MASK       /* implementation-defined */
 // #define _LIBCPP_LC_ALL         /* implementation-defined */
 //
+//
+// ctype masks
+// -----------
+//
+// // required by the headers
+// struct __ctype_base { // may be an alias instead
+//   using mask = /* implementation-defined */
+//
+//   static const mask space         = /* implementation-defined */
+//   static const mask print         = /* implementation-defined */
+//   static const mask cntrl         = /* implementation-defined */
+//   static const mask upper         = /* implementation-defined */
+//   static const mask lower         = /* implementation-defined */
+//   static const mask alpha         = /* implementation-defined */
+//   static const mask digit         = /* implementation-defined */
+//   static const mask punct         = /* implementation-defined */
+//   static const mask xdigit        = /* implementation-defined */
+//   static const mask blank         = /* implementation-defined */
+//   static const mask __regex_word  = /* implementation-defined */
+// };
+//
+// const mask* __classic_table() noexcept;
+//
 // Strtonum functions
 // ------------------
 // namespace __locale {
@@ -105,8 +128,6 @@
 //
 //  const char* __get_locale_encoding(__locale_t);
 //
-// #define _LIBCPP_PROVIDES_DEFAULT_RUNE_TABLE /* 0 or 1 depending on whether a rune table has to be provided */
-//
 // }
 
 #if _LIBCPP_HAS_LOCALIZATION
@@ -182,6 +203,51 @@ inline _LIBCPP_HIDE_FROM_ABI void __freelocale(__locale_t __loc) { freelocale(__
 inline _LIBCPP_HIDE_FROM_ABI __lconv_t* __localeconv(__locale_t& __loc) { return __libcpp_localeconv_l(__loc); }
 #    endif // _LIBCPP_BUILDING_LIBRARY
 
+//
+// ctype masks
+//
+
+struct __ctype_base {
+#    if defined(__NATIVE_ASCII_F)
+  using mask = unsigned int;
+
+  static const mask space  = _ISSPACE_A;
+  static const mask print  = _ISPRINT_A;
+  static const mask cntrl  = _ISCNTRL_A;
+  static const mask upper  = _ISUPPER_A;
+  static const mask lower  = _ISLOWER_A;
+  static const mask alpha  = _ISALPHA_A;
+  static const mask digit  = _ISDIGIT_A;
+  static const mask punct  = _ISPUNCT_A;
+  static const mask xdigit = _ISXDIGIT_A;
+  static const mask blank  = _ISBLANK_A;
+#    else
+  using mask = unsigned short;
+
+  static const mask space  = __ISSPACE;
+  static const mask print  = __ISPRINT;
+  static const mask cntrl  = __ISCNTRL;
+  static const mask upper  = __ISUPPER;
+  static const mask lower  = __ISLOWER;
+  static const mask alpha  = __ISALPHA;
+  static const mask digit  = __ISDIGIT;
+  static const mask punct  = __ISPUNCT;
+  static const mask xdigit = __ISXDIGIT;
+  static const mask blank  = __ISBLANK;
+#    endif
+  static const mask __regex_word = 0x8000;
+};
+
+#    ifdef _LIBCPP_BUILDING_LIBRARY
+inline const __ctype_base::mask* __classic_table() noexcept {
+#      if defined(__NATIVE_ASCII_F)
+  return const_cast<const ctype<char>::mask*>(__OBJ_DATA(__lc_ctype_a)->mask);
+#      else
+  return const_cast<const ctype<char>::mask*>(__ctypec);
+#      endif
+}
+#    endif
+
 //
 // Strtonum functions
 //
diff --git a/libcxx/include/__locale_dir/support/aix.h b/libcxx/include/__locale_dir/support/aix.h
index d5c2b395b1a37..98fd82dce3edf 100644
--- a/libcxx/include/__locale_dir/support/aix.h
+++ b/libcxx/include/__locale_dir/support/aix.h
@@ -86,6 +86,30 @@ inline _LIBCPP_HIDE_FROM_ABI const char* __get_locale_encoding(__locale_t __loc)
 }
 #endif // _LIBCPP_BUILDING_LIBRARY
 
+//
+// ctype masks
+//
+
+struct __ctype_base {
+  using mask = unsigned int;
+
+  static const mask space        = _ISSPACE;
+  static const mask print        = _ISPRINT;
+  static const mask cntrl        = _ISCNTRL;
+  static const mask upper        = _ISUPPER;
+  static const mask lower        = _ISLOWER;
+  static const mask alpha        = _ISALPHA;
+  static const mask digit        = _ISDIGIT;
+  static const mask punct        = _ISPUNCT;
+  static const mask xdigit       = _ISXDIGIT;
+  static const mask blank        = _ISBLANK;
+  static const mask __regex_word = 0x8000;
+};
+
+#ifdef _LIBCPP_BUILDING_LIBRARY
+inline const __ctype_base::mask* __classic_table() _NOEXCEPT { return (const unsigned int*)__lc_ctype_ptr->obj->mask; }
+#endif
+
 // The following structure is a quick-and-dirty workaround for routines that AIX
 // does not provide in the "_l" (locale-aware) variants.
 struct __setAndRestore {
@@ -298,8 +322,6 @@ _LIBCPP_DIAGNOSTIC_POP
 } // namespace __locale
 _LIBCPP_END_NAMESPACE_STD
 
-#define _LIBCPP_PROVIDES_DEFAULT_RUNE_TABLE 0
-
 #include <__locale_dir/support/default/get_c_locale.h>
 
 #endif // _LIBCPP___LOCALE_DIR_SUPPORT_AIX_H
diff --git a/libcxx/include/__locale_dir/support/bsd_like.h b/libcxx/include/__locale_dir/support/bsd_like.h
index ebe3f726e34ff..a6e9a73cf060c 100644
--- a/libcxx/include/__locale_dir/support/bsd_like.h
+++ b/libcxx/include/__locale_dir/support/bsd_like.h
@@ -75,6 +75,52 @@ inline __locale_t __get_c_locale() {
 #endif
 }
 
+//
+// ctype masks
+//
+
+struct __ctype_base {
+#ifdef __APPLE__
+  using mask = uint32_t;
+#elif defined(__FreeBSD__)
+  using mask = unsigned long;
+#elif defined(__NetBSD__)
+  using mask = unsigned short;
+#else
+#  error "BSD-like platforms have to update this list."
+#endif
+  static const mask space  = _CTYPE_S;
+  static const mask print  = _CTYPE_R;
+  static const mask cntrl  = _CTYPE_C;
+  static const mask upper  = _CTYPE_U;
+  static const mask lower  = _CTYPE_L;
+  static const mask alpha  = _CTYPE_A;
+  static const mask digit  = _CTYPE_D;
+  static const mask punct  = _CTYPE_P;
+  static const mask xdigit = _CTYPE_X;
+
+#if defined(__NetBSD__)
+  static const mask blank = _CTYPE_BL;
+  // NetBSD defines classes up to 0x2000
+  // see sys/ctype_bits.h, _CTYPE_Q
+  static const mask __regex_word = 0x8000;
+#else
+  static const mask blank        = _CTYPE_B;
+  static const mask __regex_word = 0x80;
+#endif
+};
+
+#ifdef _LIBCPP_BUILDING_LIBRARY
+inline const __ctype_base::mask* __classic_table() noexcept {
+#  if defined(__APPLE__) || defined(__FreeBSD__)
+  return _DefaultRuneLocale.__runetype;
+#  elif defined(__NetBSD__)
+  return _C_ctype_tab_ + 1;
+#  else
+#    error "BSD-like platforms have to update this list."
+#  endif
+}
+#endif
 //
 // Strtonum functions
 //
@@ -223,6 +269,4 @@ _LIBCPP_DIAGNOSTIC_POP
 } // namespace __locale
 _LIBCPP_END_NAMESPACE_STD
 
-#define _LIBCPP_PROVIDES_DEFAULT_RUNE_TABLE 0
-
 #endif // _LIBCPP___LOCALE_DIR_SUPPORT_BSD_LIKE_H
diff --git a/libcxx/include/__locale_dir/support/default/rune_table.h b/libcxx/include/__locale_dir/support/default/rune_table.h
new file mode 100644
index 0000000000000..4df184f126bda
--- /dev/null
+++ b/libcxx/include/__locale_dir/support/default/rune_table.h
@@ -0,0 +1,139 @@
+//===-----------------------------------------------------------------------===//
+//
+// 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___LOCALE_DIR_SUPPORT_DEFAULT_RUNE_TABLE_H
+#define _LIBCPP___LOCALE_DIR_SUPPORT_DEFAULT_RUNE_TABLE_H
+
+#include <__config>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+#  pragma GCC system_header
+#endif
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+namespace __locale {
+struct __ctype_base {
+  typedef unsigned long mask;
+  static const mask space  = 1 << 0;
+  static const mask print  = 1 << 1;
+  static const mask cntrl  = 1 << 2;
+  static const mask upper  = 1 << 3;
+  static const mask lower  = 1 << 4;
+  static const mask alpha  = 1 << 5;
+  static const mask digit  = 1 << 6;
+  static const mask punct  = 1 << 7;
+  static const mask xdigit = 1 << 8;
+  static const mask blank  = 1 << 9;
+#if defined(__BIONIC__)
+  // Historically this was a part of regex_traits rather than ctype_base. The
+  // historical value of the constant is preserved for ABI compatibility.
+  static const mask __regex_word = 0x8000;
+#else
+  static const mask __regex_word = 1 << 10;
+#endif // defined(__BIONIC__)
+};
+
+#ifdef _LIBCPP_BUILDING_LIBRARY
+inline const __ctype_base::mask* __classic_table() noexcept {
+  constexpr auto space  = __ctype_base::space;
+  constexpr auto print  = __ctype_base::print;
+  constexpr auto cntrl  = __ctype_base::cntrl;
+  constexpr auto upper  = __ctype_base::upper;
+  constexpr auto lower  = __ctype_base::lower;
+  constexpr auto alpha  = __ctype_base::alpha;
+  constexpr auto digit  = __ctype_base::digit;
+  constexpr auto punct  = __ctype_base::punct;
+  constexpr auto xdigit = __ctype_base::xdigit;
+  constexpr auto blank  = __ctype_base::blank;
+
+  // clang-format off
+    static constexpr const __ctype_base::mask __table[256] = {
+        cntrl,                          cntrl,
+        cntrl,                          cntrl,
+        cntrl,                          cntrl,
+        cntrl,                          cntrl,
+        cntrl,                          cntrl | space | blank,
+        cntrl | space,                  cntrl | space,
+        cntrl | space,                  cntrl | space,
+        cntrl,                          cntrl,
+        cntrl,                          cntrl,
+        cntrl,                          cntrl,
+        cntrl,                          cntrl,
+        cntrl,                          cntrl,
+        cntrl,                          cntrl,
+        cntrl,                          cntrl,
+        cntrl,                          cntrl,
+        cntrl,                          cntrl,
+        space | blank | print,          punct | print,
+        punct | print,                  punct | print,
+        punct | print,                  punct | print,
+        punct | print,                  punct | print,
+        punct | print,                  punct | print,
+        punct | print,                  punct | print,
+        punct | print,                  punct | print,
+        punct | print,                  punct | print,
+        digit | print | xdigit,         digit | print | xdigit,
+        digit | print | xdigit,         digit | print | xdigit,
+        digit | print | xdigit,         digit | print | xdigit,
+        digit | print | xdigit,         digit | print | xdigit,
+        digit | print | xdigit,         digit | print | xdigit,
+        punct | print,                  punct | print,
+        punct | print,                  punct | print,
+        punct | print,                  punct | print,
+        punct | print,                  upper | xdigit | print | alpha,
+        upper | xdigit | print | alpha, upper | xdigit | print | alpha,
+        upper | xdigit | print | alpha, upper | xdigit | print | alpha,
+        upper | xdigit | print | alpha, upper | print | alpha,
+        upper | print | alpha,          upper | print | alpha,
+        upper | print | alpha,          upper | print | alpha,
+        upper | print | alpha,          upper | print | alpha,
+        upper | print | alpha,          upper | print | alpha,
+        upper | print | alpha,          upper | print | alpha,
+        upper | print | alpha,          upper | print | alpha,
+        upper | print | alpha,          upper | print | alpha,
+        upper | print | alpha,          upper | print | alpha,
+        upper | print | alpha,          upper | print | alpha,
+        upper | print | alpha,          punct | print,
+        punct | print,                  punct | print,
+        punct | print,                  punct | print,
+        punct | print,                  lower | xdigit | print | alpha,
+        lower | xdigit | print | alpha, lower | xdigit | print | alpha,
+        lower | xdigit | print | alpha, lower | xdigit | print | alpha,
+        lower | xdigit | print | alpha, lower | print | alpha,
+        lower | print | alpha,          lower | print | alpha,
+        lower | print | alpha,          lower | print | alpha,
+        lower | print | alpha,          lower | print | alpha,
+        lower | print | alpha,          lower | print | alpha,
+        lower | print | alpha,          lower | print | alpha,
+        lower | print | alpha,          lower | print | alpha,
+        lower | print | alpha,          lower | print | alpha,
+        lower | print | alpha,          lower | print | alpha,
+        lower | print | alpha,          lower | print | alpha,
+        lower | print | alpha,          punct | print,
+        punct | print,                  punct | print,
+        punct | print,                  cntrl,
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+    };
+  // clang-format on
+  return __table;
+}
+#endif
+
+} // namespace __locale
+
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP___LOCALE_DIR_SUPPORT_DEFAULT_RUNE_TABLE_H
diff --git a/libcxx/include/__locale_dir/support/fuchsia.h b/libcxx/include/__locale_dir/support/fuchsia.h
index 0b4c268108032..c3f155d8840d5 100644
--- a/libcxx/include/__locale_dir/support/fuchsia.h
+++ b/libcxx/include/__locale_dir/support/fuchsia.h
@@ -153,9 +153,8 @@ _LIBCPP_DIAGNOSTIC_POP
 _LIBCPP_END_NAMESPACE_STD
 
 #include <__locale_dir/support/default/get_c_locale.h>
+#include <__locale_dir/support/default/rune_table.h>
 #include <__locale_dir/support/no_locale/characters.h>
 #include <__locale_dir/support/no_locale/strtonum.h>
 
-#define _LIBCPP_PROVIDES_DEFAULT_RUNE_TABLE 1
-
 #endif // _LIBCPP___LOCALE_DIR_SUPPORT_FUCHSIA_H
diff --git a/libcxx/include/__locale_dir/support/linux.h b/libcxx/include/__locale_dir/support/linux.h
index 8d20bbe9180c4..048f5655dabe7 100644
--- a/libcxx/include/__locale_dir/support/linux.h
+++ b/libcxx/include/__locale_dir/support/linux.h
@@ -82,6 +82,38 @@ inline _LIBCPP_HIDE_FROM_ABI __lconv_t* __localeconv(__locale_t& __loc) {
 }
 #endif // _LIBCPP_BUILDING_LIBRARY
 
+//
+// ctype masks
+//
+
+#if !(defined(__BIONIC__) || _LIBCPP_HAS_MUSL_LIBC)
+struct __ctype_base {
+  using mask = unsigned short;
+  _LIBCPP_DIAGNOSTIC_PUSH
+  _LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wmodules-ambiguous-internal-linkage")
+  static const mask space  = _ISspace;
+  static const mask print  = _ISprint;
+  static const mask cntrl  = _IScntrl;
+  static const mask upper  = _ISupper;
+  static const mask lower  = _ISlower;
+  static const mask alpha  = _ISalpha;
+  static const mask digit  = _ISdigit;
+  static const mask punct  = _ISpunct;
+  static const mask xdigit = _ISxdigit;
+  static const mask blank  = _ISblank;
+  _LIBCPP_DIAGNOSTIC_POP
+#  if defined(__mips__) || defined(_LIBCPP_BIG_ENDIAN)
+  static const mask __regex_word = static_cast<mask>(_ISbit(15));
+#  else
+  static const mask __regex_word = 0x80;
+#  endif
+};
+
+__locale_t __get_c_locale();
+
+inline const __ctype_base::mask* __classic_table() noexcept { return __get_c_locale()->__ctype_b; }
+#endif
+
 //
 // Strtonum functions
 //
@@ -253,9 +285,7 @@ inline _LIBCPP_ATTRIBUTE_FORMAT(__printf__, 3, 4) int __asprintf(
 _LIBCPP_END_NAMESPACE_STD
 
 #if defined(__BIONIC__) || _LIBCPP_HAS_MUSL_LIBC
-#  define _LIBCPP_PROVIDES_DEFAULT_RUNE_TABLE 1
-#else
-#  define _LIBCPP_PROVIDES_DEFAULT_RUNE_TABLE 0
+#  include <__locale_dir/support/default/rune_table.h>
 #endif
 
 #include <__locale_dir/support/default/get_c_locale.h>
diff --git a/libcxx/include/__locale_dir/support/llvm_libc.h b/libcxx/include/__locale_dir/support/llvm_libc.h
index 6f3662ae99dae..fced448ce8741 100644
--- a/libcxx/include/__locale_dir/support/llvm_libc.h
+++ b/libcxx/include/__locale_dir/support/llvm_libc.h
@@ -55,11 +55,10 @@ inline _LIBCPP_HIDE_FROM_ABI const char* __get_locale_encoding(__locale_t) { ret
 _LIBCPP_END_NAMESPACE_STD
 
 #include <__locale_dir/support/default/get_c_locale.h>
+#include <__locale_dir/support/default/rune_table.h>
 #include <__locale_dir/support/no_locale/characters.h>
 #include <__locale_dir/support/no_locale/conversions.h>
 #include <__locale_dir/support/no_locale/formatting.h>
 #include <__locale_dir/support/no_locale/strtonum.h>
 
-#define _LIBCPP_PROVIDES_DEFAULT_RUNE_TABLE 1
-
 #endif // _LIBCPP___LOCALE_DIR_SUPPORT_LLVM_LIBC_H
diff --git a/libcxx/include/__locale_dir/support/newlib.h b/libcxx/include/__locale_dir/support/newlib.h
index daf60e8a48ea2..646a750666e3b 100644
--- a/libcxx/include/__locale_dir/support/newlib.h
+++ b/libcxx/include/__locale_dir/support/newlib.h
@@ -83,6 +83,39 @@ inline _LIBCPP_HIDE_FROM_ABI const char* __get_locale_encoding(__locale_t __loc)
 }
 #endif // _LIBCPP_BUILDING_LIBRARY
 
+//
+// ctype masks
+//
+
+struct __ctype_base {
+  // Same type as Newlib's _ctype_ array in newlib/libc/include/ctype.h.
+  typedef char mask;
+  // In case char is signed, static_cast is needed to avoid warning on
+  // positive value becomming negative.
+  static const mask space  = static_cast<mask>(_S);
+  static const mask print  = static_cast<mask>(_P | _U | _L | _N | _B);
+  static const mask cntrl  = static_cast<mask>(_C);
+  static const mask upper  = static_cast<mask>(_U);
+  static const mask lower  = static_cast<mask>(_L);
+  static const mask alpha  = static_cast<mask>(_U | _L);
+  static const mask digit  = static_cast<mask>(_N);
+  static const mask punct  = static_cast<mask>(_P);
+  static const mask xdigit = static_cast<mask>(_X | _N);
+  static const mask blank  = static_cast<mask>(_B);
+  // mask is already fully saturated, use a different type in regex_type_traits.
+  static const unsigned short __regex_word = 0x100;
+#define _LIBCPP_CTYPE_MASK_IS_COMPOSITE_PRINT
+#define _LIBCPP_CTYPE_MASK_IS_COMPOSITE_ALPHA
+#define _LIBCPP_CTYPE_MASK_IS_COMPOSITE_XDIGIT
+};
+
+#ifdef _LIBCPP_BUILDING_LIBRARY
+inline const __ctype_base::mask* __classic_table() noexcept {
+  // Newlib has a 257-entry table in ctype_.c, where (char)0 starts at [1].
+  return _ctype_ + 1;
+}
+#endif
+
 //
 // Strtonum functions
 //
@@ -245,8 +278,6 @@ inline _LIBCPP_ATTRIBUTE_FORMAT(__printf__, 3, 4) int __asprintf(
 } // namespace __locale
 _LIBCPP_END_NAMESPACE_STD
 
-#define _LIBCPP_PROVIDES_DEFAULT_RUNE_TABLE 0
-
 #include <__locale_dir/support/default/get_c_locale.h>
 
 #endif // _LIBCPP___LOCALE_DIR_SUPPORT_NEWLIB_H
diff --git a/libcxx/include/__locale_dir/support/openbsd.h b/libcxx/include/__locale_dir/support/openbsd.h
index 85f008f8a17f0..1a80d635e12ea 100644
--- a/libcxx/include/__locale_dir/support/openbsd.h
+++ b/libcxx/include/__locale_dir/support/openbsd.h
@@ -226,8 +226,7 @@ _LIBCPP_DIAGNOSTIC_POP
 } // namespace __locale
 _LIBCPP_END_NAMESPACE_STD
 
-#define _LIBCPP_PROVIDES_DEFAULT_RUNE_TABLE 1
-
 #include <__locale_dir/support/default/get_c_locale.h>
+#include <__locale_dir/support/default/rune_table.h>
 
 #endif // _LIBCPP___LOCALE_DIR_LOCALE_BASE_API_OPENBSD_H
diff --git a/libcxx/include/__locale_dir/support/windows.h b/libcxx/include/__locale_dir/support/windows.h
index 5f35d089ac1fc..cab5e0c6b96f9 100644
--- a/libcxx/include/__locale_dir/support/windows.h
+++ b/libcxx/include/__locale_dir/support/windows.h
@@ -167,6 +167,32 @@ _LIBCPP_EXPORTED_FROM_ABI __lconv_t* __localeconv(__locale_t& __loc);
 _LIBCPP_EXPORTED_FROM_ABI const char* __get_locale_encoding(__locale_t __loc);
 #endif // _LIBCPP_BUILDING_LIBRARY
 
+//
+// ctype masks
+//
+
+struct __ctype_base {
+  using mask = unsigned short;
+
+  static const mask space        = _SPACE;
+  static const mask print        = _BLANK | _PUNCT | _ALPHA | _DIGIT;
+  static const mask cntrl        = _CONTROL;
+  static const mask upper        = _UPPER;
+  static const mask lower        = _LOWER;
+  static const mask alpha        = _ALPHA;
+  static const mask digit        = _DIGIT;
+  static const mask punct        = _PUNCT;
+  static const mask xdigit       = _HEX;
+  static const mask blank        = _BLANK;
+  static const mask __regex_word = 0x4000; // 0x8000 and 0x0100 and 0x00ff are used
+#define _LIBCPP_CTYPE_MASK_IS_COMPOSITE_PRINT
+#define _LIBCPP_CTYPE_MASK_IS_COMPOSITE_ALPHA
+};
+
+#ifdef _LIBCPP_BUILDING_LIBRARY
+inline const __ctype_base::mask* __classic_table() noexcept { return __pctype_func(); }
+#endif
+
 //
 // Strtonum functions
 //
@@ -309,8 +335,6 @@ struct __locale_guard {
 _LIBCPP_END_EXPLICIT_ABI_ANNOTATIONS
 _LIBCPP_END_NAMESPACE_STD
 
-#define _LIBCPP_PROVIDES_DEFAULT_RUNE_TABLE 0
-
 #include <__locale_dir/support/default/get_c_locale.h>
 
 #endif // _LIBCPP___LOCALE_DIR_SUPPORT_WINDOWS_H
diff --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in
index 3e2b446780a43..8e676604b5800 100644
--- a/libcxx/include/module.modulemap.in
+++ b/libcxx/include/module.modulemap.in
@@ -1628,6 +1628,7 @@ module std {
       textual header "__locale_dir/support/apple.h"
       textual header "__locale_dir/support/bsd_like.h"
       textual header "__locale_dir/support/default/get_c_locale.h"
+      textual header "__locale_dir/support/default/rune_table.h"
       textual header "__locale_dir/support/freebsd.h"
       textual header "__locale_dir/support/fuchsia.h"
       textual header "__locale_dir/support/linux.h"
diff --git a/libcxx/src/locale.cpp b/libcxx/src/locale.cpp
index 058bc0ec6f901..9060938a06e68 100644
--- a/libcxx/src/locale.cpp
+++ b/libcxx/src/locale.cpp
@@ -810,125 +810,7 @@ const char* ctype<char>::do_narrow(const char_type* low, const char_type* high,
   return low;
 }
 
-#if defined(__EMSCRIPTEN__)
-extern "C" const unsigned short** __ctype_b_loc();
-extern "C" const int** __ctype_tolower_loc();
-extern "C" const int** __ctype_toupper_loc();
-#endif
-
-#if _LIBCPP_PROVIDES_DEFAULT_RUNE_TABLE
-const ctype<char>::mask* ctype<char>::classic_table() noexcept {
-  // clang-format off
-    static constexpr const ctype<char>::mask builtin_table[table_size] = {
-        cntrl,                          cntrl,
-        cntrl,                          cntrl,
-        cntrl,                          cntrl,
-        cntrl,                          cntrl,
-        cntrl,                          cntrl | space | blank,
-        cntrl | space,                  cntrl | space,
-        cntrl | space,                  cntrl | space,
-        cntrl,                          cntrl,
-        cntrl,                          cntrl,
-        cntrl,                          cntrl,
-        cntrl,                          cntrl,
-        cntrl,                          cntrl,
-        cntrl,                          cntrl,
-        cntrl,                          cntrl,
-        cntrl,                          cntrl,
-        cntrl,                          cntrl,
-        space | blank | print,          punct | print,
-        punct | print,                  punct | print,
-        punct | print,                  punct | print,
-        punct | print,                  punct | print,
-        punct | print,                  punct | print,
-        punct | print,                  punct | print,
-        punct | print,                  punct | print,
-        punct | print,                  punct | print,
-        digit | print | xdigit,         digit | print | xdigit,
-        digit | print | xdigit,         digit | print | xdigit,
-        digit | print | xdigit,         digit | print | xdigit,
-        digit | print | xdigit,         digit | print | xdigit,
-        digit | print | xdigit,         digit | print | xdigit,
-        punct | print,                  punct | print,
-        punct | print,                  punct | print,
-        punct | print,                  punct | print,
-        punct | print,                  upper | xdigit | print | alpha,
-        upper | xdigit | print | alpha, upper | xdigit | print | alpha,
-        upper | xdigit | print | alpha, upper | xdigit | print | alpha,
-        upper | xdigit | print | alpha, upper | print | alpha,
-        upper | print | alpha,          upper | print | alpha,
-        upper | print | alpha,          upper | print | alpha,
-        upper | print | alpha,          upper | print | alpha,
-        upper | print | alpha,          upper | print | alpha,
-        upper | print | alpha,          upper | print | alpha,
-        upper | print | alpha,          upper | print | alpha,
-        upper | print | alpha,          upper | print | alpha,
-        upper | print | alpha,          upper | print | alpha,
-        upper | print | alpha,          upper | print | alpha,
-        upper | print | alpha,          punct | print,
-        punct | print,                  punct | print,
-        punct | print,                  punct | print,
-        punct | print,                  lower | xdigit | print | alpha,
-        lower | xdigit | print | alpha, lower | xdigit | print | alpha,
-        lower | xdigit | print | alpha, lower | xdigit | print | alpha,
-        lower | xdigit | print | alpha, lower | print | alpha,
-        lower | print | alpha,          lower | print | alpha,
-        lower | print | alpha,          lower | print | alpha,
-        lower | print | alpha,          lower | print | alpha,
-        lower | print | alpha,          lower | print | alpha,
-        lower | print | alpha,          lower | print | alpha,
-        lower | print | alpha,          lower | print | alpha,
-        lower | print | alpha,          lower | print | alpha,
-        lower | print | alpha,          lower | print | alpha,
-        lower | print | alpha,          lower | print | alpha,
-        lower | print | alpha,          punct | print,
-        punct | print,                  punct | print,
-        punct | print,                  cntrl,
-        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
-    };
-  // clang-format on
-  return builtin_table;
-}
-#else
-const ctype<char>::mask* ctype<char>::classic_table() noexcept {
-#  if defined(__APPLE__) || defined(__FreeBSD__)
-  return _DefaultRuneLocale.__runetype;
-#  elif defined(__NetBSD__)
-  return _C_ctype_tab_ + 1;
-#  elif defined(__GLIBC__)
-  return __locale::__get_c_locale()->__ctype_b;
-#  elif defined(_WIN32)
-  return __pctype_func();
-#  elif defined(__EMSCRIPTEN__)
-  return *__ctype_b_loc();
-#  elif _LIBCPP_LIBC_NEWLIB
-  // Newlib has a 257-entry table in ctype_.c, where (char)0 starts at [1].
-  return _ctype_ + 1;
-#  elif defined(_AIX)
-  return (const unsigned int*)__lc_ctype_ptr->obj->mask;
-#  elif defined(__MVS__)
-#    if defined(__NATIVE_ASCII_F)
-  return const_cast<const ctype<char>::mask*>(__OBJ_DATA(__lc_ctype_a)->mask);
-#    else
-  return const_cast<const ctype<char>::mask*>(__ctypec);
-#    endif
-#  else
-  // Platform not supported: abort so the person doing the port knows what to
-  // fix
-#    warning ctype<char>::classic_table() is not implemented
-  printf("ctype<char>::classic_table() is not implemented\n");
-  abort();
-  return nullptr;
-#  endif
-}
-#endif
+const ctype<char>::mask* ctype<char>::classic_table() noexcept { return __classic_table(); }
 
 // template <> class ctype_byname<char>
 



More information about the libcxx-commits mailing list