//
// Copyright (c) 2009-2010 Ronald Kluth
//
// 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)
//

/**
 * @file detail/TypeToString.h
 * @author Ronald Kluth
 * @date created at 2009/03/29
 * @brief Declaration and implementation of the free function typeToString()
 * @since 0.1
 */

#ifndef LOG_DETAIL_TYPETOSTRING_INCLUDED
#define LOG_DETAIL_TYPETOSTRING_INCLUDED

// typeid().name() returns a mangled type name on GCC,
// needs to be treated differently than other compilers,
// the following includes the demangling library header

#if defined(__GNUC__) /* GNU Compiler */

	#include <cxxabi.h>

#endif

#include <cstdlib>
#include <sstream>
#include <stdexcept>
#include <string>
#include <typeinfo>

namespace Log {
namespace Detail {

/**
 * @brief Get a string representation of the type name
 * @param type reference to a type_info object returned by typeid()
 * @return the type name as string
 *
 * The method @c std::type_info::name returns a mangled type name on GCC
 * and thus needs to be treated differently than on other compilers.
 * This function applies demangling to retrieve a human-readable
 * string representation of type names.
 */
inline std::string typeToString( const std::type_info& type )
{
#if defined(__GNUC__) /* GNU Compiler */

	int demangleStatus = -1;

	char* cString = abi::__cxa_demangle( type.name(), 0, 0, &demangleStatus );

//	demangleStatus is set to one of the following values:
//	 0: The demangling operation succeeded.
//	-1: A memory allocation failure occurred.
//	-2: mangled_name is not a valid name under the C++ ABI mangling rules.
//	-3: One of the arguments is invalid.

	if( demangleStatus != 0 )
	{
		std::ostringstream stream;
		stream << "typeToString() failed,"
				<< " error code: " << demangleStatus
				<< " while trying to convert '" << type.name() << "'"
				<< std::endl;

		throw std::runtime_error( stream.str() );
	}

	std::string typeString;
	if( cString != NULL )
	{
		typeString = cString;
		std::free( cString );
	}

#else // other compilers should give a demangled name

	std::string typeString( type.name() );

#endif

	return typeString;
}

} } // namespace Log::Detail

#endif /* LOG_DETAIL_TYPETOSTRING_INCLUDED */
