blob: c6a8bf7a04e7379f9d29e5ba0e3498fe4637bdd1 [file] [log] [blame]
// Copyright David Abrahams 2001.
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include <boost/python/type_id.hpp>
#include <boost/python/detail/decorated_type_id.hpp>
#include <utility>
#include <vector>
#include <algorithm>
#include <memory>
#include <cstdlib>
#include <cstring>
#if defined(__QNXNTO__)
# include <ostream>
#else /* defined(__QNXNTO__) */
#if !defined(__GNUC__) || __GNUC__ >= 3 || __SGI_STL_PORT || __EDG_VERSION__
# include <ostream>
#else
# include <ostream.h>
#endif
# ifdef BOOST_PYTHON_HAVE_GCC_CP_DEMANGLE
# if defined(__GNUC__) && __GNUC__ >= 3
// http://lists.debian.org/debian-gcc/2003/09/msg00055.html notes
// that, in cxxabi.h of gcc-3.x for x < 4, this type is used before it
// is declared.
# if __GNUC__ == 3 && __GNUC_MINOR__ < 4
class __class_type_info;
# endif
# include <cxxabi.h>
# endif
# endif
#endif /* defined(__QNXNTO__) */
namespace boost { namespace python {
# ifdef BOOST_PYTHON_HAVE_GCC_CP_DEMANGLE
# if defined(__QNXNTO__)
namespace cxxabi {
extern "C" char* __cxa_demangle(char const*, char*, std::size_t*, int*);
}
# else /* defined(__QNXNTO__) */
# ifdef __GNUC__
# if __GNUC__ < 3
namespace cxxabi = :: ;
extern "C" char* __cxa_demangle(char const*, char*, std::size_t*, int*);
# else
namespace cxxabi = ::abi; // GCC 3.1 and later
# if __GNUC__ == 3 && __GNUC_MINOR__ == 0
namespace abi
{
extern "C" char* __cxa_demangle(char const*, char*, std::size_t*, int*);
}
# endif /* __GNUC__ == 3 && __GNUC_MINOR__ == 0 */
# endif /* __GNUC__ < 3 */
# endif /* __GNUC__ */
# endif /* defined(__QNXNTO__) */
namespace
{
struct compare_first_cstring
{
template <class T>
bool operator()(T const& x, T const& y)
{
return std::strcmp(x.first,y.first) < 0;
}
};
struct free_mem
{
free_mem(char*p)
: p(p) {}
~free_mem()
{
std::free(p);
}
char* p;
};
}
bool cxxabi_cxa_demangle_is_broken()
{
static bool was_tested = false;
static bool is_broken = false;
if (!was_tested) {
int status;
free_mem keeper(cxxabi::__cxa_demangle("b", 0, 0, &status));
was_tested = true;
if (status == -2 || strcmp(keeper.p, "bool") != 0) {
is_broken = true;
}
}
return is_broken;
}
namespace detail
{
BOOST_PYTHON_DECL char const* gcc_demangle(char const* mangled)
{
typedef std::vector<
std::pair<char const*, char const*>
> mangling_map;
static mangling_map demangler;
mangling_map::iterator p
= std::lower_bound(
demangler.begin(), demangler.end()
, std::make_pair(mangled, (char const*)0)
, compare_first_cstring());
if (p == demangler.end() || strcmp(p->first, mangled))
{
int status;
free_mem keeper(
cxxabi::__cxa_demangle(mangled, 0, 0, &status)
);
assert(status != -3); // invalid argument error
if (status == -1)
{
throw std::bad_alloc();
}
else
{
char const* demangled
= status == -2
// Invalid mangled name. Best we can do is to
// return it intact.
? mangled
: keeper.p;
// Ult Mundane, 2005 Aug 17
// Contributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
// The __cxa_demangle function is supposed to translate
// builtin types from their one-character mangled names,
// but it doesn't in gcc 3.3.5 and gcc 3.4.x.
if (cxxabi_cxa_demangle_is_broken()
&& status == -2 && strlen(mangled) == 1)
{
// list from
// http://www.codesourcery.com/cxx-abi/abi.html
switch (mangled[0])
{
case 'v': demangled = "void"; break;
case 'w': demangled = "wchar_t"; break;
case 'b': demangled = "bool"; break;
case 'c': demangled = "char"; break;
case 'a': demangled = "signed char"; break;
case 'h': demangled = "unsigned char"; break;
case 's': demangled = "short"; break;
case 't': demangled = "unsigned short"; break;
case 'i': demangled = "int"; break;
case 'j': demangled = "unsigned int"; break;
case 'l': demangled = "long"; break;
case 'm': demangled = "unsigned long"; break;
case 'x': demangled = "long long"; break;
case 'y': demangled = "unsigned long long"; break;
case 'n': demangled = "__int128"; break;
case 'o': demangled = "unsigned __int128"; break;
case 'f': demangled = "float"; break;
case 'd': demangled = "double"; break;
case 'e': demangled = "long double"; break;
case 'g': demangled = "__float128"; break;
case 'z': demangled = "..."; break;
}
}
p = demangler.insert(p, std::make_pair(mangled, demangled));
keeper.p = 0;
}
}
return p->second;
}
}
# endif
BOOST_PYTHON_DECL std::ostream& operator<<(std::ostream& os, type_info const& x)
{
return os << x.name();
}
namespace detail
{
BOOST_PYTHON_DECL std::ostream& operator<<(std::ostream& os, detail::decorated_type_info const& x)
{
os << x.m_base_type;
if (x.m_decoration & decorated_type_info::const_)
os << " const";
if (x.m_decoration & decorated_type_info::volatile_)
os << " volatile";
if (x.m_decoration & decorated_type_info::reference)
os << "&";
return os;
}
}
}} // namespace boost::python::converter