From f06ca60651e70768a1e29b48cbfbdfe88ee7b9d6 Mon Sep 17 00:00:00 2001
From: Wim Lavrijsen <WLavrijsen@lbl.gov>
Date: Wed, 4 May 2011 22:55:51 +0000
Subject: [PATCH] enable the use of std::exception deriveds in python

git-svn-id: http://root.cern.ch/svn/root/trunk@39104 27541ba8-7e3a-0410-8455-c3a389f83636
---
 bindings/pyroot/ROOT.py             | 13 ++++++--
 bindings/pyroot/src/RootWrapper.cxx | 48 +++++++++++++++++++++--------
 2 files changed, 45 insertions(+), 16 deletions(-)

diff --git a/bindings/pyroot/ROOT.py b/bindings/pyroot/ROOT.py
index ada08dfbc80..e05edf8a11e 100755
--- a/bindings/pyroot/ROOT.py
+++ b/bindings/pyroot/ROOT.py
@@ -192,13 +192,20 @@ _root.Template = Template
 
 
 ### scope place holder for STL classes ------------------------------------------
-class std:
-   stlclasses = ( 'complex', 'exception', 'pair', \
+class _stdmeta( type ):
+   def __getattr__( cls, attr ):   # for non-templated classes in std
+      klass = _root.MakeRootClass( attr, cls )
+      setattr( cls, attr, klass )
+      return klass
+
+class std( object ):
+   __metaclass__ = _stdmeta
+
+   stlclasses = ( 'complex', 'pair', \
       'deque', 'list', 'queue', 'stack', 'vector', 'map', 'multimap', 'set', 'multiset' )
 
    for name in stlclasses:
       locals()[ name ] = Template( "std::%s" % name )
-#      exec '%(name)s = Template( "std::%(name)s" )' % { 'name' : name }
 
    string = _root.MakeRootClass( 'string' )
 
diff --git a/bindings/pyroot/src/RootWrapper.cxx b/bindings/pyroot/src/RootWrapper.cxx
index 0e1c730f026..6a7cc44334c 100644
--- a/bindings/pyroot/src/RootWrapper.cxx
+++ b/bindings/pyroot/src/RootWrapper.cxx
@@ -125,19 +125,27 @@ namespace {
          PyROOT::BindRootObject( obj, klass ) );
    }
 
-   std::set< std::string > gSTLTypes, gLoadedSTLTypes;
+   std::set< std::string > gSTLTypes, gSTLExceptions;
    struct InitSTLTypes_t {
       InitSTLTypes_t()
       {
+         std::string nss = "std::";
+
          const char* stlTypes[] = { "complex", "exception",
             "deque", "list", "queue", "stack", "vector",
             "map", "multimap", "set", "multiset" };
-         std::string nss = "std::";
          for ( int i = 0; i < int(sizeof(stlTypes)/sizeof(stlTypes[0])); ++i ) {
             gSTLTypes.insert( stlTypes[ i ] );
             gSTLTypes.insert( nss + stlTypes[ i ] );
          }
-         gLoadedSTLTypes.insert( "vector" );
+
+         const char* stlExceptions[] = { "logic_error", "domain_error",
+            "invalid_argument", "length_error", "out_of_range", "runtime_error",
+            "range_error", "overflow_error", "underflow_error" };
+         for ( int i = 0; i < int(sizeof(stlExceptions)/sizeof(stlExceptions[0])); ++i ) {
+            gSTLExceptions.insert( stlExceptions[ i ] );
+            gSTLExceptions.insert( nss + stlExceptions[ i ] );
+         }
       }
    } initSTLTypes_;
 
@@ -151,22 +159,36 @@ namespace {
          if ( klass != 0 )
             TClass::RemoveClass( (TClass*)klass );
 
-      // make sure to only load once
-         if ( gLoadedSTLTypes.find( sub ) == gLoadedSTLTypes.end() ) {
+      // strip std:: part as needed to form proper file name
+         if ( sub.substr( 0, 5 ) == "std::" )
+            sub = sub.substr( 5, std::string::npos );
 
-         // strip std:: part as needed to form proper file name
-            if ( sub.substr( 0, 5 ) == "std::" )
-               sub = sub.substr( 5, std::string::npos );
+      // tell CINT to go for it
+         gROOT->ProcessLine( (std::string( "#include <" ) + sub + ">").c_str() );
 
-         // tell CINT to go for it
-            gROOT->ProcessLine( (std::string( "#include <" ) + sub + ">").c_str() );
+      // prevent second attempt to load by erasing name
+         gSTLTypes.erase( gSTLTypes.find( sub ) );
+         gSTLTypes.erase( gSTLTypes.find( "std::" + sub ) );
 
-         // prevent second attempt to load by erasing name
-            gLoadedSTLTypes.insert( sub );
-            gLoadedSTLTypes.insert( "std::" + sub );
+         return kTRUE;
 
+      } else if ( gSTLExceptions.find( sub ) != gSTLExceptions.end() ) {
+      // removal is required or the dictionary can't be updated properly
+         if ( klass != 0 )
+            TClass::RemoveClass( (TClass*)klass );
+
+      // load base class std::exception if not yet done so, and refresh
+         if ( gSTLTypes.find( "exception" ) != gSTLTypes.end() ) {
+            gROOT->ProcessLine( "#include <exception>" );
+            TClass::RemoveClass( TClass::GetClass( "std::exception" ) );
+            gSTLTypes.erase( gSTLTypes.find( "exception" ) );
+            gSTLTypes.erase( gSTLTypes.find( "std::exception" ) );
          }
 
+      // load stdexcept, which contains all std exceptions
+         gROOT->ProcessLine( "#include <stdexcept>" );
+         gSTLExceptions.clear();   // completely done with std exceptions
+
          return kTRUE;
       }
 
-- 
GitLab