Commits

Anonymous committed de52503

Add StdHackGenerator.

Comments (0)

Files changed (5)

+2007-10-08  scott snyder  <snyder@bnl.gov>
+
+	* Tagging RootUtils-00-00-02.
+
+2007-10-07  scott snyder  <snyder@bnl.gov>
+
+	* src/StdHackGenerator.cxx: (new)
+	* RootUtils/StdHackGenerator.h: (new)
+	* RootUtils/selection.xml: Add it.
+	* RootUtils/RootUtilsDict.h: Add it.
+
+	* Tagging RootUtils-00-00-01.
+
+	* Initial checkin, with InitHist.
+	
+

RootUtils/RootUtilsDict.h

 // This file's extension implies that it's C, but it's really -*- C++ -*-.
-// $Id: RootUtilsDict.h,v 1.1 2007-10-07 00:01:54 ssnyder Exp $
+// $Id: RootUtilsDict.h,v 1.2 2007-10-08 14:41:46 ssnyder Exp $
 
 /**
  * @file  RootUtils/RootUtilsDict.h
  */
 
 #include "RootUtils/InitHist.h"
+#include "RootUtils/StdHackGenerator.h"

RootUtils/StdHackGenerator.h

+// This file's extension implies that it's C, but it's really -*- C++ -*-.
+// $Id: StdHackGenerator.h,v 1.1 2007-10-08 14:41:46 ssnyder Exp $
+
+/**
+ * @file  RootUtils/StdHackGenerator.h
+ * @author scott snyder
+ * @date Oct 2007
+ * @brief Work around inconsistent use of std::.
+ *
+ * Sometimes, when Athena is requesting a class to autoload (via GetClass),
+ * the name that's requested omits some of the std:: qualifications
+ * in front of the STL names.  One usually finds, though, that the
+ * autoload database contains the full std::-qualified names.  Thus,
+ * the autoload fails.
+ *
+ * For example, we may be asked to load a class with a name like
+ *   Navigable<foo,vector<...> >
+ * but what's in the rootmap file is
+ *   Navigable<foo,std::vector<...> >
+ *
+ * Root does provide a way to hook into class autoloading ---
+ * a @c TClassGenerator, which is called when autoloading fails.
+ * Thus, we create an autoloader such that when autoloading fails,
+ * it tries again with any missing `std::' qualifications reinserted.
+ *
+ * ??? FIXME: Find out why the bad names are being requested
+ * in the first place.
+ */
+
+#ifndef ROOTUTILS_STDHACKGENERATOR_H
+#define ROOTUTILS_STDHACKGENERATOR_H
+
+#include "TClassGenerator.h"
+
+
+namespace RootUtils {
+
+
+/**
+ * @brief Work around inconsistent use of std::.
+ */
+class StdHackGenerator
+  : public TClassGenerator
+{
+public:
+  /**
+   * @brief Initialize.
+   *        Create an instance of this class and register it as a generator.
+   */
+  static void Initialize();
+
+
+  /**
+   * @brief Look up a class by name.
+   * @param classname The name of the class to find.
+   * @param load If true, enable autoloading.
+   */
+  virtual TClass *GetClass(const char* classname, Bool_t load);
+
+
+  /**
+   * @brief Look up a class by @c type_info.
+   * @param typeinfo The @c type_info of the class to find.
+   * @param load If true, enable autoloading.
+   */
+  virtual TClass *GetClass(const type_info& typeinfo, Bool_t load);
+};
+
+
+} // namespace RootUtils
+
+
+#endif // not ROOTUTILS_STDHACKGENERATOR_H

RootUtils/selection.xml

 <lcgdict>
     <class name="RootUtils::InitHist" />
+    <class name="RootUtils::StdHackGenerator" />
 </lcgdict>

src/StdHackGenerator.cxx

+// $Id: StdHackGenerator.cxx,v 1.1 2007-10-08 14:41:46 ssnyder Exp $
+/**
+ * @file  RootUtils/src/StdHackGenerator.cxx
+ * @author scott snyder
+ * @date Oct 2007
+ * @brief Work around inconsistent use of std::.
+ */
+
+#include "RootUtils/StdHackGenerator.h"
+#include "TROOT.h"
+#include "TClassEdit.h"
+#include "TClassTable.h"
+#include "TInterpreter.h"
+
+
+namespace {
+
+
+/**
+ * @brief Make a new clas name, inserting any missing std:: qualifications.
+ * @param in The name to edit.
+ * @returns The new name (may be the same as in).
+ */
+std::string addstd (const std::string& in)
+{
+  // string -> std::string
+  if (in == "string")
+    return "std::string";
+
+  // Otherwise, give up if it's not a template name.
+  if (strchr (in.c_str(), '<') == 0)
+    return in;
+
+  // Split apart template arguments.
+  std::vector<std::string> vec;
+  int loc;
+  TClassEdit::GetSplit (in.c_str(), vec, loc);
+  if (vec.empty())
+    return "";
+  else {
+    std::string out;
+
+    // If the template name is a STL name that does not start with
+    // std::, then add std::.
+    if (strncmp (vec[0].c_str(), "std::", 5) != 0 &&
+        (TClassEdit::STLKind (vec[0].c_str()) != 0 ||
+         vec[0] == "pair" ||
+         vec[0] == "string"))
+    {
+      out = "std::";
+    }
+    out += vec[0];
+
+    // Now add the arguments.  Process each one recursively.
+    if (vec.size() > 1) {
+      out += "<";
+      for (size_t i = 1; i < vec.size(); i++) {
+        if (i > 1) out += ",";
+        out += addstd (vec[i]);
+      }
+      if (out[out.size()-1] == '>')
+        out += " ";
+      out += ">";
+    }
+    return out;
+  }
+}
+
+
+} // anonymous namespace
+
+
+namespace RootUtils {
+
+
+/**
+ * @brief Initialize.
+ *        Create an instance of this class and register it as a generator.
+ */
+void StdHackGenerator::Initialize()
+{
+  // Only do this once.
+  static bool initialized = false;
+  if (!initialized) {
+    initialized = true;
+    gROOT->AddClassGenerator (new StdHackGenerator);
+  }
+}
+
+
+/**
+ * @brief Look up a class by name.
+ * @param classname The name of the class to find.
+ * @param load If true, enable autoloading.
+ */
+TClass* StdHackGenerator::GetClass (const char* classname, Bool_t load)
+{
+  // Don't do anything if no autoloading.
+  if (!load)
+    return 0;
+
+  // Add any missing std::'s to the name.
+  std::string newname = addstd (classname);
+
+  // If it's different, retry the autoloading.
+  if (newname != classname && gInterpreter->AutoLoad (newname.c_str())) {
+    // From here, we're just copying what the root code does.
+    VoidFuncPtr_t dict = TClassTable::GetDict (newname.c_str());
+    if (!dict)
+      dict = TClassTable::GetDict (classname);
+    if (dict) {
+      (dict)();
+      return gROOT->GetClass (newname.c_str(), kFALSE);
+    }
+  }
+  return 0;
+}
+
+
+/**
+ * @brief Look up a class by @c type_info.
+ * @param typeinfo The @c type_info of the class to find.
+ * @param load If true, enable autoloading.
+ */
+TClass* StdHackGenerator::GetClass (const type_info& typeinfo, Bool_t load)
+{
+  // Just get the name and pass to the other overload.
+  return GetClass (typeinfo.name(), load);
+}
+
+
+} // namespace RootUtils