1 //===-- User literal for unsigned integers ----------------------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // This set of user defined literals allows uniform constructions of constants 9 // up to 256 bits and also help with unit tests (EXPECT_EQ requires the same 10 // type for LHS and RHS). 11 //===----------------------------------------------------------------------===// 12 13 #ifndef LLVM_LIBC_SRC___SUPPORT_INTEGER_LITERALS_H 14 #define LLVM_LIBC_SRC___SUPPORT_INTEGER_LITERALS_H 15 16 #include "src/__support/CPP/limits.h" // CHAR_BIT 17 #include "src/__support/ctype_utils.h" 18 #include "src/__support/macros/attributes.h" // LIBC_INLINE 19 #include "src/__support/macros/config.h" 20 #include "src/__support/uint128.h" // UInt128 21 #include <stddef.h> // size_t 22 #include <stdint.h> // uintxx_t 23 24 namespace LIBC_NAMESPACE_DECL { 25 26 LIBC_INLINE constexpr uint8_t operator""_u8(unsigned long long value) { 27 return static_cast<uint8_t>(value); 28 } 29 30 LIBC_INLINE constexpr uint16_t operator""_u16(unsigned long long value) { 31 return static_cast<uint16_t>(value); 32 } 33 34 LIBC_INLINE constexpr uint32_t operator""_u32(unsigned long long value) { 35 return static_cast<uint32_t>(value); 36 } 37 38 LIBC_INLINE constexpr uint64_t operator""_u64(unsigned long long value) { 39 return static_cast<uint64_t>(value); 40 } 41 42 namespace internal { 43 44 // Creates a T by reading digits from an array. 45 template <typename T> 46 LIBC_INLINE constexpr T accumulate(int base, const uint8_t *digits, 47 size_t size) { 48 T value{}; 49 for (; size; ++digits, --size) { 50 value *= base; 51 value += *digits; 52 } 53 return value; 54 } 55 56 // A static buffer to hold the digits for a T. 57 template <typename T, int base> struct DigitBuffer { 58 static_assert(base == 2 || base == 10 || base == 16); 59 // One character provides log2(base) bits. 60 // Base 2 and 16 provide exactly one and four bits per character respectively. 61 // For base 10, a character provides log2(10) ≈ 3.32... which we round to 3 62 // for the purpose of buffer allocation. 63 LIBC_INLINE_VAR static constexpr size_t BITS_PER_DIGIT = base == 2 ? 1 64 : base == 10 ? 3 65 : base == 16 ? 4 66 : 0; 67 LIBC_INLINE_VAR static constexpr size_t MAX_DIGITS = 68 sizeof(T) * CHAR_BIT / BITS_PER_DIGIT; 69 LIBC_INLINE_VAR static constexpr uint8_t INVALID_DIGIT = 255; 70 71 uint8_t digits[MAX_DIGITS] = {}; 72 size_t size = 0; 73 74 constexpr DigitBuffer(const char *str) { 75 for (; *str != '\0'; ++str) 76 push(*str); 77 } 78 79 // Adds a single character to this buffer. 80 LIBC_INLINE constexpr void push(char c) { 81 if (c == '\'') 82 return; // ' is valid but not taken into account. 83 const int b36_val = internal::b36_char_to_int(c); 84 const uint8_t value = static_cast<uint8_t>( 85 b36_val < base && (b36_val != 0 || c == '0') ? b36_val : INVALID_DIGIT); 86 if (value == INVALID_DIGIT || size >= MAX_DIGITS) { 87 // During constant evaluation `__builtin_unreachable` will halt the 88 // compiler as it is not executable. This is preferable over `assert` that 89 // will only trigger in debug mode. Also we can't use `static_assert` 90 // because `value` and `size` are not constant. 91 __builtin_unreachable(); // invalid or too many characters. 92 } 93 digits[size] = value; 94 ++size; 95 } 96 }; 97 98 // Generic implementation for native types (including __uint128_t or ExtInt 99 // where available). 100 template <typename T> struct Parser { 101 template <int base> LIBC_INLINE static constexpr T parse(const char *str) { 102 const DigitBuffer<T, base> buffer(str); 103 return accumulate<T>(base, buffer.digits, buffer.size); 104 } 105 }; 106 107 // Specialization for UInt<N>. 108 // Because this code runs at compile time we try to make it efficient. For 109 // binary and hexadecimal formats we read digits by chunks of 64 bits and 110 // produce the BigInt internal representation direcly. For decimal numbers we 111 // go the slow path and use slower BigInt arithmetic. 112 template <size_t N> struct Parser<LIBC_NAMESPACE::UInt<N>> { 113 using UIntT = UInt<N>; 114 template <int base> static constexpr UIntT parse(const char *str) { 115 const DigitBuffer<UIntT, base> buffer(str); 116 if constexpr (base == 10) { 117 // Slow path, we sum and multiply BigInt for each digit. 118 return accumulate<UIntT>(base, buffer.digits, buffer.size); 119 } else { 120 // Fast path, we consume blocks of WordType and creates the BigInt's 121 // internal representation directly. 122 using WordArrayT = decltype(UIntT::val); 123 using WordType = typename WordArrayT::value_type; 124 WordArrayT array = {}; 125 size_t size = buffer.size; 126 const uint8_t *digit_ptr = buffer.digits + size; 127 for (size_t i = 0; i < array.size(); ++i) { 128 constexpr size_t DIGITS = DigitBuffer<WordType, base>::MAX_DIGITS; 129 const size_t chunk = size > DIGITS ? DIGITS : size; 130 digit_ptr -= chunk; 131 size -= chunk; 132 array[i] = accumulate<WordType>(base, digit_ptr, chunk); 133 } 134 return UIntT(array); 135 } 136 } 137 }; 138 139 // Detects the base of the number and dispatches to the right implementation. 140 template <typename T> 141 LIBC_INLINE constexpr T parse_with_prefix(const char *ptr) { 142 using P = Parser<T>; 143 if (ptr == nullptr) 144 return T(); 145 if (ptr[0] == '0') { 146 if (ptr[1] == 'b') 147 return P::template parse<2>(ptr + 2); 148 if (ptr[1] == 'x') 149 return P::template parse<16>(ptr + 2); 150 } 151 return P::template parse<10>(ptr); 152 } 153 154 } // namespace internal 155 156 LIBC_INLINE constexpr UInt<96> operator""_u96(const char *x) { 157 return internal::parse_with_prefix<UInt<96>>(x); 158 } 159 160 LIBC_INLINE constexpr UInt128 operator""_u128(const char *x) { 161 return internal::parse_with_prefix<UInt128>(x); 162 } 163 164 LIBC_INLINE constexpr auto operator""_u256(const char *x) { 165 return internal::parse_with_prefix<UInt<256>>(x); 166 } 167 168 template <typename T> LIBC_INLINE constexpr T parse_bigint(const char *ptr) { 169 if (ptr == nullptr) 170 return T(); 171 if (ptr[0] == '-' || ptr[0] == '+') { 172 auto positive = internal::parse_with_prefix<T>(ptr + 1); 173 return ptr[0] == '-' ? -positive : positive; 174 } 175 return internal::parse_with_prefix<T>(ptr); 176 } 177 178 } // namespace LIBC_NAMESPACE_DECL 179 180 #endif // LLVM_LIBC_SRC___SUPPORT_INTEGER_LITERALS_H 181