From f0e07fa1f0181a6f7a41e8ff4baf46e2c9c85900 Mon Sep 17 00:00:00 2001
From: Markus Frank <Markus.Frank@cern.ch>
Date: Fri, 14 Jul 2017 22:20:14 +0200
Subject: [PATCH] First attempt to make ObjectExtension instances persistent in
 ROOT

---
 .../include/DDAlign/GlobalAlignmentCache.h    |  2 +
 DDAlign/src/GlobalAlignmentCache.cpp          |  4 +-
 DDCore/include/DD4hep/DetElement.h            | 23 +++---
 DDCore/include/DD4hep/Detector.h              |  9 ++-
 DDCore/include/DD4hep/ExtensionEntry.h        | 77 ++++++++++++-------
 DDCore/src/ExtensionEntry.cpp                 |  2 +-
 DDCore/src/ObjectExtensions.cpp               |  4 +-
 DDG4/include/DDG4/Geant4Context.h             |  8 +-
 8 files changed, 79 insertions(+), 50 deletions(-)

diff --git a/DDAlign/include/DDAlign/GlobalAlignmentCache.h b/DDAlign/include/DDAlign/GlobalAlignmentCache.h
index fe4ac1d53..6e8bbcd85 100644
--- a/DDAlign/include/DDAlign/GlobalAlignmentCache.h
+++ b/DDAlign/include/DDAlign/GlobalAlignmentCache.h
@@ -14,6 +14,7 @@
 #define DD4HEP_ALIGNMENT_GLOBALALIGNMENTCACHE_H
 
 // Framework include files
+#include "DD4hep/ExtensionEntry.h"
 #include "DD4hep/GlobalAlignment.h"
 #include "DDAlign/GlobalAlignmentStack.h"
 
@@ -40,6 +41,7 @@ namespace dd4hep {
     class GlobalAlignmentCache  {
       friend class dd4hep::Detector;
       friend class GlobalAlignmentOperator;
+      friend class dd4hep::detail::DeleteExtension<GlobalAlignmentCache,GlobalAlignmentCache>;
 
     public:
       typedef GlobalAlignmentStack                        Stack;
diff --git a/DDAlign/src/GlobalAlignmentCache.cpp b/DDAlign/src/GlobalAlignmentCache.cpp
index bb8249bee..fd36e2101 100644
--- a/DDAlign/src/GlobalAlignmentCache.cpp
+++ b/DDAlign/src/GlobalAlignmentCache.cpp
@@ -75,8 +75,8 @@ GlobalAlignmentCache* GlobalAlignmentCache::install(Detector& description)   {
   GlobalAlignmentCache* cache = description.extension<GlobalAlignmentCache>(false);
   if ( !cache )  {
     cache = new GlobalAlignmentCache(description,"world",true);
-    description.addUserExtension(detail::typeHash64<GlobalAlignmentCache>(),
-                                 new detail::SimpleExtension<GlobalAlignmentCache>(cache));
+    ExtensionEntry* e = new detail::DeleteExtension<GlobalAlignmentCache,GlobalAlignmentCache>(cache);
+    description.addUserExtension(detail::typeHash64<GlobalAlignmentCache>(),e);
   }
   return cache;
 }
diff --git a/DDCore/include/DD4hep/DetElement.h b/DDCore/include/DD4hep/DetElement.h
index cf9b37740..4d2514df7 100644
--- a/DDCore/include/DD4hep/DetElement.h
+++ b/DDCore/include/DD4hep/DetElement.h
@@ -124,7 +124,8 @@ namespace dd4hep {
 
     /// Extend the sensitive detector element with an arbitrary structure accessible by the type
     template <typename IFACE, typename CONCRETE> IFACE* addExtension(CONCRETE* c)  const {
-      return (IFACE*) this->addExtension(detail::typeHash64<IFACE>(),new detail::DeleteExtension<CONCRETE>(c));
+      return (IFACE*) this->addExtension(detail::typeHash64<IFACE>(),
+                                         new detail::DeleteExtension<IFACE,CONCRETE>(c));
     }
 
     /// Access extension element by the type
@@ -198,22 +199,25 @@ namespace dd4hep {
 
   protected:
 
-    template <typename T> struct DetElementExtension : public ExtensionEntry  {
+    template <typename Q, typename T> struct DetElementExtension : public ExtensionEntry  {
     protected:
-      T* ptr;
+      T* ptr = 0;
+      mutable Q* iface = 0;  //!
     public:
       DetElementExtension() = delete;
-      DetElementExtension(T* p) : ptr(p) {}
+      DetElementExtension(T* p) : ptr(p) {  iface = dynamic_cast<Q*>(p); }
       DetElementExtension(const DetElementExtension& copy) = default;
       DetElementExtension& operator=(const DetElementExtension& copy) = default;
       virtual ~DetElementExtension() = default;
       // This one ensures we have the correct signatures
-      T* copy(DetElement de)  const            { return new T(*ptr,de);   }
-      virtual void* object()  const override        { return ptr;              }
-      virtual void* copy(void* det)  const override { return copy(DetElement((Object*)det));  }
+      T* copy(DetElement de)  const                 { return new T(*ptr,de);   }
       virtual void  destruct()  const override      { delete ptr;              }
+      virtual void* object()  const override
+      { return iface ? iface : (iface=dynamic_cast<Q*>(ptr));                  }
+      virtual void* copy(void* det)  const override
+      { return copy(DetElement((Object*)det));                                 }
       virtual ExtensionEntry* clone(void* det)  const  override
-      {  return new DetElementExtension<T>((T*)this->copy(det));           }
+      {  return new DetElementExtension<Q,T>((T*)this->copy(det));             }
     };
 
     /// Internal call to extend the detector element with an arbitrary structure accessible by the type
@@ -285,7 +289,8 @@ namespace dd4hep {
     /// Extend the detector element with an arbitrary structure accessible by the type
     template <typename IFACE, typename CONCRETE> IFACE* addExtension(CONCRETE* c) const {
       CallbackSequence::checkTypes(typeid(IFACE), typeid(CONCRETE), dynamic_cast<IFACE*>(c));
-      return (IFACE*) this->addExtension(detail::typeHash64<IFACE>(),new DetElementExtension<CONCRETE>(c));
+      return (IFACE*) this->addExtension(detail::typeHash64<IFACE>(),
+                                         new DetElementExtension<IFACE,CONCRETE>(c));
     }
     /// Access extension element by the type
     template <typename IFACE> IFACE* extension() const {
diff --git a/DDCore/include/DD4hep/Detector.h b/DDCore/include/DD4hep/Detector.h
index 6e5363047..9d5c1fadb 100644
--- a/DDCore/include/DD4hep/Detector.h
+++ b/DDCore/include/DD4hep/Detector.h
@@ -266,15 +266,18 @@ namespace dd4hep {
 
     /// Add an extension object to the detector element (low level member function)
     virtual void* addUserExtension(unsigned long long int key, ExtensionEntry* entry) = 0;
-    /// Remove an existing extension object from the Detector instance. If not destroyed, the instance is returned  (low level member function)
+
+    /// Remove an existing extension object from the Detector instance.
+    /** If not destroyed, the instance is returned  (low level member function) */
     virtual void* removeUserExtension(unsigned long long int key, bool destroy) = 0;
+
     /// Access an existing extension object from the detector element (low level member function)
     virtual void* userExtension(unsigned long long int key, bool alert=true) const = 0;
 
     /// Extend the sensitive detector element with an arbitrary structure accessible by the type
-    template <typename IFACE, typename CONCRETE> IFACE* addExtension(CONCRETE* c) {
+    template <typename IFACE, typename CONCRETE> IFACE* addExtension(CONCRETE* c)  {
       return (IFACE*) addUserExtension(detail::typeHash64<IFACE>(),
-                                       new detail::DeleteExtension<IFACE>(dynamic_cast<IFACE*>(c)));
+                                       new detail::DeleteExtension<IFACE,CONCRETE>(c));
     }
 
     /// Remove an existing extension object from the Detector instance. If not destroyed, the instance is returned
diff --git a/DDCore/include/DD4hep/ExtensionEntry.h b/DDCore/include/DD4hep/ExtensionEntry.h
index c227c2af3..9542523bc 100644
--- a/DDCore/include/DD4hep/ExtensionEntry.h
+++ b/DDCore/include/DD4hep/ExtensionEntry.h
@@ -60,109 +60,128 @@ namespace dd4hep {
   namespace detail  {
 
     /// Implementation class for the object extension mechanism.
-    /** This implementation class supports the object extension mechanism
-     *  for dd4hep. 
+    /**  This implementation class supports the object extension mechanism
+     *   for dd4hep. 
+     *
+     *   Note:
+     *   The double-template implementation is necessary to support extensions
+     *   using a virtual inheritance relationship between the interface and the
+     *   concrete implementation of the extension object.
      *
      *   \author  M.Frank
      *   \date    13.08.2013
      *   \ingroup DD4HEP
      */
-    template <typename T> struct SimpleExtension : public ExtensionEntry  {
+    template <typename Q,typename T> struct SimpleExtension : public ExtensionEntry  {
     protected:
-      T* ptr;
+      T* ptr = 0;
+      mutable Q* iface = 0;  //!
     public:
       /// Default constructor
       SimpleExtension() = delete;
       /// Initializing constructor
-      SimpleExtension(T* p) : ptr(p) {}
+      SimpleExtension(T* p) : ptr(p) { iface = dynamic_cast<Q*>(p); }
       /// Copy constructor
       SimpleExtension(const SimpleExtension& copy) = default;
       /// Default destructor
       virtual ~SimpleExtension() = default;
       /// Assignment operator
       SimpleExtension& operator=(const SimpleExtension& copy) = default;
-      /// Virtual object accessor
-      virtual void* object()    const override { return ptr;                      }
       /// Virtual object copy operator
       virtual void* copy(void*) const override { invalidCall("copy"); return 0;   }
-      /// Virtual object destructor
-      virtual void  destruct()  const override { invalidCall("destruct"); return; }
+      /// Virtual object destructor. Function may still be called without side-effects.
+      virtual void  destruct()  const override {                                  }
+      /// Virtual object accessor
+      virtual void* object()    const override
+      { return iface ? iface : (iface=dynamic_cast<Q*>(ptr));                     }
       /// Virtual entry clone function
       virtual ExtensionEntry* clone(void*)  const  override
       { invalidCall("clone"); return 0;                                           }
     };
-
+      
     /// Implementation class for the object extension mechanism.
-    /** This implementation class supports the object extension mechanism
-     *  for dd4hep. It is ensured, that on the object destruction or
-     *  on request the reference to the user object may be destructed.
+    /**  This implementation class supports the object extension mechanism
+     *   for dd4hep. It is ensured, that on the object destruction or
+     *   on request the reference to the user object may be destructed.
      *
-     *  Note: User object must be taken from the heap using "new".
+     *   Note: User object must be taken from the heap using "new".
+     *   Note:
+     *   The double-template implementation is necessary to support extensions
+     *   using a virtual inheritance relationship between the interface and the
+     *   concrete implementation of the extension object.
      *
      *   \author  M.Frank
      *   \date    13.08.2013
      *   \ingroup DD4HEP
      */
-    template <typename T> struct DeleteExtension : public ExtensionEntry  {
+    template <typename Q,typename T> struct DeleteExtension : public ExtensionEntry  {
     protected:
-      T* ptr;
+      T* ptr = 0;
+      mutable Q* iface = 0;  //!
     public:
       /// Default constructor
       DeleteExtension() = delete;
       /// Initializing constructor
-      DeleteExtension(T* p) : ptr(p) {}
+      DeleteExtension(T* p) : ptr(p)  { iface = dynamic_cast<Q*>(p); }
       /// Copy constructor
       DeleteExtension(const DeleteExtension& copy) = default;
       /// Default destructor
       virtual ~DeleteExtension() = default;
       /// Assignment operator
       DeleteExtension& operator=(const DeleteExtension& copy) = default;
-      /// Virtual object accessor
-      virtual void* object()     const override  { return ptr;                    }
       /// Virtual object copy operator
       virtual void* copy(void*)  const override  { invalidCall("copy"); return 0; }
       /// Virtual object destructor
       virtual void  destruct()   const override  { delete ptr;                    }
+      /// Virtual object accessor
+      virtual void* object()     const override
+      { return iface ? iface : (iface=dynamic_cast<Q*>(ptr));                     }
       /// Virtual entry clone function
       virtual ExtensionEntry* clone(void* arg)  const  override
       {  return new DeleteExtension((T*)this->copy(arg));                         }
     };
 
     /// Implementation class for the object extension mechanism.
-    /** This implementation class supports the object extension mechanism
-     *  for dd4hep. It is ensured, that on the object destruction or
-     *  on request the reference to the user object may be destructed.
+    /**  This implementation class supports the object extension mechanism
+     *   for dd4hep. It is ensured, that on the object destruction or
+     *   on request the reference to the user object may be destructed.
      *
-     *  Note: User object must be taken from the heap using "new".
+     *   Note: User object must be taken from the heap using "new".
+     *   Note:
+     *   The double-template implementation is necessary to support extensions
+     *   using a virtual inheritance relationship between the interface and the
+     *   concrete implementation of the extension object.
      *
      *   \author  M.Frank
      *   \date    13.08.2013
      *   \ingroup DD4HEP
      */
-    template <typename T> struct CopyDeleteExtension : public ExtensionEntry  {
+    template <typename Q,typename T> struct CopyDeleteExtension : public ExtensionEntry  {
     protected:
-      T* ptr;
+      T* ptr = 0;
+      mutable Q* iface = 0;  //!
     public:
       /// Default constructor
       CopyDeleteExtension() = delete;
       /// Initializing constructor
-      CopyDeleteExtension(T* p) : ptr(p) {}
+      CopyDeleteExtension(T* p) : ptr(p)  { iface = dynamic_cast<Q*>(p);          }
       /// Copy constructor
       CopyDeleteExtension(const CopyDeleteExtension& copy) = default;
       /// Default destructor
       virtual ~CopyDeleteExtension() = default;
       /// Assignment operator
       CopyDeleteExtension& operator=(const CopyDeleteExtension& copy) = default;
-      /// Virtual object accessor
-      virtual void* object()     const override  { return ptr;                    }
       /// Virtual object copy operator
       virtual void* copy(void*)  const override  { return new T(*ptr);            }
       /// Virtual object destructor
       virtual void  destruct()   const override  { delete ptr;                    }
+      /// Virtual object accessor
+      virtual void* object()     const override
+      { return iface ? iface : (iface=dynamic_cast<Q*>(ptr));                     }
       /// Virtual entry clone function
       virtual ExtensionEntry* clone(void* arg)  const  override
       {  return new CopyDeleteExtension((T*)this->copy(arg));                     }
     };
   }     // End namespace detail
-  }       // End namespace dd4hep
+}       // End namespace dd4hep
 #endif  /* DD4HEP_DDCORE_EXTENSIONENTRY_H */
diff --git a/DDCore/src/ExtensionEntry.cpp b/DDCore/src/ExtensionEntry.cpp
index 250203c29..f22876858 100644
--- a/DDCore/src/ExtensionEntry.cpp
+++ b/DDCore/src/ExtensionEntry.cpp
@@ -17,6 +17,6 @@
 
 /// Callback on invalid call invokation
 void dd4hep::ExtensionEntry::invalidCall(const char* tag)  const {
-  except("ExtensionEntry","Invalid call invokation from %s to method %s(...).",
+  except("ExtensionEntry","Invalid call invocation from %s to method %s(...).",
          typeName(typeid(*this)).c_str(), tag);    
 }
diff --git a/DDCore/src/ObjectExtensions.cpp b/DDCore/src/ObjectExtensions.cpp
index bbb9212a2..dd288c2f5 100644
--- a/DDCore/src/ObjectExtensions.cpp
+++ b/DDCore/src/ObjectExtensions.cpp
@@ -95,7 +95,7 @@ void* ObjectExtensions::removeExtension(unsigned long long int key, bool destroy
 void* ObjectExtensions::extension(unsigned long long int key) const {
   const auto j = extensions.find(key);
   if (j != extensions.end()) {
-    return (*j).second;
+    return (*j).second->object();
   }
   except("removeExtension","The object has no extension of type %016llX.",key);
   return 0;
@@ -105,7 +105,7 @@ void* ObjectExtensions::extension(unsigned long long int key) const {
 void* ObjectExtensions::extension(unsigned long long int key, bool alert) const {
   const auto j = extensions.find(key);
   if (j != extensions.end()) {
-    return (*j).second;
+    return (*j).second->object();
   }
   else if ( !alert )
     return 0;
diff --git a/DDG4/include/DDG4/Geant4Context.h b/DDG4/include/DDG4/Geant4Context.h
index 030cbaba0..2500bc211 100644
--- a/DDG4/include/DDG4/Geant4Context.h
+++ b/DDG4/include/DDG4/Geant4Context.h
@@ -86,8 +86,8 @@ namespace dd4hep {
       /// Add user extension object. Ownership is transferred!
       template <typename T> T* addExtension(T* ptr, bool take_ownership=true)   {
         ExtensionEntry* e = take_ownership
-          ? (ExtensionEntry*)new detail::DeleteExtension<T>(ptr)
-          : (ExtensionEntry*)new detail::SimpleExtension<T>(ptr);
+          ? (ExtensionEntry*)new detail::DeleteExtension<T,T>(ptr)
+          : (ExtensionEntry*)new detail::SimpleExtension<T,T>(ptr);
         return (T*)ObjectExtensions::addExtension(detail::typeHash64<T>(),e);
       }
       /// Access to type safe extension object. Exception is thrown if the object is invalid
@@ -142,8 +142,8 @@ namespace dd4hep {
       /// Add user extension object. Ownership is transferred and object deleted at the end of the event.
       template <typename T> T* addExtension(T* ptr, bool take_ownership=true)   {
         ExtensionEntry* e = take_ownership
-          ? (ExtensionEntry*)new detail::DeleteExtension<T>(ptr)
-          : (ExtensionEntry*)new detail::SimpleExtension<T>(ptr);
+          ? (ExtensionEntry*)new detail::DeleteExtension<T,T>(ptr)
+          : (ExtensionEntry*)new detail::SimpleExtension<T,T>(ptr);
         return (T*)ObjectExtensions::addExtension(detail::typeHash64<T>(),e);
       }
       /// Access to type safe extension object. Exception is thrown if the object is invalid
-- 
GitLab