//===-- User literal for unsigned 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 // //===----------------------------------------------------------------------===// // This set of user defined literals allows uniform constructions of constants // up to 256 bits and also help with unit tests (EXPECT_EQ requires the same // type for LHS and RHS). //===----------------------------------------------------------------------===// #ifndef LLVM_LIBC_SRC___SUPPORT_INTEGER_LITERALS_H #define LLVM_LIBC_SRC___SUPPORT_INTEGER_LITERALS_H #include "src/__support/CPP/limits.h" // CHAR_BIT #include "src/__support/ctype_utils.h" #include "src/__support/macros/attributes.h" // LIBC_INLINE #include "src/__support/macros/config.h" #include "src/__support/uint128.h" // UInt128 #include // size_t #include // uintxx_t namespace LIBC_NAMESPACE_DECL { LIBC_INLINE constexpr uint8_t operator""_u8(unsigned long long value) { return static_cast(value); } LIBC_INLINE constexpr uint16_t operator""_u16(unsigned long long value) { return static_cast(value); } LIBC_INLINE constexpr uint32_t operator""_u32(unsigned long long value) { return static_cast(value); } LIBC_INLINE constexpr uint64_t operator""_u64(unsigned long long value) { return static_cast(value); } namespace internal { // Creates a T by reading digits from an array. template LIBC_INLINE constexpr T accumulate(int base, const uint8_t *digits, size_t size) { T value{}; for (; size; ++digits, --size) { value *= base; value += *digits; } return value; } // A static buffer to hold the digits for a T. template struct DigitBuffer { static_assert(base == 2 || base == 10 || base == 16); // One character provides log2(base) bits. // Base 2 and 16 provide exactly one and four bits per character respectively. // For base 10, a character provides log2(10) ≈ 3.32... which we round to 3 // for the purpose of buffer allocation. LIBC_INLINE_VAR static constexpr size_t BITS_PER_DIGIT = base == 2 ? 1 : base == 10 ? 3 : base == 16 ? 4 : 0; LIBC_INLINE_VAR static constexpr size_t MAX_DIGITS = sizeof(T) * CHAR_BIT / BITS_PER_DIGIT; LIBC_INLINE_VAR static constexpr uint8_t INVALID_DIGIT = 255; uint8_t digits[MAX_DIGITS] = {}; size_t size = 0; constexpr DigitBuffer(const char *str) { for (; *str != '\0'; ++str) push(*str); } // Adds a single character to this buffer. LIBC_INLINE constexpr void push(char c) { if (c == '\'') return; // ' is valid but not taken into account. const int b36_val = internal::b36_char_to_int(c); const uint8_t value = static_cast( b36_val < base && (b36_val != 0 || c == '0') ? b36_val : INVALID_DIGIT); if (value == INVALID_DIGIT || size >= MAX_DIGITS) { // During constant evaluation `__builtin_unreachable` will halt the // compiler as it is not executable. This is preferable over `assert` that // will only trigger in debug mode. Also we can't use `static_assert` // because `value` and `size` are not constant. __builtin_unreachable(); // invalid or too many characters. } digits[size] = value; ++size; } }; // Generic implementation for native types (including __uint128_t or ExtInt // where available). template struct Parser { template LIBC_INLINE static constexpr T parse(const char *str) { const DigitBuffer buffer(str); return accumulate(base, buffer.digits, buffer.size); } }; // Specialization for UInt. // Because this code runs at compile time we try to make it efficient. For // binary and hexadecimal formats we read digits by chunks of 64 bits and // produce the BigInt internal representation direcly. For decimal numbers we // go the slow path and use slower BigInt arithmetic. template struct Parser> { using UIntT = UInt; template static constexpr UIntT parse(const char *str) { const DigitBuffer buffer(str); if constexpr (base == 10) { // Slow path, we sum and multiply BigInt for each digit. return accumulate(base, buffer.digits, buffer.size); } else { // Fast path, we consume blocks of WordType and creates the BigInt's // internal representation directly. using WordArrayT = decltype(UIntT::val); using WordType = typename WordArrayT::value_type; WordArrayT array = {}; size_t size = buffer.size; const uint8_t *digit_ptr = buffer.digits + size; for (size_t i = 0; i < array.size(); ++i) { constexpr size_t DIGITS = DigitBuffer::MAX_DIGITS; const size_t chunk = size > DIGITS ? DIGITS : size; digit_ptr -= chunk; size -= chunk; array[i] = accumulate(base, digit_ptr, chunk); } return UIntT(array); } } }; // Detects the base of the number and dispatches to the right implementation. template LIBC_INLINE constexpr T parse_with_prefix(const char *ptr) { using P = Parser; if (ptr == nullptr) return T(); if (ptr[0] == '0') { if (ptr[1] == 'b') return P::template parse<2>(ptr + 2); if (ptr[1] == 'x') return P::template parse<16>(ptr + 2); } return P::template parse<10>(ptr); } } // namespace internal LIBC_INLINE constexpr UInt<96> operator""_u96(const char *x) { return internal::parse_with_prefix>(x); } LIBC_INLINE constexpr UInt128 operator""_u128(const char *x) { return internal::parse_with_prefix(x); } LIBC_INLINE constexpr auto operator""_u256(const char *x) { return internal::parse_with_prefix>(x); } template LIBC_INLINE constexpr T parse_bigint(const char *ptr) { if (ptr == nullptr) return T(); if (ptr[0] == '-' || ptr[0] == '+') { auto positive = internal::parse_with_prefix(ptr + 1); return ptr[0] == '-' ? -positive : positive; } return internal::parse_with_prefix(ptr); } } // namespace LIBC_NAMESPACE_DECL #endif // LLVM_LIBC_SRC___SUPPORT_INTEGER_LITERALS_H