mirror of
https://codeberg.org/ziglang/zig.git
synced 2026-10-28 10:45:48 +08:00
llvm-libc: update to LLVM 23
This commit is contained in:
45 files changed
+1214
-466
No files matched your search
Vendored
+1
-1
@@ -25,6 +25,6 @@
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#endif // LLVM_LIBC_FULL_BUILD
|
||||
#endif // LIBC_FULL_BUILD
|
||||
|
||||
#endif // LLVM_LIBC_HDR_ERRNO_MACROS_H
|
||||
Vendored
+1
-1
@@ -56,6 +56,6 @@
|
||||
#define FE_UPWARD 0x800
|
||||
#endif // FE_UPWARD
|
||||
|
||||
#endif // LLVM_LIBC_FULL_BUILD
|
||||
#endif // LIBC_FULL_BUILD
|
||||
|
||||
#endif // LLVM_LIBC_HDR_FENV_MACROS_H
|
||||
Vendored
+1
-1
@@ -17,6 +17,6 @@
|
||||
|
||||
#include <float.h>
|
||||
|
||||
#endif // LLVM_LIBC_FULL_BUILD
|
||||
#endif // LIBC_FULL_BUILD
|
||||
|
||||
#endif // LLVM_LIBC_HDR_FLOAT_MACROS_H
|
||||
Vendored
+1
-1
@@ -17,6 +17,6 @@
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
#endif // LLVM_LIBC_FULL_BUILD
|
||||
#endif // LIBC_FULL_BUILD
|
||||
|
||||
#endif // LLVM_LIBC_HDR_LIMITS_MACROS_H
|
||||
Vendored
+23
@@ -0,0 +1,23 @@
|
||||
//===-- Proxy for size_t --------------------------------------------------===//
|
||||
//
|
||||
// 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_SIZE_T_H
|
||||
#define LLVM_LIBC_HDR_TYPES_SIZE_T_H
|
||||
|
||||
#ifdef LIBC_FULL_BUILD
|
||||
|
||||
#include "include/llvm-libc-types/size_t.h"
|
||||
|
||||
#else
|
||||
|
||||
#define __need_size_t
|
||||
#include <stddef.h>
|
||||
#undef __need_size_t
|
||||
|
||||
#endif // LIBC_FULL_BUILD
|
||||
|
||||
#endif // LLVM_LIBC_HDR_TYPES_SIZE_T_H
|
||||
Vendored
+1
-1
@@ -18,6 +18,6 @@
|
||||
|
||||
#include "hdr/wchar_overlay.h"
|
||||
|
||||
#endif // LLVM_LIBC_FULL_BUILD
|
||||
#endif // LIBC_FULL_BUILD
|
||||
|
||||
#endif // LLVM_LIBC_HDR_TYPES_WCHAR_T_H
|
||||
Vendored
+23
@@ -0,0 +1,23 @@
|
||||
//===-- Definition of wint_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_WINT_T_H
|
||||
#define LLVM_LIBC_HDR_TYPES_WINT_T_H
|
||||
|
||||
#ifdef LIBC_FULL_BUILD
|
||||
|
||||
#include "include/llvm-libc-types/wint_t.h"
|
||||
|
||||
#else // overlay mode
|
||||
|
||||
#include "hdr/wchar_overlay.h"
|
||||
|
||||
#endif // LIBC_FULL_BUILD
|
||||
|
||||
#endif // LLVM_LIBC_HDR_TYPES_WINT_T_H
|
||||
@@ -27,7 +27,7 @@
|
||||
#define LIBC_TYPES_HAS_CFLOAT128
|
||||
#endif
|
||||
#elif defined(__GNUC__)
|
||||
#if (defined(__STDC_IEC_60559_COMPLEX__) || defined(__SIZEOF_FLOAT128__)) && \
|
||||
#if (defined(__STDC_IEC_60559_COMPLEX__) && defined(__SIZEOF_FLOAT128__)) && \
|
||||
(__GNUC__ >= 13 || (!defined(__cplusplus)))
|
||||
#define LIBC_TYPES_HAS_CFLOAT128
|
||||
#endif
|
||||
|
||||
@@ -9,6 +9,12 @@
|
||||
#ifndef LLVM_LIBC_MACROS_FLOAT_MACROS_H
|
||||
#define LLVM_LIBC_MACROS_FLOAT_MACROS_H
|
||||
|
||||
// __has_builtin is a Clang extension; GCC < 10 doesn't define it, which
|
||||
// turns a bare `#if __has_builtin(...)` into a preprocessor syntax error.
|
||||
#ifndef __has_builtin
|
||||
#define __has_builtin(x) 0
|
||||
#endif
|
||||
|
||||
#ifndef FLT_RADIX
|
||||
#define FLT_RADIX __FLT_RADIX__
|
||||
#endif // FLT_RADIX
|
||||
|
||||
@@ -12,7 +12,8 @@
|
||||
#include "../llvm-libc-types/float128.h"
|
||||
|
||||
#if defined(__FLT16_MANT_DIG__) && \
|
||||
(!defined(__GNUC__) || __GNUC__ >= 13 || defined(__clang__)) && \
|
||||
(!defined(__GNUC__) || __GNUC__ >= 13 || \
|
||||
(defined(__clang__) && __clang_major__ >= 12)) && \
|
||||
!defined(__arm__) && !defined(_M_ARM) && !defined(__riscv) && \
|
||||
!defined(_WIN32)
|
||||
#define LIBC_TYPES_HAS_FLOAT16
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
#ifndef LLVM_LIBC_MACROS_STDFIX_MACROS_H
|
||||
#define LLVM_LIBC_MACROS_STDFIX_MACROS_H
|
||||
|
||||
#ifdef __FRACT_FBIT__
|
||||
#if defined(__FRACT_FBIT__) && defined(__clang__)
|
||||
// _Fract and _Accum types are available
|
||||
#define LIBC_COMPILER_HAS_FIXED_POINT
|
||||
#endif // __FRACT_FBIT__
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
//===-- Definition of size_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_SIZE_T_H
|
||||
#define LLVM_LIBC_TYPES_SIZE_T_H
|
||||
|
||||
typedef __SIZE_TYPE__ size_t;
|
||||
|
||||
#endif // LLVM_LIBC_TYPES_SIZE_T_H
|
||||
+46
-14
@@ -6,7 +6,7 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
// This is inspired by LLVM ADT/bit.h header.
|
||||
// Some functions are missing, we can add them as needed (popcount, byteswap).
|
||||
// Some functions are missing, we can add them as needed.
|
||||
|
||||
#ifndef LLVM_LIBC_SRC___SUPPORT_CPP_BIT_H
|
||||
#define LLVM_LIBC_SRC___SUPPORT_CPP_BIT_H
|
||||
@@ -27,9 +27,14 @@ namespace cpp {
|
||||
#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);
|
||||
LIBC_INLINE constexpr void inline_copy(const char *from, char *to) {
|
||||
#if __has_builtin(__builtin_memcpy_inline) && \
|
||||
defined(LIBC_HAS_BUILTIN_IS_CONSTANT_EVALUATED)
|
||||
if (cpp::is_constant_evaluated())
|
||||
for (unsigned i = 0; i < N; ++i)
|
||||
to[i] = from[i];
|
||||
else
|
||||
__builtin_memcpy_inline(to, from, N);
|
||||
#else
|
||||
for (unsigned i = 0; i < N; ++i)
|
||||
to[i] = from[i];
|
||||
@@ -39,15 +44,14 @@ LIBC_INLINE static void inline_copy(const char *from, char *to) {
|
||||
// This implementation of bit_cast requires trivially-constructible To, to avoid
|
||||
// UB in the implementation.
|
||||
template <typename To, typename From>
|
||||
LIBC_INLINE constexpr cpp::enable_if_t<
|
||||
LIBC_INLINE static 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,
|
||||
To>
|
||||
bit_cast(const From &from) {
|
||||
MSAN_UNPOISON(&from, sizeof(From));
|
||||
#if __has_builtin(__builtin_bit_cast) || defined(LIBC_COMPILER_IS_MSVC)
|
||||
#if LIBC_HAS_BUILTIN_BIT_CAST
|
||||
return __builtin_bit_cast(To, from);
|
||||
#else
|
||||
To to{};
|
||||
@@ -60,14 +64,12 @@ bit_cast(const From &from) {
|
||||
|
||||
// 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>
|
||||
LIBC_INLINE 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);
|
||||
@@ -330,6 +332,36 @@ ADD_SPECIALIZATION(unsigned long long, __builtin_popcountll)
|
||||
#endif // __builtin_popcountg
|
||||
#undef ADD_SPECIALIZATION
|
||||
|
||||
/// Reverses the bytes in the given integer value.
|
||||
///
|
||||
/// All integral types are allowed, matching C++23 std::byteswap semantics.
|
||||
/// Signed types delegate to the unsigned path via static_cast.
|
||||
///
|
||||
/// The recursive decomposition generates optimal 'bswap' or 'rolw'
|
||||
/// instructions on Clang at -O2 without requiring compiler intrinsics.
|
||||
template <typename T>
|
||||
[[nodiscard]] LIBC_INLINE constexpr cpp::enable_if_t<cpp::is_integral_v<T>, T>
|
||||
byteswap(T value) {
|
||||
static_assert(sizeof(T) <= 16, "byteswap: unsupported type size");
|
||||
if constexpr (!cpp::is_unsigned_v<T>) {
|
||||
using U = cpp::make_unsigned_t<T>;
|
||||
return static_cast<T>(byteswap(static_cast<U>(value)));
|
||||
} else if constexpr (sizeof(T) == 1) {
|
||||
return value;
|
||||
} else {
|
||||
constexpr unsigned half_bits = sizeof(T) * 8 / 2;
|
||||
using Half = cpp::conditional_t<
|
||||
sizeof(T) == 2, uint8_t,
|
||||
cpp::conditional_t<
|
||||
sizeof(T) == 4, uint16_t,
|
||||
cpp::conditional_t<sizeof(T) == 8, uint32_t, uint64_t>>>;
|
||||
Half lo = static_cast<Half>(value);
|
||||
Half hi = static_cast<Half>(value >> half_bits);
|
||||
return static_cast<T>((static_cast<T>(byteswap(lo)) << half_bits) |
|
||||
static_cast<T>(byteswap(hi)));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace cpp
|
||||
} // namespace LIBC_NAMESPACE_DECL
|
||||
|
||||
|
||||
+29
@@ -9,6 +9,7 @@
|
||||
#ifndef LLVM_LIBC_SRC___SUPPORT_CPP_ITERATOR_H
|
||||
#define LLVM_LIBC_SRC___SUPPORT_CPP_ITERATOR_H
|
||||
|
||||
#include "hdr/types/size_t.h"
|
||||
#include "src/__support/CPP/type_traits/enable_if.h"
|
||||
#include "src/__support/CPP/type_traits/is_convertible.h"
|
||||
#include "src/__support/CPP/type_traits/is_same.h"
|
||||
@@ -18,9 +19,13 @@
|
||||
namespace LIBC_NAMESPACE_DECL {
|
||||
namespace cpp {
|
||||
|
||||
struct input_iterator_tag {};
|
||||
struct random_access_iterator_tag : input_iterator_tag {};
|
||||
|
||||
template <typename T> struct iterator_traits;
|
||||
template <typename T> struct iterator_traits<T *> {
|
||||
using reference = T &;
|
||||
using iterator_category = random_access_iterator_tag;
|
||||
using value_type = T;
|
||||
};
|
||||
|
||||
@@ -93,6 +98,30 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
namespace cpp_internal {
|
||||
|
||||
template <typename It>
|
||||
LIBC_INLINE constexpr size_t distance(It first, It last,
|
||||
random_access_iterator_tag) {
|
||||
return last - first;
|
||||
}
|
||||
|
||||
template <typename It>
|
||||
LIBC_INLINE constexpr auto distance(It first, It last, input_iterator_tag) {
|
||||
size_t n = 0;
|
||||
for (; first != last; ++first) {
|
||||
++n;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
} // namespace cpp_internal
|
||||
|
||||
template <typename It> LIBC_INLINE constexpr auto distance(It first, It last) {
|
||||
return cpp_internal::distance(
|
||||
first, last, typename iterator_traits<It>::iterator_category{});
|
||||
}
|
||||
|
||||
} // namespace cpp
|
||||
} // namespace LIBC_NAMESPACE_DECL
|
||||
|
||||
|
||||
+26
-62
@@ -1,4 +1,4 @@
|
||||
//===-- A self contained equivalent of std::limits --------------*- C++ -*-===//
|
||||
//===-- A self contained equivalent of <limits> ----------------*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
@@ -13,78 +13,42 @@
|
||||
#include "src/__support/CPP/type_traits/is_integral.h"
|
||||
#include "src/__support/CPP/type_traits/is_signed.h"
|
||||
#include "src/__support/macros/attributes.h" // LIBC_INLINE
|
||||
#include "src/__support/macros/config.h"
|
||||
#include "src/__support/macros/properties/types.h" // LIBC_TYPES_HAS_INT128
|
||||
|
||||
namespace LIBC_NAMESPACE_DECL {
|
||||
namespace cpp {
|
||||
|
||||
namespace internal {
|
||||
|
||||
template <typename T, T min_value, T max_value> struct integer_impl {
|
||||
static_assert(cpp::is_integral_v<T>);
|
||||
LIBC_INLINE static constexpr T max() { return max_value; }
|
||||
LIBC_INLINE static constexpr T min() { return min_value; }
|
||||
template <typename T, bool is_integral> struct numeric_limits_impl {};
|
||||
|
||||
template <typename T> struct numeric_limits_impl<T, true> {
|
||||
LIBC_INLINE_VAR static constexpr bool is_signed = T(-1) < T(0);
|
||||
|
||||
LIBC_INLINE_VAR static constexpr int digits =
|
||||
CHAR_BIT * sizeof(T) - cpp::is_signed_v<T>;
|
||||
(CHAR_BIT * sizeof(T)) - is_signed;
|
||||
|
||||
LIBC_INLINE static constexpr T min() {
|
||||
if constexpr (is_signed) {
|
||||
return T(T(1) << digits);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
LIBC_INLINE static constexpr T max() {
|
||||
if constexpr (is_signed) {
|
||||
return T(T(~0) ^ min());
|
||||
} else {
|
||||
return T(~0);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
template <class T> struct numeric_limits {};
|
||||
|
||||
// TODO: Add numeric_limits specializations as needed for new types.
|
||||
template <>
|
||||
struct numeric_limits<short>
|
||||
: public internal::integer_impl<short, SHRT_MIN, SHRT_MAX> {};
|
||||
|
||||
template <>
|
||||
struct numeric_limits<unsigned short>
|
||||
: public internal::integer_impl<unsigned short, 0, USHRT_MAX> {};
|
||||
|
||||
template <>
|
||||
struct numeric_limits<int>
|
||||
: public internal::integer_impl<int, INT_MIN, INT_MAX> {};
|
||||
|
||||
template <>
|
||||
struct numeric_limits<unsigned int>
|
||||
: public internal::integer_impl<unsigned int, 0, UINT_MAX> {};
|
||||
|
||||
template <>
|
||||
struct numeric_limits<long>
|
||||
: public internal::integer_impl<long, LONG_MIN, LONG_MAX> {};
|
||||
|
||||
template <>
|
||||
struct numeric_limits<unsigned long>
|
||||
: public internal::integer_impl<unsigned long, 0, ULONG_MAX> {};
|
||||
|
||||
template <>
|
||||
struct numeric_limits<long long>
|
||||
: public internal::integer_impl<long long, LLONG_MIN, LLONG_MAX> {};
|
||||
|
||||
template <>
|
||||
struct numeric_limits<unsigned long long>
|
||||
: public internal::integer_impl<unsigned long long, 0, ULLONG_MAX> {};
|
||||
|
||||
template <>
|
||||
struct numeric_limits<char>
|
||||
: public internal::integer_impl<char, CHAR_MIN, CHAR_MAX> {};
|
||||
|
||||
template <>
|
||||
struct numeric_limits<signed char>
|
||||
: public internal::integer_impl<signed char, SCHAR_MIN, SCHAR_MAX> {};
|
||||
|
||||
template <>
|
||||
struct numeric_limits<unsigned char>
|
||||
: public internal::integer_impl<unsigned char, 0, UCHAR_MAX> {};
|
||||
|
||||
#ifdef LIBC_TYPES_HAS_INT128
|
||||
// On platform where UInt128 resolves to __uint128_t, this specialization
|
||||
// provides the limits of UInt128.
|
||||
template <>
|
||||
struct numeric_limits<__uint128_t>
|
||||
: public internal::integer_impl<__uint128_t, 0, ~__uint128_t(0)> {};
|
||||
#endif
|
||||
template <typename T>
|
||||
struct numeric_limits
|
||||
: public internal::numeric_limits_impl<T, is_integral_v<T>> {};
|
||||
|
||||
} // namespace cpp
|
||||
} // namespace LIBC_NAMESPACE_DECL
|
||||
|
||||
+79
-62
@@ -18,46 +18,52 @@
|
||||
namespace LIBC_NAMESPACE_DECL {
|
||||
namespace cpp {
|
||||
|
||||
// This is very simple alternate of the std::string_view class. There is no
|
||||
// bounds check performed in any of the methods. The callers are expected to
|
||||
// do the checks before invoking the methods.
|
||||
template <typename CharT> class basic_string_view;
|
||||
|
||||
using string_view = basic_string_view<char>;
|
||||
using wstring_view = basic_string_view<wchar_t>;
|
||||
|
||||
// This is a very simple alternate of the std::basic_string_view class template.
|
||||
// There is no bounds check performed in any of the methods. The callers are
|
||||
// expected to do the checks before invoking the methods.
|
||||
//
|
||||
// This class will be extended as needed in future.
|
||||
class string_view {
|
||||
template <typename CharT> class basic_string_view {
|
||||
private:
|
||||
const char *Data;
|
||||
const CharT *Data;
|
||||
size_t Len;
|
||||
|
||||
LIBC_INLINE static size_t min(size_t A, size_t B) { return A <= B ? A : B; }
|
||||
LIBC_INLINE static constexpr size_t min(size_t A, size_t B) {
|
||||
return A <= B ? A : B;
|
||||
}
|
||||
|
||||
LIBC_INLINE static int compareMemory(const char *Lhs, const char *Rhs,
|
||||
size_t Length) {
|
||||
LIBC_INLINE static constexpr int compareN(const CharT *Lhs, const CharT *Rhs,
|
||||
size_t Length) {
|
||||
for (size_t i = 0; i < Length; ++i)
|
||||
if (int Diff = (int)Lhs[i] - (int)Rhs[i])
|
||||
return Diff;
|
||||
if (Lhs[i] != Rhs[i])
|
||||
return Lhs[i] < Rhs[i] ? -1 : 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
LIBC_INLINE static constexpr size_t length(const char *Str) {
|
||||
for (const char *End = Str;; ++End)
|
||||
if (*End == '\0')
|
||||
LIBC_INLINE static constexpr size_t length(const CharT *Str) {
|
||||
for (const CharT *End = Str;; ++End)
|
||||
if (*End == CharT{0})
|
||||
return static_cast<size_t>(End - Str);
|
||||
}
|
||||
|
||||
LIBC_INLINE bool equals(string_view Other) const {
|
||||
return (Len == Other.Len &&
|
||||
compareMemory(Data, Other.Data, Other.Len) == 0);
|
||||
LIBC_INLINE constexpr bool equals(basic_string_view Other) const {
|
||||
return (Len == Other.Len && compareN(Data, Other.Data, Other.Len) == 0);
|
||||
}
|
||||
|
||||
public:
|
||||
using value_type = char;
|
||||
using value_type = CharT;
|
||||
using size_type = size_t;
|
||||
using difference_type = ptrdiff_t;
|
||||
using pointer = char *;
|
||||
using const_pointer = const char *;
|
||||
using reference = char &;
|
||||
using const_reference = const char &;
|
||||
using const_iterator = char *;
|
||||
using pointer = CharT *;
|
||||
using const_pointer = const CharT *;
|
||||
using reference = CharT &;
|
||||
using const_reference = const CharT &;
|
||||
using const_iterator = CharT *;
|
||||
using iterator = const_iterator;
|
||||
|
||||
// special value equal to the maximum value representable by the type
|
||||
@@ -65,124 +71,126 @@ public:
|
||||
LIBC_INLINE_VAR static constexpr size_t npos =
|
||||
cpp::numeric_limits<size_t>::max();
|
||||
|
||||
LIBC_INLINE constexpr string_view() : Data(nullptr), Len(0) {}
|
||||
LIBC_INLINE constexpr basic_string_view() : Data(nullptr), Len(0) {}
|
||||
|
||||
// Assumes Str is a null-terminated string. The length of the string does
|
||||
// not include the terminating null character.
|
||||
// Preconditions: [Str, Str + length(Str)) is a valid range.
|
||||
LIBC_INLINE constexpr string_view(const char *Str)
|
||||
LIBC_INLINE constexpr basic_string_view(const CharT *Str)
|
||||
: Data(Str), Len(length(Str)) {}
|
||||
|
||||
// Preconditions: [Str, Str + N) is a valid range.
|
||||
LIBC_INLINE constexpr string_view(const char *Str, size_t N)
|
||||
LIBC_INLINE constexpr basic_string_view(const CharT *Str, size_t N)
|
||||
: Data(Str), Len(N) {}
|
||||
|
||||
LIBC_INLINE constexpr const char *data() const { return Data; }
|
||||
LIBC_INLINE constexpr const CharT *data() const { return Data; }
|
||||
|
||||
// Returns the size of the string_view.
|
||||
// Returns the size of the basic_string_view.
|
||||
LIBC_INLINE constexpr size_t size() const { return Len; }
|
||||
|
||||
// Returns whether the string_view is empty.
|
||||
// Returns whether the basic_string_view is empty.
|
||||
LIBC_INLINE constexpr bool empty() const { return Len == 0; }
|
||||
|
||||
// Returns an iterator to the first character of the view.
|
||||
LIBC_INLINE const char *begin() const { return Data; }
|
||||
LIBC_INLINE constexpr const CharT *begin() const { return Data; }
|
||||
|
||||
// Returns an iterator to the character following the last character of the
|
||||
// view.
|
||||
LIBC_INLINE const char *end() const { return Data + Len; }
|
||||
LIBC_INLINE constexpr const CharT *end() const { return Data + Len; }
|
||||
|
||||
// Returns a const reference to the character at specified location pos.
|
||||
// No bounds checking is performed: the behavior is undefined if pos >=
|
||||
// size().
|
||||
LIBC_INLINE constexpr const char &operator[](size_t Index) const {
|
||||
LIBC_INLINE constexpr const CharT &operator[](size_t Index) const {
|
||||
return Data[Index];
|
||||
}
|
||||
|
||||
/// compare - Compare two strings; the result is -1, 0, or 1 if this string
|
||||
/// is lexicographically less than, equal to, or greater than the \p Other.
|
||||
LIBC_INLINE int compare(string_view Other) const {
|
||||
LIBC_INLINE constexpr int compare(basic_string_view Other) const {
|
||||
// Check the prefix for a mismatch.
|
||||
if (int Res = compareMemory(Data, Other.Data, min(Len, Other.Len)))
|
||||
return Res < 0 ? -1 : 1;
|
||||
if (int Res = compareN(Data, Other.Data, min(Len, Other.Len)))
|
||||
return Res;
|
||||
// Otherwise the prefixes match, so we only need to check the lengths.
|
||||
if (Len == Other.Len)
|
||||
return 0;
|
||||
return Len < Other.Len ? -1 : 1;
|
||||
}
|
||||
|
||||
LIBC_INLINE bool operator==(string_view Other) const { return equals(Other); }
|
||||
LIBC_INLINE bool operator!=(string_view Other) const {
|
||||
LIBC_INLINE constexpr bool operator==(basic_string_view Other) const {
|
||||
return equals(Other);
|
||||
}
|
||||
LIBC_INLINE constexpr bool operator!=(basic_string_view Other) const {
|
||||
return !(*this == Other);
|
||||
}
|
||||
LIBC_INLINE bool operator<(string_view Other) const {
|
||||
LIBC_INLINE constexpr bool operator<(basic_string_view Other) const {
|
||||
return compare(Other) == -1;
|
||||
}
|
||||
LIBC_INLINE bool operator<=(string_view Other) const {
|
||||
LIBC_INLINE constexpr bool operator<=(basic_string_view Other) const {
|
||||
return compare(Other) != 1;
|
||||
}
|
||||
LIBC_INLINE bool operator>(string_view Other) const {
|
||||
LIBC_INLINE constexpr bool operator>(basic_string_view Other) const {
|
||||
return compare(Other) == 1;
|
||||
}
|
||||
LIBC_INLINE bool operator>=(string_view Other) const {
|
||||
LIBC_INLINE constexpr bool operator>=(basic_string_view Other) const {
|
||||
return compare(Other) != -1;
|
||||
}
|
||||
|
||||
// Moves the start of the view forward by n characters.
|
||||
// The behavior is undefined if n > size().
|
||||
LIBC_INLINE void remove_prefix(size_t N) {
|
||||
LIBC_INLINE constexpr void remove_prefix(size_t N) {
|
||||
Len -= N;
|
||||
Data += N;
|
||||
}
|
||||
|
||||
// Moves the end of the view back by n characters.
|
||||
// The behavior is undefined if n > size().
|
||||
LIBC_INLINE void remove_suffix(size_t N) { Len -= N; }
|
||||
LIBC_INLINE constexpr void remove_suffix(size_t N) { Len -= N; }
|
||||
|
||||
// Check if this string starts with the given Prefix.
|
||||
LIBC_INLINE bool starts_with(string_view Prefix) const {
|
||||
return Len >= Prefix.Len &&
|
||||
compareMemory(Data, Prefix.Data, Prefix.Len) == 0;
|
||||
LIBC_INLINE constexpr bool starts_with(basic_string_view Prefix) const {
|
||||
return Len >= Prefix.Len && compareN(Data, Prefix.Data, Prefix.Len) == 0;
|
||||
}
|
||||
|
||||
// Check if this string starts with the given Prefix.
|
||||
LIBC_INLINE bool starts_with(const char Prefix) const {
|
||||
LIBC_INLINE constexpr bool starts_with(const CharT Prefix) const {
|
||||
return !empty() && front() == Prefix;
|
||||
}
|
||||
|
||||
// Check if this string ends with the given Prefix.
|
||||
LIBC_INLINE bool ends_with(const char Suffix) const {
|
||||
LIBC_INLINE constexpr bool ends_with(const CharT Suffix) const {
|
||||
return !empty() && back() == Suffix;
|
||||
}
|
||||
|
||||
// Check if this string ends with the given Suffix.
|
||||
LIBC_INLINE bool ends_with(string_view Suffix) const {
|
||||
LIBC_INLINE constexpr bool ends_with(basic_string_view Suffix) const {
|
||||
return Len >= Suffix.Len &&
|
||||
compareMemory(end() - Suffix.Len, Suffix.Data, Suffix.Len) == 0;
|
||||
compareN(end() - Suffix.Len, Suffix.Data, Suffix.Len) == 0;
|
||||
}
|
||||
|
||||
// Return a reference to the substring from [Start, Start + N).
|
||||
//
|
||||
// Start The index of the starting character in the substring; if the index is
|
||||
// npos or greater than the length of the string then the empty substring will
|
||||
// be returned.
|
||||
// Start The index of the starting character in the substring; if the index
|
||||
// is npos or greater than the length of the string then the empty substring
|
||||
// will be returned.
|
||||
//
|
||||
// N The number of characters to included in the substring. If N exceeds the
|
||||
// number of characters remaining in the string, the string suffix (starting
|
||||
// with Start) will be returned.
|
||||
LIBC_INLINE string_view substr(size_t Start, size_t N = npos) const {
|
||||
LIBC_INLINE constexpr basic_string_view substr(size_t Start,
|
||||
size_t N = npos) const {
|
||||
Start = min(Start, Len);
|
||||
return string_view(Data + Start, min(N, Len - Start));
|
||||
return basic_string_view(Data + Start, min(N, Len - Start));
|
||||
}
|
||||
|
||||
// front - Get the first character in the string.
|
||||
LIBC_INLINE char front() const { return Data[0]; }
|
||||
LIBC_INLINE constexpr CharT front() const { return Data[0]; }
|
||||
|
||||
// back - Get the last character in the string.
|
||||
LIBC_INLINE char back() const { return Data[Len - 1]; }
|
||||
LIBC_INLINE constexpr CharT back() const { return Data[Len - 1]; }
|
||||
|
||||
// Finds the first occurence of c in this view, starting at position From.
|
||||
LIBC_INLINE constexpr size_t find_first_of(const char c,
|
||||
LIBC_INLINE constexpr size_t find_first_of(const CharT c,
|
||||
size_t From = 0) const {
|
||||
for (size_t Pos = From; Pos < size(); ++Pos)
|
||||
if ((*this)[Pos] == c)
|
||||
@@ -191,7 +199,7 @@ public:
|
||||
}
|
||||
|
||||
// Finds the last occurence of c in this view, ending at position End.
|
||||
LIBC_INLINE constexpr size_t find_last_of(const char c,
|
||||
LIBC_INLINE constexpr size_t find_last_of(const CharT c,
|
||||
size_t End = npos) const {
|
||||
End = End >= size() ? size() : End + 1;
|
||||
for (; End > 0; --End)
|
||||
@@ -200,9 +208,18 @@ public:
|
||||
return npos;
|
||||
}
|
||||
|
||||
// Finds the first character not equal to c in this view, starting at position
|
||||
// From.
|
||||
LIBC_INLINE constexpr size_t find_first_not_of(const char c,
|
||||
LIBC_INLINE constexpr size_t find_last_not_of(const char c,
|
||||
size_t end = npos) const {
|
||||
end = end >= size() ? size() : end + 1;
|
||||
for (; end > 0; --end)
|
||||
if ((*this)[end - 1] != c)
|
||||
return end - 1;
|
||||
return npos;
|
||||
}
|
||||
|
||||
// Finds the first character not equal to c in this view, starting at
|
||||
// position From.
|
||||
LIBC_INLINE constexpr size_t find_first_not_of(const CharT c,
|
||||
size_t From = 0) const {
|
||||
for (size_t Pos = From; Pos < size(); ++Pos)
|
||||
if ((*this)[Pos] != c)
|
||||
@@ -211,7 +228,7 @@ public:
|
||||
}
|
||||
|
||||
// Check if this view contains the given character.
|
||||
LIBC_INLINE constexpr bool contains(char c) const {
|
||||
LIBC_INLINE constexpr bool contains(CharT c) const {
|
||||
return find_first_of(c) != npos;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
//===------------------------------------------------------------*- 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// \file
|
||||
// This file contains a free-standing implementation of is_assignable
|
||||
// type trait.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_IS_ASSIGNABLE_H
|
||||
#define LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_IS_ASSIGNABLE_H
|
||||
|
||||
#include "src/__support/CPP/type_traits/bool_constant.h"
|
||||
#include "src/__support/CPP/utility/declval.h"
|
||||
#include "src/__support/macros/attributes.h"
|
||||
#include "src/__support/macros/config.h"
|
||||
|
||||
namespace LIBC_NAMESPACE_DECL {
|
||||
namespace cpp {
|
||||
|
||||
namespace is_assignable_detail {
|
||||
|
||||
#if LIBC_HAS_BUILTIN_IS_ASSIGNABLE
|
||||
|
||||
template <typename T, typename U>
|
||||
struct is_assignable_impl : public bool_constant<__is_assignable(T, U)> {};
|
||||
|
||||
#else
|
||||
// Fallback SFINAE implementation for GCC 7 and older toolchains
|
||||
|
||||
template <typename T, typename U> struct is_assignable_impl {
|
||||
private:
|
||||
template <typename T1, typename U1>
|
||||
LIBC_INLINE static auto test(int)
|
||||
-> decltype(declval<T1>() = declval<U1>(), bool_constant<true>());
|
||||
|
||||
template <typename, typename>
|
||||
LIBC_INLINE static auto test(...) -> bool_constant<false>;
|
||||
|
||||
public:
|
||||
using type = decltype(test<T, U>(0));
|
||||
};
|
||||
|
||||
#endif // LIBC_HAS_BUILTIN_IS_ASSIGNABLE
|
||||
|
||||
} // namespace is_assignable_detail
|
||||
|
||||
// is_assignable
|
||||
template <typename T, typename U>
|
||||
struct is_assignable : public is_assignable_detail::is_assignable_impl<T, U> {};
|
||||
|
||||
template <typename T, typename U>
|
||||
LIBC_INLINE_VAR constexpr bool is_assignable_v = is_assignable<T, U>::value;
|
||||
|
||||
} // namespace cpp
|
||||
} // namespace LIBC_NAMESPACE_DECL
|
||||
|
||||
#endif // LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_IS_ASSIGNABLE_H
|
||||
@@ -15,7 +15,11 @@ namespace LIBC_NAMESPACE_DECL {
|
||||
namespace cpp {
|
||||
|
||||
LIBC_INLINE constexpr bool is_constant_evaluated() {
|
||||
#if LIBC_HAS_BUILTIN_IS_CONSTANT_EVALUATED
|
||||
return __builtin_is_constant_evaluated();
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace cpp
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
//===------------------------------------------------------------*- 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// \file
|
||||
// This file contains a free-standing implementation of is_constructible
|
||||
// type trait.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_IS_CONSTRUCTIBLE_H
|
||||
#define LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_IS_CONSTRUCTIBLE_H
|
||||
|
||||
#include "src/__support/CPP/type_traits/bool_constant.h"
|
||||
#include "src/__support/CPP/utility/declval.h"
|
||||
#include "src/__support/macros/attributes.h"
|
||||
#include "src/__support/macros/config.h"
|
||||
|
||||
namespace LIBC_NAMESPACE_DECL {
|
||||
namespace cpp {
|
||||
|
||||
namespace is_contructible_detail {
|
||||
|
||||
#if LIBC_HAS_BUILTIN_IS_CONSTRUCTIBLE
|
||||
|
||||
template <typename T, typename... Args>
|
||||
struct is_constructible_impl
|
||||
: public bool_constant<__is_constructible(T, Args...)> {};
|
||||
|
||||
#else
|
||||
// Fallback SFINAE implementation for GCC 7 and older toolchains
|
||||
|
||||
template <typename T, typename... Args> struct is_constructible_impl {
|
||||
private:
|
||||
template <typename T1, typename... Args1>
|
||||
LIBC_INLINE static auto test(int)
|
||||
-> decltype(T1(declval<Args1>()...), bool_constant<true>());
|
||||
|
||||
template <typename, typename...>
|
||||
LIBC_INLINE static auto test(...) -> bool_constant<false>;
|
||||
|
||||
public:
|
||||
using type = decltype(test<T, Args...>(0));
|
||||
};
|
||||
|
||||
#endif // LIBC_HAS_BUILTIN_IS_CONSTRUCTIBLE
|
||||
|
||||
} // namespace is_contructible_detail
|
||||
|
||||
template <typename T, typename... Args>
|
||||
struct is_constructible
|
||||
: public is_contructible_detail::is_constructible_impl<T, Args...> {};
|
||||
|
||||
template <typename T, typename... Args>
|
||||
LIBC_INLINE_VAR constexpr bool is_constructible_v =
|
||||
is_constructible<T, Args...>::value;
|
||||
|
||||
} // namespace cpp
|
||||
} // namespace LIBC_NAMESPACE_DECL
|
||||
|
||||
#endif // LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_IS_CONSTRUCTIBLE_H
|
||||
@@ -9,7 +9,7 @@
|
||||
#define LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_IS_COPY_ASSIGNABLE_H
|
||||
|
||||
#include "src/__support/CPP/type_traits/add_lvalue_reference.h"
|
||||
#include "src/__support/CPP/type_traits/integral_constant.h"
|
||||
#include "src/__support/CPP/type_traits/is_assignable.h"
|
||||
#include "src/__support/macros/config.h"
|
||||
|
||||
namespace LIBC_NAMESPACE_DECL {
|
||||
@@ -18,9 +18,8 @@ namespace cpp {
|
||||
// is copy assignable
|
||||
template <class T>
|
||||
struct is_copy_assignable
|
||||
: public integral_constant<
|
||||
bool, __is_assignable(cpp::add_lvalue_reference_t<T>,
|
||||
cpp::add_lvalue_reference_t<const T>)> {};
|
||||
: public cpp::is_assignable<cpp::add_lvalue_reference_t<T>,
|
||||
cpp::add_lvalue_reference_t<const T>> {};
|
||||
|
||||
template <class T>
|
||||
LIBC_INLINE_VAR constexpr bool is_copy_assignable_v =
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
#define LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_IS_COPY_CONSTRUCTIBLE_H
|
||||
|
||||
#include "src/__support/CPP/type_traits/add_lvalue_reference.h"
|
||||
#include "src/__support/CPP/type_traits/integral_constant.h"
|
||||
#include "src/__support/CPP/type_traits/is_constructible.h"
|
||||
#include "src/__support/macros/config.h"
|
||||
|
||||
namespace LIBC_NAMESPACE_DECL {
|
||||
@@ -18,8 +18,7 @@ namespace cpp {
|
||||
// is copy constructible
|
||||
template <class T>
|
||||
struct is_copy_constructible
|
||||
: public integral_constant<
|
||||
bool, __is_constructible(T, cpp::add_lvalue_reference_t<const T>)> {};
|
||||
: public cpp::is_constructible<T, cpp::add_lvalue_reference_t<const T>> {};
|
||||
|
||||
template <class T>
|
||||
LIBC_INLINE_VAR constexpr bool is_copy_constructible_v =
|
||||
|
||||
+10
-5
@@ -26,13 +26,18 @@ private:
|
||||
}
|
||||
|
||||
public:
|
||||
LIBC_INLINE_VAR static constexpr bool value = __is_unqualified_any_of<
|
||||
T,
|
||||
LIBC_INLINE_VAR static constexpr bool value =
|
||||
__is_unqualified_any_of<T,
|
||||
#ifdef LIBC_TYPES_HAS_INT128
|
||||
__int128_t, __uint128_t,
|
||||
__int128_t, __uint128_t,
|
||||
#endif
|
||||
char, signed char, unsigned char, short, unsigned short, int,
|
||||
unsigned int, long, unsigned long, long long, unsigned long long, bool>();
|
||||
#ifdef __cpp_char8_t
|
||||
char8_t,
|
||||
#endif
|
||||
char16_t, char32_t, wchar_t, char, signed char,
|
||||
unsigned char, short, unsigned short, int,
|
||||
unsigned int, long, unsigned long, long long,
|
||||
unsigned long long, bool>();
|
||||
};
|
||||
template <typename T>
|
||||
LIBC_INLINE_VAR constexpr bool is_integral_v = is_integral<T>::value;
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
#include "src/__support/CPP/type_traits/add_lvalue_reference.h"
|
||||
#include "src/__support/CPP/type_traits/add_rvalue_reference.h"
|
||||
#include "src/__support/CPP/type_traits/integral_constant.h"
|
||||
#include "src/__support/CPP/type_traits/is_assignable.h"
|
||||
#include "src/__support/macros/config.h"
|
||||
|
||||
namespace LIBC_NAMESPACE_DECL {
|
||||
@@ -19,9 +19,8 @@ namespace cpp {
|
||||
// is move assignable
|
||||
template <class T>
|
||||
struct is_move_assignable
|
||||
: public integral_constant<bool, __is_assignable(
|
||||
cpp::add_lvalue_reference_t<T>,
|
||||
cpp::add_rvalue_reference_t<T>)> {};
|
||||
: public cpp::is_assignable<cpp::add_lvalue_reference_t<T>,
|
||||
cpp::add_rvalue_reference_t<T>> {};
|
||||
|
||||
template <class T>
|
||||
LIBC_INLINE_VAR constexpr bool is_move_assignable_v =
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
#define LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_IS_MOVE_CONSTRUCTIBLE_H
|
||||
|
||||
#include "src/__support/CPP/type_traits/add_rvalue_reference.h"
|
||||
#include "src/__support/CPP/type_traits/integral_constant.h"
|
||||
#include "src/__support/CPP/type_traits/is_constructible.h"
|
||||
#include "src/__support/macros/config.h"
|
||||
|
||||
namespace LIBC_NAMESPACE_DECL {
|
||||
@@ -18,8 +18,7 @@ namespace cpp {
|
||||
// is move constructible
|
||||
template <class T>
|
||||
struct is_move_constructible
|
||||
: public integral_constant<bool, __is_constructible(
|
||||
T, cpp::add_rvalue_reference_t<T>)> {};
|
||||
: public cpp::is_constructible<T, cpp::add_rvalue_reference_t<T>> {};
|
||||
|
||||
template <class T>
|
||||
LIBC_INLINE_VAR constexpr bool is_move_constructible_v =
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
#include "include/llvm-libc-macros/stdfix-macros.h"
|
||||
#include "src/__support/CPP/type_traits/bool_constant.h"
|
||||
#include "src/__support/CPP/type_traits/is_arithmetic.h"
|
||||
#include "src/__support/CPP/type_traits/is_integral.h"
|
||||
#include "src/__support/CPP/type_traits/is_same.h"
|
||||
#include "src/__support/CPP/type_traits/remove_cv.h"
|
||||
#include "src/__support/macros/attributes.h"
|
||||
@@ -23,7 +23,7 @@ namespace cpp {
|
||||
|
||||
#ifndef LIBC_COMPILER_HAS_FIXED_POINT
|
||||
template <typename T>
|
||||
struct is_unsigned : bool_constant<(is_arithmetic_v<T> && (T(-1) > T(0)))> {
|
||||
struct is_unsigned : bool_constant<(is_integral_v<T> && (T(-1) > T(0)))> {
|
||||
LIBC_INLINE constexpr operator bool() const { return is_unsigned::value; }
|
||||
LIBC_INLINE constexpr bool operator()() const { return is_unsigned::value; }
|
||||
};
|
||||
@@ -37,7 +37,7 @@ private:
|
||||
|
||||
public:
|
||||
LIBC_INLINE_VAR static constexpr bool value =
|
||||
(is_arithmetic_v<T> && (T(-1) > T(0))) ||
|
||||
(is_integral_v<T> && (T(-1) > T(0))) ||
|
||||
__is_unqualified_any_of<T, unsigned short fract, unsigned fract,
|
||||
unsigned long fract, unsigned short accum,
|
||||
unsigned accum, unsigned long accum,
|
||||
|
||||
+16
-13
@@ -798,7 +798,9 @@ template <typename T> LIBC_INLINE static constexpr FPType get_fp_type() {
|
||||
return FPType::IEEE754_Binary64;
|
||||
else if constexpr (LDBL_MANT_DIG == 64)
|
||||
return FPType::X86_Binary80;
|
||||
else if constexpr (LDBL_MANT_DIG == 113)
|
||||
// TODO: properly treat double-double type.
|
||||
// else if constexpr (LDBL_MANT_DIG == 113)
|
||||
else
|
||||
return FPType::IEEE754_Binary128;
|
||||
}
|
||||
#if defined(LIBC_TYPES_HAS_FLOAT16)
|
||||
@@ -833,21 +835,22 @@ struct FPBits final : public internal::FPRepImpl<get_fp_type<T>(), FPBits<T>> {
|
||||
// Constructors.
|
||||
LIBC_INLINE constexpr FPBits() = default;
|
||||
|
||||
template <typename XType> LIBC_INLINE constexpr explicit FPBits(XType x) {
|
||||
using Unqual = typename cpp::remove_cv_t<XType>;
|
||||
if constexpr (cpp::is_same_v<Unqual, T>) {
|
||||
UP::bits = cpp::bit_cast<StorageType>(x);
|
||||
} else if constexpr (cpp::is_same_v<Unqual, StorageType>) {
|
||||
UP::bits = x;
|
||||
} else {
|
||||
// We don't want accidental type promotions/conversions, so we require
|
||||
// exact type match.
|
||||
static_assert(cpp::always_false<XType>);
|
||||
}
|
||||
template <
|
||||
typename XType,
|
||||
cpp::enable_if_t<cpp::is_same_v<cpp::remove_cv_t<XType>, T>, int> = 0>
|
||||
LIBC_INLINE LIBC_BIT_CAST_CONSTEXPR explicit FPBits(XType x) {
|
||||
UP::bits = cpp::bit_cast<StorageType>(x);
|
||||
}
|
||||
|
||||
template <typename XType,
|
||||
cpp::enable_if_t<
|
||||
cpp::is_same_v<cpp::remove_cv_t<XType>, StorageType>, int> = 0>
|
||||
LIBC_INLINE constexpr explicit FPBits(XType x) : UP(x) {}
|
||||
|
||||
// Floating-point conversions.
|
||||
LIBC_INLINE constexpr T get_val() const { return cpp::bit_cast<T>(UP::bits); }
|
||||
LIBC_INLINE LIBC_BIT_CAST_CONSTEXPR T get_val() const {
|
||||
return cpp::bit_cast<T>(UP::bits);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace fputil
|
||||
|
||||
+25
-5
@@ -24,8 +24,12 @@ namespace generic {
|
||||
// 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() {
|
||||
#ifdef LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY
|
||||
return false;
|
||||
#else
|
||||
static volatile float x = 0x1.0p-25f;
|
||||
return (1.0f + x != 1.0f);
|
||||
#endif // LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY
|
||||
}
|
||||
|
||||
// Quick free-standing test whether fegetround() == FE_DOWNWARD.
|
||||
@@ -33,8 +37,12 @@ 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() {
|
||||
#ifdef LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY
|
||||
return false;
|
||||
#else
|
||||
static volatile float x = 0x1.0p-25f;
|
||||
return (-1.0f - x != -1.0f);
|
||||
#endif // LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY
|
||||
}
|
||||
|
||||
// Quick free-standing test whether fegetround() == FE_TONEAREST.
|
||||
@@ -44,9 +52,13 @@ LIBC_INLINE bool fenv_is_round_down() {
|
||||
// 1.5f - 2^-24 = 1.5f for FE_TONEAREST, FE_UPWARD
|
||||
// = 0x1.0ffffep-1f for FE_DOWNWARD, FE_TOWARDZERO
|
||||
LIBC_INLINE bool fenv_is_round_to_nearest() {
|
||||
#ifdef LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY
|
||||
return true;
|
||||
#else
|
||||
static volatile float x = 0x1.0p-24f;
|
||||
float y = 1.5f + x;
|
||||
return (y == 1.5f - x);
|
||||
#endif // LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY
|
||||
}
|
||||
|
||||
// Quick free-standing test whether fegetround() == FE_TOWARDZERO.
|
||||
@@ -60,13 +72,20 @@ LIBC_INLINE bool fenv_is_round_to_nearest() {
|
||||
// = 2^-22 for FE_TONEAREST, FE_UPWARD
|
||||
// = 0 for FE_DOWNWARD
|
||||
LIBC_INLINE bool fenv_is_round_to_zero() {
|
||||
#ifdef LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY
|
||||
return false;
|
||||
#else
|
||||
static volatile float x = 0x1.0p-24f;
|
||||
float y = x;
|
||||
return ((0x1.000002p0f + y) + (-1.0f - y) == 0x1.0p-23f);
|
||||
#endif // LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY
|
||||
}
|
||||
|
||||
// Quick free standing get rounding mode based on the above observations.
|
||||
LIBC_INLINE int quick_get_round() {
|
||||
#ifdef LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY
|
||||
return FE_TONEAREST;
|
||||
#else
|
||||
static volatile float x = 0x1.0p-24f;
|
||||
float y = x;
|
||||
float z = (0x1.000002p0f + y) + (-1.0f - y);
|
||||
@@ -76,11 +95,12 @@ LIBC_INLINE int quick_get_round() {
|
||||
if (z == 0x1.0p-23f)
|
||||
return FE_TOWARDZERO;
|
||||
return (2.0f + y == 2.0f) ? FE_TONEAREST : FE_UPWARD;
|
||||
#endif // LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY
|
||||
}
|
||||
|
||||
} // namespace generic
|
||||
|
||||
LIBC_INLINE static constexpr bool fenv_is_round_up() {
|
||||
LIBC_INLINE LIBC_CONSTEXPR_DEFAULT bool fenv_is_round_up() {
|
||||
if (cpp::is_constant_evaluated()) {
|
||||
return false;
|
||||
} else {
|
||||
@@ -88,7 +108,7 @@ LIBC_INLINE static constexpr bool fenv_is_round_up() {
|
||||
}
|
||||
}
|
||||
|
||||
LIBC_INLINE static constexpr bool fenv_is_round_down() {
|
||||
LIBC_INLINE LIBC_CONSTEXPR_DEFAULT bool fenv_is_round_down() {
|
||||
if (cpp::is_constant_evaluated()) {
|
||||
return false;
|
||||
} else {
|
||||
@@ -96,7 +116,7 @@ LIBC_INLINE static constexpr bool fenv_is_round_down() {
|
||||
}
|
||||
}
|
||||
|
||||
LIBC_INLINE static constexpr bool fenv_is_round_to_nearest() {
|
||||
LIBC_INLINE LIBC_CONSTEXPR_DEFAULT bool fenv_is_round_to_nearest() {
|
||||
if (cpp::is_constant_evaluated()) {
|
||||
return true;
|
||||
} else {
|
||||
@@ -104,7 +124,7 @@ LIBC_INLINE static constexpr bool fenv_is_round_to_nearest() {
|
||||
}
|
||||
}
|
||||
|
||||
LIBC_INLINE static constexpr bool fenv_is_round_to_zero() {
|
||||
LIBC_INLINE LIBC_CONSTEXPR_DEFAULT bool fenv_is_round_to_zero() {
|
||||
if (cpp::is_constant_evaluated()) {
|
||||
return false;
|
||||
} else {
|
||||
@@ -113,7 +133,7 @@ LIBC_INLINE static constexpr bool fenv_is_round_to_zero() {
|
||||
}
|
||||
|
||||
// Quick free standing get rounding mode based on the above observations.
|
||||
LIBC_INLINE static constexpr int quick_get_round() {
|
||||
LIBC_INLINE LIBC_CONSTEXPR_DEFAULT int quick_get_round() {
|
||||
if (cpp::is_constant_evaluated()) {
|
||||
return FE_TONEAREST;
|
||||
} else {
|
||||
|
||||
+35
-49
@@ -242,10 +242,9 @@ LIBC_INLINE constexpr void quick_mul_hi(cpp::array<word, N> &dst,
|
||||
|
||||
template <typename word, size_t N>
|
||||
LIBC_INLINE constexpr bool is_negative(const cpp::array<word, N> &array) {
|
||||
using signed_word = cpp::make_signed_t<word>;
|
||||
return cpp::bit_cast<signed_word>(array.back()) < 0;
|
||||
constexpr size_t WORD_BITS = cpp::numeric_limits<word>::digits;
|
||||
return (array.back() >> (WORD_BITS - 1)) != 0;
|
||||
}
|
||||
|
||||
// An enum for the shift function below.
|
||||
enum Direction { LEFT, RIGHT };
|
||||
|
||||
@@ -257,9 +256,11 @@ LIBC_INLINE constexpr cpp::array<word, N> shift(cpp::array<word, N> array,
|
||||
size_t offset) {
|
||||
static_assert(direction == LEFT || direction == RIGHT);
|
||||
constexpr size_t WORD_BITS = cpp::numeric_limits<word>::digits;
|
||||
#if LIBC_HAS_BUILTIN_BIT_CAST
|
||||
#ifdef LIBC_TYPES_HAS_INT128
|
||||
constexpr size_t TOTAL_BITS = N * WORD_BITS;
|
||||
if constexpr (TOTAL_BITS == 128) {
|
||||
if constexpr (TOTAL_BITS == 128 &&
|
||||
__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) {
|
||||
using type = cpp::conditional_t<is_signed, __int128_t, __uint128_t>;
|
||||
auto tmp = cpp::bit_cast<type>(array);
|
||||
if constexpr (direction == LEFT)
|
||||
@@ -269,6 +270,8 @@ LIBC_INLINE constexpr cpp::array<word, N> shift(cpp::array<word, N> array,
|
||||
return cpp::bit_cast<cpp::array<word, N>>(tmp);
|
||||
}
|
||||
#endif
|
||||
#endif // LIBC_HAS_BUILTIN_BIT_CAST
|
||||
|
||||
if (LIBC_UNLIKELY(offset == 0))
|
||||
return array;
|
||||
const bool is_neg = is_signed && is_negative(array);
|
||||
@@ -336,8 +339,8 @@ private:
|
||||
"WordType must be unsigned integer.");
|
||||
|
||||
struct Division {
|
||||
BigInt quotient;
|
||||
BigInt remainder;
|
||||
BigInt quotient{};
|
||||
BigInt remainder{};
|
||||
};
|
||||
|
||||
public:
|
||||
@@ -355,7 +358,7 @@ public:
|
||||
|
||||
LIBC_INLINE_VAR static constexpr size_t WORD_COUNT = Bits / WORD_SIZE;
|
||||
|
||||
cpp::array<WordType, WORD_COUNT> val{}; // zero initialized.
|
||||
cpp::array<WordType, WORD_COUNT> val;
|
||||
|
||||
LIBC_INLINE constexpr BigInt() = default;
|
||||
|
||||
@@ -363,9 +366,10 @@ public:
|
||||
|
||||
template <size_t OtherBits, bool OtherSigned, typename OtherWordType>
|
||||
LIBC_INLINE constexpr BigInt(
|
||||
const BigInt<OtherBits, OtherSigned, OtherWordType> &other) {
|
||||
const BigInt<OtherBits, OtherSigned, OtherWordType> &other)
|
||||
: val{} {
|
||||
using BigIntOther = BigInt<OtherBits, OtherSigned, OtherWordType>;
|
||||
const bool should_sign_extend = Signed && other.is_neg();
|
||||
[[maybe_unused]] const bool should_sign_extend = Signed && other.is_neg();
|
||||
|
||||
static_assert(!(Bits == OtherBits && WORD_SIZE != BigIntOther::WORD_SIZE) &&
|
||||
"This is currently untested for casting between bigints with "
|
||||
@@ -453,20 +457,22 @@ public:
|
||||
}
|
||||
|
||||
// Construct a BigInt from a C array.
|
||||
template <size_t N> LIBC_INLINE constexpr BigInt(const WordType (&nums)[N]) {
|
||||
template <size_t N>
|
||||
LIBC_INLINE constexpr BigInt(const WordType (&nums)[N]) : val{} {
|
||||
static_assert(N == WORD_COUNT);
|
||||
for (size_t i = 0; i < WORD_COUNT; ++i)
|
||||
val[i] = nums[i];
|
||||
}
|
||||
|
||||
LIBC_INLINE constexpr explicit BigInt(
|
||||
const cpp::array<WordType, WORD_COUNT> &words) {
|
||||
const cpp::array<WordType, WORD_COUNT> &words)
|
||||
: val{} {
|
||||
val = words;
|
||||
}
|
||||
|
||||
// Initialize the first word to |v| and the rest to 0.
|
||||
template <typename T, typename = cpp::enable_if_t<cpp::is_integral_v<T>>>
|
||||
LIBC_INLINE constexpr BigInt(T v) {
|
||||
LIBC_INLINE constexpr BigInt(T v) : val{} {
|
||||
constexpr size_t T_SIZE = sizeof(T) * CHAR_BIT;
|
||||
const bool is_neg = v < 0;
|
||||
for (size_t i = 0; i < WORD_COUNT; ++i) {
|
||||
@@ -488,7 +494,7 @@ public:
|
||||
LIBC_INLINE static constexpr BigInt one() { return BigInt(1); }
|
||||
LIBC_INLINE static constexpr BigInt all_ones() { return ~zero(); }
|
||||
LIBC_INLINE static constexpr BigInt min() {
|
||||
BigInt out;
|
||||
BigInt out{};
|
||||
if constexpr (SIGNED)
|
||||
out.set_msb();
|
||||
return out;
|
||||
@@ -601,7 +607,7 @@ public:
|
||||
template <size_t OtherBits>
|
||||
LIBC_INLINE constexpr auto
|
||||
ful_mul(const BigInt<OtherBits, Signed, WordType> &other) const {
|
||||
BigInt<Bits + OtherBits, Signed, WordType> result;
|
||||
BigInt<Bits + OtherBits, Signed, WordType> result{};
|
||||
multiword::multiply_with_carry(result.val, val, other.val);
|
||||
return result;
|
||||
}
|
||||
@@ -633,7 +639,7 @@ public:
|
||||
// 256 4 16 10 3
|
||||
// 512 8 64 36 7
|
||||
LIBC_INLINE constexpr BigInt quick_mul_hi(const BigInt &other) const {
|
||||
BigInt result;
|
||||
BigInt result{};
|
||||
multiword::quick_mul_hi(result.val, val, other.val);
|
||||
return result;
|
||||
}
|
||||
@@ -686,7 +692,7 @@ public:
|
||||
// And finally we perform some extra alignment steps for the remaining bits.
|
||||
LIBC_INLINE constexpr cpp::optional<BigInt>
|
||||
div_uint_half_times_pow_2(multiword::half_width_t<WordType> x, size_t e) {
|
||||
BigInt remainder;
|
||||
BigInt remainder{};
|
||||
if (x == 0)
|
||||
return cpp::nullopt;
|
||||
if (e >= Bits) {
|
||||
@@ -694,7 +700,7 @@ public:
|
||||
*this = BigInt<Bits, false, WordType>();
|
||||
return remainder;
|
||||
}
|
||||
BigInt quotient;
|
||||
BigInt quotient{};
|
||||
WordType x_word = static_cast<WordType>(x);
|
||||
constexpr size_t LOG2_WORD_SIZE =
|
||||
static_cast<size_t>(cpp::bit_width(WORD_SIZE) - 1);
|
||||
@@ -846,13 +852,13 @@ public:
|
||||
#define DEFINE_BINOP(OP) \
|
||||
LIBC_INLINE friend constexpr BigInt operator OP(const BigInt &lhs, \
|
||||
const BigInt &rhs) { \
|
||||
BigInt result; \
|
||||
BigInt result{}; \
|
||||
for (size_t i = 0; i < WORD_COUNT; ++i) \
|
||||
result[i] = lhs[i] OP rhs[i]; \
|
||||
return result; \
|
||||
} \
|
||||
LIBC_INLINE friend constexpr BigInt operator OP##=(BigInt &lhs, \
|
||||
const BigInt &rhs) { \
|
||||
LIBC_INLINE friend constexpr BigInt operator OP## = \
|
||||
(BigInt & lhs, const BigInt &rhs) { \
|
||||
for (size_t i = 0; i < WORD_COUNT; ++i) \
|
||||
lhs[i] OP## = rhs[i]; \
|
||||
return lhs; \
|
||||
@@ -864,7 +870,7 @@ public:
|
||||
#undef DEFINE_BINOP
|
||||
|
||||
LIBC_INLINE constexpr BigInt operator~() const {
|
||||
BigInt result;
|
||||
BigInt result{};
|
||||
for (size_t i = 0; i < WORD_COUNT; ++i)
|
||||
result[i] = static_cast<WordType>(~val[i]);
|
||||
return result;
|
||||
@@ -1004,7 +1010,7 @@ private:
|
||||
LIBC_INLINE constexpr static Division divide_unsigned(const BigInt ÷nd,
|
||||
const BigInt ÷r) {
|
||||
BigInt remainder = dividend;
|
||||
BigInt quotient;
|
||||
BigInt quotient{};
|
||||
if (remainder >= divider) {
|
||||
BigInt subtractor = divider;
|
||||
int cur_bit = multiword::countl_zero(subtractor.val) -
|
||||
@@ -1181,31 +1187,6 @@ LIBC_INLINE_VAR constexpr bool is_unsigned_integral_or_big_int_v =
|
||||
|
||||
namespace cpp {
|
||||
|
||||
// Specialization of cpp::bit_cast ('bit.h') from T to BigInt.
|
||||
template <typename To, typename From>
|
||||
LIBC_INLINE constexpr cpp::enable_if_t<
|
||||
(sizeof(To) == sizeof(From)) && cpp::is_trivially_copyable<To>::value &&
|
||||
cpp::is_trivially_copyable<From>::value && is_big_int<To>::value,
|
||||
To>
|
||||
bit_cast(const From &from) {
|
||||
To out;
|
||||
using Storage = decltype(out.val);
|
||||
out.val = cpp::bit_cast<Storage>(from);
|
||||
return out;
|
||||
}
|
||||
|
||||
// Specialization of cpp::bit_cast ('bit.h') from BigInt to T.
|
||||
template <typename To, size_t Bits>
|
||||
LIBC_INLINE constexpr cpp::enable_if_t<
|
||||
sizeof(To) == sizeof(UInt<Bits>) &&
|
||||
cpp::is_trivially_constructible<To>::value &&
|
||||
cpp::is_trivially_copyable<To>::value &&
|
||||
cpp::is_trivially_copyable<UInt<Bits>>::value,
|
||||
To>
|
||||
bit_cast(const UInt<Bits> &from) {
|
||||
return cpp::bit_cast<To>(from.val);
|
||||
}
|
||||
|
||||
// Specialization of cpp::popcount ('bit.h') for BigInt.
|
||||
template <typename T>
|
||||
[[nodiscard]] LIBC_INLINE constexpr cpp::enable_if_t<is_big_int_v<T>, int>
|
||||
@@ -1311,7 +1292,7 @@ mask_trailing_ones() {
|
||||
return T::all_ones();
|
||||
constexpr size_t QUOTIENT = count / T::WORD_SIZE;
|
||||
constexpr size_t REMAINDER = count % T::WORD_SIZE;
|
||||
T out; // zero initialized
|
||||
T out{};
|
||||
for (size_t i = 0; i <= QUOTIENT; ++i)
|
||||
out[i] = i < QUOTIENT
|
||||
? cpp::numeric_limits<typename T::word_type>::max()
|
||||
@@ -1327,7 +1308,7 @@ LIBC_INLINE constexpr cpp::enable_if_t<is_big_int_v<T>, T> mask_leading_ones() {
|
||||
return T::all_ones();
|
||||
constexpr size_t QUOTIENT = (T::BITS - count - 1U) / T::WORD_SIZE;
|
||||
constexpr size_t REMAINDER = count % T::WORD_SIZE;
|
||||
T out; // zero initialized
|
||||
T out{};
|
||||
for (size_t i = QUOTIENT; i < T::WORD_COUNT; ++i)
|
||||
out[i] = i > QUOTIENT
|
||||
? cpp::numeric_limits<typename T::word_type>::max()
|
||||
@@ -1386,6 +1367,11 @@ first_trailing_one(T value) {
|
||||
return value == 0 ? 0 : cpp::countr_zero(value) + 1;
|
||||
}
|
||||
|
||||
static_assert(LIBC_NAMESPACE::cpp::is_trivially_constructible<
|
||||
LIBC_NAMESPACE::BigInt<128, false>>::value);
|
||||
static_assert(LIBC_NAMESPACE::cpp::is_trivially_copyable<
|
||||
LIBC_NAMESPACE::BigInt<128, false>>::value);
|
||||
|
||||
} // namespace LIBC_NAMESPACE_DECL
|
||||
|
||||
#endif // LLVM_LIBC_SRC___SUPPORT_BIG_INT_H
|
||||
+45
-32
@@ -22,6 +22,10 @@
|
||||
#define LLVM_LIBC_FUNCTION_ATTR
|
||||
#endif
|
||||
|
||||
#ifndef LLVM_LIBC_VARIABLE_ATTR
|
||||
#define LLVM_LIBC_VARIABLE_ATTR
|
||||
#endif
|
||||
|
||||
// clang-format off
|
||||
// Allow each function `func` to have extra attributes specified by defining:
|
||||
// `LLVM_LIBC_FUNCTION_ATTR_func` macro, which should always start with
|
||||
@@ -33,7 +37,9 @@
|
||||
// clang-format on
|
||||
#define LLVM_LIBC_EMPTY
|
||||
|
||||
#define GET_NOTHING(...) 0
|
||||
#define GET_SECOND(first, second, ...) second
|
||||
#define GET_FIFTH(first, second, third, fourth, fifth, ...) fifth
|
||||
#define EXPAND_THEN_SECOND(name) GET_SECOND(name, LLVM_LIBC_EMPTY)
|
||||
|
||||
#define LLVM_LIBC_ATTR(name) EXPAND_THEN_SECOND(LLVM_LIBC_FUNCTION_ATTR_##name)
|
||||
@@ -44,50 +50,57 @@
|
||||
// symbol. Moreover, a C symbol `func` in macOS is mangled as `_func`.
|
||||
#if defined(LIBC_COPT_PUBLIC_PACKAGING) && !defined(LIBC_COMPILER_IS_MSVC)
|
||||
#ifndef __APPLE__
|
||||
#define LLVM_LIBC_FUNCTION_IMPL(type, name, arglist) \
|
||||
#define LLVM_LIBC_FUNCTION_IMPL_4(type, name, arglist, c_alias) \
|
||||
LLVM_LIBC_ATTR(name) \
|
||||
LLVM_LIBC_FUNCTION_ATTR decltype(LIBC_NAMESPACE::name) \
|
||||
__##name##_impl__ asm(#name); \
|
||||
decltype(LIBC_NAMESPACE::name) name [[gnu::alias(#name)]]; \
|
||||
__##name##_impl__ asm(c_alias); \
|
||||
decltype(LIBC_NAMESPACE::name) name [[gnu::alias(c_alias)]]; \
|
||||
type __##name##_impl__ arglist
|
||||
#else // __APPLE__
|
||||
#define LLVM_LIBC_FUNCTION_IMPL(type, name, arglist) \
|
||||
#define LLVM_LIBC_FUNCTION_IMPL_4(type, name, arglist, c_alias) \
|
||||
LLVM_LIBC_ATTR(name) \
|
||||
LLVM_LIBC_FUNCTION_ATTR decltype(LIBC_NAMESPACE::name) name asm("_" #name); \
|
||||
LLVM_LIBC_FUNCTION_ATTR decltype(LIBC_NAMESPACE::name) name asm( \
|
||||
"_" c_alias); \
|
||||
type name arglist
|
||||
#endif // __APPLE__
|
||||
|
||||
#else // LIBC_COPT_PUBLIC_PACKAGING
|
||||
#define LLVM_LIBC_FUNCTION_IMPL(type, name, arglist) type name arglist
|
||||
#define LLVM_LIBC_FUNCTION_IMPL_4(type, name, arglist, c_alias) \
|
||||
type name arglist
|
||||
#endif // LIBC_COPT_PUBLIC_PACKAGING
|
||||
|
||||
// This extra layer of macro allows `name` to be a macro to rename a function.
|
||||
#define LLVM_LIBC_FUNCTION(type, name, arglist) \
|
||||
LLVM_LIBC_FUNCTION_IMPL(type, name, arglist)
|
||||
#define LLVM_LIBC_FUNCTION_IMPL_3(type, name, arglist) \
|
||||
LLVM_LIBC_FUNCTION_IMPL_4(type, name, arglist, #name)
|
||||
|
||||
namespace LIBC_NAMESPACE_DECL {
|
||||
namespace internal {
|
||||
LIBC_INLINE constexpr bool same_string(char const *lhs, char const *rhs) {
|
||||
for (; *lhs || *rhs; ++lhs, ++rhs)
|
||||
if (*lhs != *rhs)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
} // namespace internal
|
||||
} // namespace LIBC_NAMESPACE_DECL
|
||||
// LLVM_LIBC_FUNCTION(type, name, arglist) is equivalent to
|
||||
// LLVM_LIBC_FUNCTION(type, name, arglist, #name)
|
||||
#define LLVM_LIBC_FUNCTION(...) \
|
||||
GET_FIFTH(__VA_ARGS__, LLVM_LIBC_FUNCTION_IMPL_4, LLVM_LIBC_FUNCTION_IMPL_3, \
|
||||
GET_NOTHING)(__VA_ARGS__)
|
||||
|
||||
#define __LIBC_MACRO_TO_STRING(str) #str
|
||||
#define LIBC_MACRO_TO_STRING(str) __LIBC_MACRO_TO_STRING(str)
|
||||
// At the moment, [[gnu::alias()]] is not supported on MacOS, and it is needed
|
||||
// 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) && !defined(LIBC_COMPILER_IS_MSVC)
|
||||
#ifndef __APPLE__
|
||||
#define LLVM_LIBC_VARIABLE_IMPL(type, name) \
|
||||
LLVM_LIBC_ATTR(name) \
|
||||
extern LLVM_LIBC_VARIABLE_ATTR decltype(LIBC_NAMESPACE::name) \
|
||||
__##name##_impl__ asm(#name); \
|
||||
extern decltype(LIBC_NAMESPACE::name) name [[gnu::alias(#name)]]; \
|
||||
type __##name##_impl__
|
||||
#else // __APPLE__
|
||||
#define LLVM_LIBC_VARIABLE_IMPL(type, name) \
|
||||
LLVM_LIBC_ATTR(name) \
|
||||
extern LLVM_LIBC_VARIABLE_ATTR decltype(LIBC_NAMESPACE::name) name asm( \
|
||||
"_" #name); \
|
||||
type name
|
||||
#endif // __APPLE__
|
||||
#else // LIBC_COPT_PUBLIC_PACKAGING
|
||||
#define LLVM_LIBC_VARIABLE_IMPL(type, name) type name
|
||||
#endif // LIBC_COPT_PUBLIC_PACKAGING
|
||||
|
||||
// LLVM_LIBC_IS_DEFINED checks whether a particular macro is defined.
|
||||
// Usage: constexpr bool kUseAvx = LLVM_LIBC_IS_DEFINED(__AVX__);
|
||||
//
|
||||
// This works by comparing the stringified version of the macro with and without
|
||||
// evaluation. If FOO is not undefined both stringifications yield "FOO". If FOO
|
||||
// is defined, one stringification yields "FOO" while the other yields its
|
||||
// stringified value "1".
|
||||
#define LLVM_LIBC_IS_DEFINED(macro) \
|
||||
!LIBC_NAMESPACE::internal::same_string( \
|
||||
LLVM_LIBC_IS_DEFINED__EVAL_AND_STRINGIZE(macro), #macro)
|
||||
#define LLVM_LIBC_IS_DEFINED__EVAL_AND_STRINGIZE(s) #s
|
||||
#define LLVM_LIBC_VARIABLE(type, name) LLVM_LIBC_VARIABLE_IMPL(type, name)
|
||||
|
||||
#endif // LLVM_LIBC_SRC___SUPPORT_COMMON_H
|
||||
+27
-15
@@ -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(char ch) {
|
||||
LIBC_INLINE constexpr bool islower(char ch) {
|
||||
switch (ch) {
|
||||
case 'a':
|
||||
case 'b':
|
||||
@@ -71,7 +71,7 @@ LIBC_INLINE static constexpr bool islower(char ch) {
|
||||
}
|
||||
}
|
||||
|
||||
LIBC_INLINE static constexpr bool isupper(char ch) {
|
||||
LIBC_INLINE constexpr bool isupper(char ch) {
|
||||
switch (ch) {
|
||||
case 'A':
|
||||
case 'B':
|
||||
@@ -105,7 +105,7 @@ LIBC_INLINE static constexpr bool isupper(char ch) {
|
||||
}
|
||||
}
|
||||
|
||||
LIBC_INLINE static constexpr bool isdigit(char ch) {
|
||||
LIBC_INLINE constexpr bool isdigit(char ch) {
|
||||
switch (ch) {
|
||||
case '0':
|
||||
case '1':
|
||||
@@ -123,7 +123,7 @@ LIBC_INLINE static constexpr bool isdigit(char ch) {
|
||||
}
|
||||
}
|
||||
|
||||
LIBC_INLINE static constexpr char tolower(char ch) {
|
||||
LIBC_INLINE constexpr char tolower(char ch) {
|
||||
switch (ch) {
|
||||
case 'A':
|
||||
return 'a';
|
||||
@@ -182,7 +182,7 @@ LIBC_INLINE static constexpr char tolower(char ch) {
|
||||
}
|
||||
}
|
||||
|
||||
LIBC_INLINE static constexpr char toupper(char ch) {
|
||||
LIBC_INLINE constexpr char toupper(char ch) {
|
||||
switch (ch) {
|
||||
case 'a':
|
||||
return 'A';
|
||||
@@ -241,7 +241,7 @@ LIBC_INLINE static constexpr char toupper(char ch) {
|
||||
}
|
||||
}
|
||||
|
||||
LIBC_INLINE static constexpr bool isalpha(char ch) {
|
||||
LIBC_INLINE constexpr bool isalpha(char ch) {
|
||||
switch (ch) {
|
||||
case 'a':
|
||||
case 'b':
|
||||
@@ -301,7 +301,7 @@ LIBC_INLINE static constexpr bool isalpha(char ch) {
|
||||
}
|
||||
}
|
||||
|
||||
LIBC_INLINE static constexpr bool isalnum(char ch) {
|
||||
LIBC_INLINE constexpr bool isalnum(char ch) {
|
||||
switch (ch) {
|
||||
case 'a':
|
||||
case 'b':
|
||||
@@ -371,7 +371,8 @@ LIBC_INLINE static constexpr bool isalnum(char ch) {
|
||||
}
|
||||
}
|
||||
|
||||
LIBC_INLINE static constexpr int b36_char_to_int(char ch) {
|
||||
#ifndef LIBC_COPT_CTYPE_SMALLER_ASCII
|
||||
LIBC_INLINE constexpr int b36_char_to_int(char ch) {
|
||||
switch (ch) {
|
||||
case '0':
|
||||
return 0;
|
||||
@@ -475,8 +476,21 @@ LIBC_INLINE static constexpr int b36_char_to_int(char ch) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
#else // LIBC_COPT_SMALL_ASCII_CTYPE
|
||||
// This version assumes ASCII for the tolower, but generates smaller code since
|
||||
// the switch version of this function ends up with a table. This should only be
|
||||
// used when the target is known to be ASCII.
|
||||
LIBC_INLINE constexpr int b36_char_to_int(char ch) {
|
||||
if (ch >= '0' && ch <= '9')
|
||||
return ch - '0';
|
||||
char ch_unsafe_lower = ch | 32;
|
||||
if (ch_unsafe_lower >= 'a' && ch_unsafe_lower <= 'z')
|
||||
return ch_unsafe_lower - 'a' + 10;
|
||||
return 0;
|
||||
}
|
||||
#endif // LIBC_COPT_SMALL_ASCII_CTYPE
|
||||
|
||||
LIBC_INLINE static constexpr char int_to_b36_char(int num) {
|
||||
LIBC_INLINE 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 +573,7 @@ LIBC_INLINE static constexpr char int_to_b36_char(int num) {
|
||||
}
|
||||
}
|
||||
|
||||
LIBC_INLINE static constexpr bool isspace(char ch) {
|
||||
LIBC_INLINE constexpr bool isspace(char ch) {
|
||||
switch (ch) {
|
||||
case ' ':
|
||||
case '\t':
|
||||
@@ -574,14 +588,12 @@ LIBC_INLINE static constexpr bool isspace(char ch) {
|
||||
}
|
||||
|
||||
// not yet encoding independent.
|
||||
LIBC_INLINE static constexpr bool isgraph(char ch) {
|
||||
return 0x20 < ch && ch < 0x7f;
|
||||
}
|
||||
LIBC_INLINE 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) {
|
||||
LIBC_INLINE constexpr bool is_char_or_wchar(char ch, char c_value,
|
||||
[[maybe_unused]] wchar_t) {
|
||||
return (ch == c_value);
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
//===-- High Precision Decimal ----------------------------------*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See httpss//llvm.org/LICENSE.txt for license information.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
+4
-11
@@ -25,8 +25,9 @@
|
||||
#include "src/__support/OSUtil/exit.h"
|
||||
#include "src/__support/OSUtil/io.h"
|
||||
#include "src/__support/integer_to_string.h"
|
||||
#include "src/__support/macros/attributes.h" // For LIBC_INLINE
|
||||
#include "src/__support/macros/attributes.h" // For LIBC_INLINE
|
||||
#include "src/__support/macros/config.h"
|
||||
#include "src/__support/macros/macro-utils.h"
|
||||
#include "src/__support/macros/optimization.h" // For LIBC_UNLIKELY
|
||||
|
||||
namespace LIBC_NAMESPACE_DECL {
|
||||
@@ -65,19 +66,11 @@ LIBC_INLINE void report_assertion_failure(const char *assertion,
|
||||
} while (false)
|
||||
#else
|
||||
|
||||
// Convert __LINE__ to a string using macros. The indirection is necessary
|
||||
// because otherwise it will turn "__LINE__" into a string, not its value. The
|
||||
// value is evaluated in the indirection step.
|
||||
#define __LIBC_MACRO_TO_STR(x) #x
|
||||
#define __LIBC_MACRO_TO_STR_INDIR(y) __LIBC_MACRO_TO_STR(y)
|
||||
#define __LIBC_LINE_STR__ __LIBC_MACRO_TO_STR_INDIR(__LINE__)
|
||||
|
||||
#define LIBC_ASSERT(COND) \
|
||||
do { \
|
||||
if (LIBC_UNLIKELY(!(COND))) { \
|
||||
LIBC_NAMESPACE::write_to_stderr(__FILE__ ":" __LIBC_LINE_STR__ \
|
||||
": Assertion failed: '" #COND \
|
||||
"' in function: '"); \
|
||||
LIBC_NAMESPACE::write_to_stderr(__FILE__ ":" LLVM_LIBC_STRINGIFY( \
|
||||
__LINE__) ": Assertion failed: '" #COND "' in function: '"); \
|
||||
LIBC_NAMESPACE::write_to_stderr(__PRETTY_FUNCTION__); \
|
||||
LIBC_NAMESPACE::write_to_stderr("'\n"); \
|
||||
LIBC_NAMESPACE::internal::exit(0xFF); \
|
||||
|
||||
@@ -29,6 +29,80 @@
|
||||
#define LIBC_INLINE_ASM __asm__ __volatile__
|
||||
#define LIBC_UNUSED __attribute__((unused))
|
||||
|
||||
#ifndef LIBC_HAS_BUILTIN_IS_CONSTANT_EVALUATED
|
||||
#if (defined(LIBC_COMPILER_IS_GCC) && (LIBC_COMPILER_GCC_VER >= 900)) || \
|
||||
(defined(LIBC_COMPILER_IS_CLANG) && LIBC_COMPILER_CLANG_VER >= 900)
|
||||
#define LIBC_HAS_BUILTIN_IS_CONSTANT_EVALUATED 1
|
||||
#else
|
||||
#define LIBC_HAS_BUILTIN_IS_CONSTANT_EVALUATED \
|
||||
(__has_builtin(__builtin_is_constant_evaluated))
|
||||
#endif // (defined(LIBC_COMPILER_IS_GCC) && (LIBC_COMPILER_GCC_VER >= 900)) ||
|
||||
// (defined(LIBC_COMPILER_IS_CLANG) && LIBC_COMPILER_CLANG
|
||||
#endif // LIBC_HAS_BUILTIN_IS_CONSTANT_EVALUATED
|
||||
|
||||
#ifndef LIBC_HAS_BUILTIN_BIT_CAST
|
||||
#if __has_builtin(__builtin_bit_cast) || defined(LIBC_COMPILER_IS_MSVC)
|
||||
#define LIBC_HAS_BUILTIN_BIT_CAST 1
|
||||
#else
|
||||
#define LIBC_HAS_BUILTIN_BIT_CAST 0
|
||||
#endif // has_builtin(__builtin_bit_cast)
|
||||
#endif // LIBC_HAS_BUILTIN_BIT_CAST
|
||||
|
||||
#if LIBC_HAS_BUILTIN_BIT_CAST
|
||||
#define LIBC_BIT_CAST_CONSTEXPR constexpr
|
||||
#define LIBC_BIT_CAST_CONSTEXPR_VAR constexpr
|
||||
#else
|
||||
#define LIBC_BIT_CAST_CONSTEXPR
|
||||
#define LIBC_BIT_CAST_CONSTEXPR_VAR const
|
||||
#endif // LIBC_HAS_BUILTIN_BIT_CAST
|
||||
|
||||
#ifndef LIBC_HAS_CONSTANT_EVALUATION
|
||||
#define LIBC_HAS_CONSTANT_EVALUATION \
|
||||
(LIBC_HAS_BUILTIN_IS_CONSTANT_EVALUATED && LIBC_HAS_BUILTIN_BIT_CAST)
|
||||
#endif // LIBC_HAS_CONSTANT_EVALUATION
|
||||
|
||||
#if LIBC_HAS_CONSTANT_EVALUATION
|
||||
#define LIBC_CONSTEXPR_DEFAULT constexpr
|
||||
#define LIBC_CONSTEXPR_VAR_DEFAULT constexpr
|
||||
#else
|
||||
#define LIBC_CONSTEXPR_DEFAULT
|
||||
#define LIBC_CONSTEXPR_VAR_DEFAULT const
|
||||
#endif // LIBC_HAS_CONSTANT_EVALUATION
|
||||
|
||||
// TODO: Remove the macro once Clang/LLVM bump their minimum compilers' version.
|
||||
// The reason for indirection is GCC is known to fail with constexpr qualified
|
||||
// functions that doesn't produce constant expression.
|
||||
// Also, there are some circular dependency in the generic functions without
|
||||
// __builtin_func for the following functions:
|
||||
// fputil::fma
|
||||
// fputil::sqrt
|
||||
#if LIBC_ENABLE_CONSTEXPR && LIBC_HAS_CONSTANT_EVALUATION
|
||||
#define LIBC_USE_CONSTEXPR
|
||||
#define LIBC_CONSTEXPR constexpr
|
||||
#define LIBC_CONSTEXPR_VAR constexpr
|
||||
#else
|
||||
#define LIBC_CONSTEXPR
|
||||
#define LIBC_CONSTEXPR_VAR const
|
||||
#endif // LIBC_USE_CONSTEXPR
|
||||
|
||||
#ifndef LIBC_HAS_BUILTIN_IS_ASSIGNABLE
|
||||
#if (__has_builtin(__is_assignable) || \
|
||||
(defined(LIBC_COMPILER_IS_GCC) && (LIBC_COMPILER_GCC_VER >= 800)))
|
||||
#define LIBC_HAS_BUILTIN_IS_ASSIGNABLE 1
|
||||
#else
|
||||
#define LIBC_HAS_BUILTIN_IS_ASSIGNABLE 0
|
||||
#endif
|
||||
#endif // LIBC_HAS_BUILTIN_IS_ASSIGNABLE
|
||||
|
||||
#ifndef LIBC_HAS_BUILTIN_IS_CONSTRUCTIBLE
|
||||
#if (__has_builtin(__is_constructible) || \
|
||||
(defined(LIBC_COMPILER_IS_GCC) && (LIBC_COMPILER_GCC_VER >= 800)))
|
||||
#define LIBC_HAS_BUILTIN_IS_CONSTRUCTIBLE 1
|
||||
#else
|
||||
#define LIBC_HAS_BUILTIN_IS_CONSTRUCTIBLE 0
|
||||
#endif
|
||||
#endif // LIBC_HAS_BUILTIN_IS_CONSTRUCTIBLE
|
||||
|
||||
// Uses the platform specific specialization
|
||||
#define LIBC_THREAD_MODE_PLATFORM 0
|
||||
|
||||
|
||||
+14
@@ -48,6 +48,10 @@
|
||||
|
||||
#define __builtin_prefetch(X, Y, Z)
|
||||
|
||||
#define LIBC_HAS_BUILTIN_IS_CONSTANT_EVALUATED 1
|
||||
#define LIBC_HAS_BUILTIN_IS_ASSIGNABLE 1
|
||||
#define LIBC_HAS_BUILTIN_IS_CONSTRUCTIBLE 1
|
||||
|
||||
#endif // LIBC_COMPILER_IS_MSVC
|
||||
|
||||
#ifdef __clang__
|
||||
@@ -66,4 +70,14 @@
|
||||
#define LIBC_NAMESPACE_DECL LIBC_NAMESPACE
|
||||
#endif
|
||||
|
||||
// IMPORTANT (USE WITH CAUTION): This macro is intended to be used at the top of
|
||||
// the file and set to 1. It alters the signatures of some functions to have
|
||||
// constexpr qualifier and forces the use of constexpr-compatible
|
||||
// implementation, which might be a completely different code path or
|
||||
// instructions. Some of these functions exploit platform-specific non-constexpr
|
||||
// implementations to achieve certain goals, thus it is disabled by default.
|
||||
#ifndef LIBC_ENABLE_CONSTEXPR
|
||||
#define LIBC_ENABLE_CONSTEXPR 0
|
||||
#endif
|
||||
|
||||
#endif // LLVM_LIBC_SRC___SUPPORT_MACROS_CONFIG_H
|
||||
@@ -0,0 +1,16 @@
|
||||
//===-- Macros used by other macros ----------------------------*- 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_MACROS_MACRO_UTILS_H
|
||||
#define LLVM_LIBC_SRC___SUPPORT_MACROS_MACRO_UTILS_H
|
||||
|
||||
// Stringify the argument after an extra pass of macro expansion.
|
||||
#define LLVM_LIBC_STRINGIFY(x) LLVM_LIBC_STRINGIFY_IMPL(x)
|
||||
#define LLVM_LIBC_STRINGIFY_IMPL(x) #x
|
||||
|
||||
#endif // LLVM_LIBC_SRC___SUPPORT_MACROS_MACRO_UTILS_H
|
||||
+18
-7
@@ -32,8 +32,13 @@ LIBC_INLINE constexpr bool expects_bool_condition(T value, T expected) {
|
||||
#define LIBC_LOOP_NOUNROLL _Pragma("nounroll")
|
||||
#define LIBC_LOOP_UNROLL _Pragma("unroll")
|
||||
#elif defined(LIBC_COMPILER_IS_GCC)
|
||||
#if LIBC_COMPILER_GCC_VER >= 800
|
||||
#define LIBC_LOOP_NOUNROLL _Pragma("GCC unroll 0")
|
||||
#define LIBC_LOOP_UNROLL _Pragma("GCC unroll 2048")
|
||||
#else
|
||||
#define LIBC_LOOP_NOUNROLL
|
||||
#define LIBC_LOOP_UNROLL
|
||||
#endif
|
||||
#elif defined(LIBC_COMPILER_IS_MSVC)
|
||||
#define LIBC_LOOP_NOUNROLL
|
||||
#define LIBC_LOOP_UNROLL
|
||||
@@ -47,33 +52,39 @@ LIBC_INLINE constexpr bool expects_bool_condition(T value, T expected) {
|
||||
#define LIBC_MATH_SMALL_TABLES 0x02
|
||||
#define LIBC_MATH_NO_ERRNO 0x04
|
||||
#define LIBC_MATH_NO_EXCEPT 0x08
|
||||
#define LIBC_MATH_INTERMEDIATE_COMP_IN_FLOAT 0x10
|
||||
#define LIBC_MATH_ASSUME_ROUND_NEAREST_ONLY 0x20
|
||||
#define LIBC_MATH_FAST \
|
||||
(LIBC_MATH_SKIP_ACCURATE_PASS | LIBC_MATH_SMALL_TABLES | \
|
||||
LIBC_MATH_NO_ERRNO | LIBC_MATH_NO_EXCEPT)
|
||||
#define LIBC_MATH_INTERMEDIATE_COMP_IN_FLOAT 0x10
|
||||
LIBC_MATH_NO_ERRNO | LIBC_MATH_NO_EXCEPT | \
|
||||
LIBC_MATH_ASSUME_ROUND_NEAREST_ONLY)
|
||||
|
||||
#ifndef LIBC_MATH
|
||||
#define LIBC_MATH 0
|
||||
#endif // LIBC_MATH
|
||||
|
||||
#if (LIBC_MATH & LIBC_MATH_SKIP_ACCURATE_PASS)
|
||||
#if ((LIBC_MATH) & LIBC_MATH_SKIP_ACCURATE_PASS)
|
||||
#define LIBC_MATH_HAS_SKIP_ACCURATE_PASS
|
||||
#endif
|
||||
|
||||
#if (LIBC_MATH & LIBC_MATH_SMALL_TABLES)
|
||||
#if ((LIBC_MATH) & LIBC_MATH_SMALL_TABLES)
|
||||
#define LIBC_MATH_HAS_SMALL_TABLES
|
||||
#endif
|
||||
|
||||
#if (LIBC_MATH & LIBC_MATH_INTERMEDIATE_COMP_IN_FLOAT)
|
||||
#if ((LIBC_MATH) & LIBC_MATH_INTERMEDIATE_COMP_IN_FLOAT)
|
||||
#define LIBC_MATH_HAS_INTERMEDIATE_COMP_IN_FLOAT
|
||||
#endif
|
||||
|
||||
#if (LIBC_MATH & LIBC_MATH_NO_ERRNO)
|
||||
#if ((LIBC_MATH) & LIBC_MATH_NO_ERRNO)
|
||||
#define LIBC_MATH_HAS_NO_ERRNO
|
||||
#endif
|
||||
|
||||
#if (LIBC_MATH & LIBC_MATH_NO_EXCEPT)
|
||||
#if ((LIBC_MATH) & LIBC_MATH_NO_EXCEPT)
|
||||
#define LIBC_MATH_HAS_NO_EXCEPT
|
||||
#endif
|
||||
|
||||
#if ((LIBC_MATH) & LIBC_MATH_ASSUME_ROUND_NEAREST_ONLY)
|
||||
#define LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY
|
||||
#endif
|
||||
|
||||
#endif // LLVM_LIBC_SRC___SUPPORT_MACROS_OPTIMIZATION_H
|
||||
@@ -13,11 +13,16 @@
|
||||
#define LIBC_TARGET_ARCH_IS_AMDGPU
|
||||
#endif
|
||||
|
||||
#if defined(__SPIRV__)
|
||||
#define LIBC_TARGET_ARCH_IS_SPIRV
|
||||
#endif
|
||||
|
||||
#if defined(__NVPTX__)
|
||||
#define LIBC_TARGET_ARCH_IS_NVPTX
|
||||
#endif
|
||||
|
||||
#if defined(LIBC_TARGET_ARCH_IS_NVPTX) || defined(LIBC_TARGET_ARCH_IS_AMDGPU)
|
||||
#if defined(LIBC_TARGET_ARCH_IS_NVPTX) || \
|
||||
defined(LIBC_TARGET_ARCH_IS_AMDGPU) || defined(LIBC_TARGET_ARCH_IS_SPIRV)
|
||||
#define LIBC_TARGET_ARCH_IS_GPU
|
||||
#endif
|
||||
|
||||
|
||||
@@ -56,6 +56,10 @@
|
||||
#define LIBC_TARGET_CPU_HAS_AVX512BW
|
||||
#endif
|
||||
|
||||
#if defined(__AVX512F__) || defined(__AVX2__)
|
||||
#define LIBC_TARGET_CPU_HAS_GATHER
|
||||
#endif
|
||||
|
||||
#if defined(__ARM_FP)
|
||||
#if (__ARM_FP & 0x2)
|
||||
#define LIBC_TARGET_CPU_HAS_ARM_FPU_HALF
|
||||
@@ -91,13 +95,14 @@
|
||||
#endif // LIBC_TARGET_CPU_HAS_RISCV_FPU_DOUBLE
|
||||
#endif // __riscv_flen
|
||||
|
||||
#if defined(__NVPTX__) || defined(__AMDGPU__)
|
||||
#if defined(__NVPTX__) || defined(__AMDGPU__) || defined(__SPIRV__)
|
||||
#define LIBC_TARGET_CPU_HAS_FPU_FLOAT
|
||||
#define LIBC_TARGET_CPU_HAS_FPU_DOUBLE
|
||||
#endif
|
||||
|
||||
#if defined(__ARM_FEATURE_FMA) || (defined(__AVX2__) && defined(__FMA__)) || \
|
||||
defined(__NVPTX__) || defined(__AMDGPU__) || defined(__riscv_flen)
|
||||
defined(__NVPTX__) || defined(__AMDGPU__) || defined(__riscv_flen) || \
|
||||
defined(__SPIRV__)
|
||||
#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)
|
||||
|
||||
+7
-6
@@ -26,24 +26,25 @@
|
||||
#ifdef LIBC_HAS_MEMORY_SANITIZER
|
||||
// Only perform MSAN unpoison in non-constexpr context.
|
||||
#include <sanitizer/msan_interface.h>
|
||||
#define MSAN_UNPOISON(addr, size) \
|
||||
#define LIBC_MSAN_UNPOISON(addr, size) \
|
||||
do { \
|
||||
if (!__builtin_is_constant_evaluated()) \
|
||||
__msan_unpoison(addr, size); \
|
||||
} while (0)
|
||||
#else
|
||||
#define MSAN_UNPOISON(ptr, size)
|
||||
#define LIBC_MSAN_UNPOISON(ptr, size)
|
||||
#endif
|
||||
|
||||
#ifdef LIBC_HAS_ADDRESS_SANITIZER
|
||||
#include <sanitizer/asan_interface.h>
|
||||
#define ASAN_POISON_MEMORY_REGION(addr, size) \
|
||||
#define LIBC_ASAN_POISON_MEMORY_REGION(addr, size) \
|
||||
__asan_poison_memory_region((addr), (size))
|
||||
#define ASAN_UNPOISON_MEMORY_REGION(addr, size) \
|
||||
#define LIBC_ASAN_UNPOISON_MEMORY_REGION(addr, size) \
|
||||
__asan_unpoison_memory_region((addr), (size))
|
||||
#else
|
||||
#define ASAN_POISON_MEMORY_REGION(addr, size) ((void)(addr), (void)(size))
|
||||
#define ASAN_UNPOISON_MEMORY_REGION(addr, size) ((void)(addr), (void)(size))
|
||||
#define LIBC_ASAN_POISON_MEMORY_REGION(addr, size) ((void)(addr), (void)(size))
|
||||
#define LIBC_ASAN_UNPOISON_MEMORY_REGION(addr, size) \
|
||||
((void)(addr), (void)(size))
|
||||
#endif
|
||||
|
||||
#endif // LLVM_LIBC_SRC___SUPPORT_MACROS_SANITIZER_H
|
||||
+15
@@ -80,6 +80,21 @@ template <typename T>
|
||||
#endif // __builtin_sub_overflow
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
[[nodiscard]] LIBC_INLINE constexpr bool mul_overflow(T a, T b, T &res) {
|
||||
#if __has_builtin(__builtin_mul_overflow)
|
||||
return __builtin_mul_overflow(a, b, &res);
|
||||
#else
|
||||
T max = cpp::numeric_limits<T>::max();
|
||||
T min = cpp::numeric_limits<T>::min();
|
||||
bool overflow = (b > 0 && (a > max / b || a < min / b)) ||
|
||||
(b < 0 && (a < max / b || a > min / b));
|
||||
if (!overflow)
|
||||
res = a * b;
|
||||
return overflow;
|
||||
#endif
|
||||
}
|
||||
|
||||
#define RETURN_IF(TYPE, BUILTIN) \
|
||||
if constexpr (cpp::is_same_v<T, TYPE>) \
|
||||
return BUILTIN(a, b, carry_in, &carry_out);
|
||||
|
||||
+14
-9
@@ -124,7 +124,7 @@ eisel_lemire(ExpandedFloat<T> init_num,
|
||||
// Wider Approximation
|
||||
UInt128 final_approx;
|
||||
// The halfway constant is used to check if the bits that will be shifted away
|
||||
// intially are all 1. For doubles this is 64 (bitstype size) - 52 (final
|
||||
// initially are all 1. For doubles this is 64 (bitstype size) - 52 (final
|
||||
// mantissa size) - 3 (we shift away the last two bits separately for
|
||||
// accuracy, and the most significant bit is ignored.) = 9 bits. Similarly,
|
||||
// it's 6 bits for floats in this case.
|
||||
@@ -262,7 +262,7 @@ eisel_lemire<long double>(ExpandedFloat<long double> init_num,
|
||||
(final_approx_lower < approx_lower ? 1 : 0);
|
||||
|
||||
// The halfway constant is used to check if the bits that will be shifted away
|
||||
// intially are all 1. For 80 bit floats this is 128 (bitstype size) - 64
|
||||
// initially are all 1. For 80 bit floats this is 128 (bitstype size) - 64
|
||||
// (final mantissa size) - 3 (we shift away the last two bits separately for
|
||||
// accuracy, and the most significant bit is ignored.) = 61 bits. Similarly,
|
||||
// it's 12 bits for 128 bit floats in this case.
|
||||
@@ -680,17 +680,15 @@ template <> LIBC_INLINE constexpr int32_t get_lower_bound<double>() {
|
||||
// accuracy.
|
||||
template <typename T, typename CharType>
|
||||
LIBC_INLINE FloatConvertReturn<T> decimal_exp_to_float(
|
||||
ExpandedFloat<T> init_num, bool truncated, RoundDirection round,
|
||||
const CharType *__restrict numStart,
|
||||
ExpandedFloat<T> init_num, [[maybe_unused]] bool truncated,
|
||||
RoundDirection round, 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;
|
||||
|
||||
StorageType mantissa = init_num.mantissa;
|
||||
int32_t exp10 = init_num.exponent;
|
||||
|
||||
FloatConvertReturn<T> output;
|
||||
cpp::optional<ExpandedFloat<T>> opt_output;
|
||||
[[maybe_unused]] cpp::optional<ExpandedFloat<T>> opt_output;
|
||||
|
||||
// If the exponent is too large and can't be represented in this size of
|
||||
// float, return inf. These bounds are relatively loose, but are mostly
|
||||
@@ -725,6 +723,8 @@ LIBC_INLINE FloatConvertReturn<T> decimal_exp_to_float(
|
||||
|
||||
#ifndef LIBC_COPT_STRTOFLOAT_DISABLE_EISEL_LEMIRE
|
||||
// Try Eisel-Lemire
|
||||
using StorageType = typename FPBits::StorageType;
|
||||
StorageType mantissa = init_num.mantissa;
|
||||
opt_output = eisel_lemire<T>(init_num, round);
|
||||
if (opt_output.has_value()) {
|
||||
if (!truncated) {
|
||||
@@ -1093,7 +1093,7 @@ hexadecimal_string_to_float(const CharType *__restrict src,
|
||||
}
|
||||
|
||||
template <typename T, typename CharType>
|
||||
LIBC_INLINE typename fputil::FPBits<T>::StorageType
|
||||
LIBC_INLINE constexpr typename fputil::FPBits<T>::StorageType
|
||||
nan_mantissa_from_ncharseq(const CharType *str, size_t len) {
|
||||
using FPBits = typename fputil::FPBits<T>;
|
||||
using StorageType = typename FPBits::StorageType;
|
||||
@@ -1129,7 +1129,9 @@ strtofloatingpoint(const CharType *__restrict src) {
|
||||
|
||||
size_t index = first_non_whitespace(src);
|
||||
int sign = get_sign(src + index);
|
||||
#ifndef LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY
|
||||
bool is_positive = (sign >= 0);
|
||||
#endif
|
||||
index += (sign != 0);
|
||||
|
||||
if (sign < 0) {
|
||||
@@ -1146,6 +1148,7 @@ strtofloatingpoint(const CharType *__restrict src) {
|
||||
}
|
||||
|
||||
RoundDirection round_direction = RoundDirection::Nearest;
|
||||
#ifndef LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY
|
||||
switch (fputil::quick_get_round()) {
|
||||
case FE_TONEAREST:
|
||||
round_direction = RoundDirection::Nearest;
|
||||
@@ -1160,6 +1163,7 @@ strtofloatingpoint(const CharType *__restrict src) {
|
||||
round_direction = RoundDirection::Down;
|
||||
break;
|
||||
}
|
||||
#endif // LIBC_MATH_HAS_ASSUME_ROUND_NEAREST_ONLY
|
||||
|
||||
StrToNumResult<ExpandedFloat<T>> parse_result({0, 0});
|
||||
if (base == 16) {
|
||||
@@ -1221,7 +1225,8 @@ strtofloatingpoint(const CharType *__restrict src) {
|
||||
return {result.get_val(), static_cast<ptrdiff_t>(index), error};
|
||||
}
|
||||
|
||||
template <class T> LIBC_INLINE StrToNumResult<T> strtonan(const char *arg) {
|
||||
template <class T>
|
||||
LIBC_INLINE constexpr StrToNumResult<T> strtonan(const char *arg) {
|
||||
using FPBits = typename fputil::FPBits<T>;
|
||||
using StorageType = typename FPBits::StorageType;
|
||||
|
||||
|
||||
+21
-2
@@ -33,7 +33,7 @@ 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
|
||||
LIBC_INLINE constexpr size_t
|
||||
first_non_whitespace(const CharType *__restrict src,
|
||||
size_t src_len = cpp::numeric_limits<size_t>::max()) {
|
||||
size_t src_cur = 0;
|
||||
@@ -65,6 +65,18 @@ LIBC_INLINE static bool is_hex_start(const CharType *__restrict src,
|
||||
b36_char_to_int(src[2]) < 16;
|
||||
}
|
||||
|
||||
// checks if the next 3 characters of the string pointer are the start of a
|
||||
// binary number. Does not advance the string pointer.
|
||||
template <typename CharType>
|
||||
LIBC_INLINE static bool is_binary_start(const CharType *__restrict src,
|
||||
size_t src_len) {
|
||||
if (src_len < 3)
|
||||
return false;
|
||||
return is_char_or_wchar(src[0], '0', L'0') &&
|
||||
is_char_or_wchar(tolower(src[1]), 'b', L'b') && isalnum(src[2]) &&
|
||||
b36_char_to_int(src[2]) < 2;
|
||||
}
|
||||
|
||||
// Takes the address of the string pointer and parses the base from the start of
|
||||
// it.
|
||||
template <typename CharType>
|
||||
@@ -75,6 +87,10 @@ LIBC_INLINE static int infer_base(const CharType *__restrict src,
|
||||
// with values 10 through 15 respectively." (C standard 6.4.4.1)
|
||||
if (is_hex_start(src, src_len))
|
||||
return 16;
|
||||
// A binary number is defined as "the prefix 0b or 0B optionally followed
|
||||
// by a sequence of letters and digits." (C standard 7.24.1.7)
|
||||
if (is_binary_start(src, src_len))
|
||||
return 2;
|
||||
// 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.
|
||||
@@ -94,7 +110,7 @@ LIBC_INLINE static int infer_base(const CharType *__restrict src,
|
||||
// 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 <typename T, typename CharType>
|
||||
LIBC_INLINE StrToNumResult<T>
|
||||
LIBC_INLINE constexpr StrToNumResult<T>
|
||||
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>;
|
||||
@@ -120,6 +136,9 @@ strtointeger(const CharType *__restrict src, int base,
|
||||
if (base == 16 && is_hex_start(src + src_cur, src_len - src_cur))
|
||||
src_cur = src_cur + 2;
|
||||
|
||||
if (base == 2 && is_binary_start(src + src_cur, src_len - src_cur))
|
||||
src_cur = src_cur + 2;
|
||||
|
||||
constexpr bool IS_UNSIGNED = cpp::is_unsigned_v<T>;
|
||||
ResultType constexpr NEGATIVE_MAX =
|
||||
!IS_UNSIGNED ? static_cast<ResultType>(cpp::numeric_limits<T>::max()) + 1
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
//===-- Utils for wctype classification 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
// DO NOT EDIT MANUALLY.
|
||||
// This file is generated by libc/utils/wctype_utils scripts.
|
||||
|
||||
#ifndef LLVM_LIBC_SRC___SUPPORT_WCTYPE_WCTYPE_CLASSIFICATION_UTILS_H
|
||||
#define LLVM_LIBC_SRC___SUPPORT_WCTYPE_WCTYPE_CLASSIFICATION_UTILS_H
|
||||
|
||||
#include "hdr/stdint_proxy.h"
|
||||
#include "hdr/types/wchar_t.h"
|
||||
#include "src/__support/CPP/limits.h"
|
||||
#include "src/__support/libc_assert.h"
|
||||
#include "src/__support/macros/attributes.h"
|
||||
#include "src/__support/macros/config.h"
|
||||
|
||||
namespace LIBC_NAMESPACE_DECL {
|
||||
|
||||
// Property flags for Unicode categories
|
||||
enum PropertyFlag : uint8_t {
|
||||
UPPER = 1 << 0,
|
||||
LOWER = 1 << 1,
|
||||
ALPHA = 1 << 2,
|
||||
SPACE = 1 << 3,
|
||||
PRINT = 1 << 4,
|
||||
BLANK = 1 << 5,
|
||||
CNTRL = 1 << 6,
|
||||
PUNCT = 1 << 7,
|
||||
};
|
||||
|
||||
static_assert(4352 <= cpp::numeric_limits<unsigned short>::max());
|
||||
static_assert(39168 <= cpp::numeric_limits<unsigned short>::max());
|
||||
|
||||
LIBC_INLINE_VAR constexpr uint16_t LEVEL1_SIZE = 4352;
|
||||
LIBC_INLINE_VAR constexpr uint16_t LEVEL2_SIZE = 39168;
|
||||
|
||||
// Level 1 table: indexed by (codepoint >> 8), stores level2 block offsets
|
||||
extern const uint16_t LEVEL1[LEVEL1_SIZE];
|
||||
|
||||
// Level 2 table: blocks of 256 property flags
|
||||
extern const uint8_t LEVEL2[LEVEL2_SIZE];
|
||||
|
||||
// Returns the Unicode property flag for a given wide character.
|
||||
LIBC_INLINE uint8_t lookup_properties(const wchar_t wc) {
|
||||
// Out of Unicode range
|
||||
if (static_cast<uint32_t>(wc) > 0x10FFFF) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint16_t l1_idx = static_cast<uint16_t>(wc >> 8);
|
||||
LIBC_ASSERT(l1_idx < LEVEL1_SIZE);
|
||||
|
||||
uint16_t l2_offset = LEVEL1[l1_idx];
|
||||
uint16_t l2_idx = l2_offset + (wc & 0xFF);
|
||||
LIBC_ASSERT(l2_idx < LEVEL2_SIZE);
|
||||
|
||||
return LEVEL2[l2_idx];
|
||||
}
|
||||
|
||||
} // namespace LIBC_NAMESPACE_DECL
|
||||
|
||||
#endif // LLVM_LIBC_SRC___SUPPORT_WCTYPE_WCTYPE_CLASSIFICATION_UTILS_H
|
||||
@@ -0,0 +1,34 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
///
|
||||
/// \file
|
||||
/// Interface for wctype conversion functions.
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_LIBC_SRC___SUPPORT_WCTYPE_WCTYPE_CONVERSION_UTILS_H
|
||||
#define LLVM_LIBC_SRC___SUPPORT_WCTYPE_WCTYPE_CONVERSION_UTILS_H
|
||||
|
||||
#include "hdr/types/wchar_t.h"
|
||||
#include "hdr/types/wint_t.h"
|
||||
#include "src/__support/macros/attributes.h"
|
||||
#include "src/__support/macros/config.h"
|
||||
|
||||
namespace LIBC_NAMESPACE_DECL {
|
||||
namespace wctype_internal {
|
||||
|
||||
// Helper functions for non-ASCII case conversions.
|
||||
// These are implemented in wctype_conversion_utils.cpp using the generated
|
||||
// maps.
|
||||
wint_t tolower(wchar_t wch);
|
||||
wint_t toupper(wchar_t wch);
|
||||
|
||||
} // namespace wctype_internal
|
||||
} // namespace LIBC_NAMESPACE_DECL
|
||||
|
||||
#endif // LLVM_LIBC_SRC___SUPPORT_WCTYPE_WCTYPE_CONVERSION_UTILS_H
|
||||
+359
-145
@@ -13,6 +13,18 @@
|
||||
#include "src/__support/macros/attributes.h" // LIBC_INLINE
|
||||
#include "src/__support/macros/config.h"
|
||||
|
||||
#define LIBC_WCTYPE_MODE_ASCII 0
|
||||
#define LIBC_WCTYPE_MODE_UTF8 1
|
||||
|
||||
#ifndef LIBC_CONF_WCTYPE_MODE
|
||||
#define LIBC_CONF_WCTYPE_MODE LIBC_WCTYPE_MODE_ASCII
|
||||
#endif
|
||||
|
||||
#if LIBC_CONF_WCTYPE_MODE == LIBC_WCTYPE_MODE_UTF8
|
||||
#include "src/__support/wctype/wctype_classification_utils.h"
|
||||
#include "src/__support/wctype/wctype_conversion_utils.h"
|
||||
#endif
|
||||
|
||||
namespace LIBC_NAMESPACE_DECL {
|
||||
namespace internal {
|
||||
|
||||
@@ -38,8 +50,8 @@ namespace internal {
|
||||
// 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) {
|
||||
namespace ascii {
|
||||
LIBC_INLINE constexpr bool islower(wchar_t wch) {
|
||||
switch (wch) {
|
||||
case L'a':
|
||||
case L'b':
|
||||
@@ -73,7 +85,7 @@ LIBC_INLINE static constexpr bool islower(wchar_t wch) {
|
||||
}
|
||||
}
|
||||
|
||||
LIBC_INLINE static constexpr bool isupper(wchar_t wch) {
|
||||
LIBC_INLINE constexpr bool isupper(wchar_t wch) {
|
||||
switch (wch) {
|
||||
case L'A':
|
||||
case L'B':
|
||||
@@ -107,7 +119,7 @@ LIBC_INLINE static constexpr bool isupper(wchar_t wch) {
|
||||
}
|
||||
}
|
||||
|
||||
LIBC_INLINE static constexpr bool isdigit(wchar_t wch) {
|
||||
LIBC_INLINE constexpr bool isdigit(wchar_t wch) {
|
||||
switch (wch) {
|
||||
case L'0':
|
||||
case L'1':
|
||||
@@ -125,7 +137,207 @@ LIBC_INLINE static constexpr bool isdigit(wchar_t wch) {
|
||||
}
|
||||
}
|
||||
|
||||
LIBC_INLINE static constexpr wchar_t tolower(wchar_t wch) {
|
||||
LIBC_INLINE 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 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 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;
|
||||
}
|
||||
}
|
||||
|
||||
LIBC_INLINE constexpr bool isblank(wchar_t wch) {
|
||||
switch (wch) {
|
||||
case L' ':
|
||||
case L'\t':
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
LIBC_INLINE constexpr bool isgraph(wchar_t wch) {
|
||||
return 0x20 < wch && wch < 0x7f;
|
||||
}
|
||||
|
||||
LIBC_INLINE constexpr bool isprint(wchar_t wch) {
|
||||
return (static_cast<unsigned>(wch) - ' ') < 95;
|
||||
}
|
||||
|
||||
LIBC_INLINE constexpr bool isxdigit(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'A':
|
||||
case L'B':
|
||||
case L'C':
|
||||
case L'D':
|
||||
case L'E':
|
||||
case L'F':
|
||||
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 constexpr bool iscntrl(wchar_t wch) {
|
||||
return (wch < 0x20 || wch == 0x7f);
|
||||
}
|
||||
|
||||
LIBC_INLINE constexpr bool ispunct(wchar_t wch) {
|
||||
return !isalnum(wch) && isgraph(wch);
|
||||
}
|
||||
|
||||
LIBC_INLINE constexpr wchar_t tolower(wchar_t wch) {
|
||||
switch (wch) {
|
||||
case L'A':
|
||||
return L'a';
|
||||
@@ -184,7 +396,7 @@ LIBC_INLINE static constexpr wchar_t tolower(wchar_t wch) {
|
||||
}
|
||||
}
|
||||
|
||||
LIBC_INLINE static constexpr wchar_t toupper(wchar_t wch) {
|
||||
LIBC_INLINE constexpr wchar_t toupper(wchar_t wch) {
|
||||
switch (wch) {
|
||||
case L'a':
|
||||
return L'A';
|
||||
@@ -243,137 +455,153 @@ LIBC_INLINE static constexpr wchar_t toupper(wchar_t 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;
|
||||
} // namespace ascii
|
||||
|
||||
LIBC_INLINE constexpr bool islower(wchar_t wch) {
|
||||
#if LIBC_CONF_WCTYPE_MODE != LIBC_WCTYPE_MODE_UTF8
|
||||
return ascii::islower(wch);
|
||||
#else
|
||||
if (static_cast<uint32_t>(wch) < 128) {
|
||||
return ascii::islower(wch);
|
||||
}
|
||||
return lookup_properties(wch) & PropertyFlag::LOWER;
|
||||
#endif
|
||||
}
|
||||
|
||||
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 constexpr bool isupper(wchar_t wch) {
|
||||
#if LIBC_CONF_WCTYPE_MODE != LIBC_WCTYPE_MODE_UTF8
|
||||
return ascii::isupper(wch);
|
||||
#else
|
||||
if (static_cast<uint32_t>(wch) < 128) {
|
||||
return ascii::isupper(wch);
|
||||
}
|
||||
return lookup_properties(wch) & PropertyFlag::UPPER;
|
||||
#endif
|
||||
}
|
||||
|
||||
LIBC_INLINE static constexpr int b36_char_to_int(wchar_t wch) {
|
||||
LIBC_INLINE constexpr bool isdigit(wchar_t wch) {
|
||||
// In C.UT8, only ASCII digits are considered digits
|
||||
return ascii::isdigit(wch);
|
||||
}
|
||||
|
||||
LIBC_INLINE constexpr bool isalpha(wchar_t wch) {
|
||||
#if LIBC_CONF_WCTYPE_MODE != LIBC_WCTYPE_MODE_UTF8
|
||||
return ascii::isalpha(wch);
|
||||
#else
|
||||
if (static_cast<uint32_t>(wch) < 128) {
|
||||
return ascii::isalpha(wch);
|
||||
}
|
||||
return lookup_properties(wch) & PropertyFlag::ALPHA;
|
||||
#endif
|
||||
}
|
||||
|
||||
LIBC_INLINE constexpr bool isalnum(wchar_t wch) {
|
||||
#if LIBC_CONF_WCTYPE_MODE != LIBC_WCTYPE_MODE_UTF8
|
||||
return ascii::isalnum(wch);
|
||||
#else
|
||||
if (static_cast<uint32_t>(wch) < 128) {
|
||||
return ascii::isalnum(wch);
|
||||
}
|
||||
// Only need to check ALPHA, digit cases are covered by ASCII path
|
||||
return lookup_properties(wch) & PropertyFlag::ALPHA;
|
||||
#endif
|
||||
}
|
||||
|
||||
LIBC_INLINE constexpr bool isspace(wchar_t wch) {
|
||||
#if LIBC_CONF_WCTYPE_MODE != LIBC_WCTYPE_MODE_UTF8
|
||||
return ascii::isspace(wch);
|
||||
#else
|
||||
if (static_cast<uint32_t>(wch) < 128) {
|
||||
return ascii::isspace(wch);
|
||||
}
|
||||
return lookup_properties(wch) & PropertyFlag::SPACE;
|
||||
#endif
|
||||
}
|
||||
|
||||
LIBC_INLINE constexpr bool isblank(wchar_t wch) {
|
||||
#if LIBC_CONF_WCTYPE_MODE != LIBC_WCTYPE_MODE_UTF8
|
||||
return ascii::isblank(wch);
|
||||
#else
|
||||
if (static_cast<uint32_t>(wch) < 128) {
|
||||
return ascii::isblank(wch);
|
||||
}
|
||||
return lookup_properties(wch) & PropertyFlag::BLANK;
|
||||
#endif
|
||||
}
|
||||
|
||||
LIBC_INLINE constexpr bool isgraph(wchar_t wch) {
|
||||
#if LIBC_CONF_WCTYPE_MODE != LIBC_WCTYPE_MODE_UTF8
|
||||
return ascii::isgraph(wch);
|
||||
#else
|
||||
if (static_cast<uint32_t>(wch) < 128) {
|
||||
return ascii::isgraph(wch);
|
||||
}
|
||||
// print && !space
|
||||
return (lookup_properties(wch) &
|
||||
(PropertyFlag::PRINT | PropertyFlag::SPACE)) == PropertyFlag::PRINT;
|
||||
#endif
|
||||
}
|
||||
|
||||
LIBC_INLINE constexpr bool isprint(wchar_t wch) {
|
||||
#if LIBC_CONF_WCTYPE_MODE != LIBC_WCTYPE_MODE_UTF8
|
||||
return ascii::isprint(wch);
|
||||
#else
|
||||
if (static_cast<uint32_t>(wch) < 128) {
|
||||
return ascii::isprint(wch);
|
||||
}
|
||||
return lookup_properties(wch) & PropertyFlag::PRINT;
|
||||
#endif
|
||||
}
|
||||
LIBC_INLINE constexpr bool isxdigit(wchar_t wch) {
|
||||
// Hexadecimal digits are the same in C.UTF8 as in ASCII
|
||||
return ascii::isxdigit(wch);
|
||||
}
|
||||
|
||||
LIBC_INLINE constexpr bool iscntrl(wchar_t wch) {
|
||||
#if LIBC_CONF_WCTYPE_MODE != LIBC_WCTYPE_MODE_UTF8
|
||||
return ascii::iscntrl(wch);
|
||||
#else
|
||||
if (static_cast<uint32_t>(wch) < 128) {
|
||||
return ascii::iscntrl(wch);
|
||||
}
|
||||
return lookup_properties(wch) & PropertyFlag::CNTRL;
|
||||
#endif
|
||||
}
|
||||
|
||||
LIBC_INLINE constexpr bool ispunct(wchar_t wch) {
|
||||
#if LIBC_CONF_WCTYPE_MODE != LIBC_WCTYPE_MODE_UTF8
|
||||
return ascii::ispunct(wch);
|
||||
#else
|
||||
if (static_cast<uint32_t>(wch) < 128) {
|
||||
return ascii::ispunct(wch);
|
||||
}
|
||||
return lookup_properties(wch) & PropertyFlag::PUNCT;
|
||||
#endif
|
||||
}
|
||||
|
||||
LIBC_INLINE constexpr wchar_t tolower(wchar_t wch) {
|
||||
#if LIBC_CONF_WCTYPE_MODE != LIBC_WCTYPE_MODE_UTF8
|
||||
return ascii::tolower(wch);
|
||||
#else
|
||||
if (static_cast<uint32_t>(wch) < 128) {
|
||||
return ascii::tolower(wch);
|
||||
}
|
||||
return static_cast<wchar_t>(wctype_internal::tolower(wch));
|
||||
#endif
|
||||
}
|
||||
|
||||
LIBC_INLINE constexpr wchar_t toupper(wchar_t wch) {
|
||||
#if LIBC_CONF_WCTYPE_MODE != LIBC_WCTYPE_MODE_UTF8
|
||||
return ascii::toupper(wch);
|
||||
#else
|
||||
if (static_cast<uint32_t>(wch) < 128) {
|
||||
return ascii::toupper(wch);
|
||||
}
|
||||
return static_cast<wchar_t>(wctype_internal::toupper(wch));
|
||||
#endif
|
||||
}
|
||||
|
||||
LIBC_INLINE constexpr int b36_char_to_int(wchar_t wch) {
|
||||
switch (wch) {
|
||||
case L'0':
|
||||
return 0;
|
||||
@@ -561,20 +789,6 @@ LIBC_INLINE static constexpr wchar_t int_to_b36_wchar(int num) {
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
Reference in new issue
Block a user