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

source code of libc/src/__support/integer_literals.h