uniform_type_name.cc
Go to the documentation of this file.
2 
3 #include "cetlib/replace_all.h"
4 
5 #include <regex>
6 #include <string>
7 
8 namespace {
9  /// \fn reformat.
10  ///
11  /// \brief Reformat the input string according to the provided regex
12  /// and format string.
13  ///
14  /// \param[in,out] input The string to be manipulated.
15  ///
16  /// \param[in] exp The regular expression to be (repeatedly) applied.
17  ///
18  /// \param[format] format The specified format string for the
19  /// replacement.
20  void
21  reformat(std::string& input, std::regex const& exp, std::string const& format)
22  {
23  while (1) {
24  std::string const formatted = std::regex_replace(input, exp, format);
25  if (formatted == input) {
26  break;
27  } else {
28  input = formatted;
29  }
30  }
31  }
32 
33  /// \fn removeParameter.
34  ///
35  /// \brief Remove the specified paramter from the input string.
36  ///
37  /// \param[in,out] name The string from which the parameter should be
38  /// removed.
39  ///
40  /// \param[in] toRemove The parameter to remove from the
41  /// string. Include leading comma if appropriate and trailing open
42  /// angled bracket for template instantiations.
43  void
44  removeParameter(std::string& name, std::string const& toRemove)
45  {
46  auto const asize = toRemove.size();
47  auto const initDepth = (toRemove.back() == '<') ? 1 : 0;
48  if (asize == 0ul) {
49  return;
50  }
51  char const* const delimiters = "<>";
52  auto index = std::string::npos;
53  while ((index = name.find(toRemove)) != std::string::npos) {
54  int depth = initDepth;
55  auto inx = index + asize;
56  while ((inx = name.find_first_of(delimiters, inx)) != std::string::npos) {
57  if (name[inx] == '<') {
58  ++depth;
59  } else {
60  if (--depth == 0) {
61  name.erase(index, inx + 1 - index);
62  if (name[index] == ' ' && (index == 0 || name[index - 1] != '>')) {
63  name.erase(index, 1);
64  }
65  break;
66  }
67  }
68  ++inx;
69  }
70  }
71  }
72 
73  /// \fn constBeforeIdentifier.
74  ///
75  /// \brief Change all occurrences of "<type> const" in name to "const
76  /// <type>."
77  ///
78  /// \param[in,out] name The string to manipulate.
79  void
80  constBeforeIdentifier(std::string& name)
81  {
82  std::string const toBeMoved(" const");
83  auto const asize = toBeMoved.size();
84  auto index = std::string::npos;
85  while ((index = name.find(toBeMoved)) != std::string::npos) {
86  name.erase(index, asize);
87  int depth = 0;
88  for (std::string::size_type inx = index - 1; inx > 0; --inx) {
89  char const c = name[inx];
90  if (c == '>') {
91  ++depth;
92  } else if (depth > 0) {
93  if (c == '<') {
94  --depth;
95  }
96  } else if (c == '<' || c == ',') {
97  name.insert(inx + 1, "const ");
98  break;
99  }
100  }
101  }
102  }
103 
104  /// \fn translateInlineNamespace
105  ///
106  /// \brief Remove inlined namespace and apply Itanium abbreviations
107  ///
108  /// \param[in,out] name The directly demangled typename to translate
109  ///
110  /// Inlined namespaces prevent direct use of Itanium ABI compressions
111  /// so fully qualified typenames will be returned by any demangling.
112  /// For example, libc++'s inline namespace "std::__1::" means that
113  /// demangling a std::string argument will return
114  ///
115  /// std::__1::basic_string<char, std::char_traits<char>, std::allocator<char>
116  /// >
117  ///
118  /// instead of
119  ///
120  /// std::string
121  ///
122  /// which would be the case without inline namespaces.
123  ///
124  /// Canvas requires the abbreviations, so the demangled name must be
125  /// stripped of the inline namespace and any Itanium abbreviation
126  /// reapplied. Currently known inlined namespaces are:
127  ///
128  /// std::__1:: Clang/libc++
129  /// std::__cxx11:: GCC/libstdc++
130  ///
131  /// For further information on the Itanium ABI abbreviations, see
132  ///
133  /// http://mentorembedded.github.io/cxx-abi/abi.html#mangling-compression
134  ///
135  void
136  translateInlineNamespace(std::string& name)
137  {
138  // libc++/libstdc++ std::ABI_TAG -> std::
139  {
140  static std::regex const ns_regex("std::__(1|cxx11)::");
141  static std::string const ns_format("std::");
142  reformat(name, ns_regex, ns_format);
143  }
144 
145  // Apply Itanium abbreviations
146  // FIXME: If the need arises, may need to apply other abbreviations:
147  // http://mentorembedded.github.io/cxx-abi/abi.html#mangling-compression
149  name,
150  "std::basic_string<char, std::char_traits<char>, std::allocator<char> >",
151  "std::string");
153  name, "std::basic_string<char, std::char_traits<char> >", "std::string");
154  }
155 }
156 
159 {
160  using namespace std::string_literals;
161  // We must use the same conventions previously used by Reflex.
162  // The order is important.
163 
164  // Translate any inlined namespace
165  translateInlineNamespace(name);
166 
167  // We must change std::__cxx11:: -> std:: for all type names. This
168  // should not have implications for I/O because ROOT stores the data
169  // that STL objects represent rather than doing a "dumb serialization"
170  // of the class.
171  cet::replace_all(name, "std::__cxx11::"s, "std::"s);
172  // According to a report from Chris Jones, Apple Clang has a similar
173  // issue with std::__1.
174  cet::replace_all(name, "std::__1::"s, "std::"s);
175 
176  // No space after comma.
177  cet::replace_all(name, ", "s, ","s);
178  // No space before opening square bracket.
179  cet::replace_all(name, " ["s, "["s);
180  // Strip default allocator.
181  removeParameter(name, ",std::allocator<"s);
182  // Strip default comparator.
183  removeParameter(name, ",std::less<"s);
184  // Strip char traits.
185  removeParameter(name, ",std::char_traits<"s);
186  // std::basic_string<char> -> std::string
187  {
188  static std::regex const bs_regex("std::basic_string<char>\\s*"s);
189  reformat(name, bs_regex, "std::string"s);
190  }
191  // Put const qualifier before identifier.
192  constBeforeIdentifier(name);
193 
194  // No spaces between template brakets and arguments
195  // FIXME?: need a regex because just stripping the spaces
196  // can cause subsequent ">>" removal fail...
197  {
198  static std::regex const bk_regex("([_a-zA-Z0-9])( +)>");
199  static std::string const bk_format("$1>");
200  reformat(name, bk_regex, bk_format);
201  }
202 
203  // No consecutive '>'.
204  //
205  // FIXME: The first time we see a type with e.g. operator>> as a
206  // template argument, we could have a problem.
207  cet::replace_all(name, ">>"s, "> >"s);
208  // No u or l qualifiers for integers.
209  {
210  static std::regex const ul_regex("(.*[<,][0-9]+)[ul]l*([,>].*)"s);
211  reformat(name, ul_regex, "$1$2"s);
212  }
213  // For ROOT 6 and beyond.
214  cet::replace_all(name, "unsigned long long"s, "ULong64_t"s);
215  cet::replace_all(name, "long long"s, "Long64_t"s);
216  // Done.
217  return name;
218 }
static QCString name
Definition: declinfo.cpp:673
std::string string
Definition: nybbler.cc:12
static bool format(QChar::Decomposition tag, QString &str, int index, int len)
Definition: qstring.cpp:11496
bool replace_all(std::string &in, std::string const &from, std::string const &to)
Replace all occurrences of from in string with to.
Definition: replace_all.cc:4
std::string uniform_type_name(std::type_info const &tid)
static int input(void)
Definition: code.cpp:15695
static QCString * s
Definition: config.cpp:1042