1
0
forked from boostorg/core

Added low level tools for demangling. Requested by Boost.TypeIndex author.

This commit is contained in:
Andrey Semashev
2014-06-12 19:23:36 +04:00
parent b745260e9e
commit 6b1dd51818
3 changed files with 189 additions and 59 deletions

View File

@@ -1,5 +1,6 @@
[/
Copyright 2014 Peter Dimov
Copyright 2014 Andrey Semashev
Distributed under the Boost Software License, Version 1.0.
@@ -18,30 +19,48 @@
[section Header <boost/core/demangle.hpp>]
The header `<boost/core/demangle.hpp>` defines the function
`boost::core::demangle`. It takes a mangled string such as
those returned by `typeid(T).name()` on certain implementations
such as `g++`, and returns its demangled, human-readable, form.
The header `<boost/core/demangle.hpp>` defines several tools for undecorating
symbol names.
[section Synopsis]
``
namespace boost
{
namespace core
{
std::string demangle( char const * name );
char const * demangle_alloc( char const * name ) noexcept;
void demangle_free( char const * demangled_name ) noexcept;
class scoped_demangled_name
{
public:
explicit scoped_demangled_name( char const * name ) noexcept;
~scoped_demangled_name() noexcept;
char const * get() const noexcept;
scoped_demangled_name( scoped_demangled_name const& ) = delete;
scoped_demangled_name& operator= ( scoped_demangled_name const& ) = delete;
};
}
}
``
[endsect]
[section Conventional interface]
The function `boost::core::demangle` is the conventional
way to obtain demangled symbol name. It takes a mangled string such as
those returned by `typeid(T).name()` on certain implementations
such as `g++`, and returns its demangled, human-readable, form. In case if
demangling fails (e.g. if `name` cannot be interpreted as a mangled name)
the function returns `name`.
[section Example]
``
#include <boost/core/demangle.hpp>
#include <typeinfo>
#include <iostream>
@@ -57,7 +76,50 @@ int main()
std::cout << name << std::endl; // prints 1XIiE
std::cout << boost::core::demangle( name ) << std::endl; // prints X<int>
}
``
[endsect]
[endsect]
[section Low level interface]
In some cases more low level interface may be desirable. For example:
* Assuming that symbol demangling may fail, the user wants to be able to handle such errors.
* The user needs to post-process the demangled name (e.g. remove common namespaces), and
allocating a temporary string with the complete demangled name is significant overhead.
The function `boost::core::demangle_alloc` performs name demangling and returns a pointer
to a string with the demangled name, if succeeded, or `nullptr` otherwise. The returned pointer
must be passed to `boost::core::demangle_free` to reclaim resources. Note that on some platforms
the pointer returned by `boost::core::demangle_alloc` may refer to the string denoted by `name`,
so this string must be kept immutable for the whole life time of the returned pointer.
The `boost::core::scoped_demangled_name` class is a scope guard that automates the calls to
`boost::core::demangle_alloc` (on its construction) and `boost::core::demangle_free` (on destruction).
The string with the demangled name can be obtained with its `get` method. Note that this method may
return `nullptr` if demangling failed.
[section Example]
#include <boost/core/demangle.hpp>
#include <typeinfo>
#include <iostream>
template<class T> struct X
{
};
int main()
{
char const * name = typeid( X<int> ).name();
boost::core::scoped_demangled_name demangled( name );
std::cout << name << std::endl; // prints 1XIiE
std::cout << (demangled.get() ? demangled.get() : "[unknown]") << std::endl; // prints X<int>
}
[endsect]
[endsect]
@@ -67,7 +129,7 @@ int main()
The implementation of `core::demangle` was taken from
`boost/exception/detail/type_info.hpp`, which in turn was adapted
from `boost/units/detail/utility.hpp`.
from `boost/units/detail/utility.hpp` and `boost/log/utility/type_info_wrapper.hpp`.
[endsect]

View File

@@ -1,15 +1,10 @@
#ifndef BOOST_CORE_DEMANGLE_HPP_INCLUDED
#define BOOST_CORE_DEMANGLE_HPP_INCLUDED
// MS compatible compilers support #pragma once
#if defined(_MSC_VER) && (_MSC_VER >= 1020)
# pragma once
#endif
// core::demangle
//
// Copyright 2014 Peter Dimov
// Copyright 2014 Andrey Semashev
//
// Distributed under the Boost Software License, Version 1.0.
// See accompanying file LICENSE_1_0.txt or copy at
@@ -18,6 +13,10 @@
#include <boost/config.hpp>
#include <string>
#if defined(BOOST_HAS_PRAGMA_ONCE)
# pragma once
#endif
#if defined( __clang__ ) && defined( __has_include )
# if __has_include(<cxxabi.h>)
# define BOOST_CORE_HAS_CXXABI_H
@@ -38,34 +37,56 @@ namespace boost
namespace core
{
char const * demangle_alloc( char const * name ) BOOST_NOEXCEPT;
void demangle_free( char const * name ) BOOST_NOEXCEPT;
class scoped_demangled_name
{
private:
char const * m_p;
public:
explicit scoped_demangled_name( char const * name ) BOOST_NOEXCEPT :
m_p( demangle_alloc( name ) )
{
}
~scoped_demangled_name() BOOST_NOEXCEPT
{
demangle_free( m_p );
}
char const * get() const BOOST_NOEXCEPT
{
return m_p;
}
BOOST_DELETED_FUNCTION(scoped_demangled_name( scoped_demangled_name const& ))
BOOST_DELETED_FUNCTION(scoped_demangled_name& operator= ( scoped_demangled_name const& ))
};
#if defined( BOOST_CORE_HAS_CXXABI_H )
// lifted from boost/exception/detail/type_info.hpp
inline char const * demangle_alloc( char const * name ) BOOST_NOEXCEPT
{
int status = 0;
std::size_t size = 0;
return abi::__cxa_demangle( name, NULL, &size, &status );
}
inline void demangle_free( char const * name ) BOOST_NOEXCEPT
{
std::free( const_cast< char* >( name ) );
}
inline std::string demangle( char const * name )
{
struct auto_free
scoped_demangled_name demangled_name( name );
char const * const p = demangled_name.get();
if( p )
{
explicit auto_free( char * ptr ): p( ptr )
{
}
~auto_free()
{
std::free( p );
}
char * p;
};
int status = 0;
std::size_t size = 0;
auto_free demangled( abi::__cxa_demangle( name, NULL, &size, &status ) );
if( demangled.p )
{
return demangled.p;
return p;
}
else
{
@@ -75,6 +96,15 @@ inline std::string demangle( char const * name )
#else
inline char const * demangle_alloc( char const * name ) BOOST_NOEXCEPT
{
return name;
}
inline void demangle_free( char const * ) BOOST_NOEXCEPT
{
}
inline std::string demangle( char const * name )
{
return name;

View File

@@ -2,6 +2,7 @@
// Trivial test for core::demangle
//
// Copyright (c) 2014 Peter Dimov
// Copyright (c) 2014 Andrey Semashev
//
// Distributed under the Boost Software License, Version 1.0.
// See accompanying file LICENSE_1_0.txt or copy at
@@ -15,9 +16,46 @@ template<class T1, class T2> struct Y1
{
};
int main()
void test_demangle()
{
typedef Y1<int, long> T;
std::cout << boost::core::demangle( typeid( T ).name() );
std::cout << boost::core::demangle( typeid( T ).name() ) << std::endl;
}
void test_demangle_alloc()
{
typedef Y1<int, long> T;
const char* p = boost::core::demangle_alloc( typeid( T ).name() );
if (p)
{
std::cout << p << std::endl;
boost::core::demangle_free(p);
}
else
{
std::cout << "[demangling failed]" << std::endl;
}
}
void test_scoped_demangled_name()
{
typedef Y1<int, long> T;
boost::core::scoped_demangled_name demangled_name( typeid( T ).name() );
const char* p = demangled_name.get();
if (p)
{
std::cout << p << std::endl;
}
else
{
std::cout << "[demangling failed]" << std::endl;
}
}
int main()
{
test_demangle();
test_demangle_alloc();
test_scoped_demangled_name();
return 0;
}