This is the mail archive of the
libstdc++@gcc.gnu.org
mailing list for the libstdc++ project.
Re: what's next
- From: Carlo Wood <carlo at alinoe dot com>
- To: Benjamin Kosnik <bkoz at redhat dot com>
- Cc: phil at jaj dot com, libstdc++ at gcc dot gnu dot org
- Date: Thu, 5 Dec 2002 15:23:13 +0100
- Subject: Re: what's next
- References: <rt-6444-26525.13.5026931490963@rt.gnu.org> <20021204232045.GA8085@alinoe.com> <20021204183457.04334c27.bkoz@redhat.com> <20021204185711.2c258cbd.bkoz@redhat.com> <20021205014606.GA10993@alinoe.com> <20021204224911.2c437a33.bkoz@redhat.com>
On Wed, Dec 04, 2002 at 10:49:11PM -0600, Benjamin Kosnik wrote:
> >there are other reasons that
> >it would be good to be able to externally provide the memory
> >management stuff (ie, pre-allocation).
>
> Exactly.
>
> I think this discussion can, and should be, public. You might want to do
> so, under say "augmenting __cxa_demangle" on the libstdc++ list.
>
> Would it be possible to do this after the __cxa_demangle bits go in?
>
> >namespace abi {
> > extern "C" inline char*
> > __cxa_demangle (const char* mangled_name, char* buf, size_t* n, int* status)
> > {
> > return __cxa_demangle_withalloc (mangled_name, buf, n, status, malloc, free);
> > }
> >}
>
> What do you think about using a allocator template parameter, a la
> std::string? Then the IA64 __cxa_demangle would just be a
> specialization, perhaps. These kind of design decisions should really be
> in a public place so that people, in two years, and try and see why
> things were done the way they were...
I'd like to just stay the coder and not being dragged into endless
discussions. I do not have much time for this.
However, we can CC libstdc++@gcc.gnu.org - then it will be archived
and other can give constructive suggestions. Please CC me when you
do as I am not subscribed.
> -benjamin
About the allocator template parameter, that is my original design.
I just thought you'd like the C interface more easily heheh.
I already did this work for boost (although that failed then afterwards
as a result of a horrible politic/administrative/whatever; I like no-nonsense,
not endless discussions).
The lowest level interface, which can be totally hidden from the normal
public, but which should be globally accessible somehow, is - at the moment:
namespace /*something*/ { ...
namespace demangler { // This is the inner name I propose, it makes things readable.
template<typename Allocator>
class session {
private:
// ... lots of stuff here
public:
explicit session(char const* in, int len);
static int decode_encoding(std::basic_string<char, std::char_traits<char>, Allocator>& output, char const* input, int len);
bool decode_type(std::basic_string<char, std::char_traits<char>, Allocator>& output, qualifier_list<Allocator>* qualifiers = NULL);
bool remaining_input_characters(void) const;
};
} // namespace demangler
}
The users will never pass a qualifier_list, so I don't mention it as
being public even here ;).
Now this interface is very low level and don't even want to discuss it,
but it shows that you get your Allocator interface.
A less low level interface then could be for example:
namespace foobar {
//
// Public interface
//
template<typename Allocator>
struct demangle {
typedef Allocator allocator_type;
static std::basic_string<char, std::char_traits<char>, Allocator> symbol(char const* in);
static std::basic_string<char, std::char_traits<char>, Allocator> type(char const* in);
};
//
// demangle::symbol()
//
// Demangle the input `first' till `last' and append to `dest'.
// The input should be a mangled function name as for instance
// returned by nm(1).
//
template<typename Allocator>
std::basic_string<char, std::char_traits<char>, Allocator> demangle<Allocator>::
symbol(char const* in)
{
std::basic_string<char, std::char_traits<char>, Allocator> result;
bool failure = false;
//
// <mangled-name> ::= _Z <encoding>
//
char const* inp = in;
if (*inp != '_')
failure = true;
else if (*++inp != 'Z')
failure = true;
else
{
++inp; // Skip 'Z'
int cnt;
if ((cnt = demangler::session<Allocator>::decode_encoding(result, inp, INT_MAX)) < 0 || inp[cnt] != 0)
failure = true;
}
if (failure)
result = in; // Failure to demangle, return the mangled name.
return result;
}
//
// demangle::type()
//
// Demangle input `in'.
// The input must be a zero terminated mangled type name as for instance returned by std::type_info::name().
// `len' may optionally be the length of the input string.
//
template<typename Allocator>
std::basic_string<char, std::char_traits<char>, Allocator> demangle<Allocator>::
type(char const* in)
{
std::basic_string<char, std::char_traits<char>, Allocator> result;
if (in == NULL)
result = "(null)";
else
{
demangler::session<Allocator> demangler_session(in, INT_MAX);
if (!demangler_session.decode_type(result) || demangler_session.remaining_input_characters())
result = in; // Failure to demangle, return the mangled name.
}
return result;
}
An even less low interface, where the allocator is filled in, then would be:
typedef foobar::demangle<std::allocator<char> > demangle;
Which would allow you to do for example:
char const* mangled_name = typeid(main).name();
std::string demangled_name = demangle::type(mangled_name);
std::cout << mangled_name << " => " << demangled_name << std::endl;
Using that interface, the __cxa_demangle will then look like this:
(UNTESTED CODE!)
Header:
namespace abi {
extern "C" char* __cxa_demangle (const char* mangled_name,
char* buf,
size_t* n,
int* status);
}
Source file:
namespace abi {
char* __cxa_demangle (const char* mangled_name,
char* buf,
size_t* n,
int* status)
{
if (!mangled_name || (buf && !n))
{
*status = -3;
return NULL;
}
std::string result;
bool failure = false;
char const* inp = mangled_name;
try
{
if (*inp != '_' || *++inp != 'Z')
{
demangler::session<std::allocator<char> > demangler_session(mangled_name, INT_MAX);
if (!demangler_session.decode_type(result) || demangler_session.remaining_input_characters())
result = mangled_name; // Failure to demangle, return the mangled name.
}
else
{
++inp;
int cnt;
if ((cnt = demangler::session<std::allocator<char> >::decode_encoding(result, inp, INT_MAX)) < 0 || inp[cnt] != 0)
{
*status = -2; // Failure to demangle.
return NULL;
}
}
}
catch (std::bad_alloc)
{
*status = -1;
return NULL;
}
size_t len = result.size();
if (!buf)
buf = (char*)malloc(len + 1);
else if (len + 1 > n)
buf = (char*)realloc(buf, len + 1);
if (!buf)
*status = -1;
else
{
std::memcpy(buf, result.data(), len);
buf[len] = 0;
}
return buf;
}
}
--
Carlo Wood <carlo@alinoe.com>