diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2025-04-05 01:46:13 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-04-05 01:46:13 -0400 |
| commit | 0cd31fc7ff157551cfbba5da35cd79f118d2a2e3 (patch) | |
| tree | a308488f5d85184c8ec402fb3f55f1cf2704443e /lib/libcxx/libc/src | |
| parent | 8acedfd5baabab705946ad097746f9183ef62420 (diff) | |
| parent | cefe65c1b8abe65a22d4b68410db1be264fdeda0 (diff) | |
| download | zig-0cd31fc7ff157551cfbba5da35cd79f118d2a2e3.tar.gz zig-0cd31fc7ff157551cfbba5da35cd79f118d2a2e3.zip | |
Merge pull request #22780 from ziglang/llvm20
LLVM 20
Diffstat (limited to 'lib/libcxx/libc/src')
98 files changed, 9709 insertions, 0 deletions
diff --git a/lib/libcxx/libc/src/__support/CPP/array.h b/lib/libcxx/libc/src/__support/CPP/array.h new file mode 100644 index 0000000000..db0a986b71 --- /dev/null +++ b/lib/libcxx/libc/src/__support/CPP/array.h @@ -0,0 +1,80 @@ +//===-- A self contained equivalent of std::array ---------------*- 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_CPP_ARRAY_H +#define LLVM_LIBC_SRC___SUPPORT_CPP_ARRAY_H + +#include "src/__support/CPP/iterator.h" // reverse_iterator +#include "src/__support/macros/attributes.h" +#include "src/__support/macros/config.h" +#include <stddef.h> // For size_t. + +namespace LIBC_NAMESPACE_DECL { +namespace cpp { + +template <class T, size_t N> struct array { + static_assert(N != 0, + "Cannot create a LIBC_NAMESPACE::cpp::array of size 0."); + + T Data[N]; + using value_type = T; + using iterator = T *; + using const_iterator = const T *; + using reverse_iterator = cpp::reverse_iterator<iterator>; + using const_reverse_iterator = cpp::reverse_iterator<const_iterator>; + + LIBC_INLINE constexpr T *data() { return Data; } + LIBC_INLINE constexpr const T *data() const { return Data; } + + LIBC_INLINE constexpr T &front() { return Data[0]; } + LIBC_INLINE constexpr const T &front() const { return Data[0]; } + + LIBC_INLINE constexpr T &back() { return Data[N - 1]; } + LIBC_INLINE constexpr const T &back() const { return Data[N - 1]; } + + LIBC_INLINE constexpr T &operator[](size_t Index) { return Data[Index]; } + + LIBC_INLINE constexpr const T &operator[](size_t Index) const { + return Data[Index]; + } + + LIBC_INLINE constexpr size_t size() const { return N; } + + LIBC_INLINE constexpr bool empty() const { return N == 0; } + + LIBC_INLINE constexpr iterator begin() { return Data; } + LIBC_INLINE constexpr const_iterator begin() const { return Data; } + LIBC_INLINE constexpr const_iterator cbegin() const { return begin(); } + + LIBC_INLINE constexpr iterator end() { return Data + N; } + LIBC_INLINE constexpr const_iterator end() const { return Data + N; } + LIBC_INLINE constexpr const_iterator cend() const { return end(); } + + LIBC_INLINE constexpr reverse_iterator rbegin() { + return reverse_iterator{end()}; + } + LIBC_INLINE constexpr const_reverse_iterator rbegin() const { + return const_reverse_iterator{end()}; + } + LIBC_INLINE constexpr const_reverse_iterator crbegin() const { + return rbegin(); + } + + LIBC_INLINE constexpr reverse_iterator rend() { + return reverse_iterator{begin()}; + } + LIBC_INLINE constexpr const_reverse_iterator rend() const { + return const_reverse_iterator{begin()}; + } + LIBC_INLINE constexpr const_reverse_iterator crend() const { return rend(); } +}; + +} // namespace cpp +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_CPP_ARRAY_H diff --git a/lib/libcxx/libc/src/__support/CPP/bit.h b/lib/libcxx/libc/src/__support/CPP/bit.h new file mode 100644 index 0000000000..adcd047274 --- /dev/null +++ b/lib/libcxx/libc/src/__support/CPP/bit.h @@ -0,0 +1,298 @@ +//===-- Implementation of the C++20 bit header -----------------*- 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 +// +//===----------------------------------------------------------------------===// +// This is inspired by LLVM ADT/bit.h header. +// Some functions are missing, we can add them as needed (popcount, byteswap). + +#ifndef LLVM_LIBC_SRC___SUPPORT_CPP_BIT_H +#define LLVM_LIBC_SRC___SUPPORT_CPP_BIT_H + +#include "src/__support/CPP/limits.h" // numeric_limits +#include "src/__support/CPP/type_traits.h" +#include "src/__support/macros/attributes.h" +#include "src/__support/macros/config.h" +#include "src/__support/macros/sanitizer.h" + +#include <stdint.h> + +namespace LIBC_NAMESPACE_DECL { +namespace cpp { + +#if __has_builtin(__builtin_memcpy_inline) +#define LLVM_LIBC_HAS_BUILTIN_MEMCPY_INLINE +#endif + +// 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< + (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) + return __builtin_bit_cast(To, from); +#else + To to; + char *dst = reinterpret_cast<char *>(&to); + const char *src = reinterpret_cast<const char *>(&from); +#if __has_builtin(__builtin_memcpy_inline) + __builtin_memcpy_inline(dst, src, sizeof(To)); +#else + for (unsigned i = 0; i < sizeof(To); ++i) + dst[i] = src[i]; +#endif // __has_builtin(__builtin_memcpy_inline) + return to; +#endif // __has_builtin(__builtin_bit_cast) +} + +template <typename T> +[[nodiscard]] LIBC_INLINE constexpr cpp::enable_if_t<cpp::is_unsigned_v<T>, + bool> +has_single_bit(T value) { + return (value != 0) && ((value & (value - 1)) == 0); +} + +// A temporary macro to add template function specialization when compiler +// builtin is available. +#define ADD_SPECIALIZATION(NAME, TYPE, BUILTIN) \ + template <> [[nodiscard]] LIBC_INLINE constexpr int NAME<TYPE>(TYPE value) { \ + static_assert(cpp::is_unsigned_v<TYPE>); \ + return value == 0 ? cpp::numeric_limits<TYPE>::digits : BUILTIN(value); \ + } + +/// Count number of 0's from the least significant bit to the most +/// stopping at the first 1. +/// +/// Only unsigned integral types are allowed. +/// +/// Returns cpp::numeric_limits<T>::digits on an input of 0. +// clang-19+, gcc-14+ +#if __has_builtin(__builtin_ctzg) +template <typename T> +[[nodiscard]] LIBC_INLINE constexpr cpp::enable_if_t<cpp::is_unsigned_v<T>, int> +countr_zero(T value) { + return __builtin_ctzg(value, cpp::numeric_limits<T>::digits); +} +#else +template <typename T> +[[nodiscard]] LIBC_INLINE constexpr cpp::enable_if_t<cpp::is_unsigned_v<T>, int> +countr_zero(T value) { + if (!value) + return cpp::numeric_limits<T>::digits; + if (value & 0x1) + return 0; + // Bisection method. + unsigned zero_bits = 0; + unsigned shift = cpp::numeric_limits<T>::digits >> 1; + T mask = cpp::numeric_limits<T>::max() >> shift; + while (shift) { + if ((value & mask) == 0) { + value >>= shift; + zero_bits |= shift; + } + shift >>= 1; + mask >>= shift; + } + return zero_bits; +} +#if __has_builtin(__builtin_ctzs) +ADD_SPECIALIZATION(countr_zero, unsigned short, __builtin_ctzs) +#endif +ADD_SPECIALIZATION(countr_zero, unsigned int, __builtin_ctz) +ADD_SPECIALIZATION(countr_zero, unsigned long, __builtin_ctzl) +ADD_SPECIALIZATION(countr_zero, unsigned long long, __builtin_ctzll) +#endif // __has_builtin(__builtin_ctzg) + +/// Count number of 0's from the most significant bit to the least +/// stopping at the first 1. +/// +/// Only unsigned integral types are allowed. +/// +/// Returns cpp::numeric_limits<T>::digits on an input of 0. +// clang-19+, gcc-14+ +#if __has_builtin(__builtin_clzg) +template <typename T> +[[nodiscard]] LIBC_INLINE constexpr cpp::enable_if_t<cpp::is_unsigned_v<T>, int> +countl_zero(T value) { + return __builtin_clzg(value, cpp::numeric_limits<T>::digits); +} +#else +template <typename T> +[[nodiscard]] LIBC_INLINE constexpr cpp::enable_if_t<cpp::is_unsigned_v<T>, int> +countl_zero(T value) { + if (!value) + return cpp::numeric_limits<T>::digits; + // Bisection method. + unsigned zero_bits = 0; + for (unsigned shift = cpp::numeric_limits<T>::digits >> 1; shift; + shift >>= 1) { + T tmp = value >> shift; + if (tmp) + value = tmp; + else + zero_bits |= shift; + } + return zero_bits; +} +#if __has_builtin(__builtin_clzs) +ADD_SPECIALIZATION(countl_zero, unsigned short, __builtin_clzs) +#endif +ADD_SPECIALIZATION(countl_zero, unsigned int, __builtin_clz) +ADD_SPECIALIZATION(countl_zero, unsigned long, __builtin_clzl) +ADD_SPECIALIZATION(countl_zero, unsigned long long, __builtin_clzll) +#endif // __has_builtin(__builtin_clzg) + +#undef ADD_SPECIALIZATION + +/// Count the number of ones from the most significant bit to the first +/// zero bit. +/// +/// Ex. countl_one(0xFF0FFF00) == 8. +/// Only unsigned integral types are allowed. +/// +/// Returns cpp::numeric_limits<T>::digits on an input of all ones. +template <typename T> +[[nodiscard]] LIBC_INLINE constexpr cpp::enable_if_t<cpp::is_unsigned_v<T>, int> +countl_one(T value) { + return cpp::countl_zero<T>(~value); +} + +/// Count the number of ones from the least significant bit to the first +/// zero bit. +/// +/// Ex. countr_one(0x00FF00FF) == 8. +/// Only unsigned integral types are allowed. +/// +/// Returns cpp::numeric_limits<T>::digits on an input of all ones. +template <typename T> +[[nodiscard]] LIBC_INLINE constexpr cpp::enable_if_t<cpp::is_unsigned_v<T>, int> +countr_one(T value) { + return cpp::countr_zero<T>(~value); +} + +/// Returns the number of bits needed to represent value if value is nonzero. +/// Returns 0 otherwise. +/// +/// Ex. bit_width(5) == 3. +template <typename T> +[[nodiscard]] LIBC_INLINE constexpr cpp::enable_if_t<cpp::is_unsigned_v<T>, int> +bit_width(T value) { + return cpp::numeric_limits<T>::digits - cpp::countl_zero(value); +} + +/// Returns the largest integral power of two no greater than value if value is +/// nonzero. Returns 0 otherwise. +/// +/// Ex. bit_floor(5) == 4. +template <typename T> +[[nodiscard]] LIBC_INLINE constexpr cpp::enable_if_t<cpp::is_unsigned_v<T>, T> +bit_floor(T value) { + if (!value) + return 0; + return static_cast<T>(T(1) << (cpp::bit_width(value) - 1)); +} + +/// Returns the smallest integral power of two no smaller than value if value is +/// nonzero. Returns 1 otherwise. +/// +/// Ex. bit_ceil(5) == 8. +/// +/// The return value is undefined if the input is larger than the largest power +/// of two representable in T. +template <typename T> +[[nodiscard]] LIBC_INLINE constexpr cpp::enable_if_t<cpp::is_unsigned_v<T>, T> +bit_ceil(T value) { + if (value < 2) + return 1; + return static_cast<T>(T(1) << cpp::bit_width(value - 1U)); +} + +// Rotate algorithms make use of "Safe, Efficient, and Portable Rotate in C/C++" +// from https://blog.regehr.org/archives/1063. + +// Forward-declare rotr so that rotl can use it. +template <typename T> +[[nodiscard]] LIBC_INLINE constexpr cpp::enable_if_t<cpp::is_unsigned_v<T>, T> +rotr(T value, int rotate); + +template <typename T> +[[nodiscard]] LIBC_INLINE constexpr cpp::enable_if_t<cpp::is_unsigned_v<T>, T> +rotl(T value, int rotate) { + constexpr unsigned N = cpp::numeric_limits<T>::digits; + rotate = rotate % N; + if (!rotate) + return value; + if (rotate < 0) + return cpp::rotr<T>(value, -rotate); + return (value << rotate) | (value >> (N - rotate)); +} + +template <typename T> +[[nodiscard]] LIBC_INLINE constexpr cpp::enable_if_t<cpp::is_unsigned_v<T>, T> +rotr(T value, int rotate) { + constexpr unsigned N = cpp::numeric_limits<T>::digits; + rotate = rotate % N; + if (!rotate) + return value; + if (rotate < 0) + return cpp::rotl<T>(value, -rotate); + return (value >> rotate) | (value << (N - rotate)); +} + +// TODO: Do we need this function at all? How is it different from +// 'static_cast'? +template <class To, class From> +LIBC_INLINE constexpr To bit_or_static_cast(const From &from) { + if constexpr (sizeof(To) == sizeof(From)) { + return bit_cast<To>(from); + } else { + return static_cast<To>(from); + } +} + +/// Count number of 1's aka population count or Hamming weight. +/// +/// Only unsigned integral types are allowed. +// clang-19+, gcc-14+ +#if __has_builtin(__builtin_popcountg) +template <typename T> +[[nodiscard]] LIBC_INLINE constexpr cpp::enable_if_t<cpp::is_unsigned_v<T>, int> +popcount(T value) { + return __builtin_popcountg(value); +} +#else // !__has_builtin(__builtin_popcountg) +template <typename T> +[[nodiscard]] LIBC_INLINE constexpr cpp::enable_if_t<cpp::is_unsigned_v<T>, int> +popcount(T value) { + int count = 0; + while (value) { + value &= value - 1; + ++count; + } + return count; +} +#define ADD_SPECIALIZATION(TYPE, BUILTIN) \ + template <> \ + [[nodiscard]] LIBC_INLINE constexpr int popcount<TYPE>(TYPE value) { \ + return BUILTIN(value); \ + } +ADD_SPECIALIZATION(unsigned char, __builtin_popcount) +ADD_SPECIALIZATION(unsigned short, __builtin_popcount) +ADD_SPECIALIZATION(unsigned, __builtin_popcount) +ADD_SPECIALIZATION(unsigned long, __builtin_popcountl) +ADD_SPECIALIZATION(unsigned long long, __builtin_popcountll) +#endif // __builtin_popcountg +#undef ADD_SPECIALIZATION + +} // namespace cpp +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_CPP_BIT_H diff --git a/lib/libcxx/libc/src/__support/CPP/iterator.h b/lib/libcxx/libc/src/__support/CPP/iterator.h new file mode 100644 index 0000000000..168a269731 --- /dev/null +++ b/lib/libcxx/libc/src/__support/CPP/iterator.h @@ -0,0 +1,99 @@ +//===-- Standalone implementation of iterator -------------------*- 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_CPP_ITERATOR_H +#define LLVM_LIBC_SRC___SUPPORT_CPP_ITERATOR_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" +#include "src/__support/macros/attributes.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { +namespace cpp { + +template <typename T> struct iterator_traits; +template <typename T> struct iterator_traits<T *> { + using reference = T &; + using value_type = T; +}; + +template <typename Iter> class reverse_iterator { + Iter current; + +public: + using reference = typename iterator_traits<Iter>::reference; + using value_type = typename iterator_traits<Iter>::value_type; + using iterator_type = Iter; + + LIBC_INLINE reverse_iterator() : current() {} + LIBC_INLINE constexpr explicit reverse_iterator(Iter it) : current(it) {} + + template <typename Other, + cpp::enable_if_t<!cpp::is_same_v<Iter, Other> && + cpp::is_convertible_v<const Other &, Iter>, + int> = 0> + LIBC_INLINE constexpr explicit reverse_iterator(const Other &it) + : current(it) {} + + LIBC_INLINE friend constexpr bool operator==(const reverse_iterator &lhs, + const reverse_iterator &rhs) { + return lhs.base() == rhs.base(); + } + + LIBC_INLINE friend constexpr bool operator!=(const reverse_iterator &lhs, + const reverse_iterator &rhs) { + return lhs.base() != rhs.base(); + } + + LIBC_INLINE friend constexpr bool operator<(const reverse_iterator &lhs, + const reverse_iterator &rhs) { + return lhs.base() > rhs.base(); + } + + LIBC_INLINE friend constexpr bool operator<=(const reverse_iterator &lhs, + const reverse_iterator &rhs) { + return lhs.base() >= rhs.base(); + } + + LIBC_INLINE friend constexpr bool operator>(const reverse_iterator &lhs, + const reverse_iterator &rhs) { + return lhs.base() < rhs.base(); + } + + LIBC_INLINE friend constexpr bool operator>=(const reverse_iterator &lhs, + const reverse_iterator &rhs) { + return lhs.base() <= rhs.base(); + } + + LIBC_INLINE constexpr iterator_type base() const { return current; } + + LIBC_INLINE constexpr reference operator*() const { + Iter tmp = current; + return *--tmp; + } + LIBC_INLINE constexpr reverse_iterator operator--() { + ++current; + return *this; + } + LIBC_INLINE constexpr reverse_iterator &operator++() { + --current; + return *this; + } + LIBC_INLINE constexpr reverse_iterator operator++(int) { + reverse_iterator tmp(*this); + --current; + return tmp; + } +}; + +} // namespace cpp +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_CPP_ITERATOR_H diff --git a/lib/libcxx/libc/src/__support/CPP/limits.h b/lib/libcxx/libc/src/__support/CPP/limits.h new file mode 100644 index 0000000000..cf4beb9cc8 --- /dev/null +++ b/lib/libcxx/libc/src/__support/CPP/limits.h @@ -0,0 +1,92 @@ +//===-- A self contained equivalent of std::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. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_CPP_LIMITS_H +#define LLVM_LIBC_SRC___SUPPORT_CPP_LIMITS_H + +#include "hdr/limits_macros.h" // CHAR_BIT +#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; } + LIBC_INLINE_VAR static constexpr int digits = + CHAR_BIT * sizeof(T) - cpp::is_signed_v<T>; +}; + +} // 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 + +} // namespace cpp +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_CPP_LIMITS_H diff --git a/lib/libcxx/libc/src/__support/CPP/optional.h b/lib/libcxx/libc/src/__support/CPP/optional.h new file mode 100644 index 0000000000..aed2269db1 --- /dev/null +++ b/lib/libcxx/libc/src/__support/CPP/optional.h @@ -0,0 +1,139 @@ +//===-- Standalone implementation of std::optional --------------*- 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_CPP_OPTIONAL_H +#define LLVM_LIBC_SRC___SUPPORT_CPP_OPTIONAL_H + +#include "src/__support/CPP/type_traits.h" +#include "src/__support/CPP/utility.h" +#include "src/__support/macros/attributes.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { +namespace cpp { + +// Trivial nullopt_t struct. +struct nullopt_t { + LIBC_INLINE constexpr explicit nullopt_t() = default; +}; + +// nullopt that can be used and returned. +LIBC_INLINE_VAR constexpr nullopt_t nullopt{}; + +// This is very simple implementation of the std::optional class. It makes +// several assumptions that the underlying type is trivially constructible, +// copyable, or movable. +template <typename T> class optional { + template <typename U, bool = !is_trivially_destructible<U>::value> + struct OptionalStorage { + union { + char empty; + U stored_value; + }; + + bool in_use = false; + + LIBC_INLINE ~OptionalStorage() { reset(); } + + LIBC_INLINE constexpr OptionalStorage() : empty() {} + + template <typename... Args> + LIBC_INLINE constexpr explicit OptionalStorage(in_place_t, Args &&...args) + : stored_value(forward<Args>(args)...) {} + + LIBC_INLINE constexpr void reset() { + if (in_use) + stored_value.~U(); + in_use = false; + } + }; + + // The only difference is that this type U doesn't have a nontrivial + // destructor. + template <typename U> struct OptionalStorage<U, false> { + union { + char empty; + U stored_value; + }; + + bool in_use = false; + + LIBC_INLINE constexpr OptionalStorage() : empty() {} + + template <typename... Args> + LIBC_INLINE constexpr explicit OptionalStorage(in_place_t, Args &&...args) + : stored_value(forward<Args>(args)...) {} + + LIBC_INLINE constexpr void reset() { in_use = false; } + }; + + OptionalStorage<T> storage; + +public: + LIBC_INLINE constexpr optional() = default; + LIBC_INLINE constexpr optional(nullopt_t) {} + + LIBC_INLINE constexpr optional(const T &t) : storage(in_place, t) { + storage.in_use = true; + } + LIBC_INLINE constexpr optional(const optional &) = default; + + LIBC_INLINE constexpr optional(T &&t) : storage(in_place, move(t)) { + storage.in_use = true; + } + LIBC_INLINE constexpr optional(optional &&O) = default; + + template <typename... ArgTypes> + LIBC_INLINE constexpr optional(in_place_t, ArgTypes &&...Args) + : storage(in_place, forward<ArgTypes>(Args)...) { + storage.in_use = true; + } + + LIBC_INLINE constexpr optional &operator=(T &&t) { + storage = move(t); + return *this; + } + LIBC_INLINE constexpr optional &operator=(optional &&) = default; + + LIBC_INLINE constexpr optional &operator=(const T &t) { + storage = t; + return *this; + } + LIBC_INLINE constexpr optional &operator=(const optional &) = default; + + LIBC_INLINE constexpr void reset() { storage.reset(); } + + LIBC_INLINE constexpr const T &value() const & { + return storage.stored_value; + } + + LIBC_INLINE constexpr T &value() & { return storage.stored_value; } + + LIBC_INLINE constexpr explicit operator bool() const { + return storage.in_use; + } + LIBC_INLINE constexpr bool has_value() const { return storage.in_use; } + LIBC_INLINE constexpr const T *operator->() const { + return &storage.stored_value; + } + LIBC_INLINE constexpr T *operator->() { return &storage.stored_value; } + LIBC_INLINE constexpr const T &operator*() const & { + return storage.stored_value; + } + LIBC_INLINE constexpr T &operator*() & { return storage.stored_value; } + + LIBC_INLINE constexpr T &&value() && { return move(storage.stored_value); } + LIBC_INLINE constexpr T &&operator*() && { + return move(storage.stored_value); + } +}; + +} // namespace cpp +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_CPP_OPTIONAL_H diff --git a/lib/libcxx/libc/src/__support/CPP/string_view.h b/lib/libcxx/libc/src/__support/CPP/string_view.h new file mode 100644 index 0000000000..745c62c35f --- /dev/null +++ b/lib/libcxx/libc/src/__support/CPP/string_view.h @@ -0,0 +1,220 @@ +//===-- Standalone implementation std::string_view --------------*- 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_CPP_STRING_VIEW_H +#define LLVM_LIBC_SRC___SUPPORT_CPP_STRING_VIEW_H + +#include "src/__support/common.h" +#include "src/__support/macros/config.h" + +#include <stddef.h> + +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. +// +// This class will be extended as needed in future. +class string_view { +private: + const char *Data; + size_t Len; + + LIBC_INLINE static 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) { + for (size_t i = 0; i < Length; ++i) + if (int Diff = (int)Lhs[i] - (int)Rhs[i]) + return Diff; + return 0; + } + + LIBC_INLINE static constexpr size_t length(const char *Str) { + for (const char *End = Str;; ++End) + if (*End == '\0') + return End - Str; + } + + LIBC_INLINE bool equals(string_view Other) const { + return (Len == Other.Len && + compareMemory(Data, Other.Data, Other.Len) == 0); + } + +public: + using value_type = char; + 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 iterator = const_iterator; + + // special value equal to the maximum value representable by the type + // size_type. + LIBC_INLINE_VAR static constexpr size_t npos = -1; + + LIBC_INLINE constexpr 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) + : Data(Str), Len(length(Str)) {} + + // Preconditions: [Str, Str + N) is a valid range. + LIBC_INLINE constexpr string_view(const char *Str, size_t N) + : Data(Str), Len(N) {} + + LIBC_INLINE constexpr const char *data() const { return Data; } + + // Returns the size of the string_view. + LIBC_INLINE constexpr size_t size() const { return Len; } + + // Returns whether the 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; } + + // Returns an iterator to the character following the last character of the + // view. + LIBC_INLINE const char *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 { + 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 { + // Check the prefix for a mismatch. + if (int Res = compareMemory(Data, Other.Data, min(Len, Other.Len))) + return Res < 0 ? -1 : 1; + // 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 { + return !(*this == Other); + } + LIBC_INLINE bool operator<(string_view Other) const { + return compare(Other) == -1; + } + LIBC_INLINE bool operator<=(string_view Other) const { + return compare(Other) != 1; + } + LIBC_INLINE bool operator>(string_view Other) const { + return compare(Other) == 1; + } + LIBC_INLINE bool operator>=(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) { + 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; } + + // 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; + } + + // Check if this string starts with the given Prefix. + LIBC_INLINE bool starts_with(const char Prefix) const { + return !empty() && front() == Prefix; + } + + // Check if this string ends with the given Prefix. + LIBC_INLINE bool ends_with(const char Suffix) const { + return !empty() && back() == Suffix; + } + + // Check if this string ends with the given Suffix. + LIBC_INLINE bool ends_with(string_view Suffix) const { + return Len >= Suffix.Len && + compareMemory(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. + // + // 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 { + Start = min(Start, Len); + return string_view(Data + Start, min(N, Len - Start)); + } + + // front - Get the first character in the string. + LIBC_INLINE char front() const { return Data[0]; } + + // back - Get the last character in the string. + LIBC_INLINE char 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, + size_t From = 0) const { + for (size_t Pos = From; Pos < size(); ++Pos) + if ((*this)[Pos] == c) + return Pos; + return npos; + } + + // Finds the last occurence of c in this view, ending at position End. + LIBC_INLINE constexpr size_t find_last_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 char c, + size_t From = 0) const { + for (size_t Pos = From; Pos < size(); ++Pos) + if ((*this)[Pos] != c) + return Pos; + return npos; + } + + // Check if this view contains the given character. + LIBC_INLINE constexpr bool contains(char c) const { + return find_first_of(c) != npos; + } +}; + +} // namespace cpp +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_CPP_STRING_VIEW_H diff --git a/lib/libcxx/libc/src/__support/CPP/type_traits.h b/lib/libcxx/libc/src/__support/CPP/type_traits.h new file mode 100644 index 0000000000..d48ee23aea --- /dev/null +++ b/lib/libcxx/libc/src/__support/CPP/type_traits.h @@ -0,0 +1,70 @@ +//===-- Self contained C++ type_traits --------------------------*- 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_CPP_TYPE_TRAITS_H +#define LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_H + +#include "src/__support/CPP/type_traits/add_lvalue_reference.h" +#include "src/__support/CPP/type_traits/add_pointer.h" +#include "src/__support/CPP/type_traits/add_rvalue_reference.h" +#include "src/__support/CPP/type_traits/aligned_storage.h" +#include "src/__support/CPP/type_traits/bool_constant.h" +#include "src/__support/CPP/type_traits/conditional.h" +#include "src/__support/CPP/type_traits/decay.h" +#include "src/__support/CPP/type_traits/enable_if.h" +#include "src/__support/CPP/type_traits/false_type.h" +#include "src/__support/CPP/type_traits/has_unique_object_representations.h" +#include "src/__support/CPP/type_traits/integral_constant.h" +#include "src/__support/CPP/type_traits/invoke.h" +#include "src/__support/CPP/type_traits/invoke_result.h" +#include "src/__support/CPP/type_traits/is_arithmetic.h" +#include "src/__support/CPP/type_traits/is_array.h" +#include "src/__support/CPP/type_traits/is_base_of.h" +#include "src/__support/CPP/type_traits/is_class.h" +#include "src/__support/CPP/type_traits/is_complex.h" +#include "src/__support/CPP/type_traits/is_const.h" +#include "src/__support/CPP/type_traits/is_constant_evaluated.h" +#include "src/__support/CPP/type_traits/is_convertible.h" +#include "src/__support/CPP/type_traits/is_copy_assignable.h" +#include "src/__support/CPP/type_traits/is_copy_constructible.h" +#include "src/__support/CPP/type_traits/is_destructible.h" +#include "src/__support/CPP/type_traits/is_enum.h" +#include "src/__support/CPP/type_traits/is_fixed_point.h" +#include "src/__support/CPP/type_traits/is_floating_point.h" +#include "src/__support/CPP/type_traits/is_function.h" +#include "src/__support/CPP/type_traits/is_integral.h" +#include "src/__support/CPP/type_traits/is_lvalue_reference.h" +#include "src/__support/CPP/type_traits/is_member_pointer.h" +#include "src/__support/CPP/type_traits/is_move_assignable.h" +#include "src/__support/CPP/type_traits/is_move_constructible.h" +#include "src/__support/CPP/type_traits/is_null_pointer.h" +#include "src/__support/CPP/type_traits/is_object.h" +#include "src/__support/CPP/type_traits/is_pointer.h" +#include "src/__support/CPP/type_traits/is_reference.h" +#include "src/__support/CPP/type_traits/is_rvalue_reference.h" +#include "src/__support/CPP/type_traits/is_same.h" +#include "src/__support/CPP/type_traits/is_scalar.h" +#include "src/__support/CPP/type_traits/is_signed.h" +#include "src/__support/CPP/type_traits/is_trivially_constructible.h" +#include "src/__support/CPP/type_traits/is_trivially_copyable.h" +#include "src/__support/CPP/type_traits/is_trivially_destructible.h" +#include "src/__support/CPP/type_traits/is_union.h" +#include "src/__support/CPP/type_traits/is_unsigned.h" +#include "src/__support/CPP/type_traits/is_void.h" +#include "src/__support/CPP/type_traits/make_signed.h" +#include "src/__support/CPP/type_traits/make_unsigned.h" +#include "src/__support/CPP/type_traits/remove_all_extents.h" +#include "src/__support/CPP/type_traits/remove_cv.h" +#include "src/__support/CPP/type_traits/remove_cvref.h" +#include "src/__support/CPP/type_traits/remove_extent.h" +#include "src/__support/CPP/type_traits/remove_reference.h" +#include "src/__support/CPP/type_traits/true_type.h" +#include "src/__support/CPP/type_traits/type_identity.h" +#include "src/__support/CPP/type_traits/void_t.h" + +#endif // LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_H diff --git a/lib/libcxx/libc/src/__support/CPP/type_traits/add_lvalue_reference.h b/lib/libcxx/libc/src/__support/CPP/type_traits/add_lvalue_reference.h new file mode 100644 index 0000000000..6f5fc6b0a4 --- /dev/null +++ b/lib/libcxx/libc/src/__support/CPP/type_traits/add_lvalue_reference.h @@ -0,0 +1,33 @@ +//===-- add_lvalue_reference type_traits ------------------------*- 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_CPP_TYPE_TRAITS_ADD_LVALUE_REFERENCE_H +#define LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_ADD_LVALUE_REFERENCE_H + +#include "src/__support/CPP/type_traits/type_identity.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { +namespace cpp { + +// add_lvalue_reference +namespace detail { +template <class T> // Note that `cv void&` is a substitution failure +auto try_add_lvalue_reference(int) -> cpp::type_identity<T &>; +template <class T> // Handle T = cv void case +auto try_add_lvalue_reference(...) -> cpp::type_identity<T>; +} // namespace detail +template <class T> +struct add_lvalue_reference : decltype(detail::try_add_lvalue_reference<T>(0)) { +}; +template <class T> +using add_lvalue_reference_t = typename add_lvalue_reference<T>::type; + +} // namespace cpp +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_ADD_LVALUE_REFERENCE_H diff --git a/lib/libcxx/libc/src/__support/CPP/type_traits/add_pointer.h b/lib/libcxx/libc/src/__support/CPP/type_traits/add_pointer.h new file mode 100644 index 0000000000..2568a35653 --- /dev/null +++ b/lib/libcxx/libc/src/__support/CPP/type_traits/add_pointer.h @@ -0,0 +1,30 @@ +//===-- add_pointer type_traits ---------------------------------*- 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_CPP_TYPE_TRAITS_ADD_POINTER_H +#define LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_ADD_POINTER_H + +#include "src/__support/CPP/type_traits/remove_reference.h" +#include "src/__support/CPP/type_traits/type_identity.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { +namespace cpp { + +// add_pointer +namespace detail { +template <class T> +auto try_add_pointer(int) -> cpp::type_identity<cpp::remove_reference_t<T> *>; +template <class T> auto try_add_pointer(...) -> cpp::type_identity<T>; +} // namespace detail +template <class T> +struct add_pointer : decltype(detail::try_add_pointer<T>(0)) {}; +template <class T> using add_pointer_t = typename add_pointer<T>::type; +} // namespace cpp +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_ADD_POINTER_H diff --git a/lib/libcxx/libc/src/__support/CPP/type_traits/add_rvalue_reference.h b/lib/libcxx/libc/src/__support/CPP/type_traits/add_rvalue_reference.h new file mode 100644 index 0000000000..f51ebf46d7 --- /dev/null +++ b/lib/libcxx/libc/src/__support/CPP/type_traits/add_rvalue_reference.h @@ -0,0 +1,32 @@ +//===-- add_rvalue_reference type_traits ------------------------*- 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_CPP_TYPE_TRAITS_ADD_RVALUE_REFERENCE_H +#define LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_ADD_RVALUE_REFERENCE_H + +#include "src/__support/CPP/type_traits/type_identity.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { +namespace cpp { + +// add_rvalue_reference +namespace detail { +template <class T> +auto try_add_rvalue_reference(int) -> cpp::type_identity<T &&>; +template <class T> auto try_add_rvalue_reference(...) -> cpp::type_identity<T>; +} // namespace detail +template <class T> +struct add_rvalue_reference : decltype(detail::try_add_rvalue_reference<T>(0)) { +}; +template <class T> +using add_rvalue_reference_t = typename add_rvalue_reference<T>::type; + +} // namespace cpp +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_ADD_RVALUE_REFERENCE_H diff --git a/lib/libcxx/libc/src/__support/CPP/type_traits/aligned_storage.h b/lib/libcxx/libc/src/__support/CPP/type_traits/aligned_storage.h new file mode 100644 index 0000000000..69ad4cc847 --- /dev/null +++ b/lib/libcxx/libc/src/__support/CPP/type_traits/aligned_storage.h @@ -0,0 +1,30 @@ +//===-- aligned_storage type_traits --------------------------*- 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_CPP_TYPE_TRAITS_ALIGNED_STORAGE_H +#define LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_ALIGNED_STORAGE_H + +#include "src/__support/macros/config.h" +#include <stddef.h> // size_t + +namespace LIBC_NAMESPACE_DECL { +namespace cpp { + +template <size_t Len, size_t Align> struct aligned_storage { + struct type { + alignas(Align) unsigned char data[Len]; + }; +}; + +template <size_t Len, size_t Align> +using aligned_storage_t = typename aligned_storage<Len, Align>::type; + +} // namespace cpp +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_ALIGNED_STORAGE_H diff --git a/lib/libcxx/libc/src/__support/CPP/type_traits/always_false.h b/lib/libcxx/libc/src/__support/CPP/type_traits/always_false.h new file mode 100644 index 0000000000..218eb9d577 --- /dev/null +++ b/lib/libcxx/libc/src/__support/CPP/type_traits/always_false.h @@ -0,0 +1,32 @@ +//===-- convenient static_assert(false) helper ------------------*- 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_CPP_TYPE_TRAITS_ALWAYS_FALSE_H +#define LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_ALWAYS_FALSE_H + +#include "src/__support/macros/attributes.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { +namespace cpp { + +// This is technically not part of the standard but it come often enough that +// it's convenient to have around. +// +// https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2593r0.html#valid-workaround +// +// This will be fixed in C++23 according to [CWG +// 2518](https://cplusplus.github.io/CWG/issues/2518.html). + +// Usage `static_assert(cpp::always_false<T>, "error message");` +template <typename...> LIBC_INLINE_VAR constexpr bool always_false = false; + +} // namespace cpp +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_ALWAYS_FALSE_H diff --git a/lib/libcxx/libc/src/__support/CPP/type_traits/bool_constant.h b/lib/libcxx/libc/src/__support/CPP/type_traits/bool_constant.h new file mode 100644 index 0000000000..e61a81a84b --- /dev/null +++ b/lib/libcxx/libc/src/__support/CPP/type_traits/bool_constant.h @@ -0,0 +1,23 @@ +//===-- bool_constant type_traits -------------------------------*- 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_CPP_TYPE_TRAITS_BOOL_CONSTANT_H +#define LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_BOOL_CONSTANT_H + +#include "src/__support/CPP/type_traits/integral_constant.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { +namespace cpp { + +// bool_constant +template <bool V> using bool_constant = cpp::integral_constant<bool, V>; + +} // namespace cpp +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_BOOL_CONSTANT_H diff --git a/lib/libcxx/libc/src/__support/CPP/type_traits/conditional.h b/lib/libcxx/libc/src/__support/CPP/type_traits/conditional.h new file mode 100644 index 0000000000..effcda02da --- /dev/null +++ b/lib/libcxx/libc/src/__support/CPP/type_traits/conditional.h @@ -0,0 +1,28 @@ +//===-- conditional type_traits ---------------------------------*- 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_CPP_TYPE_TRAITS_CONDITIONAL_H +#define LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_CONDITIONAL_H + +#include "src/__support/CPP/type_traits/type_identity.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { +namespace cpp { + +// conditional +template <bool B, typename T, typename F> +struct conditional : type_identity<T> {}; +template <typename T, typename F> +struct conditional<false, T, F> : type_identity<F> {}; +template <bool B, typename T, typename F> +using conditional_t = typename conditional<B, T, F>::type; + +} // namespace cpp +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_CONDITIONAL_H diff --git a/lib/libcxx/libc/src/__support/CPP/type_traits/decay.h b/lib/libcxx/libc/src/__support/CPP/type_traits/decay.h new file mode 100644 index 0000000000..c07e9e8557 --- /dev/null +++ b/lib/libcxx/libc/src/__support/CPP/type_traits/decay.h @@ -0,0 +1,40 @@ +//===-- decay type_traits ---------------------------------------*- 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_CPP_TYPE_TRAITS_DECAY_H +#define LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_DECAY_H + +#include "src/__support/macros/attributes.h" + +#include "src/__support/CPP/type_traits/add_pointer.h" +#include "src/__support/CPP/type_traits/conditional.h" +#include "src/__support/CPP/type_traits/is_array.h" +#include "src/__support/CPP/type_traits/is_function.h" +#include "src/__support/CPP/type_traits/remove_cv.h" +#include "src/__support/CPP/type_traits/remove_extent.h" +#include "src/__support/CPP/type_traits/remove_reference.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { +namespace cpp { + +// decay +template <class T> class decay { + using U = cpp::remove_reference_t<T>; + +public: + using type = conditional_t< + cpp::is_array_v<U>, cpp::add_pointer_t<cpp::remove_extent_t<U>>, + cpp::conditional_t<cpp::is_function_v<U>, cpp::add_pointer_t<U>, + cpp::remove_cv_t<U>>>; +}; +template <class T> using decay_t = typename decay<T>::type; + +} // namespace cpp +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_DECAY_H diff --git a/lib/libcxx/libc/src/__support/CPP/type_traits/enable_if.h b/lib/libcxx/libc/src/__support/CPP/type_traits/enable_if.h new file mode 100644 index 0000000000..a2ce2037eb --- /dev/null +++ b/lib/libcxx/libc/src/__support/CPP/type_traits/enable_if.h @@ -0,0 +1,26 @@ +//===-- enable_if type_traits -----------------------------------*- 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_CPP_TYPE_TRAITS_ENABLE_IF_H +#define LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_ENABLE_IF_H + +#include "src/__support/CPP/type_traits/type_identity.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { +namespace cpp { + +// enable_if +template <bool B, typename T = void> struct enable_if; +template <typename T> struct enable_if<true, T> : type_identity<T> {}; +template <bool B, typename T = void> +using enable_if_t = typename enable_if<B, T>::type; + +} // namespace cpp +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_ENABLE_IF_H diff --git a/lib/libcxx/libc/src/__support/CPP/type_traits/false_type.h b/lib/libcxx/libc/src/__support/CPP/type_traits/false_type.h new file mode 100644 index 0000000000..65934b96ba --- /dev/null +++ b/lib/libcxx/libc/src/__support/CPP/type_traits/false_type.h @@ -0,0 +1,23 @@ +//===-- false_type type_traits ----------------------------------*- 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_CPP_TYPE_TRAITS_FALSE_TYPE_H +#define LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_FALSE_TYPE_H + +#include "src/__support/CPP/type_traits/bool_constant.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { +namespace cpp { + +// false_type +using false_type = cpp::bool_constant<false>; + +} // namespace cpp +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_FALSE_TYPE_H diff --git a/lib/libcxx/libc/src/__support/CPP/type_traits/has_unique_object_representations.h b/lib/libcxx/libc/src/__support/CPP/type_traits/has_unique_object_representations.h new file mode 100644 index 0000000000..639fb69d27 --- /dev/null +++ b/lib/libcxx/libc/src/__support/CPP/type_traits/has_unique_object_representations.h @@ -0,0 +1,30 @@ +//===-- has_unique_object_representations type_traits ------------*- 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_CPP_TYPE_TRAITS_HAS_UNIQUE_OBJECT_REPRESENTATIONS_H +#define LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_HAS_UNIQUE_OBJECT_REPRESENTATIONS_H + +#include "src/__support/CPP/type_traits/integral_constant.h" +#include "src/__support/CPP/type_traits/remove_all_extents.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { +namespace cpp { + +template <class T> +struct has_unique_object_representations + : public integral_constant<bool, __has_unique_object_representations( + remove_all_extents_t<T>)> {}; + +template <class T> +LIBC_INLINE_VAR constexpr bool has_unique_object_representations_v = + has_unique_object_representations<T>::value; + +} // namespace cpp +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_HAS_UNIQUE_OBJECT_REPRESENTATIONS_H diff --git a/lib/libcxx/libc/src/__support/CPP/type_traits/integral_constant.h b/lib/libcxx/libc/src/__support/CPP/type_traits/integral_constant.h new file mode 100644 index 0000000000..931a9b98a6 --- /dev/null +++ b/lib/libcxx/libc/src/__support/CPP/type_traits/integral_constant.h @@ -0,0 +1,26 @@ +//===-- integral_constant type_traits ---------------------------*- 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_CPP_TYPE_TRAITS_INTEGRAL_CONSTANT_H +#define LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_INTEGRAL_CONSTANT_H + +#include "src/__support/macros/attributes.h" // LIBC_INLINE_VAR +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { +namespace cpp { + +// integral_constant +template <typename T, T v> struct integral_constant { + using value_type = T; + LIBC_INLINE_VAR static constexpr T value = v; +}; + +} // namespace cpp +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_INTEGRAL_CONSTANT_H diff --git a/lib/libcxx/libc/src/__support/CPP/type_traits/invoke.h b/lib/libcxx/libc/src/__support/CPP/type_traits/invoke.h new file mode 100644 index 0000000000..e4d9be74d1 --- /dev/null +++ b/lib/libcxx/libc/src/__support/CPP/type_traits/invoke.h @@ -0,0 +1,67 @@ +//===-- invoke type_traits --------------------------------------*- 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_CPP_TYPE_TRAITS_INVOKE_H +#define LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_INVOKE_H + +#include "src/__support/CPP/type_traits/always_false.h" +#include "src/__support/CPP/type_traits/decay.h" +#include "src/__support/CPP/type_traits/enable_if.h" +#include "src/__support/CPP/type_traits/is_base_of.h" +#include "src/__support/CPP/type_traits/is_pointer.h" +#include "src/__support/CPP/type_traits/is_same.h" +#include "src/__support/CPP/utility/forward.h" +#include "src/__support/macros/attributes.h" // LIBC_INLINE +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { +namespace cpp { + +namespace detail { + +// Catch all function and functor types. +template <class FunctionPtrType> struct invoke_dispatcher { + template <class T, class... Args, + typename = cpp::enable_if_t< + cpp::is_same_v<cpp::decay_t<T>, FunctionPtrType>>> + LIBC_INLINE static decltype(auto) call(T &&fun, Args &&...args) { + return cpp::forward<T>(fun)(cpp::forward<Args>(args)...); + } +}; + +// Catch pointer to member function types. +template <class Class, class FunctionReturnType> +struct invoke_dispatcher<FunctionReturnType Class::*> { + using FunctionPtrType = FunctionReturnType Class::*; + + template <class T, class... Args, class DecayT = cpp::decay_t<T>> + LIBC_INLINE static decltype(auto) call(FunctionPtrType fun, T &&t1, + Args &&...args) { + if constexpr (cpp::is_base_of_v<Class, DecayT>) { + // T is a (possibly cv ref) type. + return (cpp::forward<T>(t1).*fun)(cpp::forward<Args>(args)...); + } else if constexpr (cpp::is_pointer_v<T>) { + // T is a pointer type. + return (*cpp::forward<T>(t1).*fun)(cpp::forward<Args>(args)...); + } else { + static_assert(cpp::always_false<T>); + } + } +}; + +} // namespace detail +template <class Function, class... Args> +decltype(auto) invoke(Function &&fun, Args &&...args) { + return detail::invoke_dispatcher<cpp::decay_t<Function>>::call( + cpp::forward<Function>(fun), cpp::forward<Args>(args)...); +} + +} // namespace cpp +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_INVOKE_H diff --git a/lib/libcxx/libc/src/__support/CPP/type_traits/invoke_result.h b/lib/libcxx/libc/src/__support/CPP/type_traits/invoke_result.h new file mode 100644 index 0000000000..71d848b77f --- /dev/null +++ b/lib/libcxx/libc/src/__support/CPP/type_traits/invoke_result.h @@ -0,0 +1,29 @@ +//===-- invoke_result type_traits -------------------------------*- 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_CPP_TYPE_TRAITS_INVOKE_RESULT_H +#define LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_INVOKE_RESULT_H + +#include "src/__support/CPP/type_traits/invoke.h" +#include "src/__support/CPP/type_traits/type_identity.h" +#include "src/__support/CPP/utility/declval.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { +namespace cpp { + +template <class F, class... Args> +struct invoke_result : cpp::type_identity<decltype(cpp::invoke( + cpp::declval<F>(), cpp::declval<Args>()...))> {}; + +template <class F, class... Args> +using invoke_result_t = typename invoke_result<F, Args...>::type; + +} // namespace cpp +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_INVOKE_RESULT_H diff --git a/lib/libcxx/libc/src/__support/CPP/type_traits/is_arithmetic.h b/lib/libcxx/libc/src/__support/CPP/type_traits/is_arithmetic.h new file mode 100644 index 0000000000..33671b0def --- /dev/null +++ b/lib/libcxx/libc/src/__support/CPP/type_traits/is_arithmetic.h @@ -0,0 +1,30 @@ +//===-- is_arithmetic type_traits -------------------------------*- 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_CPP_TYPE_TRAITS_IS_ARITHMETIC_H +#define LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_IS_ARITHMETIC_H + +#include "src/__support/CPP/type_traits/bool_constant.h" +#include "src/__support/CPP/type_traits/is_floating_point.h" +#include "src/__support/CPP/type_traits/is_integral.h" +#include "src/__support/macros/attributes.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { +namespace cpp { + +// is_arithmetic +template <typename T> +struct is_arithmetic : cpp::bool_constant<(cpp::is_integral_v<T> || + cpp::is_floating_point_v<T>)> {}; +template <typename T> +LIBC_INLINE_VAR constexpr bool is_arithmetic_v = is_arithmetic<T>::value; + +} // namespace cpp +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_IS_ARITHMETIC_H diff --git a/lib/libcxx/libc/src/__support/CPP/type_traits/is_array.h b/lib/libcxx/libc/src/__support/CPP/type_traits/is_array.h new file mode 100644 index 0000000000..f0ab100fd5 --- /dev/null +++ b/lib/libcxx/libc/src/__support/CPP/type_traits/is_array.h @@ -0,0 +1,31 @@ +//===-- is_array type_traits ------------------------------------*- 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_CPP_TYPE_TRAITS_IS_ARRAY_H +#define LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_IS_ARRAY_H + +#include "src/__support/CPP/type_traits/false_type.h" +#include "src/__support/CPP/type_traits/true_type.h" +#include "src/__support/macros/attributes.h" +#include "src/__support/macros/config.h" + +#include <stddef.h> // For size_t + +namespace LIBC_NAMESPACE_DECL { +namespace cpp { + +// is_array +template <class T> struct is_array : false_type {}; +template <class T> struct is_array<T[]> : true_type {}; +template <class T, size_t N> struct is_array<T[N]> : true_type {}; +template <class T> +LIBC_INLINE_VAR constexpr bool is_array_v = is_array<T>::value; + +} // namespace cpp +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_IS_ARRAY_H diff --git a/lib/libcxx/libc/src/__support/CPP/type_traits/is_base_of.h b/lib/libcxx/libc/src/__support/CPP/type_traits/is_base_of.h new file mode 100644 index 0000000000..2efd1bf3f1 --- /dev/null +++ b/lib/libcxx/libc/src/__support/CPP/type_traits/is_base_of.h @@ -0,0 +1,47 @@ +//===-- is_base_of type_traits ----------------------------------*- 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_CPP_TYPE_TRAITS_IS_BASE_OF_H +#define LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_IS_BASE_OF_H + +#include "src/__support/CPP/type_traits/add_rvalue_reference.h" +#include "src/__support/CPP/type_traits/false_type.h" +#include "src/__support/CPP/type_traits/is_class.h" +#include "src/__support/CPP/type_traits/remove_all_extents.h" +#include "src/__support/CPP/type_traits/true_type.h" +#include "src/__support/macros/attributes.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { +namespace cpp { + +// is_base_of +namespace detail { +template <typename B> cpp::true_type __test_ptr_conv(const volatile B *); +template <typename> cpp::false_type __test_ptr_conv(const volatile void *); + +template <typename B, typename D> +auto is_base_of(int) -> decltype(__test_ptr_conv<B>(static_cast<D *>(nullptr))); + +template <typename, typename> +auto is_base_of(...) -> cpp::true_type; // private or ambiguous base + +} // namespace detail + +template <typename Base, typename Derived> +struct is_base_of + : cpp::bool_constant< + cpp::is_class_v<Base> && + cpp::is_class_v<Derived> &&decltype(detail::is_base_of<Base, Derived>( + 0))::value> {}; +template <typename Base, typename Derived> +LIBC_INLINE_VAR constexpr bool is_base_of_v = is_base_of<Base, Derived>::value; + +} // namespace cpp +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_IS_BASE_OF_H diff --git a/lib/libcxx/libc/src/__support/CPP/type_traits/is_class.h b/lib/libcxx/libc/src/__support/CPP/type_traits/is_class.h new file mode 100644 index 0000000000..fe12f7d276 --- /dev/null +++ b/lib/libcxx/libc/src/__support/CPP/type_traits/is_class.h @@ -0,0 +1,32 @@ +//===-- is_class type_traits ------------------------------------*- 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_CPP_TYPE_TRAITS_IS_CLASS_H +#define LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_IS_CLASS_H + +#include "src/__support/CPP/type_traits/bool_constant.h" +#include "src/__support/CPP/type_traits/false_type.h" +#include "src/__support/CPP/type_traits/is_union.h" +#include "src/__support/macros/attributes.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { +namespace cpp { + +// is_class +namespace detail { +template <class T> cpp::bool_constant<!cpp::is_union_v<T>> test(int T::*); +template <class> cpp::false_type test(...); +} // namespace detail +template <class T> struct is_class : decltype(detail::test<T>(nullptr)) {}; +template <typename T> +LIBC_INLINE_VAR constexpr bool is_class_v = is_class<T>::value; + +} // namespace cpp +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_IS_CLASS_H diff --git a/lib/libcxx/libc/src/__support/CPP/type_traits/is_complex.h b/lib/libcxx/libc/src/__support/CPP/type_traits/is_complex.h new file mode 100644 index 0000000000..23f05c08cc --- /dev/null +++ b/lib/libcxx/libc/src/__support/CPP/type_traits/is_complex.h @@ -0,0 +1,53 @@ +//===-- is_complex type_traits ----------------------------------*- 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_CPP_TYPE_TRAITS_IS_COMPLEX_H +#define LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_IS_COMPLEX_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" +#include "src/__support/macros/config.h" +// LIBC_TYPES_HAS_CFLOAT16 && LIBC_TYPES_HAS_CFLOAT128 +#include "src/__support/macros/properties/complex_types.h" + +namespace LIBC_NAMESPACE_DECL { +namespace cpp { + +// is_complex +template <typename T> struct is_complex { +private: + template <typename Head, typename... Args> + LIBC_INLINE_VAR static constexpr bool __is_unqualified_any_of() { + return (... || is_same_v<remove_cv_t<Head>, Args>); + } + +public: + LIBC_INLINE_VAR static constexpr bool value = + __is_unqualified_any_of<T, _Complex float, _Complex double, + _Complex long double +#ifdef LIBC_TYPES_HAS_CFLOAT16 + , + cfloat16 +#endif +#ifdef LIBC_TYPES_HAS_CFLOAT128 + , + cfloat128 +#endif + >(); +}; +template <typename T> +LIBC_INLINE_VAR constexpr bool is_complex_v = is_complex<T>::value; +template <typename T1, typename T2> +LIBC_INLINE_VAR constexpr bool is_complex_type_same() { + return is_same_v<remove_cv_t<T1>, T2>; +} + +} // namespace cpp +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_IS_COMPLEX_H diff --git a/lib/libcxx/libc/src/__support/CPP/type_traits/is_const.h b/lib/libcxx/libc/src/__support/CPP/type_traits/is_const.h new file mode 100644 index 0000000000..b8e60f79a6 --- /dev/null +++ b/lib/libcxx/libc/src/__support/CPP/type_traits/is_const.h @@ -0,0 +1,28 @@ +//===-- is_const type_traits ------------------------------------*- 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_CPP_TYPE_TRAITS_IS_CONST_H +#define LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_IS_CONST_H + +#include "src/__support/CPP/type_traits/false_type.h" +#include "src/__support/CPP/type_traits/true_type.h" +#include "src/__support/macros/attributes.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { +namespace cpp { + +// is_const +template <class T> struct is_const : cpp::false_type {}; +template <class T> struct is_const<const T> : cpp::true_type {}; +template <class T> +LIBC_INLINE_VAR constexpr bool is_const_v = is_const<T>::value; + +} // namespace cpp +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_IS_CONST_H diff --git a/lib/libcxx/libc/src/__support/CPP/type_traits/is_constant_evaluated.h b/lib/libcxx/libc/src/__support/CPP/type_traits/is_constant_evaluated.h new file mode 100644 index 0000000000..0bb2d0806c --- /dev/null +++ b/lib/libcxx/libc/src/__support/CPP/type_traits/is_constant_evaluated.h @@ -0,0 +1,24 @@ +//===-- is_constant_evaluated type_traits -----------------------*- 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_CPP_TYPE_TRAITS_IS_CONSTANT_EVALUATED_H +#define LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_IS_CONSTANT_EVALUATED_H + +#include "src/__support/macros/attributes.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { +namespace cpp { + +LIBC_INLINE constexpr bool is_constant_evaluated() { + return __builtin_is_constant_evaluated(); +} + +} // namespace cpp +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_IS_CONSTANT_EVALUATED_H diff --git a/lib/libcxx/libc/src/__support/CPP/type_traits/is_convertible.h b/lib/libcxx/libc/src/__support/CPP/type_traits/is_convertible.h new file mode 100644 index 0000000000..a9f94cbb95 --- /dev/null +++ b/lib/libcxx/libc/src/__support/CPP/type_traits/is_convertible.h @@ -0,0 +1,48 @@ +//===-- is_convertible type_traits ------------------------------*- 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_CPP_TYPE_TRAITS_IS_CONVERTIBLE_H +#define LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_IS_CONVERTIBLE_H + +#include "src/__support/CPP/type_traits/is_void.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 { + +// is_convertible +namespace detail { +template <class T> +auto test_returnable(int) + -> decltype(void(static_cast<T (*)()>(nullptr)), cpp::true_type{}); +template <class> auto test_returnable(...) -> cpp::false_type; + +template <class From, class To> +auto test_implicitly_convertible(int) + -> decltype(void(cpp::declval<void (&)(To)>()(cpp::declval<From>())), + cpp::true_type{}); +template <class, class> +auto test_implicitly_convertible(...) -> cpp::false_type; +} // namespace detail + +template <class From, class To> +struct is_convertible + : cpp::bool_constant< + (decltype(detail::test_returnable<To>(0))::value && + decltype(detail::test_implicitly_convertible<From, To>(0))::value) || + (cpp::is_void_v<From> && cpp::is_void_v<To>)> {}; + +template <class From, class To> +LIBC_INLINE_VAR constexpr bool is_convertible_v = + is_convertible<From, To>::value; + +} // namespace cpp +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_IS_CONVERTIBLE_H diff --git a/lib/libcxx/libc/src/__support/CPP/type_traits/is_copy_assignable.h b/lib/libcxx/libc/src/__support/CPP/type_traits/is_copy_assignable.h new file mode 100644 index 0000000000..9beb93d146 --- /dev/null +++ b/lib/libcxx/libc/src/__support/CPP/type_traits/is_copy_assignable.h @@ -0,0 +1,32 @@ +//===-- is_copy_assignable type_traits --------------------------*- 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_CPP_TYPE_TRAITS_IS_COPY_ASSIGNABLE_H +#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/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { +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>)> {}; + +template <class T> +LIBC_INLINE_VAR constexpr bool is_copy_assignable_v = + is_copy_assignable<T>::value; + +} // namespace cpp +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_IS_COPY_ASSIGNABLE_H diff --git a/lib/libcxx/libc/src/__support/CPP/type_traits/is_copy_constructible.h b/lib/libcxx/libc/src/__support/CPP/type_traits/is_copy_constructible.h new file mode 100644 index 0000000000..d8eb9ad350 --- /dev/null +++ b/lib/libcxx/libc/src/__support/CPP/type_traits/is_copy_constructible.h @@ -0,0 +1,31 @@ +//===-- is_copy_constructible type_traits -----------------------*- 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_CPP_TYPE_TRAITS_IS_COPY_CONSTRUCTIBLE_H +#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/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { +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>)> {}; + +template <class T> +LIBC_INLINE_VAR constexpr bool is_copy_constructible_v = + is_copy_constructible<T>::value; + +} // namespace cpp +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_IS_COPY_CONSTRUCTIBLE_H diff --git a/lib/libcxx/libc/src/__support/CPP/type_traits/is_destructible.h b/lib/libcxx/libc/src/__support/CPP/type_traits/is_destructible.h new file mode 100644 index 0000000000..830f22efaf --- /dev/null +++ b/lib/libcxx/libc/src/__support/CPP/type_traits/is_destructible.h @@ -0,0 +1,68 @@ +//===-- is_destructible type_traits -----------------------------*- 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_CPP_TYPE_TRAITS_IS_DESTRUCTIBLE_H +#define LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_IS_DESTRUCTIBLE_H + +#include "src/__support/CPP/type_traits/bool_constant.h" +#include "src/__support/CPP/type_traits/false_type.h" +#include "src/__support/CPP/type_traits/is_function.h" +#include "src/__support/CPP/type_traits/is_reference.h" +#include "src/__support/CPP/type_traits/remove_all_extents.h" +#include "src/__support/CPP/type_traits/true_type.h" +#include "src/__support/CPP/type_traits/type_identity.h" +#include "src/__support/macros/attributes.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { +namespace cpp { + +// is_destructible +#if __has_builtin(__is_destructible) +template <typename T> +struct is_destructible : bool_constant<__is_destructible(T)> {}; +#else +// if it's a reference, return true +// if it's a function, return false +// if it's void, return false +// if it's an array of unknown bound, return false +// Otherwise, return "declval<T&>().~T()" is well-formed +// where T is remove_all_extents<T>::type +template <typename> struct __is_destructible_apply : cpp::type_identity<int> {}; +template <typename T> struct __is_destructor_wellformed { + template <typename T1> + static cpp::true_type __test( + typename __is_destructible_apply<decltype(declval<T1 &>().~T1())>::type); + template <typename T1> static cpp::false_type __test(...); + static const bool value = decltype(__test<T>(12))::value; +}; +template <typename T, bool> struct __destructible_imp; +template <typename T> +struct __destructible_imp<T, false> + : public bool_constant< + __is_destructor_wellformed<cpp::remove_all_extents_t<T>>::value> {}; +template <typename T> +struct __destructible_imp<T, true> : public cpp::true_type {}; +template <typename T, bool> struct __destructible_false; +template <typename T> +struct __destructible_false<T, false> + : public __destructible_imp<T, is_reference<T>::value> {}; +template <typename T> +struct __destructible_false<T, true> : public cpp::false_type {}; +template <typename T> +struct is_destructible : public __destructible_false<T, is_function<T>::value> { +}; +template <typename T> struct is_destructible<T[]> : public false_type {}; +template <> struct is_destructible<void> : public false_type {}; +#endif +template <class T> +LIBC_INLINE_VAR constexpr bool is_destructible_v = is_destructible<T>::value; + +} // namespace cpp +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_IS_DESTRUCTIBLE_H diff --git a/lib/libcxx/libc/src/__support/CPP/type_traits/is_enum.h b/lib/libcxx/libc/src/__support/CPP/type_traits/is_enum.h new file mode 100644 index 0000000000..623ae072af --- /dev/null +++ b/lib/libcxx/libc/src/__support/CPP/type_traits/is_enum.h @@ -0,0 +1,26 @@ +//===-- is_enum type_traits -------------------------------------*- 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_CPP_TYPE_TRAITS_IS_ENUM_H +#define LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_IS_ENUM_H + +#include "src/__support/CPP/type_traits/bool_constant.h" +#include "src/__support/macros/attributes.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { +namespace cpp { + +// is_enum +template <typename T> struct is_enum : bool_constant<__is_enum(T)> {}; +template <typename T> +LIBC_INLINE_VAR constexpr bool is_enum_v = is_enum<T>::value; + +} // namespace cpp +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_IS_ENUM_H diff --git a/lib/libcxx/libc/src/__support/CPP/type_traits/is_fixed_point.h b/lib/libcxx/libc/src/__support/CPP/type_traits/is_fixed_point.h new file mode 100644 index 0000000000..9df2a7727c --- /dev/null +++ b/lib/libcxx/libc/src/__support/CPP/type_traits/is_fixed_point.h @@ -0,0 +1,49 @@ +//===-- is_fixed_point type_traits ------------------------------*- 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_CPP_TYPE_TRAITS_IS_FIXED_POINT_H +#define LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_IS_FIXED_POINT_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" + +#include "include/llvm-libc-macros/stdfix-macros.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { +namespace cpp { + +// is_fixed_point +#ifdef LIBC_COMPILER_HAS_FIXED_POINT +template <typename T> struct is_fixed_point { +private: + template <typename Head, typename... Args> + LIBC_INLINE static constexpr bool __is_unqualified_any_of() { + return (... || is_same_v<remove_cv_t<Head>, Args>); + } + +public: + LIBC_INLINE_VAR static constexpr bool value = __is_unqualified_any_of< + T, short fract, fract, long fract, unsigned short fract, unsigned fract, + unsigned long fract, short accum, accum, long accum, unsigned short accum, + unsigned accum, unsigned long accum, short sat fract, sat fract, + long sat fract, unsigned short sat fract, unsigned sat fract, + unsigned long sat fract, short sat accum, sat accum, long sat accum, + unsigned short sat accum, unsigned sat accum, unsigned long sat accum>(); +}; +#else +template <typename T> struct is_fixed_point : false_type {}; +#endif // LIBC_COMPILER_HAS_FIXED_POINT + +template <typename T> +LIBC_INLINE_VAR constexpr bool is_fixed_point_v = is_fixed_point<T>::value; + +} // namespace cpp +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_IS_FIXED_POINT_H diff --git a/lib/libcxx/libc/src/__support/CPP/type_traits/is_floating_point.h b/lib/libcxx/libc/src/__support/CPP/type_traits/is_floating_point.h new file mode 100644 index 0000000000..11ffbfabe6 --- /dev/null +++ b/lib/libcxx/libc/src/__support/CPP/type_traits/is_floating_point.h @@ -0,0 +1,48 @@ +//===-- is_floating_point type_traits ---------------------------*- 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_CPP_TYPE_TRAITS_IS_FLOATING_POINT_H +#define LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_IS_FLOATING_POINT_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" +#include "src/__support/macros/config.h" +#include "src/__support/macros/properties/types.h" // LIBC_TYPES_HAS_FLOAT128 + +namespace LIBC_NAMESPACE_DECL { +namespace cpp { + +// is_floating_point +template <typename T> struct is_floating_point { +private: + template <typename Head, typename... Args> + LIBC_INLINE_VAR static constexpr bool __is_unqualified_any_of() { + return (... || is_same_v<remove_cv_t<Head>, Args>); + } + +public: + LIBC_INLINE_VAR static constexpr bool value = + __is_unqualified_any_of<T, float, double, long double +#ifdef LIBC_TYPES_HAS_FLOAT16 + , + float16 +#endif +#ifdef LIBC_TYPES_HAS_FLOAT128 + , + float128 +#endif + >(); +}; +template <typename T> +LIBC_INLINE_VAR constexpr bool is_floating_point_v = + is_floating_point<T>::value; + +} // namespace cpp +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_IS_FLOATING_POINT_H diff --git a/lib/libcxx/libc/src/__support/CPP/type_traits/is_function.h b/lib/libcxx/libc/src/__support/CPP/type_traits/is_function.h new file mode 100644 index 0000000000..f7717f0a4d --- /dev/null +++ b/lib/libcxx/libc/src/__support/CPP/type_traits/is_function.h @@ -0,0 +1,35 @@ +//===-- is_function type_traits ---------------------------------*- 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_CPP_TYPE_TRAITS_IS_FUNCTION_H +#define LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_IS_FUNCTION_H + +#include "src/__support/CPP/type_traits/bool_constant.h" +#include "src/__support/CPP/type_traits/is_const.h" +#include "src/__support/CPP/type_traits/is_reference.h" +#include "src/__support/macros/attributes.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { +namespace cpp { + +// is_function +#if __has_builtin(__is_function) +template <typename T> +struct is_function : integral_constant<bool, __is_function(T)> {}; +#else +template <typename T> +struct is_function + : public bool_constant<!(is_reference_v<T> || is_const_v<const T>)> {}; +#endif +template <class T> +LIBC_INLINE_VAR constexpr bool is_function_v = is_function<T>::value; + +} // namespace cpp +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_IS_FUNCTION_H diff --git a/lib/libcxx/libc/src/__support/CPP/type_traits/is_integral.h b/lib/libcxx/libc/src/__support/CPP/type_traits/is_integral.h new file mode 100644 index 0000000000..96ba09a07d --- /dev/null +++ b/lib/libcxx/libc/src/__support/CPP/type_traits/is_integral.h @@ -0,0 +1,43 @@ +//===-- is_integral type_traits ---------------------------------*- 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_CPP_TYPE_TRAITS_IS_INTEGRAL_H +#define LLVM_LIBC_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" +#include "src/__support/macros/config.h" +#include "src/__support/macros/properties/types.h" // LIBC_TYPES_HAS_INT128 + +namespace LIBC_NAMESPACE_DECL { +namespace cpp { + +// is_integral +template <typename T> struct is_integral { +private: + template <typename Head, typename... Args> + LIBC_INLINE_VAR static constexpr bool __is_unqualified_any_of() { + return (... || is_same_v<remove_cv_t<Head>, Args>); + } + +public: + LIBC_INLINE_VAR static constexpr bool value = __is_unqualified_any_of< + T, +#ifdef LIBC_TYPES_HAS_INT128 + __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>(); +}; +template <typename T> +LIBC_INLINE_VAR constexpr bool is_integral_v = is_integral<T>::value; + +} // namespace cpp +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_IS_INTEGRAL_H diff --git a/lib/libcxx/libc/src/__support/CPP/type_traits/is_lvalue_reference.h b/lib/libcxx/libc/src/__support/CPP/type_traits/is_lvalue_reference.h new file mode 100644 index 0000000000..e0bfbebdaa --- /dev/null +++ b/lib/libcxx/libc/src/__support/CPP/type_traits/is_lvalue_reference.h @@ -0,0 +1,35 @@ +//===-- is_lvalue_reference type_traits -------------------------*- 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_CPP_TYPE_TRAITS_IS_LVALUE_REFERENCE_H +#define LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_IS_LVALUE_REFERENCE_H + +#include "src/__support/CPP/type_traits/bool_constant.h" +#include "src/__support/CPP/type_traits/false_type.h" +#include "src/__support/CPP/type_traits/true_type.h" +#include "src/__support/macros/attributes.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { +namespace cpp { + +// is_lvalue_reference +#if __has_builtin(__is_lvalue_reference) +template <typename T> +struct is_lvalue_reference : bool_constant<__is_lvalue_reference(T)> {}; +#else +template <typename T> struct is_lvalue_reference : public false_type {}; +template <typename T> struct is_lvalue_reference<T &> : public true_type {}; +#endif +template <class T> +LIBC_INLINE_VAR constexpr bool is_lvalue_reference_v = + is_lvalue_reference<T>::value; + +} // namespace cpp +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_IS_LVALUE_REFERENCE_H diff --git a/lib/libcxx/libc/src/__support/CPP/type_traits/is_member_pointer.h b/lib/libcxx/libc/src/__support/CPP/type_traits/is_member_pointer.h new file mode 100644 index 0000000000..f445670039 --- /dev/null +++ b/lib/libcxx/libc/src/__support/CPP/type_traits/is_member_pointer.h @@ -0,0 +1,33 @@ +//===-- is_member_pointer type_traits ---------------------------*- 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_CPP_TYPE_TRAITS_IS_MEMBER_POINTER_H +#define LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_IS_MEMBER_POINTER_H + +#include "src/__support/CPP/type_traits/false_type.h" +#include "src/__support/CPP/type_traits/remove_cv.h" +#include "src/__support/CPP/type_traits/true_type.h" +#include "src/__support/macros/attributes.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { +namespace cpp { + +// is_member_pointer +template <class T> struct is_member_pointer_helper : cpp::false_type {}; +template <class T, class U> +struct is_member_pointer_helper<T U::*> : cpp::true_type {}; +template <class T> +struct is_member_pointer : is_member_pointer_helper<cpp::remove_cv_t<T>> {}; +template <class T> +LIBC_INLINE_VAR constexpr bool is_member_pointer_v = + is_member_pointer<T>::value; + +} // namespace cpp +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_IS_MEMBER_POINTER_H diff --git a/lib/libcxx/libc/src/__support/CPP/type_traits/is_move_assignable.h b/lib/libcxx/libc/src/__support/CPP/type_traits/is_move_assignable.h new file mode 100644 index 0000000000..a788bd9074 --- /dev/null +++ b/lib/libcxx/libc/src/__support/CPP/type_traits/is_move_assignable.h @@ -0,0 +1,33 @@ +//===-- is_move_assignable type_traits --------------------------*- 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_CPP_TYPE_TRAITS_IS_MOVE_ASSIGNABLE_H +#define LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_IS_MOVE_ASSIGNABLE_H + +#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/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { +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>)> {}; + +template <class T> +LIBC_INLINE_VAR constexpr bool is_move_assignable_v = + is_move_assignable<T>::value; + +} // namespace cpp +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_IS_MOVE_ASSIGNABLE_H diff --git a/lib/libcxx/libc/src/__support/CPP/type_traits/is_move_constructible.h b/lib/libcxx/libc/src/__support/CPP/type_traits/is_move_constructible.h new file mode 100644 index 0000000000..c898960546 --- /dev/null +++ b/lib/libcxx/libc/src/__support/CPP/type_traits/is_move_constructible.h @@ -0,0 +1,31 @@ +//===-- is_move_constructible type_traits ------------------------*- 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_CPP_TYPE_TRAITS_IS_MOVE_CONSTRUCTIBLE_H +#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/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { +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>)> {}; + +template <class T> +LIBC_INLINE_VAR constexpr bool is_move_constructible_v = + is_move_constructible<T>::value; + +} // namespace cpp +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_IS_MOVE_CONSTRUCTIBLE_H diff --git a/lib/libcxx/libc/src/__support/CPP/type_traits/is_null_pointer.h b/lib/libcxx/libc/src/__support/CPP/type_traits/is_null_pointer.h new file mode 100644 index 0000000000..acf341311b --- /dev/null +++ b/lib/libcxx/libc/src/__support/CPP/type_traits/is_null_pointer.h @@ -0,0 +1,29 @@ +//===-- is_null_pointer type_traits -----------------------------*- 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_CPP_TYPE_TRAITS_IS_NULL_POINTER_H +#define LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_IS_NULL_POINTER_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" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { +namespace cpp { + +// is_null_pointer +using nullptr_t = decltype(nullptr); +template <class T> +struct is_null_pointer : cpp::is_same<cpp::nullptr_t, cpp::remove_cv_t<T>> {}; +template <class T> +LIBC_INLINE_VAR constexpr bool is_null_pointer_v = is_null_pointer<T>::value; + +} // namespace cpp +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_IS_NULL_POINTER_H diff --git a/lib/libcxx/libc/src/__support/CPP/type_traits/is_object.h b/lib/libcxx/libc/src/__support/CPP/type_traits/is_object.h new file mode 100644 index 0000000000..16799fb8f2 --- /dev/null +++ b/lib/libcxx/libc/src/__support/CPP/type_traits/is_object.h @@ -0,0 +1,33 @@ +//===-- is_object type_traits -----------------------------------*- 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_CPP_TYPE_TRAITS_IS_OBJECT_H +#define LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_IS_OBJECT_H + +#include "src/__support/CPP/type_traits/bool_constant.h" +#include "src/__support/CPP/type_traits/is_array.h" +#include "src/__support/CPP/type_traits/is_class.h" +#include "src/__support/CPP/type_traits/is_scalar.h" +#include "src/__support/CPP/type_traits/is_union.h" +#include "src/__support/macros/attributes.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { +namespace cpp { + +// is_object +template <class T> +struct is_object + : cpp::bool_constant<cpp::is_scalar_v<T> || cpp::is_array_v<T> || + cpp::is_union_v<T> || cpp::is_class_v<T>> {}; +template <class T> +LIBC_INLINE_VAR constexpr bool is_object_v = is_object<T>::value; + +} // namespace cpp +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_IS_OBJECT_H diff --git a/lib/libcxx/libc/src/__support/CPP/type_traits/is_pointer.h b/lib/libcxx/libc/src/__support/CPP/type_traits/is_pointer.h new file mode 100644 index 0000000000..606c8e9e8c --- /dev/null +++ b/lib/libcxx/libc/src/__support/CPP/type_traits/is_pointer.h @@ -0,0 +1,31 @@ +//===-- is_pointer type_traits ----------------------------------*- 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_CPP_TYPE_TRAITS_IS_POINTER_H +#define LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_IS_POINTER_H + +#include "src/__support/CPP/type_traits/false_type.h" +#include "src/__support/CPP/type_traits/true_type.h" +#include "src/__support/macros/attributes.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { +namespace cpp { + +// is_pointer +template <typename T> struct is_pointer : cpp::false_type {}; +template <typename T> struct is_pointer<T *> : cpp::true_type {}; +template <typename T> struct is_pointer<T *const> : cpp::true_type {}; +template <typename T> struct is_pointer<T *volatile> : cpp::true_type {}; +template <typename T> struct is_pointer<T *const volatile> : cpp::true_type {}; +template <typename T> +LIBC_INLINE_VAR constexpr bool is_pointer_v = is_pointer<T>::value; + +} // namespace cpp +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_IS_POINTER_H diff --git a/lib/libcxx/libc/src/__support/CPP/type_traits/is_reference.h b/lib/libcxx/libc/src/__support/CPP/type_traits/is_reference.h new file mode 100644 index 0000000000..12da81778f --- /dev/null +++ b/lib/libcxx/libc/src/__support/CPP/type_traits/is_reference.h @@ -0,0 +1,34 @@ +//===-- is_reference type_traits --------------------------------*- 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_CPP_TYPE_TRAITS_IS_REFERENCE_H +#define LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_IS_REFERENCE_H + +#include "src/__support/CPP/type_traits/bool_constant.h" +#include "src/__support/CPP/type_traits/false_type.h" +#include "src/__support/CPP/type_traits/true_type.h" +#include "src/__support/macros/attributes.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { +namespace cpp { + +// is_reference +#if __has_builtin(__is_reference) +template <typename T> struct is_reference : bool_constant<__is_reference(T)> {}; +#else +template <typename T> struct is_reference : public false_type {}; +template <typename T> struct is_reference<T &> : public true_type {}; +template <typename T> struct is_reference<T &&> : public true_type {}; +#endif +template <class T> +LIBC_INLINE_VAR constexpr bool is_reference_v = is_reference<T>::value; + +} // namespace cpp +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_IS_REFERENCE_H diff --git a/lib/libcxx/libc/src/__support/CPP/type_traits/is_rvalue_reference.h b/lib/libcxx/libc/src/__support/CPP/type_traits/is_rvalue_reference.h new file mode 100644 index 0000000000..998b6353af --- /dev/null +++ b/lib/libcxx/libc/src/__support/CPP/type_traits/is_rvalue_reference.h @@ -0,0 +1,35 @@ +//===-- is_rvalue_reference type_traits -------------------------*- 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_CPP_TYPE_TRAITS_IS_RVALUE_REFERENCE_H +#define LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_IS_RVALUE_REFERENCE_H + +#include "src/__support/CPP/type_traits/bool_constant.h" +#include "src/__support/CPP/type_traits/false_type.h" +#include "src/__support/CPP/type_traits/true_type.h" +#include "src/__support/macros/attributes.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { +namespace cpp { + +// is_rvalue_reference +#if __has_builtin(__is_rvalue_reference) +template <typename T> +struct is_rvalue_reference : bool_constant<__is_rvalue_reference(T)> {}; +#else +template <typename T> struct is_rvalue_reference : public false_type {}; +template <typename T> struct is_rvalue_reference<T &&> : public true_type {}; +#endif +template <class T> +LIBC_INLINE_VAR constexpr bool is_rvalue_reference_v = + is_rvalue_reference<T>::value; + +} // namespace cpp +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_IS_RVALUE_REFERENCE_H diff --git a/lib/libcxx/libc/src/__support/CPP/type_traits/is_same.h b/lib/libcxx/libc/src/__support/CPP/type_traits/is_same.h new file mode 100644 index 0000000000..306d16b86f --- /dev/null +++ b/lib/libcxx/libc/src/__support/CPP/type_traits/is_same.h @@ -0,0 +1,28 @@ +//===-- is_same type_traits -------------------------------------*- 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_CPP_TYPE_TRAITS_IS_SAME_H +#define LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_IS_SAME_H + +#include "src/__support/CPP/type_traits/false_type.h" +#include "src/__support/CPP/type_traits/true_type.h" +#include "src/__support/macros/attributes.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { +namespace cpp { + +// is_same +template <typename T, typename U> struct is_same : cpp::false_type {}; +template <typename T> struct is_same<T, T> : cpp::true_type {}; +template <typename T, typename U> +LIBC_INLINE_VAR constexpr bool is_same_v = is_same<T, U>::value; + +} // namespace cpp +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_IS_SAME_H diff --git a/lib/libcxx/libc/src/__support/CPP/type_traits/is_scalar.h b/lib/libcxx/libc/src/__support/CPP/type_traits/is_scalar.h new file mode 100644 index 0000000000..7f8a750cd7 --- /dev/null +++ b/lib/libcxx/libc/src/__support/CPP/type_traits/is_scalar.h @@ -0,0 +1,35 @@ +//===-- is_scalar type_traits -----------------------------------*- 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_CPP_TYPE_TRAITS_IS_SCALAR_H +#define LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_IS_SCALAR_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_enum.h" +#include "src/__support/CPP/type_traits/is_member_pointer.h" +#include "src/__support/CPP/type_traits/is_null_pointer.h" +#include "src/__support/CPP/type_traits/is_pointer.h" +#include "src/__support/macros/attributes.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { +namespace cpp { + +// is_scalar +template <class T> +struct is_scalar + : cpp::bool_constant<cpp::is_arithmetic_v<T> || cpp::is_enum_v<T> || + cpp::is_pointer_v<T> || cpp::is_member_pointer_v<T> || + cpp::is_null_pointer_v<T>> {}; +template <class T> +LIBC_INLINE_VAR constexpr bool is_scalar_v = is_scalar<T>::value; + +} // namespace cpp +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_IS_SCALAR_H diff --git a/lib/libcxx/libc/src/__support/CPP/type_traits/is_signed.h b/lib/libcxx/libc/src/__support/CPP/type_traits/is_signed.h new file mode 100644 index 0000000000..3f56fb38aa --- /dev/null +++ b/lib/libcxx/libc/src/__support/CPP/type_traits/is_signed.h @@ -0,0 +1,31 @@ +//===-- is_signed type_traits -----------------------------------*- 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_CPP_TYPE_TRAITS_IS_SIGNED_H +#define LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_IS_SIGNED_H + +#include "src/__support/CPP/type_traits/bool_constant.h" +#include "src/__support/CPP/type_traits/is_arithmetic.h" +#include "src/__support/macros/attributes.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { +namespace cpp { + +// is_signed +template <typename T> +struct is_signed : bool_constant<(is_arithmetic_v<T> && (T(-1) < T(0)))> { + LIBC_INLINE constexpr operator bool() const { return is_signed::value; } + LIBC_INLINE constexpr bool operator()() const { return is_signed::value; } +}; +template <typename T> +LIBC_INLINE_VAR constexpr bool is_signed_v = is_signed<T>::value; + +} // namespace cpp +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_IS_SIGNED_H diff --git a/lib/libcxx/libc/src/__support/CPP/type_traits/is_trivially_constructible.h b/lib/libcxx/libc/src/__support/CPP/type_traits/is_trivially_constructible.h new file mode 100644 index 0000000000..b801911038 --- /dev/null +++ b/lib/libcxx/libc/src/__support/CPP/type_traits/is_trivially_constructible.h @@ -0,0 +1,25 @@ +//===-- is_trivially_constructible type_traits ------------------*- 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_CPP_TYPE_TRAITS_IS_TRIVIALLY_CONSTRUCTIBLE_H +#define LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_IS_TRIVIALLY_CONSTRUCTIBLE_H + +#include "src/__support/CPP/type_traits/integral_constant.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { +namespace cpp { + +// is_trivially_constructible +template <class T, class... Args> +struct is_trivially_constructible + : integral_constant<bool, __is_trivially_constructible(T, Args...)> {}; + +} // namespace cpp +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_IS_TRIVIALLY_CONSTRUCTIBLE_H diff --git a/lib/libcxx/libc/src/__support/CPP/type_traits/is_trivially_copyable.h b/lib/libcxx/libc/src/__support/CPP/type_traits/is_trivially_copyable.h new file mode 100644 index 0000000000..a3e786fe1d --- /dev/null +++ b/lib/libcxx/libc/src/__support/CPP/type_traits/is_trivially_copyable.h @@ -0,0 +1,29 @@ +//===-- is_trivially_copyable type_traits -----------------------*- 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_CPP_TYPE_TRAITS_IS_TRIVIALLY_COPYABLE_H +#define LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_IS_TRIVIALLY_COPYABLE_H + +#include "src/__support/CPP/type_traits/integral_constant.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { +namespace cpp { + +// is_trivially_copyable +template <class T> +struct is_trivially_copyable + : public integral_constant<bool, __is_trivially_copyable(T)> {}; + +template <class T> +LIBC_INLINE_VAR constexpr bool is_trivially_copyable_v = + is_trivially_copyable<T>::value; + +} // namespace cpp +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_IS_TRIVIALLY_COPYABLE_H diff --git a/lib/libcxx/libc/src/__support/CPP/type_traits/is_trivially_destructible.h b/lib/libcxx/libc/src/__support/CPP/type_traits/is_trivially_destructible.h new file mode 100644 index 0000000000..d727a0ec3a --- /dev/null +++ b/lib/libcxx/libc/src/__support/CPP/type_traits/is_trivially_destructible.h @@ -0,0 +1,37 @@ +//===-- is_trivially_destructible type_traits -------------------*- 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_CPP_TYPE_TRAITS_IS_TRIVIALLY_DESTRUCTIBLE_H +#define LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_IS_TRIVIALLY_DESTRUCTIBLE_H + +#include "src/__support/CPP/type_traits/bool_constant.h" +#include "src/__support/CPP/type_traits/is_destructible.h" +#include "src/__support/macros/attributes.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { +namespace cpp { + +// is_trivially_destructible +#if __has_builtin(__is_trivially_destructible) +template <typename T> +struct is_trivially_destructible + : public bool_constant<__is_trivially_destructible(T)> {}; +#else +template <typename T> +struct is_trivially_destructible + : public bool_constant<cpp::is_destructible_v<T> &&__has_trivial_destructor( + T)> {}; +#endif // __has_builtin(__is_trivially_destructible) +template <typename T> +LIBC_INLINE_VAR constexpr bool is_trivially_destructible_v = + is_trivially_destructible<T>::value; + +} // namespace cpp +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_IS_TRIVIALLY_DESTRUCTIBLE_H diff --git a/lib/libcxx/libc/src/__support/CPP/type_traits/is_union.h b/lib/libcxx/libc/src/__support/CPP/type_traits/is_union.h new file mode 100644 index 0000000000..00ca11a351 --- /dev/null +++ b/lib/libcxx/libc/src/__support/CPP/type_traits/is_union.h @@ -0,0 +1,26 @@ +//===-- is_union type_traits ------------------------------------*- 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_CPP_TYPE_TRAITS_IS_UNION_H +#define LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_IS_UNION_H + +#include "src/__support/CPP/type_traits/bool_constant.h" +#include "src/__support/macros/attributes.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { +namespace cpp { + +// is_union +template <class T> struct is_union : bool_constant<__is_union(T)> {}; +template <typename T> +LIBC_INLINE_VAR constexpr bool is_union_v = is_union<T>::value; + +} // namespace cpp +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_IS_UNION_H diff --git a/lib/libcxx/libc/src/__support/CPP/type_traits/is_unsigned.h b/lib/libcxx/libc/src/__support/CPP/type_traits/is_unsigned.h new file mode 100644 index 0000000000..eed519b1c0 --- /dev/null +++ b/lib/libcxx/libc/src/__support/CPP/type_traits/is_unsigned.h @@ -0,0 +1,31 @@ +//===-- is_unsigned type_traits ---------------------------------*- 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_CPP_TYPE_TRAITS_IS_UNSIGNED_H +#define LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_IS_UNSIGNED_H + +#include "src/__support/CPP/type_traits/bool_constant.h" +#include "src/__support/CPP/type_traits/is_arithmetic.h" +#include "src/__support/macros/attributes.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { +namespace cpp { + +// is_unsigned +template <typename T> +struct is_unsigned : bool_constant<(is_arithmetic_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; } +}; +template <typename T> +LIBC_INLINE_VAR constexpr bool is_unsigned_v = is_unsigned<T>::value; + +} // namespace cpp +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_IS_UNSIGNED_H diff --git a/lib/libcxx/libc/src/__support/CPP/type_traits/is_void.h b/lib/libcxx/libc/src/__support/CPP/type_traits/is_void.h new file mode 100644 index 0000000000..30459dcf91 --- /dev/null +++ b/lib/libcxx/libc/src/__support/CPP/type_traits/is_void.h @@ -0,0 +1,27 @@ +//===-- is_void type_traits -------------------------------------*- 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_CPP_TYPE_TRAITS_IS_VOID_H +#define LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_IS_VOID_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" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { +namespace cpp { + +// is_void +template <typename T> struct is_void : is_same<void, remove_cv_t<T>> {}; +template <typename T> +LIBC_INLINE_VAR constexpr bool is_void_v = is_void<T>::value; + +} // namespace cpp +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_IS_VOID_H diff --git a/lib/libcxx/libc/src/__support/CPP/type_traits/make_signed.h b/lib/libcxx/libc/src/__support/CPP/type_traits/make_signed.h new file mode 100644 index 0000000000..00bc6be8fc --- /dev/null +++ b/lib/libcxx/libc/src/__support/CPP/type_traits/make_signed.h @@ -0,0 +1,41 @@ +//===-- make_signed type_traits ---------------------------------*- 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_CPP_TYPE_TRAITS_MAKE_SIGNED_H +#define LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_MAKE_SIGNED_H + +#include "src/__support/CPP/type_traits/type_identity.h" +#include "src/__support/macros/config.h" +#include "src/__support/macros/properties/types.h" // LIBC_TYPES_HAS_INT128 + +namespace LIBC_NAMESPACE_DECL { +namespace cpp { + +// make_signed +template <typename T> struct make_signed; +template <> struct make_signed<char> : type_identity<char> {}; +template <> struct make_signed<signed char> : type_identity<char> {}; +template <> struct make_signed<short> : type_identity<short> {}; +template <> struct make_signed<int> : type_identity<int> {}; +template <> struct make_signed<long> : type_identity<long> {}; +template <> struct make_signed<long long> : type_identity<long long> {}; +template <> struct make_signed<unsigned char> : type_identity<char> {}; +template <> struct make_signed<unsigned short> : type_identity<short> {}; +template <> struct make_signed<unsigned int> : type_identity<int> {}; +template <> struct make_signed<unsigned long> : type_identity<long> {}; +template <> +struct make_signed<unsigned long long> : type_identity<long long> {}; +#ifdef LIBC_TYPES_HAS_INT128 +template <> struct make_signed<__int128_t> : type_identity<__int128_t> {}; +template <> struct make_signed<__uint128_t> : type_identity<__int128_t> {}; +#endif +template <typename T> using make_signed_t = typename make_signed<T>::type; + +} // namespace cpp +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_MAKE_SIGNED_H diff --git a/lib/libcxx/libc/src/__support/CPP/type_traits/make_unsigned.h b/lib/libcxx/libc/src/__support/CPP/type_traits/make_unsigned.h new file mode 100644 index 0000000000..e5f60ae665 --- /dev/null +++ b/lib/libcxx/libc/src/__support/CPP/type_traits/make_unsigned.h @@ -0,0 +1,46 @@ +//===-- make_unsigned type_traits -------------------------------*- 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_CPP_TYPE_TRAITS_MAKE_UNSIGNED_H +#define LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_MAKE_UNSIGNED_H + +#include "src/__support/CPP/type_traits/type_identity.h" +#include "src/__support/macros/config.h" +#include "src/__support/macros/properties/types.h" // LIBC_TYPES_HAS_INT128 + +namespace LIBC_NAMESPACE_DECL { +namespace cpp { + +// make_unsigned + +template <typename T> struct make_unsigned; +template <> struct make_unsigned<char> : type_identity<unsigned char> {}; +template <> struct make_unsigned<signed char> : type_identity<unsigned char> {}; +template <> struct make_unsigned<short> : type_identity<unsigned short> {}; +template <> struct make_unsigned<int> : type_identity<unsigned int> {}; +template <> struct make_unsigned<long> : type_identity<unsigned long> {}; +template <> +struct make_unsigned<long long> : type_identity<unsigned long long> {}; +template <> +struct make_unsigned<unsigned char> : type_identity<unsigned char> {}; +template <> +struct make_unsigned<unsigned short> : type_identity<unsigned short> {}; +template <> struct make_unsigned<unsigned int> : type_identity<unsigned int> {}; +template <> +struct make_unsigned<unsigned long> : type_identity<unsigned long> {}; +template <> +struct make_unsigned<unsigned long long> : type_identity<unsigned long long> {}; +#ifdef LIBC_TYPES_HAS_INT128 +template <> struct make_unsigned<__int128_t> : type_identity<__uint128_t> {}; +template <> struct make_unsigned<__uint128_t> : type_identity<__uint128_t> {}; +#endif +template <typename T> using make_unsigned_t = typename make_unsigned<T>::type; + +} // namespace cpp +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_MAKE_UNSIGNED_H diff --git a/lib/libcxx/libc/src/__support/CPP/type_traits/remove_all_extents.h b/lib/libcxx/libc/src/__support/CPP/type_traits/remove_all_extents.h new file mode 100644 index 0000000000..bc577ca6f4 --- /dev/null +++ b/lib/libcxx/libc/src/__support/CPP/type_traits/remove_all_extents.h @@ -0,0 +1,41 @@ +//===-- remove_all_extents type_traits --------------------------*- 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_CPP_TYPE_TRAITS_REMOVE_ALL_EXTENTS_H +#define LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_REMOVE_ALL_EXTENTS_H + +#include "src/__support/CPP/type_traits/type_identity.h" +#include "src/__support/macros/config.h" + +#include <stddef.h> // size_t + +namespace LIBC_NAMESPACE_DECL { +namespace cpp { + +// remove_all_extents +#if __has_builtin(__remove_all_extents) +template <typename T> using remove_all_extents_t = __remove_all_extents(T); +template <typename T> +struct remove_all_extents : cpp::type_identity<remove_all_extents_t<T>> {}; +#else +template <typename T> struct remove_all_extents { + using type = T; +}; +template <typename T> struct remove_all_extents<T[]> { + using type = typename remove_all_extents<T>::type; +}; +template <typename T, size_t _Np> struct remove_all_extents<T[_Np]> { + using type = typename remove_all_extents<T>::type; +}; +template <typename T> +using remove_all_extents_t = typename remove_all_extents<T>::type; +#endif + +} // namespace cpp +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_REMOVE_ALL_EXTENTS_H diff --git a/lib/libcxx/libc/src/__support/CPP/type_traits/remove_cv.h b/lib/libcxx/libc/src/__support/CPP/type_traits/remove_cv.h new file mode 100644 index 0000000000..2e843e0b43 --- /dev/null +++ b/lib/libcxx/libc/src/__support/CPP/type_traits/remove_cv.h @@ -0,0 +1,28 @@ +//===-- remove_cv type_traits -----------------------------------*- 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_CPP_TYPE_TRAITS_REMOVE_CV_H +#define LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_REMOVE_CV_H + +#include "src/__support/CPP/type_traits/type_identity.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { +namespace cpp { + +// remove_cv +template <class T> struct remove_cv : cpp::type_identity<T> {}; +template <class T> struct remove_cv<const T> : cpp::type_identity<T> {}; +template <class T> struct remove_cv<volatile T> : cpp::type_identity<T> {}; +template <class T> +struct remove_cv<const volatile T> : cpp::type_identity<T> {}; +template <class T> using remove_cv_t = typename remove_cv<T>::type; + +} // namespace cpp +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_REMOVE_CV_H diff --git a/lib/libcxx/libc/src/__support/CPP/type_traits/remove_cvref.h b/lib/libcxx/libc/src/__support/CPP/type_traits/remove_cvref.h new file mode 100644 index 0000000000..27591783fd --- /dev/null +++ b/lib/libcxx/libc/src/__support/CPP/type_traits/remove_cvref.h @@ -0,0 +1,27 @@ +//===-- remove_cvref type_traits --------------------------------*- 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_CPP_TYPE_TRAITS_REMOVE_CVREF_H +#define LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_REMOVE_CVREF_H + +#include "src/__support/CPP/type_traits/remove_cv.h" +#include "src/__support/CPP/type_traits/remove_reference.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { +namespace cpp { + +// remove_cvref +template <typename T> struct remove_cvref { + using type = remove_cv_t<remove_reference_t<T>>; +}; +template <typename T> using remove_cvref_t = typename remove_cvref<T>::type; + +} // namespace cpp +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_REMOVE_CVREF_H diff --git a/lib/libcxx/libc/src/__support/CPP/type_traits/remove_extent.h b/lib/libcxx/libc/src/__support/CPP/type_traits/remove_extent.h new file mode 100644 index 0000000000..4f5ffd3453 --- /dev/null +++ b/lib/libcxx/libc/src/__support/CPP/type_traits/remove_extent.h @@ -0,0 +1,28 @@ +//===-- remove_extent type_traits -------------------------------*- 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_CPP_TYPE_TRAITS_REMOVE_EXTENT_H +#define LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_REMOVE_EXTENT_H + +#include "src/__support/CPP/type_traits/type_identity.h" +#include "src/__support/macros/config.h" +#include "stddef.h" // size_t + +namespace LIBC_NAMESPACE_DECL { +namespace cpp { + +// remove_extent +template <class T> struct remove_extent : cpp::type_identity<T> {}; +template <class T> struct remove_extent<T[]> : cpp::type_identity<T> {}; +template <class T, size_t N> +struct remove_extent<T[N]> : cpp::type_identity<T> {}; +template <class T> using remove_extent_t = typename remove_extent<T>::type; + +} // namespace cpp +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_REMOVE_EXTENT_H diff --git a/lib/libcxx/libc/src/__support/CPP/type_traits/remove_reference.h b/lib/libcxx/libc/src/__support/CPP/type_traits/remove_reference.h new file mode 100644 index 0000000000..26ded0879f --- /dev/null +++ b/lib/libcxx/libc/src/__support/CPP/type_traits/remove_reference.h @@ -0,0 +1,27 @@ +//===-- remove_reference type_traits ----------------------------*- 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_CPP_TYPE_TRAITS_REMOVE_REFERENCE_H +#define LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_REMOVE_REFERENCE_H + +#include "src/__support/CPP/type_traits/type_identity.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { +namespace cpp { + +// remove_reference +template <class T> struct remove_reference : cpp::type_identity<T> {}; +template <class T> struct remove_reference<T &> : cpp::type_identity<T> {}; +template <class T> struct remove_reference<T &&> : cpp::type_identity<T> {}; +template <class T> +using remove_reference_t = typename remove_reference<T>::type; + +} // namespace cpp +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_REMOVE_REFERENCE_H diff --git a/lib/libcxx/libc/src/__support/CPP/type_traits/true_type.h b/lib/libcxx/libc/src/__support/CPP/type_traits/true_type.h new file mode 100644 index 0000000000..55f8a535d0 --- /dev/null +++ b/lib/libcxx/libc/src/__support/CPP/type_traits/true_type.h @@ -0,0 +1,23 @@ +//===-- true_type type_traits -----------------------------------*- 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_CPP_TYPE_TRAITS_TRUE_TYPE_H +#define LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_TRUE_TYPE_H + +#include "src/__support/CPP/type_traits/bool_constant.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { +namespace cpp { + +// true_type +using true_type = cpp::bool_constant<true>; + +} // namespace cpp +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_TRUE_TYPE_H diff --git a/lib/libcxx/libc/src/__support/CPP/type_traits/type_identity.h b/lib/libcxx/libc/src/__support/CPP/type_traits/type_identity.h new file mode 100644 index 0000000000..304a1ed2ce --- /dev/null +++ b/lib/libcxx/libc/src/__support/CPP/type_traits/type_identity.h @@ -0,0 +1,24 @@ +//===-- type_identity type_traits -------------------------------*- 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_CPP_TYPE_TRAITS_TYPE_IDENTITY_H +#define LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_TYPE_IDENTITY_H + +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { +namespace cpp { + +// type_identity +template <typename T> struct type_identity { + using type = T; +}; + +} // namespace cpp +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_TYPE_IDENTITY_H diff --git a/lib/libcxx/libc/src/__support/CPP/type_traits/void_t.h b/lib/libcxx/libc/src/__support/CPP/type_traits/void_t.h new file mode 100644 index 0000000000..9018860a83 --- /dev/null +++ b/lib/libcxx/libc/src/__support/CPP/type_traits/void_t.h @@ -0,0 +1,29 @@ +//===-- void_t type_traits --------------------------------------*- 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_CPP_TYPE_TRAITS_VOID_T_H +#define LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_VOID_T_H + +#include "src/__support/CPP/type_traits/type_identity.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { +namespace cpp { + +// void_t + +namespace detail { +template <typename... Ts> struct make_void : cpp::type_identity<void> {}; +} // namespace detail + +template <typename... Ts> +using void_t = typename detail::make_void<Ts...>::type; + +} // namespace cpp +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_CPP_TYPE_TRAITS_VOID_T_H diff --git a/lib/libcxx/libc/src/__support/CPP/utility.h b/lib/libcxx/libc/src/__support/CPP/utility.h new file mode 100644 index 0000000000..083b4877c3 --- /dev/null +++ b/lib/libcxx/libc/src/__support/CPP/utility.h @@ -0,0 +1,18 @@ +//===-- Analogous to <utility> ----------------------------------*- 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_CPP_UTILITY_H +#define LLVM_LIBC_SRC___SUPPORT_CPP_UTILITY_H + +#include "src/__support/CPP/utility/declval.h" +#include "src/__support/CPP/utility/forward.h" +#include "src/__support/CPP/utility/in_place.h" +#include "src/__support/CPP/utility/integer_sequence.h" +#include "src/__support/CPP/utility/move.h" + +#endif // LLVM_LIBC_SRC___SUPPORT_CPP_UTILITY_H diff --git a/lib/libcxx/libc/src/__support/CPP/utility/declval.h b/lib/libcxx/libc/src/__support/CPP/utility/declval.h new file mode 100644 index 0000000000..9b963b9220 --- /dev/null +++ b/lib/libcxx/libc/src/__support/CPP/utility/declval.h @@ -0,0 +1,27 @@ +//===-- declval utility -----------------------------------------*- 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_CPP_UTILITY_DECLVAL_H +#define LLVM_LIBC_SRC___SUPPORT_CPP_UTILITY_DECLVAL_H + +#include "src/__support/CPP/type_traits/add_rvalue_reference.h" +#include "src/__support/CPP/type_traits/always_false.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { +namespace cpp { + +// declval +template <typename T> cpp::add_rvalue_reference_t<T> declval() { + static_assert(cpp::always_false<T>, + "declval not allowed in an evaluated context"); +} + +} // namespace cpp +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_CPP_UTILITY_DECLVAL_H diff --git a/lib/libcxx/libc/src/__support/CPP/utility/forward.h b/lib/libcxx/libc/src/__support/CPP/utility/forward.h new file mode 100644 index 0000000000..085b3d16f9 --- /dev/null +++ b/lib/libcxx/libc/src/__support/CPP/utility/forward.h @@ -0,0 +1,35 @@ +//===-- forward utility -----------------------------------------*- 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_CPP_UTILITY_FORWARD_H +#define LLVM_LIBC_SRC___SUPPORT_CPP_UTILITY_FORWARD_H + +#include "src/__support/CPP/type_traits/is_lvalue_reference.h" +#include "src/__support/CPP/type_traits/remove_reference.h" +#include "src/__support/macros/attributes.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { +namespace cpp { + +// forward +template <typename T> +LIBC_INLINE constexpr T &&forward(remove_reference_t<T> &value) { + return static_cast<T &&>(value); +} + +template <typename T> +LIBC_INLINE constexpr T &&forward(remove_reference_t<T> &&value) { + static_assert(!is_lvalue_reference_v<T>, + "cannot forward an rvalue as an lvalue"); + return static_cast<T &&>(value); +} + +} // namespace cpp +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_CPP_UTILITY_FORWARD_H diff --git a/lib/libcxx/libc/src/__support/CPP/utility/in_place.h b/lib/libcxx/libc/src/__support/CPP/utility/in_place.h new file mode 100644 index 0000000000..3967eb1c53 --- /dev/null +++ b/lib/libcxx/libc/src/__support/CPP/utility/in_place.h @@ -0,0 +1,39 @@ +//===-- in_place utility ----------------------------------------*- 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_CPP_UTILITY_IN_PLACE_H +#define LLVM_LIBC_SRC___SUPPORT_CPP_UTILITY_IN_PLACE_H + +#include "src/__support/macros/attributes.h" // LIBC_INLINE, LIBC_INLINE_VAR +#include "src/__support/macros/config.h" + +#include <stddef.h> // size_t + +namespace LIBC_NAMESPACE_DECL { +namespace cpp { + +// in_place +struct in_place_t { + LIBC_INLINE explicit in_place_t() = default; +}; +LIBC_INLINE_VAR constexpr in_place_t in_place{}; + +template <class T> struct in_place_type_t { + LIBC_INLINE explicit in_place_type_t() = default; +}; +template <class T> LIBC_INLINE_VAR constexpr in_place_type_t<T> in_place_type{}; + +template <size_t IDX> struct in_place_index_t { + LIBC_INLINE explicit in_place_index_t() = default; +}; +template <size_t IDX> +LIBC_INLINE_VAR constexpr in_place_index_t<IDX> in_place_index{}; + +} // namespace cpp +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_CPP_UTILITY_IN_PLACE_H diff --git a/lib/libcxx/libc/src/__support/CPP/utility/integer_sequence.h b/lib/libcxx/libc/src/__support/CPP/utility/integer_sequence.h new file mode 100644 index 0000000000..06643d505a --- /dev/null +++ b/lib/libcxx/libc/src/__support/CPP/utility/integer_sequence.h @@ -0,0 +1,40 @@ +//===-- integer_sequence utility --------------------------------*- 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_CPP_UTILITY_INTEGER_SEQUENCE_H +#define LLVM_LIBC_SRC___SUPPORT_CPP_UTILITY_INTEGER_SEQUENCE_H + +#include "src/__support/CPP/type_traits/is_integral.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { +namespace cpp { + +// integer_sequence +template <typename T, T... Ints> struct integer_sequence { + static_assert(cpp::is_integral_v<T>); + template <T Next> using append = integer_sequence<T, Ints..., Next>; +}; + +namespace detail { +template <typename T, int N> struct make_integer_sequence { + using type = + typename make_integer_sequence<T, N - 1>::type::template append<N>; +}; +template <typename T> struct make_integer_sequence<T, -1> { + using type = integer_sequence<T>; +}; +} // namespace detail + +template <typename T, int N> +using make_integer_sequence = + typename detail::make_integer_sequence<T, N - 1>::type; + +} // namespace cpp +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_CPP_UTILITY_INTEGER_SEQUENCE_H diff --git a/lib/libcxx/libc/src/__support/CPP/utility/move.h b/lib/libcxx/libc/src/__support/CPP/utility/move.h new file mode 100644 index 0000000000..b61f723e8d --- /dev/null +++ b/lib/libcxx/libc/src/__support/CPP/utility/move.h @@ -0,0 +1,27 @@ +//===-- move utility --------------------------------------------*- 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_CPP_UTILITY_MOVE_H +#define LLVM_LIBC_SRC___SUPPORT_CPP_UTILITY_MOVE_H + +#include "src/__support/CPP/type_traits/remove_reference.h" +#include "src/__support/macros/attributes.h" // LIBC_INLINE +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { +namespace cpp { + +// move +template <class T> +LIBC_INLINE constexpr cpp::remove_reference_t<T> &&move(T &&t) { + return static_cast<typename cpp::remove_reference_t<T> &&>(t); +} + +} // namespace cpp +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_CPP_UTILITY_MOVE_H diff --git a/lib/libcxx/libc/src/__support/FPUtil/FPBits.h b/lib/libcxx/libc/src/__support/FPUtil/FPBits.h new file mode 100644 index 0000000000..90b6e406e0 --- /dev/null +++ b/lib/libcxx/libc/src/__support/FPUtil/FPBits.h @@ -0,0 +1,846 @@ +//===-- Abstract class for bit manipulation of float numbers. ---*- 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 +// +//===----------------------------------------------------------------------===// + +// ----------------------------------------------------------------------------- +// **** WARNING **** +// This file is shared with libc++. You should also be careful when adding +// dependencies to this file, since it needs to build for all libc++ targets. +// ----------------------------------------------------------------------------- + +#ifndef LLVM_LIBC_SRC___SUPPORT_FPUTIL_FPBITS_H +#define LLVM_LIBC_SRC___SUPPORT_FPUTIL_FPBITS_H + +#include "src/__support/CPP/bit.h" +#include "src/__support/CPP/type_traits.h" +#include "src/__support/common.h" +#include "src/__support/libc_assert.h" // LIBC_ASSERT +#include "src/__support/macros/attributes.h" // LIBC_INLINE, LIBC_INLINE_VAR +#include "src/__support/macros/config.h" +#include "src/__support/macros/properties/types.h" // LIBC_TYPES_HAS_FLOAT128 +#include "src/__support/math_extras.h" // mask_trailing_ones +#include "src/__support/sign.h" // Sign +#include "src/__support/uint128.h" + +#include <stdint.h> + +namespace LIBC_NAMESPACE_DECL { +namespace fputil { + +// The supported floating point types. +enum class FPType { + IEEE754_Binary16, + IEEE754_Binary32, + IEEE754_Binary64, + IEEE754_Binary128, + X86_Binary80, +}; + +// The classes hierarchy is as follows: +// +// ┌───────────────────┐ +// │ FPLayout<FPType> │ +// └─────────▲─────────┘ +// │ +// ┌─────────┴─────────┐ +// │ FPStorage<FPType> │ +// └─────────▲─────────┘ +// │ +// ┌────────────┴─────────────┐ +// │ │ +// ┌────────┴─────────┐ ┌──────────────┴──────────────────┐ +// │ FPRepSem<FPType> │ │ FPRepSem<FPType::X86_Binary80 │ +// └────────▲─────────┘ └──────────────▲──────────────────┘ +// │ │ +// └────────────┬─────────────┘ +// │ +// ┌───────┴───────┐ +// │ FPRepImpl<T> │ +// └───────▲───────┘ +// │ +// ┌────────┴────────┐ +// ┌─────┴─────┐ ┌─────┴─────┐ +// │ FPRep<T> │ │ FPBits<T> │ +// └───────────┘ └───────────┘ +// +// - 'FPLayout' defines only a few constants, namely the 'StorageType' and +// length of the sign, the exponent, fraction and significand parts. +// - 'FPStorage' builds more constants on top of those from 'FPLayout' like +// exponent bias and masks. It also holds the bit representation of the +// floating point as a 'StorageType' type and defines tools to assemble or +// test these parts. +// - 'FPRepSem' defines functions to interact semantically with the floating +// point representation. The default implementation is the one for 'IEEE754', +// a specialization is provided for X86 Extended Precision. +// - 'FPRepImpl' derives from 'FPRepSem' and adds functions that are common to +// all implementations or build on the ones in 'FPRepSem'. +// - 'FPRep' exposes all functions from 'FPRepImpl' and returns 'FPRep' +// instances when using Builders (static functions to create values). +// - 'FPBits' exposes all the functions from 'FPRepImpl' but operates on the +// native C++ floating point type instead of 'FPType'. An additional 'get_val' +// function allows getting the C++ floating point type value back. Builders +// called from 'FPBits' return 'FPBits' instances. + +namespace internal { + +// Defines the layout (sign, exponent, significand) of a floating point type in +// memory. It also defines its associated StorageType, i.e., the unsigned +// integer type used to manipulate its representation. +// Additionally we provide the fractional part length, i.e., the number of bits +// after the decimal dot when the number is in normal form. +template <FPType> struct FPLayout {}; + +template <> struct FPLayout<FPType::IEEE754_Binary16> { + using StorageType = uint16_t; + LIBC_INLINE_VAR static constexpr int SIGN_LEN = 1; + LIBC_INLINE_VAR static constexpr int EXP_LEN = 5; + LIBC_INLINE_VAR static constexpr int SIG_LEN = 10; + LIBC_INLINE_VAR static constexpr int FRACTION_LEN = SIG_LEN; +}; + +template <> struct FPLayout<FPType::IEEE754_Binary32> { + using StorageType = uint32_t; + LIBC_INLINE_VAR static constexpr int SIGN_LEN = 1; + LIBC_INLINE_VAR static constexpr int EXP_LEN = 8; + LIBC_INLINE_VAR static constexpr int SIG_LEN = 23; + LIBC_INLINE_VAR static constexpr int FRACTION_LEN = SIG_LEN; +}; + +template <> struct FPLayout<FPType::IEEE754_Binary64> { + using StorageType = uint64_t; + LIBC_INLINE_VAR static constexpr int SIGN_LEN = 1; + LIBC_INLINE_VAR static constexpr int EXP_LEN = 11; + LIBC_INLINE_VAR static constexpr int SIG_LEN = 52; + LIBC_INLINE_VAR static constexpr int FRACTION_LEN = SIG_LEN; +}; + +template <> struct FPLayout<FPType::IEEE754_Binary128> { + using StorageType = UInt128; + LIBC_INLINE_VAR static constexpr int SIGN_LEN = 1; + LIBC_INLINE_VAR static constexpr int EXP_LEN = 15; + LIBC_INLINE_VAR static constexpr int SIG_LEN = 112; + LIBC_INLINE_VAR static constexpr int FRACTION_LEN = SIG_LEN; +}; + +template <> struct FPLayout<FPType::X86_Binary80> { +#if __SIZEOF_LONG_DOUBLE__ == 12 + using StorageType = UInt<__SIZEOF_LONG_DOUBLE__ * CHAR_BIT>; +#else + using StorageType = UInt128; +#endif + LIBC_INLINE_VAR static constexpr int SIGN_LEN = 1; + LIBC_INLINE_VAR static constexpr int EXP_LEN = 15; + LIBC_INLINE_VAR static constexpr int SIG_LEN = 64; + LIBC_INLINE_VAR static constexpr int FRACTION_LEN = SIG_LEN - 1; +}; + +// FPStorage derives useful constants from the FPLayout above. +template <FPType fp_type> struct FPStorage : public FPLayout<fp_type> { + using UP = FPLayout<fp_type>; + + using UP::EXP_LEN; // The number of bits for the *exponent* part + using UP::SIG_LEN; // The number of bits for the *significand* part + using UP::SIGN_LEN; // The number of bits for the *sign* part + // For convenience, the sum of `SIG_LEN`, `EXP_LEN`, and `SIGN_LEN`. + LIBC_INLINE_VAR static constexpr int TOTAL_LEN = SIGN_LEN + EXP_LEN + SIG_LEN; + + // The number of bits after the decimal dot when the number is in normal form. + using UP::FRACTION_LEN; + + // An unsigned integer that is wide enough to contain all of the floating + // point bits. + using StorageType = typename UP::StorageType; + + // The number of bits in StorageType. + LIBC_INLINE_VAR static constexpr int STORAGE_LEN = + sizeof(StorageType) * CHAR_BIT; + static_assert(STORAGE_LEN >= TOTAL_LEN); + + // The exponent bias. Always positive. + LIBC_INLINE_VAR static constexpr int32_t EXP_BIAS = + (1U << (EXP_LEN - 1U)) - 1U; + static_assert(EXP_BIAS > 0); + + // The bit pattern that keeps only the *significand* part. + LIBC_INLINE_VAR static constexpr StorageType SIG_MASK = + mask_trailing_ones<StorageType, SIG_LEN>(); + // The bit pattern that keeps only the *exponent* part. + LIBC_INLINE_VAR static constexpr StorageType EXP_MASK = + mask_trailing_ones<StorageType, EXP_LEN>() << SIG_LEN; + // The bit pattern that keeps only the *sign* part. + LIBC_INLINE_VAR static constexpr StorageType SIGN_MASK = + mask_trailing_ones<StorageType, SIGN_LEN>() << (EXP_LEN + SIG_LEN); + // The bit pattern that keeps only the *exponent + significand* part. + LIBC_INLINE_VAR static constexpr StorageType EXP_SIG_MASK = + mask_trailing_ones<StorageType, EXP_LEN + SIG_LEN>(); + // The bit pattern that keeps only the *sign + exponent + significand* part. + LIBC_INLINE_VAR static constexpr StorageType FP_MASK = + mask_trailing_ones<StorageType, TOTAL_LEN>(); + // The bit pattern that keeps only the *fraction* part. + // i.e., the *significand* without the leading one. + LIBC_INLINE_VAR static constexpr StorageType FRACTION_MASK = + mask_trailing_ones<StorageType, FRACTION_LEN>(); + + static_assert((SIG_MASK & EXP_MASK & SIGN_MASK) == 0, "masks disjoint"); + static_assert((SIG_MASK | EXP_MASK | SIGN_MASK) == FP_MASK, "masks cover"); + +protected: + // Merge bits from 'a' and 'b' values according to 'mask'. + // Use 'a' bits when corresponding 'mask' bits are zeroes and 'b' bits when + // corresponding bits are ones. + LIBC_INLINE static constexpr StorageType merge(StorageType a, StorageType b, + StorageType mask) { + // https://graphics.stanford.edu/~seander/bithacks.html#MaskedMerge + return a ^ ((a ^ b) & mask); + } + + // A stongly typed integer that prevents mixing and matching integers with + // different semantics. + template <typename T> struct TypedInt { + using value_type = T; + LIBC_INLINE constexpr explicit TypedInt(T value) : value(value) {} + LIBC_INLINE constexpr TypedInt(const TypedInt &value) = default; + LIBC_INLINE constexpr TypedInt &operator=(const TypedInt &value) = default; + + LIBC_INLINE constexpr explicit operator T() const { return value; } + + LIBC_INLINE constexpr StorageType to_storage_type() const { + return StorageType(value); + } + + LIBC_INLINE friend constexpr bool operator==(TypedInt a, TypedInt b) { + return a.value == b.value; + } + LIBC_INLINE friend constexpr bool operator!=(TypedInt a, TypedInt b) { + return a.value != b.value; + } + + protected: + T value; + }; + + // An opaque type to store a floating point exponent. + // We define special values but it is valid to create arbitrary values as long + // as they are in the range [min, max]. + struct Exponent : public TypedInt<int32_t> { + using UP = TypedInt<int32_t>; + using UP::UP; + LIBC_INLINE static constexpr auto subnormal() { + return Exponent(-EXP_BIAS); + } + LIBC_INLINE static constexpr auto min() { return Exponent(1 - EXP_BIAS); } + LIBC_INLINE static constexpr auto zero() { return Exponent(0); } + LIBC_INLINE static constexpr auto max() { return Exponent(EXP_BIAS); } + LIBC_INLINE static constexpr auto inf() { return Exponent(EXP_BIAS + 1); } + }; + + // An opaque type to store a floating point biased exponent. + // We define special values but it is valid to create arbitrary values as long + // as they are in the range [zero, bits_all_ones]. + // Values greater than bits_all_ones are truncated. + struct BiasedExponent : public TypedInt<uint32_t> { + using UP = TypedInt<uint32_t>; + using UP::UP; + + LIBC_INLINE constexpr BiasedExponent(Exponent exp) + : UP(static_cast<int32_t>(exp) + EXP_BIAS) {} + + // Cast operator to get convert from BiasedExponent to Exponent. + LIBC_INLINE constexpr operator Exponent() const { + return Exponent(UP::value - EXP_BIAS); + } + + LIBC_INLINE constexpr BiasedExponent &operator++() { + LIBC_ASSERT(*this != BiasedExponent(Exponent::inf())); + ++UP::value; + return *this; + } + + LIBC_INLINE constexpr BiasedExponent &operator--() { + LIBC_ASSERT(*this != BiasedExponent(Exponent::subnormal())); + --UP::value; + return *this; + } + }; + + // An opaque type to store a floating point significand. + // We define special values but it is valid to create arbitrary values as long + // as they are in the range [zero, bits_all_ones]. + // Note that the semantics of the Significand are implementation dependent. + // Values greater than bits_all_ones are truncated. + struct Significand : public TypedInt<StorageType> { + using UP = TypedInt<StorageType>; + using UP::UP; + + LIBC_INLINE friend constexpr Significand operator|(const Significand a, + const Significand b) { + return Significand( + StorageType(a.to_storage_type() | b.to_storage_type())); + } + LIBC_INLINE friend constexpr Significand operator^(const Significand a, + const Significand b) { + return Significand( + StorageType(a.to_storage_type() ^ b.to_storage_type())); + } + LIBC_INLINE friend constexpr Significand operator>>(const Significand a, + int shift) { + return Significand(StorageType(a.to_storage_type() >> shift)); + } + + LIBC_INLINE static constexpr auto zero() { + return Significand(StorageType(0)); + } + LIBC_INLINE static constexpr auto lsb() { + return Significand(StorageType(1)); + } + LIBC_INLINE static constexpr auto msb() { + return Significand(StorageType(1) << (SIG_LEN - 1)); + } + LIBC_INLINE static constexpr auto bits_all_ones() { + return Significand(SIG_MASK); + } + }; + + LIBC_INLINE static constexpr StorageType encode(BiasedExponent exp) { + return (exp.to_storage_type() << SIG_LEN) & EXP_MASK; + } + + LIBC_INLINE static constexpr StorageType encode(Significand value) { + return value.to_storage_type() & SIG_MASK; + } + + LIBC_INLINE static constexpr StorageType encode(BiasedExponent exp, + Significand sig) { + return encode(exp) | encode(sig); + } + + LIBC_INLINE static constexpr StorageType encode(Sign sign, BiasedExponent exp, + Significand sig) { + if (sign.is_neg()) + return SIGN_MASK | encode(exp, sig); + return encode(exp, sig); + } + + // The floating point number representation as an unsigned integer. + StorageType bits{}; + + LIBC_INLINE constexpr FPStorage() : bits(0) {} + LIBC_INLINE constexpr FPStorage(StorageType value) : bits(value) {} + + // Observers + LIBC_INLINE constexpr StorageType exp_bits() const { return bits & EXP_MASK; } + LIBC_INLINE constexpr StorageType sig_bits() const { return bits & SIG_MASK; } + LIBC_INLINE constexpr StorageType exp_sig_bits() const { + return bits & EXP_SIG_MASK; + } + + // Parts + LIBC_INLINE constexpr BiasedExponent biased_exponent() const { + return BiasedExponent(static_cast<uint32_t>(exp_bits() >> SIG_LEN)); + } + LIBC_INLINE constexpr void set_biased_exponent(BiasedExponent biased) { + bits = merge(bits, encode(biased), EXP_MASK); + } + +public: + LIBC_INLINE constexpr Sign sign() const { + return (bits & SIGN_MASK) ? Sign::NEG : Sign::POS; + } + LIBC_INLINE constexpr void set_sign(Sign signVal) { + if (sign() != signVal) + bits ^= SIGN_MASK; + } +}; + +// This layer defines all functions that are specific to how the the floating +// point type is encoded. It enables constructions, modification and observation +// of values manipulated as 'StorageType'. +template <FPType fp_type, typename RetT> +struct FPRepSem : public FPStorage<fp_type> { + using UP = FPStorage<fp_type>; + using typename UP::StorageType; + using UP::FRACTION_LEN; + using UP::FRACTION_MASK; + +protected: + using typename UP::Exponent; + using typename UP::Significand; + using UP::bits; + using UP::encode; + using UP::exp_bits; + using UP::exp_sig_bits; + using UP::sig_bits; + using UP::UP; + +public: + // Builders + LIBC_INLINE static constexpr RetT zero(Sign sign = Sign::POS) { + return RetT(encode(sign, Exponent::subnormal(), Significand::zero())); + } + LIBC_INLINE static constexpr RetT one(Sign sign = Sign::POS) { + return RetT(encode(sign, Exponent::zero(), Significand::zero())); + } + LIBC_INLINE static constexpr RetT min_subnormal(Sign sign = Sign::POS) { + return RetT(encode(sign, Exponent::subnormal(), Significand::lsb())); + } + LIBC_INLINE static constexpr RetT max_subnormal(Sign sign = Sign::POS) { + return RetT( + encode(sign, Exponent::subnormal(), Significand::bits_all_ones())); + } + LIBC_INLINE static constexpr RetT min_normal(Sign sign = Sign::POS) { + return RetT(encode(sign, Exponent::min(), Significand::zero())); + } + LIBC_INLINE static constexpr RetT max_normal(Sign sign = Sign::POS) { + return RetT(encode(sign, Exponent::max(), Significand::bits_all_ones())); + } + LIBC_INLINE static constexpr RetT inf(Sign sign = Sign::POS) { + return RetT(encode(sign, Exponent::inf(), Significand::zero())); + } + LIBC_INLINE static constexpr RetT signaling_nan(Sign sign = Sign::POS, + StorageType v = 0) { + return RetT(encode(sign, Exponent::inf(), + (v ? Significand(v) : (Significand::msb() >> 1)))); + } + LIBC_INLINE static constexpr RetT quiet_nan(Sign sign = Sign::POS, + StorageType v = 0) { + return RetT( + encode(sign, Exponent::inf(), Significand::msb() | Significand(v))); + } + + // Observers + LIBC_INLINE constexpr bool is_zero() const { return exp_sig_bits() == 0; } + LIBC_INLINE constexpr bool is_nan() const { + return exp_sig_bits() > encode(Exponent::inf(), Significand::zero()); + } + LIBC_INLINE constexpr bool is_quiet_nan() const { + return exp_sig_bits() >= encode(Exponent::inf(), Significand::msb()); + } + LIBC_INLINE constexpr bool is_signaling_nan() const { + return is_nan() && !is_quiet_nan(); + } + LIBC_INLINE constexpr bool is_inf() const { + return exp_sig_bits() == encode(Exponent::inf(), Significand::zero()); + } + LIBC_INLINE constexpr bool is_finite() const { + return exp_bits() != encode(Exponent::inf()); + } + LIBC_INLINE + constexpr bool is_subnormal() const { + return exp_bits() == encode(Exponent::subnormal()); + } + LIBC_INLINE constexpr bool is_normal() const { + return is_finite() && !is_subnormal(); + } + LIBC_INLINE constexpr RetT next_toward_inf() const { + if (is_finite()) + return RetT(bits + StorageType(1)); + return RetT(bits); + } + + // Returns the mantissa with the implicit bit set iff the current + // value is a valid normal number. + LIBC_INLINE constexpr StorageType get_explicit_mantissa() const { + if (is_subnormal()) + return sig_bits(); + return (StorageType(1) << UP::SIG_LEN) | sig_bits(); + } +}; + +// Specialization for the X86 Extended Precision type. +template <typename RetT> +struct FPRepSem<FPType::X86_Binary80, RetT> + : public FPStorage<FPType::X86_Binary80> { + using UP = FPStorage<FPType::X86_Binary80>; + using typename UP::StorageType; + using UP::FRACTION_LEN; + using UP::FRACTION_MASK; + + // The x86 80 bit float represents the leading digit of the mantissa + // explicitly. This is the mask for that bit. + static constexpr StorageType EXPLICIT_BIT_MASK = StorageType(1) + << FRACTION_LEN; + // The X80 significand is made of an explicit bit and the fractional part. + static_assert((EXPLICIT_BIT_MASK & FRACTION_MASK) == 0, + "the explicit bit and the fractional part should not overlap"); + static_assert((EXPLICIT_BIT_MASK | FRACTION_MASK) == SIG_MASK, + "the explicit bit and the fractional part should cover the " + "whole significand"); + +protected: + using typename UP::Exponent; + using typename UP::Significand; + using UP::encode; + using UP::UP; + +public: + // Builders + LIBC_INLINE static constexpr RetT zero(Sign sign = Sign::POS) { + return RetT(encode(sign, Exponent::subnormal(), Significand::zero())); + } + LIBC_INLINE static constexpr RetT one(Sign sign = Sign::POS) { + return RetT(encode(sign, Exponent::zero(), Significand::msb())); + } + LIBC_INLINE static constexpr RetT min_subnormal(Sign sign = Sign::POS) { + return RetT(encode(sign, Exponent::subnormal(), Significand::lsb())); + } + LIBC_INLINE static constexpr RetT max_subnormal(Sign sign = Sign::POS) { + return RetT(encode(sign, Exponent::subnormal(), + Significand::bits_all_ones() ^ Significand::msb())); + } + LIBC_INLINE static constexpr RetT min_normal(Sign sign = Sign::POS) { + return RetT(encode(sign, Exponent::min(), Significand::msb())); + } + LIBC_INLINE static constexpr RetT max_normal(Sign sign = Sign::POS) { + return RetT(encode(sign, Exponent::max(), Significand::bits_all_ones())); + } + LIBC_INLINE static constexpr RetT inf(Sign sign = Sign::POS) { + return RetT(encode(sign, Exponent::inf(), Significand::msb())); + } + LIBC_INLINE static constexpr RetT signaling_nan(Sign sign = Sign::POS, + StorageType v = 0) { + return RetT(encode(sign, Exponent::inf(), + Significand::msb() | + (v ? Significand(v) : (Significand::msb() >> 2)))); + } + LIBC_INLINE static constexpr RetT quiet_nan(Sign sign = Sign::POS, + StorageType v = 0) { + return RetT(encode(sign, Exponent::inf(), + Significand::msb() | (Significand::msb() >> 1) | + Significand(v))); + } + + // Observers + LIBC_INLINE constexpr bool is_zero() const { return exp_sig_bits() == 0; } + LIBC_INLINE constexpr bool is_nan() const { + // Most encoding forms from the table found in + // https://en.wikipedia.org/wiki/Extended_precision#x86_extended_precision_format + // are interpreted as NaN. + // More precisely : + // - Pseudo-Infinity + // - Pseudo Not a Number + // - Signalling Not a Number + // - Floating-point Indefinite + // - Quiet Not a Number + // - Unnormal + // This can be reduced to the following logic: + if (exp_bits() == encode(Exponent::inf())) + return !is_inf(); + if (exp_bits() != encode(Exponent::subnormal())) + return (sig_bits() & encode(Significand::msb())) == 0; + return false; + } + LIBC_INLINE constexpr bool is_quiet_nan() const { + return exp_sig_bits() >= + encode(Exponent::inf(), + Significand::msb() | (Significand::msb() >> 1)); + } + LIBC_INLINE constexpr bool is_signaling_nan() const { + return is_nan() && !is_quiet_nan(); + } + LIBC_INLINE constexpr bool is_inf() const { + return exp_sig_bits() == encode(Exponent::inf(), Significand::msb()); + } + LIBC_INLINE constexpr bool is_finite() const { + return !is_inf() && !is_nan(); + } + LIBC_INLINE + constexpr bool is_subnormal() const { + return exp_bits() == encode(Exponent::subnormal()); + } + LIBC_INLINE constexpr bool is_normal() const { + const auto exp = exp_bits(); + if (exp == encode(Exponent::subnormal()) || exp == encode(Exponent::inf())) + return false; + return get_implicit_bit(); + } + LIBC_INLINE constexpr RetT next_toward_inf() const { + if (is_finite()) { + if (exp_sig_bits() == max_normal().uintval()) { + return inf(sign()); + } else if (exp_sig_bits() == max_subnormal().uintval()) { + return min_normal(sign()); + } else if (sig_bits() == SIG_MASK) { + return RetT(encode(sign(), ++biased_exponent(), Significand::zero())); + } else { + return RetT(bits + StorageType(1)); + } + } + return RetT(bits); + } + + LIBC_INLINE constexpr StorageType get_explicit_mantissa() const { + return sig_bits(); + } + + // This functions is specific to FPRepSem<FPType::X86_Binary80>. + // TODO: Remove if possible. + LIBC_INLINE constexpr bool get_implicit_bit() const { + return static_cast<bool>(bits & EXPLICIT_BIT_MASK); + } + + // This functions is specific to FPRepSem<FPType::X86_Binary80>. + // TODO: Remove if possible. + LIBC_INLINE constexpr void set_implicit_bit(bool implicitVal) { + if (get_implicit_bit() != implicitVal) + bits ^= EXPLICIT_BIT_MASK; + } +}; + +// 'FPRepImpl' is the bottom of the class hierarchy that only deals with +// 'FPType'. The operations dealing with specific float semantics are +// implemented by 'FPRepSem' above and specialized when needed. +// +// The 'RetT' type is being propagated up to 'FPRepSem' so that the functions +// creating new values (Builders) can return the appropriate type. That is, when +// creating a value through 'FPBits' below the builder will return an 'FPBits' +// value. +// FPBits<float>::zero(); // returns an FPBits<> +// +// When we don't care about specific C++ floating point type we can use +// 'FPRep' and specify the 'FPType' directly. +// FPRep<FPType::IEEE754_Binary32:>::zero() // returns an FPRep<> +template <FPType fp_type, typename RetT> +struct FPRepImpl : public FPRepSem<fp_type, RetT> { + using UP = FPRepSem<fp_type, RetT>; + using StorageType = typename UP::StorageType; + +protected: + using UP::bits; + using UP::encode; + using UP::exp_bits; + using UP::exp_sig_bits; + + using typename UP::BiasedExponent; + using typename UP::Exponent; + using typename UP::Significand; + + using UP::FP_MASK; + +public: + // Constants. + using UP::EXP_BIAS; + using UP::EXP_MASK; + using UP::FRACTION_MASK; + using UP::SIG_LEN; + using UP::SIG_MASK; + using UP::SIGN_MASK; + LIBC_INLINE_VAR static constexpr int MAX_BIASED_EXPONENT = + (1 << UP::EXP_LEN) - 1; + + // CTors + LIBC_INLINE constexpr FPRepImpl() = default; + LIBC_INLINE constexpr explicit FPRepImpl(StorageType x) : UP(x) {} + + // Comparison + LIBC_INLINE constexpr friend bool operator==(FPRepImpl a, FPRepImpl b) { + return a.uintval() == b.uintval(); + } + LIBC_INLINE constexpr friend bool operator!=(FPRepImpl a, FPRepImpl b) { + return a.uintval() != b.uintval(); + } + + // Representation + LIBC_INLINE constexpr StorageType uintval() const { return bits & FP_MASK; } + LIBC_INLINE constexpr void set_uintval(StorageType value) { + bits = (value & FP_MASK); + } + + // Builders + using UP::inf; + using UP::max_normal; + using UP::max_subnormal; + using UP::min_normal; + using UP::min_subnormal; + using UP::one; + using UP::quiet_nan; + using UP::signaling_nan; + using UP::zero; + + // Modifiers + LIBC_INLINE constexpr RetT abs() const { + return RetT(static_cast<StorageType>(bits & UP::EXP_SIG_MASK)); + } + + // Observers + using UP::get_explicit_mantissa; + using UP::is_finite; + using UP::is_inf; + using UP::is_nan; + using UP::is_normal; + using UP::is_quiet_nan; + using UP::is_signaling_nan; + using UP::is_subnormal; + using UP::is_zero; + using UP::next_toward_inf; + using UP::sign; + LIBC_INLINE constexpr bool is_inf_or_nan() const { return !is_finite(); } + LIBC_INLINE constexpr bool is_neg() const { return sign().is_neg(); } + LIBC_INLINE constexpr bool is_pos() const { return sign().is_pos(); } + + LIBC_INLINE constexpr uint16_t get_biased_exponent() const { + return static_cast<uint16_t>(static_cast<uint32_t>(UP::biased_exponent())); + } + + LIBC_INLINE constexpr void set_biased_exponent(StorageType biased) { + UP::set_biased_exponent(BiasedExponent((int32_t)biased)); + } + + LIBC_INLINE constexpr int get_exponent() const { + return static_cast<int32_t>(Exponent(UP::biased_exponent())); + } + + // If the number is subnormal, the exponent is treated as if it were the + // minimum exponent for a normal number. This is to keep continuity between + // the normal and subnormal ranges, but it causes problems for functions where + // values are calculated from the exponent, since just subtracting the bias + // will give a slightly incorrect result. Additionally, zero has an exponent + // of zero, and that should actually be treated as zero. + LIBC_INLINE constexpr int get_explicit_exponent() const { + Exponent exponent(UP::biased_exponent()); + if (is_zero()) + exponent = Exponent::zero(); + if (exponent == Exponent::subnormal()) + exponent = Exponent::min(); + return static_cast<int32_t>(exponent); + } + + LIBC_INLINE constexpr StorageType get_mantissa() const { + return bits & FRACTION_MASK; + } + + LIBC_INLINE constexpr void set_mantissa(StorageType mantVal) { + bits = UP::merge(bits, mantVal, FRACTION_MASK); + } + + LIBC_INLINE constexpr void set_significand(StorageType sigVal) { + bits = UP::merge(bits, sigVal, SIG_MASK); + } + // Unsafe function to create a floating point representation. + // It simply packs the sign, biased exponent and mantissa values without + // checking bound nor normalization. + // + // WARNING: For X86 Extended Precision, implicit bit needs to be set correctly + // in the 'mantissa' by the caller. This function will not check for its + // validity. + // + // FIXME: Use an uint32_t for 'biased_exp'. + LIBC_INLINE static constexpr RetT + create_value(Sign sign, StorageType biased_exp, StorageType mantissa) { + return RetT(encode(sign, BiasedExponent(static_cast<uint32_t>(biased_exp)), + Significand(mantissa))); + } + + // The function converts integer number and unbiased exponent to proper + // float T type: + // Result = number * 2^(ep+1 - exponent_bias) + // Be careful! + // 1) "ep" is the raw exponent value. + // 2) The function adds +1 to ep for seamless normalized to denormalized + // transition. + // 3) The function does not check exponent high limit. + // 4) "number" zero value is not processed correctly. + // 5) Number is unsigned, so the result can be only positive. + LIBC_INLINE static constexpr RetT make_value(StorageType number, int ep) { + FPRepImpl result(0); + int lz = + UP::FRACTION_LEN + 1 - (UP::STORAGE_LEN - cpp::countl_zero(number)); + + number <<= lz; + ep -= lz; + + if (LIBC_LIKELY(ep >= 0)) { + // Implicit number bit will be removed by mask + result.set_significand(number); + result.set_biased_exponent(static_cast<StorageType>(ep + 1)); + } else { + result.set_significand(number >> -ep); + } + return RetT(result.uintval()); + } +}; + +// A generic class to manipulate floating point formats. +// It derives its functionality to FPRepImpl above. +template <FPType fp_type> +struct FPRep : public FPRepImpl<fp_type, FPRep<fp_type>> { + using UP = FPRepImpl<fp_type, FPRep<fp_type>>; + using StorageType = typename UP::StorageType; + using UP::UP; + + LIBC_INLINE constexpr explicit operator StorageType() const { + return UP::uintval(); + } +}; + +} // namespace internal + +// Returns the FPType corresponding to C++ type T on the host. +template <typename T> LIBC_INLINE static constexpr FPType get_fp_type() { + using UnqualT = cpp::remove_cv_t<T>; + if constexpr (cpp::is_same_v<UnqualT, float> && __FLT_MANT_DIG__ == 24) + return FPType::IEEE754_Binary32; + else if constexpr (cpp::is_same_v<UnqualT, double> && __DBL_MANT_DIG__ == 53) + return FPType::IEEE754_Binary64; + else if constexpr (cpp::is_same_v<UnqualT, long double>) { + if constexpr (__LDBL_MANT_DIG__ == 53) + return FPType::IEEE754_Binary64; + else if constexpr (__LDBL_MANT_DIG__ == 64) + return FPType::X86_Binary80; + else if constexpr (__LDBL_MANT_DIG__ == 113) + return FPType::IEEE754_Binary128; + } +#if defined(LIBC_TYPES_HAS_FLOAT16) + else if constexpr (cpp::is_same_v<UnqualT, float16>) + return FPType::IEEE754_Binary16; +#endif +#if defined(LIBC_TYPES_HAS_FLOAT128) + else if constexpr (cpp::is_same_v<UnqualT, float128>) + return FPType::IEEE754_Binary128; +#endif + else + static_assert(cpp::always_false<UnqualT>, "Unsupported type"); +} + +// ----------------------------------------------------------------------------- +// **** WARNING **** +// This interface is shared with libc++, if you change this interface you need +// to update it in both libc and libc++. You should also be careful when adding +// dependencies to this file, since it needs to build for all libc++ targets. +// ----------------------------------------------------------------------------- +// A generic class to manipulate C++ floating point formats. +// It derives its functionality to FPRepImpl above. +template <typename T> +struct FPBits final : public internal::FPRepImpl<get_fp_type<T>(), FPBits<T>> { + static_assert(cpp::is_floating_point_v<T>, + "FPBits instantiated with invalid type."); + using UP = internal::FPRepImpl<get_fp_type<T>(), FPBits<T>>; + using StorageType = typename UP::StorageType; + + // 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>); + } + } + + // Floating-point conversions. + LIBC_INLINE constexpr T get_val() const { return cpp::bit_cast<T>(UP::bits); } +}; + +} // namespace fputil +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_FPUTIL_FPBITS_H diff --git a/lib/libcxx/libc/src/__support/FPUtil/rounding_mode.h b/lib/libcxx/libc/src/__support/FPUtil/rounding_mode.h new file mode 100644 index 0000000000..bc66d09b94 --- /dev/null +++ b/lib/libcxx/libc/src/__support/FPUtil/rounding_mode.h @@ -0,0 +1,81 @@ +//===---- Free-standing function to detect rounding mode --------*- 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_FPUTIL_ROUNDING_MODE_H +#define LLVM_LIBC_SRC___SUPPORT_FPUTIL_ROUNDING_MODE_H + +#include "hdr/fenv_macros.h" +#include "src/__support/macros/attributes.h" // LIBC_INLINE +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { +namespace fputil { + +// Quick free-standing test whether fegetround() == FE_UPWARD. +// Using the following observation: +// 1.0f + 2^-25 = 1.0f for FE_TONEAREST, FE_DOWNWARD, FE_TOWARDZERO +// = 0x1.000002f for FE_UPWARD. +LIBC_INLINE bool fenv_is_round_up() { + volatile float x = 0x1.0p-25f; + return (1.0f + x != 1.0f); +} + +// Quick free-standing test whether fegetround() == FE_DOWNWARD. +// Using the following observation: +// -1.0f - 2^-25 = -1.0f for FE_TONEAREST, FE_UPWARD, FE_TOWARDZERO +// = -0x1.000002f for FE_DOWNWARD. +LIBC_INLINE bool fenv_is_round_down() { + volatile float x = 0x1.0p-25f; + return (-1.0f - x != -1.0f); +} + +// Quick free-standing test whether fegetround() == FE_TONEAREST. +// Using the following observation: +// 1.5f + 2^-24 = 1.5f for FE_TONEAREST, FE_DOWNWARD, FE_TOWARDZERO +// = 0x1.100002p0f for FE_UPWARD, +// 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() { + static volatile float x = 0x1.0p-24f; + float y = x; + return (1.5f + y == 1.5f - y); +} + +// Quick free-standing test whether fegetround() == FE_TOWARDZERO. +// Using the following observation: +// 1.0f + 2^-23 + 2^-24 = 0x1.000002p0f for FE_DOWNWARD, FE_TOWARDZERO +// = 0x1.000004p0f for FE_TONEAREST, FE_UPWARD, +// -1.0f - 2^-24 = -1.0f for FE_TONEAREST, FE_UPWARD, FE_TOWARDZERO +// = -0x1.000002p0f for FE_DOWNWARD +// So: +// (0x1.000002p0f + 2^-24) + (-1.0f - 2^-24) = 2^-23 for FE_TOWARDZERO +// = 2^-22 for FE_TONEAREST, FE_UPWARD +// = 0 for FE_DOWNWARD +LIBC_INLINE bool fenv_is_round_to_zero() { + static volatile float x = 0x1.0p-24f; + float y = x; + return ((0x1.000002p0f + y) + (-1.0f - y) == 0x1.0p-23f); +} + +// Quick free standing get rounding mode based on the above observations. +LIBC_INLINE int quick_get_round() { + static volatile float x = 0x1.0p-24f; + float y = x; + float z = (0x1.000002p0f + y) + (-1.0f - y); + + if (z == 0.0f) + return FE_DOWNWARD; + if (z == 0x1.0p-23f) + return FE_TOWARDZERO; + return (2.0f + y == 2.0f) ? FE_TONEAREST : FE_UPWARD; +} + +} // namespace fputil +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_FPUTIL_ROUNDING_MODE_H diff --git a/lib/libcxx/libc/src/__support/big_int.h b/lib/libcxx/libc/src/__support/big_int.h new file mode 100644 index 0000000000..a95ab4ff8e --- /dev/null +++ b/lib/libcxx/libc/src/__support/big_int.h @@ -0,0 +1,1384 @@ +//===-- A class to manipulate wide integers. --------------------*- 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_BIG_INT_H +#define LLVM_LIBC_SRC___SUPPORT_BIG_INT_H + +#include "src/__support/CPP/array.h" +#include "src/__support/CPP/bit.h" // countl_zero +#include "src/__support/CPP/limits.h" +#include "src/__support/CPP/optional.h" +#include "src/__support/CPP/type_traits.h" +#include "src/__support/macros/attributes.h" // LIBC_INLINE +#include "src/__support/macros/config.h" +#include "src/__support/macros/optimization.h" // LIBC_UNLIKELY +#include "src/__support/macros/properties/compiler.h" // LIBC_COMPILER_IS_CLANG +#include "src/__support/macros/properties/types.h" // LIBC_TYPES_HAS_INT128, LIBC_TYPES_HAS_INT64 +#include "src/__support/math_extras.h" // add_with_carry, sub_with_borrow +#include "src/__support/number_pair.h" + +#include <stddef.h> // For size_t +#include <stdint.h> + +namespace LIBC_NAMESPACE_DECL { + +namespace multiword { + +// A type trait mapping unsigned integers to their half-width unsigned +// counterparts. +template <typename T> struct half_width; +template <> struct half_width<uint16_t> : cpp::type_identity<uint8_t> {}; +template <> struct half_width<uint32_t> : cpp::type_identity<uint16_t> {}; +#ifdef LIBC_TYPES_HAS_INT64 +template <> struct half_width<uint64_t> : cpp::type_identity<uint32_t> {}; +#ifdef LIBC_TYPES_HAS_INT128 +template <> struct half_width<__uint128_t> : cpp::type_identity<uint64_t> {}; +#endif // LIBC_TYPES_HAS_INT128 +#endif // LIBC_TYPES_HAS_INT64 +template <typename T> using half_width_t = typename half_width<T>::type; + +// An array of two elements that can be used in multiword operations. +template <typename T> struct DoubleWide final : cpp::array<T, 2> { + using UP = cpp::array<T, 2>; + using UP::UP; + LIBC_INLINE constexpr DoubleWide(T lo, T hi) : UP({lo, hi}) {} +}; + +// Converts an unsigned value into a DoubleWide<half_width_t<T>>. +template <typename T> LIBC_INLINE constexpr auto split(T value) { + static_assert(cpp::is_unsigned_v<T>); + using half_type = half_width_t<T>; + return DoubleWide<half_type>( + half_type(value), + half_type(value >> cpp::numeric_limits<half_type>::digits)); +} + +// The low part of a DoubleWide value. +template <typename T> LIBC_INLINE constexpr T lo(const DoubleWide<T> &value) { + return value[0]; +} +// The high part of a DoubleWide value. +template <typename T> LIBC_INLINE constexpr T hi(const DoubleWide<T> &value) { + return value[1]; +} +// The low part of an unsigned value. +template <typename T> LIBC_INLINE constexpr half_width_t<T> lo(T value) { + return lo(split(value)); +} +// The high part of an unsigned value. +template <typename T> LIBC_INLINE constexpr half_width_t<T> hi(T value) { + return hi(split(value)); +} + +// Returns 'a' times 'b' in a DoubleWide<word>. Cannot overflow by construction. +template <typename word> +LIBC_INLINE constexpr DoubleWide<word> mul2(word a, word b) { + if constexpr (cpp::is_same_v<word, uint8_t>) { + return split<uint16_t>(uint16_t(a) * uint16_t(b)); + } else if constexpr (cpp::is_same_v<word, uint16_t>) { + return split<uint32_t>(uint32_t(a) * uint32_t(b)); + } +#ifdef LIBC_TYPES_HAS_INT64 + else if constexpr (cpp::is_same_v<word, uint32_t>) { + return split<uint64_t>(uint64_t(a) * uint64_t(b)); + } +#endif +#ifdef LIBC_TYPES_HAS_INT128 + else if constexpr (cpp::is_same_v<word, uint64_t>) { + return split<__uint128_t>(__uint128_t(a) * __uint128_t(b)); + } +#endif + else { + using half_word = half_width_t<word>; + const auto shiftl = [](word value) -> word { + return value << cpp::numeric_limits<half_word>::digits; + }; + const auto shiftr = [](word value) -> word { + return value >> cpp::numeric_limits<half_word>::digits; + }; + // Here we do a one digit multiplication where 'a' and 'b' are of type + // word. We split 'a' and 'b' into half words and perform the classic long + // multiplication with 'a' and 'b' being two-digit numbers. + + // a a_hi a_lo + // x b => x b_hi b_lo + // ---- ----------- + // c result + // We convert 'lo' and 'hi' from 'half_word' to 'word' so multiplication + // doesn't overflow. + const word a_lo = lo(a); + const word b_lo = lo(b); + const word a_hi = hi(a); + const word b_hi = hi(b); + const word step1 = b_lo * a_lo; // no overflow; + const word step2 = b_lo * a_hi; // no overflow; + const word step3 = b_hi * a_lo; // no overflow; + const word step4 = b_hi * a_hi; // no overflow; + word lo_digit = step1; + word hi_digit = step4; + const word no_carry = 0; + word carry; + word _; // unused carry variable. + lo_digit = add_with_carry<word>(lo_digit, shiftl(step2), no_carry, carry); + hi_digit = add_with_carry<word>(hi_digit, shiftr(step2), carry, _); + lo_digit = add_with_carry<word>(lo_digit, shiftl(step3), no_carry, carry); + hi_digit = add_with_carry<word>(hi_digit, shiftr(step3), carry, _); + return DoubleWide<word>(lo_digit, hi_digit); + } +} + +// In-place 'dst op= rhs' with operation with carry propagation. Returns carry. +template <typename Function, typename word, size_t N, size_t M> +LIBC_INLINE constexpr word inplace_binop(Function op_with_carry, + cpp::array<word, N> &dst, + const cpp::array<word, M> &rhs) { + static_assert(N >= M); + word carry_out = 0; + for (size_t i = 0; i < N; ++i) { + const bool has_rhs_value = i < M; + const word rhs_value = has_rhs_value ? rhs[i] : 0; + const word carry_in = carry_out; + dst[i] = op_with_carry(dst[i], rhs_value, carry_in, carry_out); + // stop early when rhs is over and no carry is to be propagated. + if (!has_rhs_value && carry_out == 0) + break; + } + return carry_out; +} + +// In-place addition. Returns carry. +template <typename word, size_t N, size_t M> +LIBC_INLINE constexpr word add_with_carry(cpp::array<word, N> &dst, + const cpp::array<word, M> &rhs) { + return inplace_binop(LIBC_NAMESPACE::add_with_carry<word>, dst, rhs); +} + +// In-place subtraction. Returns borrow. +template <typename word, size_t N, size_t M> +LIBC_INLINE constexpr word sub_with_borrow(cpp::array<word, N> &dst, + const cpp::array<word, M> &rhs) { + return inplace_binop(LIBC_NAMESPACE::sub_with_borrow<word>, dst, rhs); +} + +// In-place multiply-add. Returns carry. +// i.e., 'dst += b * c' +template <typename word, size_t N> +LIBC_INLINE constexpr word mul_add_with_carry(cpp::array<word, N> &dst, word b, + word c) { + return add_with_carry(dst, mul2(b, c)); +} + +// An array of two elements serving as an accumulator during multiword +// computations. +template <typename T> struct Accumulator final : cpp::array<T, 2> { + using UP = cpp::array<T, 2>; + LIBC_INLINE constexpr Accumulator() : UP({0, 0}) {} + LIBC_INLINE constexpr T advance(T carry_in) { + auto result = UP::front(); + UP::front() = UP::back(); + UP::back() = carry_in; + return result; + } + LIBC_INLINE constexpr T sum() const { return UP::front(); } + LIBC_INLINE constexpr T carry() const { return UP::back(); } +}; + +// In-place multiplication by a single word. Returns carry. +template <typename word, size_t N> +LIBC_INLINE constexpr word scalar_multiply_with_carry(cpp::array<word, N> &dst, + word x) { + Accumulator<word> acc; + for (auto &val : dst) { + const word carry = mul_add_with_carry(acc, val, x); + val = acc.advance(carry); + } + return acc.carry(); +} + +// Multiplication of 'lhs' by 'rhs' into 'dst'. Returns carry. +// This function is safe to use for signed numbers. +// https://stackoverflow.com/a/20793834 +// https://pages.cs.wisc.edu/%7Emarkhill/cs354/Fall2008/beyond354/int.mult.html +template <typename word, size_t O, size_t M, size_t N> +LIBC_INLINE constexpr word multiply_with_carry(cpp::array<word, O> &dst, + const cpp::array<word, M> &lhs, + const cpp::array<word, N> &rhs) { + static_assert(O >= M + N); + Accumulator<word> acc; + for (size_t i = 0; i < O; ++i) { + const size_t lower_idx = i < N ? 0 : i - N + 1; + const size_t upper_idx = i < M ? i : M - 1; + word carry = 0; + for (size_t j = lower_idx; j <= upper_idx; ++j) + carry += mul_add_with_carry(acc, lhs[j], rhs[i - j]); + dst[i] = acc.advance(carry); + } + return acc.carry(); +} + +template <typename word, size_t N> +LIBC_INLINE constexpr void quick_mul_hi(cpp::array<word, N> &dst, + const cpp::array<word, N> &lhs, + const cpp::array<word, N> &rhs) { + Accumulator<word> acc; + word carry = 0; + // First round of accumulation for those at N - 1 in the full product. + for (size_t i = 0; i < N; ++i) + carry += mul_add_with_carry(acc, lhs[i], rhs[N - 1 - i]); + for (size_t i = N; i < 2 * N - 1; ++i) { + acc.advance(carry); + carry = 0; + for (size_t j = i - N + 1; j < N; ++j) + carry += mul_add_with_carry(acc, lhs[j], rhs[i - j]); + dst[i - N] = acc.sum(); + } + dst.back() = acc.carry(); +} + +template <typename word, size_t N> +LIBC_INLINE constexpr bool is_negative(cpp::array<word, N> &array) { + using signed_word = cpp::make_signed_t<word>; + return cpp::bit_cast<signed_word>(array.back()) < 0; +} + +// An enum for the shift function below. +enum Direction { LEFT, RIGHT }; + +// A bitwise shift on an array of elements. +// 'offset' must be less than TOTAL_BITS (i.e., sizeof(word) * CHAR_BIT * N) +// otherwise the behavior is undefined. +template <Direction direction, bool is_signed, typename word, size_t N> +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; +#ifdef LIBC_TYPES_HAS_INT128 + constexpr size_t TOTAL_BITS = N * WORD_BITS; + if constexpr (TOTAL_BITS == 128) { + using type = cpp::conditional_t<is_signed, __int128_t, __uint128_t>; + auto tmp = cpp::bit_cast<type>(array); + if constexpr (direction == LEFT) + tmp <<= offset; + else + tmp >>= offset; + return cpp::bit_cast<cpp::array<word, N>>(tmp); + } +#endif + if (LIBC_UNLIKELY(offset == 0)) + return array; + const bool is_neg = is_signed && is_negative(array); + constexpr auto at = [](size_t index) -> int { + // reverse iteration when direction == LEFT. + if constexpr (direction == LEFT) + return int(N) - int(index) - 1; + return int(index); + }; + const auto safe_get_at = [&](size_t index) -> word { + // return appropriate value when accessing out of bound elements. + const int i = at(index); + if (i < 0) + return 0; + if (i >= int(N)) + return is_neg ? -1 : 0; + return array[i]; + }; + const size_t index_offset = offset / WORD_BITS; + const size_t bit_offset = offset % WORD_BITS; +#ifdef LIBC_COMPILER_IS_CLANG + __builtin_assume(index_offset < N); +#endif + cpp::array<word, N> out = {}; + for (size_t index = 0; index < N; ++index) { + const word part1 = safe_get_at(index + index_offset); + const word part2 = safe_get_at(index + index_offset + 1); + word &dst = out[at(index)]; + if (bit_offset == 0) + dst = part1; // no crosstalk between parts. + else if constexpr (direction == LEFT) + dst = static_cast<word>((part1 << bit_offset) | + (part2 >> (WORD_BITS - bit_offset))); + else + dst = static_cast<word>((part1 >> bit_offset) | + (part2 << (WORD_BITS - bit_offset))); + } + return out; +} + +#define DECLARE_COUNTBIT(NAME, INDEX_EXPR) \ + template <typename word, size_t N> \ + LIBC_INLINE constexpr int NAME(const cpp::array<word, N> &val) { \ + int bit_count = 0; \ + for (size_t i = 0; i < N; ++i) { \ + const int word_count = cpp::NAME<word>(val[INDEX_EXPR]); \ + bit_count += word_count; \ + if (word_count != cpp::numeric_limits<word>::digits) \ + break; \ + } \ + return bit_count; \ + } + +DECLARE_COUNTBIT(countr_zero, i) // iterating forward +DECLARE_COUNTBIT(countr_one, i) // iterating forward +DECLARE_COUNTBIT(countl_zero, N - i - 1) // iterating backward +DECLARE_COUNTBIT(countl_one, N - i - 1) // iterating backward + +} // namespace multiword + +template <size_t Bits, bool Signed, typename WordType = uint64_t> +struct BigInt { +private: + static_assert(cpp::is_integral_v<WordType> && cpp::is_unsigned_v<WordType>, + "WordType must be unsigned integer."); + + struct Division { + BigInt quotient; + BigInt remainder; + }; + +public: + using word_type = WordType; + using unsigned_type = BigInt<Bits, false, word_type>; + using signed_type = BigInt<Bits, true, word_type>; + + LIBC_INLINE_VAR static constexpr bool SIGNED = Signed; + LIBC_INLINE_VAR static constexpr size_t BITS = Bits; + LIBC_INLINE_VAR + static constexpr size_t WORD_SIZE = sizeof(WordType) * CHAR_BIT; + + static_assert(Bits > 0 && Bits % WORD_SIZE == 0, + "Number of bits in BigInt should be a multiple of WORD_SIZE."); + + LIBC_INLINE_VAR static constexpr size_t WORD_COUNT = Bits / WORD_SIZE; + + cpp::array<WordType, WORD_COUNT> val{}; // zero initialized. + + LIBC_INLINE constexpr BigInt() = default; + + LIBC_INLINE constexpr BigInt(const BigInt &other) = default; + + template <size_t OtherBits, bool OtherSigned, typename OtherWordType> + LIBC_INLINE constexpr BigInt( + const BigInt<OtherBits, OtherSigned, OtherWordType> &other) { + using BigIntOther = BigInt<OtherBits, OtherSigned, OtherWordType>; + 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 " + "the same bit width but different word sizes."); + + if constexpr (BigIntOther::WORD_SIZE < WORD_SIZE) { + // OtherWordType is smaller + constexpr size_t WORD_SIZE_RATIO = WORD_SIZE / BigIntOther::WORD_SIZE; + static_assert( + (WORD_SIZE % BigIntOther::WORD_SIZE) == 0 && + "Word types must be multiples of each other for correct conversion."); + if constexpr (OtherBits >= Bits) { // truncate + // for each big word + for (size_t i = 0; i < WORD_COUNT; ++i) { + WordType cur_word = 0; + // combine WORD_SIZE_RATIO small words into a big word + for (size_t j = 0; j < WORD_SIZE_RATIO; ++j) + cur_word |= static_cast<WordType>(other[(i * WORD_SIZE_RATIO) + j]) + << (BigIntOther::WORD_SIZE * j); + + val[i] = cur_word; + } + } else { // zero or sign extend + size_t i = 0; + WordType cur_word = 0; + // for each small word + for (; i < BigIntOther::WORD_COUNT; ++i) { + // combine WORD_SIZE_RATIO small words into a big word + cur_word |= static_cast<WordType>(other[i]) + << (BigIntOther::WORD_SIZE * (i % WORD_SIZE_RATIO)); + // if we've completed a big word, copy it into place and reset + if ((i % WORD_SIZE_RATIO) == WORD_SIZE_RATIO - 1) { + val[i / WORD_SIZE_RATIO] = cur_word; + cur_word = 0; + } + } + // Pretend there are extra words of the correct sign extension as needed + + const WordType extension_bits = + should_sign_extend ? cpp::numeric_limits<WordType>::max() + : cpp::numeric_limits<WordType>::min(); + if ((i % WORD_SIZE_RATIO) != 0) { + cur_word |= static_cast<WordType>(extension_bits) + << (BigIntOther::WORD_SIZE * (i % WORD_SIZE_RATIO)); + } + // Copy the last word into place. + val[(i / WORD_SIZE_RATIO)] = cur_word; + extend((i / WORD_SIZE_RATIO) + 1, should_sign_extend); + } + } else if constexpr (BigIntOther::WORD_SIZE == WORD_SIZE) { + if constexpr (OtherBits >= Bits) { // truncate + for (size_t i = 0; i < WORD_COUNT; ++i) + val[i] = other[i]; + } else { // zero or sign extend + size_t i = 0; + for (; i < BigIntOther::WORD_COUNT; ++i) + val[i] = other[i]; + extend(i, should_sign_extend); + } + } else { + // OtherWordType is bigger. + constexpr size_t WORD_SIZE_RATIO = BigIntOther::WORD_SIZE / WORD_SIZE; + static_assert( + (BigIntOther::WORD_SIZE % WORD_SIZE) == 0 && + "Word types must be multiples of each other for correct conversion."); + if constexpr (OtherBits >= Bits) { // truncate + // for each small word + for (size_t i = 0; i < WORD_COUNT; ++i) { + // split each big word into WORD_SIZE_RATIO small words + val[i] = static_cast<WordType>(other[i / WORD_SIZE_RATIO] >> + ((i % WORD_SIZE_RATIO) * WORD_SIZE)); + } + } else { // zero or sign extend + size_t i = 0; + // for each big word + for (; i < BigIntOther::WORD_COUNT; ++i) { + // split each big word into WORD_SIZE_RATIO small words + for (size_t j = 0; j < WORD_SIZE_RATIO; ++j) + val[(i * WORD_SIZE_RATIO) + j] = + static_cast<WordType>(other[i] >> (j * WORD_SIZE)); + } + extend(i * WORD_SIZE_RATIO, should_sign_extend); + } + } + } + + // Construct a BigInt from a C array. + template <size_t N> LIBC_INLINE constexpr BigInt(const WordType (&nums)[N]) { + 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) { + 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> && + !cpp::is_same_v<T, bool>>> + LIBC_INLINE constexpr BigInt(T v) { + constexpr size_t T_SIZE = sizeof(T) * CHAR_BIT; + const bool is_neg = v < 0; + for (size_t i = 0; i < WORD_COUNT; ++i) { + if (v == 0) { + extend(i, is_neg); + return; + } + val[i] = static_cast<WordType>(v); + if constexpr (T_SIZE > WORD_SIZE) + v >>= WORD_SIZE; + else + v = 0; + } + } + LIBC_INLINE constexpr BigInt &operator=(const BigInt &other) = default; + + // constants + LIBC_INLINE static constexpr BigInt zero() { return BigInt(); } + 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; + if constexpr (SIGNED) + out.set_msb(); + return out; + } + LIBC_INLINE static constexpr BigInt max() { + BigInt out = all_ones(); + if constexpr (SIGNED) + out.clear_msb(); + return out; + } + + // TODO: Reuse the Sign type. + LIBC_INLINE constexpr bool is_neg() const { return SIGNED && get_msb(); } + + template <size_t OtherBits, bool OtherSigned, typename OtherWordType> + LIBC_INLINE constexpr explicit + operator BigInt<OtherBits, OtherSigned, OtherWordType>() const { + return BigInt<OtherBits, OtherSigned, OtherWordType>(this); + } + + template <typename T> LIBC_INLINE constexpr explicit operator T() const { + return to<T>(); + } + + template <typename T> + LIBC_INLINE constexpr cpp::enable_if_t< + cpp::is_integral_v<T> && !cpp::is_same_v<T, bool>, T> + to() const { + constexpr size_t T_SIZE = sizeof(T) * CHAR_BIT; + T lo = static_cast<T>(val[0]); + if constexpr (T_SIZE <= WORD_SIZE) + return lo; + constexpr size_t MAX_COUNT = + T_SIZE > Bits ? WORD_COUNT : T_SIZE / WORD_SIZE; + for (size_t i = 1; i < MAX_COUNT; ++i) + lo += static_cast<T>(static_cast<T>(val[i]) << (WORD_SIZE * i)); + if constexpr (Signed && (T_SIZE > Bits)) { + // Extend sign for negative numbers. + constexpr T MASK = (~T(0) << Bits); + if (is_neg()) + lo |= MASK; + } + return lo; + } + + LIBC_INLINE constexpr explicit operator bool() const { return !is_zero(); } + + LIBC_INLINE constexpr bool is_zero() const { + for (auto part : val) + if (part != 0) + return false; + return true; + } + + // Add 'rhs' to this number and store the result in this number. + // Returns the carry value produced by the addition operation. + LIBC_INLINE constexpr WordType add_overflow(const BigInt &rhs) { + return multiword::add_with_carry(val, rhs.val); + } + + LIBC_INLINE constexpr BigInt operator+(const BigInt &other) const { + BigInt result = *this; + result.add_overflow(other); + return result; + } + + // This will only apply when initializing a variable from constant values, so + // it will always use the constexpr version of add_with_carry. + LIBC_INLINE constexpr BigInt operator+(BigInt &&other) const { + // We use addition commutativity to reuse 'other' and prevent allocation. + other.add_overflow(*this); // Returned carry value is ignored. + return other; + } + + LIBC_INLINE constexpr BigInt &operator+=(const BigInt &other) { + add_overflow(other); // Returned carry value is ignored. + return *this; + } + + // Subtract 'rhs' to this number and store the result in this number. + // Returns the carry value produced by the subtraction operation. + LIBC_INLINE constexpr WordType sub_overflow(const BigInt &rhs) { + return multiword::sub_with_borrow(val, rhs.val); + } + + LIBC_INLINE constexpr BigInt operator-(const BigInt &other) const { + BigInt result = *this; + result.sub_overflow(other); // Returned carry value is ignored. + return result; + } + + LIBC_INLINE constexpr BigInt operator-(BigInt &&other) const { + BigInt result = *this; + result.sub_overflow(other); // Returned carry value is ignored. + return result; + } + + LIBC_INLINE constexpr BigInt &operator-=(const BigInt &other) { + // TODO(lntue): Set overflow flag / errno when carry is true. + sub_overflow(other); // Returned carry value is ignored. + return *this; + } + + // Multiply this number with x and store the result in this number. + LIBC_INLINE constexpr WordType mul(WordType x) { + return multiword::scalar_multiply_with_carry(val, x); + } + + // Return the full product. + template <size_t OtherBits> + LIBC_INLINE constexpr auto + ful_mul(const BigInt<OtherBits, Signed, WordType> &other) const { + BigInt<Bits + OtherBits, Signed, WordType> result; + multiword::multiply_with_carry(result.val, val, other.val); + return result; + } + + LIBC_INLINE constexpr BigInt operator*(const BigInt &other) const { + // Perform full mul and truncate. + return BigInt(ful_mul(other)); + } + + // Fast hi part of the full product. The normal product `operator*` returns + // `Bits` least significant bits of the full product, while this function will + // approximate `Bits` most significant bits of the full product with errors + // bounded by: + // 0 <= (a.full_mul(b) >> Bits) - a.quick_mul_hi(b)) <= WORD_COUNT - 1. + // + // An example usage of this is to quickly (but less accurately) compute the + // product of (normalized) mantissas of floating point numbers: + // (mant_1, mant_2) -> quick_mul_hi -> normalize leading bit + // is much more efficient than: + // (mant_1, mant_2) -> ful_mul -> normalize leading bit + // -> convert back to same Bits width by shifting/rounding, + // especially for higher precisions. + // + // Performance summary: + // Number of 64-bit x 64-bit -> 128-bit multiplications performed. + // Bits WORD_COUNT ful_mul quick_mul_hi Error bound + // 128 2 4 3 1 + // 196 3 9 6 2 + // 256 4 16 10 3 + // 512 8 64 36 7 + LIBC_INLINE constexpr BigInt quick_mul_hi(const BigInt &other) const { + BigInt result; + multiword::quick_mul_hi(result.val, val, other.val); + return result; + } + + // BigInt(x).pow_n(n) computes x ^ n. + // Note 0 ^ 0 == 1. + LIBC_INLINE constexpr void pow_n(uint64_t power) { + static_assert(!Signed); + BigInt result = one(); + BigInt cur_power = *this; + while (power > 0) { + if ((power % 2) > 0) + result *= cur_power; + power >>= 1; + cur_power *= cur_power; + } + *this = result; + } + + // Performs inplace signed / unsigned division. Returns remainder if not + // dividing by zero. + // For signed numbers it behaves like C++ signed integer division. + // That is by truncating the fractionnal part + // https://stackoverflow.com/a/3602857 + LIBC_INLINE constexpr cpp::optional<BigInt> div(const BigInt ÷r) { + if (LIBC_UNLIKELY(divider.is_zero())) + return cpp::nullopt; + if (LIBC_UNLIKELY(divider == BigInt::one())) + return BigInt::zero(); + Division result; + if constexpr (SIGNED) + result = divide_signed(*this, divider); + else + result = divide_unsigned(*this, divider); + *this = result.quotient; + return result.remainder; + } + + // Efficiently perform BigInt / (x * 2^e), where x is a half-word-size + // unsigned integer, and return the remainder. The main idea is as follow: + // Let q = y / (x * 2^e) be the quotient, and + // r = y % (x * 2^e) be the remainder. + // First, notice that: + // r % (2^e) = y % (2^e), + // so we just need to focus on all the bits of y that is >= 2^e. + // To speed up the shift-and-add steps, we only use x as the divisor, and + // performing 32-bit shiftings instead of bit-by-bit shiftings. + // Since the remainder of each division step < x < 2^(WORD_SIZE / 2), the + // computation of each step is now properly contained within WordType. + // 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; + if (x == 0) + return cpp::nullopt; + if (e >= Bits) { + remainder = *this; + *this = BigInt<Bits, false, WordType>(); + return remainder; + } + BigInt quotient; + WordType x_word = static_cast<WordType>(x); + constexpr size_t LOG2_WORD_SIZE = cpp::bit_width(WORD_SIZE) - 1; + constexpr size_t HALF_WORD_SIZE = WORD_SIZE >> 1; + constexpr WordType HALF_MASK = ((WordType(1) << HALF_WORD_SIZE) - 1); + // lower = smallest multiple of WORD_SIZE that is >= e. + size_t lower = ((e >> LOG2_WORD_SIZE) + ((e & (WORD_SIZE - 1)) != 0)) + << LOG2_WORD_SIZE; + // lower_pos is the index of the closest WORD_SIZE-bit chunk >= 2^e. + size_t lower_pos = lower / WORD_SIZE; + // Keep track of current remainder mod x * 2^(32*i) + WordType rem = 0; + // pos is the index of the current 64-bit chunk that we are processing. + size_t pos = WORD_COUNT; + + // TODO: look into if constexpr(Bits > 256) skip leading zeroes. + + for (size_t q_pos = WORD_COUNT - lower_pos; q_pos > 0; --q_pos) { + // q_pos is 1 + the index of the current WORD_SIZE-bit chunk of the + // quotient being processed. Performing the division / modulus with + // divisor: + // x * 2^(WORD_SIZE*q_pos - WORD_SIZE/2), + // i.e. using the upper (WORD_SIZE/2)-bit of the current WORD_SIZE-bit + // chunk. + rem <<= HALF_WORD_SIZE; + rem += val[--pos] >> HALF_WORD_SIZE; + WordType q_tmp = rem / x_word; + rem %= x_word; + + // Performing the division / modulus with divisor: + // x * 2^(WORD_SIZE*(q_pos - 1)), + // i.e. using the lower (WORD_SIZE/2)-bit of the current WORD_SIZE-bit + // chunk. + rem <<= HALF_WORD_SIZE; + rem += val[pos] & HALF_MASK; + quotient.val[q_pos - 1] = (q_tmp << HALF_WORD_SIZE) + rem / x_word; + rem %= x_word; + } + + // So far, what we have is: + // quotient = y / (x * 2^lower), and + // rem = (y % (x * 2^lower)) / 2^lower. + // If (lower > e), we will need to perform an extra adjustment of the + // quotient and remainder, namely: + // y / (x * 2^e) = [ y / (x * 2^lower) ] * 2^(lower - e) + + // + (rem * 2^(lower - e)) / x + // (y % (x * 2^e)) / 2^e = (rem * 2^(lower - e)) % x + size_t last_shift = lower - e; + + if (last_shift > 0) { + // quotient * 2^(lower - e) + quotient <<= last_shift; + WordType q_tmp = 0; + WordType d = val[--pos]; + if (last_shift >= HALF_WORD_SIZE) { + // The shifting (rem * 2^(lower - e)) might overflow WordTyoe, so we + // perform a HALF_WORD_SIZE-bit shift first. + rem <<= HALF_WORD_SIZE; + rem += d >> HALF_WORD_SIZE; + d &= HALF_MASK; + q_tmp = rem / x_word; + rem %= x_word; + last_shift -= HALF_WORD_SIZE; + } else { + // Only use the upper HALF_WORD_SIZE-bit of the current WORD_SIZE-bit + // chunk. + d >>= HALF_WORD_SIZE; + } + + if (last_shift > 0) { + rem <<= HALF_WORD_SIZE; + rem += d; + q_tmp <<= last_shift; + x_word <<= HALF_WORD_SIZE - last_shift; + q_tmp += rem / x_word; + rem %= x_word; + } + + quotient.val[0] += q_tmp; + + if (lower - e <= HALF_WORD_SIZE) { + // The remainder rem * 2^(lower - e) might overflow to the higher + // WORD_SIZE-bit chunk. + if (pos < WORD_COUNT - 1) { + remainder[pos + 1] = rem >> HALF_WORD_SIZE; + } + remainder[pos] = (rem << HALF_WORD_SIZE) + (val[pos] & HALF_MASK); + } else { + remainder[pos] = rem; + } + + } else { + remainder[pos] = rem; + } + + // Set the remaining lower bits of the remainder. + for (; pos > 0; --pos) { + remainder[pos - 1] = val[pos - 1]; + } + + *this = quotient; + return remainder; + } + + LIBC_INLINE constexpr BigInt operator/(const BigInt &other) const { + BigInt result(*this); + result.div(other); + return result; + } + + LIBC_INLINE constexpr BigInt &operator/=(const BigInt &other) { + div(other); + return *this; + } + + LIBC_INLINE constexpr BigInt operator%(const BigInt &other) const { + BigInt result(*this); + return *result.div(other); + } + + LIBC_INLINE constexpr BigInt operator%=(const BigInt &other) { + *this = *this % other; + return *this; + } + + LIBC_INLINE constexpr BigInt &operator*=(const BigInt &other) { + *this = *this * other; + return *this; + } + + LIBC_INLINE constexpr BigInt &operator<<=(size_t s) { + val = multiword::shift<multiword::LEFT, SIGNED>(val, s); + return *this; + } + + LIBC_INLINE constexpr BigInt operator<<(size_t s) const { + return BigInt(multiword::shift<multiword::LEFT, SIGNED>(val, s)); + } + + LIBC_INLINE constexpr BigInt &operator>>=(size_t s) { + val = multiword::shift<multiword::RIGHT, SIGNED>(val, s); + return *this; + } + + LIBC_INLINE constexpr BigInt operator>>(size_t s) const { + return BigInt(multiword::shift<multiword::RIGHT, SIGNED>(val, s)); + } + +#define DEFINE_BINOP(OP) \ + LIBC_INLINE friend constexpr BigInt operator OP(const BigInt &lhs, \ + const BigInt &rhs) { \ + 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) { \ + for (size_t i = 0; i < WORD_COUNT; ++i) \ + lhs[i] OP## = rhs[i]; \ + return lhs; \ + } + + DEFINE_BINOP(&) // & and &= + DEFINE_BINOP(|) // | and |= + DEFINE_BINOP(^) // ^ and ^= +#undef DEFINE_BINOP + + LIBC_INLINE constexpr BigInt operator~() const { + BigInt result; + for (size_t i = 0; i < WORD_COUNT; ++i) + result[i] = ~val[i]; + return result; + } + + LIBC_INLINE constexpr BigInt operator-() const { + BigInt result(*this); + result.negate(); + return result; + } + + LIBC_INLINE friend constexpr bool operator==(const BigInt &lhs, + const BigInt &rhs) { + for (size_t i = 0; i < WORD_COUNT; ++i) + if (lhs.val[i] != rhs.val[i]) + return false; + return true; + } + + LIBC_INLINE friend constexpr bool operator!=(const BigInt &lhs, + const BigInt &rhs) { + return !(lhs == rhs); + } + + LIBC_INLINE friend constexpr bool operator>(const BigInt &lhs, + const BigInt &rhs) { + return cmp(lhs, rhs) > 0; + } + LIBC_INLINE friend constexpr bool operator>=(const BigInt &lhs, + const BigInt &rhs) { + return cmp(lhs, rhs) >= 0; + } + LIBC_INLINE friend constexpr bool operator<(const BigInt &lhs, + const BigInt &rhs) { + return cmp(lhs, rhs) < 0; + } + LIBC_INLINE friend constexpr bool operator<=(const BigInt &lhs, + const BigInt &rhs) { + return cmp(lhs, rhs) <= 0; + } + + LIBC_INLINE constexpr BigInt &operator++() { + increment(); + return *this; + } + + LIBC_INLINE constexpr BigInt operator++(int) { + BigInt oldval(*this); + increment(); + return oldval; + } + + LIBC_INLINE constexpr BigInt &operator--() { + decrement(); + return *this; + } + + LIBC_INLINE constexpr BigInt operator--(int) { + BigInt oldval(*this); + decrement(); + return oldval; + } + + // Return the i-th word of the number. + LIBC_INLINE constexpr const WordType &operator[](size_t i) const { + return val[i]; + } + + // Return the i-th word of the number. + LIBC_INLINE constexpr WordType &operator[](size_t i) { return val[i]; } + +private: + LIBC_INLINE friend constexpr int cmp(const BigInt &lhs, const BigInt &rhs) { + constexpr auto compare = [](WordType a, WordType b) { + return a == b ? 0 : a > b ? 1 : -1; + }; + if constexpr (Signed) { + const bool lhs_is_neg = lhs.is_neg(); + const bool rhs_is_neg = rhs.is_neg(); + if (lhs_is_neg != rhs_is_neg) + return rhs_is_neg ? 1 : -1; + } + for (size_t i = WORD_COUNT; i-- > 0;) + if (auto cmp = compare(lhs[i], rhs[i]); cmp != 0) + return cmp; + return 0; + } + + LIBC_INLINE constexpr void bitwise_not() { + for (auto &part : val) + part = ~part; + } + + LIBC_INLINE constexpr void negate() { + bitwise_not(); + increment(); + } + + LIBC_INLINE constexpr void increment() { + multiword::add_with_carry(val, cpp::array<WordType, 1>{1}); + } + + LIBC_INLINE constexpr void decrement() { + multiword::add_with_carry(val, cpp::array<WordType, 1>{1}); + } + + LIBC_INLINE constexpr void extend(size_t index, bool is_neg) { + const WordType value = is_neg ? cpp::numeric_limits<WordType>::max() + : cpp::numeric_limits<WordType>::min(); + for (size_t i = index; i < WORD_COUNT; ++i) + val[i] = value; + } + + LIBC_INLINE constexpr bool get_msb() const { + return val.back() >> (WORD_SIZE - 1); + } + + LIBC_INLINE constexpr void set_msb() { + val.back() |= mask_leading_ones<WordType, 1>(); + } + + LIBC_INLINE constexpr void clear_msb() { + val.back() &= mask_trailing_ones<WordType, WORD_SIZE - 1>(); + } + + LIBC_INLINE constexpr void set_bit(size_t i) { + const size_t word_index = i / WORD_SIZE; + val[word_index] |= WordType(1) << (i % WORD_SIZE); + } + + LIBC_INLINE constexpr static Division divide_unsigned(const BigInt ÷nd, + const BigInt ÷r) { + BigInt remainder = dividend; + BigInt quotient; + if (remainder >= divider) { + BigInt subtractor = divider; + int cur_bit = multiword::countl_zero(subtractor.val) - + multiword::countl_zero(remainder.val); + subtractor <<= cur_bit; + for (; cur_bit >= 0 && remainder > 0; --cur_bit, subtractor >>= 1) { + if (remainder < subtractor) + continue; + remainder -= subtractor; + quotient.set_bit(cur_bit); + } + } + return Division{quotient, remainder}; + } + + LIBC_INLINE constexpr static Division divide_signed(const BigInt ÷nd, + const BigInt ÷r) { + // Special case because it is not possible to negate the min value of a + // signed integer. + if (dividend == min() && divider == min()) + return Division{one(), zero()}; + // 1. Convert the dividend and divisor to unsigned representation. + unsigned_type udividend(dividend); + unsigned_type udivider(divider); + // 2. Negate the dividend if it's negative, and similarly for the divisor. + const bool dividend_is_neg = dividend.is_neg(); + const bool divider_is_neg = divider.is_neg(); + if (dividend_is_neg) + udividend.negate(); + if (divider_is_neg) + udivider.negate(); + // 3. Use unsigned multiword division algorithm. + const auto unsigned_result = divide_unsigned(udividend, udivider); + // 4. Convert the quotient and remainder to signed representation. + Division result; + result.quotient = signed_type(unsigned_result.quotient); + result.remainder = signed_type(unsigned_result.remainder); + // 5. Negate the quotient if the dividend and divisor had opposite signs. + if (dividend_is_neg != divider_is_neg) + result.quotient.negate(); + // 6. Negate the remainder if the dividend was negative. + if (dividend_is_neg) + result.remainder.negate(); + return result; + } + + friend signed_type; + friend unsigned_type; +}; + +namespace internal { +// We default BigInt's WordType to 'uint64_t' or 'uint32_t' depending on type +// availability. +template <size_t Bits> +struct WordTypeSelector : cpp::type_identity< +#ifdef LIBC_TYPES_HAS_INT64 + uint64_t +#else + uint32_t +#endif // LIBC_TYPES_HAS_INT64 + > { +}; +// Except if we request 16 or 32 bits explicitly. +template <> struct WordTypeSelector<16> : cpp::type_identity<uint16_t> {}; +template <> struct WordTypeSelector<32> : cpp::type_identity<uint32_t> {}; +template <> struct WordTypeSelector<96> : cpp::type_identity<uint32_t> {}; + +template <size_t Bits> +using WordTypeSelectorT = typename WordTypeSelector<Bits>::type; +} // namespace internal + +template <size_t Bits> +using UInt = BigInt<Bits, false, internal::WordTypeSelectorT<Bits>>; + +template <size_t Bits> +using Int = BigInt<Bits, true, internal::WordTypeSelectorT<Bits>>; + +// Provides limits of BigInt. +template <size_t Bits, bool Signed, typename T> +struct cpp::numeric_limits<BigInt<Bits, Signed, T>> { + LIBC_INLINE static constexpr BigInt<Bits, Signed, T> max() { + return BigInt<Bits, Signed, T>::max(); + } + LIBC_INLINE static constexpr BigInt<Bits, Signed, T> min() { + return BigInt<Bits, Signed, T>::min(); + } + // Meant to match std::numeric_limits interface. + // NOLINTNEXTLINE(readability-identifier-naming) + LIBC_INLINE_VAR static constexpr int digits = Bits - Signed; +}; + +// type traits to determine whether a T is a BigInt. +template <typename T> struct is_big_int : cpp::false_type {}; + +template <size_t Bits, bool Signed, typename T> +struct is_big_int<BigInt<Bits, Signed, T>> : cpp::true_type {}; + +template <class T> +LIBC_INLINE_VAR constexpr bool is_big_int_v = is_big_int<T>::value; + +// extensions of type traits to include BigInt + +// is_integral_or_big_int +template <typename T> +struct is_integral_or_big_int + : cpp::bool_constant<(cpp::is_integral_v<T> || is_big_int_v<T>)> {}; + +template <typename T> +LIBC_INLINE_VAR constexpr bool is_integral_or_big_int_v = + is_integral_or_big_int<T>::value; + +// make_big_int_unsigned +template <typename T> struct make_big_int_unsigned; + +template <size_t Bits, bool Signed, typename T> +struct make_big_int_unsigned<BigInt<Bits, Signed, T>> + : cpp::type_identity<BigInt<Bits, false, T>> {}; + +template <typename T> +using make_big_int_unsigned_t = typename make_big_int_unsigned<T>::type; + +// make_big_int_signed +template <typename T> struct make_big_int_signed; + +template <size_t Bits, bool Signed, typename T> +struct make_big_int_signed<BigInt<Bits, Signed, T>> + : cpp::type_identity<BigInt<Bits, true, T>> {}; + +template <typename T> +using make_big_int_signed_t = typename make_big_int_signed<T>::type; + +// make_integral_or_big_int_unsigned +template <typename T, class = void> struct make_integral_or_big_int_unsigned; + +template <typename T> +struct make_integral_or_big_int_unsigned< + T, cpp::enable_if_t<cpp::is_integral_v<T>>> : cpp::make_unsigned<T> {}; + +template <typename T> +struct make_integral_or_big_int_unsigned<T, cpp::enable_if_t<is_big_int_v<T>>> + : make_big_int_unsigned<T> {}; + +template <typename T> +using make_integral_or_big_int_unsigned_t = + typename make_integral_or_big_int_unsigned<T>::type; + +// make_integral_or_big_int_signed +template <typename T, class = void> struct make_integral_or_big_int_signed; + +template <typename T> +struct make_integral_or_big_int_signed<T, + cpp::enable_if_t<cpp::is_integral_v<T>>> + : cpp::make_signed<T> {}; + +template <typename T> +struct make_integral_or_big_int_signed<T, cpp::enable_if_t<is_big_int_v<T>>> + : make_big_int_signed<T> {}; + +template <typename T> +using make_integral_or_big_int_signed_t = + typename make_integral_or_big_int_signed<T>::type; + +// is_unsigned_integral_or_big_int +template <typename T> +struct is_unsigned_integral_or_big_int + : cpp::bool_constant< + cpp::is_same_v<T, make_integral_or_big_int_unsigned_t<T>>> {}; + +template <typename T> +// Meant to look like <type_traits> helper variable templates. +// NOLINTNEXTLINE(readability-identifier-naming) +LIBC_INLINE_VAR constexpr bool is_unsigned_integral_or_big_int_v = + is_unsigned_integral_or_big_int<T>::value; + +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> +popcount(T value) { + int bits = 0; + for (auto word : value.val) + if (word) + bits += popcount(word); + return bits; +} + +// Specialization of cpp::has_single_bit ('bit.h') for BigInt. +template <typename T> +[[nodiscard]] LIBC_INLINE constexpr cpp::enable_if_t<is_big_int_v<T>, bool> +has_single_bit(T value) { + int bits = 0; + for (auto word : value.val) { + if (word == 0) + continue; + bits += popcount(word); + if (bits > 1) + return false; + } + return bits == 1; +} + +// Specialization of cpp::countr_zero ('bit.h') for BigInt. +template <typename T> +[[nodiscard]] LIBC_INLINE constexpr cpp::enable_if_t<is_big_int_v<T>, int> +countr_zero(const T &value) { + return multiword::countr_zero(value.val); +} + +// Specialization of cpp::countl_zero ('bit.h') for BigInt. +template <typename T> +[[nodiscard]] LIBC_INLINE constexpr cpp::enable_if_t<is_big_int_v<T>, int> +countl_zero(const T &value) { + return multiword::countl_zero(value.val); +} + +// Specialization of cpp::countl_one ('bit.h') for BigInt. +template <typename T> +[[nodiscard]] LIBC_INLINE constexpr cpp::enable_if_t<is_big_int_v<T>, int> +countl_one(T value) { + return multiword::countl_one(value.val); +} + +// Specialization of cpp::countr_one ('bit.h') for BigInt. +template <typename T> +[[nodiscard]] LIBC_INLINE constexpr cpp::enable_if_t<is_big_int_v<T>, int> +countr_one(T value) { + return multiword::countr_one(value.val); +} + +// Specialization of cpp::bit_width ('bit.h') for BigInt. +template <typename T> +[[nodiscard]] LIBC_INLINE constexpr cpp::enable_if_t<is_big_int_v<T>, int> +bit_width(T value) { + return cpp::numeric_limits<T>::digits - cpp::countl_zero(value); +} + +// Forward-declare rotr so that rotl can use it. +template <typename T> +[[nodiscard]] LIBC_INLINE constexpr cpp::enable_if_t<is_big_int_v<T>, T> +rotr(T value, int rotate); + +// Specialization of cpp::rotl ('bit.h') for BigInt. +template <typename T> +[[nodiscard]] LIBC_INLINE constexpr cpp::enable_if_t<is_big_int_v<T>, T> +rotl(T value, int rotate) { + constexpr unsigned N = cpp::numeric_limits<T>::digits; + rotate = rotate % N; + if (!rotate) + return value; + if (rotate < 0) + return cpp::rotr<T>(value, -rotate); + return (value << rotate) | (value >> (N - rotate)); +} + +// Specialization of cpp::rotr ('bit.h') for BigInt. +template <typename T> +[[nodiscard]] LIBC_INLINE constexpr cpp::enable_if_t<is_big_int_v<T>, T> +rotr(T value, int rotate) { + constexpr unsigned N = cpp::numeric_limits<T>::digits; + rotate = rotate % N; + if (!rotate) + return value; + if (rotate < 0) + return cpp::rotl<T>(value, -rotate); + return (value >> rotate) | (value << (N - rotate)); +} + +} // namespace cpp + +// Specialization of mask_trailing_ones ('math_extras.h') for BigInt. +template <typename T, size_t count> +LIBC_INLINE constexpr cpp::enable_if_t<is_big_int_v<T>, T> +mask_trailing_ones() { + static_assert(!T::SIGNED && count <= T::BITS); + if (count == T::BITS) + return T::all_ones(); + constexpr size_t QUOTIENT = count / T::WORD_SIZE; + constexpr size_t REMAINDER = count % T::WORD_SIZE; + T out; // zero initialized + for (size_t i = 0; i <= QUOTIENT; ++i) + out[i] = i < QUOTIENT + ? -1 + : mask_trailing_ones<typename T::word_type, REMAINDER>(); + return out; +} + +// Specialization of mask_leading_ones ('math_extras.h') for BigInt. +template <typename T, size_t count> +LIBC_INLINE constexpr cpp::enable_if_t<is_big_int_v<T>, T> mask_leading_ones() { + static_assert(!T::SIGNED && count <= T::BITS); + if (count == T::BITS) + 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 + for (size_t i = QUOTIENT; i < T::WORD_COUNT; ++i) + out[i] = i > QUOTIENT + ? -1 + : mask_leading_ones<typename T::word_type, REMAINDER>(); + return out; +} + +// Specialization of mask_trailing_zeros ('math_extras.h') for BigInt. +template <typename T, size_t count> +LIBC_INLINE constexpr cpp::enable_if_t<is_big_int_v<T>, T> +mask_trailing_zeros() { + return mask_leading_ones<T, T::BITS - count>(); +} + +// Specialization of mask_leading_zeros ('math_extras.h') for BigInt. +template <typename T, size_t count> +LIBC_INLINE constexpr cpp::enable_if_t<is_big_int_v<T>, T> +mask_leading_zeros() { + return mask_trailing_ones<T, T::BITS - count>(); +} + +// Specialization of count_zeros ('math_extras.h') for BigInt. +template <typename T> +[[nodiscard]] LIBC_INLINE constexpr cpp::enable_if_t<is_big_int_v<T>, int> +count_zeros(T value) { + return cpp::popcount(~value); +} + +// Specialization of first_leading_zero ('math_extras.h') for BigInt. +template <typename T> +[[nodiscard]] LIBC_INLINE constexpr cpp::enable_if_t<is_big_int_v<T>, int> +first_leading_zero(T value) { + return value == cpp::numeric_limits<T>::max() ? 0 + : cpp::countl_one(value) + 1; +} + +// Specialization of first_leading_one ('math_extras.h') for BigInt. +template <typename T> +[[nodiscard]] LIBC_INLINE constexpr cpp::enable_if_t<is_big_int_v<T>, int> +first_leading_one(T value) { + return first_leading_zero(~value); +} + +// Specialization of first_trailing_zero ('math_extras.h') for BigInt. +template <typename T> +[[nodiscard]] LIBC_INLINE constexpr cpp::enable_if_t<is_big_int_v<T>, int> +first_trailing_zero(T value) { + return value == cpp::numeric_limits<T>::max() ? 0 + : cpp::countr_zero(~value) + 1; +} + +// Specialization of first_trailing_one ('math_extras.h') for BigInt. +template <typename T> +[[nodiscard]] LIBC_INLINE constexpr cpp::enable_if_t<is_big_int_v<T>, int> +first_trailing_one(T value) { + return value == cpp::numeric_limits<T>::max() ? 0 + : cpp::countr_zero(value) + 1; +} + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_BIG_INT_H diff --git a/lib/libcxx/libc/src/__support/common.h b/lib/libcxx/libc/src/__support/common.h new file mode 100644 index 0000000000..42e8a79187 --- /dev/null +++ b/lib/libcxx/libc/src/__support/common.h @@ -0,0 +1,82 @@ +//===-- Common internal contructs -------------------------------*- 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_COMMON_H +#define LLVM_LIBC_SRC___SUPPORT_COMMON_H + +#ifndef LIBC_NAMESPACE +#error "LIBC_NAMESPACE macro is not defined." +#endif + +#include "src/__support/macros/attributes.h" +#include "src/__support/macros/config.h" +#include "src/__support/macros/properties/architectures.h" + +#ifndef LLVM_LIBC_FUNCTION_ATTR +#define LLVM_LIBC_FUNCTION_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 +// "LLVM_LIBC_EMPTY, " +// +// For examples: +// #define LLVM_LIBC_FUNCTION_ATTR_memcpy LLVM_LIBC_EMPTY, [[gnu::weak]] +// #define LLVM_LIBC_FUNCTION_ATTR_memchr LLVM_LIBC_EMPTY, [[gnu::weak]] [[gnu::visibility("default")]] +// clang-format on +#define LLVM_LIBC_EMPTY + +#define GET_SECOND(first, second, ...) second +#define EXPAND_THEN_SECOND(name) GET_SECOND(name, LLVM_LIBC_EMPTY) + +#define LLVM_LIBC_ATTR(name) EXPAND_THEN_SECOND(LLVM_LIBC_FUNCTION_ATTR_##name) + +// MacOS needs to be excluded because it does not support aliasing. +#if defined(LIBC_COPT_PUBLIC_PACKAGING) && (!defined(__APPLE__)) +#define LLVM_LIBC_FUNCTION_IMPL(type, name, arglist) \ + LLVM_LIBC_ATTR(name) \ + LLVM_LIBC_FUNCTION_ATTR decltype(LIBC_NAMESPACE::name) \ + __##name##_impl__ __asm__(#name); \ + decltype(LIBC_NAMESPACE::name) name [[gnu::alias(#name)]]; \ + type __##name##_impl__ arglist +#else +#define LLVM_LIBC_FUNCTION_IMPL(type, name, arglist) type name arglist +#endif + +// 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) + +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 + +#define __LIBC_MACRO_TO_STRING(str) #str +#define LIBC_MACRO_TO_STRING(str) __LIBC_MACRO_TO_STRING(str) + +// 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 + +#endif // LLVM_LIBC_SRC___SUPPORT_COMMON_H diff --git a/lib/libcxx/libc/src/__support/ctype_utils.h b/lib/libcxx/libc/src/__support/ctype_utils.h new file mode 100644 index 0000000000..be0f25330a --- /dev/null +++ b/lib/libcxx/libc/src/__support/ctype_utils.h @@ -0,0 +1,584 @@ +//===-- Collection of utils for implementing ctype functions-------*-C++-*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_CTYPE_UTILS_H +#define LLVM_LIBC_SRC___SUPPORT_CTYPE_UTILS_H + +#include "src/__support/macros/attributes.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { +namespace internal { + +// ----------------------------------------------------------------------------- +// ****************** WARNING ****************** +// ****************** DO NOT TRY TO OPTIMIZE THESE FUNCTIONS! ****************** +// ----------------------------------------------------------------------------- +// This switch/case form is easier for the compiler to understand, and is +// optimized into a form that is almost always the same as or better than +// versions written by hand (see https://godbolt.org/z/qvrebqvvr). Also this +// form makes these functions encoding independent. If you want to rewrite these +// functions, make sure you have benchmarks to show your new solution is faster, +// as well as a way to support non-ASCII character encodings. + +// Similarly, do not change these functions to use case ranges. e.g. +// bool islower(int ch) { +// switch(ch) { +// case 'a'...'z': +// return true; +// } +// } +// This assumes the character ranges are contiguous, which they aren't in +// EBCDIC. Technically we could use some smaller ranges, but that's even harder +// to read. + +LIBC_INLINE static constexpr bool islower(int ch) { + switch (ch) { + case 'a': + case 'b': + case 'c': + case 'd': + case 'e': + case 'f': + case 'g': + case 'h': + case 'i': + case 'j': + case 'k': + case 'l': + case 'm': + case 'n': + case 'o': + case 'p': + case 'q': + case 'r': + case 's': + case 't': + case 'u': + case 'v': + case 'w': + case 'x': + case 'y': + case 'z': + return true; + default: + return false; + } +} + +LIBC_INLINE static constexpr bool isupper(int ch) { + switch (ch) { + case 'A': + case 'B': + case 'C': + case 'D': + case 'E': + case 'F': + case 'G': + case 'H': + case 'I': + case 'J': + case 'K': + case 'L': + case 'M': + case 'N': + case 'O': + case 'P': + case 'Q': + case 'R': + case 'S': + case 'T': + case 'U': + case 'V': + case 'W': + case 'X': + case 'Y': + case 'Z': + return true; + default: + return false; + } +} + +LIBC_INLINE static constexpr bool isdigit(int ch) { + switch (ch) { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + return true; + default: + return false; + } +} + +LIBC_INLINE static constexpr int tolower(int ch) { + switch (ch) { + case 'A': + return 'a'; + case 'B': + return 'b'; + case 'C': + return 'c'; + case 'D': + return 'd'; + case 'E': + return 'e'; + case 'F': + return 'f'; + case 'G': + return 'g'; + case 'H': + return 'h'; + case 'I': + return 'i'; + case 'J': + return 'j'; + case 'K': + return 'k'; + case 'L': + return 'l'; + case 'M': + return 'm'; + case 'N': + return 'n'; + case 'O': + return 'o'; + case 'P': + return 'p'; + case 'Q': + return 'q'; + case 'R': + return 'r'; + case 'S': + return 's'; + case 'T': + return 't'; + case 'U': + return 'u'; + case 'V': + return 'v'; + case 'W': + return 'w'; + case 'X': + return 'x'; + case 'Y': + return 'y'; + case 'Z': + return 'z'; + default: + return ch; + } +} + +LIBC_INLINE static constexpr int toupper(int ch) { + switch (ch) { + case 'a': + return 'A'; + case 'b': + return 'B'; + case 'c': + return 'C'; + case 'd': + return 'D'; + case 'e': + return 'E'; + case 'f': + return 'F'; + case 'g': + return 'G'; + case 'h': + return 'H'; + case 'i': + return 'I'; + case 'j': + return 'J'; + case 'k': + return 'K'; + case 'l': + return 'L'; + case 'm': + return 'M'; + case 'n': + return 'N'; + case 'o': + return 'O'; + case 'p': + return 'P'; + case 'q': + return 'Q'; + case 'r': + return 'R'; + case 's': + return 'S'; + case 't': + return 'T'; + case 'u': + return 'U'; + case 'v': + return 'V'; + case 'w': + return 'W'; + case 'x': + return 'X'; + case 'y': + return 'Y'; + case 'z': + return 'Z'; + default: + return ch; + } +} + +LIBC_INLINE static constexpr bool isalpha(int ch) { + switch (ch) { + case 'a': + case 'b': + case 'c': + case 'd': + case 'e': + case 'f': + case 'g': + case 'h': + case 'i': + case 'j': + case 'k': + case 'l': + case 'm': + case 'n': + case 'o': + case 'p': + case 'q': + case 'r': + case 's': + case 't': + case 'u': + case 'v': + case 'w': + case 'x': + case 'y': + case 'z': + case 'A': + case 'B': + case 'C': + case 'D': + case 'E': + case 'F': + case 'G': + case 'H': + case 'I': + case 'J': + case 'K': + case 'L': + case 'M': + case 'N': + case 'O': + case 'P': + case 'Q': + case 'R': + case 'S': + case 'T': + case 'U': + case 'V': + case 'W': + case 'X': + case 'Y': + case 'Z': + return true; + default: + return false; + } +} + +LIBC_INLINE static constexpr bool isalnum(int ch) { + switch (ch) { + case 'a': + case 'b': + case 'c': + case 'd': + case 'e': + case 'f': + case 'g': + case 'h': + case 'i': + case 'j': + case 'k': + case 'l': + case 'm': + case 'n': + case 'o': + case 'p': + case 'q': + case 'r': + case 's': + case 't': + case 'u': + case 'v': + case 'w': + case 'x': + case 'y': + case 'z': + case 'A': + case 'B': + case 'C': + case 'D': + case 'E': + case 'F': + case 'G': + case 'H': + case 'I': + case 'J': + case 'K': + case 'L': + case 'M': + case 'N': + case 'O': + case 'P': + case 'Q': + case 'R': + case 'S': + case 'T': + case 'U': + case 'V': + case 'W': + case 'X': + case 'Y': + case 'Z': + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + return true; + default: + return false; + } +} + +LIBC_INLINE static constexpr int b36_char_to_int(int ch) { + switch (ch) { + case '0': + return 0; + case '1': + return 1; + case '2': + return 2; + case '3': + return 3; + case '4': + return 4; + case '5': + return 5; + case '6': + return 6; + case '7': + return 7; + case '8': + return 8; + case '9': + return 9; + case 'a': + case 'A': + return 10; + case 'b': + case 'B': + return 11; + case 'c': + case 'C': + return 12; + case 'd': + case 'D': + return 13; + case 'e': + case 'E': + return 14; + case 'f': + case 'F': + return 15; + case 'g': + case 'G': + return 16; + case 'h': + case 'H': + return 17; + case 'i': + case 'I': + return 18; + case 'j': + case 'J': + return 19; + case 'k': + case 'K': + return 20; + case 'l': + case 'L': + return 21; + case 'm': + case 'M': + return 22; + case 'n': + case 'N': + return 23; + case 'o': + case 'O': + return 24; + case 'p': + case 'P': + return 25; + case 'q': + case 'Q': + return 26; + case 'r': + case 'R': + return 27; + case 's': + case 'S': + return 28; + case 't': + case 'T': + return 29; + case 'u': + case 'U': + return 30; + case 'v': + case 'V': + return 31; + case 'w': + case 'W': + return 32; + case 'x': + case 'X': + return 33; + case 'y': + case 'Y': + return 34; + case 'z': + case 'Z': + return 35; + default: + return 0; + } +} + +LIBC_INLINE static constexpr int int_to_b36_char(int num) { + // Can't actually use LIBC_ASSERT here because it depends on integer_to_string + // which depends on this. + + // LIBC_ASSERT(num < 36); + switch (num) { + case 0: + return '0'; + case 1: + return '1'; + case 2: + return '2'; + case 3: + return '3'; + case 4: + return '4'; + case 5: + return '5'; + case 6: + return '6'; + case 7: + return '7'; + case 8: + return '8'; + case 9: + return '9'; + case 10: + return 'a'; + case 11: + return 'b'; + case 12: + return 'c'; + case 13: + return 'd'; + case 14: + return 'e'; + case 15: + return 'f'; + case 16: + return 'g'; + case 17: + return 'h'; + case 18: + return 'i'; + case 19: + return 'j'; + case 20: + return 'k'; + case 21: + return 'l'; + case 22: + return 'm'; + case 23: + return 'n'; + case 24: + return 'o'; + case 25: + return 'p'; + case 26: + return 'q'; + case 27: + return 'r'; + case 28: + return 's'; + case 29: + return 't'; + case 30: + return 'u'; + case 31: + return 'v'; + case 32: + return 'w'; + case 33: + return 'x'; + case 34: + return 'y'; + case 35: + return 'z'; + default: + return '!'; + } +} + +LIBC_INLINE static constexpr bool isspace(int ch) { + switch (ch) { + case ' ': + case '\t': + case '\n': + case '\v': + case '\f': + case '\r': + return true; + default: + return false; + } +} + +// not yet encoding independent. +LIBC_INLINE static constexpr bool isgraph(int ch) { + return 0x20 < ch && ch < 0x7f; +} + +} // namespace internal +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_CTYPE_UTILS_H diff --git a/lib/libcxx/libc/src/__support/detailed_powers_of_ten.h b/lib/libcxx/libc/src/__support/detailed_powers_of_ten.h new file mode 100644 index 0000000000..28741b8a3f --- /dev/null +++ b/lib/libcxx/libc/src/__support/detailed_powers_of_ten.h @@ -0,0 +1,740 @@ +//===-- detailed powers of ten ----------------------------------*- 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_DETAILED_POWERS_OF_TEN_H +#define LLVM_LIBC_SRC___SUPPORT_DETAILED_POWERS_OF_TEN_H + +#include "src/__support/common.h" +#include "src/__support/macros/config.h" + +#include <stdint.h> + +namespace LIBC_NAMESPACE_DECL { +namespace internal { + +// TODO(michaelrj): write a script that will generate this table. + +// This table was generated by +// https://github.com/google/wuffs/blob/788479dd64f35cb6b4e998a851acb06ee962435b/script/print-mpb-powers-of-10.go +// and contains the 128 bit mantissa approximations of the powers of 10 from +// -348 to 347. The exponents are implied by a linear expression with slope +// 217706.0/65536.0 ≈ log(10)/log(2). This is used by the Eisel-Lemire algorithm +// in str_to_float.h. + +constexpr int32_t DETAILED_POWERS_OF_TEN_MIN_EXP_10 = -348; +constexpr int32_t DETAILED_POWERS_OF_TEN_MAX_EXP_10 = 347; + +// This rescales the base 10 exponent by a factor of log(10)/log(2). +LIBC_INLINE int32_t exp10_to_exp2(int32_t exp10) { + // Valid if exp10 < 646 456 636. + return static_cast<int32_t>((217706 * static_cast<int64_t>(exp10)) >> 16); +} + +static constexpr uint64_t DETAILED_POWERS_OF_TEN[696][2] = { + {0x1732C869CD60E453, 0xFA8FD5A0081C0288}, // 1e-348 + {0x0E7FBD42205C8EB4, 0x9C99E58405118195}, // 1e-347 + {0x521FAC92A873B261, 0xC3C05EE50655E1FA}, // 1e-346 + {0xE6A797B752909EF9, 0xF4B0769E47EB5A78}, // 1e-345 + {0x9028BED2939A635C, 0x98EE4A22ECF3188B}, // 1e-344 + {0x7432EE873880FC33, 0xBF29DCABA82FDEAE}, // 1e-343 + {0x113FAA2906A13B3F, 0xEEF453D6923BD65A}, // 1e-342 + {0x4AC7CA59A424C507, 0x9558B4661B6565F8}, // 1e-341 + {0x5D79BCF00D2DF649, 0xBAAEE17FA23EBF76}, // 1e-340 + {0xF4D82C2C107973DC, 0xE95A99DF8ACE6F53}, // 1e-339 + {0x79071B9B8A4BE869, 0x91D8A02BB6C10594}, // 1e-338 + {0x9748E2826CDEE284, 0xB64EC836A47146F9}, // 1e-337 + {0xFD1B1B2308169B25, 0xE3E27A444D8D98B7}, // 1e-336 + {0xFE30F0F5E50E20F7, 0x8E6D8C6AB0787F72}, // 1e-335 + {0xBDBD2D335E51A935, 0xB208EF855C969F4F}, // 1e-334 + {0xAD2C788035E61382, 0xDE8B2B66B3BC4723}, // 1e-333 + {0x4C3BCB5021AFCC31, 0x8B16FB203055AC76}, // 1e-332 + {0xDF4ABE242A1BBF3D, 0xADDCB9E83C6B1793}, // 1e-331 + {0xD71D6DAD34A2AF0D, 0xD953E8624B85DD78}, // 1e-330 + {0x8672648C40E5AD68, 0x87D4713D6F33AA6B}, // 1e-329 + {0x680EFDAF511F18C2, 0xA9C98D8CCB009506}, // 1e-328 + {0x0212BD1B2566DEF2, 0xD43BF0EFFDC0BA48}, // 1e-327 + {0x014BB630F7604B57, 0x84A57695FE98746D}, // 1e-326 + {0x419EA3BD35385E2D, 0xA5CED43B7E3E9188}, // 1e-325 + {0x52064CAC828675B9, 0xCF42894A5DCE35EA}, // 1e-324 + {0x7343EFEBD1940993, 0x818995CE7AA0E1B2}, // 1e-323 + {0x1014EBE6C5F90BF8, 0xA1EBFB4219491A1F}, // 1e-322 + {0xD41A26E077774EF6, 0xCA66FA129F9B60A6}, // 1e-321 + {0x8920B098955522B4, 0xFD00B897478238D0}, // 1e-320 + {0x55B46E5F5D5535B0, 0x9E20735E8CB16382}, // 1e-319 + {0xEB2189F734AA831D, 0xC5A890362FDDBC62}, // 1e-318 + {0xA5E9EC7501D523E4, 0xF712B443BBD52B7B}, // 1e-317 + {0x47B233C92125366E, 0x9A6BB0AA55653B2D}, // 1e-316 + {0x999EC0BB696E840A, 0xC1069CD4EABE89F8}, // 1e-315 + {0xC00670EA43CA250D, 0xF148440A256E2C76}, // 1e-314 + {0x380406926A5E5728, 0x96CD2A865764DBCA}, // 1e-313 + {0xC605083704F5ECF2, 0xBC807527ED3E12BC}, // 1e-312 + {0xF7864A44C633682E, 0xEBA09271E88D976B}, // 1e-311 + {0x7AB3EE6AFBE0211D, 0x93445B8731587EA3}, // 1e-310 + {0x5960EA05BAD82964, 0xB8157268FDAE9E4C}, // 1e-309 + {0x6FB92487298E33BD, 0xE61ACF033D1A45DF}, // 1e-308 + {0xA5D3B6D479F8E056, 0x8FD0C16206306BAB}, // 1e-307 + {0x8F48A4899877186C, 0xB3C4F1BA87BC8696}, // 1e-306 + {0x331ACDABFE94DE87, 0xE0B62E2929ABA83C}, // 1e-305 + {0x9FF0C08B7F1D0B14, 0x8C71DCD9BA0B4925}, // 1e-304 + {0x07ECF0AE5EE44DD9, 0xAF8E5410288E1B6F}, // 1e-303 + {0xC9E82CD9F69D6150, 0xDB71E91432B1A24A}, // 1e-302 + {0xBE311C083A225CD2, 0x892731AC9FAF056E}, // 1e-301 + {0x6DBD630A48AAF406, 0xAB70FE17C79AC6CA}, // 1e-300 + {0x092CBBCCDAD5B108, 0xD64D3D9DB981787D}, // 1e-299 + {0x25BBF56008C58EA5, 0x85F0468293F0EB4E}, // 1e-298 + {0xAF2AF2B80AF6F24E, 0xA76C582338ED2621}, // 1e-297 + {0x1AF5AF660DB4AEE1, 0xD1476E2C07286FAA}, // 1e-296 + {0x50D98D9FC890ED4D, 0x82CCA4DB847945CA}, // 1e-295 + {0xE50FF107BAB528A0, 0xA37FCE126597973C}, // 1e-294 + {0x1E53ED49A96272C8, 0xCC5FC196FEFD7D0C}, // 1e-293 + {0x25E8E89C13BB0F7A, 0xFF77B1FCBEBCDC4F}, // 1e-292 + {0x77B191618C54E9AC, 0x9FAACF3DF73609B1}, // 1e-291 + {0xD59DF5B9EF6A2417, 0xC795830D75038C1D}, // 1e-290 + {0x4B0573286B44AD1D, 0xF97AE3D0D2446F25}, // 1e-289 + {0x4EE367F9430AEC32, 0x9BECCE62836AC577}, // 1e-288 + {0x229C41F793CDA73F, 0xC2E801FB244576D5}, // 1e-287 + {0x6B43527578C1110F, 0xF3A20279ED56D48A}, // 1e-286 + {0x830A13896B78AAA9, 0x9845418C345644D6}, // 1e-285 + {0x23CC986BC656D553, 0xBE5691EF416BD60C}, // 1e-284 + {0x2CBFBE86B7EC8AA8, 0xEDEC366B11C6CB8F}, // 1e-283 + {0x7BF7D71432F3D6A9, 0x94B3A202EB1C3F39}, // 1e-282 + {0xDAF5CCD93FB0CC53, 0xB9E08A83A5E34F07}, // 1e-281 + {0xD1B3400F8F9CFF68, 0xE858AD248F5C22C9}, // 1e-280 + {0x23100809B9C21FA1, 0x91376C36D99995BE}, // 1e-279 + {0xABD40A0C2832A78A, 0xB58547448FFFFB2D}, // 1e-278 + {0x16C90C8F323F516C, 0xE2E69915B3FFF9F9}, // 1e-277 + {0xAE3DA7D97F6792E3, 0x8DD01FAD907FFC3B}, // 1e-276 + {0x99CD11CFDF41779C, 0xB1442798F49FFB4A}, // 1e-275 + {0x40405643D711D583, 0xDD95317F31C7FA1D}, // 1e-274 + {0x482835EA666B2572, 0x8A7D3EEF7F1CFC52}, // 1e-273 + {0xDA3243650005EECF, 0xAD1C8EAB5EE43B66}, // 1e-272 + {0x90BED43E40076A82, 0xD863B256369D4A40}, // 1e-271 + {0x5A7744A6E804A291, 0x873E4F75E2224E68}, // 1e-270 + {0x711515D0A205CB36, 0xA90DE3535AAAE202}, // 1e-269 + {0x0D5A5B44CA873E03, 0xD3515C2831559A83}, // 1e-268 + {0xE858790AFE9486C2, 0x8412D9991ED58091}, // 1e-267 + {0x626E974DBE39A872, 0xA5178FFF668AE0B6}, // 1e-266 + {0xFB0A3D212DC8128F, 0xCE5D73FF402D98E3}, // 1e-265 + {0x7CE66634BC9D0B99, 0x80FA687F881C7F8E}, // 1e-264 + {0x1C1FFFC1EBC44E80, 0xA139029F6A239F72}, // 1e-263 + {0xA327FFB266B56220, 0xC987434744AC874E}, // 1e-262 + {0x4BF1FF9F0062BAA8, 0xFBE9141915D7A922}, // 1e-261 + {0x6F773FC3603DB4A9, 0x9D71AC8FADA6C9B5}, // 1e-260 + {0xCB550FB4384D21D3, 0xC4CE17B399107C22}, // 1e-259 + {0x7E2A53A146606A48, 0xF6019DA07F549B2B}, // 1e-258 + {0x2EDA7444CBFC426D, 0x99C102844F94E0FB}, // 1e-257 + {0xFA911155FEFB5308, 0xC0314325637A1939}, // 1e-256 + {0x793555AB7EBA27CA, 0xF03D93EEBC589F88}, // 1e-255 + {0x4BC1558B2F3458DE, 0x96267C7535B763B5}, // 1e-254 + {0x9EB1AAEDFB016F16, 0xBBB01B9283253CA2}, // 1e-253 + {0x465E15A979C1CADC, 0xEA9C227723EE8BCB}, // 1e-252 + {0x0BFACD89EC191EC9, 0x92A1958A7675175F}, // 1e-251 + {0xCEF980EC671F667B, 0xB749FAED14125D36}, // 1e-250 + {0x82B7E12780E7401A, 0xE51C79A85916F484}, // 1e-249 + {0xD1B2ECB8B0908810, 0x8F31CC0937AE58D2}, // 1e-248 + {0x861FA7E6DCB4AA15, 0xB2FE3F0B8599EF07}, // 1e-247 + {0x67A791E093E1D49A, 0xDFBDCECE67006AC9}, // 1e-246 + {0xE0C8BB2C5C6D24E0, 0x8BD6A141006042BD}, // 1e-245 + {0x58FAE9F773886E18, 0xAECC49914078536D}, // 1e-244 + {0xAF39A475506A899E, 0xDA7F5BF590966848}, // 1e-243 + {0x6D8406C952429603, 0x888F99797A5E012D}, // 1e-242 + {0xC8E5087BA6D33B83, 0xAAB37FD7D8F58178}, // 1e-241 + {0xFB1E4A9A90880A64, 0xD5605FCDCF32E1D6}, // 1e-240 + {0x5CF2EEA09A55067F, 0x855C3BE0A17FCD26}, // 1e-239 + {0xF42FAA48C0EA481E, 0xA6B34AD8C9DFC06F}, // 1e-238 + {0xF13B94DAF124DA26, 0xD0601D8EFC57B08B}, // 1e-237 + {0x76C53D08D6B70858, 0x823C12795DB6CE57}, // 1e-236 + {0x54768C4B0C64CA6E, 0xA2CB1717B52481ED}, // 1e-235 + {0xA9942F5DCF7DFD09, 0xCB7DDCDDA26DA268}, // 1e-234 + {0xD3F93B35435D7C4C, 0xFE5D54150B090B02}, // 1e-233 + {0xC47BC5014A1A6DAF, 0x9EFA548D26E5A6E1}, // 1e-232 + {0x359AB6419CA1091B, 0xC6B8E9B0709F109A}, // 1e-231 + {0xC30163D203C94B62, 0xF867241C8CC6D4C0}, // 1e-230 + {0x79E0DE63425DCF1D, 0x9B407691D7FC44F8}, // 1e-229 + {0x985915FC12F542E4, 0xC21094364DFB5636}, // 1e-228 + {0x3E6F5B7B17B2939D, 0xF294B943E17A2BC4}, // 1e-227 + {0xA705992CEECF9C42, 0x979CF3CA6CEC5B5A}, // 1e-226 + {0x50C6FF782A838353, 0xBD8430BD08277231}, // 1e-225 + {0xA4F8BF5635246428, 0xECE53CEC4A314EBD}, // 1e-224 + {0x871B7795E136BE99, 0x940F4613AE5ED136}, // 1e-223 + {0x28E2557B59846E3F, 0xB913179899F68584}, // 1e-222 + {0x331AEADA2FE589CF, 0xE757DD7EC07426E5}, // 1e-221 + {0x3FF0D2C85DEF7621, 0x9096EA6F3848984F}, // 1e-220 + {0x0FED077A756B53A9, 0xB4BCA50B065ABE63}, // 1e-219 + {0xD3E8495912C62894, 0xE1EBCE4DC7F16DFB}, // 1e-218 + {0x64712DD7ABBBD95C, 0x8D3360F09CF6E4BD}, // 1e-217 + {0xBD8D794D96AACFB3, 0xB080392CC4349DEC}, // 1e-216 + {0xECF0D7A0FC5583A0, 0xDCA04777F541C567}, // 1e-215 + {0xF41686C49DB57244, 0x89E42CAAF9491B60}, // 1e-214 + {0x311C2875C522CED5, 0xAC5D37D5B79B6239}, // 1e-213 + {0x7D633293366B828B, 0xD77485CB25823AC7}, // 1e-212 + {0xAE5DFF9C02033197, 0x86A8D39EF77164BC}, // 1e-211 + {0xD9F57F830283FDFC, 0xA8530886B54DBDEB}, // 1e-210 + {0xD072DF63C324FD7B, 0xD267CAA862A12D66}, // 1e-209 + {0x4247CB9E59F71E6D, 0x8380DEA93DA4BC60}, // 1e-208 + {0x52D9BE85F074E608, 0xA46116538D0DEB78}, // 1e-207 + {0x67902E276C921F8B, 0xCD795BE870516656}, // 1e-206 + {0x00BA1CD8A3DB53B6, 0x806BD9714632DFF6}, // 1e-205 + {0x80E8A40ECCD228A4, 0xA086CFCD97BF97F3}, // 1e-204 + {0x6122CD128006B2CD, 0xC8A883C0FDAF7DF0}, // 1e-203 + {0x796B805720085F81, 0xFAD2A4B13D1B5D6C}, // 1e-202 + {0xCBE3303674053BB0, 0x9CC3A6EEC6311A63}, // 1e-201 + {0xBEDBFC4411068A9C, 0xC3F490AA77BD60FC}, // 1e-200 + {0xEE92FB5515482D44, 0xF4F1B4D515ACB93B}, // 1e-199 + {0x751BDD152D4D1C4A, 0x991711052D8BF3C5}, // 1e-198 + {0xD262D45A78A0635D, 0xBF5CD54678EEF0B6}, // 1e-197 + {0x86FB897116C87C34, 0xEF340A98172AACE4}, // 1e-196 + {0xD45D35E6AE3D4DA0, 0x9580869F0E7AAC0E}, // 1e-195 + {0x8974836059CCA109, 0xBAE0A846D2195712}, // 1e-194 + {0x2BD1A438703FC94B, 0xE998D258869FACD7}, // 1e-193 + {0x7B6306A34627DDCF, 0x91FF83775423CC06}, // 1e-192 + {0x1A3BC84C17B1D542, 0xB67F6455292CBF08}, // 1e-191 + {0x20CABA5F1D9E4A93, 0xE41F3D6A7377EECA}, // 1e-190 + {0x547EB47B7282EE9C, 0x8E938662882AF53E}, // 1e-189 + {0xE99E619A4F23AA43, 0xB23867FB2A35B28D}, // 1e-188 + {0x6405FA00E2EC94D4, 0xDEC681F9F4C31F31}, // 1e-187 + {0xDE83BC408DD3DD04, 0x8B3C113C38F9F37E}, // 1e-186 + {0x9624AB50B148D445, 0xAE0B158B4738705E}, // 1e-185 + {0x3BADD624DD9B0957, 0xD98DDAEE19068C76}, // 1e-184 + {0xE54CA5D70A80E5D6, 0x87F8A8D4CFA417C9}, // 1e-183 + {0x5E9FCF4CCD211F4C, 0xA9F6D30A038D1DBC}, // 1e-182 + {0x7647C3200069671F, 0xD47487CC8470652B}, // 1e-181 + {0x29ECD9F40041E073, 0x84C8D4DFD2C63F3B}, // 1e-180 + {0xF468107100525890, 0xA5FB0A17C777CF09}, // 1e-179 + {0x7182148D4066EEB4, 0xCF79CC9DB955C2CC}, // 1e-178 + {0xC6F14CD848405530, 0x81AC1FE293D599BF}, // 1e-177 + {0xB8ADA00E5A506A7C, 0xA21727DB38CB002F}, // 1e-176 + {0xA6D90811F0E4851C, 0xCA9CF1D206FDC03B}, // 1e-175 + {0x908F4A166D1DA663, 0xFD442E4688BD304A}, // 1e-174 + {0x9A598E4E043287FE, 0x9E4A9CEC15763E2E}, // 1e-173 + {0x40EFF1E1853F29FD, 0xC5DD44271AD3CDBA}, // 1e-172 + {0xD12BEE59E68EF47C, 0xF7549530E188C128}, // 1e-171 + {0x82BB74F8301958CE, 0x9A94DD3E8CF578B9}, // 1e-170 + {0xE36A52363C1FAF01, 0xC13A148E3032D6E7}, // 1e-169 + {0xDC44E6C3CB279AC1, 0xF18899B1BC3F8CA1}, // 1e-168 + {0x29AB103A5EF8C0B9, 0x96F5600F15A7B7E5}, // 1e-167 + {0x7415D448F6B6F0E7, 0xBCB2B812DB11A5DE}, // 1e-166 + {0x111B495B3464AD21, 0xEBDF661791D60F56}, // 1e-165 + {0xCAB10DD900BEEC34, 0x936B9FCEBB25C995}, // 1e-164 + {0x3D5D514F40EEA742, 0xB84687C269EF3BFB}, // 1e-163 + {0x0CB4A5A3112A5112, 0xE65829B3046B0AFA}, // 1e-162 + {0x47F0E785EABA72AB, 0x8FF71A0FE2C2E6DC}, // 1e-161 + {0x59ED216765690F56, 0xB3F4E093DB73A093}, // 1e-160 + {0x306869C13EC3532C, 0xE0F218B8D25088B8}, // 1e-159 + {0x1E414218C73A13FB, 0x8C974F7383725573}, // 1e-158 + {0xE5D1929EF90898FA, 0xAFBD2350644EEACF}, // 1e-157 + {0xDF45F746B74ABF39, 0xDBAC6C247D62A583}, // 1e-156 + {0x6B8BBA8C328EB783, 0x894BC396CE5DA772}, // 1e-155 + {0x066EA92F3F326564, 0xAB9EB47C81F5114F}, // 1e-154 + {0xC80A537B0EFEFEBD, 0xD686619BA27255A2}, // 1e-153 + {0xBD06742CE95F5F36, 0x8613FD0145877585}, // 1e-152 + {0x2C48113823B73704, 0xA798FC4196E952E7}, // 1e-151 + {0xF75A15862CA504C5, 0xD17F3B51FCA3A7A0}, // 1e-150 + {0x9A984D73DBE722FB, 0x82EF85133DE648C4}, // 1e-149 + {0xC13E60D0D2E0EBBA, 0xA3AB66580D5FDAF5}, // 1e-148 + {0x318DF905079926A8, 0xCC963FEE10B7D1B3}, // 1e-147 + {0xFDF17746497F7052, 0xFFBBCFE994E5C61F}, // 1e-146 + {0xFEB6EA8BEDEFA633, 0x9FD561F1FD0F9BD3}, // 1e-145 + {0xFE64A52EE96B8FC0, 0xC7CABA6E7C5382C8}, // 1e-144 + {0x3DFDCE7AA3C673B0, 0xF9BD690A1B68637B}, // 1e-143 + {0x06BEA10CA65C084E, 0x9C1661A651213E2D}, // 1e-142 + {0x486E494FCFF30A62, 0xC31BFA0FE5698DB8}, // 1e-141 + {0x5A89DBA3C3EFCCFA, 0xF3E2F893DEC3F126}, // 1e-140 + {0xF89629465A75E01C, 0x986DDB5C6B3A76B7}, // 1e-139 + {0xF6BBB397F1135823, 0xBE89523386091465}, // 1e-138 + {0x746AA07DED582E2C, 0xEE2BA6C0678B597F}, // 1e-137 + {0xA8C2A44EB4571CDC, 0x94DB483840B717EF}, // 1e-136 + {0x92F34D62616CE413, 0xBA121A4650E4DDEB}, // 1e-135 + {0x77B020BAF9C81D17, 0xE896A0D7E51E1566}, // 1e-134 + {0x0ACE1474DC1D122E, 0x915E2486EF32CD60}, // 1e-133 + {0x0D819992132456BA, 0xB5B5ADA8AAFF80B8}, // 1e-132 + {0x10E1FFF697ED6C69, 0xE3231912D5BF60E6}, // 1e-131 + {0xCA8D3FFA1EF463C1, 0x8DF5EFABC5979C8F}, // 1e-130 + {0xBD308FF8A6B17CB2, 0xB1736B96B6FD83B3}, // 1e-129 + {0xAC7CB3F6D05DDBDE, 0xDDD0467C64BCE4A0}, // 1e-128 + {0x6BCDF07A423AA96B, 0x8AA22C0DBEF60EE4}, // 1e-127 + {0x86C16C98D2C953C6, 0xAD4AB7112EB3929D}, // 1e-126 + {0xE871C7BF077BA8B7, 0xD89D64D57A607744}, // 1e-125 + {0x11471CD764AD4972, 0x87625F056C7C4A8B}, // 1e-124 + {0xD598E40D3DD89BCF, 0xA93AF6C6C79B5D2D}, // 1e-123 + {0x4AFF1D108D4EC2C3, 0xD389B47879823479}, // 1e-122 + {0xCEDF722A585139BA, 0x843610CB4BF160CB}, // 1e-121 + {0xC2974EB4EE658828, 0xA54394FE1EEDB8FE}, // 1e-120 + {0x733D226229FEEA32, 0xCE947A3DA6A9273E}, // 1e-119 + {0x0806357D5A3F525F, 0x811CCC668829B887}, // 1e-118 + {0xCA07C2DCB0CF26F7, 0xA163FF802A3426A8}, // 1e-117 + {0xFC89B393DD02F0B5, 0xC9BCFF6034C13052}, // 1e-116 + {0xBBAC2078D443ACE2, 0xFC2C3F3841F17C67}, // 1e-115 + {0xD54B944B84AA4C0D, 0x9D9BA7832936EDC0}, // 1e-114 + {0x0A9E795E65D4DF11, 0xC5029163F384A931}, // 1e-113 + {0x4D4617B5FF4A16D5, 0xF64335BCF065D37D}, // 1e-112 + {0x504BCED1BF8E4E45, 0x99EA0196163FA42E}, // 1e-111 + {0xE45EC2862F71E1D6, 0xC06481FB9BCF8D39}, // 1e-110 + {0x5D767327BB4E5A4C, 0xF07DA27A82C37088}, // 1e-109 + {0x3A6A07F8D510F86F, 0x964E858C91BA2655}, // 1e-108 + {0x890489F70A55368B, 0xBBE226EFB628AFEA}, // 1e-107 + {0x2B45AC74CCEA842E, 0xEADAB0ABA3B2DBE5}, // 1e-106 + {0x3B0B8BC90012929D, 0x92C8AE6B464FC96F}, // 1e-105 + {0x09CE6EBB40173744, 0xB77ADA0617E3BBCB}, // 1e-104 + {0xCC420A6A101D0515, 0xE55990879DDCAABD}, // 1e-103 + {0x9FA946824A12232D, 0x8F57FA54C2A9EAB6}, // 1e-102 + {0x47939822DC96ABF9, 0xB32DF8E9F3546564}, // 1e-101 + {0x59787E2B93BC56F7, 0xDFF9772470297EBD}, // 1e-100 + {0x57EB4EDB3C55B65A, 0x8BFBEA76C619EF36}, // 1e-99 + {0xEDE622920B6B23F1, 0xAEFAE51477A06B03}, // 1e-98 + {0xE95FAB368E45ECED, 0xDAB99E59958885C4}, // 1e-97 + {0x11DBCB0218EBB414, 0x88B402F7FD75539B}, // 1e-96 + {0xD652BDC29F26A119, 0xAAE103B5FCD2A881}, // 1e-95 + {0x4BE76D3346F0495F, 0xD59944A37C0752A2}, // 1e-94 + {0x6F70A4400C562DDB, 0x857FCAE62D8493A5}, // 1e-93 + {0xCB4CCD500F6BB952, 0xA6DFBD9FB8E5B88E}, // 1e-92 + {0x7E2000A41346A7A7, 0xD097AD07A71F26B2}, // 1e-91 + {0x8ED400668C0C28C8, 0x825ECC24C873782F}, // 1e-90 + {0x728900802F0F32FA, 0xA2F67F2DFA90563B}, // 1e-89 + {0x4F2B40A03AD2FFB9, 0xCBB41EF979346BCA}, // 1e-88 + {0xE2F610C84987BFA8, 0xFEA126B7D78186BC}, // 1e-87 + {0x0DD9CA7D2DF4D7C9, 0x9F24B832E6B0F436}, // 1e-86 + {0x91503D1C79720DBB, 0xC6EDE63FA05D3143}, // 1e-85 + {0x75A44C6397CE912A, 0xF8A95FCF88747D94}, // 1e-84 + {0xC986AFBE3EE11ABA, 0x9B69DBE1B548CE7C}, // 1e-83 + {0xFBE85BADCE996168, 0xC24452DA229B021B}, // 1e-82 + {0xFAE27299423FB9C3, 0xF2D56790AB41C2A2}, // 1e-81 + {0xDCCD879FC967D41A, 0x97C560BA6B0919A5}, // 1e-80 + {0x5400E987BBC1C920, 0xBDB6B8E905CB600F}, // 1e-79 + {0x290123E9AAB23B68, 0xED246723473E3813}, // 1e-78 + {0xF9A0B6720AAF6521, 0x9436C0760C86E30B}, // 1e-77 + {0xF808E40E8D5B3E69, 0xB94470938FA89BCE}, // 1e-76 + {0xB60B1D1230B20E04, 0xE7958CB87392C2C2}, // 1e-75 + {0xB1C6F22B5E6F48C2, 0x90BD77F3483BB9B9}, // 1e-74 + {0x1E38AEB6360B1AF3, 0xB4ECD5F01A4AA828}, // 1e-73 + {0x25C6DA63C38DE1B0, 0xE2280B6C20DD5232}, // 1e-72 + {0x579C487E5A38AD0E, 0x8D590723948A535F}, // 1e-71 + {0x2D835A9DF0C6D851, 0xB0AF48EC79ACE837}, // 1e-70 + {0xF8E431456CF88E65, 0xDCDB1B2798182244}, // 1e-69 + {0x1B8E9ECB641B58FF, 0x8A08F0F8BF0F156B}, // 1e-68 + {0xE272467E3D222F3F, 0xAC8B2D36EED2DAC5}, // 1e-67 + {0x5B0ED81DCC6ABB0F, 0xD7ADF884AA879177}, // 1e-66 + {0x98E947129FC2B4E9, 0x86CCBB52EA94BAEA}, // 1e-65 + {0x3F2398D747B36224, 0xA87FEA27A539E9A5}, // 1e-64 + {0x8EEC7F0D19A03AAD, 0xD29FE4B18E88640E}, // 1e-63 + {0x1953CF68300424AC, 0x83A3EEEEF9153E89}, // 1e-62 + {0x5FA8C3423C052DD7, 0xA48CEAAAB75A8E2B}, // 1e-61 + {0x3792F412CB06794D, 0xCDB02555653131B6}, // 1e-60 + {0xE2BBD88BBEE40BD0, 0x808E17555F3EBF11}, // 1e-59 + {0x5B6ACEAEAE9D0EC4, 0xA0B19D2AB70E6ED6}, // 1e-58 + {0xF245825A5A445275, 0xC8DE047564D20A8B}, // 1e-57 + {0xEED6E2F0F0D56712, 0xFB158592BE068D2E}, // 1e-56 + {0x55464DD69685606B, 0x9CED737BB6C4183D}, // 1e-55 + {0xAA97E14C3C26B886, 0xC428D05AA4751E4C}, // 1e-54 + {0xD53DD99F4B3066A8, 0xF53304714D9265DF}, // 1e-53 + {0xE546A8038EFE4029, 0x993FE2C6D07B7FAB}, // 1e-52 + {0xDE98520472BDD033, 0xBF8FDB78849A5F96}, // 1e-51 + {0x963E66858F6D4440, 0xEF73D256A5C0F77C}, // 1e-50 + {0xDDE7001379A44AA8, 0x95A8637627989AAD}, // 1e-49 + {0x5560C018580D5D52, 0xBB127C53B17EC159}, // 1e-48 + {0xAAB8F01E6E10B4A6, 0xE9D71B689DDE71AF}, // 1e-47 + {0xCAB3961304CA70E8, 0x9226712162AB070D}, // 1e-46 + {0x3D607B97C5FD0D22, 0xB6B00D69BB55C8D1}, // 1e-45 + {0x8CB89A7DB77C506A, 0xE45C10C42A2B3B05}, // 1e-44 + {0x77F3608E92ADB242, 0x8EB98A7A9A5B04E3}, // 1e-43 + {0x55F038B237591ED3, 0xB267ED1940F1C61C}, // 1e-42 + {0x6B6C46DEC52F6688, 0xDF01E85F912E37A3}, // 1e-41 + {0x2323AC4B3B3DA015, 0x8B61313BBABCE2C6}, // 1e-40 + {0xABEC975E0A0D081A, 0xAE397D8AA96C1B77}, // 1e-39 + {0x96E7BD358C904A21, 0xD9C7DCED53C72255}, // 1e-38 + {0x7E50D64177DA2E54, 0x881CEA14545C7575}, // 1e-37 + {0xDDE50BD1D5D0B9E9, 0xAA242499697392D2}, // 1e-36 + {0x955E4EC64B44E864, 0xD4AD2DBFC3D07787}, // 1e-35 + {0xBD5AF13BEF0B113E, 0x84EC3C97DA624AB4}, // 1e-34 + {0xECB1AD8AEACDD58E, 0xA6274BBDD0FADD61}, // 1e-33 + {0x67DE18EDA5814AF2, 0xCFB11EAD453994BA}, // 1e-32 + {0x80EACF948770CED7, 0x81CEB32C4B43FCF4}, // 1e-31 + {0xA1258379A94D028D, 0xA2425FF75E14FC31}, // 1e-30 + {0x096EE45813A04330, 0xCAD2F7F5359A3B3E}, // 1e-29 + {0x8BCA9D6E188853FC, 0xFD87B5F28300CA0D}, // 1e-28 + {0x775EA264CF55347D, 0x9E74D1B791E07E48}, // 1e-27 + {0x95364AFE032A819D, 0xC612062576589DDA}, // 1e-26 + {0x3A83DDBD83F52204, 0xF79687AED3EEC551}, // 1e-25 + {0xC4926A9672793542, 0x9ABE14CD44753B52}, // 1e-24 + {0x75B7053C0F178293, 0xC16D9A0095928A27}, // 1e-23 + {0x5324C68B12DD6338, 0xF1C90080BAF72CB1}, // 1e-22 + {0xD3F6FC16EBCA5E03, 0x971DA05074DA7BEE}, // 1e-21 + {0x88F4BB1CA6BCF584, 0xBCE5086492111AEA}, // 1e-20 + {0x2B31E9E3D06C32E5, 0xEC1E4A7DB69561A5}, // 1e-19 + {0x3AFF322E62439FCF, 0x9392EE8E921D5D07}, // 1e-18 + {0x09BEFEB9FAD487C2, 0xB877AA3236A4B449}, // 1e-17 + {0x4C2EBE687989A9B3, 0xE69594BEC44DE15B}, // 1e-16 + {0x0F9D37014BF60A10, 0x901D7CF73AB0ACD9}, // 1e-15 + {0x538484C19EF38C94, 0xB424DC35095CD80F}, // 1e-14 + {0x2865A5F206B06FB9, 0xE12E13424BB40E13}, // 1e-13 + {0xF93F87B7442E45D3, 0x8CBCCC096F5088CB}, // 1e-12 + {0xF78F69A51539D748, 0xAFEBFF0BCB24AAFE}, // 1e-11 + {0xB573440E5A884D1B, 0xDBE6FECEBDEDD5BE}, // 1e-10 + {0x31680A88F8953030, 0x89705F4136B4A597}, // 1e-9 + {0xFDC20D2B36BA7C3D, 0xABCC77118461CEFC}, // 1e-8 + {0x3D32907604691B4C, 0xD6BF94D5E57A42BC}, // 1e-7 + {0xA63F9A49C2C1B10F, 0x8637BD05AF6C69B5}, // 1e-6 + {0x0FCF80DC33721D53, 0xA7C5AC471B478423}, // 1e-5 + {0xD3C36113404EA4A8, 0xD1B71758E219652B}, // 1e-4 + {0x645A1CAC083126E9, 0x83126E978D4FDF3B}, // 1e-3 + {0x3D70A3D70A3D70A3, 0xA3D70A3D70A3D70A}, // 1e-2 + {0xCCCCCCCCCCCCCCCC, 0xCCCCCCCCCCCCCCCC}, // 1e-1 + {0x0000000000000000, 0x8000000000000000}, // 1e0 + {0x0000000000000000, 0xA000000000000000}, // 1e1 + {0x0000000000000000, 0xC800000000000000}, // 1e2 + {0x0000000000000000, 0xFA00000000000000}, // 1e3 + {0x0000000000000000, 0x9C40000000000000}, // 1e4 + {0x0000000000000000, 0xC350000000000000}, // 1e5 + {0x0000000000000000, 0xF424000000000000}, // 1e6 + {0x0000000000000000, 0x9896800000000000}, // 1e7 + {0x0000000000000000, 0xBEBC200000000000}, // 1e8 + {0x0000000000000000, 0xEE6B280000000000}, // 1e9 + {0x0000000000000000, 0x9502F90000000000}, // 1e10 + {0x0000000000000000, 0xBA43B74000000000}, // 1e11 + {0x0000000000000000, 0xE8D4A51000000000}, // 1e12 + {0x0000000000000000, 0x9184E72A00000000}, // 1e13 + {0x0000000000000000, 0xB5E620F480000000}, // 1e14 + {0x0000000000000000, 0xE35FA931A0000000}, // 1e15 + {0x0000000000000000, 0x8E1BC9BF04000000}, // 1e16 + {0x0000000000000000, 0xB1A2BC2EC5000000}, // 1e17 + {0x0000000000000000, 0xDE0B6B3A76400000}, // 1e18 + {0x0000000000000000, 0x8AC7230489E80000}, // 1e19 + {0x0000000000000000, 0xAD78EBC5AC620000}, // 1e20 + {0x0000000000000000, 0xD8D726B7177A8000}, // 1e21 + {0x0000000000000000, 0x878678326EAC9000}, // 1e22 + {0x0000000000000000, 0xA968163F0A57B400}, // 1e23 + {0x0000000000000000, 0xD3C21BCECCEDA100}, // 1e24 + {0x0000000000000000, 0x84595161401484A0}, // 1e25 + {0x0000000000000000, 0xA56FA5B99019A5C8}, // 1e26 + {0x0000000000000000, 0xCECB8F27F4200F3A}, // 1e27 + {0x4000000000000000, 0x813F3978F8940984}, // 1e28 + {0x5000000000000000, 0xA18F07D736B90BE5}, // 1e29 + {0xA400000000000000, 0xC9F2C9CD04674EDE}, // 1e30 + {0x4D00000000000000, 0xFC6F7C4045812296}, // 1e31 + {0xF020000000000000, 0x9DC5ADA82B70B59D}, // 1e32 + {0x6C28000000000000, 0xC5371912364CE305}, // 1e33 + {0xC732000000000000, 0xF684DF56C3E01BC6}, // 1e34 + {0x3C7F400000000000, 0x9A130B963A6C115C}, // 1e35 + {0x4B9F100000000000, 0xC097CE7BC90715B3}, // 1e36 + {0x1E86D40000000000, 0xF0BDC21ABB48DB20}, // 1e37 + {0x1314448000000000, 0x96769950B50D88F4}, // 1e38 + {0x17D955A000000000, 0xBC143FA4E250EB31}, // 1e39 + {0x5DCFAB0800000000, 0xEB194F8E1AE525FD}, // 1e40 + {0x5AA1CAE500000000, 0x92EFD1B8D0CF37BE}, // 1e41 + {0xF14A3D9E40000000, 0xB7ABC627050305AD}, // 1e42 + {0x6D9CCD05D0000000, 0xE596B7B0C643C719}, // 1e43 + {0xE4820023A2000000, 0x8F7E32CE7BEA5C6F}, // 1e44 + {0xDDA2802C8A800000, 0xB35DBF821AE4F38B}, // 1e45 + {0xD50B2037AD200000, 0xE0352F62A19E306E}, // 1e46 + {0x4526F422CC340000, 0x8C213D9DA502DE45}, // 1e47 + {0x9670B12B7F410000, 0xAF298D050E4395D6}, // 1e48 + {0x3C0CDD765F114000, 0xDAF3F04651D47B4C}, // 1e49 + {0xA5880A69FB6AC800, 0x88D8762BF324CD0F}, // 1e50 + {0x8EEA0D047A457A00, 0xAB0E93B6EFEE0053}, // 1e51 + {0x72A4904598D6D880, 0xD5D238A4ABE98068}, // 1e52 + {0x47A6DA2B7F864750, 0x85A36366EB71F041}, // 1e53 + {0x999090B65F67D924, 0xA70C3C40A64E6C51}, // 1e54 + {0xFFF4B4E3F741CF6D, 0xD0CF4B50CFE20765}, // 1e55 + {0xBFF8F10E7A8921A4, 0x82818F1281ED449F}, // 1e56 + {0xAFF72D52192B6A0D, 0xA321F2D7226895C7}, // 1e57 + {0x9BF4F8A69F764490, 0xCBEA6F8CEB02BB39}, // 1e58 + {0x02F236D04753D5B4, 0xFEE50B7025C36A08}, // 1e59 + {0x01D762422C946590, 0x9F4F2726179A2245}, // 1e60 + {0x424D3AD2B7B97EF5, 0xC722F0EF9D80AAD6}, // 1e61 + {0xD2E0898765A7DEB2, 0xF8EBAD2B84E0D58B}, // 1e62 + {0x63CC55F49F88EB2F, 0x9B934C3B330C8577}, // 1e63 + {0x3CBF6B71C76B25FB, 0xC2781F49FFCFA6D5}, // 1e64 + {0x8BEF464E3945EF7A, 0xF316271C7FC3908A}, // 1e65 + {0x97758BF0E3CBB5AC, 0x97EDD871CFDA3A56}, // 1e66 + {0x3D52EEED1CBEA317, 0xBDE94E8E43D0C8EC}, // 1e67 + {0x4CA7AAA863EE4BDD, 0xED63A231D4C4FB27}, // 1e68 + {0x8FE8CAA93E74EF6A, 0x945E455F24FB1CF8}, // 1e69 + {0xB3E2FD538E122B44, 0xB975D6B6EE39E436}, // 1e70 + {0x60DBBCA87196B616, 0xE7D34C64A9C85D44}, // 1e71 + {0xBC8955E946FE31CD, 0x90E40FBEEA1D3A4A}, // 1e72 + {0x6BABAB6398BDBE41, 0xB51D13AEA4A488DD}, // 1e73 + {0xC696963C7EED2DD1, 0xE264589A4DCDAB14}, // 1e74 + {0xFC1E1DE5CF543CA2, 0x8D7EB76070A08AEC}, // 1e75 + {0x3B25A55F43294BCB, 0xB0DE65388CC8ADA8}, // 1e76 + {0x49EF0EB713F39EBE, 0xDD15FE86AFFAD912}, // 1e77 + {0x6E3569326C784337, 0x8A2DBF142DFCC7AB}, // 1e78 + {0x49C2C37F07965404, 0xACB92ED9397BF996}, // 1e79 + {0xDC33745EC97BE906, 0xD7E77A8F87DAF7FB}, // 1e80 + {0x69A028BB3DED71A3, 0x86F0AC99B4E8DAFD}, // 1e81 + {0xC40832EA0D68CE0C, 0xA8ACD7C0222311BC}, // 1e82 + {0xF50A3FA490C30190, 0xD2D80DB02AABD62B}, // 1e83 + {0x792667C6DA79E0FA, 0x83C7088E1AAB65DB}, // 1e84 + {0x577001B891185938, 0xA4B8CAB1A1563F52}, // 1e85 + {0xED4C0226B55E6F86, 0xCDE6FD5E09ABCF26}, // 1e86 + {0x544F8158315B05B4, 0x80B05E5AC60B6178}, // 1e87 + {0x696361AE3DB1C721, 0xA0DC75F1778E39D6}, // 1e88 + {0x03BC3A19CD1E38E9, 0xC913936DD571C84C}, // 1e89 + {0x04AB48A04065C723, 0xFB5878494ACE3A5F}, // 1e90 + {0x62EB0D64283F9C76, 0x9D174B2DCEC0E47B}, // 1e91 + {0x3BA5D0BD324F8394, 0xC45D1DF942711D9A}, // 1e92 + {0xCA8F44EC7EE36479, 0xF5746577930D6500}, // 1e93 + {0x7E998B13CF4E1ECB, 0x9968BF6ABBE85F20}, // 1e94 + {0x9E3FEDD8C321A67E, 0xBFC2EF456AE276E8}, // 1e95 + {0xC5CFE94EF3EA101E, 0xEFB3AB16C59B14A2}, // 1e96 + {0xBBA1F1D158724A12, 0x95D04AEE3B80ECE5}, // 1e97 + {0x2A8A6E45AE8EDC97, 0xBB445DA9CA61281F}, // 1e98 + {0xF52D09D71A3293BD, 0xEA1575143CF97226}, // 1e99 + {0x593C2626705F9C56, 0x924D692CA61BE758}, // 1e100 + {0x6F8B2FB00C77836C, 0xB6E0C377CFA2E12E}, // 1e101 + {0x0B6DFB9C0F956447, 0xE498F455C38B997A}, // 1e102 + {0x4724BD4189BD5EAC, 0x8EDF98B59A373FEC}, // 1e103 + {0x58EDEC91EC2CB657, 0xB2977EE300C50FE7}, // 1e104 + {0x2F2967B66737E3ED, 0xDF3D5E9BC0F653E1}, // 1e105 + {0xBD79E0D20082EE74, 0x8B865B215899F46C}, // 1e106 + {0xECD8590680A3AA11, 0xAE67F1E9AEC07187}, // 1e107 + {0xE80E6F4820CC9495, 0xDA01EE641A708DE9}, // 1e108 + {0x3109058D147FDCDD, 0x884134FE908658B2}, // 1e109 + {0xBD4B46F0599FD415, 0xAA51823E34A7EEDE}, // 1e110 + {0x6C9E18AC7007C91A, 0xD4E5E2CDC1D1EA96}, // 1e111 + {0x03E2CF6BC604DDB0, 0x850FADC09923329E}, // 1e112 + {0x84DB8346B786151C, 0xA6539930BF6BFF45}, // 1e113 + {0xE612641865679A63, 0xCFE87F7CEF46FF16}, // 1e114 + {0x4FCB7E8F3F60C07E, 0x81F14FAE158C5F6E}, // 1e115 + {0xE3BE5E330F38F09D, 0xA26DA3999AEF7749}, // 1e116 + {0x5CADF5BFD3072CC5, 0xCB090C8001AB551C}, // 1e117 + {0x73D9732FC7C8F7F6, 0xFDCB4FA002162A63}, // 1e118 + {0x2867E7FDDCDD9AFA, 0x9E9F11C4014DDA7E}, // 1e119 + {0xB281E1FD541501B8, 0xC646D63501A1511D}, // 1e120 + {0x1F225A7CA91A4226, 0xF7D88BC24209A565}, // 1e121 + {0x3375788DE9B06958, 0x9AE757596946075F}, // 1e122 + {0x0052D6B1641C83AE, 0xC1A12D2FC3978937}, // 1e123 + {0xC0678C5DBD23A49A, 0xF209787BB47D6B84}, // 1e124 + {0xF840B7BA963646E0, 0x9745EB4D50CE6332}, // 1e125 + {0xB650E5A93BC3D898, 0xBD176620A501FBFF}, // 1e126 + {0xA3E51F138AB4CEBE, 0xEC5D3FA8CE427AFF}, // 1e127 + {0xC66F336C36B10137, 0x93BA47C980E98CDF}, // 1e128 + {0xB80B0047445D4184, 0xB8A8D9BBE123F017}, // 1e129 + {0xA60DC059157491E5, 0xE6D3102AD96CEC1D}, // 1e130 + {0x87C89837AD68DB2F, 0x9043EA1AC7E41392}, // 1e131 + {0x29BABE4598C311FB, 0xB454E4A179DD1877}, // 1e132 + {0xF4296DD6FEF3D67A, 0xE16A1DC9D8545E94}, // 1e133 + {0x1899E4A65F58660C, 0x8CE2529E2734BB1D}, // 1e134 + {0x5EC05DCFF72E7F8F, 0xB01AE745B101E9E4}, // 1e135 + {0x76707543F4FA1F73, 0xDC21A1171D42645D}, // 1e136 + {0x6A06494A791C53A8, 0x899504AE72497EBA}, // 1e137 + {0x0487DB9D17636892, 0xABFA45DA0EDBDE69}, // 1e138 + {0x45A9D2845D3C42B6, 0xD6F8D7509292D603}, // 1e139 + {0x0B8A2392BA45A9B2, 0x865B86925B9BC5C2}, // 1e140 + {0x8E6CAC7768D7141E, 0xA7F26836F282B732}, // 1e141 + {0x3207D795430CD926, 0xD1EF0244AF2364FF}, // 1e142 + {0x7F44E6BD49E807B8, 0x8335616AED761F1F}, // 1e143 + {0x5F16206C9C6209A6, 0xA402B9C5A8D3A6E7}, // 1e144 + {0x36DBA887C37A8C0F, 0xCD036837130890A1}, // 1e145 + {0xC2494954DA2C9789, 0x802221226BE55A64}, // 1e146 + {0xF2DB9BAA10B7BD6C, 0xA02AA96B06DEB0FD}, // 1e147 + {0x6F92829494E5ACC7, 0xC83553C5C8965D3D}, // 1e148 + {0xCB772339BA1F17F9, 0xFA42A8B73ABBF48C}, // 1e149 + {0xFF2A760414536EFB, 0x9C69A97284B578D7}, // 1e150 + {0xFEF5138519684ABA, 0xC38413CF25E2D70D}, // 1e151 + {0x7EB258665FC25D69, 0xF46518C2EF5B8CD1}, // 1e152 + {0xEF2F773FFBD97A61, 0x98BF2F79D5993802}, // 1e153 + {0xAAFB550FFACFD8FA, 0xBEEEFB584AFF8603}, // 1e154 + {0x95BA2A53F983CF38, 0xEEAABA2E5DBF6784}, // 1e155 + {0xDD945A747BF26183, 0x952AB45CFA97A0B2}, // 1e156 + {0x94F971119AEEF9E4, 0xBA756174393D88DF}, // 1e157 + {0x7A37CD5601AAB85D, 0xE912B9D1478CEB17}, // 1e158 + {0xAC62E055C10AB33A, 0x91ABB422CCB812EE}, // 1e159 + {0x577B986B314D6009, 0xB616A12B7FE617AA}, // 1e160 + {0xED5A7E85FDA0B80B, 0xE39C49765FDF9D94}, // 1e161 + {0x14588F13BE847307, 0x8E41ADE9FBEBC27D}, // 1e162 + {0x596EB2D8AE258FC8, 0xB1D219647AE6B31C}, // 1e163 + {0x6FCA5F8ED9AEF3BB, 0xDE469FBD99A05FE3}, // 1e164 + {0x25DE7BB9480D5854, 0x8AEC23D680043BEE}, // 1e165 + {0xAF561AA79A10AE6A, 0xADA72CCC20054AE9}, // 1e166 + {0x1B2BA1518094DA04, 0xD910F7FF28069DA4}, // 1e167 + {0x90FB44D2F05D0842, 0x87AA9AFF79042286}, // 1e168 + {0x353A1607AC744A53, 0xA99541BF57452B28}, // 1e169 + {0x42889B8997915CE8, 0xD3FA922F2D1675F2}, // 1e170 + {0x69956135FEBADA11, 0x847C9B5D7C2E09B7}, // 1e171 + {0x43FAB9837E699095, 0xA59BC234DB398C25}, // 1e172 + {0x94F967E45E03F4BB, 0xCF02B2C21207EF2E}, // 1e173 + {0x1D1BE0EEBAC278F5, 0x8161AFB94B44F57D}, // 1e174 + {0x6462D92A69731732, 0xA1BA1BA79E1632DC}, // 1e175 + {0x7D7B8F7503CFDCFE, 0xCA28A291859BBF93}, // 1e176 + {0x5CDA735244C3D43E, 0xFCB2CB35E702AF78}, // 1e177 + {0x3A0888136AFA64A7, 0x9DEFBF01B061ADAB}, // 1e178 + {0x088AAA1845B8FDD0, 0xC56BAEC21C7A1916}, // 1e179 + {0x8AAD549E57273D45, 0xF6C69A72A3989F5B}, // 1e180 + {0x36AC54E2F678864B, 0x9A3C2087A63F6399}, // 1e181 + {0x84576A1BB416A7DD, 0xC0CB28A98FCF3C7F}, // 1e182 + {0x656D44A2A11C51D5, 0xF0FDF2D3F3C30B9F}, // 1e183 + {0x9F644AE5A4B1B325, 0x969EB7C47859E743}, // 1e184 + {0x873D5D9F0DDE1FEE, 0xBC4665B596706114}, // 1e185 + {0xA90CB506D155A7EA, 0xEB57FF22FC0C7959}, // 1e186 + {0x09A7F12442D588F2, 0x9316FF75DD87CBD8}, // 1e187 + {0x0C11ED6D538AEB2F, 0xB7DCBF5354E9BECE}, // 1e188 + {0x8F1668C8A86DA5FA, 0xE5D3EF282A242E81}, // 1e189 + {0xF96E017D694487BC, 0x8FA475791A569D10}, // 1e190 + {0x37C981DCC395A9AC, 0xB38D92D760EC4455}, // 1e191 + {0x85BBE253F47B1417, 0xE070F78D3927556A}, // 1e192 + {0x93956D7478CCEC8E, 0x8C469AB843B89562}, // 1e193 + {0x387AC8D1970027B2, 0xAF58416654A6BABB}, // 1e194 + {0x06997B05FCC0319E, 0xDB2E51BFE9D0696A}, // 1e195 + {0x441FECE3BDF81F03, 0x88FCF317F22241E2}, // 1e196 + {0xD527E81CAD7626C3, 0xAB3C2FDDEEAAD25A}, // 1e197 + {0x8A71E223D8D3B074, 0xD60B3BD56A5586F1}, // 1e198 + {0xF6872D5667844E49, 0x85C7056562757456}, // 1e199 + {0xB428F8AC016561DB, 0xA738C6BEBB12D16C}, // 1e200 + {0xE13336D701BEBA52, 0xD106F86E69D785C7}, // 1e201 + {0xECC0024661173473, 0x82A45B450226B39C}, // 1e202 + {0x27F002D7F95D0190, 0xA34D721642B06084}, // 1e203 + {0x31EC038DF7B441F4, 0xCC20CE9BD35C78A5}, // 1e204 + {0x7E67047175A15271, 0xFF290242C83396CE}, // 1e205 + {0x0F0062C6E984D386, 0x9F79A169BD203E41}, // 1e206 + {0x52C07B78A3E60868, 0xC75809C42C684DD1}, // 1e207 + {0xA7709A56CCDF8A82, 0xF92E0C3537826145}, // 1e208 + {0x88A66076400BB691, 0x9BBCC7A142B17CCB}, // 1e209 + {0x6ACFF893D00EA435, 0xC2ABF989935DDBFE}, // 1e210 + {0x0583F6B8C4124D43, 0xF356F7EBF83552FE}, // 1e211 + {0xC3727A337A8B704A, 0x98165AF37B2153DE}, // 1e212 + {0x744F18C0592E4C5C, 0xBE1BF1B059E9A8D6}, // 1e213 + {0x1162DEF06F79DF73, 0xEDA2EE1C7064130C}, // 1e214 + {0x8ADDCB5645AC2BA8, 0x9485D4D1C63E8BE7}, // 1e215 + {0x6D953E2BD7173692, 0xB9A74A0637CE2EE1}, // 1e216 + {0xC8FA8DB6CCDD0437, 0xE8111C87C5C1BA99}, // 1e217 + {0x1D9C9892400A22A2, 0x910AB1D4DB9914A0}, // 1e218 + {0x2503BEB6D00CAB4B, 0xB54D5E4A127F59C8}, // 1e219 + {0x2E44AE64840FD61D, 0xE2A0B5DC971F303A}, // 1e220 + {0x5CEAECFED289E5D2, 0x8DA471A9DE737E24}, // 1e221 + {0x7425A83E872C5F47, 0xB10D8E1456105DAD}, // 1e222 + {0xD12F124E28F77719, 0xDD50F1996B947518}, // 1e223 + {0x82BD6B70D99AAA6F, 0x8A5296FFE33CC92F}, // 1e224 + {0x636CC64D1001550B, 0xACE73CBFDC0BFB7B}, // 1e225 + {0x3C47F7E05401AA4E, 0xD8210BEFD30EFA5A}, // 1e226 + {0x65ACFAEC34810A71, 0x8714A775E3E95C78}, // 1e227 + {0x7F1839A741A14D0D, 0xA8D9D1535CE3B396}, // 1e228 + {0x1EDE48111209A050, 0xD31045A8341CA07C}, // 1e229 + {0x934AED0AAB460432, 0x83EA2B892091E44D}, // 1e230 + {0xF81DA84D5617853F, 0xA4E4B66B68B65D60}, // 1e231 + {0x36251260AB9D668E, 0xCE1DE40642E3F4B9}, // 1e232 + {0xC1D72B7C6B426019, 0x80D2AE83E9CE78F3}, // 1e233 + {0xB24CF65B8612F81F, 0xA1075A24E4421730}, // 1e234 + {0xDEE033F26797B627, 0xC94930AE1D529CFC}, // 1e235 + {0x169840EF017DA3B1, 0xFB9B7CD9A4A7443C}, // 1e236 + {0x8E1F289560EE864E, 0x9D412E0806E88AA5}, // 1e237 + {0xF1A6F2BAB92A27E2, 0xC491798A08A2AD4E}, // 1e238 + {0xAE10AF696774B1DB, 0xF5B5D7EC8ACB58A2}, // 1e239 + {0xACCA6DA1E0A8EF29, 0x9991A6F3D6BF1765}, // 1e240 + {0x17FD090A58D32AF3, 0xBFF610B0CC6EDD3F}, // 1e241 + {0xDDFC4B4CEF07F5B0, 0xEFF394DCFF8A948E}, // 1e242 + {0x4ABDAF101564F98E, 0x95F83D0A1FB69CD9}, // 1e243 + {0x9D6D1AD41ABE37F1, 0xBB764C4CA7A4440F}, // 1e244 + {0x84C86189216DC5ED, 0xEA53DF5FD18D5513}, // 1e245 + {0x32FD3CF5B4E49BB4, 0x92746B9BE2F8552C}, // 1e246 + {0x3FBC8C33221DC2A1, 0xB7118682DBB66A77}, // 1e247 + {0x0FABAF3FEAA5334A, 0xE4D5E82392A40515}, // 1e248 + {0x29CB4D87F2A7400E, 0x8F05B1163BA6832D}, // 1e249 + {0x743E20E9EF511012, 0xB2C71D5BCA9023F8}, // 1e250 + {0x914DA9246B255416, 0xDF78E4B2BD342CF6}, // 1e251 + {0x1AD089B6C2F7548E, 0x8BAB8EEFB6409C1A}, // 1e252 + {0xA184AC2473B529B1, 0xAE9672ABA3D0C320}, // 1e253 + {0xC9E5D72D90A2741E, 0xDA3C0F568CC4F3E8}, // 1e254 + {0x7E2FA67C7A658892, 0x8865899617FB1871}, // 1e255 + {0xDDBB901B98FEEAB7, 0xAA7EEBFB9DF9DE8D}, // 1e256 + {0x552A74227F3EA565, 0xD51EA6FA85785631}, // 1e257 + {0xD53A88958F87275F, 0x8533285C936B35DE}, // 1e258 + {0x8A892ABAF368F137, 0xA67FF273B8460356}, // 1e259 + {0x2D2B7569B0432D85, 0xD01FEF10A657842C}, // 1e260 + {0x9C3B29620E29FC73, 0x8213F56A67F6B29B}, // 1e261 + {0x8349F3BA91B47B8F, 0xA298F2C501F45F42}, // 1e262 + {0x241C70A936219A73, 0xCB3F2F7642717713}, // 1e263 + {0xED238CD383AA0110, 0xFE0EFB53D30DD4D7}, // 1e264 + {0xF4363804324A40AA, 0x9EC95D1463E8A506}, // 1e265 + {0xB143C6053EDCD0D5, 0xC67BB4597CE2CE48}, // 1e266 + {0xDD94B7868E94050A, 0xF81AA16FDC1B81DA}, // 1e267 + {0xCA7CF2B4191C8326, 0x9B10A4E5E9913128}, // 1e268 + {0xFD1C2F611F63A3F0, 0xC1D4CE1F63F57D72}, // 1e269 + {0xBC633B39673C8CEC, 0xF24A01A73CF2DCCF}, // 1e270 + {0xD5BE0503E085D813, 0x976E41088617CA01}, // 1e271 + {0x4B2D8644D8A74E18, 0xBD49D14AA79DBC82}, // 1e272 + {0xDDF8E7D60ED1219E, 0xEC9C459D51852BA2}, // 1e273 + {0xCABB90E5C942B503, 0x93E1AB8252F33B45}, // 1e274 + {0x3D6A751F3B936243, 0xB8DA1662E7B00A17}, // 1e275 + {0x0CC512670A783AD4, 0xE7109BFBA19C0C9D}, // 1e276 + {0x27FB2B80668B24C5, 0x906A617D450187E2}, // 1e277 + {0xB1F9F660802DEDF6, 0xB484F9DC9641E9DA}, // 1e278 + {0x5E7873F8A0396973, 0xE1A63853BBD26451}, // 1e279 + {0xDB0B487B6423E1E8, 0x8D07E33455637EB2}, // 1e280 + {0x91CE1A9A3D2CDA62, 0xB049DC016ABC5E5F}, // 1e281 + {0x7641A140CC7810FB, 0xDC5C5301C56B75F7}, // 1e282 + {0xA9E904C87FCB0A9D, 0x89B9B3E11B6329BA}, // 1e283 + {0x546345FA9FBDCD44, 0xAC2820D9623BF429}, // 1e284 + {0xA97C177947AD4095, 0xD732290FBACAF133}, // 1e285 + {0x49ED8EABCCCC485D, 0x867F59A9D4BED6C0}, // 1e286 + {0x5C68F256BFFF5A74, 0xA81F301449EE8C70}, // 1e287 + {0x73832EEC6FFF3111, 0xD226FC195C6A2F8C}, // 1e288 + {0xC831FD53C5FF7EAB, 0x83585D8FD9C25DB7}, // 1e289 + {0xBA3E7CA8B77F5E55, 0xA42E74F3D032F525}, // 1e290 + {0x28CE1BD2E55F35EB, 0xCD3A1230C43FB26F}, // 1e291 + {0x7980D163CF5B81B3, 0x80444B5E7AA7CF85}, // 1e292 + {0xD7E105BCC332621F, 0xA0555E361951C366}, // 1e293 + {0x8DD9472BF3FEFAA7, 0xC86AB5C39FA63440}, // 1e294 + {0xB14F98F6F0FEB951, 0xFA856334878FC150}, // 1e295 + {0x6ED1BF9A569F33D3, 0x9C935E00D4B9D8D2}, // 1e296 + {0x0A862F80EC4700C8, 0xC3B8358109E84F07}, // 1e297 + {0xCD27BB612758C0FA, 0xF4A642E14C6262C8}, // 1e298 + {0x8038D51CB897789C, 0x98E7E9CCCFBD7DBD}, // 1e299 + {0xE0470A63E6BD56C3, 0xBF21E44003ACDD2C}, // 1e300 + {0x1858CCFCE06CAC74, 0xEEEA5D5004981478}, // 1e301 + {0x0F37801E0C43EBC8, 0x95527A5202DF0CCB}, // 1e302 + {0xD30560258F54E6BA, 0xBAA718E68396CFFD}, // 1e303 + {0x47C6B82EF32A2069, 0xE950DF20247C83FD}, // 1e304 + {0x4CDC331D57FA5441, 0x91D28B7416CDD27E}, // 1e305 + {0xE0133FE4ADF8E952, 0xB6472E511C81471D}, // 1e306 + {0x58180FDDD97723A6, 0xE3D8F9E563A198E5}, // 1e307 + {0x570F09EAA7EA7648, 0x8E679C2F5E44FF8F}, // 1e308 + {0x2CD2CC6551E513DA, 0xB201833B35D63F73}, // 1e309 + {0xF8077F7EA65E58D1, 0xDE81E40A034BCF4F}, // 1e310 + {0xFB04AFAF27FAF782, 0x8B112E86420F6191}, // 1e311 + {0x79C5DB9AF1F9B563, 0xADD57A27D29339F6}, // 1e312 + {0x18375281AE7822BC, 0xD94AD8B1C7380874}, // 1e313 + {0x8F2293910D0B15B5, 0x87CEC76F1C830548}, // 1e314 + {0xB2EB3875504DDB22, 0xA9C2794AE3A3C69A}, // 1e315 + {0x5FA60692A46151EB, 0xD433179D9C8CB841}, // 1e316 + {0xDBC7C41BA6BCD333, 0x849FEEC281D7F328}, // 1e317 + {0x12B9B522906C0800, 0xA5C7EA73224DEFF3}, // 1e318 + {0xD768226B34870A00, 0xCF39E50FEAE16BEF}, // 1e319 + {0xE6A1158300D46640, 0x81842F29F2CCE375}, // 1e320 + {0x60495AE3C1097FD0, 0xA1E53AF46F801C53}, // 1e321 + {0x385BB19CB14BDFC4, 0xCA5E89B18B602368}, // 1e322 + {0x46729E03DD9ED7B5, 0xFCF62C1DEE382C42}, // 1e323 + {0x6C07A2C26A8346D1, 0x9E19DB92B4E31BA9}, // 1e324 + {0xC7098B7305241885, 0xC5A05277621BE293}, // 1e325 + {0xB8CBEE4FC66D1EA7, 0xF70867153AA2DB38}, // 1e326 + {0x737F74F1DC043328, 0x9A65406D44A5C903}, // 1e327 + {0x505F522E53053FF2, 0xC0FE908895CF3B44}, // 1e328 + {0x647726B9E7C68FEF, 0xF13E34AABB430A15}, // 1e329 + {0x5ECA783430DC19F5, 0x96C6E0EAB509E64D}, // 1e330 + {0xB67D16413D132072, 0xBC789925624C5FE0}, // 1e331 + {0xE41C5BD18C57E88F, 0xEB96BF6EBADF77D8}, // 1e332 + {0x8E91B962F7B6F159, 0x933E37A534CBAAE7}, // 1e333 + {0x723627BBB5A4ADB0, 0xB80DC58E81FE95A1}, // 1e334 + {0xCEC3B1AAA30DD91C, 0xE61136F2227E3B09}, // 1e335 + {0x213A4F0AA5E8A7B1, 0x8FCAC257558EE4E6}, // 1e336 + {0xA988E2CD4F62D19D, 0xB3BD72ED2AF29E1F}, // 1e337 + {0x93EB1B80A33B8605, 0xE0ACCFA875AF45A7}, // 1e338 + {0xBC72F130660533C3, 0x8C6C01C9498D8B88}, // 1e339 + {0xEB8FAD7C7F8680B4, 0xAF87023B9BF0EE6A}, // 1e340 + {0xA67398DB9F6820E1, 0xDB68C2CA82ED2A05}, // 1e341 + {0x88083F8943A1148C, 0x892179BE91D43A43}, // 1e342 + {0x6A0A4F6B948959B0, 0xAB69D82E364948D4}, // 1e343 + {0x848CE34679ABB01C, 0xD6444E39C3DB9B09}, // 1e344 + {0xF2D80E0C0C0B4E11, 0x85EAB0E41A6940E5}, // 1e345 + {0x6F8E118F0F0E2195, 0xA7655D1D2103911F}, // 1e346 + {0x4B7195F2D2D1A9FB, 0xD13EB46469447567}, // 1e347 +}; + +} // namespace internal +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_DETAILED_POWERS_OF_TEN_H diff --git a/lib/libcxx/libc/src/__support/high_precision_decimal.h b/lib/libcxx/libc/src/__support/high_precision_decimal.h new file mode 100644 index 0000000000..922dce484a --- /dev/null +++ b/lib/libcxx/libc/src/__support/high_precision_decimal.h @@ -0,0 +1,442 @@ +//===-- 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. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// ----------------------------------------------------------------------------- +// **** WARNING **** +// This file is shared with libc++. You should also be careful when adding +// dependencies to this file, since it needs to build for all libc++ targets. +// ----------------------------------------------------------------------------- + +#ifndef LLVM_LIBC_SRC___SUPPORT_HIGH_PRECISION_DECIMAL_H +#define LLVM_LIBC_SRC___SUPPORT_HIGH_PRECISION_DECIMAL_H + +#include "src/__support/CPP/limits.h" +#include "src/__support/ctype_utils.h" +#include "src/__support/macros/config.h" +#include "src/__support/str_to_integer.h" +#include <stdint.h> + +namespace LIBC_NAMESPACE_DECL { +namespace internal { + +struct LShiftTableEntry { + uint32_t new_digits; + char const *power_of_five; +}; + +// ----------------------------------------------------------------------------- +// **** WARNING **** +// This interface is shared with libc++, if you change this interface you need +// to update it in both libc and libc++. +// ----------------------------------------------------------------------------- +// This is used in both this file and in the main str_to_float.h. +// TODO: Figure out where to put this. +enum class RoundDirection { Up, Down, Nearest }; + +// This is based on the HPD data structure described as part of the Simple +// Decimal Conversion algorithm by Nigel Tao, described at this link: +// https://nigeltao.github.io/blog/2020/parse-number-f64-simple.html +class HighPrecisionDecimal { + + // This precomputed table speeds up left shifts by having the number of new + // digits that will be added by multiplying 5^i by 2^i. If the number is less + // than 5^i then it will add one fewer digit. There are only 60 entries since + // that's the max shift amount. + // This table was generated by the script at + // libc/utils/mathtools/GenerateHPDConstants.py + static constexpr LShiftTableEntry LEFT_SHIFT_DIGIT_TABLE[] = { + {0, ""}, + {1, "5"}, + {1, "25"}, + {1, "125"}, + {2, "625"}, + {2, "3125"}, + {2, "15625"}, + {3, "78125"}, + {3, "390625"}, + {3, "1953125"}, + {4, "9765625"}, + {4, "48828125"}, + {4, "244140625"}, + {4, "1220703125"}, + {5, "6103515625"}, + {5, "30517578125"}, + {5, "152587890625"}, + {6, "762939453125"}, + {6, "3814697265625"}, + {6, "19073486328125"}, + {7, "95367431640625"}, + {7, "476837158203125"}, + {7, "2384185791015625"}, + {7, "11920928955078125"}, + {8, "59604644775390625"}, + {8, "298023223876953125"}, + {8, "1490116119384765625"}, + {9, "7450580596923828125"}, + {9, "37252902984619140625"}, + {9, "186264514923095703125"}, + {10, "931322574615478515625"}, + {10, "4656612873077392578125"}, + {10, "23283064365386962890625"}, + {10, "116415321826934814453125"}, + {11, "582076609134674072265625"}, + {11, "2910383045673370361328125"}, + {11, "14551915228366851806640625"}, + {12, "72759576141834259033203125"}, + {12, "363797880709171295166015625"}, + {12, "1818989403545856475830078125"}, + {13, "9094947017729282379150390625"}, + {13, "45474735088646411895751953125"}, + {13, "227373675443232059478759765625"}, + {13, "1136868377216160297393798828125"}, + {14, "5684341886080801486968994140625"}, + {14, "28421709430404007434844970703125"}, + {14, "142108547152020037174224853515625"}, + {15, "710542735760100185871124267578125"}, + {15, "3552713678800500929355621337890625"}, + {15, "17763568394002504646778106689453125"}, + {16, "88817841970012523233890533447265625"}, + {16, "444089209850062616169452667236328125"}, + {16, "2220446049250313080847263336181640625"}, + {16, "11102230246251565404236316680908203125"}, + {17, "55511151231257827021181583404541015625"}, + {17, "277555756156289135105907917022705078125"}, + {17, "1387778780781445675529539585113525390625"}, + {18, "6938893903907228377647697925567626953125"}, + {18, "34694469519536141888238489627838134765625"}, + {18, "173472347597680709441192448139190673828125"}, + {19, "867361737988403547205962240695953369140625"}, + }; + + // The maximum amount we can shift is the number of bits used in the + // accumulator, minus the number of bits needed to represent the base (in this + // case 4). + static constexpr uint32_t MAX_SHIFT_AMOUNT = sizeof(uint64_t) - 4; + + // 800 is an arbitrary number of digits, but should be + // large enough for any practical number. + static constexpr uint32_t MAX_NUM_DIGITS = 800; + + uint32_t num_digits = 0; + int32_t decimal_point = 0; + bool truncated = false; + uint8_t digits[MAX_NUM_DIGITS]; + +private: + LIBC_INLINE bool should_round_up(int32_t round_to_digit, + RoundDirection round) { + if (round_to_digit < 0 || + static_cast<uint32_t>(round_to_digit) >= this->num_digits) { + return false; + } + + // The above condition handles all cases where all of the trailing digits + // are zero. In that case, if the rounding mode is up, then this number + // should be rounded up. Similarly, if the rounding mode is down, then it + // should always round down. + if (round == RoundDirection::Up) { + return true; + } else if (round == RoundDirection::Down) { + return false; + } + // Else round to nearest. + + // If we're right in the middle and there are no extra digits + if (this->digits[round_to_digit] == 5 && + static_cast<uint32_t>(round_to_digit + 1) == this->num_digits) { + + // Round up if we've truncated (since that means the result is slightly + // higher than what's represented.) + if (this->truncated) { + return true; + } + + // If this exactly halfway, round to even. + if (round_to_digit == 0) + // When the input is ".5". + return false; + return this->digits[round_to_digit - 1] % 2 != 0; + } + // If there are digits after round_to_digit, they must be non-zero since we + // trim trailing zeroes after all operations that change digits. + return this->digits[round_to_digit] >= 5; + } + + // Takes an amount to left shift and returns the number of new digits needed + // to store the result based on LEFT_SHIFT_DIGIT_TABLE. + LIBC_INLINE uint32_t get_num_new_digits(uint32_t lshift_amount) { + const char *power_of_five = + LEFT_SHIFT_DIGIT_TABLE[lshift_amount].power_of_five; + uint32_t new_digits = LEFT_SHIFT_DIGIT_TABLE[lshift_amount].new_digits; + uint32_t digit_index = 0; + while (power_of_five[digit_index] != 0) { + if (digit_index >= this->num_digits) { + return new_digits - 1; + } + if (this->digits[digit_index] != + internal::b36_char_to_int(power_of_five[digit_index])) { + return new_digits - + ((this->digits[digit_index] < + internal::b36_char_to_int(power_of_five[digit_index])) + ? 1 + : 0); + } + ++digit_index; + } + return new_digits; + } + + // Trim all trailing 0s + LIBC_INLINE void trim_trailing_zeroes() { + while (this->num_digits > 0 && this->digits[this->num_digits - 1] == 0) { + --this->num_digits; + } + if (this->num_digits == 0) { + this->decimal_point = 0; + } + } + + // Perform a digitwise binary non-rounding right shift on this value by + // shift_amount. The shift_amount can't be more than MAX_SHIFT_AMOUNT to + // prevent overflow. + LIBC_INLINE void right_shift(uint32_t shift_amount) { + uint32_t read_index = 0; + uint32_t write_index = 0; + + uint64_t accumulator = 0; + + const uint64_t shift_mask = (uint64_t(1) << shift_amount) - 1; + + // Warm Up phase: we don't have enough digits to start writing, so just + // read them into the accumulator. + while (accumulator >> shift_amount == 0) { + uint64_t read_digit = 0; + // If there are still digits to read, read the next one, else the digit is + // assumed to be 0. + if (read_index < this->num_digits) { + read_digit = this->digits[read_index]; + } + accumulator = accumulator * 10 + read_digit; + ++read_index; + } + + // Shift the decimal point by the number of digits it took to fill the + // accumulator. + this->decimal_point -= read_index - 1; + + // Middle phase: we have enough digits to write, as well as more digits to + // read. Keep reading until we run out of digits. + while (read_index < this->num_digits) { + uint64_t read_digit = this->digits[read_index]; + uint64_t write_digit = accumulator >> shift_amount; + accumulator &= shift_mask; + this->digits[write_index] = static_cast<uint8_t>(write_digit); + accumulator = accumulator * 10 + read_digit; + ++read_index; + ++write_index; + } + + // Cool Down phase: All of the readable digits have been read, so just write + // the remainder, while treating any more digits as 0. + while (accumulator > 0) { + uint64_t write_digit = accumulator >> shift_amount; + accumulator &= shift_mask; + if (write_index < MAX_NUM_DIGITS) { + this->digits[write_index] = static_cast<uint8_t>(write_digit); + ++write_index; + } else if (write_digit > 0) { + this->truncated = true; + } + accumulator = accumulator * 10; + } + this->num_digits = write_index; + this->trim_trailing_zeroes(); + } + + // Perform a digitwise binary non-rounding left shift on this value by + // shift_amount. The shift_amount can't be more than MAX_SHIFT_AMOUNT to + // prevent overflow. + LIBC_INLINE void left_shift(uint32_t shift_amount) { + uint32_t new_digits = this->get_num_new_digits(shift_amount); + + int32_t read_index = this->num_digits - 1; + uint32_t write_index = this->num_digits + new_digits; + + uint64_t accumulator = 0; + + // No Warm Up phase. Since we're putting digits in at the top and taking + // digits from the bottom we don't have to wait for the accumulator to fill. + + // Middle phase: while we have more digits to read, keep reading as well as + // writing. + while (read_index >= 0) { + accumulator += static_cast<uint64_t>(this->digits[read_index]) + << shift_amount; + uint64_t next_accumulator = accumulator / 10; + uint64_t write_digit = accumulator - (10 * next_accumulator); + --write_index; + if (write_index < MAX_NUM_DIGITS) { + this->digits[write_index] = static_cast<uint8_t>(write_digit); + } else if (write_digit != 0) { + this->truncated = true; + } + accumulator = next_accumulator; + --read_index; + } + + // Cool Down phase: there are no more digits to read, so just write the + // remaining digits in the accumulator. + while (accumulator > 0) { + uint64_t next_accumulator = accumulator / 10; + uint64_t write_digit = accumulator - (10 * next_accumulator); + --write_index; + if (write_index < MAX_NUM_DIGITS) { + this->digits[write_index] = static_cast<uint8_t>(write_digit); + } else if (write_digit != 0) { + this->truncated = true; + } + accumulator = next_accumulator; + } + + this->num_digits += new_digits; + if (this->num_digits > MAX_NUM_DIGITS) { + this->num_digits = MAX_NUM_DIGITS; + } + this->decimal_point += new_digits; + this->trim_trailing_zeroes(); + } + +public: + // num_string is assumed to be a string of numeric characters. It doesn't + // handle leading spaces. + LIBC_INLINE + HighPrecisionDecimal( + const char *__restrict num_string, + const size_t num_len = cpp::numeric_limits<size_t>::max()) { + bool saw_dot = false; + size_t num_cur = 0; + // This counts the digits in the number, even if there isn't space to store + // them all. + uint32_t total_digits = 0; + while (num_cur < num_len && + (isdigit(num_string[num_cur]) || num_string[num_cur] == '.')) { + if (num_string[num_cur] == '.') { + if (saw_dot) { + break; + } + this->decimal_point = total_digits; + saw_dot = true; + } else { + if (num_string[num_cur] == '0' && this->num_digits == 0) { + --this->decimal_point; + ++num_cur; + continue; + } + ++total_digits; + if (this->num_digits < MAX_NUM_DIGITS) { + this->digits[this->num_digits] = static_cast<uint8_t>( + internal::b36_char_to_int(num_string[num_cur])); + ++this->num_digits; + } else if (num_string[num_cur] != '0') { + this->truncated = true; + } + } + ++num_cur; + } + + if (!saw_dot) + this->decimal_point = total_digits; + + if (num_cur < num_len && + (num_string[num_cur] == 'e' || num_string[num_cur] == 'E')) { + ++num_cur; + if (isdigit(num_string[num_cur]) || num_string[num_cur] == '+' || + num_string[num_cur] == '-') { + auto result = + strtointeger<int32_t>(num_string + num_cur, 10, num_len - num_cur); + if (result.has_error()) { + // TODO: handle error + } + int32_t add_to_exponent = result.value; + + // Here we do this operation as int64 to avoid overflow. + int64_t temp_exponent = static_cast<int64_t>(this->decimal_point) + + static_cast<int64_t>(add_to_exponent); + + // Theoretically these numbers should be MAX_BIASED_EXPONENT for long + // double, but that should be ~16,000 which is much less than 1 << 30. + if (temp_exponent > (1 << 30)) { + temp_exponent = (1 << 30); + } else if (temp_exponent < -(1 << 30)) { + temp_exponent = -(1 << 30); + } + this->decimal_point = static_cast<int32_t>(temp_exponent); + } + } + + this->trim_trailing_zeroes(); + } + + // Binary shift left (shift_amount > 0) or right (shift_amount < 0) + LIBC_INLINE void shift(int shift_amount) { + if (shift_amount == 0) { + return; + } + // Left + else if (shift_amount > 0) { + while (static_cast<uint32_t>(shift_amount) > MAX_SHIFT_AMOUNT) { + this->left_shift(MAX_SHIFT_AMOUNT); + shift_amount -= MAX_SHIFT_AMOUNT; + } + this->left_shift(shift_amount); + } + // Right + else { + while (static_cast<uint32_t>(shift_amount) < -MAX_SHIFT_AMOUNT) { + this->right_shift(MAX_SHIFT_AMOUNT); + shift_amount += MAX_SHIFT_AMOUNT; + } + this->right_shift(-shift_amount); + } + } + + // Round the number represented to the closest value of unsigned int type T. + // This is done ignoring overflow. + template <class T> + LIBC_INLINE T + round_to_integer_type(RoundDirection round = RoundDirection::Nearest) { + T result = 0; + uint32_t cur_digit = 0; + + while (static_cast<int32_t>(cur_digit) < this->decimal_point && + cur_digit < this->num_digits) { + result = result * 10 + (this->digits[cur_digit]); + ++cur_digit; + } + + // If there are implicit 0s at the end of the number, include those. + while (static_cast<int32_t>(cur_digit) < this->decimal_point) { + result *= 10; + ++cur_digit; + } + return result + static_cast<unsigned int>( + this->should_round_up(this->decimal_point, round)); + } + + // Extra functions for testing. + + LIBC_INLINE uint8_t *get_digits() { return this->digits; } + LIBC_INLINE uint32_t get_num_digits() { return this->num_digits; } + LIBC_INLINE int32_t get_decimal_point() { return this->decimal_point; } + LIBC_INLINE void set_truncated(bool trunc) { this->truncated = trunc; } +}; + +} // namespace internal +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_HIGH_PRECISION_DECIMAL_H diff --git a/lib/libcxx/libc/src/__support/libc_assert.h b/lib/libcxx/libc/src/__support/libc_assert.h new file mode 100644 index 0000000000..3db179ff67 --- /dev/null +++ b/lib/libcxx/libc/src/__support/libc_assert.h @@ -0,0 +1,88 @@ +//===-- Definition of a libc internal assert macro --------------*- 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_LIBC_ASSERT_H +#define LLVM_LIBC_SRC___SUPPORT_LIBC_ASSERT_H + +#include "src/__support/macros/config.h" +#if defined(LIBC_COPT_USE_C_ASSERT) || !defined(LIBC_FULL_BUILD) + +// The build is configured to just use the public <assert.h> API +// for libc's internal assertions. + +#include <assert.h> + +#define LIBC_ASSERT(COND) assert(COND) + +#else // Not LIBC_COPT_USE_C_ASSERT + +#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/optimization.h" // For LIBC_UNLIKELY + +namespace LIBC_NAMESPACE_DECL { + +// This is intended to be removed in a future patch to use a similar design to +// below, but it's necessary for the external assert. +LIBC_INLINE void report_assertion_failure(const char *assertion, + const char *filename, unsigned line, + const char *funcname) { + const IntegerToString<unsigned> line_buffer(line); + write_to_stderr(filename); + write_to_stderr(":"); + write_to_stderr(line_buffer.view()); + write_to_stderr(": Assertion failed: '"); + write_to_stderr(assertion); + write_to_stderr("' in function: '"); + write_to_stderr(funcname); + write_to_stderr("'\n"); +} + +} // namespace LIBC_NAMESPACE_DECL + +#ifdef LIBC_ASSERT +#error "Unexpected: LIBC_ASSERT macro already defined" +#endif + +// The public "assert" macro calls abort on failure. Should it be same here? +// The libc internal assert can fire from anywhere inside the libc. So, to +// avoid potential chicken-and-egg problems, it is simple to do an exit +// on assertion failure instead of calling abort. We also don't want to use +// __builtin_trap as it could potentially be implemented using illegal +// instructions which can be very misleading when debugging. +#ifdef NDEBUG +#define LIBC_ASSERT(COND) \ + do { \ + } 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(__PRETTY_FUNCTION__); \ + LIBC_NAMESPACE::write_to_stderr("'\n"); \ + LIBC_NAMESPACE::internal::exit(0xFF); \ + } \ + } while (false) +#endif // NDEBUG + +#endif // LIBC_COPT_USE_C_ASSERT + +#endif // LLVM_LIBC_SRC___SUPPORT_LIBC_ASSERT_H diff --git a/lib/libcxx/libc/src/__support/macros/attributes.h b/lib/libcxx/libc/src/__support/macros/attributes.h new file mode 100644 index 0000000000..c6474673de --- /dev/null +++ b/lib/libcxx/libc/src/__support/macros/attributes.h @@ -0,0 +1,51 @@ +//===-- Portable attributes -------------------------------------*- 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 +// +//===----------------------------------------------------------------------===// +// This header file defines macros for declaring attributes for functions, +// types, and variables. +// +// These macros are used within llvm-libc and allow the compiler to optimize, +// where applicable, certain function calls. +// +// Most macros here are exposing GCC or Clang features, and are stubbed out for +// other compilers. + +#ifndef LLVM_LIBC_SRC___SUPPORT_MACROS_ATTRIBUTES_H +#define LLVM_LIBC_SRC___SUPPORT_MACROS_ATTRIBUTES_H + +#include "properties/architectures.h" + +#ifndef __has_attribute +#define __has_attribute(x) 0 +#endif + +#define LIBC_INLINE inline +#define LIBC_INLINE_VAR inline +#define LIBC_INLINE_ASM __asm__ __volatile__ +#define LIBC_UNUSED __attribute__((unused)) + +#ifdef LIBC_TARGET_ARCH_IS_GPU +#define LIBC_THREAD_LOCAL +#else +#define LIBC_THREAD_LOCAL thread_local +#endif + +#if __cplusplus >= 202002L +#define LIBC_CONSTINIT constinit +#elif __has_attribute(__require_constant_initialization__) +#define LIBC_CONSTINIT __attribute__((__require_constant_initialization__)) +#else +#define LIBC_CONSTINIT +#endif + +#if defined(__clang__) && __has_attribute(preferred_type) +#define LIBC_PREFERED_TYPE(TYPE) [[clang::preferred_type(TYPE)]] +#else +#define LIBC_PREFERED_TYPE(TYPE) +#endif + +#endif // LLVM_LIBC_SRC___SUPPORT_MACROS_ATTRIBUTES_H diff --git a/lib/libcxx/libc/src/__support/macros/config.h b/lib/libcxx/libc/src/__support/macros/config.h new file mode 100644 index 0000000000..2ab0fba095 --- /dev/null +++ b/lib/libcxx/libc/src/__support/macros/config.h @@ -0,0 +1,46 @@ +//===-- Portable attributes -------------------------------------*- 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 +// +//===----------------------------------------------------------------------===// +// This header file defines a set of macros for checking the presence of +// important compiler and platform features. Such macros can be used to +// produce portable code by parameterizing compilation based on the presence or +// lack of a given feature. + +#ifndef LLVM_LIBC_SRC___SUPPORT_MACROS_CONFIG_H +#define LLVM_LIBC_SRC___SUPPORT_MACROS_CONFIG_H + +// Workaround for compilers that do not support builtin detection. +// FIXME: This is only required for the GPU portion which should be moved. +#ifndef __has_builtin +#define __has_builtin(b) 0 +#endif + +// Compiler feature-detection. +// clang.llvm.org/docs/LanguageExtensions.html#has-feature-and-has-extension +#ifdef __has_feature +#define LIBC_HAS_FEATURE(f) __has_feature(f) +#else +#define LIBC_HAS_FEATURE(f) 0 +#endif + +#ifdef __clang__ +// Declare a LIBC_NAMESPACE with hidden visibility. `namespace +// LIBC_NAMESPACE_DECL {` should be used around all declarations and definitions +// for libc internals as opposed to just `namespace LIBC_NAMESPACE {`. This +// ensures that all declarations within this namespace have hidden +// visibility, which optimizes codegen for uses of symbols defined in other +// translation units in ways that can be necessary for correctness by avoiding +// dynamic relocations. This does not affect the public C symbols which are +// controlled independently via `LLVM_LIBC_FUNCTION_ATTR`. +#define LIBC_NAMESPACE_DECL [[gnu::visibility("hidden")]] LIBC_NAMESPACE +#else +// TODO(#98548): GCC emits a warning when using the visibility attribute which +// needs to be diagnosed and addressed. +#define LIBC_NAMESPACE_DECL LIBC_NAMESPACE +#endif + +#endif // LLVM_LIBC_SRC___SUPPORT_MACROS_CONFIG_H diff --git a/lib/libcxx/libc/src/__support/macros/null_check.h b/lib/libcxx/libc/src/__support/macros/null_check.h new file mode 100644 index 0000000000..eda19f8892 --- /dev/null +++ b/lib/libcxx/libc/src/__support/macros/null_check.h @@ -0,0 +1,28 @@ +//===-- Safe nullptr check --------------------------------------*- 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_NULL_CHECK_H +#define LLVM_LIBC_SRC___SUPPORT_MACROS_NULL_CHECK_H + +#include "src/__support/macros/config.h" +#include "src/__support/macros/optimization.h" +#include "src/__support/macros/sanitizer.h" + +#if defined(LIBC_ADD_NULL_CHECKS) && !defined(LIBC_HAS_SANITIZER) +#define LIBC_CRASH_ON_NULLPTR(ptr) \ + do { \ + if (LIBC_UNLIKELY((ptr) == nullptr)) \ + __builtin_trap(); \ + } while (0) +#else +#define LIBC_CRASH_ON_NULLPTR(ptr) \ + do { \ + } while (0) +#endif + +#endif // LLVM_LIBC_SRC___SUPPORT_MACROS_NULL_CHECK_H diff --git a/lib/libcxx/libc/src/__support/macros/optimization.h b/lib/libcxx/libc/src/__support/macros/optimization.h new file mode 100644 index 0000000000..a2634950d4 --- /dev/null +++ b/lib/libcxx/libc/src/__support/macros/optimization.h @@ -0,0 +1,61 @@ +//===-- Portable optimization 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 +// +//===----------------------------------------------------------------------===// +// This header file defines portable macros for performance optimization. + +#ifndef LLVM_LIBC_SRC___SUPPORT_MACROS_OPTIMIZATION_H +#define LLVM_LIBC_SRC___SUPPORT_MACROS_OPTIMIZATION_H + +#include "src/__support/macros/attributes.h" // LIBC_INLINE +#include "src/__support/macros/config.h" +#include "src/__support/macros/properties/compiler.h" // LIBC_COMPILER_IS_CLANG + +// We use a template to implement likely/unlikely to make sure that we don't +// accidentally pass an integer. +namespace LIBC_NAMESPACE_DECL { +namespace details { +template <typename T> +LIBC_INLINE constexpr bool expects_bool_condition(T value, T expected) { + return __builtin_expect(value, expected); +} +} // namespace details +} // namespace LIBC_NAMESPACE_DECL +#define LIBC_LIKELY(x) LIBC_NAMESPACE::details::expects_bool_condition(x, true) +#define LIBC_UNLIKELY(x) \ + LIBC_NAMESPACE::details::expects_bool_condition(x, false) + +#if defined(LIBC_COMPILER_IS_CLANG) +#define LIBC_LOOP_NOUNROLL _Pragma("nounroll") +#elif defined(LIBC_COMPILER_IS_GCC) +#define LIBC_LOOP_NOUNROLL _Pragma("GCC unroll 0") +#else +#error "Unhandled compiler" +#endif + +// Defining optimization options for math functions. +// TODO: Exporting this to public generated headers? +#define LIBC_MATH_SKIP_ACCURATE_PASS 0x01 +#define LIBC_MATH_SMALL_TABLES 0x02 +#define LIBC_MATH_NO_ERRNO 0x04 +#define LIBC_MATH_NO_EXCEPT 0x08 +#define LIBC_MATH_FAST \ + (LIBC_MATH_SKIP_ACCURATE_PASS | LIBC_MATH_SMALL_TABLES | \ + LIBC_MATH_NO_ERRNO | LIBC_MATH_NO_EXCEPT) + +#ifndef LIBC_MATH +#define LIBC_MATH 0 +#endif // LIBC_MATH + +#if (LIBC_MATH & LIBC_MATH_SKIP_ACCURATE_PASS) +#define LIBC_MATH_HAS_SKIP_ACCURATE_PASS +#endif + +#if (LIBC_MATH & LIBC_MATH_SMALL_TABLES) +#define LIBC_MATH_HAS_SMALL_TABLES +#endif + +#endif // LLVM_LIBC_SRC___SUPPORT_MACROS_OPTIMIZATION_H diff --git a/lib/libcxx/libc/src/__support/macros/properties/architectures.h b/lib/libcxx/libc/src/__support/macros/properties/architectures.h new file mode 100644 index 0000000000..c88956ff41 --- /dev/null +++ b/lib/libcxx/libc/src/__support/macros/properties/architectures.h @@ -0,0 +1,64 @@ +//===-- Compile time architecture detection ---------------------*- 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_PROPERTIES_ARCHITECTURES_H +#define LLVM_LIBC_SRC___SUPPORT_MACROS_PROPERTIES_ARCHITECTURES_H + +#if defined(__AMDGPU__) +#define LIBC_TARGET_ARCH_IS_AMDGPU +#endif + +#if defined(__NVPTX__) +#define LIBC_TARGET_ARCH_IS_NVPTX +#endif + +#if defined(LIBC_TARGET_ARCH_IS_NVPTX) || defined(LIBC_TARGET_ARCH_IS_AMDGPU) +#define LIBC_TARGET_ARCH_IS_GPU +#endif + +#if defined(__pnacl__) || defined(__CLR_VER) || defined(LIBC_TARGET_ARCH_IS_GPU) +#define LIBC_TARGET_ARCH_IS_VM +#endif + +#if (defined(_M_IX86) || defined(__i386__)) && !defined(LIBC_TARGET_ARCH_IS_VM) +#define LIBC_TARGET_ARCH_IS_X86_32 +#endif + +#if (defined(_M_X64) || defined(__x86_64__)) && !defined(LIBC_TARGET_ARCH_IS_VM) +#define LIBC_TARGET_ARCH_IS_X86_64 +#endif + +#if defined(LIBC_TARGET_ARCH_IS_X86_32) || defined(LIBC_TARGET_ARCH_IS_X86_64) +#define LIBC_TARGET_ARCH_IS_X86 +#endif + +#if (defined(__arm__) || defined(_M_ARM)) +#define LIBC_TARGET_ARCH_IS_ARM +#endif + +#if defined(__aarch64__) || defined(__arm64__) || defined(_M_ARM64) +#define LIBC_TARGET_ARCH_IS_AARCH64 +#endif + +#if defined(LIBC_TARGET_ARCH_IS_AARCH64) || defined(LIBC_TARGET_ARCH_IS_ARM) +#define LIBC_TARGET_ARCH_IS_ANY_ARM +#endif + +#if defined(__riscv) && (__riscv_xlen == 64) +#define LIBC_TARGET_ARCH_IS_RISCV64 +#endif + +#if defined(__riscv) && (__riscv_xlen == 32) +#define LIBC_TARGET_ARCH_IS_RISCV32 +#endif + +#if defined(LIBC_TARGET_ARCH_IS_RISCV64) || defined(LIBC_TARGET_ARCH_IS_RISCV32) +#define LIBC_TARGET_ARCH_IS_ANY_RISCV +#endif + +#endif // LLVM_LIBC_SRC___SUPPORT_MACROS_PROPERTIES_ARCHITECTURES_H diff --git a/lib/libcxx/libc/src/__support/macros/properties/compiler.h b/lib/libcxx/libc/src/__support/macros/properties/compiler.h new file mode 100644 index 0000000000..b9ec0dd1de --- /dev/null +++ b/lib/libcxx/libc/src/__support/macros/properties/compiler.h @@ -0,0 +1,43 @@ +//===-- Compile time compiler detection -------------------------*- 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_PROPERTIES_COMPILER_H +#define LLVM_LIBC_SRC___SUPPORT_MACROS_PROPERTIES_COMPILER_H + +// Example usage of compiler version checks +// #if defined(LIBC_COMPILER_CLANG_VER) +// # if LIBC_COMPILER_CLANG_VER < 1500 +// # warning "Libc only supports Clang 15 and later" +// # endif +// #elif defined(LIBC_COMPILER_GCC_VER) +// # if LIBC_COMPILER_GCC_VER < 1500 +// # warning "Libc only supports GCC 15 and later" +// # endif +// #elif defined(LIBC_COMPILER_MSC_VER) +// # if LIBC_COMPILER_MSC_VER < 1930 +// # warning "Libc only supports Visual Studio 2022 RTW (17.0) and later" +// # endif +// #endif + +#if defined(__clang__) +#define LIBC_COMPILER_IS_CLANG +#define LIBC_COMPILER_CLANG_VER (__clang_major__ * 100 + __clang_minor__) +#endif + +#if defined(__GNUC__) && !defined(__clang__) +#define LIBC_COMPILER_IS_GCC +#define LIBC_COMPILER_GCC_VER (__GNUC__ * 100 + __GNUC_MINOR__) +#endif + +#if defined(_MSC_VER) +#define LIBC_COMPILER_IS_MSC +// https://learn.microsoft.com/en-us/cpp/preprocessor/predefined-macros +#define LIBC_COMPILER_MSC_VER (_MSC_VER) +#endif + +#endif // LLVM_LIBC_SRC___SUPPORT_MACROS_PROPERTIES_COMPILER_H diff --git a/lib/libcxx/libc/src/__support/macros/properties/complex_types.h b/lib/libcxx/libc/src/__support/macros/properties/complex_types.h new file mode 100644 index 0000000000..ede4d6b7c7 --- /dev/null +++ b/lib/libcxx/libc/src/__support/macros/properties/complex_types.h @@ -0,0 +1,30 @@ +//===-- Complex Types support -----------------------------------*- 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 +// +//===----------------------------------------------------------------------===// +// Complex Types detection and support. + +#ifndef LLVM_LIBC_SRC___SUPPORT_MACROS_PROPERTIES_CTYPES_H +#define LLVM_LIBC_SRC___SUPPORT_MACROS_PROPERTIES_CTYPES_H + +#include "include/llvm-libc-types/cfloat128.h" +#include "include/llvm-libc-types/cfloat16.h" +#include "types.h" + +// -- cfloat16 support -------------------------------------------------------- +// LIBC_TYPES_HAS_CFLOAT16 and 'cfloat16' type is provided by +// "include/llvm-libc-types/cfloat16.h" + +// -- cfloat128 support ------------------------------------------------------- +// LIBC_TYPES_HAS_CFLOAT128 and 'cfloat128' type are provided by +// "include/llvm-libc-types/cfloat128.h" + +#if defined(LIBC_TYPES_HAS_CFLOAT128) && \ + !defined(LIBC_TYPES_CFLOAT128_IS_COMPLEX_LONG_DOUBLE) +#define LIBC_TYPES_CFLOAT128_IS_NOT_COMPLEX_LONG_DOUBLE +#endif + +#endif // LLVM_LIBC_SRC___SUPPORT_MACROS_PROPERTIES_CTYPES_H diff --git a/lib/libcxx/libc/src/__support/macros/properties/cpu_features.h b/lib/libcxx/libc/src/__support/macros/properties/cpu_features.h new file mode 100644 index 0000000000..d2cea36751 --- /dev/null +++ b/lib/libcxx/libc/src/__support/macros/properties/cpu_features.h @@ -0,0 +1,60 @@ +//===-- Compile time cpu feature detection ----------------------*- 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 +// +//===----------------------------------------------------------------------===// +// This file lists target cpu features by introspecting compiler enabled +// preprocessor definitions. +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_MACROS_PROPERTIES_CPU_FEATURES_H +#define LLVM_LIBC_SRC___SUPPORT_MACROS_PROPERTIES_CPU_FEATURES_H + +#include "architectures.h" + +#if defined(__ARM_FEATURE_FP16_SCALAR_ARITHMETIC) +#define LIBC_TARGET_CPU_HAS_FULLFP16 +#endif + +#if defined(__SSE2__) +#define LIBC_TARGET_CPU_HAS_SSE2 +#endif + +#if defined(__SSE4_2__) +#define LIBC_TARGET_CPU_HAS_SSE4_2 +#endif + +#if defined(__AVX__) +#define LIBC_TARGET_CPU_HAS_AVX +#endif + +#if defined(__AVX2__) +#define LIBC_TARGET_CPU_HAS_AVX2 +#endif + +#if defined(__AVX512F__) +#define LIBC_TARGET_CPU_HAS_AVX512F +#endif + +#if defined(__AVX512BW__) +#define LIBC_TARGET_CPU_HAS_AVX512BW +#endif + +#if defined(__ARM_FEATURE_FMA) || (defined(__AVX2__) && defined(__FMA__)) || \ + defined(__NVPTX__) || defined(__AMDGPU__) || defined(__LIBC_RISCV_USE_FMA) +#define LIBC_TARGET_CPU_HAS_FMA +#endif + +#if defined(LIBC_TARGET_ARCH_IS_AARCH64) || \ + (defined(LIBC_TARGET_ARCH_IS_X86_64) && \ + defined(LIBC_TARGET_CPU_HAS_SSE4_2)) +#define LIBC_TARGET_CPU_HAS_NEAREST_INT +#endif + +#if defined(LIBC_TARGET_ARCH_IS_AARCH64) || defined(LIBC_TARGET_ARCH_IS_GPU) +#define LIBC_TARGET_CPU_HAS_FAST_FLOAT16_OPS +#endif + +#endif // LLVM_LIBC_SRC___SUPPORT_MACROS_PROPERTIES_CPU_FEATURES_H diff --git a/lib/libcxx/libc/src/__support/macros/properties/os.h b/lib/libcxx/libc/src/__support/macros/properties/os.h new file mode 100644 index 0000000000..807ce18127 --- /dev/null +++ b/lib/libcxx/libc/src/__support/macros/properties/os.h @@ -0,0 +1,32 @@ +//===-- Target OS detection -------------------------------------*- 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_PROPERTIES_OS_H +#define LLVM_LIBC_SRC___SUPPORT_MACROS_PROPERTIES_OS_H + +#if (defined(__freebsd__) || defined(__FreeBSD__)) +#define LIBC_TARGET_OS_IS_FREEBSD +#endif + +#if defined(__ANDROID__) +#define LIBC_TARGET_OS_IS_ANDROID +#endif + +#if defined(__linux__) && !defined(LIBC_TARGET_OS_IS_FREEBSD) && \ + !defined(LIBC_TARGET_OS_IS_ANDROID) +#define LIBC_TARGET_OS_IS_LINUX +#endif + +#if (defined(_WIN64) || defined(_WIN32)) +#define LIBC_TARGET_OS_IS_WINDOWS +#endif + +#if defined(__Fuchsia__) +#define LIBC_TARGET_OS_IS_FUCHSIA +#endif + +#endif // LLVM_LIBC_SRC___SUPPORT_MACROS_PROPERTIES_OS_H diff --git a/lib/libcxx/libc/src/__support/macros/properties/types.h b/lib/libcxx/libc/src/__support/macros/properties/types.h new file mode 100644 index 0000000000..6293b9d4d2 --- /dev/null +++ b/lib/libcxx/libc/src/__support/macros/properties/types.h @@ -0,0 +1,61 @@ +//===-- Types support -------------------------------------------*- 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 +// +//===----------------------------------------------------------------------===// +// Types detection and support. + +#ifndef LLVM_LIBC_SRC___SUPPORT_MACROS_PROPERTIES_TYPES_H +#define LLVM_LIBC_SRC___SUPPORT_MACROS_PROPERTIES_TYPES_H + +#include "hdr/float_macros.h" // LDBL_MANT_DIG +#include "include/llvm-libc-macros/float16-macros.h" // LIBC_TYPES_HAS_FLOAT16 +#include "include/llvm-libc-types/float128.h" // float128 +#include "src/__support/macros/properties/architectures.h" +#include "src/__support/macros/properties/compiler.h" +#include "src/__support/macros/properties/cpu_features.h" +#include "src/__support/macros/properties/os.h" + +#include <stdint.h> // UINT64_MAX, __SIZEOF_INT128__ + +// 'long double' properties. +#if (LDBL_MANT_DIG == 53) +#define LIBC_TYPES_LONG_DOUBLE_IS_FLOAT64 +#elif (LDBL_MANT_DIG == 64) +#define LIBC_TYPES_LONG_DOUBLE_IS_X86_FLOAT80 +#elif (LDBL_MANT_DIG == 113) +#define LIBC_TYPES_LONG_DOUBLE_IS_FLOAT128 +#elif (LDBL_MANT_DIG == 106) +#define LIBC_TYPES_LONG_DOUBLE_IS_DOUBLE_DOUBLE +#endif + +#if defined(LIBC_TYPES_HAS_FLOAT128) && \ + !defined(LIBC_TYPES_LONG_DOUBLE_IS_FLOAT128) +#define LIBC_TYPES_FLOAT128_IS_NOT_LONG_DOUBLE +#endif + +// int64 / uint64 support +#if defined(UINT64_MAX) +#define LIBC_TYPES_HAS_INT64 +#endif // UINT64_MAX + +// int128 / uint128 support +#if defined(__SIZEOF_INT128__) && !defined(LIBC_TARGET_OS_IS_WINDOWS) +#define LIBC_TYPES_HAS_INT128 +#endif // defined(__SIZEOF_INT128__) + +// -- float16 support --------------------------------------------------------- +// LIBC_TYPES_HAS_FLOAT16 is provided by +// "include/llvm-libc-macros/float16-macros.h" +#ifdef LIBC_TYPES_HAS_FLOAT16 +// Type alias for internal use. +using float16 = _Float16; +#endif // LIBC_TYPES_HAS_FLOAT16 + +// -- float128 support -------------------------------------------------------- +// LIBC_TYPES_HAS_FLOAT128 and 'float128' type are provided by +// "include/llvm-libc-types/float128.h" + +#endif // LLVM_LIBC_SRC___SUPPORT_MACROS_PROPERTIES_TYPES_H diff --git a/lib/libcxx/libc/src/__support/macros/sanitizer.h b/lib/libcxx/libc/src/__support/macros/sanitizer.h new file mode 100644 index 0000000000..c20412e0f8 --- /dev/null +++ b/lib/libcxx/libc/src/__support/macros/sanitizer.h @@ -0,0 +1,59 @@ +//===-- Convenient sanitizer 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_SANITIZER_H +#define LLVM_LIBC_SRC___SUPPORT_MACROS_SANITIZER_H + +#include "src/__support/macros/config.h" //LIBC_HAS_FEATURE + +//----------------------------------------------------------------------------- +// Functions to unpoison memory +//----------------------------------------------------------------------------- + +#if LIBC_HAS_FEATURE(address_sanitizer) || defined(__SANITIZE_ADDRESS__) +#define LIBC_HAS_ADDRESS_SANITIZER +#endif + +#if LIBC_HAS_FEATURE(memory_sanitizer) +#define LIBC_HAS_MEMORY_SANITIZER +#endif + +#if LIBC_HAS_FEATURE(undefined_behavior_sanitizer) +#define LIBC_HAS_UNDEFINED_BEHAVIOR_SANITIZER +#endif + +#if defined(LIBC_HAS_ADDRESS_SANITIZER) || \ + defined(LIBC_HAS_MEMORY_SANITIZER) || \ + defined(LIBC_HAS_UNDEFINED_BEHAVIOR_SANITIZER) +#define LIBC_HAS_SANITIZER +#endif + +#ifdef LIBC_HAS_MEMORY_SANITIZER +// Only perform MSAN unpoison in non-constexpr context. +#include <sanitizer/msan_interface.h> +#define MSAN_UNPOISON(addr, size) \ + do { \ + if (!__builtin_is_constant_evaluated()) \ + __msan_unpoison(addr, size); \ + } while (0) +#else +#define MSAN_UNPOISON(ptr, size) +#endif + +#ifdef LIBC_HAS_ADDRESS_SANITIZER +#include <sanitizer/asan_interface.h> +#define ASAN_POISON_MEMORY_REGION(addr, size) \ + __asan_poison_memory_region((addr), (size)) +#define 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)) +#endif + +#endif // LLVM_LIBC_SRC___SUPPORT_MACROS_SANITIZER_H diff --git a/lib/libcxx/libc/src/__support/math_extras.h b/lib/libcxx/libc/src/__support/math_extras.h new file mode 100644 index 0000000000..6f4a006aad --- /dev/null +++ b/lib/libcxx/libc/src/__support/math_extras.h @@ -0,0 +1,161 @@ +//===-- Mimics llvm/Support/MathExtras.h ------------------------*- C++ -*-===// +// Provides useful math functions. +// +// 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_MATH_EXTRAS_H +#define LLVM_LIBC_SRC___SUPPORT_MATH_EXTRAS_H + +#include "src/__support/CPP/bit.h" // countl_one, countr_zero +#include "src/__support/CPP/limits.h" // CHAR_BIT, numeric_limits +#include "src/__support/CPP/type_traits.h" // is_unsigned_v, is_constant_evaluated +#include "src/__support/macros/attributes.h" // LIBC_INLINE +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { + +// Create a bitmask with the count right-most bits set to 1, and all other bits +// set to 0. Only unsigned types are allowed. +template <typename T, size_t count> +LIBC_INLINE constexpr cpp::enable_if_t<cpp::is_unsigned_v<T>, T> +mask_trailing_ones() { + constexpr unsigned T_BITS = CHAR_BIT * sizeof(T); + static_assert(count <= T_BITS && "Invalid bit index"); + return count == 0 ? 0 : (T(-1) >> (T_BITS - count)); +} + +// Create a bitmask with the count left-most bits set to 1, and all other bits +// set to 0. Only unsigned types are allowed. +template <typename T, size_t count> +LIBC_INLINE constexpr cpp::enable_if_t<cpp::is_unsigned_v<T>, T> +mask_leading_ones() { + return T(~mask_trailing_ones<T, CHAR_BIT * sizeof(T) - count>()); +} + +// Create a bitmask with the count right-most bits set to 0, and all other bits +// set to 1. Only unsigned types are allowed. +template <typename T, size_t count> +LIBC_INLINE constexpr cpp::enable_if_t<cpp::is_unsigned_v<T>, T> +mask_trailing_zeros() { + return mask_leading_ones<T, CHAR_BIT * sizeof(T) - count>(); +} + +// Create a bitmask with the count left-most bits set to 0, and all other bits +// set to 1. Only unsigned types are allowed. +template <typename T, size_t count> +LIBC_INLINE constexpr cpp::enable_if_t<cpp::is_unsigned_v<T>, T> +mask_leading_zeros() { + return mask_trailing_ones<T, CHAR_BIT * sizeof(T) - count>(); +} + +// Returns whether 'a + b' overflows, the result is stored in 'res'. +template <typename T> +[[nodiscard]] LIBC_INLINE constexpr bool add_overflow(T a, T b, T &res) { + return __builtin_add_overflow(a, b, &res); +} + +// Returns whether 'a - b' overflows, the result is stored in 'res'. +template <typename T> +[[nodiscard]] LIBC_INLINE constexpr bool sub_overflow(T a, T b, T &res) { + return __builtin_sub_overflow(a, b, &res); +} + +#define RETURN_IF(TYPE, BUILTIN) \ + if constexpr (cpp::is_same_v<T, TYPE>) \ + return BUILTIN(a, b, carry_in, carry_out); + +// Returns the result of 'a + b' taking into account 'carry_in'. +// The carry out is stored in 'carry_out' it not 'nullptr', dropped otherwise. +// We keep the pass by pointer interface for consistency with the intrinsic. +template <typename T> +[[nodiscard]] LIBC_INLINE constexpr cpp::enable_if_t<cpp::is_unsigned_v<T>, T> +add_with_carry(T a, T b, T carry_in, T &carry_out) { + if constexpr (!cpp::is_constant_evaluated()) { +#if __has_builtin(__builtin_addcb) + RETURN_IF(unsigned char, __builtin_addcb) +#elif __has_builtin(__builtin_addcs) + RETURN_IF(unsigned short, __builtin_addcs) +#elif __has_builtin(__builtin_addc) + RETURN_IF(unsigned int, __builtin_addc) +#elif __has_builtin(__builtin_addcl) + RETURN_IF(unsigned long, __builtin_addcl) +#elif __has_builtin(__builtin_addcll) + RETURN_IF(unsigned long long, __builtin_addcll) +#endif + } + T sum = {}; + T carry1 = add_overflow(a, b, sum); + T carry2 = add_overflow(sum, carry_in, sum); + carry_out = carry1 | carry2; + return sum; +} + +// Returns the result of 'a - b' taking into account 'carry_in'. +// The carry out is stored in 'carry_out' it not 'nullptr', dropped otherwise. +// We keep the pass by pointer interface for consistency with the intrinsic. +template <typename T> +[[nodiscard]] LIBC_INLINE constexpr cpp::enable_if_t<cpp::is_unsigned_v<T>, T> +sub_with_borrow(T a, T b, T carry_in, T &carry_out) { + if constexpr (!cpp::is_constant_evaluated()) { +#if __has_builtin(__builtin_subcb) + RETURN_IF(unsigned char, __builtin_subcb) +#elif __has_builtin(__builtin_subcs) + RETURN_IF(unsigned short, __builtin_subcs) +#elif __has_builtin(__builtin_subc) + RETURN_IF(unsigned int, __builtin_subc) +#elif __has_builtin(__builtin_subcl) + RETURN_IF(unsigned long, __builtin_subcl) +#elif __has_builtin(__builtin_subcll) + RETURN_IF(unsigned long long, __builtin_subcll) +#endif + } + T sub = {}; + T carry1 = sub_overflow(a, b, sub); + T carry2 = sub_overflow(sub, carry_in, sub); + carry_out = carry1 | carry2; + return sub; +} + +#undef RETURN_IF + +template <typename T> +[[nodiscard]] LIBC_INLINE constexpr cpp::enable_if_t<cpp::is_unsigned_v<T>, int> +first_leading_zero(T value) { + return value == cpp::numeric_limits<T>::max() ? 0 + : cpp::countl_one(value) + 1; +} + +template <typename T> +[[nodiscard]] LIBC_INLINE constexpr cpp::enable_if_t<cpp::is_unsigned_v<T>, int> +first_leading_one(T value) { + return first_leading_zero(static_cast<T>(~value)); +} + +template <typename T> +[[nodiscard]] LIBC_INLINE constexpr cpp::enable_if_t<cpp::is_unsigned_v<T>, int> +first_trailing_zero(T value) { + return value == cpp::numeric_limits<T>::max() + ? 0 + : cpp::countr_zero(static_cast<T>(~value)) + 1; +} + +template <typename T> +[[nodiscard]] LIBC_INLINE constexpr cpp::enable_if_t<cpp::is_unsigned_v<T>, int> +first_trailing_one(T value) { + return value == cpp::numeric_limits<T>::max() ? 0 + : cpp::countr_zero(value) + 1; +} + +template <typename T> +[[nodiscard]] LIBC_INLINE constexpr cpp::enable_if_t<cpp::is_unsigned_v<T>, int> +count_zeros(T value) { + return cpp::popcount<T>(static_cast<T>(~value)); +} + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_MATH_EXTRAS_H diff --git a/lib/libcxx/libc/src/__support/number_pair.h b/lib/libcxx/libc/src/__support/number_pair.h new file mode 100644 index 0000000000..f5e877406d --- /dev/null +++ b/lib/libcxx/libc/src/__support/number_pair.h @@ -0,0 +1,26 @@ +//===-- Utilities for pairs of numbers. -------------------------*- 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_NUMBER_PAIR_H +#define LLVM_LIBC_SRC___SUPPORT_NUMBER_PAIR_H + +#include "CPP/type_traits.h" +#include "src/__support/macros/config.h" + +#include <stddef.h> + +namespace LIBC_NAMESPACE_DECL { + +template <typename T> struct NumberPair { + T lo = T(0); + T hi = T(0); +}; + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_NUMBER_PAIR_H diff --git a/lib/libcxx/libc/src/__support/sign.h b/lib/libcxx/libc/src/__support/sign.h new file mode 100644 index 0000000000..4a629e4488 --- /dev/null +++ b/lib/libcxx/libc/src/__support/sign.h @@ -0,0 +1,43 @@ +//===-- A simple sign type --------------------------------------*- 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_SIGN_H +#define LLVM_LIBC_SRC___SUPPORT_SIGN_H + +#include "src/__support/macros/attributes.h" // LIBC_INLINE, LIBC_INLINE_VAR + +namespace LIBC_NAMESPACE_DECL { + +// A type to interact with signed arithmetic types. +struct Sign { + LIBC_INLINE constexpr bool is_pos() const { return !is_negative; } + LIBC_INLINE constexpr bool is_neg() const { return is_negative; } + + LIBC_INLINE friend constexpr bool operator==(Sign a, Sign b) { + return a.is_negative == b.is_negative; + } + + LIBC_INLINE friend constexpr bool operator!=(Sign a, Sign b) { + return !(a == b); + } + + static const Sign POS; + static const Sign NEG; + +private: + LIBC_INLINE constexpr explicit Sign(bool is_negative) + : is_negative(is_negative) {} + + bool is_negative; +}; + +LIBC_INLINE_VAR constexpr Sign Sign::NEG = Sign(true); +LIBC_INLINE_VAR constexpr Sign Sign::POS = Sign(false); + +} // namespace LIBC_NAMESPACE_DECL +#endif // LLVM_LIBC_SRC___SUPPORT_SIGN_H diff --git a/lib/libcxx/libc/src/__support/str_to_float.h b/lib/libcxx/libc/src/__support/str_to_float.h new file mode 100644 index 0000000000..b4d5646822 --- /dev/null +++ b/lib/libcxx/libc/src/__support/str_to_float.h @@ -0,0 +1,1275 @@ +//===-- String to float conversion utils ------------------------*- 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 +// +//===----------------------------------------------------------------------===// + +// ----------------------------------------------------------------------------- +// **** WARNING **** +// This file is shared with libc++. You should also be careful when adding +// dependencies to this file, since it needs to build for all libc++ targets. +// ----------------------------------------------------------------------------- + +#ifndef LLVM_LIBC_SRC___SUPPORT_STR_TO_FLOAT_H +#define LLVM_LIBC_SRC___SUPPORT_STR_TO_FLOAT_H + +#include "src/__support/CPP/bit.h" +#include "src/__support/CPP/limits.h" +#include "src/__support/CPP/optional.h" +#include "src/__support/CPP/string_view.h" +#include "src/__support/FPUtil/FPBits.h" +#include "src/__support/FPUtil/rounding_mode.h" +#include "src/__support/common.h" +#include "src/__support/ctype_utils.h" +#include "src/__support/detailed_powers_of_ten.h" +#include "src/__support/high_precision_decimal.h" +#include "src/__support/macros/config.h" +#include "src/__support/macros/null_check.h" +#include "src/__support/macros/optimization.h" +#include "src/__support/str_to_integer.h" +#include "src/__support/str_to_num_result.h" +#include "src/__support/uint128.h" +#include "src/errno/libc_errno.h" // For ERANGE + +#include <stdint.h> + +namespace LIBC_NAMESPACE_DECL { +namespace internal { + +// ----------------------------------------------------------------------------- +// **** WARNING **** +// This interface is shared with libc++, if you change this interface you need +// to update it in both libc and libc++. +// ----------------------------------------------------------------------------- +template <class T> struct ExpandedFloat { + typename fputil::FPBits<T>::StorageType mantissa; + int32_t exponent; +}; + +// ----------------------------------------------------------------------------- +// **** WARNING **** +// This interface is shared with libc++, if you change this interface you need +// to update it in both libc and libc++. +// ----------------------------------------------------------------------------- +template <class T> struct FloatConvertReturn { + ExpandedFloat<T> num = {0, 0}; + int error = 0; +}; + +LIBC_INLINE uint64_t low64(const UInt128 &num) { + return static_cast<uint64_t>(num & 0xffffffffffffffff); +} + +LIBC_INLINE uint64_t high64(const UInt128 &num) { + return static_cast<uint64_t>(num >> 64); +} + +template <class T> LIBC_INLINE void set_implicit_bit(fputil::FPBits<T> &) { + return; +} + +#if defined(LIBC_TYPES_LONG_DOUBLE_IS_X86_FLOAT80) +template <> +LIBC_INLINE void +set_implicit_bit<long double>(fputil::FPBits<long double> &result) { + result.set_implicit_bit(result.get_biased_exponent() != 0); +} +#endif // LIBC_TYPES_LONG_DOUBLE_IS_X86_FLOAT80 + +// This Eisel-Lemire implementation is based on the algorithm described in the +// paper Number Parsing at a Gigabyte per Second, Software: Practice and +// Experience 51 (8), 2021 (https://arxiv.org/abs/2101.11408), as well as the +// description by Nigel Tao +// (https://nigeltao.github.io/blog/2020/eisel-lemire.html) and the golang +// implementation, also by Nigel Tao +// (https://github.com/golang/go/blob/release-branch.go1.16/src/strconv/eisel_lemire.go#L25) +// for some optimizations as well as handling 32 bit floats. +template <class T> +LIBC_INLINE cpp::optional<ExpandedFloat<T>> +eisel_lemire(ExpandedFloat<T> init_num, + RoundDirection round = RoundDirection::Nearest) { + using FPBits = typename fputil::FPBits<T>; + using StorageType = typename FPBits::StorageType; + + StorageType mantissa = init_num.mantissa; + int32_t exp10 = init_num.exponent; + + if (sizeof(T) > 8) { // This algorithm cannot handle anything longer than a + // double, so we skip straight to the fallback. + return cpp::nullopt; + } + + // Exp10 Range + if (exp10 < DETAILED_POWERS_OF_TEN_MIN_EXP_10 || + exp10 > DETAILED_POWERS_OF_TEN_MAX_EXP_10) { + return cpp::nullopt; + } + + // Normalization + uint32_t clz = cpp::countl_zero<StorageType>(mantissa); + mantissa <<= clz; + + int32_t exp2 = + exp10_to_exp2(exp10) + FPBits::STORAGE_LEN + FPBits::EXP_BIAS - clz; + + // Multiplication + const uint64_t *power_of_ten = + DETAILED_POWERS_OF_TEN[exp10 - DETAILED_POWERS_OF_TEN_MIN_EXP_10]; + + UInt128 first_approx = + static_cast<UInt128>(mantissa) * static_cast<UInt128>(power_of_ten[1]); + + // 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 + // 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. + const uint64_t halfway_constant = + (uint64_t(1) << (FPBits::STORAGE_LEN - (FPBits::FRACTION_LEN + 3))) - 1; + if ((high64(first_approx) & halfway_constant) == halfway_constant && + low64(first_approx) + mantissa < mantissa) { + UInt128 low_bits = + static_cast<UInt128>(mantissa) * static_cast<UInt128>(power_of_ten[0]); + UInt128 second_approx = + first_approx + static_cast<UInt128>(high64(low_bits)); + + if ((high64(second_approx) & halfway_constant) == halfway_constant && + low64(second_approx) + 1 == 0 && + low64(low_bits) + mantissa < mantissa) { + return cpp::nullopt; + } + final_approx = second_approx; + } else { + final_approx = first_approx; + } + + // Shifting to 54 bits for doubles and 25 bits for floats + StorageType msb = static_cast<StorageType>(high64(final_approx) >> + (FPBits::STORAGE_LEN - 1)); + StorageType final_mantissa = static_cast<StorageType>( + high64(final_approx) >> + (msb + FPBits::STORAGE_LEN - (FPBits::FRACTION_LEN + 3))); + exp2 -= static_cast<uint32_t>(1 ^ msb); // same as !msb + + if (round == RoundDirection::Nearest) { + // Half-way ambiguity + if (low64(final_approx) == 0 && + (high64(final_approx) & halfway_constant) == 0 && + (final_mantissa & 3) == 1) { + return cpp::nullopt; + } + + // Round to even. + final_mantissa += final_mantissa & 1; + + } else if (round == RoundDirection::Up) { + // If any of the bits being rounded away are non-zero, then round up. + if (low64(final_approx) > 0 || + (high64(final_approx) & halfway_constant) > 0) { + // Add two since the last current lowest bit is about to be shifted away. + final_mantissa += 2; + } + } + // else round down, which has no effect. + + // From 54 to 53 bits for doubles and 25 to 24 bits for floats + final_mantissa >>= 1; + if ((final_mantissa >> (FPBits::FRACTION_LEN + 1)) > 0) { + final_mantissa >>= 1; + ++exp2; + } + + // The if block is equivalent to (but has fewer branches than): + // if exp2 <= 0 || exp2 >= 0x7FF { etc } + if (static_cast<uint32_t>(exp2) - 1 >= (1 << FPBits::EXP_LEN) - 2) { + return cpp::nullopt; + } + + ExpandedFloat<T> output; + output.mantissa = final_mantissa; + output.exponent = exp2; + return output; +} + +// TODO: Re-enable eisel-lemire for long double is double double once it's +// properly supported. +#if !defined(LIBC_TYPES_LONG_DOUBLE_IS_FLOAT64) && \ + !defined(LIBC_TYPES_LONG_DOUBLE_IS_DOUBLE_DOUBLE) +template <> +LIBC_INLINE cpp::optional<ExpandedFloat<long double>> +eisel_lemire<long double>(ExpandedFloat<long double> init_num, + RoundDirection round) { + using FPBits = typename fputil::FPBits<long double>; + using StorageType = typename FPBits::StorageType; + + UInt128 mantissa = init_num.mantissa; + int32_t exp10 = init_num.exponent; + + // Exp10 Range + // This doesn't reach very far into the range for long doubles, since it's + // sized for doubles and their 11 exponent bits, and not for long doubles and + // their 15 exponent bits (max exponent of ~300 for double vs ~5000 for long + // double). This is a known tradeoff, and was made because a proper long + // double table would be approximately 16 times larger. This would have + // significant memory and storage costs all the time to speed up a relatively + // uncommon path. In addition the exp10_to_exp2 function only approximates + // multiplying by log(10)/log(2), and that approximation may not be accurate + // out to the full long double range. + if (exp10 < DETAILED_POWERS_OF_TEN_MIN_EXP_10 || + exp10 > DETAILED_POWERS_OF_TEN_MAX_EXP_10) { + return cpp::nullopt; + } + + // Normalization + uint32_t clz = cpp::countl_zero(mantissa) - + ((sizeof(UInt128) - sizeof(StorageType)) * CHAR_BIT); + mantissa <<= clz; + + int32_t exp2 = + exp10_to_exp2(exp10) + FPBits::STORAGE_LEN + FPBits::EXP_BIAS - clz; + + // Multiplication + const uint64_t *power_of_ten = + DETAILED_POWERS_OF_TEN[exp10 - DETAILED_POWERS_OF_TEN_MIN_EXP_10]; + + // Since the input mantissa is more than 64 bits, we have to multiply with the + // full 128 bits of the power of ten to get an approximation with the same + // number of significant bits. This means that we only get the one + // approximation, and that approximation is 256 bits long. + UInt128 approx_upper = static_cast<UInt128>(high64(mantissa)) * + static_cast<UInt128>(power_of_ten[1]); + + UInt128 approx_middle_a = static_cast<UInt128>(high64(mantissa)) * + static_cast<UInt128>(power_of_ten[0]); + UInt128 approx_middle_b = static_cast<UInt128>(low64(mantissa)) * + static_cast<UInt128>(power_of_ten[1]); + + UInt128 approx_middle = approx_middle_a + approx_middle_b; + + // Handle overflow in the middle + approx_upper += (approx_middle < approx_middle_a) ? UInt128(1) << 64 : 0; + + UInt128 approx_lower = static_cast<UInt128>(low64(mantissa)) * + static_cast<UInt128>(power_of_ten[0]); + + UInt128 final_approx_lower = + approx_lower + (static_cast<UInt128>(low64(approx_middle)) << 64); + UInt128 final_approx_upper = approx_upper + high64(approx_middle) + + (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 + // (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. + constexpr UInt128 HALFWAY_CONSTANT = + (UInt128(1) << (FPBits::STORAGE_LEN - (FPBits::FRACTION_LEN + 3))) - 1; + + if ((final_approx_upper & HALFWAY_CONSTANT) == HALFWAY_CONSTANT && + final_approx_lower + mantissa < mantissa) { + return cpp::nullopt; + } + + // Shifting to 65 bits for 80 bit floats and 113 bits for 128 bit floats + uint32_t msb = + static_cast<uint32_t>(final_approx_upper >> (FPBits::STORAGE_LEN - 1)); + UInt128 final_mantissa = final_approx_upper >> (msb + FPBits::STORAGE_LEN - + (FPBits::FRACTION_LEN + 3)); + exp2 -= static_cast<uint32_t>(1 ^ msb); // same as !msb + + if (round == RoundDirection::Nearest) { + // Half-way ambiguity + if (final_approx_lower == 0 && + (final_approx_upper & HALFWAY_CONSTANT) == 0 && + (final_mantissa & 3) == 1) { + return cpp::nullopt; + } + // Round to even. + final_mantissa += final_mantissa & 1; + + } else if (round == RoundDirection::Up) { + // If any of the bits being rounded away are non-zero, then round up. + if (final_approx_lower > 0 || (final_approx_upper & HALFWAY_CONSTANT) > 0) { + // Add two since the last current lowest bit is about to be shifted away. + final_mantissa += 2; + } + } + // else round down, which has no effect. + + // From 65 to 64 bits for 80 bit floats and 113 to 112 bits for 128 bit + // floats + final_mantissa >>= 1; + if ((final_mantissa >> (FPBits::FRACTION_LEN + 1)) > 0) { + final_mantissa >>= 1; + ++exp2; + } + + // The if block is equivalent to (but has fewer branches than): + // if exp2 <= 0 || exp2 >= MANTISSA_MAX { etc } + if (exp2 - 1 >= (1 << FPBits::EXP_LEN) - 2) { + return cpp::nullopt; + } + + ExpandedFloat<long double> output; + output.mantissa = static_cast<StorageType>(final_mantissa); + output.exponent = exp2; + return output; +} +#endif // !defined(LIBC_TYPES_LONG_DOUBLE_IS_FLOAT64) && + // !defined(LIBC_TYPES_LONG_DOUBLE_IS_DOUBLE_DOUBLE) + +// The nth item in POWERS_OF_TWO represents the greatest power of two less than +// 10^n. This tells us how much we can safely shift without overshooting. +constexpr uint8_t POWERS_OF_TWO[19] = { + 0, 3, 6, 9, 13, 16, 19, 23, 26, 29, 33, 36, 39, 43, 46, 49, 53, 56, 59, +}; +constexpr int32_t NUM_POWERS_OF_TWO = + sizeof(POWERS_OF_TWO) / sizeof(POWERS_OF_TWO[0]); + +// Takes a mantissa and base 10 exponent and converts it into its closest +// floating point type T equivalent. This is the fallback algorithm used when +// the Eisel-Lemire algorithm fails, it's slower but more accurate. It's based +// on the Simple Decimal Conversion algorithm by Nigel Tao, described at this +// link: https://nigeltao.github.io/blog/2020/parse-number-f64-simple.html +template <class T> +LIBC_INLINE FloatConvertReturn<T> simple_decimal_conversion( + const char *__restrict numStart, + const size_t num_len = cpp::numeric_limits<size_t>::max(), + RoundDirection round = RoundDirection::Nearest) { + using FPBits = typename fputil::FPBits<T>; + using StorageType = typename FPBits::StorageType; + + int32_t exp2 = 0; + HighPrecisionDecimal hpd = HighPrecisionDecimal(numStart, num_len); + + FloatConvertReturn<T> output; + + if (hpd.get_num_digits() == 0) { + output.num = {0, 0}; + return output; + } + + // If the exponent is too large and can't be represented in this size of + // float, return inf. + if (hpd.get_decimal_point() > 0 && + exp10_to_exp2(hpd.get_decimal_point() - 1) > FPBits::EXP_BIAS) { + output.num = {0, fputil::FPBits<T>::MAX_BIASED_EXPONENT}; + output.error = ERANGE; + return output; + } + // If the exponent is too small even for a subnormal, return 0. + if (hpd.get_decimal_point() < 0 && + exp10_to_exp2(-hpd.get_decimal_point()) > + (FPBits::EXP_BIAS + static_cast<int32_t>(FPBits::FRACTION_LEN))) { + output.num = {0, 0}; + output.error = ERANGE; + return output; + } + + // Right shift until the number is smaller than 1. + while (hpd.get_decimal_point() > 0) { + int32_t shift_amount = 0; + if (hpd.get_decimal_point() >= NUM_POWERS_OF_TWO) { + shift_amount = 60; + } else { + shift_amount = POWERS_OF_TWO[hpd.get_decimal_point()]; + } + exp2 += shift_amount; + hpd.shift(-shift_amount); + } + + // Left shift until the number is between 1/2 and 1 + while (hpd.get_decimal_point() < 0 || + (hpd.get_decimal_point() == 0 && hpd.get_digits()[0] < 5)) { + int32_t shift_amount = 0; + + if (-hpd.get_decimal_point() >= NUM_POWERS_OF_TWO) { + shift_amount = 60; + } else if (hpd.get_decimal_point() != 0) { + shift_amount = POWERS_OF_TWO[-hpd.get_decimal_point()]; + } else { // This handles the case of the number being between .1 and .5 + shift_amount = 1; + } + exp2 -= shift_amount; + hpd.shift(shift_amount); + } + + // Left shift once so that the number is between 1 and 2 + --exp2; + hpd.shift(1); + + // Get the biased exponent + exp2 += FPBits::EXP_BIAS; + + // Handle the exponent being too large (and return inf). + if (exp2 >= FPBits::MAX_BIASED_EXPONENT) { + output.num = {0, FPBits::MAX_BIASED_EXPONENT}; + output.error = ERANGE; + return output; + } + + // Shift left to fill the mantissa + hpd.shift(FPBits::FRACTION_LEN); + StorageType final_mantissa = hpd.round_to_integer_type<StorageType>(); + + // Handle subnormals + if (exp2 <= 0) { + // Shift right until there is a valid exponent + while (exp2 < 0) { + hpd.shift(-1); + ++exp2; + } + // Shift right one more time to compensate for the left shift to get it + // between 1 and 2. + hpd.shift(-1); + final_mantissa = hpd.round_to_integer_type<StorageType>(round); + + // Check if by shifting right we've caused this to round to a normal number. + if ((final_mantissa >> FPBits::FRACTION_LEN) != 0) { + ++exp2; + } + } + + // Check if rounding added a bit, and shift down if that's the case. + if (final_mantissa == StorageType(2) << FPBits::FRACTION_LEN) { + final_mantissa >>= 1; + ++exp2; + + // Check if this rounding causes exp2 to go out of range and make the result + // INF. If this is the case, then finalMantissa and exp2 are already the + // correct values for an INF result. + if (exp2 >= FPBits::MAX_BIASED_EXPONENT) { + output.error = ERANGE; + } + } + + if (exp2 == 0) { + output.error = ERANGE; + } + + output.num = {final_mantissa, exp2}; + return output; +} + +// This class is used for templating the constants for Clinger's Fast Path, +// described as a method of approximation in +// Clinger WD. How to Read Floating Point Numbers Accurately. SIGPLAN Not 1990 +// Jun;25(6):92–101. https://doi.org/10.1145/93548.93557. +// As well as the additions by Gay that extend the useful range by the number of +// exact digits stored by the float type, described in +// Gay DM, Correctly rounded binary-decimal and decimal-binary conversions; +// 1990. AT&T Bell Laboratories Numerical Analysis Manuscript 90-10. +template <class T> class ClingerConsts; + +template <> class ClingerConsts<float> { +public: + static constexpr float POWERS_OF_TEN_ARRAY[] = {1e0, 1e1, 1e2, 1e3, 1e4, 1e5, + 1e6, 1e7, 1e8, 1e9, 1e10}; + static constexpr int32_t EXACT_POWERS_OF_TEN = 10; + static constexpr int32_t DIGITS_IN_MANTISSA = 7; + static constexpr float MAX_EXACT_INT = 16777215.0; +}; + +template <> class ClingerConsts<double> { +public: + static constexpr double POWERS_OF_TEN_ARRAY[] = { + 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11, + 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, 1e20, 1e21, 1e22}; + static constexpr int32_t EXACT_POWERS_OF_TEN = 22; + static constexpr int32_t DIGITS_IN_MANTISSA = 15; + static constexpr double MAX_EXACT_INT = 9007199254740991.0; +}; + +#if defined(LIBC_TYPES_LONG_DOUBLE_IS_FLOAT64) +template <> class ClingerConsts<long double> { +public: + static constexpr long double POWERS_OF_TEN_ARRAY[] = { + 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11, + 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, 1e20, 1e21, 1e22}; + static constexpr int32_t EXACT_POWERS_OF_TEN = + ClingerConsts<double>::EXACT_POWERS_OF_TEN; + static constexpr int32_t DIGITS_IN_MANTISSA = + ClingerConsts<double>::DIGITS_IN_MANTISSA; + static constexpr long double MAX_EXACT_INT = + ClingerConsts<double>::MAX_EXACT_INT; +}; +#elif defined(LIBC_TYPES_LONG_DOUBLE_IS_X86_FLOAT80) +template <> class ClingerConsts<long double> { +public: + static constexpr long double POWERS_OF_TEN_ARRAY[] = { + 1e0L, 1e1L, 1e2L, 1e3L, 1e4L, 1e5L, 1e6L, 1e7L, 1e8L, 1e9L, + 1e10L, 1e11L, 1e12L, 1e13L, 1e14L, 1e15L, 1e16L, 1e17L, 1e18L, 1e19L, + 1e20L, 1e21L, 1e22L, 1e23L, 1e24L, 1e25L, 1e26L, 1e27L}; + static constexpr int32_t EXACT_POWERS_OF_TEN = 27; + static constexpr int32_t DIGITS_IN_MANTISSA = 21; + static constexpr long double MAX_EXACT_INT = 18446744073709551615.0L; +}; +#elif defined(LIBC_TYPES_LONG_DOUBLE_IS_FLOAT128) +template <> class ClingerConsts<long double> { +public: + static constexpr long double POWERS_OF_TEN_ARRAY[] = { + 1e0L, 1e1L, 1e2L, 1e3L, 1e4L, 1e5L, 1e6L, 1e7L, 1e8L, 1e9L, + 1e10L, 1e11L, 1e12L, 1e13L, 1e14L, 1e15L, 1e16L, 1e17L, 1e18L, 1e19L, + 1e20L, 1e21L, 1e22L, 1e23L, 1e24L, 1e25L, 1e26L, 1e27L, 1e28L, 1e29L, + 1e30L, 1e31L, 1e32L, 1e33L, 1e34L, 1e35L, 1e36L, 1e37L, 1e38L, 1e39L, + 1e40L, 1e41L, 1e42L, 1e43L, 1e44L, 1e45L, 1e46L, 1e47L, 1e48L}; + static constexpr int32_t EXACT_POWERS_OF_TEN = 48; + static constexpr int32_t DIGITS_IN_MANTISSA = 33; + static constexpr long double MAX_EXACT_INT = + 10384593717069655257060992658440191.0L; +}; +#elif defined(LIBC_TYPES_LONG_DOUBLE_IS_DOUBLE_DOUBLE) +// TODO: Add proper double double type support here, currently using constants +// for double since it should be safe. +template <> class ClingerConsts<long double> { +public: + static constexpr double POWERS_OF_TEN_ARRAY[] = { + 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11, + 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, 1e20, 1e21, 1e22}; + static constexpr int32_t EXACT_POWERS_OF_TEN = 22; + static constexpr int32_t DIGITS_IN_MANTISSA = 15; + static constexpr double MAX_EXACT_INT = 9007199254740991.0; +}; +#else +#error "Unknown long double type" +#endif + +// Take an exact mantissa and exponent and attempt to convert it using only +// exact floating point arithmetic. This only handles numbers with low +// exponents, but handles them quickly. This is an implementation of Clinger's +// Fast Path, as described above. +template <class T> +LIBC_INLINE cpp::optional<ExpandedFloat<T>> +clinger_fast_path(ExpandedFloat<T> init_num, + RoundDirection round = RoundDirection::Nearest) { + using FPBits = typename fputil::FPBits<T>; + using StorageType = typename FPBits::StorageType; + + StorageType mantissa = init_num.mantissa; + int32_t exp10 = init_num.exponent; + + if ((mantissa >> FPBits::FRACTION_LEN) > 0) { + return cpp::nullopt; + } + + FPBits result; + T float_mantissa; + if constexpr (is_big_int_v<StorageType> || sizeof(T) > sizeof(uint64_t)) { + float_mantissa = + (static_cast<T>(uint64_t(mantissa >> 64)) * static_cast<T>(0x1.0p64)) + + static_cast<T>(uint64_t(mantissa)); + } else { + float_mantissa = static_cast<T>(mantissa); + } + + if (exp10 == 0) { + result = FPBits(float_mantissa); + } + if (exp10 > 0) { + if (exp10 > ClingerConsts<T>::EXACT_POWERS_OF_TEN + + ClingerConsts<T>::DIGITS_IN_MANTISSA) { + return cpp::nullopt; + } + if (exp10 > ClingerConsts<T>::EXACT_POWERS_OF_TEN) { + float_mantissa = float_mantissa * + ClingerConsts<T>::POWERS_OF_TEN_ARRAY + [exp10 - ClingerConsts<T>::EXACT_POWERS_OF_TEN]; + exp10 = ClingerConsts<T>::EXACT_POWERS_OF_TEN; + } + if (float_mantissa > ClingerConsts<T>::MAX_EXACT_INT) { + return cpp::nullopt; + } + result = + FPBits(float_mantissa * ClingerConsts<T>::POWERS_OF_TEN_ARRAY[exp10]); + } else if (exp10 < 0) { + if (-exp10 > ClingerConsts<T>::EXACT_POWERS_OF_TEN) { + return cpp::nullopt; + } + result = + FPBits(float_mantissa / ClingerConsts<T>::POWERS_OF_TEN_ARRAY[-exp10]); + } + + // If the rounding mode is not nearest, then the sign of the number may affect + // the result. To make sure the rounding mode is respected properly, the + // calculation is redone with a negative result, and the rounding mode is used + // to select the correct result. + if (round != RoundDirection::Nearest) { + FPBits negative_result; + // I'm 99% sure this will break under fast math optimizations. + negative_result = FPBits((-float_mantissa) * + ClingerConsts<T>::POWERS_OF_TEN_ARRAY[exp10]); + + // If the results are equal, then we don't need to use the rounding mode. + if (result.get_val() != -negative_result.get_val()) { + FPBits lower_result; + FPBits higher_result; + + if (result.get_val() < -negative_result.get_val()) { + lower_result = result; + higher_result = negative_result; + } else { + lower_result = negative_result; + higher_result = result; + } + + if (round == RoundDirection::Up) { + result = higher_result; + } else { + result = lower_result; + } + } + } + + ExpandedFloat<T> output; + output.mantissa = result.get_explicit_mantissa(); + output.exponent = result.get_biased_exponent(); + return output; +} + +// The upper bound is the highest base-10 exponent that could possibly give a +// non-inf result for this size of float. The value is +// log10(2^(exponent bias)). +// The generic approximation uses the fact that log10(2^x) ~= x/3 +template <typename T> LIBC_INLINE constexpr int32_t get_upper_bound() { + return fputil::FPBits<T>::EXP_BIAS / 3; +} + +template <> LIBC_INLINE constexpr int32_t get_upper_bound<float>() { + return 39; +} + +template <> LIBC_INLINE constexpr int32_t get_upper_bound<double>() { + return 309; +} + +// The lower bound is the largest negative base-10 exponent that could possibly +// give a non-zero result for this size of float. The value is +// log10(2^(exponent bias + final mantissa width + intermediate mantissa width)) +// The intermediate mantissa is the integer that's been parsed from the string, +// and the final mantissa is the fractional part of the output number. A very +// low base 10 exponent with a very high intermediate mantissa can cancel each +// other out, and subnormal numbers allow for the result to be at the very low +// end of the final mantissa. +template <typename T> LIBC_INLINE constexpr int32_t get_lower_bound() { + using FPBits = typename fputil::FPBits<T>; + return -((FPBits::EXP_BIAS + + static_cast<int32_t>(FPBits::FRACTION_LEN + FPBits::STORAGE_LEN)) / + 3); +} + +template <> LIBC_INLINE constexpr int32_t get_lower_bound<float>() { + return -(39 + 6 + 10); +} + +template <> LIBC_INLINE constexpr int32_t get_lower_bound<double>() { + return -(309 + 15 + 20); +} + +// ----------------------------------------------------------------------------- +// **** WARNING **** +// This interface is shared with libc++, if you change this interface you need +// to update it in both libc and libc++. +// ----------------------------------------------------------------------------- +// Takes a mantissa and base 10 exponent and converts it into its closest +// floating point type T equivalient. First we try the Eisel-Lemire algorithm, +// then if that fails then we fall back to a more accurate algorithm for +// accuracy. The resulting mantissa and exponent are placed in outputMantissa +// and outputExp2. +template <class T> +LIBC_INLINE FloatConvertReturn<T> decimal_exp_to_float( + ExpandedFloat<T> init_num, bool truncated, RoundDirection round, + const char *__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; + + // 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 + // serving as a first pass. Some close numbers getting through is okay. + if (exp10 > get_upper_bound<T>()) { + output.num = {0, FPBits::MAX_BIASED_EXPONENT}; + output.error = ERANGE; + return output; + } + // If the exponent is too small even for a subnormal, return 0. + if (exp10 < get_lower_bound<T>()) { + output.num = {0, 0}; + output.error = ERANGE; + return output; + } + + // Clinger's Fast Path and Eisel-Lemire can't set errno, but they can fail. + // For this reason the "error" field in their return values is used to + // represent whether they've failed as opposed to the errno value. Any + // non-zero value represents a failure. + +#ifndef LIBC_COPT_STRTOFLOAT_DISABLE_CLINGER_FAST_PATH + if (!truncated) { + opt_output = clinger_fast_path<T>(init_num, round); + // If the algorithm succeeded the error will be 0, else it will be a + // non-zero number. + if (opt_output.has_value()) { + return {opt_output.value(), 0}; + } + } +#endif // LIBC_COPT_STRTOFLOAT_DISABLE_CLINGER_FAST_PATH + +#ifndef LIBC_COPT_STRTOFLOAT_DISABLE_EISEL_LEMIRE + // Try Eisel-Lemire + opt_output = eisel_lemire<T>(init_num, round); + if (opt_output.has_value()) { + if (!truncated) { + return {opt_output.value(), 0}; + } + // If the mantissa is truncated, then the result may be off by the LSB, so + // check if rounding the mantissa up changes the result. If not, then it's + // safe, else use the fallback. + auto second_output = eisel_lemire<T>({mantissa + 1, exp10}, round); + if (second_output.has_value()) { + if (opt_output->mantissa == second_output->mantissa && + opt_output->exponent == second_output->exponent) { + return {opt_output.value(), 0}; + } + } + } +#endif // LIBC_COPT_STRTOFLOAT_DISABLE_EISEL_LEMIRE + +#ifndef LIBC_COPT_STRTOFLOAT_DISABLE_SIMPLE_DECIMAL_CONVERSION + output = simple_decimal_conversion<T>(numStart, num_len, round); +#else +#warning "Simple decimal conversion is disabled, result may not be correct." +#endif // LIBC_COPT_STRTOFLOAT_DISABLE_SIMPLE_DECIMAL_CONVERSION + + return output; +} + +// ----------------------------------------------------------------------------- +// **** WARNING **** +// This interface is shared with libc++, if you change this interface you need +// to update it in both libc and libc++. +// ----------------------------------------------------------------------------- +// Takes a mantissa and base 2 exponent and converts it into its closest +// floating point type T equivalient. Since the exponent is already in the right +// form, this is mostly just shifting and rounding. This is used for hexadecimal +// numbers since a base 16 exponent multiplied by 4 is the base 2 exponent. +template <class T> +LIBC_INLINE FloatConvertReturn<T> binary_exp_to_float(ExpandedFloat<T> init_num, + bool truncated, + RoundDirection round) { + using FPBits = typename fputil::FPBits<T>; + using StorageType = typename FPBits::StorageType; + + StorageType mantissa = init_num.mantissa; + int32_t exp2 = init_num.exponent; + + FloatConvertReturn<T> output; + + // This is the number of leading zeroes a properly normalized float of type T + // should have. + constexpr int32_t INF_EXP = (1 << FPBits::EXP_LEN) - 1; + + // Normalization step 1: Bring the leading bit to the highest bit of + // StorageType. + uint32_t amount_to_shift_left = cpp::countl_zero<StorageType>(mantissa); + mantissa <<= amount_to_shift_left; + + // Keep exp2 representing the exponent of the lowest bit of StorageType. + exp2 -= amount_to_shift_left; + + // biased_exponent represents the biased exponent of the most significant bit. + int32_t biased_exponent = exp2 + FPBits::STORAGE_LEN + FPBits::EXP_BIAS - 1; + + // Handle numbers that're too large and get squashed to inf + if (biased_exponent >= INF_EXP) { + // This indicates an overflow, so we make the result INF and set errno. + output.num = {0, (1 << FPBits::EXP_LEN) - 1}; + output.error = ERANGE; + return output; + } + + uint32_t amount_to_shift_right = + FPBits::STORAGE_LEN - FPBits::FRACTION_LEN - 1; + + // Handle subnormals. + if (biased_exponent <= 0) { + amount_to_shift_right += 1 - biased_exponent; + biased_exponent = 0; + + if (amount_to_shift_right > FPBits::STORAGE_LEN) { + // Return 0 if the exponent is too small. + output.num = {0, 0}; + output.error = ERANGE; + return output; + } + } + + StorageType round_bit_mask = StorageType(1) << (amount_to_shift_right - 1); + StorageType sticky_mask = round_bit_mask - 1; + bool round_bit = static_cast<bool>(mantissa & round_bit_mask); + bool sticky_bit = static_cast<bool>(mantissa & sticky_mask) || truncated; + + if (amount_to_shift_right < FPBits::STORAGE_LEN) { + // Shift the mantissa and clear the implicit bit. + mantissa >>= amount_to_shift_right; + mantissa &= FPBits::FRACTION_MASK; + } else { + mantissa = 0; + } + bool least_significant_bit = static_cast<bool>(mantissa & StorageType(1)); + + // TODO: check that this rounding behavior is correct. + + if (round == RoundDirection::Nearest) { + // Perform rounding-to-nearest, tie-to-even. + if (round_bit && (least_significant_bit || sticky_bit)) { + ++mantissa; + } + } else if (round == RoundDirection::Up) { + if (round_bit || sticky_bit) { + ++mantissa; + } + } else /* (round == RoundDirection::Down)*/ { + if (round_bit && sticky_bit) { + ++mantissa; + } + } + + if (mantissa > FPBits::FRACTION_MASK) { + // Rounding causes the exponent to increase. + ++biased_exponent; + + if (biased_exponent == INF_EXP) { + output.error = ERANGE; + } + } + + if (biased_exponent == 0) { + output.error = ERANGE; + } + + output.num = {mantissa & FPBits::FRACTION_MASK, biased_exponent}; + return output; +} + +// checks if the next 4 characters of the string pointer are the start of a +// hexadecimal floating point number. Does not advance the string pointer. +LIBC_INLINE bool is_float_hex_start(const char *__restrict src, + const char decimalPoint) { + if (!(src[0] == '0' && tolower(src[1]) == 'x')) { + return false; + } + size_t first_digit = 2; + if (src[2] == decimalPoint) { + ++first_digit; + } + return isalnum(src[first_digit]) && b36_char_to_int(src[first_digit]) < 16; +} + +// Takes the start of a string representing a decimal float, as well as the +// local decimalPoint. It returns if it suceeded in parsing any digits, and if +// the return value is true then the outputs are pointer to the end of the +// number, and the mantissa and exponent for the closest float T representation. +// If the return value is false, then it is assumed that there is no number +// here. +template <class T> +LIBC_INLINE StrToNumResult<ExpandedFloat<T>> +decimal_string_to_float(const char *__restrict src, const char DECIMAL_POINT, + RoundDirection round) { + using FPBits = typename fputil::FPBits<T>; + using StorageType = typename FPBits::StorageType; + + constexpr uint32_t BASE = 10; + constexpr char EXPONENT_MARKER = 'e'; + + bool truncated = false; + bool seen_digit = false; + bool after_decimal = false; + StorageType mantissa = 0; + int32_t exponent = 0; + + size_t index = 0; + + StrToNumResult<ExpandedFloat<T>> output({0, 0}); + + // The goal for the first step of parsing is to convert the number in src to + // the format mantissa * (base ^ exponent) + + // The loop fills the mantissa with as many digits as it can hold + const StorageType bitstype_max_div_by_base = + cpp::numeric_limits<StorageType>::max() / BASE; + while (true) { + if (isdigit(src[index])) { + uint32_t digit = b36_char_to_int(src[index]); + seen_digit = true; + + if (mantissa < bitstype_max_div_by_base) { + mantissa = (mantissa * BASE) + digit; + if (after_decimal) { + --exponent; + } + } else { + if (digit > 0) + truncated = true; + if (!after_decimal) + ++exponent; + } + + ++index; + continue; + } + if (src[index] == DECIMAL_POINT) { + if (after_decimal) { + break; // this means that src[index] points to a second decimal point, + // ending the number. + } + after_decimal = true; + ++index; + continue; + } + // The character is neither a digit nor a decimal point. + break; + } + + if (!seen_digit) + return output; + + // TODO: When adding max length argument, handle the case of a trailing + // EXPONENT MARKER, see scanf for more details. + if (tolower(src[index]) == EXPONENT_MARKER) { + bool has_sign = false; + if (src[index + 1] == '+' || src[index + 1] == '-') { + has_sign = true; + } + if (isdigit(src[index + 1 + static_cast<size_t>(has_sign)])) { + ++index; + auto result = strtointeger<int32_t>(src + index, 10); + if (result.has_error()) + output.error = result.error; + int32_t add_to_exponent = result.value; + index += result.parsed_len; + + // Here we do this operation as int64 to avoid overflow. + int64_t temp_exponent = static_cast<int64_t>(exponent) + + static_cast<int64_t>(add_to_exponent); + + // If the result is in the valid range, then we use it. The valid range is + // also within the int32 range, so this prevents overflow issues. + if (temp_exponent > FPBits::MAX_BIASED_EXPONENT) { + exponent = FPBits::MAX_BIASED_EXPONENT; + } else if (temp_exponent < -FPBits::MAX_BIASED_EXPONENT) { + exponent = -FPBits::MAX_BIASED_EXPONENT; + } else { + exponent = static_cast<int32_t>(temp_exponent); + } + } + } + + output.parsed_len = index; + if (mantissa == 0) { // if we have a 0, then also 0 the exponent. + output.value = {0, 0}; + } else { + auto temp = + decimal_exp_to_float<T>({mantissa, exponent}, truncated, round, src); + output.value = temp.num; + output.error = temp.error; + } + return output; +} + +// Takes the start of a string representing a hexadecimal float, as well as the +// local decimal point. It returns if it suceeded in parsing any digits, and if +// the return value is true then the outputs are pointer to the end of the +// number, and the mantissa and exponent for the closest float T representation. +// If the return value is false, then it is assumed that there is no number +// here. +template <class T> +LIBC_INLINE StrToNumResult<ExpandedFloat<T>> +hexadecimal_string_to_float(const char *__restrict src, + const char DECIMAL_POINT, RoundDirection round) { + using FPBits = typename fputil::FPBits<T>; + using StorageType = typename FPBits::StorageType; + + constexpr uint32_t BASE = 16; + constexpr char EXPONENT_MARKER = 'p'; + + bool truncated = false; + bool seen_digit = false; + bool after_decimal = false; + StorageType mantissa = 0; + int32_t exponent = 0; + + size_t index = 0; + + StrToNumResult<ExpandedFloat<T>> output({0, 0}); + + // The goal for the first step of parsing is to convert the number in src to + // the format mantissa * (base ^ exponent) + + // The loop fills the mantissa with as many digits as it can hold + const StorageType bitstype_max_div_by_base = + cpp::numeric_limits<StorageType>::max() / BASE; + while (true) { + if (isalnum(src[index])) { + uint32_t digit = b36_char_to_int(src[index]); + if (digit < BASE) + seen_digit = true; + else + break; + + if (mantissa < bitstype_max_div_by_base) { + mantissa = (mantissa * BASE) + digit; + if (after_decimal) + --exponent; + } else { + if (digit > 0) + truncated = true; + if (!after_decimal) + ++exponent; + } + ++index; + continue; + } + if (src[index] == DECIMAL_POINT) { + if (after_decimal) { + break; // this means that src[index] points to a second decimal point, + // ending the number. + } + after_decimal = true; + ++index; + continue; + } + // The character is neither a hexadecimal digit nor a decimal point. + break; + } + + if (!seen_digit) + return output; + + // Convert the exponent from having a base of 16 to having a base of 2. + exponent *= 4; + + if (tolower(src[index]) == EXPONENT_MARKER) { + bool has_sign = false; + if (src[index + 1] == '+' || src[index + 1] == '-') { + has_sign = true; + } + if (isdigit(src[index + 1 + static_cast<size_t>(has_sign)])) { + ++index; + auto result = strtointeger<int32_t>(src + index, 10); + if (result.has_error()) + output.error = result.error; + + int32_t add_to_exponent = result.value; + index += result.parsed_len; + + // Here we do this operation as int64 to avoid overflow. + int64_t temp_exponent = static_cast<int64_t>(exponent) + + static_cast<int64_t>(add_to_exponent); + + // If the result is in the valid range, then we use it. The valid range is + // also within the int32 range, so this prevents overflow issues. + if (temp_exponent > FPBits::MAX_BIASED_EXPONENT) { + exponent = FPBits::MAX_BIASED_EXPONENT; + } else if (temp_exponent < -FPBits::MAX_BIASED_EXPONENT) { + exponent = -FPBits::MAX_BIASED_EXPONENT; + } else { + exponent = static_cast<int32_t>(temp_exponent); + } + } + } + output.parsed_len = index; + if (mantissa == 0) { // if we have a 0, then also 0 the exponent. + output.value.exponent = 0; + output.value.mantissa = 0; + } else { + auto temp = binary_exp_to_float<T>({mantissa, exponent}, truncated, round); + output.error = temp.error; + output.value = temp.num; + } + return output; +} + +template <class T> +LIBC_INLINE typename fputil::FPBits<T>::StorageType +nan_mantissa_from_ncharseq(const cpp::string_view ncharseq) { + using FPBits = typename fputil::FPBits<T>; + using StorageType = typename FPBits::StorageType; + + StorageType nan_mantissa = 0; + + if (ncharseq.data() != nullptr && isdigit(ncharseq[0])) { + StrToNumResult<StorageType> strtoint_result = + strtointeger<StorageType>(ncharseq.data(), 0); + if (!strtoint_result.has_error()) + nan_mantissa = strtoint_result.value; + + if (strtoint_result.parsed_len != static_cast<ptrdiff_t>(ncharseq.size())) + nan_mantissa = 0; + } + + return nan_mantissa; +} + +// Takes a pointer to a string and a pointer to a string pointer. This function +// is used as the backend for all of the string to float functions. +// TODO: Add src_len member to match strtointeger. +// TODO: Next, move from char* and length to string_view +template <class T> +LIBC_INLINE StrToNumResult<T> strtofloatingpoint(const char *__restrict src) { + using FPBits = typename fputil::FPBits<T>; + using StorageType = typename FPBits::StorageType; + + FPBits result = FPBits(); + bool seen_digit = false; + char sign = '+'; + + int error = 0; + + ptrdiff_t index = first_non_whitespace(src) - src; + + if (src[index] == '+' || src[index] == '-') { + sign = src[index]; + ++index; + } + + if (sign == '-') { + result.set_sign(Sign::NEG); + } + + static constexpr char DECIMAL_POINT = '.'; + static const char *inf_string = "infinity"; + static const char *nan_string = "nan"; + + if (isdigit(src[index]) || src[index] == DECIMAL_POINT) { // regular number + int base = 10; + if (is_float_hex_start(src + index, DECIMAL_POINT)) { + base = 16; + index += 2; + seen_digit = true; + } + + RoundDirection round_direction = RoundDirection::Nearest; + + switch (fputil::quick_get_round()) { + case FE_TONEAREST: + round_direction = RoundDirection::Nearest; + break; + case FE_UPWARD: + if (sign == '+') { + round_direction = RoundDirection::Up; + } else { + round_direction = RoundDirection::Down; + } + break; + case FE_DOWNWARD: + if (sign == '+') { + round_direction = RoundDirection::Down; + } else { + round_direction = RoundDirection::Up; + } + break; + case FE_TOWARDZERO: + round_direction = RoundDirection::Down; + break; + } + + StrToNumResult<ExpandedFloat<T>> parse_result({0, 0}); + if (base == 16) { + parse_result = hexadecimal_string_to_float<T>(src + index, DECIMAL_POINT, + round_direction); + } else { // base is 10 + parse_result = decimal_string_to_float<T>(src + index, DECIMAL_POINT, + round_direction); + } + seen_digit = parse_result.parsed_len != 0; + result.set_mantissa(parse_result.value.mantissa); + result.set_biased_exponent(parse_result.value.exponent); + index += parse_result.parsed_len; + error = parse_result.error; + } else if (tolower(src[index]) == 'n') { // NaN + if (tolower(src[index + 1]) == nan_string[1] && + tolower(src[index + 2]) == nan_string[2]) { + seen_digit = true; + index += 3; + StorageType nan_mantissa = 0; + // this handles the case of `NaN(n-character-sequence)`, where the + // n-character-sequence is made of 0 or more letters, numbers, or + // underscore characters in any order. + if (src[index] == '(') { + size_t left_paren = index; + ++index; + while (isalnum(src[index]) || src[index] == '_') + ++index; + if (src[index] == ')') { + ++index; + nan_mantissa = nan_mantissa_from_ncharseq<T>( + cpp::string_view(src + (left_paren + 1), index - left_paren - 2)); + } else { + index = left_paren; + } + } + result = FPBits(result.quiet_nan(result.sign(), nan_mantissa)); + } + } else if (tolower(src[index]) == 'i') { // INF + if (tolower(src[index + 1]) == inf_string[1] && + tolower(src[index + 2]) == inf_string[2]) { + seen_digit = true; + result = FPBits(result.inf(result.sign())); + if (tolower(src[index + 3]) == inf_string[3] && + tolower(src[index + 4]) == inf_string[4] && + tolower(src[index + 5]) == inf_string[5] && + tolower(src[index + 6]) == inf_string[6] && + tolower(src[index + 7]) == inf_string[7]) { + // if the string is "INFINITY" then consume 8 characters. + index += 8; + } else { + index += 3; + } + } + } + if (!seen_digit) { // If there is nothing to actually parse, then return 0. + return {T(0), 0, error}; + } + + // This function only does something if T is long double and the platform uses + // special 80 bit long doubles. Otherwise it should be inlined out. + set_implicit_bit<T>(result); + + return {result.get_val(), index, error}; +} + +template <class T> LIBC_INLINE StrToNumResult<T> strtonan(const char *arg) { + using FPBits = typename fputil::FPBits<T>; + using StorageType = typename FPBits::StorageType; + + LIBC_CRASH_ON_NULLPTR(arg); + + FPBits result; + int error = 0; + StorageType nan_mantissa = 0; + + ptrdiff_t index = 0; + while (isalnum(arg[index]) || arg[index] == '_') + ++index; + + if (arg[index] == '\0') + nan_mantissa = nan_mantissa_from_ncharseq<T>(cpp::string_view(arg, index)); + + result = FPBits::quiet_nan(Sign::POS, nan_mantissa); + return {result.get_val(), 0, error}; +} + +} // namespace internal +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_STR_TO_FLOAT_H diff --git a/lib/libcxx/libc/src/__support/str_to_integer.h b/lib/libcxx/libc/src/__support/str_to_integer.h new file mode 100644 index 0000000000..8e569e8a7f --- /dev/null +++ b/lib/libcxx/libc/src/__support/str_to_integer.h @@ -0,0 +1,169 @@ +//===-- String to integer conversion utils ----------------------*- 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 +// +//===----------------------------------------------------------------------===// + +// ----------------------------------------------------------------------------- +// **** WARNING **** +// This file is shared with libc++. You should also be careful when adding +// dependencies to this file, since it needs to build for all libc++ targets. +// ----------------------------------------------------------------------------- + +#ifndef LLVM_LIBC_SRC___SUPPORT_STR_TO_INTEGER_H +#define LLVM_LIBC_SRC___SUPPORT_STR_TO_INTEGER_H + +#include "src/__support/CPP/limits.h" +#include "src/__support/CPP/type_traits.h" +#include "src/__support/CPP/type_traits/make_unsigned.h" +#include "src/__support/big_int.h" +#include "src/__support/common.h" +#include "src/__support/ctype_utils.h" +#include "src/__support/macros/config.h" +#include "src/__support/str_to_num_result.h" +#include "src/__support/uint128.h" +#include "src/errno/libc_errno.h" // For ERANGE + +namespace LIBC_NAMESPACE_DECL { +namespace internal { + +// Returns a pointer to the first character in src that is not a whitespace +// character (as determined by isspace()) +// TODO: Change from returning a pointer to returning a length. +LIBC_INLINE const char * +first_non_whitespace(const char *__restrict src, + size_t src_len = cpp::numeric_limits<size_t>::max()) { + size_t src_cur = 0; + while (src_cur < src_len && internal::isspace(src[src_cur])) { + ++src_cur; + } + return src + src_cur; +} + +// checks if the next 3 characters of the string pointer are the start of a +// hexadecimal number. Does not advance the string pointer. +LIBC_INLINE bool +is_hex_start(const char *__restrict src, + size_t src_len = cpp::numeric_limits<size_t>::max()) { + if (src_len < 3) + return false; + return *src == '0' && tolower(*(src + 1)) == 'x' && isalnum(*(src + 2)) && + b36_char_to_int(*(src + 2)) < 16; +} + +// Takes the address of the string pointer and parses the base from the start of +// it. +LIBC_INLINE int infer_base(const char *__restrict src, size_t src_len) { + // A hexadecimal number is defined as "the prefix 0x or 0X followed by a + // sequence of the decimal digits and the letters a (or A) through f (or F) + // with values 10 through 15 respectively." (C standard 6.4.4.1) + if (is_hex_start(src, src_len)) + return 16; + // An octal number is defined as "the prefix 0 optionally followed by a + // sequence of the digits 0 through 7 only" (C standard 6.4.4.1) and so any + // number that starts with 0, including just 0, is an octal number. + if (src_len > 0 && src[0] == '0') + return 8; + // A decimal number is defined as beginning "with a nonzero digit and + // consist[ing] of a sequence of decimal digits." (C standard 6.4.4.1) + return 10; +} + +// ----------------------------------------------------------------------------- +// **** WARNING **** +// This interface is shared with libc++, if you change this interface you need +// to update it in both libc and libc++. +// ----------------------------------------------------------------------------- +// Takes a pointer to a string and the base to convert to. This function is used +// as the backend for all of the string to int functions. +template <class T> +LIBC_INLINE StrToNumResult<T> +strtointeger(const char *__restrict src, int base, + const size_t src_len = cpp::numeric_limits<size_t>::max()) { + using ResultType = make_integral_or_big_int_unsigned_t<T>; + + ResultType result = 0; + + bool is_number = false; + size_t src_cur = 0; + int error_val = 0; + + if (src_len == 0) + return {0, 0, 0}; + + if (base < 0 || base == 1 || base > 36) + return {0, 0, EINVAL}; + + src_cur = first_non_whitespace(src, src_len) - src; + + char result_sign = '+'; + if (src[src_cur] == '+' || src[src_cur] == '-') { + result_sign = src[src_cur]; + ++src_cur; + } + + if (base == 0) + base = infer_base(src + src_cur, src_len - src_cur); + + if (base == 16 && is_hex_start(src + src_cur, src_len - src_cur)) + src_cur = src_cur + 2; + + constexpr bool IS_UNSIGNED = cpp::is_unsigned_v<T>; + const bool is_positive = (result_sign == '+'); + + ResultType constexpr NEGATIVE_MAX = + !IS_UNSIGNED ? static_cast<ResultType>(cpp::numeric_limits<T>::max()) + 1 + : cpp::numeric_limits<T>::max(); + ResultType const abs_max = + (is_positive ? cpp::numeric_limits<T>::max() : NEGATIVE_MAX); + ResultType const abs_max_div_by_base = + static_cast<ResultType>(abs_max / base); + + while (src_cur < src_len && isalnum(src[src_cur])) { + int cur_digit = b36_char_to_int(src[src_cur]); + if (cur_digit >= base) + break; + + is_number = true; + ++src_cur; + + // If the number has already hit the maximum value for the current type then + // the result cannot change, but we still need to advance src to the end of + // the number. + if (result == abs_max) { + error_val = ERANGE; + continue; + } + + if (result > abs_max_div_by_base) { + result = abs_max; + error_val = ERANGE; + } else { + result = static_cast<ResultType>(result * base); + } + if (result > abs_max - cur_digit) { + result = abs_max; + error_val = ERANGE; + } else { + result = static_cast<ResultType>(result + cur_digit); + } + } + + ptrdiff_t str_len = is_number ? (src_cur) : 0; + + if (error_val == ERANGE) { + if (is_positive || IS_UNSIGNED) + return {cpp::numeric_limits<T>::max(), str_len, error_val}; + else // T is signed and there is a negative overflow + return {cpp::numeric_limits<T>::min(), str_len, error_val}; + } + + return {static_cast<T>(is_positive ? result : -result), str_len, error_val}; +} + +} // namespace internal +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_STR_TO_INTEGER_H diff --git a/lib/libcxx/libc/src/__support/str_to_num_result.h b/lib/libcxx/libc/src/__support/str_to_num_result.h new file mode 100644 index 0000000000..48c363c88f --- /dev/null +++ b/lib/libcxx/libc/src/__support/str_to_num_result.h @@ -0,0 +1,48 @@ +//===-- A data structure for str_to_number to return ------------*- 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 +// +//===----------------------------------------------------------------------===// + +// ----------------------------------------------------------------------------- +// **** WARNING **** +// This file is shared with libc++. You should also be careful when adding +// dependencies to this file, since it needs to build for all libc++ targets. +// ----------------------------------------------------------------------------- + +#ifndef LLVM_LIBC_SRC___SUPPORT_STR_TO_NUM_RESULT_H +#define LLVM_LIBC_SRC___SUPPORT_STR_TO_NUM_RESULT_H + +#include "src/__support/macros/attributes.h" // LIBC_INLINE +#include "src/__support/macros/config.h" + +#include <stddef.h> + +namespace LIBC_NAMESPACE_DECL { + +// ----------------------------------------------------------------------------- +// **** WARNING **** +// This interface is shared with libc++, if you change this interface you need +// to update it in both libc and libc++. +// ----------------------------------------------------------------------------- +template <typename T> struct StrToNumResult { + T value; + int error; + ptrdiff_t parsed_len; + + LIBC_INLINE constexpr StrToNumResult(T value) + : value(value), error(0), parsed_len(0) {} + LIBC_INLINE constexpr StrToNumResult(T value, ptrdiff_t parsed_len) + : value(value), error(0), parsed_len(parsed_len) {} + LIBC_INLINE constexpr StrToNumResult(T value, ptrdiff_t parsed_len, int error) + : value(value), error(error), parsed_len(parsed_len) {} + + LIBC_INLINE constexpr bool has_error() { return error != 0; } + + LIBC_INLINE constexpr operator T() { return value; } +}; +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_STR_TO_NUM_RESULT_H diff --git a/lib/libcxx/libc/src/__support/uint128.h b/lib/libcxx/libc/src/__support/uint128.h new file mode 100644 index 0000000000..722e79d080 --- /dev/null +++ b/lib/libcxx/libc/src/__support/uint128.h @@ -0,0 +1,23 @@ +//===-- 128-bit signed and unsigned int types -------------------*- 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_UINT128_H +#define LLVM_LIBC_SRC___SUPPORT_UINT128_H + +#include "big_int.h" +#include "src/__support/macros/properties/types.h" // LIBC_TYPES_HAS_INT128 + +#ifdef LIBC_TYPES_HAS_INT128 +using UInt128 = __uint128_t; +using Int128 = __int128_t; +#else +using UInt128 = LIBC_NAMESPACE::UInt<128>; +using Int128 = LIBC_NAMESPACE::Int<128>; +#endif // LIBC_TYPES_HAS_INT128 + +#endif // LLVM_LIBC_SRC___SUPPORT_UINT128_H diff --git a/lib/libcxx/libc/src/errno/libc_errno.h b/lib/libcxx/libc/src/errno/libc_errno.h new file mode 100644 index 0000000000..44ee271484 --- /dev/null +++ b/lib/libcxx/libc/src/errno/libc_errno.h @@ -0,0 +1,47 @@ +//===-- Implementation header for libc_errno --------------------*- 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_ERRNO_LIBC_ERRNO_H +#define LLVM_LIBC_SRC_ERRNO_LIBC_ERRNO_H + +#include "src/__support/macros/attributes.h" +#include "src/__support/macros/config.h" +#include "src/__support/macros/properties/architectures.h" + +#include "hdr/errno_macros.h" + +// This header is to be consumed by internal implementations, in which all of +// them should refer to `libc_errno` instead of using `errno` directly from +// <errno.h> header. + +// Unit and hermetic tests should: +// - #include "src/errno/libc_errno.h" +// - NOT #include <errno.h> +// - Only use `libc_errno` in the code +// - Depend on libc.src.errno.errno + +// Integration tests should: +// - NOT #include "src/errno/libc_errno.h" +// - #include <errno.h> +// - Use regular `errno` in the code +// - Still depend on libc.src.errno.errno + +namespace LIBC_NAMESPACE_DECL { + +extern "C" int *__llvm_libc_errno() noexcept; + +struct Errno { + void operator=(int); + operator int(); +}; + +extern Errno libc_errno; + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC_ERRNO_LIBC_ERRNO_H |
