forked from RobotLocomotion/drake
-
Notifications
You must be signed in to change notification settings - Fork 0
/
nice_type_name.cc
132 lines (114 loc) · 4.93 KB
/
nice_type_name.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
/* Portions copyright (c) 2014 Stanford University and the Authors.
Authors: Chris Dembia, Michael Sherman
Licensed under the Apache License, Version 2.0 (the "License"); you may
not use this file except in compliance with the License. You may obtain a
copy of the License at http://www.apache.org/licenses/LICENSE-2.0. */
#include "drake/common/nice_type_name.h"
#include <algorithm>
#include <array>
#include <initializer_list>
#include <regex>
#include <string>
#include "drake/common/never_destroyed.h"
#include "drake/common/nice_type_name_override.h"
using std::string;
// __GNUG__ is defined both for gcc and clang. See:
// https://gcc.gnu.org/onlinedocs/libstdc++/libstdc++-html-USERS-4.3/a01696.html
#if defined(__GNUG__)
/* clang-format off */
#include <cxxabi.h>
#include <cstdlib>
/* clang-format on */
#endif
namespace drake {
// On gcc and clang typeid(T).name() returns an indecipherable mangled string
// that requires processing to become human readable. Microsoft returns a
// reasonable name directly.
string NiceTypeName::Demangle(const char* typeid_name) {
#if defined(__GNUG__)
int status = -100; // just in case it doesn't get set
char* ret = abi::__cxa_demangle(typeid_name, NULL, NULL, &status);
const char* const demangled_name = (status == 0) ? ret : typeid_name;
string demangled_string(demangled_name);
if (ret) std::free(ret);
return demangled_string;
#else
// On other platforms, we hope the typeid name is not mangled.
return typeid_name;
#endif
}
// Given a demangled string, attempt to canonicalize it for platform
// indpendence. We'll remove Microsoft's "class ", "struct ", etc.
// designations, and get rid of all unnecessary spaces.
string NiceTypeName::Canonicalize(const string& demangled) {
using SPair = std::pair<std::regex, string>;
using SPairList = std::initializer_list<SPair>;
// These are applied in this order.
static const never_destroyed<std::vector<SPair>> subs{SPairList{
// Remove unwanted keywords and following space. (\b is word boundary.)
SPair(std::regex("\\b(class|struct|enum|union) "), ""),
// Tidy up anonymous namespace.
SPair(std::regex("[`(]anonymous namespace[')]"), "(anonymous)"),
// Replace Microsoft __int64 with long long.
SPair(std::regex("\\b__int64\\b"), "long long"),
// Temporarily replace spaces we want to keep with "!". (\w is
// alphanumeric or underscore.)
SPair(std::regex("(\\w) (\\w)"), "$1!$2"),
SPair(std::regex(" "), ""), // Delete unwanted spaces.
// Some compilers throw in extra namespaces like "__1" or "__cxx11".
// Delete them.
SPair(std::regex("\\b__[[:alnum:]_]+::"), ""),
SPair(std::regex("!"), " "), // Restore wanted spaces.
// Recognize std::string's full name and abbreviate.
SPair(std::regex("\\bstd::basic_string<char,std::char_traits<char>,"
"std::allocator<char>>"),
"std::string"),
// Recognize Eigen types ...
// ... square matrices ...
SPair(std::regex("\\bEigen::Matrix<([^,<>]*),(-?\\d+),\\2,0,\\2,\\2>"),
"drake::Matrix$2<$1>"),
// ... vectors ...
SPair(std::regex("\\bEigen::Matrix<([^,<>]*),(-?\\d+),1,0,\\2,1>"),
"drake::Vector$2<$1>"),
// ... dynamic-size is "X" not "-1" ...
SPair(std::regex("drake::(Matrix|Vector)-1<"), "drake::$1X<"),
// ... for double, float, and int, prefer native Eigen spellings ...
SPair(std::regex("drake::(Vector|Matrix)(X|\\d+)"
"<((d)ouble|(f)loat|(i)nt)>"),
"Eigen::$1$2$4$5$6"),
// ... AutoDiff.
SPair(std::regex("Eigen::AutoDiffScalar<Eigen::VectorXd>"),
"drake::AutoDiffXd"),
// Recognize Identifier ...
// Change e.g., "drake::Identifier<drake::package::FooTag>" to
// "drake::package::FooId".
SPair(std::regex("\\bdrake::Identifier<([^>]*)Tag>"), "$1Id"),
}};
string canonical(demangled);
for (const auto& sp : subs.access()) {
canonical = std::regex_replace(canonical, sp.first, sp.second);
}
return canonical;
}
string NiceTypeName::RemoveNamespaces(const string& canonical) {
// Removes everything up to and including the last "::" that isn't part of a
// template argument. If the string ends with "::", returns the original
// string unprocessed. We are depending on the fact that namespaces can't be
// templatized to avoid bad behavior for template types where the template
// argument might include namespaces (those should not be touched).
static const never_destroyed<std::regex> regex{"^[^<>]*::"};
const std::string no_namespace =
std::regex_replace(canonical, regex.access(), "");
return no_namespace.empty() ? canonical : no_namespace;
}
std::string NiceTypeName::GetWithPossibleOverride(
const void* ptr, const std::type_info& info) {
internal::NiceTypeNamePtrOverride ptr_override =
internal::GetNiceTypeNamePtrOverride();
if (ptr_override) {
return ptr_override(internal::type_erased_ptr{ptr, info});
} else {
return Get(info);
}
}
} // namespace drake