12#include "../microfmt.hpp"
28 constexpr explicit itanium_demangler(microfmt::string_view mangled) noexcept : src_(mangled), pos_(0) {}
36 if (!detail::starts_with(src_,
"_Z")) {
43 if (match_prefix(
"TV")) {
44 out.write(
"vtable for ");
45 return parse_type(out);
47 if (match_prefix(
"TT")) {
48 out.write(
"VTT for ");
49 return parse_type(out);
51 if (match_prefix(
"TI")) {
52 out.write(
"typeinfo for ");
53 return parse_type(out);
55 if (match_prefix(
"TS")) {
56 out.write(
"typeinfo name for ");
57 return parse_type(out);
61 return parse_encoding(out);
78 microfmt::string_view src_;
82 static constexpr size_t kMaxRecursionDepth = 16;
89 [[nodiscard]]
constexpr bool eof() const noexcept {
return pos_ >= src_.size(); }
93 [[nodiscard]]
constexpr char peek() const noexcept {
return eof() ?
'\0' : src_[pos_]; }
97 constexpr char get() noexcept {
return eof() ?
'\0' : src_[pos_++]; }
102 constexpr bool match(
char c)
noexcept {
113 constexpr bool match_prefix(microfmt::string_view p)
noexcept {
114 if (detail::starts_with(src_.substr(pos_), p)) {
126 RELOCO_BEGIN_UNSAFE_CODE
127 bool parse_number(
size_t &val)
noexcept {
128 if (eof() || peek() <
'0' || peek() >
'9')
131 while (!eof() && peek() >=
'0' && peek() <=
'9') {
132 val = val * 10 +
static_cast<size_t>(get() -
'0');
141 bool parse_encoding(
const sink &out)
noexcept {
142 if (!parse_name(out))
146 if (!eof() && peek() !=
'E') {
147 if (peek() ==
'v' && (pos_ + 1 == src_.size() || src_[pos_ + 1] ==
'E')) {
153 while (!eof() && peek() !=
'E') {
157 if (!parse_type(out))
169 bool parse_name(
const sink &out)
noexcept {
170 if (depth_++ > kMaxRecursionDepth)
175 ok = parse_nested_name(out);
176 }
else if (match(
'S')) {
177 ok = parse_substitution(out);
178 if (ok && match(
'I')) {
179 ok = parse_template_args(out);
182 ok = parse_unqualified_name(out);
183 if (ok && match(
'I')) {
184 ok = parse_template_args(out);
195 bool parse_template_args(
const sink &out)
noexcept {
198 while (!eof() && peek() !=
'E') {
202 if (!parse_type(out))
212 bool parse_nested_name(
const sink &out)
noexcept {
214 while (!eof() && peek() !=
'E') {
216 if (peek() ==
'r' || peek() ==
'V' || peek() ==
'K') {
222 if (!parse_template_args(out))
232 if (!parse_substitution(out))
234 }
else if (!parse_unqualified_name(out)) {
245 bool parse_unqualified_name(
const sink &out)
noexcept {
246 if (peek() >=
'0' && peek() <=
'9') {
248 if (!parse_number(len))
250 if (pos_ + len > src_.size())
252 out.write(src_.substr(pos_, len));
258 if (match_prefix(
"C1") || match_prefix(
"C2") || match_prefix(
"C3")) {
259 out.write(
"{constructor}");
262 if (match_prefix(
"D1") || match_prefix(
"D2") || match_prefix(
"D0")) {
263 out.write(
"~{destructor}");
268 if (match_prefix(
"nw")) {
269 out.write(
"operator new");
272 if (match_prefix(
"dl")) {
273 out.write(
"operator delete");
276 if (match_prefix(
"na")) {
277 out.write(
"operator new[]");
280 if (match_prefix(
"da")) {
281 out.write(
"operator delete[]");
284 if (match_prefix(
"pl")) {
285 out.write(
"operator+");
288 if (match_prefix(
"mi")) {
289 out.write(
"operator-");
292 if (match_prefix(
"ml")) {
293 out.write(
"operator*");
296 if (match_prefix(
"dv")) {
297 out.write(
"operator/");
300 if (match_prefix(
"eq")) {
301 out.write(
"operator==");
304 if (match_prefix(
"ne")) {
305 out.write(
"operator!=");
308 if (match_prefix(
"ix")) {
309 out.write(
"operator[]");
312 if (match_prefix(
"cl")) {
313 out.write(
"operator()");
323 bool parse_substitution(
const sink &out)
noexcept {
327 return parse_unqualified_name(out);
330 out.write(
"std::allocator");
334 out.write(
"std::basic_string");
338 out.write(
"std::string");
342 out.write(
"std::istream");
346 out.write(
"std::ostream");
350 out.write(
"std::iostream");
360 while (!eof() && peek() !=
'_') {
371 bool parse_type(
const sink &out)
noexcept {
372 if (depth_++ > kMaxRecursionDepth)
377 const bool ok = parse_type(out);
383 const bool ok = parse_type(out);
389 const bool ok = parse_type(out);
395 const bool ok = parse_type(out);
401 const bool ok = parse_type(out);
402 out.write(
" volatile");
416 out.write(
"wchar_t");
431 out.write(
"signed char");
436 out.write(
"unsigned char");
446 out.write(
"unsigned short");
456 out.write(
"unsigned int");
466 out.write(
"unsigned long");
471 out.write(
"long long");
476 out.write(
"unsigned long long");
491 out.write(
"long double");
504 const bool ok = parse_name(out);
Definition microfmt.hpp:881
Zero-allocation Itanium (GCC/Clang) name demangler.
Definition demangle.hpp:22
constexpr itanium_demangler(microfmt::string_view mangled) noexcept
Constructs a demangler over an Itanium-mangled symbol.
Definition demangle.hpp:28
bool demangle_to(const sink &out) noexcept
Demangles the symbol into the sink.
Definition demangle.hpp:35
static void format_symbol(microfmt::string_view sym, const sink &out) noexcept
Demangles a symbol, falling back to the raw input on failure.
Definition demangle.hpp:69
#define MICROFMT_API_CLASS
Definition compat.hpp:181
reloco::sink sink
Type-erased, zero-allocation output sink.
Definition microfmt.hpp:46
constexpr auto as_demangled(microfmt::string_view sym) noexcept
Wraps a symbol for demangled formatting.
Definition demangle.hpp:523
RELOCO_END_UNSAFE_CODE
Definition remote_object.hpp:132
Formattable view over a demangled symbol.
Definition demangle.hpp:513
microfmt::string_view symbol
Mangled symbol.
Definition demangle.hpp:515