181 lines · c
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-exception6//7//===----------------------------------------------------------------------===//8// This set of user defined literals allows uniform constructions of constants9// up to 256 bits and also help with unit tests (EXPECT_EQ requires the same10// type for LHS and RHS).11//===----------------------------------------------------------------------===//12 13#ifndef LLVM_LIBC_SRC___SUPPORT_INTEGER_LITERALS_H14#define LLVM_LIBC_SRC___SUPPORT_INTEGER_LITERALS_H15 16#include "hdr/stdint_proxy.h" // uintxx_t17#include "src/__support/CPP/limits.h" // CHAR_BIT18#include "src/__support/ctype_utils.h"19#include "src/__support/macros/attributes.h" // LIBC_INLINE20#include "src/__support/macros/config.h"21#include "src/__support/uint128.h" // UInt12822#include <stddef.h> // size_t23 24namespace LIBC_NAMESPACE_DECL {25 26LIBC_INLINE constexpr uint8_t operator""_u8(unsigned long long value) {27 return static_cast<uint8_t>(value);28}29 30LIBC_INLINE constexpr uint16_t operator""_u16(unsigned long long value) {31 return static_cast<uint16_t>(value);32}33 34LIBC_INLINE constexpr uint32_t operator""_u32(unsigned long long value) {35 return static_cast<uint32_t>(value);36}37 38LIBC_INLINE constexpr uint64_t operator""_u64(unsigned long long value) {39 return static_cast<uint64_t>(value);40}41 42namespace internal {43 44// Creates a T by reading digits from an array.45template <typename T>46LIBC_INLINE constexpr T accumulate(int base, const uint8_t *digits,47 size_t size) {48 T value{};49 for (; size; ++digits, --size) {50 value *= static_cast<unsigned int>(base);51 value += *digits;52 }53 return value;54}55 56// A static buffer to hold the digits for a T.57template <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 362 // for the purpose of buffer allocation.63 LIBC_INLINE_VAR static constexpr size_t BITS_PER_DIGIT = base == 2 ? 164 : base == 10 ? 365 : base == 16 ? 466 : 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 the88 // compiler as it is not executable. This is preferable over `assert` that89 // 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 ExtInt99// where available).100template <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. For109// binary and hexadecimal formats we read digits by chunks of 64 bits and110// produce the BigInt internal representation direcly. For decimal numbers we111// go the slow path and use slower BigInt arithmetic.112template <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's121 // 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.140template <typename T>141LIBC_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 internal155 156LIBC_INLINE constexpr UInt<96> operator""_u96(const char *x) {157 return internal::parse_with_prefix<UInt<96>>(x);158}159 160LIBC_INLINE constexpr UInt128 operator""_u128(const char *x) {161 return internal::parse_with_prefix<UInt128>(x);162}163 164LIBC_INLINE constexpr auto operator""_u256(const char *x) {165 return internal::parse_with_prefix<UInt<256>>(x);166}167 168template <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_DECL179 180#endif // LLVM_LIBC_SRC___SUPPORT_INTEGER_LITERALS_H181