This is the mail archive of the libstdc++@gcc.gnu.org mailing list for the libstdc++ project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: what's next


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>


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]