xref: /llvm-project/libc/src/__support/integer_literals.h (revision a0c4f854cad2b97e44a1b58dc1fd982e1c4d60f3)
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/ctype_utils.h"
18 #include "src/__support/macros/attributes.h" // LIBC_INLINE
19 #include "src/__support/macros/config.h"
20 #include "src/__support/uint128.h" // UInt128
21 #include <stddef.h>                // size_t
22 #include <stdint.h>                // uintxx_t
23 
24 namespace LIBC_NAMESPACE_DECL {
25 
26 LIBC_INLINE constexpr uint8_t operator""_u8(unsigned long long value) {
27   return static_cast<uint8_t>(value);
28 }
29 
30 LIBC_INLINE constexpr uint16_t operator""_u16(unsigned long long value) {
31   return static_cast<uint16_t>(value);
32 }
33 
34 LIBC_INLINE constexpr uint32_t operator""_u32(unsigned long long value) {
35   return static_cast<uint32_t>(value);
36 }
37 
38 LIBC_INLINE constexpr uint64_t operator""_u64(unsigned long long value) {
39   return static_cast<uint64_t>(value);
40 }
41 
42 namespace internal {
43 
44 // Creates a T by reading digits from an array.
45 template <typename T>
46 LIBC_INLINE constexpr T accumulate(int base, const uint8_t *digits,
47                                    size_t size) {
48   T value{};
49   for (; size; ++digits, --size) {
50     value *= base;
51     value += *digits;
52   }
53   return value;
54 }
55 
56 // A static buffer to hold the digits for a T.
57 template <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 3
62   // for the purpose of buffer allocation.
63   LIBC_INLINE_VAR static constexpr size_t BITS_PER_DIGIT = base == 2    ? 1
64                                                            : base == 10 ? 3
65                                                            : base == 16 ? 4
66                                                                         : 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 the
88       // compiler as it is not executable. This is preferable over `assert` that
89       // 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 ExtInt
99 // where available).
100 template <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. For
109 // binary and hexadecimal formats we read digits by chunks of 64 bits and
110 // produce the BigInt internal representation direcly. For decimal numbers we
111 // go the slow path and use slower BigInt arithmetic.
112 template <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's
121       // 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.
140 template <typename T>
141 LIBC_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 internal
155 
156 LIBC_INLINE constexpr UInt<96> operator""_u96(const char *x) {
157   return internal::parse_with_prefix<UInt<96>>(x);
158 }
159 
160 LIBC_INLINE constexpr UInt128 operator""_u128(const char *x) {
161   return internal::parse_with_prefix<UInt128>(x);
162 }
163 
164 LIBC_INLINE constexpr auto operator""_u256(const char *x) {
165   return internal::parse_with_prefix<UInt<256>>(x);
166 }
167 
168 template <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_DECL
179 
180 #endif // LLVM_LIBC_SRC___SUPPORT_INTEGER_LITERALS_H
181