mirror of
https://codeberg.org/ziglang/zig.git
synced 2026-05-06 08:36:58 -04:00
llvm-libc: update to LLVM 22
This commit is contained in:
Vendored
+3
-1
@@ -15,7 +15,9 @@
|
||||
#include <linux/errno.h>
|
||||
|
||||
#include "include/llvm-libc-macros/error-number-macros.h"
|
||||
#else // __linux__
|
||||
#elif defined(__APPLE__)
|
||||
#include <sys/errno.h>
|
||||
#else // __APPLE__
|
||||
#include "include/llvm-libc-macros/generic-error-number-macros.h"
|
||||
#endif
|
||||
|
||||
|
||||
Vendored
+18
@@ -0,0 +1,18 @@
|
||||
//===-- stdint.h ----------------------------------------------------------===//
|
||||
//
|
||||
// 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 LLVM_LIBC_HDR_STDINT_PROXY_H
|
||||
#define LLVM_LIBC_HDR_STDINT_PROXY_H
|
||||
|
||||
// This target is to make sure we have correct build order in full build mode,
|
||||
// that is `libc.include.stdint` is added to the dependency of all targets
|
||||
// that use <stdint.h> header.
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#endif // LLVM_LIBC_HDR_STDINT_PROXY_H
|
||||
Vendored
+23
@@ -0,0 +1,23 @@
|
||||
//===-- Definition of wchar_t.h -------------------------------------------===//
|
||||
//
|
||||
// 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 LLVM_LIBC_HDR_TYPES_WCHAR_T_H
|
||||
#define LLVM_LIBC_HDR_TYPES_WCHAR_T_H
|
||||
|
||||
#ifdef LIBC_FULL_BUILD
|
||||
|
||||
#include "include/llvm-libc-types/wchar_t.h"
|
||||
|
||||
#else // overlay mode
|
||||
|
||||
#include "hdr/wchar_overlay.h"
|
||||
|
||||
#endif // LLVM_LIBC_FULL_BUILD
|
||||
|
||||
#endif // LLVM_LIBC_HDR_TYPES_WCHAR_T_H
|
||||
Vendored
+69
@@ -0,0 +1,69 @@
|
||||
//===-- Including wchar.h in overlay mode ---------------------------------===//
|
||||
//
|
||||
// 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 LLVM_LIBC_HDR_WCHAR_OVERLAY_H
|
||||
#define LLVM_LIBC_HDR_WCHAR_OVERLAY_H
|
||||
|
||||
#ifdef LIBC_FULL_BUILD
|
||||
#error "This header should only be included in overlay mode"
|
||||
#endif
|
||||
|
||||
// Overlay mode
|
||||
|
||||
// glibc <wchar.h> header might provide extern inline definitions for few
|
||||
// functions, causing external alias errors. They are guarded by
|
||||
// `__USE_EXTERN_INLINES` macro. We temporarily disable `__USE_EXTERN_INLINES`
|
||||
// macro by defining `__NO_INLINE__` before including <wchar.h>.
|
||||
// And the same with `__USE_FORTIFY_LEVEL`, which will be temporarily disabled
|
||||
// with `_FORTIFY_SOURCE`.
|
||||
|
||||
#ifdef _FORTIFY_SOURCE
|
||||
#define LIBC_OLD_FORTIFY_SOURCE _FORTIFY_SOURCE
|
||||
#undef _FORTIFY_SOURCE
|
||||
#endif
|
||||
|
||||
#ifndef __NO_INLINE__
|
||||
#define __NO_INLINE__ 1
|
||||
#define LIBC_SET_NO_INLINE
|
||||
#endif
|
||||
|
||||
#ifdef __USE_EXTERN_INLINES
|
||||
#define LIBC_OLD_USE_EXTERN_INLINES
|
||||
#undef __USE_EXTERN_INLINES
|
||||
#endif
|
||||
|
||||
#ifdef __USE_FORTIFY_LEVEL
|
||||
#define LIBC_OLD_USE_FORTIFY_LEVEL __USE_FORTIFY_LEVEL
|
||||
#undef __USE_FORTIFY_LEVEL
|
||||
#define __USE_FORTIFY_LEVEL 0
|
||||
#endif
|
||||
|
||||
#include <wchar.h>
|
||||
|
||||
#ifdef LIBC_OLD_FORTIFY_SOURCE
|
||||
#define _FORTIFY_SOURCE LIBC_OLD_FORTIFY_SOURCE
|
||||
#undef LIBC_OLD_FORTIFY_SOURCE
|
||||
#endif
|
||||
|
||||
#ifdef LIBC_SET_NO_INLINE
|
||||
#undef __NO_INLINE__
|
||||
#undef LIBC_SET_NO_INLINE
|
||||
#endif
|
||||
|
||||
#ifdef LIBC_OLD_USE_FORTIFY_LEVEL
|
||||
#undef __USE_FORTIFY_LEVEL
|
||||
#define __USE_FORTIFY_LEVEL LIBC_OLD_USE_FORTIFY_LEVEL
|
||||
#undef LIBC_OLD_USE_FORTIFY_LEVEL
|
||||
#endif
|
||||
|
||||
#ifdef LIBC_OLD_USE_EXTERN_INLINES
|
||||
#define __USE_EXTERN_INLINES
|
||||
#undef LIBC_OLD_USE_EXTERN_INLINES
|
||||
#endif
|
||||
|
||||
#endif // LLVM_LIBC_HDR_WCHAR_OVERLAY_H
|
||||
@@ -0,0 +1,41 @@
|
||||
//===-- Detection of _Complex _Float128 compiler builtin type -------------===//
|
||||
//
|
||||
// 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 LLVM_LIBC_MACROS_CFLOAT128_MACROS_H
|
||||
#define LLVM_LIBC_MACROS_CFLOAT128_MACROS_H
|
||||
|
||||
#include "float-macros.h" // LDBL_MANT_DIG
|
||||
|
||||
// Currently, the complex variant of C23 `_Float128` type is only defined as a
|
||||
// built-in type in GCC 7 or later, for C and in GCC 13 or later, for C++. For
|
||||
// clang, the complex variant of `__float128` is defined instead, and only on
|
||||
// x86-64 targets for clang 11 or later.
|
||||
//
|
||||
// TODO: Update the complex variant of C23 `_Float128` type detection again when
|
||||
// clang supports it.
|
||||
#ifdef __clang__
|
||||
#if (__clang_major__ >= 11) && \
|
||||
(defined(__FLOAT128__) || defined(__SIZEOF_FLOAT128__))
|
||||
// Use _Complex __float128 type. clang uses __SIZEOF_FLOAT128__ or __FLOAT128__
|
||||
// macro to notify the availability of __float128 type:
|
||||
// https://reviews.llvm.org/D15120
|
||||
#define LIBC_TYPES_HAS_CFLOAT128
|
||||
#endif
|
||||
#elif defined(__GNUC__)
|
||||
#if (defined(__STDC_IEC_60559_COMPLEX__) || defined(__SIZEOF_FLOAT128__)) && \
|
||||
(__GNUC__ >= 13 || (!defined(__cplusplus)))
|
||||
#define LIBC_TYPES_HAS_CFLOAT128
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if !defined(LIBC_TYPES_HAS_CFLOAT128) && (LDBL_MANT_DIG == 113)
|
||||
#define LIBC_TYPES_HAS_CFLOAT128
|
||||
#define LIBC_TYPES_CFLOAT128_IS_COMPLEX_LONG_DOUBLE
|
||||
#endif
|
||||
|
||||
#endif // LLVM_LIBC_MACROS_CFLOAT128_MACROS_H
|
||||
@@ -0,0 +1,20 @@
|
||||
//===-- Detection of _Complex _Float16 compiler builtin type --------------===//
|
||||
//
|
||||
// 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 LLVM_LIBC_MACROS_CFLOAT16_MACROS_H
|
||||
#define LLVM_LIBC_MACROS_CFLOAT16_MACROS_H
|
||||
|
||||
#if defined(__FLT16_MANT_DIG__) && \
|
||||
(!defined(__GNUC__) || __GNUC__ >= 13 || \
|
||||
(defined(__clang__) && __clang_major__ >= 14)) && \
|
||||
!defined(__arm__) && !defined(_M_ARM) && !defined(__riscv) && \
|
||||
!defined(_WIN32)
|
||||
#define LIBC_TYPES_HAS_CFLOAT16
|
||||
#endif
|
||||
|
||||
#endif // LLVM_LIBC_MACROS_CFLOAT16_MACROS_H
|
||||
@@ -0,0 +1,18 @@
|
||||
//===-- Macros defined in wchar.h header file -----------------------------===//
|
||||
//
|
||||
// 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 LLVM_LIBC_MACROS_WCHAR_MACROS_H
|
||||
#define LLVM_LIBC_MACROS_WCHAR_MACROS_H
|
||||
|
||||
#include "../llvm-libc-types/wint_t.h"
|
||||
|
||||
#ifndef WEOF
|
||||
#define WEOF ((wint_t)(0xffffffffu))
|
||||
#endif
|
||||
|
||||
#endif // LLVM_LIBC_MACROS_WCHAR_MACROS_H
|
||||
+11
-28
@@ -9,36 +9,19 @@
|
||||
#ifndef LLVM_LIBC_TYPES_CFLOAT128_H
|
||||
#define LLVM_LIBC_TYPES_CFLOAT128_H
|
||||
|
||||
#include "../llvm-libc-macros/float-macros.h" // LDBL_MANT_DIG
|
||||
#include "../llvm-libc-macros/cfloat128-macros.h"
|
||||
|
||||
// Currently, the complex variant of C23 `_Float128` type is only defined as a
|
||||
// built-in type in GCC 7 or later, for C and in GCC 13 or later, for C++. For
|
||||
// clang, the complex variant of `__float128` is defined instead, and only on
|
||||
// x86-64 targets for clang 11 or later.
|
||||
//
|
||||
// TODO: Update the complex variant of C23 `_Float128` type detection again when
|
||||
// clang supports it.
|
||||
#ifdef __clang__
|
||||
#if (__clang_major__ >= 11) && \
|
||||
(defined(__FLOAT128__) || defined(__SIZEOF_FLOAT128__))
|
||||
// Use _Complex __float128 type. clang uses __SIZEOF_FLOAT128__ or __FLOAT128__
|
||||
// macro to notify the availability of __float128 type:
|
||||
// https://reviews.llvm.org/D15120
|
||||
#define LIBC_TYPES_HAS_CFLOAT128
|
||||
#ifdef LIBC_TYPES_HAS_CFLOAT128
|
||||
#ifndef LIBC_TYPES_CFLOAT128_IS_COMPLEX_LONG_DOUBLE
|
||||
#if defined(__GNUC__) && !defined(__clang__)
|
||||
// Remove the workaround when https://gcc.gnu.org/PR32187 gets fixed.
|
||||
typedef __typeof__(_Complex __float128) cfloat128;
|
||||
#else // ^^^ workaround / no workaround vvv
|
||||
typedef _Complex __float128 cfloat128;
|
||||
#endif
|
||||
#elif defined(__GNUC__)
|
||||
#if (defined(__STDC_IEC_60559_COMPLEX__) || defined(__SIZEOF_FLOAT128__)) && \
|
||||
(__GNUC__ >= 13 || (!defined(__cplusplus)))
|
||||
#define LIBC_TYPES_HAS_CFLOAT128
|
||||
typedef _Complex _Float128 cfloat128;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if !defined(LIBC_TYPES_HAS_CFLOAT128) && (LDBL_MANT_DIG == 113)
|
||||
#define LIBC_TYPES_HAS_CFLOAT128
|
||||
#define LIBC_TYPES_CFLOAT128_IS_COMPLEX_LONG_DOUBLE
|
||||
#endif // ^^^ no workaround ^^^
|
||||
#else
|
||||
typedef _Complex long double cfloat128;
|
||||
#endif
|
||||
#endif // LIBC_TYPES_CFLOAT128_IS_COMPLEX_LONG_DOUBLE
|
||||
#endif // LIBC_TYPES_HAS_CFLOAT128
|
||||
|
||||
#endif // LLVM_LIBC_TYPES_CFLOAT128_H
|
||||
|
||||
+4
-7
@@ -9,13 +9,10 @@
|
||||
#ifndef LLVM_LIBC_TYPES_CFLOAT16_H
|
||||
#define LLVM_LIBC_TYPES_CFLOAT16_H
|
||||
|
||||
#if defined(__FLT16_MANT_DIG__) && \
|
||||
(!defined(__GNUC__) || __GNUC__ >= 13 || \
|
||||
(defined(__clang__) && __clang_major__ >= 14)) && \
|
||||
!defined(__arm__) && !defined(_M_ARM) && !defined(__riscv) && \
|
||||
!defined(_WIN32)
|
||||
#define LIBC_TYPES_HAS_CFLOAT16
|
||||
#include "../llvm-libc-macros/cfloat16-macros.h"
|
||||
|
||||
#ifdef LIBC_TYPES_HAS_CFLOAT16
|
||||
typedef _Complex _Float16 cfloat16;
|
||||
#endif
|
||||
#endif // LIBC_TYPES_HAS_CFLOAT16
|
||||
|
||||
#endif // LLVM_LIBC_TYPES_CFLOAT16_H
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
//===-- Definition of wint_t types ----------------------------------------===//
|
||||
//
|
||||
// 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 LLVM_LIBC_TYPES_WINT_T_H
|
||||
#define LLVM_LIBC_TYPES_WINT_T_H
|
||||
|
||||
typedef __WINT_TYPE__ wint_t;
|
||||
|
||||
#endif // LLVM_LIBC_TYPES_WINT_T_H
|
||||
Vendored
+5
@@ -19,6 +19,11 @@
|
||||
#define LIBC_ERRNO_MODE LIBC_ERRNO_MODE_SYSTEM_INLINE
|
||||
#endif // LIBC_ERRNO_MODE
|
||||
|
||||
// Use system fenv functions in math implementations.
|
||||
#ifndef LIBC_MATH_USE_SYSTEM_FENV
|
||||
#define LIBC_MATH_USE_SYSTEM_FENV
|
||||
#endif // LIBC_MATH_USE_SYSTEM_FENV
|
||||
|
||||
#ifndef LIBC_NAMESPACE
|
||||
#define LIBC_NAMESPACE __llvm_libc
|
||||
#endif // LIBC_NAMESPACE
|
||||
|
||||
+50
-12
@@ -11,14 +11,14 @@
|
||||
#ifndef LLVM_LIBC_SRC___SUPPORT_CPP_BIT_H
|
||||
#define LLVM_LIBC_SRC___SUPPORT_CPP_BIT_H
|
||||
|
||||
#include "hdr/stdint_proxy.h"
|
||||
#include "src/__support/CPP/limits.h" // numeric_limits
|
||||
#include "src/__support/CPP/type_traits.h"
|
||||
#include "src/__support/macros/attributes.h"
|
||||
#include "src/__support/macros/config.h"
|
||||
#include "src/__support/macros/properties/compiler.h"
|
||||
#include "src/__support/macros/sanitizer.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
namespace LIBC_NAMESPACE_DECL {
|
||||
namespace cpp {
|
||||
|
||||
@@ -26,6 +26,16 @@ namespace cpp {
|
||||
#define LLVM_LIBC_HAS_BUILTIN_MEMCPY_INLINE
|
||||
#endif
|
||||
|
||||
template <unsigned N>
|
||||
LIBC_INLINE static void inline_copy(const char *from, char *to) {
|
||||
#if __has_builtin(__builtin_memcpy_inline)
|
||||
__builtin_memcpy_inline(to, from, N);
|
||||
#else
|
||||
for (unsigned i = 0; i < N; ++i)
|
||||
to[i] = from[i];
|
||||
#endif // __has_builtin(__builtin_memcpy_inline)
|
||||
}
|
||||
|
||||
// This implementation of bit_cast requires trivially-constructible To, to avoid
|
||||
// UB in the implementation.
|
||||
template <typename To, typename From>
|
||||
@@ -37,22 +47,32 @@ LIBC_INLINE constexpr cpp::enable_if_t<
|
||||
To>
|
||||
bit_cast(const From &from) {
|
||||
MSAN_UNPOISON(&from, sizeof(From));
|
||||
#if __has_builtin(__builtin_bit_cast)
|
||||
#if __has_builtin(__builtin_bit_cast) || defined(LIBC_COMPILER_IS_MSVC)
|
||||
return __builtin_bit_cast(To, from);
|
||||
#else
|
||||
To to;
|
||||
To to{};
|
||||
char *dst = reinterpret_cast<char *>(&to);
|
||||
const char *src = reinterpret_cast<const char *>(&from);
|
||||
#if __has_builtin(__builtin_memcpy_inline)
|
||||
__builtin_memcpy_inline(dst, src, sizeof(To));
|
||||
#else
|
||||
for (unsigned i = 0; i < sizeof(To); ++i)
|
||||
dst[i] = src[i];
|
||||
#endif // __has_builtin(__builtin_memcpy_inline)
|
||||
inline_copy<sizeof(From)>(src, dst);
|
||||
return to;
|
||||
#endif // __has_builtin(__builtin_bit_cast)
|
||||
}
|
||||
|
||||
// The following simple bit copy from a smaller type to maybe-larger type.
|
||||
template <typename To, typename From>
|
||||
LIBC_INLINE constexpr cpp::enable_if_t<
|
||||
(sizeof(To) >= sizeof(From)) &&
|
||||
cpp::is_trivially_constructible<To>::value &&
|
||||
cpp::is_trivially_copyable<To>::value &&
|
||||
cpp::is_trivially_copyable<From>::value,
|
||||
void>
|
||||
bit_copy(const From &from, To &to) {
|
||||
MSAN_UNPOISON(&from, sizeof(From));
|
||||
char *dst = reinterpret_cast<char *>(&to);
|
||||
const char *src = reinterpret_cast<const char *>(&from);
|
||||
inline_copy<sizeof(From)>(src, dst);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
[[nodiscard]] LIBC_INLINE constexpr cpp::enable_if_t<cpp::is_unsigned_v<T>,
|
||||
bool>
|
||||
@@ -105,10 +125,16 @@ countr_zero(T value) {
|
||||
}
|
||||
#if __has_builtin(__builtin_ctzs)
|
||||
ADD_SPECIALIZATION(countr_zero, unsigned short, __builtin_ctzs)
|
||||
#endif
|
||||
#endif // __has_builtin(__builtin_ctzs)
|
||||
#if __has_builtin(__builtin_ctz)
|
||||
ADD_SPECIALIZATION(countr_zero, unsigned int, __builtin_ctz)
|
||||
#endif // __has_builtin(__builtin_ctz)
|
||||
#if __has_builtin(__builtin_ctzl)
|
||||
ADD_SPECIALIZATION(countr_zero, unsigned long, __builtin_ctzl)
|
||||
#endif // __has_builtin(__builtin_ctzl)
|
||||
#if __has_builtin(__builtin_ctzll)
|
||||
ADD_SPECIALIZATION(countr_zero, unsigned long long, __builtin_ctzll)
|
||||
#endif // __has_builtin(__builtin_ctzll)
|
||||
#endif // __has_builtin(__builtin_ctzg)
|
||||
|
||||
/// Count number of 0's from the most significant bit to the least
|
||||
@@ -144,10 +170,16 @@ countl_zero(T value) {
|
||||
}
|
||||
#if __has_builtin(__builtin_clzs)
|
||||
ADD_SPECIALIZATION(countl_zero, unsigned short, __builtin_clzs)
|
||||
#endif
|
||||
#endif // __has_builtin(__builtin_clzs)
|
||||
#if __has_builtin(__builtin_clz)
|
||||
ADD_SPECIALIZATION(countl_zero, unsigned int, __builtin_clz)
|
||||
#endif // __has_builtin(__builtin_clz)
|
||||
#if __has_builtin(__builtin_clzl)
|
||||
ADD_SPECIALIZATION(countl_zero, unsigned long, __builtin_clzl)
|
||||
#endif // __has_builtin(__builtin_clzl)
|
||||
#if __has_builtin(__builtin_clzll)
|
||||
ADD_SPECIALIZATION(countl_zero, unsigned long long, __builtin_clzll)
|
||||
#endif // __has_builtin(__builtin_clzll)
|
||||
#endif // __has_builtin(__builtin_clzg)
|
||||
|
||||
#undef ADD_SPECIALIZATION
|
||||
@@ -284,11 +316,17 @@ popcount(T value) {
|
||||
[[nodiscard]] LIBC_INLINE constexpr int popcount<TYPE>(TYPE value) { \
|
||||
return BUILTIN(value); \
|
||||
}
|
||||
#if __has_builtin(__builtin_popcount)
|
||||
ADD_SPECIALIZATION(unsigned char, __builtin_popcount)
|
||||
ADD_SPECIALIZATION(unsigned short, __builtin_popcount)
|
||||
ADD_SPECIALIZATION(unsigned, __builtin_popcount)
|
||||
#endif // __builtin_popcount
|
||||
#if __has_builtin(__builtin_popcountl)
|
||||
ADD_SPECIALIZATION(unsigned long, __builtin_popcountl)
|
||||
#endif // __builtin_popcountl
|
||||
#if __has_builtin(__builtin_popcountll)
|
||||
ADD_SPECIALIZATION(unsigned long long, __builtin_popcountll)
|
||||
#endif // __builtin_popcountll
|
||||
#endif // __builtin_popcountg
|
||||
#undef ADD_SPECIALIZATION
|
||||
|
||||
|
||||
@@ -13,12 +13,17 @@
|
||||
#include "src/__support/macros/attributes.h"
|
||||
#include "src/__support/macros/config.h"
|
||||
// LIBC_TYPES_HAS_CFLOAT16 && LIBC_TYPES_HAS_CFLOAT128
|
||||
#include "src/__support/macros/properties/compiler.h"
|
||||
#include "src/__support/macros/properties/complex_types.h"
|
||||
|
||||
namespace LIBC_NAMESPACE_DECL {
|
||||
namespace cpp {
|
||||
|
||||
// is_complex
|
||||
#ifdef LIBC_COMPILER_IS_MSVC
|
||||
// TODO: Add support for complex types with MSVC.
|
||||
template <typename T> struct is_complex : false_type {};
|
||||
#else
|
||||
template <typename T> struct is_complex {
|
||||
private:
|
||||
template <typename Head, typename... Args>
|
||||
@@ -40,6 +45,8 @@ public:
|
||||
#endif
|
||||
>();
|
||||
};
|
||||
#endif // LIBC_COMPILER_IS_MSVC
|
||||
|
||||
template <typename T>
|
||||
LIBC_INLINE_VAR constexpr bool is_complex_v = is_complex<T>::value;
|
||||
template <typename T1, typename T2>
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include "src/__support/CPP/type_traits/remove_all_extents.h"
|
||||
#include "src/__support/CPP/type_traits/true_type.h"
|
||||
#include "src/__support/CPP/type_traits/type_identity.h"
|
||||
#include "src/__support/CPP/utility/declval.h"
|
||||
#include "src/__support/macros/attributes.h"
|
||||
#include "src/__support/macros/config.h"
|
||||
|
||||
@@ -22,7 +23,7 @@ namespace LIBC_NAMESPACE_DECL {
|
||||
namespace cpp {
|
||||
|
||||
// is_destructible
|
||||
#if __has_builtin(__is_destructible)
|
||||
#if __has_builtin(__is_destructible) || defined(LIBC_COMPILER_IS_MSVC)
|
||||
template <typename T>
|
||||
struct is_destructible : bool_constant<__is_destructible(T)> {};
|
||||
#else
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
#include "src/__support/macros/attributes.h"
|
||||
#include "src/__support/macros/config.h"
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
namespace LIBC_NAMESPACE_DECL {
|
||||
namespace cpp {
|
||||
|
||||
@@ -46,6 +48,10 @@ public:
|
||||
LIBC_INLINE constexpr bool operator()() const { return is_unsigned::value; }
|
||||
};
|
||||
#endif // LIBC_COMPILER_HAS_FIXED_POINT
|
||||
#if LIBC_HAS_VECTOR_TYPE
|
||||
template <typename T, size_t N>
|
||||
struct is_unsigned<T [[clang::ext_vector_type(N)]]> : bool_constant<false> {};
|
||||
#endif
|
||||
|
||||
template <typename T>
|
||||
LIBC_INLINE_VAR constexpr bool is_unsigned_v = is_unsigned<T>::value;
|
||||
|
||||
@@ -5,12 +5,15 @@
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_LIBC_SRC___SUPPORT_CPP_UTILITY_INTEGER_SEQUENCE_H
|
||||
#define LLVM_LIBC_SRC___SUPPORT_CPP_UTILITY_INTEGER_SEQUENCE_H
|
||||
|
||||
#include "src/__support/CPP/type_traits/is_integral.h"
|
||||
#include "src/__support/macros/config.h"
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
namespace LIBC_NAMESPACE_DECL {
|
||||
namespace cpp {
|
||||
|
||||
@@ -34,6 +37,13 @@ template <typename T, int N>
|
||||
using make_integer_sequence =
|
||||
typename detail::make_integer_sequence<T, N - 1>::type;
|
||||
|
||||
// index sequence
|
||||
template <size_t... Ints>
|
||||
using index_sequence = integer_sequence<size_t, Ints...>;
|
||||
template <int N>
|
||||
using make_index_sequence =
|
||||
typename detail::make_integer_sequence<size_t, N - 1>::type;
|
||||
|
||||
} // namespace cpp
|
||||
} // namespace LIBC_NAMESPACE_DECL
|
||||
|
||||
|
||||
+6
-7
@@ -15,6 +15,7 @@
|
||||
#ifndef LLVM_LIBC_SRC___SUPPORT_FPUTIL_FPBITS_H
|
||||
#define LLVM_LIBC_SRC___SUPPORT_FPUTIL_FPBITS_H
|
||||
|
||||
#include "hdr/stdint_proxy.h"
|
||||
#include "src/__support/CPP/bit.h"
|
||||
#include "src/__support/CPP/type_traits.h"
|
||||
#include "src/__support/common.h"
|
||||
@@ -26,8 +27,6 @@
|
||||
#include "src/__support/sign.h" // Sign
|
||||
#include "src/__support/uint128.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
namespace LIBC_NAMESPACE_DECL {
|
||||
namespace fputil {
|
||||
|
||||
@@ -790,16 +789,16 @@ struct FPRep : public FPRepImpl<fp_type, FPRep<fp_type>> {
|
||||
// Returns the FPType corresponding to C++ type T on the host.
|
||||
template <typename T> LIBC_INLINE static constexpr FPType get_fp_type() {
|
||||
using UnqualT = cpp::remove_cv_t<T>;
|
||||
if constexpr (cpp::is_same_v<UnqualT, float> && __FLT_MANT_DIG__ == 24)
|
||||
if constexpr (cpp::is_same_v<UnqualT, float> && FLT_MANT_DIG == 24)
|
||||
return FPType::IEEE754_Binary32;
|
||||
else if constexpr (cpp::is_same_v<UnqualT, double> && __DBL_MANT_DIG__ == 53)
|
||||
else if constexpr (cpp::is_same_v<UnqualT, double> && DBL_MANT_DIG == 53)
|
||||
return FPType::IEEE754_Binary64;
|
||||
else if constexpr (cpp::is_same_v<UnqualT, long double>) {
|
||||
if constexpr (__LDBL_MANT_DIG__ == 53)
|
||||
if constexpr (LDBL_MANT_DIG == 53)
|
||||
return FPType::IEEE754_Binary64;
|
||||
else if constexpr (__LDBL_MANT_DIG__ == 64)
|
||||
else if constexpr (LDBL_MANT_DIG == 64)
|
||||
return FPType::X86_Binary80;
|
||||
else if constexpr (__LDBL_MANT_DIG__ == 113)
|
||||
else if constexpr (LDBL_MANT_DIG == 113)
|
||||
return FPType::IEEE754_Binary128;
|
||||
}
|
||||
#if defined(LIBC_TYPES_HAS_FLOAT16)
|
||||
|
||||
+50
-4
@@ -10,18 +10,21 @@
|
||||
#define LLVM_LIBC_SRC___SUPPORT_FPUTIL_ROUNDING_MODE_H
|
||||
|
||||
#include "hdr/fenv_macros.h"
|
||||
#include "src/__support/CPP/type_traits.h" // is_constant_evaluated
|
||||
#include "src/__support/macros/attributes.h" // LIBC_INLINE
|
||||
#include "src/__support/macros/config.h"
|
||||
|
||||
namespace LIBC_NAMESPACE_DECL {
|
||||
namespace fputil {
|
||||
|
||||
namespace generic {
|
||||
|
||||
// Quick free-standing test whether fegetround() == FE_UPWARD.
|
||||
// Using the following observation:
|
||||
// 1.0f + 2^-25 = 1.0f for FE_TONEAREST, FE_DOWNWARD, FE_TOWARDZERO
|
||||
// = 0x1.000002f for FE_UPWARD.
|
||||
LIBC_INLINE bool fenv_is_round_up() {
|
||||
volatile float x = 0x1.0p-25f;
|
||||
static volatile float x = 0x1.0p-25f;
|
||||
return (1.0f + x != 1.0f);
|
||||
}
|
||||
|
||||
@@ -30,7 +33,7 @@ LIBC_INLINE bool fenv_is_round_up() {
|
||||
// -1.0f - 2^-25 = -1.0f for FE_TONEAREST, FE_UPWARD, FE_TOWARDZERO
|
||||
// = -0x1.000002f for FE_DOWNWARD.
|
||||
LIBC_INLINE bool fenv_is_round_down() {
|
||||
volatile float x = 0x1.0p-25f;
|
||||
static volatile float x = 0x1.0p-25f;
|
||||
return (-1.0f - x != -1.0f);
|
||||
}
|
||||
|
||||
@@ -42,8 +45,8 @@ LIBC_INLINE bool fenv_is_round_down() {
|
||||
// = 0x1.0ffffep-1f for FE_DOWNWARD, FE_TOWARDZERO
|
||||
LIBC_INLINE bool fenv_is_round_to_nearest() {
|
||||
static volatile float x = 0x1.0p-24f;
|
||||
float y = x;
|
||||
return (1.5f + y == 1.5f - y);
|
||||
float y = 1.5f + x;
|
||||
return (y == 1.5f - x);
|
||||
}
|
||||
|
||||
// Quick free-standing test whether fegetround() == FE_TOWARDZERO.
|
||||
@@ -75,6 +78,49 @@ LIBC_INLINE int quick_get_round() {
|
||||
return (2.0f + y == 2.0f) ? FE_TONEAREST : FE_UPWARD;
|
||||
}
|
||||
|
||||
} // namespace generic
|
||||
|
||||
LIBC_INLINE static constexpr bool fenv_is_round_up() {
|
||||
if (cpp::is_constant_evaluated()) {
|
||||
return false;
|
||||
} else {
|
||||
return generic::fenv_is_round_up();
|
||||
}
|
||||
}
|
||||
|
||||
LIBC_INLINE static constexpr bool fenv_is_round_down() {
|
||||
if (cpp::is_constant_evaluated()) {
|
||||
return false;
|
||||
} else {
|
||||
return generic::fenv_is_round_down();
|
||||
}
|
||||
}
|
||||
|
||||
LIBC_INLINE static constexpr bool fenv_is_round_to_nearest() {
|
||||
if (cpp::is_constant_evaluated()) {
|
||||
return true;
|
||||
} else {
|
||||
return generic::fenv_is_round_to_nearest();
|
||||
}
|
||||
}
|
||||
|
||||
LIBC_INLINE static constexpr bool fenv_is_round_to_zero() {
|
||||
if (cpp::is_constant_evaluated()) {
|
||||
return false;
|
||||
} else {
|
||||
return generic::fenv_is_round_to_zero();
|
||||
}
|
||||
}
|
||||
|
||||
// Quick free standing get rounding mode based on the above observations.
|
||||
LIBC_INLINE static constexpr int quick_get_round() {
|
||||
if (cpp::is_constant_evaluated()) {
|
||||
return FE_TONEAREST;
|
||||
} else {
|
||||
return generic::quick_get_round();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace fputil
|
||||
} // namespace LIBC_NAMESPACE_DECL
|
||||
|
||||
|
||||
+14
-14
@@ -9,6 +9,7 @@
|
||||
#ifndef LLVM_LIBC_SRC___SUPPORT_BIG_INT_H
|
||||
#define LLVM_LIBC_SRC___SUPPORT_BIG_INT_H
|
||||
|
||||
#include "hdr/stdint_proxy.h"
|
||||
#include "src/__support/CPP/array.h"
|
||||
#include "src/__support/CPP/bit.h" // countl_zero
|
||||
#include "src/__support/CPP/limits.h"
|
||||
@@ -23,7 +24,6 @@
|
||||
#include "src/__support/number_pair.h"
|
||||
|
||||
#include <stddef.h> // For size_t
|
||||
#include <stdint.h>
|
||||
|
||||
namespace LIBC_NAMESPACE_DECL {
|
||||
|
||||
@@ -95,10 +95,10 @@ LIBC_INLINE constexpr DoubleWide<word> mul2(word a, word b) {
|
||||
#endif
|
||||
else {
|
||||
using half_word = half_width_t<word>;
|
||||
const auto shiftl = [](word value) -> word {
|
||||
constexpr auto shiftl = [](word value) -> word {
|
||||
return value << cpp::numeric_limits<half_word>::digits;
|
||||
};
|
||||
const auto shiftr = [](word value) -> word {
|
||||
constexpr auto shiftr = [](word value) -> word {
|
||||
return value >> cpp::numeric_limits<half_word>::digits;
|
||||
};
|
||||
// Here we do a one digit multiplication where 'a' and 'b' are of type
|
||||
@@ -111,19 +111,19 @@ LIBC_INLINE constexpr DoubleWide<word> mul2(word a, word b) {
|
||||
// c result
|
||||
// We convert 'lo' and 'hi' from 'half_word' to 'word' so multiplication
|
||||
// doesn't overflow.
|
||||
const word a_lo = lo(a);
|
||||
const word b_lo = lo(b);
|
||||
const word a_hi = hi(a);
|
||||
const word b_hi = hi(b);
|
||||
const word step1 = b_lo * a_lo; // no overflow;
|
||||
const word step2 = b_lo * a_hi; // no overflow;
|
||||
const word step3 = b_hi * a_lo; // no overflow;
|
||||
const word step4 = b_hi * a_hi; // no overflow;
|
||||
word a_lo = lo(a);
|
||||
word b_lo = lo(b);
|
||||
word a_hi = hi(a);
|
||||
word b_hi = hi(b);
|
||||
word step1 = b_lo * a_lo; // no overflow;
|
||||
word step2 = b_lo * a_hi; // no overflow;
|
||||
word step3 = b_hi * a_lo; // no overflow;
|
||||
word step4 = b_hi * a_hi; // no overflow;
|
||||
word lo_digit = step1;
|
||||
word hi_digit = step4;
|
||||
const word no_carry = 0;
|
||||
word carry;
|
||||
word _; // unused carry variable.
|
||||
word no_carry = 0;
|
||||
word carry = 0;
|
||||
[[maybe_unused]] word _ = 0; // unused carry variable.
|
||||
lo_digit = add_with_carry<word>(lo_digit, shiftl(step2), no_carry, carry);
|
||||
hi_digit = add_with_carry<word>(hi_digit, shiftr(step2), carry, _);
|
||||
lo_digit = add_with_carry<word>(lo_digit, shiftl(step3), no_carry, carry);
|
||||
|
||||
+3
-2
@@ -16,6 +16,7 @@
|
||||
#include "src/__support/macros/attributes.h"
|
||||
#include "src/__support/macros/config.h"
|
||||
#include "src/__support/macros/properties/architectures.h"
|
||||
#include "src/__support/macros/properties/compiler.h"
|
||||
|
||||
#ifndef LLVM_LIBC_FUNCTION_ATTR
|
||||
#define LLVM_LIBC_FUNCTION_ATTR
|
||||
@@ -41,12 +42,12 @@
|
||||
// to cleanly export and alias the C++ symbol `LIBC_NAMESPACE::func` with the C
|
||||
// symbol `func`. So for public packaging on MacOS, we will only export the C
|
||||
// symbol. Moreover, a C symbol `func` in macOS is mangled as `_func`.
|
||||
#if defined(LIBC_COPT_PUBLIC_PACKAGING)
|
||||
#if defined(LIBC_COPT_PUBLIC_PACKAGING) && !defined(LIBC_COMPILER_IS_MSVC)
|
||||
#ifndef __APPLE__
|
||||
#define LLVM_LIBC_FUNCTION_IMPL(type, name, arglist) \
|
||||
LLVM_LIBC_ATTR(name) \
|
||||
LLVM_LIBC_FUNCTION_ATTR decltype(LIBC_NAMESPACE::name) \
|
||||
__##name##_impl__ __asm__(#name); \
|
||||
__##name##_impl__ asm(#name); \
|
||||
decltype(LIBC_NAMESPACE::name) name [[gnu::alias(#name)]]; \
|
||||
type __##name##_impl__ arglist
|
||||
#else // __APPLE__
|
||||
|
||||
+19
-12
@@ -27,7 +27,7 @@ namespace internal {
|
||||
// as well as a way to support non-ASCII character encodings.
|
||||
|
||||
// Similarly, do not change these functions to use case ranges. e.g.
|
||||
// bool islower(int ch) {
|
||||
// bool islower(char ch) {
|
||||
// switch(ch) {
|
||||
// case 'a'...'z':
|
||||
// return true;
|
||||
@@ -37,7 +37,7 @@ namespace internal {
|
||||
// EBCDIC. Technically we could use some smaller ranges, but that's even harder
|
||||
// to read.
|
||||
|
||||
LIBC_INLINE static constexpr bool islower(int ch) {
|
||||
LIBC_INLINE static constexpr bool islower(char ch) {
|
||||
switch (ch) {
|
||||
case 'a':
|
||||
case 'b':
|
||||
@@ -71,7 +71,7 @@ LIBC_INLINE static constexpr bool islower(int ch) {
|
||||
}
|
||||
}
|
||||
|
||||
LIBC_INLINE static constexpr bool isupper(int ch) {
|
||||
LIBC_INLINE static constexpr bool isupper(char ch) {
|
||||
switch (ch) {
|
||||
case 'A':
|
||||
case 'B':
|
||||
@@ -105,7 +105,7 @@ LIBC_INLINE static constexpr bool isupper(int ch) {
|
||||
}
|
||||
}
|
||||
|
||||
LIBC_INLINE static constexpr bool isdigit(int ch) {
|
||||
LIBC_INLINE static constexpr bool isdigit(char ch) {
|
||||
switch (ch) {
|
||||
case '0':
|
||||
case '1':
|
||||
@@ -123,7 +123,7 @@ LIBC_INLINE static constexpr bool isdigit(int ch) {
|
||||
}
|
||||
}
|
||||
|
||||
LIBC_INLINE static constexpr int tolower(int ch) {
|
||||
LIBC_INLINE static constexpr char tolower(char ch) {
|
||||
switch (ch) {
|
||||
case 'A':
|
||||
return 'a';
|
||||
@@ -182,7 +182,7 @@ LIBC_INLINE static constexpr int tolower(int ch) {
|
||||
}
|
||||
}
|
||||
|
||||
LIBC_INLINE static constexpr int toupper(int ch) {
|
||||
LIBC_INLINE static constexpr char toupper(char ch) {
|
||||
switch (ch) {
|
||||
case 'a':
|
||||
return 'A';
|
||||
@@ -241,7 +241,7 @@ LIBC_INLINE static constexpr int toupper(int ch) {
|
||||
}
|
||||
}
|
||||
|
||||
LIBC_INLINE static constexpr bool isalpha(int ch) {
|
||||
LIBC_INLINE static constexpr bool isalpha(char ch) {
|
||||
switch (ch) {
|
||||
case 'a':
|
||||
case 'b':
|
||||
@@ -301,7 +301,7 @@ LIBC_INLINE static constexpr bool isalpha(int ch) {
|
||||
}
|
||||
}
|
||||
|
||||
LIBC_INLINE static constexpr bool isalnum(int ch) {
|
||||
LIBC_INLINE static constexpr bool isalnum(char ch) {
|
||||
switch (ch) {
|
||||
case 'a':
|
||||
case 'b':
|
||||
@@ -371,7 +371,7 @@ LIBC_INLINE static constexpr bool isalnum(int ch) {
|
||||
}
|
||||
}
|
||||
|
||||
LIBC_INLINE static constexpr int b36_char_to_int(int ch) {
|
||||
LIBC_INLINE static constexpr int b36_char_to_int(char ch) {
|
||||
switch (ch) {
|
||||
case '0':
|
||||
return 0;
|
||||
@@ -476,7 +476,7 @@ LIBC_INLINE static constexpr int b36_char_to_int(int ch) {
|
||||
}
|
||||
}
|
||||
|
||||
LIBC_INLINE static constexpr int int_to_b36_char(int num) {
|
||||
LIBC_INLINE static constexpr char int_to_b36_char(int num) {
|
||||
// Can't actually use LIBC_ASSERT here because it depends on integer_to_string
|
||||
// which depends on this.
|
||||
|
||||
@@ -559,7 +559,7 @@ LIBC_INLINE static constexpr int int_to_b36_char(int num) {
|
||||
}
|
||||
}
|
||||
|
||||
LIBC_INLINE static constexpr bool isspace(int ch) {
|
||||
LIBC_INLINE static constexpr bool isspace(char ch) {
|
||||
switch (ch) {
|
||||
case ' ':
|
||||
case '\t':
|
||||
@@ -574,10 +574,17 @@ LIBC_INLINE static constexpr bool isspace(int ch) {
|
||||
}
|
||||
|
||||
// not yet encoding independent.
|
||||
LIBC_INLINE static constexpr bool isgraph(int ch) {
|
||||
LIBC_INLINE static constexpr bool isgraph(char ch) {
|
||||
return 0x20 < ch && ch < 0x7f;
|
||||
}
|
||||
|
||||
// An overload which provides a way to compare input with specific character
|
||||
// values, when input can be of a regular or a wide character type.
|
||||
LIBC_INLINE static constexpr bool is_char_or_wchar(char ch, char c_value,
|
||||
[[maybe_unused]] wchar_t) {
|
||||
return (ch == c_value);
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace LIBC_NAMESPACE_DECL
|
||||
|
||||
|
||||
+1
-2
@@ -9,11 +9,10 @@
|
||||
#ifndef LLVM_LIBC_SRC___SUPPORT_DETAILED_POWERS_OF_TEN_H
|
||||
#define LLVM_LIBC_SRC___SUPPORT_DETAILED_POWERS_OF_TEN_H
|
||||
|
||||
#include "hdr/stdint_proxy.h"
|
||||
#include "src/__support/common.h"
|
||||
#include "src/__support/macros/config.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
namespace LIBC_NAMESPACE_DECL {
|
||||
namespace internal {
|
||||
|
||||
|
||||
+33
-14
@@ -15,11 +15,12 @@
|
||||
#ifndef LLVM_LIBC_SRC___SUPPORT_HIGH_PRECISION_DECIMAL_H
|
||||
#define LLVM_LIBC_SRC___SUPPORT_HIGH_PRECISION_DECIMAL_H
|
||||
|
||||
#include "hdr/stdint_proxy.h"
|
||||
#include "src/__support/CPP/limits.h"
|
||||
#include "src/__support/ctype_utils.h"
|
||||
#include "src/__support/macros/config.h"
|
||||
#include "src/__support/str_to_integer.h"
|
||||
#include <stdint.h>
|
||||
#include "src/__support/wctype_utils.h"
|
||||
|
||||
namespace LIBC_NAMESPACE_DECL {
|
||||
namespace internal {
|
||||
@@ -38,6 +39,24 @@ struct LShiftTableEntry {
|
||||
// TODO: Figure out where to put this.
|
||||
enum class RoundDirection { Up, Down, Nearest };
|
||||
|
||||
// These constants are used in both this file and in the main str_to_float.h.
|
||||
// TODO: Figure out where to put this.
|
||||
template <typename CharType> struct constants;
|
||||
template <> struct constants<char> {
|
||||
static constexpr char DECIMAL_POINT = '.';
|
||||
static constexpr char DECIMAL_EXPONENT_MARKER = 'e';
|
||||
static constexpr char HEX_EXPONENT_MARKER = 'p';
|
||||
static constexpr char INF_STRING[] = "infinity";
|
||||
static constexpr char NAN_STRING[] = "nan";
|
||||
};
|
||||
template <> struct constants<wchar_t> {
|
||||
static constexpr wchar_t DECIMAL_POINT = L'.';
|
||||
static constexpr wchar_t DECIMAL_EXPONENT_MARKER = L'e';
|
||||
static constexpr wchar_t HEX_EXPONENT_MARKER = L'p';
|
||||
static constexpr wchar_t INF_STRING[] = L"infinity";
|
||||
static constexpr wchar_t NAN_STRING[] = L"nan";
|
||||
};
|
||||
|
||||
// This is based on the HPD data structure described as part of the Simple
|
||||
// Decimal Conversion algorithm by Nigel Tao, described at this link:
|
||||
// https://nigeltao.github.io/blog/2020/parse-number-f64-simple.html
|
||||
@@ -314,9 +333,9 @@ private:
|
||||
public:
|
||||
// num_string is assumed to be a string of numeric characters. It doesn't
|
||||
// handle leading spaces.
|
||||
LIBC_INLINE
|
||||
HighPrecisionDecimal(
|
||||
const char *__restrict num_string,
|
||||
template <typename CharType>
|
||||
LIBC_INLINE HighPrecisionDecimal(
|
||||
const CharType *__restrict num_string,
|
||||
const size_t num_len = cpp::numeric_limits<size_t>::max()) {
|
||||
bool saw_dot = false;
|
||||
size_t num_cur = 0;
|
||||
@@ -324,25 +343,26 @@ public:
|
||||
// them all.
|
||||
uint32_t total_digits = 0;
|
||||
while (num_cur < num_len &&
|
||||
(isdigit(num_string[num_cur]) || num_string[num_cur] == '.')) {
|
||||
if (num_string[num_cur] == '.') {
|
||||
(isdigit(num_string[num_cur]) ||
|
||||
num_string[num_cur] == constants<CharType>::DECIMAL_POINT)) {
|
||||
if (num_string[num_cur] == constants<CharType>::DECIMAL_POINT) {
|
||||
if (saw_dot) {
|
||||
break;
|
||||
}
|
||||
this->decimal_point = static_cast<int32_t>(total_digits);
|
||||
saw_dot = true;
|
||||
} else {
|
||||
if (num_string[num_cur] == '0' && this->num_digits == 0) {
|
||||
int digit = b36_char_to_int(num_string[num_cur]);
|
||||
if (digit == 0 && this->num_digits == 0) {
|
||||
--this->decimal_point;
|
||||
++num_cur;
|
||||
continue;
|
||||
}
|
||||
++total_digits;
|
||||
if (this->num_digits < MAX_NUM_DIGITS) {
|
||||
this->digits[this->num_digits] = static_cast<uint8_t>(
|
||||
internal::b36_char_to_int(num_string[num_cur]));
|
||||
this->digits[this->num_digits] = static_cast<uint8_t>(digit);
|
||||
++this->num_digits;
|
||||
} else if (num_string[num_cur] != '0') {
|
||||
} else if (digit != 0) {
|
||||
this->truncated = true;
|
||||
}
|
||||
}
|
||||
@@ -352,11 +372,10 @@ public:
|
||||
if (!saw_dot)
|
||||
this->decimal_point = static_cast<int32_t>(total_digits);
|
||||
|
||||
if (num_cur < num_len &&
|
||||
(num_string[num_cur] == 'e' || num_string[num_cur] == 'E')) {
|
||||
if (num_cur < num_len && tolower(num_string[num_cur]) ==
|
||||
constants<CharType>::DECIMAL_EXPONENT_MARKER) {
|
||||
++num_cur;
|
||||
if (isdigit(num_string[num_cur]) || num_string[num_cur] == '+' ||
|
||||
num_string[num_cur] == '-') {
|
||||
if (isdigit(num_string[num_cur]) || get_sign(num_string + num_cur) != 0) {
|
||||
auto result =
|
||||
strtointeger<int32_t>(num_string + num_cur, 10, num_len - num_cur);
|
||||
if (result.has_error()) {
|
||||
|
||||
+2
@@ -14,9 +14,11 @@
|
||||
// The build is configured to just use the public <assert.h> API
|
||||
// for libc's internal assertions.
|
||||
|
||||
#ifndef LIBC_ASSERT
|
||||
#include <assert.h>
|
||||
|
||||
#define LIBC_ASSERT(COND) assert(COND)
|
||||
#endif // LIBC_ASSERT
|
||||
|
||||
#else // Not LIBC_COPT_USE_C_ASSERT
|
||||
|
||||
|
||||
+44
-1
@@ -17,6 +17,7 @@
|
||||
#ifndef LLVM_LIBC_SRC___SUPPORT_MACROS_ATTRIBUTES_H
|
||||
#define LLVM_LIBC_SRC___SUPPORT_MACROS_ATTRIBUTES_H
|
||||
|
||||
#include "config.h"
|
||||
#include "properties/architectures.h"
|
||||
|
||||
#ifndef __has_attribute
|
||||
@@ -28,7 +29,32 @@
|
||||
#define LIBC_INLINE_ASM __asm__ __volatile__
|
||||
#define LIBC_UNUSED __attribute__((unused))
|
||||
|
||||
#ifdef LIBC_TARGET_ARCH_IS_GPU
|
||||
// Uses the platform specific specialization
|
||||
#define LIBC_THREAD_MODE_PLATFORM 0
|
||||
|
||||
// Mutex guards nothing, used in single-threaded implementations
|
||||
#define LIBC_THREAD_MODE_SINGLE 1
|
||||
|
||||
// Vendor provides implementation
|
||||
#define LIBC_THREAD_MODE_EXTERNAL 2
|
||||
|
||||
// libcxx doesn't define LIBC_THREAD_MODE, unless that is passed in the command
|
||||
// line in the CMake invocation. This defaults to the original implementation
|
||||
// (before changes in https://github.com/llvm/llvm-project/pull/145358)
|
||||
#ifndef LIBC_THREAD_MODE
|
||||
#define LIBC_THREAD_MODE LIBC_THREAD_MODE_PLATFORM
|
||||
#endif // LIBC_THREAD_MODE
|
||||
|
||||
#if LIBC_THREAD_MODE != LIBC_THREAD_MODE_PLATFORM && \
|
||||
LIBC_THREAD_MODE != LIBC_THREAD_MODE_SINGLE && \
|
||||
LIBC_THREAD_MODE != LIBC_THREAD_MODE_EXTERNAL
|
||||
#error LIBC_THREAD_MODE must be one of the following values: \
|
||||
LIBC_THREAD_MODE_PLATFORM, \
|
||||
LIBC_THREAD_MODE_SINGLE, \
|
||||
LIBC_THREAD_MODE_EXTERNAL.
|
||||
#endif
|
||||
|
||||
#if LIBC_THREAD_MODE == LIBC_THREAD_MODE_SINGLE
|
||||
#define LIBC_THREAD_LOCAL
|
||||
#else
|
||||
#define LIBC_THREAD_LOCAL thread_local
|
||||
@@ -48,4 +74,21 @@
|
||||
#define LIBC_PREFERED_TYPE(TYPE)
|
||||
#endif
|
||||
|
||||
#if __has_attribute(ext_vector_type) && \
|
||||
LIBC_HAS_FEATURE(ext_vector_type_boolean)
|
||||
#define LIBC_HAS_VECTOR_TYPE 1
|
||||
#else
|
||||
#define LIBC_HAS_VECTOR_TYPE 0
|
||||
#endif
|
||||
|
||||
#if __has_attribute(no_sanitize)
|
||||
// Disable regular and hardware-supported ASan for functions that may
|
||||
// intentionally make out-of-bounds access. Disable TSan as well, as it detects
|
||||
// out-of-bounds accesses to heap memory.
|
||||
#define LIBC_NO_SANITIZE_OOB_ACCESS \
|
||||
__attribute__((no_sanitize("address", "hwaddress", "thread")))
|
||||
#else
|
||||
#define LIBC_NO_SANITIZE_OOB_ACCESS
|
||||
#endif
|
||||
|
||||
#endif // LLVM_LIBC_SRC___SUPPORT_MACROS_ATTRIBUTES_H
|
||||
|
||||
+23
@@ -13,6 +13,13 @@
|
||||
#ifndef LLVM_LIBC_SRC___SUPPORT_MACROS_CONFIG_H
|
||||
#define LLVM_LIBC_SRC___SUPPORT_MACROS_CONFIG_H
|
||||
|
||||
#include "src/__support/macros/properties/architectures.h"
|
||||
#include "src/__support/macros/properties/compiler.h"
|
||||
|
||||
#ifdef LIBC_COMPILER_IS_MSVC
|
||||
#include <intrin.h>
|
||||
#endif // LIBC_COMPILER_IS_MSVC
|
||||
|
||||
// Workaround for compilers that do not support builtin detection.
|
||||
// FIXME: This is only required for the GPU portion which should be moved.
|
||||
#ifndef __has_builtin
|
||||
@@ -27,6 +34,22 @@
|
||||
#define LIBC_HAS_FEATURE(f) 0
|
||||
#endif
|
||||
|
||||
#ifdef LIBC_COMPILER_IS_MSVC
|
||||
|
||||
// __builtin_trap replacement
|
||||
#ifdef LIBC_TARGET_ARCH_IS_X86
|
||||
#define __builtin_trap __ud2
|
||||
#else // arm64
|
||||
#define __builtin_trap() __break(1)
|
||||
#endif
|
||||
|
||||
#define __builtin_expect(value, expectation) (value)
|
||||
#define __builtin_unreachable() __assume(0)
|
||||
|
||||
#define __builtin_prefetch(X, Y, Z)
|
||||
|
||||
#endif // LIBC_COMPILER_IS_MSVC
|
||||
|
||||
#ifdef __clang__
|
||||
// Declare a LIBC_NAMESPACE with hidden visibility. `namespace
|
||||
// LIBC_NAMESPACE_DECL {` should be used around all declarations and definitions
|
||||
|
||||
+1
-2
@@ -11,9 +11,8 @@
|
||||
|
||||
#include "src/__support/macros/config.h"
|
||||
#include "src/__support/macros/optimization.h"
|
||||
#include "src/__support/macros/sanitizer.h"
|
||||
|
||||
#if defined(LIBC_ADD_NULL_CHECKS) && !defined(LIBC_HAS_SANITIZER)
|
||||
#if defined(LIBC_ADD_NULL_CHECKS)
|
||||
#define LIBC_CRASH_ON_NULLPTR(ptr) \
|
||||
do { \
|
||||
if (LIBC_UNLIKELY((ptr) == nullptr)) \
|
||||
|
||||
@@ -34,6 +34,9 @@ LIBC_INLINE constexpr bool expects_bool_condition(T value, T expected) {
|
||||
#elif defined(LIBC_COMPILER_IS_GCC)
|
||||
#define LIBC_LOOP_NOUNROLL _Pragma("GCC unroll 0")
|
||||
#define LIBC_LOOP_UNROLL _Pragma("GCC unroll 2048")
|
||||
#elif defined(LIBC_COMPILER_IS_MSVC)
|
||||
#define LIBC_LOOP_NOUNROLL
|
||||
#define LIBC_LOOP_UNROLL
|
||||
#else
|
||||
#error "Unhandled compiler"
|
||||
#endif
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
#define LIBC_TARGET_ARCH_IS_GPU
|
||||
#endif
|
||||
|
||||
#if defined(__pnacl__) || defined(__CLR_VER) || defined(LIBC_TARGET_ARCH_IS_GPU)
|
||||
#if defined(__CLR_VER) || defined(LIBC_TARGET_ARCH_IS_GPU)
|
||||
#define LIBC_TARGET_ARCH_IS_VM
|
||||
#endif
|
||||
|
||||
@@ -41,6 +41,10 @@
|
||||
#define LIBC_TARGET_ARCH_IS_ARM
|
||||
#endif
|
||||
|
||||
#if defined(__wasm__)
|
||||
#define LIBC_TARGET_ARCH_IS_WASM
|
||||
#endif
|
||||
|
||||
#if defined(__aarch64__) || defined(__arm64__) || defined(_M_ARM64)
|
||||
#define LIBC_TARGET_ARCH_IS_AARCH64
|
||||
#endif
|
||||
|
||||
@@ -34,10 +34,15 @@
|
||||
#define LIBC_COMPILER_GCC_VER (__GNUC__ * 100 + __GNUC_MINOR__)
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#define LIBC_COMPILER_IS_MSC
|
||||
#if defined(_MSC_VER) && !defined(__clang__)
|
||||
#define LIBC_COMPILER_IS_MSVC
|
||||
// https://learn.microsoft.com/en-us/cpp/preprocessor/predefined-macros
|
||||
#define LIBC_COMPILER_MSC_VER (_MSC_VER)
|
||||
#define LIBC_COMPILER_MSVC_VER (_MSC_VER)
|
||||
#ifdef _M_X64
|
||||
#define LIBC_COMPILER_IS_MSVC_X64
|
||||
#else
|
||||
#define LIBC_COMPILER_IS_MSVC_X86
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif // LLVM_LIBC_SRC___SUPPORT_MACROS_PROPERTIES_COMPILER_H
|
||||
|
||||
@@ -18,6 +18,18 @@
|
||||
#define LIBC_TARGET_CPU_HAS_FULLFP16
|
||||
#endif
|
||||
|
||||
#if defined(__ARM_FEATURE_SVE)
|
||||
#define LIBC_TARGET_CPU_HAS_SVE
|
||||
#endif
|
||||
|
||||
#if defined(__ARM_FEATURE_SVE2)
|
||||
#define LIBC_TARGET_CPU_HAS_SVE2
|
||||
#endif
|
||||
|
||||
#if defined(__ARM_FEATURE_MOPS)
|
||||
#define LIBC_TARGET_CPU_HAS_MOPS
|
||||
#endif
|
||||
|
||||
#if defined(__SSE2__)
|
||||
#define LIBC_TARGET_CPU_HAS_SSE2
|
||||
#define LIBC_TARGET_CPU_HAS_FPU_FLOAT
|
||||
@@ -59,6 +71,10 @@
|
||||
#endif // LIBC_TARGET_CPU_HAS_ARM_FPU_DOUBLE
|
||||
#endif // __ARM_FP
|
||||
|
||||
#if defined(__ARM_NEON)
|
||||
#define LIBC_TARGET_CPU_HAS_ARM_NEON
|
||||
#endif
|
||||
|
||||
#if defined(__riscv_flen)
|
||||
// https://github.com/riscv-non-isa/riscv-c-api-doc/blob/main/src/c-api.adoc
|
||||
#if defined(__riscv_zfhmin)
|
||||
@@ -81,7 +97,7 @@
|
||||
#endif
|
||||
|
||||
#if defined(__ARM_FEATURE_FMA) || (defined(__AVX2__) && defined(__FMA__)) || \
|
||||
defined(__NVPTX__) || defined(__AMDGPU__) || defined(__LIBC_RISCV_USE_FMA)
|
||||
defined(__NVPTX__) || defined(__AMDGPU__) || defined(__riscv_flen)
|
||||
#define LIBC_TARGET_CPU_HAS_FMA
|
||||
// Provide a more fine-grained control of FMA instruction for ARM targets.
|
||||
#if defined(LIBC_TARGET_CPU_HAS_FPU_HALF)
|
||||
|
||||
+2
-3
@@ -10,7 +10,8 @@
|
||||
#ifndef LLVM_LIBC_SRC___SUPPORT_MACROS_PROPERTIES_TYPES_H
|
||||
#define LLVM_LIBC_SRC___SUPPORT_MACROS_PROPERTIES_TYPES_H
|
||||
|
||||
#include "hdr/float_macros.h" // LDBL_MANT_DIG
|
||||
#include "hdr/float_macros.h" // LDBL_MANT_DIG
|
||||
#include "hdr/stdint_proxy.h" // UINT64_MAX, __SIZEOF_INT128__
|
||||
#include "include/llvm-libc-macros/float16-macros.h" // LIBC_TYPES_HAS_FLOAT16
|
||||
#include "include/llvm-libc-types/float128.h" // float128
|
||||
#include "src/__support/macros/config.h" // LIBC_NAMESPACE_DECL
|
||||
@@ -19,8 +20,6 @@
|
||||
#include "src/__support/macros/properties/cpu_features.h"
|
||||
#include "src/__support/macros/properties/os.h"
|
||||
|
||||
#include <stdint.h> // UINT64_MAX, __SIZEOF_INT128__
|
||||
|
||||
// 'long double' properties.
|
||||
#if (LDBL_MANT_DIG == 53)
|
||||
#define LIBC_TYPES_LONG_DOUBLE_IS_FLOAT64
|
||||
|
||||
@@ -23,16 +23,6 @@
|
||||
#define LIBC_HAS_MEMORY_SANITIZER
|
||||
#endif
|
||||
|
||||
#if LIBC_HAS_FEATURE(undefined_behavior_sanitizer)
|
||||
#define LIBC_HAS_UNDEFINED_BEHAVIOR_SANITIZER
|
||||
#endif
|
||||
|
||||
#if defined(LIBC_HAS_ADDRESS_SANITIZER) || \
|
||||
defined(LIBC_HAS_MEMORY_SANITIZER) || \
|
||||
defined(LIBC_HAS_UNDEFINED_BEHAVIOR_SANITIZER)
|
||||
#define LIBC_HAS_SANITIZER
|
||||
#endif
|
||||
|
||||
#ifdef LIBC_HAS_MEMORY_SANITIZER
|
||||
// Only perform MSAN unpoison in non-constexpr context.
|
||||
#include <sanitizer/msan_interface.h>
|
||||
|
||||
+20
-4
@@ -25,7 +25,13 @@ LIBC_INLINE constexpr cpp::enable_if_t<cpp::is_unsigned_v<T>, T>
|
||||
mask_trailing_ones() {
|
||||
constexpr unsigned T_BITS = CHAR_BIT * sizeof(T);
|
||||
static_assert(count <= T_BITS && "Invalid bit index");
|
||||
return count == 0 ? 0 : (T(-1) >> (T_BITS - count));
|
||||
// MSVC complains about out of range shifts.
|
||||
if constexpr (count == 0)
|
||||
return 0;
|
||||
else if constexpr (count >= T_BITS)
|
||||
return T(-1);
|
||||
else
|
||||
return T(-1) >> (T_BITS - count);
|
||||
}
|
||||
|
||||
// Create a bitmask with the count left-most bits set to 1, and all other bits
|
||||
@@ -55,18 +61,28 @@ mask_leading_zeros() {
|
||||
// Returns whether 'a + b' overflows, the result is stored in 'res'.
|
||||
template <typename T>
|
||||
[[nodiscard]] LIBC_INLINE constexpr bool add_overflow(T a, T b, T &res) {
|
||||
#if __has_builtin(__builtin_add_overflow)
|
||||
return __builtin_add_overflow(a, b, &res);
|
||||
#else
|
||||
res = a + b;
|
||||
return (res < a) || (res < b);
|
||||
#endif // __builtin_add_overflow
|
||||
}
|
||||
|
||||
// Returns whether 'a - b' overflows, the result is stored in 'res'.
|
||||
template <typename T>
|
||||
[[nodiscard]] LIBC_INLINE constexpr bool sub_overflow(T a, T b, T &res) {
|
||||
#if __has_builtin(__builtin_sub_overflow)
|
||||
return __builtin_sub_overflow(a, b, &res);
|
||||
#else
|
||||
res = a - b;
|
||||
return (res > a);
|
||||
#endif // __builtin_sub_overflow
|
||||
}
|
||||
|
||||
#define RETURN_IF(TYPE, BUILTIN) \
|
||||
if constexpr (cpp::is_same_v<T, TYPE>) \
|
||||
return BUILTIN(a, b, carry_in, carry_out);
|
||||
return BUILTIN(a, b, carry_in, &carry_out);
|
||||
|
||||
// Returns the result of 'a + b' taking into account 'carry_in'.
|
||||
// The carry out is stored in 'carry_out' it not 'nullptr', dropped otherwise.
|
||||
@@ -74,7 +90,7 @@ template <typename T>
|
||||
template <typename T>
|
||||
[[nodiscard]] LIBC_INLINE constexpr cpp::enable_if_t<cpp::is_unsigned_v<T>, T>
|
||||
add_with_carry(T a, T b, T carry_in, T &carry_out) {
|
||||
if constexpr (!cpp::is_constant_evaluated()) {
|
||||
if (!cpp::is_constant_evaluated()) {
|
||||
#if __has_builtin(__builtin_addcb)
|
||||
RETURN_IF(unsigned char, __builtin_addcb)
|
||||
#elif __has_builtin(__builtin_addcs)
|
||||
@@ -100,7 +116,7 @@ add_with_carry(T a, T b, T carry_in, T &carry_out) {
|
||||
template <typename T>
|
||||
[[nodiscard]] LIBC_INLINE constexpr cpp::enable_if_t<cpp::is_unsigned_v<T>, T>
|
||||
sub_with_borrow(T a, T b, T carry_in, T &carry_out) {
|
||||
if constexpr (!cpp::is_constant_evaluated()) {
|
||||
if (!cpp::is_constant_evaluated()) {
|
||||
#if __has_builtin(__builtin_subcb)
|
||||
RETURN_IF(unsigned char, __builtin_subcb)
|
||||
#elif __has_builtin(__builtin_subcs)
|
||||
|
||||
+98
-125
@@ -16,6 +16,7 @@
|
||||
#define LLVM_LIBC_SRC___SUPPORT_STR_TO_FLOAT_H
|
||||
|
||||
#include "hdr/errno_macros.h" // For ERANGE
|
||||
#include "hdr/stdint_proxy.h"
|
||||
#include "src/__support/CPP/bit.h"
|
||||
#include "src/__support/CPP/limits.h"
|
||||
#include "src/__support/CPP/optional.h"
|
||||
@@ -32,8 +33,7 @@
|
||||
#include "src/__support/str_to_integer.h"
|
||||
#include "src/__support/str_to_num_result.h"
|
||||
#include "src/__support/uint128.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include "src/__support/wctype_utils.h"
|
||||
|
||||
namespace LIBC_NAMESPACE_DECL {
|
||||
namespace internal {
|
||||
@@ -335,9 +335,9 @@ constexpr int32_t NUM_POWERS_OF_TWO =
|
||||
// the Eisel-Lemire algorithm fails, it's slower but more accurate. It's based
|
||||
// on the Simple Decimal Conversion algorithm by Nigel Tao, described at this
|
||||
// link: https://nigeltao.github.io/blog/2020/parse-number-f64-simple.html
|
||||
template <class T>
|
||||
template <typename T, typename CharType>
|
||||
LIBC_INLINE FloatConvertReturn<T> simple_decimal_conversion(
|
||||
const char *__restrict numStart,
|
||||
const CharType *__restrict numStart,
|
||||
const size_t num_len = cpp::numeric_limits<size_t>::max(),
|
||||
RoundDirection round = RoundDirection::Nearest) {
|
||||
using FPBits = typename fputil::FPBits<T>;
|
||||
@@ -677,12 +677,11 @@ template <> LIBC_INLINE constexpr int32_t get_lower_bound<double>() {
|
||||
// Takes a mantissa and base 10 exponent and converts it into its closest
|
||||
// floating point type T equivalient. First we try the Eisel-Lemire algorithm,
|
||||
// then if that fails then we fall back to a more accurate algorithm for
|
||||
// accuracy. The resulting mantissa and exponent are placed in outputMantissa
|
||||
// and outputExp2.
|
||||
template <class T>
|
||||
// accuracy.
|
||||
template <typename T, typename CharType>
|
||||
LIBC_INLINE FloatConvertReturn<T> decimal_exp_to_float(
|
||||
ExpandedFloat<T> init_num, bool truncated, RoundDirection round,
|
||||
const char *__restrict numStart,
|
||||
const CharType *__restrict numStart,
|
||||
const size_t num_len = cpp::numeric_limits<size_t>::max()) {
|
||||
using FPBits = typename fputil::FPBits<T>;
|
||||
using StorageType = typename FPBits::StorageType;
|
||||
@@ -861,36 +860,42 @@ LIBC_INLINE FloatConvertReturn<T> binary_exp_to_float(ExpandedFloat<T> init_num,
|
||||
return output;
|
||||
}
|
||||
|
||||
// checks if the next 4 characters of the string pointer are the start of a
|
||||
// Checks if the first characters of the string pointer are the start of a
|
||||
// hexadecimal floating point number. Does not advance the string pointer.
|
||||
LIBC_INLINE bool is_float_hex_start(const char *__restrict src,
|
||||
const char decimalPoint) {
|
||||
if (!(src[0] == '0' && tolower(src[1]) == 'x')) {
|
||||
template <typename CharType>
|
||||
LIBC_INLINE static bool is_float_hex_start(const CharType *__restrict src) {
|
||||
if (!is_char_or_wchar(src[0], '0', L'0') ||
|
||||
!is_char_or_wchar(tolower(src[1]), 'x', L'x')) {
|
||||
return false;
|
||||
}
|
||||
size_t first_digit = 2;
|
||||
if (src[2] == decimalPoint) {
|
||||
if (src[2] == constants<CharType>::DECIMAL_POINT) {
|
||||
++first_digit;
|
||||
}
|
||||
return isalnum(src[first_digit]) && b36_char_to_int(src[first_digit]) < 16;
|
||||
}
|
||||
|
||||
// Takes the start of a string representing a decimal float, as well as the
|
||||
// local decimalPoint. It returns if it suceeded in parsing any digits, and if
|
||||
// the return value is true then the outputs are pointer to the end of the
|
||||
// number, and the mantissa and exponent for the closest float T representation.
|
||||
// If the return value is false, then it is assumed that there is no number
|
||||
// here.
|
||||
template <class T>
|
||||
LIBC_INLINE StrToNumResult<ExpandedFloat<T>>
|
||||
decimal_string_to_float(const char *__restrict src, const char DECIMAL_POINT,
|
||||
RoundDirection round) {
|
||||
// Verifies that first prefix_len characters of str, when lowercased, match the
|
||||
// specified prefix.
|
||||
template <typename CharType>
|
||||
LIBC_INLINE static bool tolower_starts_with(const CharType *str,
|
||||
size_t prefix_len,
|
||||
const CharType *prefix) {
|
||||
for (size_t i = 0; i < prefix_len; ++i) {
|
||||
if (tolower(str[i]) != prefix[i])
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Attempts parsing a decimal floating point number at the start of the string.
|
||||
template <typename T, typename CharType>
|
||||
LIBC_INLINE static StrToNumResult<ExpandedFloat<T>>
|
||||
decimal_string_to_float(const CharType *__restrict src, RoundDirection round) {
|
||||
using FPBits = typename fputil::FPBits<T>;
|
||||
using StorageType = typename FPBits::StorageType;
|
||||
|
||||
constexpr uint32_t BASE = 10;
|
||||
constexpr char EXPONENT_MARKER = 'e';
|
||||
|
||||
bool truncated = false;
|
||||
bool seen_digit = false;
|
||||
bool after_decimal = false;
|
||||
@@ -927,7 +932,7 @@ decimal_string_to_float(const char *__restrict src, const char DECIMAL_POINT,
|
||||
++index;
|
||||
continue;
|
||||
}
|
||||
if (src[index] == DECIMAL_POINT) {
|
||||
if (src[index] == constants<CharType>::DECIMAL_POINT) {
|
||||
if (after_decimal) {
|
||||
break; // this means that src[index] points to a second decimal point,
|
||||
// ending the number.
|
||||
@@ -944,13 +949,10 @@ decimal_string_to_float(const char *__restrict src, const char DECIMAL_POINT,
|
||||
return output;
|
||||
|
||||
// TODO: When adding max length argument, handle the case of a trailing
|
||||
// EXPONENT MARKER, see scanf for more details.
|
||||
if (tolower(src[index]) == EXPONENT_MARKER) {
|
||||
bool has_sign = false;
|
||||
if (src[index + 1] == '+' || src[index + 1] == '-') {
|
||||
has_sign = true;
|
||||
}
|
||||
if (isdigit(src[index + 1 + static_cast<size_t>(has_sign)])) {
|
||||
// exponent marker, see scanf for more details.
|
||||
if (tolower(src[index]) == constants<CharType>::DECIMAL_EXPONENT_MARKER) {
|
||||
int sign = get_sign(src + index + 1);
|
||||
if (isdigit(src[index + 1 + static_cast<size_t>(sign != 0)])) {
|
||||
++index;
|
||||
auto result = strtointeger<int32_t>(src + index, 10);
|
||||
if (result.has_error())
|
||||
@@ -986,22 +988,16 @@ decimal_string_to_float(const char *__restrict src, const char DECIMAL_POINT,
|
||||
return output;
|
||||
}
|
||||
|
||||
// Takes the start of a string representing a hexadecimal float, as well as the
|
||||
// local decimal point. It returns if it suceeded in parsing any digits, and if
|
||||
// the return value is true then the outputs are pointer to the end of the
|
||||
// number, and the mantissa and exponent for the closest float T representation.
|
||||
// If the return value is false, then it is assumed that there is no number
|
||||
// here.
|
||||
template <class T>
|
||||
LIBC_INLINE StrToNumResult<ExpandedFloat<T>>
|
||||
hexadecimal_string_to_float(const char *__restrict src,
|
||||
const char DECIMAL_POINT, RoundDirection round) {
|
||||
// Attempts parsing a hexadecimal floating point number at the start of the
|
||||
// string.
|
||||
template <typename T, typename CharType>
|
||||
LIBC_INLINE static StrToNumResult<ExpandedFloat<T>>
|
||||
hexadecimal_string_to_float(const CharType *__restrict src,
|
||||
RoundDirection round) {
|
||||
using FPBits = typename fputil::FPBits<T>;
|
||||
using StorageType = typename FPBits::StorageType;
|
||||
|
||||
constexpr uint32_t BASE = 16;
|
||||
constexpr char EXPONENT_MARKER = 'p';
|
||||
|
||||
bool truncated = false;
|
||||
bool seen_digit = false;
|
||||
bool after_decimal = false;
|
||||
@@ -1039,7 +1035,7 @@ hexadecimal_string_to_float(const char *__restrict src,
|
||||
++index;
|
||||
continue;
|
||||
}
|
||||
if (src[index] == DECIMAL_POINT) {
|
||||
if (src[index] == constants<CharType>::DECIMAL_POINT) {
|
||||
if (after_decimal) {
|
||||
break; // this means that src[index] points to a second decimal point,
|
||||
// ending the number.
|
||||
@@ -1058,12 +1054,9 @@ hexadecimal_string_to_float(const char *__restrict src,
|
||||
// Convert the exponent from having a base of 16 to having a base of 2.
|
||||
exponent *= 4;
|
||||
|
||||
if (tolower(src[index]) == EXPONENT_MARKER) {
|
||||
bool has_sign = false;
|
||||
if (src[index + 1] == '+' || src[index + 1] == '-') {
|
||||
has_sign = true;
|
||||
}
|
||||
if (isdigit(src[index + 1 + static_cast<size_t>(has_sign)])) {
|
||||
if (tolower(src[index]) == constants<CharType>::HEX_EXPONENT_MARKER) {
|
||||
int sign = get_sign(src + index + 1);
|
||||
if (isdigit(src[index + 1 + static_cast<size_t>(sign != 0)])) {
|
||||
++index;
|
||||
auto result = strtointeger<int32_t>(src + index, 10);
|
||||
if (result.has_error())
|
||||
@@ -1099,21 +1092,21 @@ hexadecimal_string_to_float(const char *__restrict src,
|
||||
return output;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
template <typename T, typename CharType>
|
||||
LIBC_INLINE typename fputil::FPBits<T>::StorageType
|
||||
nan_mantissa_from_ncharseq(const cpp::string_view ncharseq) {
|
||||
nan_mantissa_from_ncharseq(const CharType *str, size_t len) {
|
||||
using FPBits = typename fputil::FPBits<T>;
|
||||
using StorageType = typename FPBits::StorageType;
|
||||
|
||||
StorageType nan_mantissa = 0;
|
||||
|
||||
if (ncharseq.data() != nullptr && isdigit(ncharseq[0])) {
|
||||
if (len > 0 && isdigit(str[0])) {
|
||||
StrToNumResult<StorageType> strtoint_result =
|
||||
strtointeger<StorageType>(ncharseq.data(), 0);
|
||||
strtointeger<StorageType>(str, 0, len);
|
||||
if (!strtoint_result.has_error())
|
||||
nan_mantissa = strtoint_result.value;
|
||||
|
||||
if (strtoint_result.parsed_len != static_cast<ptrdiff_t>(ncharseq.size()))
|
||||
if (strtoint_result.parsed_len != static_cast<ptrdiff_t>(len))
|
||||
nan_mantissa = 0;
|
||||
}
|
||||
|
||||
@@ -1124,59 +1117,44 @@ nan_mantissa_from_ncharseq(const cpp::string_view ncharseq) {
|
||||
// is used as the backend for all of the string to float functions.
|
||||
// TODO: Add src_len member to match strtointeger.
|
||||
// TODO: Next, move from char* and length to string_view
|
||||
template <class T>
|
||||
LIBC_INLINE StrToNumResult<T> strtofloatingpoint(const char *__restrict src) {
|
||||
template <typename T, typename CharType>
|
||||
LIBC_INLINE StrToNumResult<T>
|
||||
strtofloatingpoint(const CharType *__restrict src) {
|
||||
using FPBits = typename fputil::FPBits<T>;
|
||||
using StorageType = typename FPBits::StorageType;
|
||||
|
||||
FPBits result = FPBits();
|
||||
bool seen_digit = false;
|
||||
char sign = '+';
|
||||
|
||||
int error = 0;
|
||||
|
||||
size_t index = first_non_whitespace(src);
|
||||
int sign = get_sign(src + index);
|
||||
bool is_positive = (sign >= 0);
|
||||
index += (sign != 0);
|
||||
|
||||
if (src[index] == '+' || src[index] == '-') {
|
||||
sign = src[index];
|
||||
++index;
|
||||
}
|
||||
|
||||
if (sign == '-') {
|
||||
if (sign < 0) {
|
||||
result.set_sign(Sign::NEG);
|
||||
}
|
||||
|
||||
static constexpr char DECIMAL_POINT = '.';
|
||||
static const char *inf_string = "infinity";
|
||||
static const char *nan_string = "nan";
|
||||
|
||||
if (isdigit(src[index]) || src[index] == DECIMAL_POINT) { // regular number
|
||||
if (isdigit(src[index]) ||
|
||||
src[index] == constants<CharType>::DECIMAL_POINT) { // regular number
|
||||
int base = 10;
|
||||
if (is_float_hex_start(src + index, DECIMAL_POINT)) {
|
||||
if (is_float_hex_start(src + index)) {
|
||||
base = 16;
|
||||
index += 2;
|
||||
seen_digit = true;
|
||||
}
|
||||
|
||||
RoundDirection round_direction = RoundDirection::Nearest;
|
||||
|
||||
switch (fputil::quick_get_round()) {
|
||||
case FE_TONEAREST:
|
||||
round_direction = RoundDirection::Nearest;
|
||||
break;
|
||||
case FE_UPWARD:
|
||||
if (sign == '+') {
|
||||
round_direction = RoundDirection::Up;
|
||||
} else {
|
||||
round_direction = RoundDirection::Down;
|
||||
}
|
||||
round_direction = is_positive ? RoundDirection::Up : RoundDirection::Down;
|
||||
break;
|
||||
case FE_DOWNWARD:
|
||||
if (sign == '+') {
|
||||
round_direction = RoundDirection::Down;
|
||||
} else {
|
||||
round_direction = RoundDirection::Up;
|
||||
}
|
||||
round_direction = is_positive ? RoundDirection::Down : RoundDirection::Up;
|
||||
break;
|
||||
case FE_TOWARDZERO:
|
||||
round_direction = RoundDirection::Down;
|
||||
@@ -1185,58 +1163,53 @@ LIBC_INLINE StrToNumResult<T> strtofloatingpoint(const char *__restrict src) {
|
||||
|
||||
StrToNumResult<ExpandedFloat<T>> parse_result({0, 0});
|
||||
if (base == 16) {
|
||||
parse_result = hexadecimal_string_to_float<T>(src + index, DECIMAL_POINT,
|
||||
round_direction);
|
||||
parse_result =
|
||||
hexadecimal_string_to_float<T>(src + index, round_direction);
|
||||
} else { // base is 10
|
||||
parse_result = decimal_string_to_float<T>(src + index, DECIMAL_POINT,
|
||||
round_direction);
|
||||
parse_result = decimal_string_to_float<T>(src + index, round_direction);
|
||||
}
|
||||
seen_digit = parse_result.parsed_len != 0;
|
||||
result.set_mantissa(parse_result.value.mantissa);
|
||||
result.set_biased_exponent(parse_result.value.exponent);
|
||||
index += parse_result.parsed_len;
|
||||
error = parse_result.error;
|
||||
} else if (tolower(src[index]) == 'n') { // NaN
|
||||
if (tolower(src[index + 1]) == nan_string[1] &&
|
||||
tolower(src[index + 2]) == nan_string[2]) {
|
||||
seen_digit = true;
|
||||
index += 3;
|
||||
StorageType nan_mantissa = 0;
|
||||
// this handles the case of `NaN(n-character-sequence)`, where the
|
||||
// n-character-sequence is made of 0 or more letters, numbers, or
|
||||
// underscore characters in any order.
|
||||
if (src[index] == '(') {
|
||||
size_t left_paren = index;
|
||||
} else if (tolower_starts_with(src + index, 3,
|
||||
constants<CharType>::NAN_STRING)) {
|
||||
// NAN
|
||||
seen_digit = true;
|
||||
index += 3;
|
||||
StorageType nan_mantissa = 0;
|
||||
// this handles the case of `NaN(n-character-sequence)`, where the
|
||||
// n-character-sequence is made of 0 or more letters, numbers, or
|
||||
// underscore characters in any order.
|
||||
if (is_char_or_wchar(src[index], '(', L'(')) {
|
||||
size_t left_paren = index;
|
||||
++index;
|
||||
while (isalnum(src[index]) || is_char_or_wchar(src[index], '_', L'_'))
|
||||
++index;
|
||||
while (isalnum(src[index]) || src[index] == '_')
|
||||
++index;
|
||||
if (src[index] == ')') {
|
||||
++index;
|
||||
nan_mantissa = nan_mantissa_from_ncharseq<T>(
|
||||
cpp::string_view(src + (left_paren + 1), index - left_paren - 2));
|
||||
} else {
|
||||
index = left_paren;
|
||||
}
|
||||
}
|
||||
result = FPBits(result.quiet_nan(result.sign(), nan_mantissa));
|
||||
}
|
||||
} else if (tolower(src[index]) == 'i') { // INF
|
||||
if (tolower(src[index + 1]) == inf_string[1] &&
|
||||
tolower(src[index + 2]) == inf_string[2]) {
|
||||
seen_digit = true;
|
||||
result = FPBits(result.inf(result.sign()));
|
||||
if (tolower(src[index + 3]) == inf_string[3] &&
|
||||
tolower(src[index + 4]) == inf_string[4] &&
|
||||
tolower(src[index + 5]) == inf_string[5] &&
|
||||
tolower(src[index + 6]) == inf_string[6] &&
|
||||
tolower(src[index + 7]) == inf_string[7]) {
|
||||
// if the string is "INFINITY" then consume 8 characters.
|
||||
index += 8;
|
||||
if (is_char_or_wchar(src[index], ')', L')')) {
|
||||
++index;
|
||||
nan_mantissa = nan_mantissa_from_ncharseq<T>(src + (left_paren + 1),
|
||||
index - left_paren - 2);
|
||||
} else {
|
||||
index += 3;
|
||||
index = left_paren;
|
||||
}
|
||||
}
|
||||
result = FPBits(result.quiet_nan(result.sign(), nan_mantissa));
|
||||
} else if (tolower_starts_with(src + index, 8,
|
||||
constants<CharType>::INF_STRING)) {
|
||||
// INFINITY
|
||||
seen_digit = true;
|
||||
result = FPBits(result.inf(result.sign()));
|
||||
index += 8;
|
||||
} else if (tolower_starts_with(src + index, 3,
|
||||
constants<CharType>::INF_STRING)) {
|
||||
// INF
|
||||
seen_digit = true;
|
||||
result = FPBits(result.inf(result.sign()));
|
||||
index += 3;
|
||||
}
|
||||
|
||||
if (!seen_digit) { // If there is nothing to actually parse, then return 0.
|
||||
return {T(0), 0, error};
|
||||
}
|
||||
@@ -1263,7 +1236,7 @@ template <class T> LIBC_INLINE StrToNumResult<T> strtonan(const char *arg) {
|
||||
++index;
|
||||
|
||||
if (arg[index] == '\0')
|
||||
nan_mantissa = nan_mantissa_from_ncharseq<T>(cpp::string_view(arg, index));
|
||||
nan_mantissa = nan_mantissa_from_ncharseq<T>(arg, index);
|
||||
|
||||
result = FPBits::quiet_nan(Sign::POS, nan_mantissa);
|
||||
return {result.get_val(), 0, error};
|
||||
|
||||
+39
-27
@@ -25,36 +25,51 @@
|
||||
#include "src/__support/macros/config.h"
|
||||
#include "src/__support/str_to_num_result.h"
|
||||
#include "src/__support/uint128.h"
|
||||
#include "src/__support/wctype_utils.h"
|
||||
|
||||
namespace LIBC_NAMESPACE_DECL {
|
||||
namespace internal {
|
||||
|
||||
// Returns the idx to the first character in src that is not a whitespace
|
||||
// character (as determined by isspace())
|
||||
template <typename CharType>
|
||||
LIBC_INLINE size_t
|
||||
first_non_whitespace(const char *__restrict src,
|
||||
first_non_whitespace(const CharType *__restrict src,
|
||||
size_t src_len = cpp::numeric_limits<size_t>::max()) {
|
||||
size_t src_cur = 0;
|
||||
while (src_cur < src_len && internal::isspace(src[src_cur])) {
|
||||
++src_cur;
|
||||
}
|
||||
for (; src_cur < src_len && internal::isspace(src[src_cur]); ++src_cur)
|
||||
;
|
||||
return src_cur;
|
||||
}
|
||||
|
||||
// Returns +1, -1, or 0 if 'src' starts with (respectively)
|
||||
// plus sign, minus sign, or neither.
|
||||
template <typename CharType>
|
||||
LIBC_INLINE static int get_sign(const CharType *__restrict src) {
|
||||
if (is_char_or_wchar(src[0], '+', L'+'))
|
||||
return 1;
|
||||
if (is_char_or_wchar(src[0], '-', L'-'))
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// checks if the next 3 characters of the string pointer are the start of a
|
||||
// hexadecimal number. Does not advance the string pointer.
|
||||
LIBC_INLINE bool
|
||||
is_hex_start(const char *__restrict src,
|
||||
size_t src_len = cpp::numeric_limits<size_t>::max()) {
|
||||
template <typename CharType>
|
||||
LIBC_INLINE static bool is_hex_start(const CharType *__restrict src,
|
||||
size_t src_len) {
|
||||
if (src_len < 3)
|
||||
return false;
|
||||
return *src == '0' && tolower(*(src + 1)) == 'x' && isalnum(*(src + 2)) &&
|
||||
b36_char_to_int(*(src + 2)) < 16;
|
||||
return is_char_or_wchar(src[0], '0', L'0') &&
|
||||
is_char_or_wchar(tolower(src[1]), 'x', L'x') && isalnum(src[2]) &&
|
||||
b36_char_to_int(src[2]) < 16;
|
||||
}
|
||||
|
||||
// Takes the address of the string pointer and parses the base from the start of
|
||||
// it.
|
||||
LIBC_INLINE int infer_base(const char *__restrict src, size_t src_len) {
|
||||
template <typename CharType>
|
||||
LIBC_INLINE static int infer_base(const CharType *__restrict src,
|
||||
size_t src_len) {
|
||||
// A hexadecimal number is defined as "the prefix 0x or 0X followed by a
|
||||
// sequence of the decimal digits and the letters a (or A) through f (or F)
|
||||
// with values 10 through 15 respectively." (C standard 6.4.4.1)
|
||||
@@ -63,8 +78,9 @@ LIBC_INLINE int infer_base(const char *__restrict src, size_t src_len) {
|
||||
// An octal number is defined as "the prefix 0 optionally followed by a
|
||||
// sequence of the digits 0 through 7 only" (C standard 6.4.4.1) and so any
|
||||
// number that starts with 0, including just 0, is an octal number.
|
||||
if (src_len > 0 && src[0] == '0')
|
||||
if (src_len > 0 && is_char_or_wchar(src[0], '0', L'0')) {
|
||||
return 8;
|
||||
}
|
||||
// A decimal number is defined as beginning "with a nonzero digit and
|
||||
// consist[ing] of a sequence of decimal digits." (C standard 6.4.4.1)
|
||||
return 10;
|
||||
@@ -77,32 +93,27 @@ LIBC_INLINE int infer_base(const char *__restrict src, size_t src_len) {
|
||||
// -----------------------------------------------------------------------------
|
||||
// Takes a pointer to a string and the base to convert to. This function is used
|
||||
// as the backend for all of the string to int functions.
|
||||
template <class T>
|
||||
template <typename T, typename CharType>
|
||||
LIBC_INLINE StrToNumResult<T>
|
||||
strtointeger(const char *__restrict src, int base,
|
||||
strtointeger(const CharType *__restrict src, int base,
|
||||
const size_t src_len = cpp::numeric_limits<size_t>::max()) {
|
||||
using ResultType = make_integral_or_big_int_unsigned_t<T>;
|
||||
|
||||
ResultType result = 0;
|
||||
|
||||
bool is_number = false;
|
||||
size_t src_cur = 0;
|
||||
int error_val = 0;
|
||||
|
||||
if (src_len == 0)
|
||||
return {0, 0, 0};
|
||||
|
||||
if (base < 0 || base == 1 || base > 36)
|
||||
return {0, 0, EINVAL};
|
||||
|
||||
src_cur = first_non_whitespace(src, src_len);
|
||||
|
||||
char result_sign = '+';
|
||||
if (src[src_cur] == '+' || src[src_cur] == '-') {
|
||||
result_sign = src[src_cur];
|
||||
++src_cur;
|
||||
size_t src_cur = first_non_whitespace(src, src_len);
|
||||
if (src_cur == src_len) {
|
||||
return {0, 0, 0};
|
||||
}
|
||||
|
||||
int sign = get_sign(src + src_cur);
|
||||
bool is_positive = (sign >= 0);
|
||||
src_cur += (sign != 0);
|
||||
|
||||
if (base == 0)
|
||||
base = infer_base(src + src_cur, src_len - src_cur);
|
||||
|
||||
@@ -110,8 +121,6 @@ strtointeger(const char *__restrict src, int base,
|
||||
src_cur = src_cur + 2;
|
||||
|
||||
constexpr bool IS_UNSIGNED = cpp::is_unsigned_v<T>;
|
||||
const bool is_positive = (result_sign == '+');
|
||||
|
||||
ResultType constexpr NEGATIVE_MAX =
|
||||
!IS_UNSIGNED ? static_cast<ResultType>(cpp::numeric_limits<T>::max()) + 1
|
||||
: cpp::numeric_limits<T>::max();
|
||||
@@ -120,6 +129,9 @@ strtointeger(const char *__restrict src, int base,
|
||||
ResultType const abs_max_div_by_base =
|
||||
abs_max / static_cast<ResultType>(base);
|
||||
|
||||
bool is_number = false;
|
||||
int error_val = 0;
|
||||
ResultType result = 0;
|
||||
while (src_cur < src_len && isalnum(src[src_cur])) {
|
||||
int cur_digit = b36_char_to_int(src[src_cur]);
|
||||
if (cur_digit >= base)
|
||||
|
||||
+588
@@ -0,0 +1,588 @@
|
||||
//===-- Collection of utils for implementing wide char functions --*-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 LLVM_LIBC_SRC___SUPPORT_WCTYPE_UTILS_H
|
||||
#define LLVM_LIBC_SRC___SUPPORT_WCTYPE_UTILS_H
|
||||
|
||||
#include "hdr/types/wchar_t.h"
|
||||
#include "src/__support/macros/attributes.h" // LIBC_INLINE
|
||||
#include "src/__support/macros/config.h"
|
||||
|
||||
namespace LIBC_NAMESPACE_DECL {
|
||||
namespace internal {
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// ****************** WARNING ******************
|
||||
// ****************** DO NOT TRY TO OPTIMIZE THESE FUNCTIONS! ******************
|
||||
// -----------------------------------------------------------------------------
|
||||
// This switch/case form is easier for the compiler to understand, and is
|
||||
// optimized into a form that is almost always the same as or better than
|
||||
// versions written by hand (see https://godbolt.org/z/qvrebqvvr). Also this
|
||||
// form makes these functions encoding independent. If you want to rewrite these
|
||||
// functions, make sure you have benchmarks to show your new solution is faster,
|
||||
// as well as a way to support non-ASCII character encodings.
|
||||
|
||||
// Similarly, do not change these fumarks to show your new solution is faster,
|
||||
// as well as a way to support non-Anctions to use case ranges. e.g.
|
||||
// bool islower(wchar_t ch) {
|
||||
// switch(ch) {
|
||||
// case L'a'...L'z':
|
||||
// return true;
|
||||
// }
|
||||
// }
|
||||
// This assumes the character ranges are contiguous, which they aren't in
|
||||
// EBCDIC. Technically we could use some smaller ranges, but that's even harder
|
||||
// to read.
|
||||
|
||||
LIBC_INLINE static constexpr bool islower(wchar_t wch) {
|
||||
switch (wch) {
|
||||
case L'a':
|
||||
case L'b':
|
||||
case L'c':
|
||||
case L'd':
|
||||
case L'e':
|
||||
case L'f':
|
||||
case L'g':
|
||||
case L'h':
|
||||
case L'i':
|
||||
case L'j':
|
||||
case L'k':
|
||||
case L'l':
|
||||
case L'm':
|
||||
case L'n':
|
||||
case L'o':
|
||||
case L'p':
|
||||
case L'q':
|
||||
case L'r':
|
||||
case L's':
|
||||
case L't':
|
||||
case L'u':
|
||||
case L'v':
|
||||
case L'w':
|
||||
case L'x':
|
||||
case L'y':
|
||||
case L'z':
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
LIBC_INLINE static constexpr bool isupper(wchar_t wch) {
|
||||
switch (wch) {
|
||||
case L'A':
|
||||
case L'B':
|
||||
case L'C':
|
||||
case L'D':
|
||||
case L'E':
|
||||
case L'F':
|
||||
case L'G':
|
||||
case L'H':
|
||||
case L'I':
|
||||
case L'J':
|
||||
case L'K':
|
||||
case L'L':
|
||||
case L'M':
|
||||
case L'N':
|
||||
case L'O':
|
||||
case L'P':
|
||||
case L'Q':
|
||||
case L'R':
|
||||
case L'S':
|
||||
case L'T':
|
||||
case L'U':
|
||||
case L'V':
|
||||
case L'W':
|
||||
case L'X':
|
||||
case L'Y':
|
||||
case L'Z':
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
LIBC_INLINE static constexpr bool isdigit(wchar_t wch) {
|
||||
switch (wch) {
|
||||
case L'0':
|
||||
case L'1':
|
||||
case L'2':
|
||||
case L'3':
|
||||
case L'4':
|
||||
case L'5':
|
||||
case L'6':
|
||||
case L'7':
|
||||
case L'8':
|
||||
case L'9':
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
LIBC_INLINE static constexpr wchar_t tolower(wchar_t wch) {
|
||||
switch (wch) {
|
||||
case L'A':
|
||||
return L'a';
|
||||
case L'B':
|
||||
return L'b';
|
||||
case L'C':
|
||||
return L'c';
|
||||
case L'D':
|
||||
return L'd';
|
||||
case L'E':
|
||||
return L'e';
|
||||
case L'F':
|
||||
return L'f';
|
||||
case L'G':
|
||||
return L'g';
|
||||
case L'H':
|
||||
return L'h';
|
||||
case L'I':
|
||||
return L'i';
|
||||
case L'J':
|
||||
return L'j';
|
||||
case L'K':
|
||||
return L'k';
|
||||
case L'L':
|
||||
return L'l';
|
||||
case L'M':
|
||||
return L'm';
|
||||
case L'N':
|
||||
return L'n';
|
||||
case L'O':
|
||||
return L'o';
|
||||
case L'P':
|
||||
return L'p';
|
||||
case L'Q':
|
||||
return L'q';
|
||||
case L'R':
|
||||
return L'r';
|
||||
case L'S':
|
||||
return L's';
|
||||
case L'T':
|
||||
return L't';
|
||||
case L'U':
|
||||
return L'u';
|
||||
case L'V':
|
||||
return L'v';
|
||||
case L'W':
|
||||
return L'w';
|
||||
case L'X':
|
||||
return L'x';
|
||||
case L'Y':
|
||||
return L'y';
|
||||
case L'Z':
|
||||
return L'z';
|
||||
default:
|
||||
return wch;
|
||||
}
|
||||
}
|
||||
|
||||
LIBC_INLINE static constexpr wchar_t toupper(wchar_t wch) {
|
||||
switch (wch) {
|
||||
case L'a':
|
||||
return L'A';
|
||||
case L'b':
|
||||
return L'B';
|
||||
case L'c':
|
||||
return L'C';
|
||||
case L'd':
|
||||
return L'D';
|
||||
case L'e':
|
||||
return L'E';
|
||||
case L'f':
|
||||
return L'F';
|
||||
case L'g':
|
||||
return L'G';
|
||||
case L'h':
|
||||
return L'H';
|
||||
case L'i':
|
||||
return L'I';
|
||||
case L'j':
|
||||
return L'J';
|
||||
case L'k':
|
||||
return L'K';
|
||||
case L'l':
|
||||
return L'L';
|
||||
case L'm':
|
||||
return L'M';
|
||||
case L'n':
|
||||
return L'N';
|
||||
case L'o':
|
||||
return L'O';
|
||||
case L'p':
|
||||
return L'P';
|
||||
case L'q':
|
||||
return L'Q';
|
||||
case L'r':
|
||||
return L'R';
|
||||
case L's':
|
||||
return L'S';
|
||||
case L't':
|
||||
return L'T';
|
||||
case L'u':
|
||||
return L'U';
|
||||
case L'v':
|
||||
return L'V';
|
||||
case L'w':
|
||||
return L'W';
|
||||
case L'x':
|
||||
return L'X';
|
||||
case L'y':
|
||||
return L'Y';
|
||||
case L'z':
|
||||
return L'Z';
|
||||
default:
|
||||
return wch;
|
||||
}
|
||||
}
|
||||
|
||||
LIBC_INLINE static constexpr bool isalpha(wchar_t wch) {
|
||||
switch (wch) {
|
||||
case L'a':
|
||||
case L'b':
|
||||
case L'c':
|
||||
case L'd':
|
||||
case L'e':
|
||||
case L'f':
|
||||
case L'g':
|
||||
case L'h':
|
||||
case L'i':
|
||||
case L'j':
|
||||
case L'k':
|
||||
case L'l':
|
||||
case L'm':
|
||||
case L'n':
|
||||
case L'o':
|
||||
case L'p':
|
||||
case L'q':
|
||||
case L'r':
|
||||
case L's':
|
||||
case L't':
|
||||
case L'u':
|
||||
case L'v':
|
||||
case L'w':
|
||||
case L'x':
|
||||
case L'y':
|
||||
case L'z':
|
||||
case L'A':
|
||||
case L'B':
|
||||
case L'C':
|
||||
case L'D':
|
||||
case L'E':
|
||||
case L'F':
|
||||
case L'G':
|
||||
case L'H':
|
||||
case L'I':
|
||||
case L'J':
|
||||
case L'K':
|
||||
case L'L':
|
||||
case L'M':
|
||||
case L'N':
|
||||
case L'O':
|
||||
case L'P':
|
||||
case L'Q':
|
||||
case L'R':
|
||||
case L'S':
|
||||
case L'T':
|
||||
case L'U':
|
||||
case L'V':
|
||||
case L'W':
|
||||
case L'X':
|
||||
case L'Y':
|
||||
case L'Z':
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
LIBC_INLINE static constexpr bool isalnum(wchar_t wch) {
|
||||
switch (wch) {
|
||||
case L'a':
|
||||
case L'b':
|
||||
case L'c':
|
||||
case L'd':
|
||||
case L'e':
|
||||
case L'f':
|
||||
case L'g':
|
||||
case L'h':
|
||||
case L'i':
|
||||
case L'j':
|
||||
case L'k':
|
||||
case L'l':
|
||||
case L'm':
|
||||
case L'n':
|
||||
case L'o':
|
||||
case L'p':
|
||||
case L'q':
|
||||
case L'r':
|
||||
case L's':
|
||||
case L't':
|
||||
case L'u':
|
||||
case L'v':
|
||||
case L'w':
|
||||
case L'x':
|
||||
case L'y':
|
||||
case L'z':
|
||||
case L'A':
|
||||
case L'B':
|
||||
case L'C':
|
||||
case L'D':
|
||||
case L'E':
|
||||
case L'F':
|
||||
case L'G':
|
||||
case L'H':
|
||||
case L'I':
|
||||
case L'J':
|
||||
case L'K':
|
||||
case L'L':
|
||||
case L'M':
|
||||
case L'N':
|
||||
case L'O':
|
||||
case L'P':
|
||||
case L'Q':
|
||||
case L'R':
|
||||
case L'S':
|
||||
case L'T':
|
||||
case L'U':
|
||||
case L'V':
|
||||
case L'W':
|
||||
case L'X':
|
||||
case L'Y':
|
||||
case L'Z':
|
||||
case L'0':
|
||||
case L'1':
|
||||
case L'2':
|
||||
case L'3':
|
||||
case L'4':
|
||||
case L'5':
|
||||
case L'6':
|
||||
case L'7':
|
||||
case L'8':
|
||||
case L'9':
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
LIBC_INLINE static constexpr int b36_char_to_int(wchar_t wch) {
|
||||
switch (wch) {
|
||||
case L'0':
|
||||
return 0;
|
||||
case L'1':
|
||||
return 1;
|
||||
case L'2':
|
||||
return 2;
|
||||
case L'3':
|
||||
return 3;
|
||||
case L'4':
|
||||
return 4;
|
||||
case L'5':
|
||||
return 5;
|
||||
case L'6':
|
||||
return 6;
|
||||
case L'7':
|
||||
return 7;
|
||||
case L'8':
|
||||
return 8;
|
||||
case L'9':
|
||||
return 9;
|
||||
case L'a':
|
||||
case L'A':
|
||||
return 10;
|
||||
case L'b':
|
||||
case L'B':
|
||||
return 11;
|
||||
case L'c':
|
||||
case L'C':
|
||||
return 12;
|
||||
case L'd':
|
||||
case L'D':
|
||||
return 13;
|
||||
case L'e':
|
||||
case L'E':
|
||||
return 14;
|
||||
case L'f':
|
||||
case L'F':
|
||||
return 15;
|
||||
case L'g':
|
||||
case L'G':
|
||||
return 16;
|
||||
case L'h':
|
||||
case L'H':
|
||||
return 17;
|
||||
case L'i':
|
||||
case L'I':
|
||||
return 18;
|
||||
case L'j':
|
||||
case L'J':
|
||||
return 19;
|
||||
case L'k':
|
||||
case L'K':
|
||||
return 20;
|
||||
case L'l':
|
||||
case L'L':
|
||||
return 21;
|
||||
case L'm':
|
||||
case L'M':
|
||||
return 22;
|
||||
case L'n':
|
||||
case L'N':
|
||||
return 23;
|
||||
case L'o':
|
||||
case L'O':
|
||||
return 24;
|
||||
case L'p':
|
||||
case L'P':
|
||||
return 25;
|
||||
case L'q':
|
||||
case L'Q':
|
||||
return 26;
|
||||
case L'r':
|
||||
case L'R':
|
||||
return 27;
|
||||
case L's':
|
||||
case L'S':
|
||||
return 28;
|
||||
case L't':
|
||||
case L'T':
|
||||
return 29;
|
||||
case L'u':
|
||||
case L'U':
|
||||
return 30;
|
||||
case L'v':
|
||||
case L'V':
|
||||
return 31;
|
||||
case L'w':
|
||||
case L'W':
|
||||
return 32;
|
||||
case L'x':
|
||||
case L'X':
|
||||
return 33;
|
||||
case L'y':
|
||||
case L'Y':
|
||||
return 34;
|
||||
case L'z':
|
||||
case L'Z':
|
||||
return 35;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
LIBC_INLINE static constexpr wchar_t int_to_b36_wchar(int num) {
|
||||
// Can't actually use LIBC_ASSERT here because it depends on integer_to_string
|
||||
// which depends on this.
|
||||
|
||||
// LIBC_ASSERT(num < 36);
|
||||
switch (num) {
|
||||
case 0:
|
||||
return L'0';
|
||||
case 1:
|
||||
return L'1';
|
||||
case 2:
|
||||
return L'2';
|
||||
case 3:
|
||||
return L'3';
|
||||
case 4:
|
||||
return L'4';
|
||||
case 5:
|
||||
return L'5';
|
||||
case 6:
|
||||
return L'6';
|
||||
case 7:
|
||||
return L'7';
|
||||
case 8:
|
||||
return L'8';
|
||||
case 9:
|
||||
return L'9';
|
||||
case 10:
|
||||
return L'a';
|
||||
case 11:
|
||||
return L'b';
|
||||
case 12:
|
||||
return L'c';
|
||||
case 13:
|
||||
return L'd';
|
||||
case 14:
|
||||
return L'e';
|
||||
case 15:
|
||||
return L'f';
|
||||
case 16:
|
||||
return L'g';
|
||||
case 17:
|
||||
return L'h';
|
||||
case 18:
|
||||
return L'i';
|
||||
case 19:
|
||||
return L'j';
|
||||
case 20:
|
||||
return L'k';
|
||||
case 21:
|
||||
return L'l';
|
||||
case 22:
|
||||
return L'm';
|
||||
case 23:
|
||||
return L'n';
|
||||
case 24:
|
||||
return L'o';
|
||||
case 25:
|
||||
return L'p';
|
||||
case 26:
|
||||
return L'q';
|
||||
case 27:
|
||||
return L'r';
|
||||
case 28:
|
||||
return L's';
|
||||
case 29:
|
||||
return L't';
|
||||
case 30:
|
||||
return L'u';
|
||||
case 31:
|
||||
return L'v';
|
||||
case 32:
|
||||
return L'w';
|
||||
case 33:
|
||||
return L'x';
|
||||
case 34:
|
||||
return L'y';
|
||||
case 35:
|
||||
return L'z';
|
||||
default:
|
||||
return L'!';
|
||||
}
|
||||
}
|
||||
|
||||
LIBC_INLINE static constexpr bool isspace(wchar_t wch) {
|
||||
switch (wch) {
|
||||
case L' ':
|
||||
case L'\t':
|
||||
case L'\n':
|
||||
case L'\v':
|
||||
case L'\f':
|
||||
case L'\r':
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// An overload which provides a way to compare input with specific character
|
||||
// values, when input can be of a regular or a wide character type.
|
||||
LIBC_INLINE static constexpr bool
|
||||
is_char_or_wchar(wchar_t ch, [[maybe_unused]] char, wchar_t wc_value) {
|
||||
return (ch == wc_value);
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace LIBC_NAMESPACE_DECL
|
||||
|
||||
#endif // LLVM_LIBC_SRC___SUPPORT_WCTYPE_UTILS_H
|
||||
Reference in New Issue
Block a user