Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/libc/src/__support/integer_literals.h
213766 views
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 *= 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.
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
182