llvm-libc: update to LLVM 23

This commit is contained in:
Alex Rønne Petersen committed 2026-10-07 00:30:51 +02:00
1 parent 3cc56f98b4
commit f689d3cf27
45 files changed
+1214 -466

No files matched your search

+1 -1
View File
@@ -25,6 +25,6 @@
#include <errno.h>
#endif // LLVM_LIBC_FULL_BUILD
#endif // LIBC_FULL_BUILD
#endif // LLVM_LIBC_HDR_ERRNO_MACROS_H
+1 -1
View File
@@ -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
+1 -1
View File
@@ -17,6 +17,6 @@
#include <float.h>
#endif // LLVM_LIBC_FULL_BUILD
#endif // LIBC_FULL_BUILD
#endif // LLVM_LIBC_HDR_FLOAT_MACROS_H
+1 -1
View File
@@ -17,6 +17,6 @@
#include <limits.h>
#endif // LLVM_LIBC_FULL_BUILD
#endif // LIBC_FULL_BUILD
#endif // LLVM_LIBC_HDR_LIMITS_MACROS_H
+23
View File
@@ -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
+1 -1
View File
@@ -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
+23
View File
@@ -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
+2 -1
View File
@@ -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
+1 -1
View File
@@ -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__
+14
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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 &dividend,
const BigInt &divider) {
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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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); \
+74
View File
@@ -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
View File
@@ -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
+16
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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