1 // Copyright David Abrahams 2001.
2 // Distributed under the Boost Software License, Version 1.0. (See
3 // accompanying file LICENSE_1_0.txt or copy at
4 // http://www.boost.org/LICENSE_1_0.txt)
5 
6 #include <boost/python/type_id.hpp>
7 #include <boost/python/detail/decorated_type_id.hpp>
8 #include <utility>
9 #include <vector>
10 #include <algorithm>
11 #include <memory>
12 #include <cstdlib>
13 #include <cstring>
14 
15 #if defined(__QNXNTO__)
16 # include <ostream>
17 #else                       /*  defined(__QNXNTO__) */
18 
19 #if !defined(__GNUC__) || __GNUC__ >= 3 || __SGI_STL_PORT || __EDG_VERSION__
20 # include <ostream>
21 #else
22 # include <ostream.h>
23 #endif
24 
25 #  ifdef BOOST_PYTHON_HAVE_GCC_CP_DEMANGLE
26 #   if defined(__GNUC__) &&  __GNUC__ >= 3
27 
28 // http://lists.debian.org/debian-gcc/2003/09/msg00055.html notes
29 // that, in cxxabi.h of gcc-3.x for x < 4, this type is used before it
30 // is declared.
31 #    if __GNUC__ == 3 && __GNUC_MINOR__ < 4
32 class __class_type_info;
33 #    endif
34 
35 #    include <cxxabi.h>
36 #   endif
37 #  endif
38 #endif                      /*  defined(__QNXNTO__) */
39 
40 namespace boost { namespace python {
41 
42 #  ifdef BOOST_PYTHON_HAVE_GCC_CP_DEMANGLE
43 
44 #   if defined(__QNXNTO__)
45 namespace cxxabi {
46 extern "C" char* __cxa_demangle(char const*, char*, std::size_t*, int*);
47 }
48 #   else                    /*  defined(__QNXNTO__) */
49 
50 #    ifdef __GNUC__
51 #     if __GNUC__ < 3
52 
53 namespace cxxabi = :: ;
54 extern "C" char* __cxa_demangle(char const*, char*, std::size_t*, int*);
55 #     else
56 
57 namespace cxxabi = ::abi;       // GCC 3.1 and later
58 
59 #      if __GNUC__ == 3 && __GNUC_MINOR__ == 0
60 namespace abi
61 {
62   extern "C" char* __cxa_demangle(char const*, char*, std::size_t*, int*);
63 }
64 #      endif            /*  __GNUC__ == 3 && __GNUC_MINOR__ == 0    */
65 #     endif             /*  __GNUC__ < 3                            */
66 #    endif              /*  __GNUC__                                */
67 #   endif               /*  defined(__QNXNTO__)                     */
68 
69 namespace
70 {
71   struct compare_first_cstring
72   {
73       template <class T>
operator ()boost::python::__anonb1090f500111::compare_first_cstring74       bool operator()(T const& x, T const& y)
75       {
76           return std::strcmp(x.first,y.first) < 0;
77       }
78   };
79 
80   struct free_mem
81   {
free_memboost::python::__anonb1090f500111::free_mem82       free_mem(char*p)
83           : p(p) {}
84 
~free_memboost::python::__anonb1090f500111::free_mem85       ~free_mem()
86       {
87           std::free(p);
88       }
89       char* p;
90   };
91 }
92 
cxxabi_cxa_demangle_is_broken()93 bool cxxabi_cxa_demangle_is_broken()
94 {
95     static bool was_tested = false;
96     static bool is_broken = false;
97     if (!was_tested) {
98         int status;
99         free_mem keeper(cxxabi::__cxa_demangle("b", 0, 0, &status));
100         was_tested = true;
101         if (status == -2 || strcmp(keeper.p, "bool") != 0) {
102           is_broken = true;
103         }
104     }
105     return is_broken;
106 }
107 
108 namespace detail
109 {
gcc_demangle(char const * mangled)110   BOOST_PYTHON_DECL char const* gcc_demangle(char const* mangled)
111   {
112       typedef std::vector<
113           std::pair<char const*, char const*>
114       > mangling_map;
115 
116       static mangling_map demangler;
117       mangling_map::iterator p
118           = std::lower_bound(
119               demangler.begin(), demangler.end()
120             , std::make_pair(mangled, (char const*)0)
121             , compare_first_cstring());
122 
123       if (p == demangler.end() || strcmp(p->first, mangled))
124       {
125           int status;
126           free_mem keeper(
127               cxxabi::__cxa_demangle(mangled, 0, 0, &status)
128               );
129 
130           assert(status != -3); // invalid argument error
131 
132           if (status == -1)
133           {
134               throw std::bad_alloc();
135           }
136           else
137           {
138               char const* demangled
139                 = status == -2
140                   // Invalid mangled name.  Best we can do is to
141                   // return it intact.
142                   ? mangled
143                   : keeper.p;
144 
145               // Ult Mundane, 2005 Aug 17
146               // Contributed under the Boost Software License, Version 1.0.
147               // (See accompanying file LICENSE_1_0.txt or copy at
148               // http://www.boost.org/LICENSE_1_0.txt)
149               // The __cxa_demangle function is supposed to translate
150               // builtin types from their one-character mangled names,
151               // but it doesn't in gcc 3.3.5 and gcc 3.4.x.
152               if (cxxabi_cxa_demangle_is_broken()
153                   && status == -2 && strlen(mangled) == 1)
154               {
155                   // list from
156                   // http://www.codesourcery.com/cxx-abi/abi.html
157                   switch (mangled[0])
158                   {
159                       case 'v': demangled = "void"; break;
160                       case 'w': demangled = "wchar_t"; break;
161                       case 'b': demangled = "bool"; break;
162                       case 'c': demangled = "char"; break;
163                       case 'a': demangled = "signed char"; break;
164                       case 'h': demangled = "unsigned char"; break;
165                       case 's': demangled = "short"; break;
166                       case 't': demangled = "unsigned short"; break;
167                       case 'i': demangled = "int"; break;
168                       case 'j': demangled = "unsigned int"; break;
169                       case 'l': demangled = "long"; break;
170                       case 'm': demangled = "unsigned long"; break;
171                       case 'x': demangled = "long long"; break;
172                       case 'y': demangled = "unsigned long long"; break;
173                       case 'n': demangled = "__int128"; break;
174                       case 'o': demangled = "unsigned __int128"; break;
175                       case 'f': demangled = "float"; break;
176                       case 'd': demangled = "double"; break;
177                       case 'e': demangled = "long double"; break;
178                       case 'g': demangled = "__float128"; break;
179                       case 'z': demangled = "..."; break;
180                   }
181               }
182 
183               p = demangler.insert(p, std::make_pair(mangled, demangled));
184               keeper.p = 0;
185           }
186       }
187 
188       return p->second;
189   }
190 }
191 #  endif
192 
operator <<(std::ostream & os,type_info const & x)193 BOOST_PYTHON_DECL std::ostream& operator<<(std::ostream& os, type_info const& x)
194 {
195     return os << x.name();
196 }
197 
198 namespace detail
199 {
operator <<(std::ostream & os,detail::decorated_type_info const & x)200   BOOST_PYTHON_DECL std::ostream& operator<<(std::ostream& os, detail::decorated_type_info const& x)
201   {
202       os << x.m_base_type;
203       if (x.m_decoration & decorated_type_info::const_)
204           os << " const";
205       if (x.m_decoration & decorated_type_info::volatile_)
206           os << " volatile";
207       if (x.m_decoration & decorated_type_info::reference)
208           os << "&";
209       return os;
210   }
211 }
212 }} // namespace boost::python::converter
213