Path: blob/main/contrib/llvm-project/libc/src/__support/integer_literals.h
213766 views
//===-- User literal for unsigned integers ----------------------*- C++ -*-===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7// This set of user defined literals allows uniform constructions of constants8// up to 256 bits and also help with unit tests (EXPECT_EQ requires the same9// type for LHS and RHS).10//===----------------------------------------------------------------------===//1112#ifndef LLVM_LIBC_SRC___SUPPORT_INTEGER_LITERALS_H13#define LLVM_LIBC_SRC___SUPPORT_INTEGER_LITERALS_H1415#include "src/__support/CPP/limits.h" // CHAR_BIT16#include "src/__support/ctype_utils.h"17#include "src/__support/macros/attributes.h" // LIBC_INLINE18#include "src/__support/macros/config.h"19#include "src/__support/uint128.h" // UInt12820#include <stddef.h> // size_t21#include <stdint.h> // uintxx_t2223namespace LIBC_NAMESPACE_DECL {2425LIBC_INLINE constexpr uint8_t operator""_u8(unsigned long long value) {26return static_cast<uint8_t>(value);27}2829LIBC_INLINE constexpr uint16_t operator""_u16(unsigned long long value) {30return static_cast<uint16_t>(value);31}3233LIBC_INLINE constexpr uint32_t operator""_u32(unsigned long long value) {34return static_cast<uint32_t>(value);35}3637LIBC_INLINE constexpr uint64_t operator""_u64(unsigned long long value) {38return static_cast<uint64_t>(value);39}4041namespace internal {4243// Creates a T by reading digits from an array.44template <typename T>45LIBC_INLINE constexpr T accumulate(int base, const uint8_t *digits,46size_t size) {47T value{};48for (; size; ++digits, --size) {49value *= static_cast<unsigned int>(base);50value += *digits;51}52return value;53}5455// A static buffer to hold the digits for a T.56template <typename T, int base> struct DigitBuffer {57static_assert(base == 2 || base == 10 || base == 16);58// One character provides log2(base) bits.59// Base 2 and 16 provide exactly one and four bits per character respectively.60// For base 10, a character provides log2(10) ≈ 3.32... which we round to 361// for the purpose of buffer allocation.62LIBC_INLINE_VAR static constexpr size_t BITS_PER_DIGIT = base == 2 ? 163: base == 10 ? 364: base == 16 ? 465: 0;66LIBC_INLINE_VAR static constexpr size_t MAX_DIGITS =67sizeof(T) * CHAR_BIT / BITS_PER_DIGIT;68LIBC_INLINE_VAR static constexpr uint8_t INVALID_DIGIT = 255;6970uint8_t digits[MAX_DIGITS] = {};71size_t size = 0;7273constexpr DigitBuffer(const char *str) {74for (; *str != '\0'; ++str)75push(*str);76}7778// Adds a single character to this buffer.79LIBC_INLINE constexpr void push(char c) {80if (c == '\'')81return; // ' is valid but not taken into account.82const int b36_val = internal::b36_char_to_int(c);83const uint8_t value = static_cast<uint8_t>(84b36_val < base && (b36_val != 0 || c == '0') ? b36_val : INVALID_DIGIT);85if (value == INVALID_DIGIT || size >= MAX_DIGITS) {86// During constant evaluation `__builtin_unreachable` will halt the87// compiler as it is not executable. This is preferable over `assert` that88// will only trigger in debug mode. Also we can't use `static_assert`89// because `value` and `size` are not constant.90__builtin_unreachable(); // invalid or too many characters.91}92digits[size] = value;93++size;94}95};9697// Generic implementation for native types (including __uint128_t or ExtInt98// where available).99template <typename T> struct Parser {100template <int base> LIBC_INLINE static constexpr T parse(const char *str) {101const DigitBuffer<T, base> buffer(str);102return accumulate<T>(base, buffer.digits, buffer.size);103}104};105106// Specialization for UInt<N>.107// Because this code runs at compile time we try to make it efficient. For108// binary and hexadecimal formats we read digits by chunks of 64 bits and109// produce the BigInt internal representation direcly. For decimal numbers we110// go the slow path and use slower BigInt arithmetic.111template <size_t N> struct Parser<LIBC_NAMESPACE::UInt<N>> {112using UIntT = UInt<N>;113template <int base> static constexpr UIntT parse(const char *str) {114const DigitBuffer<UIntT, base> buffer(str);115if constexpr (base == 10) {116// Slow path, we sum and multiply BigInt for each digit.117return accumulate<UIntT>(base, buffer.digits, buffer.size);118} else {119// Fast path, we consume blocks of WordType and creates the BigInt's120// internal representation directly.121using WordArrayT = decltype(UIntT::val);122using WordType = typename WordArrayT::value_type;123WordArrayT array = {};124size_t size = buffer.size;125const uint8_t *digit_ptr = buffer.digits + size;126for (size_t i = 0; i < array.size(); ++i) {127constexpr size_t DIGITS = DigitBuffer<WordType, base>::MAX_DIGITS;128const size_t chunk = size > DIGITS ? DIGITS : size;129digit_ptr -= chunk;130size -= chunk;131array[i] = accumulate<WordType>(base, digit_ptr, chunk);132}133return UIntT(array);134}135}136};137138// Detects the base of the number and dispatches to the right implementation.139template <typename T>140LIBC_INLINE constexpr T parse_with_prefix(const char *ptr) {141using P = Parser<T>;142if (ptr == nullptr)143return T();144if (ptr[0] == '0') {145if (ptr[1] == 'b')146return P::template parse<2>(ptr + 2);147if (ptr[1] == 'x')148return P::template parse<16>(ptr + 2);149}150return P::template parse<10>(ptr);151}152153} // namespace internal154155LIBC_INLINE constexpr UInt<96> operator""_u96(const char *x) {156return internal::parse_with_prefix<UInt<96>>(x);157}158159LIBC_INLINE constexpr UInt128 operator""_u128(const char *x) {160return internal::parse_with_prefix<UInt128>(x);161}162163LIBC_INLINE constexpr auto operator""_u256(const char *x) {164return internal::parse_with_prefix<UInt<256>>(x);165}166167template <typename T> LIBC_INLINE constexpr T parse_bigint(const char *ptr) {168if (ptr == nullptr)169return T();170if (ptr[0] == '-' || ptr[0] == '+') {171auto positive = internal::parse_with_prefix<T>(ptr + 1);172return ptr[0] == '-' ? -positive : positive;173}174return internal::parse_with_prefix<T>(ptr);175}176177} // namespace LIBC_NAMESPACE_DECL178179#endif // LLVM_LIBC_SRC___SUPPORT_INTEGER_LITERALS_H180181182