From c6c58ab99ffb8e0763c532dc9970e3eba2646097 Mon Sep 17 00:00:00 2001
From: Axel Naumann <Axel.Naumann@cern.ch>
Date: Fri, 18 Jan 2008 08:46:25 +0000
Subject: [PATCH] From Hady Zalek: I've encountered several compilation and
 runtime errors when trying to port Reflex to Solaris and AIX:

AIX -- CC 5.8:
- Compilation fails under xlC with the following error: "DictionaryGenerator.cxx", line 42.16: 1540-0432 (S) The qualified declarator "ROOT::Reflex::operator<<" must refer to an existing declaration.
- Infinite loop on Reflex initialization due to incorrect map compare functions for 'string ' and 'const char '

Solaris -- xlC V8.0:
- Infinite loop on Reflex initialization due to incorrect map compare functions for 'string ' and 'const char '
- Segmentation fault due to incorrect buffer allocation with 'new char(buffer)' instead of 'new char[buffer]' in 'Tools.cxx':Demangle

Please find the first attached patch to correct the above issues...

The remaining patches are for a rewrite of Tools::NormalizeName to account for the mentioned platforms and make the demangling tests pass. I also took the freedom of adding an overloaded version in Tools.h that receives a 'const char *' parameter instead of a 'const std::string &'. The patch contains test cases for inclusion in test_ReflexBuilder_unit.cxx.


git-svn-id: http://root.cern.ch/svn/root/trunk@21765 27541ba8-7e3a-0410-8455-c3a389f83636
---
 reflex/inc/Reflex/DictionaryGenerator.h |   4 +
 reflex/inc/Reflex/Tools.h               |   3 +
 reflex/src/Tools.cxx                    | 117 +++++++-----------------
 reflex/src/stl_hash.h                   |  40 ++++++++
 reflex/test/test_ReflexBuilder_unit.cxx |  51 +++++++++++
 5 files changed, 133 insertions(+), 82 deletions(-)

diff --git a/reflex/inc/Reflex/DictionaryGenerator.h b/reflex/inc/Reflex/DictionaryGenerator.h
index f89708d9d4b..4778a96dace 100644
--- a/reflex/inc/Reflex/DictionaryGenerator.h
+++ b/reflex/inc/Reflex/DictionaryGenerator.h
@@ -304,6 +304,10 @@ namespace ROOT
       }; // class DictionaryGenerator
 
 
+      /** stream operator */
+      std::ostream & operator << ( std::ostream & s,
+                                   const DictionaryGenerator & obj );
+
    } // namespace Reflex
 } // namespace ROOT
 
diff --git a/reflex/inc/Reflex/Tools.h b/reflex/inc/Reflex/Tools.h
index 713636049d3..7fa9d7d4456 100644
--- a/reflex/inc/Reflex/Tools.h
+++ b/reflex/inc/Reflex/Tools.h
@@ -165,6 +165,9 @@ namespace ROOT {
 
          RFLX_API std::string NormalizeName( const std::string & name );
 
+
+         RFLX_API std::string NormalizeName( const char * name );
+
    
          /**
           * MakeVector is a utility function to create and initialize a std::vector of
diff --git a/reflex/src/Tools.cxx b/reflex/src/Tools.cxx
index d9a21697b47..5a286e9b193 100644
--- a/reflex/src/Tools.cxx
+++ b/reflex/src/Tools.cxx
@@ -388,25 +388,29 @@ std::string Tools::Demangle( const std::type_info & ti ) {
 
 #elif defined(__SUNPRO_CC)
 
-   std::string mangled = ti.name();
+   const char* mangled = ti.name();
    size_t buffer = 1024;
-   char * c_demangled = new char(buffer);
-   int ret = cplus_demangle( mangled.c_str(), c_demangled, buffer);
+   char * c_demangled = new char[buffer];
+   int ret = cplus_demangle( mangled, c_demangled, buffer);
    while ( ret == -1 ) {
       buffer = buffer*2;
-      delete c_demangled;
-      c_demangled = new char(buffer);
-      ret = cplus_demangle( mangled.c_str(), c_demangled, buffer);
+      delete[] c_demangled;
+      c_demangled = new char[buffer];
+      ret = cplus_demangle( mangled, c_demangled, buffer);
    }
    if ( ret == 1 ) {
       throw RuntimeError(std::string("Symbol ") + mangled + " not mangled correctly");
    }
    else {
-      std::string demangled = c_demangled;
-      delete c_demangled;
+      std::string demangled = Tools::NormalizeName(c_demangled);
+      delete[] c_demangled;
       return demangled;
    }
 
+#elif defined(__IBMCPP__)
+
+	return Tools::NormalizeName(ti.name());
+
 #endif
    return "";
 }
@@ -476,84 +480,33 @@ bool isalphanum(int i) {
 
 
 //-------------------------------------------------------------------------------
-std::string Tools::NormalizeName( const std::string & nam ) {
+std::string Tools::NormalizeName( const char * nam ) {
 //-------------------------------------------------------------------------------
 // Normalize a type name.
-   std::string norm_name = "";
-   //char lchar = ' ';
-   unsigned int nlen = nam.length();
-   unsigned int par = 0;
-   bool first_word = true;
-   char cprev = ' ';
-   char cnext = ' ';
-
-   for (unsigned int i = 0; i < nlen; ++i ) {
-
-      switch (nam[i]) {
-
-      case ' ':
-         // are we at the beginning of the name
-         //bool fist_pos = i ? false : true;
-
-         // consume all spaces
-         while (i < nlen && nam[i+1] == ' ') ++i;
-      
-         // if only white spaces at the beginning break or
-         // spaces at the end of the name then break
-         if ( first_word || ( i = nlen -1) ) break;
-
-         // if the last pos and the next pos is char 
-         // or we are at the closing of angular braces 
-         // then insert a space and the next position
-         cprev = nam[i-1];
-         cnext = nam[i+1];
-         if ( ( isalphanum(cprev) &&  isalpha(cnext) ) ||
-              ( cprev == '>' && cnext == '>' ) ) norm_name += ' ' + nam[i+1];
-         // otherwise only add the next pos
-         else norm_name += nam[i+1];
-         // increase counter by consumed pos
-         ++i;
-         break;
-
-      case '(':
-      case '<':
-         ++par;
-         norm_name += nam[i];
-         ++i;
-         break;
-
-      case ')':
-      case '>':
-         --par;
-         norm_name += nam[i];
-         ++i;
-         break;
-
-      case '*':
-      case '&':
-         first_word = false;
-         norm_name += nam[i];
-         ++i;
-         break;
-
-      case 'c':
-         norm_name += nam[i];
-         ++i;
-         break;
-
-      case 'v':
-         norm_name += nam[i];
-         ++i;
-         break;
-
-      default:
-         norm_name += nam[i];
-         ++i;
-         break;
-
+   std::string norm_name;
+   char prev = 0;
+   for (size_t i = 0; nam[i] != 0; i++) {
+      char curr = nam[i];
+      if (curr == ' ') {
+         char next = 0;
+         while (nam[i] != 0 && (next = nam[i + 1]) == ' ') {
+            ++i;
+         }
+         if (!isalphanum(prev) || !isalpha(next)) {
+            continue; // continue on non-word boundaries
+         }
+      } else if (curr == '>' && prev == '>' || curr == '(' && prev != ')') {
+         norm_name += ' ';
       }
-
+      norm_name += (prev = curr);
    }
 
    return norm_name;
 }
+
+
+//-------------------------------------------------------------------------------
+std::string Tools::NormalizeName( const std::string & nam ) {
+//-------------------------------------------------------------------------------
+   return Tools::NormalizeName(nam.c_str());
+}
diff --git a/reflex/src/stl_hash.h b/reflex/src/stl_hash.h
index a6c70d5e758..e40feef4284 100644
--- a/reflex/src/stl_hash.h
+++ b/reflex/src/stl_hash.h
@@ -125,4 +125,44 @@ namespace std {
 
 #endif // __GNUC__
 
+
+
+#if defined(__SUNPRO_CC)
+
+namespace __gnu_cxx {
+
+  template<> struct less<const char *> {
+     typedef const char* Key;
+     bool operator() (Key& k1, Key& k2) const { return strcmp(k1, k2) < 0; }
+  };
+
+  template<> struct less<const std::string *> {
+     typedef const std::string* Key;
+     bool operator() (Key& k1, Key& k2) const { return *k1 < *k2; }
+  };
+
+} // namespace __gnu_cxx  
+
+#endif // __SUNPRO_CC
+
+
+
+#if defined(_AIX)
+
+namespace __gnu_cxx {
+
+  template<> struct less<const char *> {
+     typedef const char* Key;
+     bool operator() (Key k1, Key k2) const { return strcmp(k1, k2) < 0; }
+  };
+
+  template<> struct less<const std::string *> {
+     typedef const std::string* Key;
+     bool operator() (Key k1, Key k2) const { return *k1 < *k2; }
+  };
+
+} // namespace __gnu_cxx  
+
+#endif // _AIX
+
 #endif // __GNU_CXX_HASH_H
diff --git a/reflex/test/test_ReflexBuilder_unit.cxx b/reflex/test/test_ReflexBuilder_unit.cxx
index c73b15de0f0..de0b8f5a361 100644
--- a/reflex/test/test_ReflexBuilder_unit.cxx
+++ b/reflex/test/test_ReflexBuilder_unit.cxx
@@ -46,6 +46,7 @@ class ReflexBuilderUnitTest : public CppUnit::TestFixture {
   CPPUNIT_TEST( freefunctionbuilder );
   CPPUNIT_TEST( freevariablebuilder );
   CPPUNIT_TEST( demangler );
+  CPPUNIT_TEST( normalizer );
   CPPUNIT_TEST( forwarddeclarations );
   CPPUNIT_TEST( subscopebuilder );
   CPPUNIT_TEST( type_equivalence );
@@ -72,6 +73,7 @@ public:
   void freefunctionbuilder();
   void freevariablebuilder();
   void demangler();
+  void normalizer();
   void forwarddeclarations();
   void subscopebuilder();
   void offset();
@@ -134,6 +136,55 @@ void ReflexBuilderUnitTest::demangler()
                               Tools::Demangle(typeid(vector<bar>)));
 }
 
+//==============================================================================================
+// Normalize test
+//==============================================================================================
+void ReflexBuilderUnitTest::normalizer()
+{
+   CPPUNIT_ASSERT_EQUAL(string(""), Tools::NormalizeName(""));
+   CPPUNIT_ASSERT_EQUAL(string(""), Tools::NormalizeName(" "));
+   CPPUNIT_ASSERT_EQUAL(string(""), Tools::NormalizeName("  "));
+   CPPUNIT_ASSERT_EQUAL(string("x"), Tools::NormalizeName("x"));
+   CPPUNIT_ASSERT_EQUAL(string("x"), Tools::NormalizeName(" x"));
+   CPPUNIT_ASSERT_EQUAL(string("int"), Tools::NormalizeName("int"));
+   CPPUNIT_ASSERT_EQUAL(string("int"), Tools::NormalizeName("   int"));
+   CPPUNIT_ASSERT_EQUAL(string("int"), Tools::NormalizeName("int  "));
+   CPPUNIT_ASSERT_EQUAL(string("int*"), Tools::NormalizeName("int *"));
+   CPPUNIT_ASSERT_EQUAL(string("int**"), Tools::NormalizeName("int **"));
+   CPPUNIT_ASSERT_EQUAL(string("int**"), Tools::NormalizeName("int **  "));
+   CPPUNIT_ASSERT_EQUAL(string("int*&"), Tools::NormalizeName("int *&"));
+   CPPUNIT_ASSERT_EQUAL(string("float (int)"), Tools::NormalizeName("float (int)"));
+   CPPUNIT_ASSERT_EQUAL(string("float* (int)"), Tools::NormalizeName("float *(int)"));
+   CPPUNIT_ASSERT_EQUAL(string("float* (int)"), Tools::NormalizeName("float * (int)"));
+   CPPUNIT_ASSERT_EQUAL(string("float* (int)"), Tools::NormalizeName("float*(int)"));
+   CPPUNIT_ASSERT_EQUAL(string("float** (int)"), Tools::NormalizeName("float **(int)"));
+   CPPUNIT_ASSERT_EQUAL(string("float*& (int)"), Tools::NormalizeName("float *&(int)"));
+   CPPUNIT_ASSERT_EQUAL(string("float*& (int)"), Tools::NormalizeName("float * & (int)"));
+   CPPUNIT_ASSERT_EQUAL(string("float*& (int)"), Tools::NormalizeName("float  *  &  (int)"));
+   CPPUNIT_ASSERT_EQUAL(string("float**& (int)"), Tools::NormalizeName("float **&(int)"));
+   CPPUNIT_ASSERT_EQUAL(string("float (*)(int)"), Tools::NormalizeName("float (*)(int)"));
+   CPPUNIT_ASSERT_EQUAL(string("float (*)(int)"), Tools::NormalizeName("float(*)(int)"));
+   CPPUNIT_ASSERT_EQUAL(string("float (*)(int)"), Tools::NormalizeName("  float  (  *  )  (  int  )  "));
+   CPPUNIT_ASSERT_EQUAL(string("float& (*)(int)"), Tools::NormalizeName("float& (*)(int)"));
+   CPPUNIT_ASSERT_EQUAL(string("float**& (*)(int)"), Tools::NormalizeName("float**& (*)(int)"));
+   CPPUNIT_ASSERT_EQUAL(string("a::b"), Tools::NormalizeName("a::b"));
+   CPPUNIT_ASSERT_EQUAL(string("std::vector<bar,std::allocator<bar> >"), Tools::NormalizeName("std::vector<bar,std::allocator<bar> >"));
+   CPPUNIT_ASSERT_EQUAL(string("std::vector<bar,std::allocator<bar> >"), Tools::NormalizeName("std::vector<bar, std::allocator<bar>>"));
+   CPPUNIT_ASSERT_EQUAL(string("std::vector<bar,std::vector<bar,std::allocator<bar> > >"), Tools::NormalizeName("std::vector<bar, std::vector<bar, std::allocator<bar>>>"));
+   CPPUNIT_ASSERT_EQUAL(string("float ()(int)"), Tools::NormalizeName("float ()(int)"));
+   CPPUNIT_ASSERT_EQUAL(string("float ()(int)"), Tools::NormalizeName("float ( )( int)"));
+   CPPUNIT_ASSERT_EQUAL(string("float ()(int)"), Tools::NormalizeName("float (  )( int)"));
+   CPPUNIT_ASSERT_EQUAL(string("float* ()(int)"), Tools::NormalizeName("float* ()(int)"));
+   CPPUNIT_ASSERT_EQUAL(string("float* ()(int)"), Tools::NormalizeName("float * () (int)"));
+   CPPUNIT_ASSERT_EQUAL(string("float* ()(int)"), Tools::NormalizeName("float* ( ) (int)"));
+   CPPUNIT_ASSERT_EQUAL(string("float* ()(int)"), Tools::NormalizeName("float * (   )   (   int   )"));
+   CPPUNIT_ASSERT_EQUAL(string("unsigned int"), Tools::NormalizeName("unsigned int"));
+   CPPUNIT_ASSERT_EQUAL(string("unsigned int"), Tools::NormalizeName("unsigned    int"));
+   CPPUNIT_ASSERT_EQUAL(string("unsigned int"), Tools::NormalizeName("   unsigned    int  "));
+   CPPUNIT_ASSERT_EQUAL(string("const char*"), Tools::NormalizeName("   const  char   *"));
+   CPPUNIT_ASSERT_EQUAL(string("volatile const char*"), Tools::NormalizeName(" volatile   const  char   *"));
+}
+
 //==============================================================================================
 // Class Building test
 //==============================================================================================
-- 
GitLab