brintos

brintos / llvm-project-archived public Read only

0
0
Text · 6.5 KiB · 67d241d Raw
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