From 9dc3c03513bcbf5160480a0915ef28ed50954ed3 Mon Sep 17 00:00:00 2001
From: Danilo Piparo <danilo.piparo@cern.ch>
Date: Wed, 16 Jan 2019 16:43:43 +0100
Subject: [PATCH] [Core] Add TClass::GetClass<T> method to lower contention

The method TClass::GetClass<T> obtains the TClass instance pointer
corresponding to T in two ways, according to the nature of T.
If T inherits from or is TObject, the TClass* value is obtained via the
T::Class() static method, which locks only upon the first call.
If T is a generic type, internally the TClass::GetClass(type_info, ...)
method is called.

The new functionality is put to a good use by this commit in TBuffer
and TDirectoryFile.

It is worth noting how the usage of tag dispatching could be replaced
by 'if constexpr'.
---
 core/base/inc/TBuffer.h    | 14 ++++----------
 core/meta/inc/TClass.h     | 26 ++++++++++++++++++++++++++
 io/io/inc/TDirectoryFile.h |  2 +-
 3 files changed, 31 insertions(+), 11 deletions(-)

diff --git a/core/base/inc/TBuffer.h b/core/base/inc/TBuffer.h
index e764da8d9ab..d7470de3098 100644
--- a/core/base/inc/TBuffer.h
+++ b/core/base/inc/TBuffer.h
@@ -22,12 +22,12 @@
 //////////////////////////////////////////////////////////////////////////
 
 #include "TObject.h"
+#include "TClass.h"
 
 #include <vector>
 
 class TVirtualStreamerInfo;
 class TStreamerElement;
-class TClass;
 class TString;
 class TProcessID;
 class TClonesArray;
@@ -386,14 +386,14 @@ template <class Tmpl> TBuffer &operator>>(TBuffer &buf, Tmpl *&obj)
    // would not be sufficient to pass the information 'which class do we want'
    // since the pointer could be zero (so typeid(*obj) is not usable).
 
-   TClass *cl = TBuffer::GetClass(typeid(Tmpl));
+   auto cl = TClass::GetClass<Tmpl>();
    obj = (Tmpl *) ( (void*) buf.ReadObjectAny(cl) );
    return buf;
 }
 
 template <class Tmpl> TBuffer &operator<<(TBuffer &buf, const Tmpl *obj)
 {
-   TClass *cl = (obj) ? TBuffer::GetClass(typeid(*obj)) : 0;
+   auto cl = (obj) ? TClass::GetClass<Tmpl>() : nullptr;
    buf.WriteObjectAny(obj, cl);
    return buf;
 }
@@ -402,16 +402,10 @@ template <class Tmpl> TBuffer &operator>>(TBuffer &buf, Tmpl *&obj);
 template <class Tmpl> TBuffer &operator<<(TBuffer &buf, Tmpl *&obj);
 #endif
 
-#if defined(R__TEMPLATE_OVERLOAD_BUG)
-template <>
-#endif
-inline TBuffer &operator<<(TBuffer &buf, const TObject *obj)
-   { buf.WriteObjectAny(obj, TObject::Class()); return buf; }
-
 template <class T>
 inline Int_t TBuffer::WriteObject(const T *objptr, Bool_t cacheReuse)
 {
-   TClass *cl = (objptr) ? TBuffer::GetClass(typeid(T)) : 0;
+   auto cl = (objptr) ? TClass::GetClass<T>() : nullptr;
    return WriteObjectAny(objptr, cl, cacheReuse);
 }
 
diff --git a/core/meta/inc/TClass.h b/core/meta/inc/TClass.h
index be1c4d88b48..825f2fddccd 100644
--- a/core/meta/inc/TClass.h
+++ b/core/meta/inc/TClass.h
@@ -539,6 +539,8 @@ public:
    static TClass        *GetClass(const char *name, Bool_t load = kTRUE, Bool_t silent = kFALSE);
    static TClass        *GetClass(const std::type_info &typeinfo, Bool_t load = kTRUE, Bool_t silent = kFALSE);
    static TClass        *GetClass(ClassInfo_t *info, Bool_t load = kTRUE, Bool_t silent = kFALSE);
+   template<typename T>
+   static TClass        *GetClass(Bool_t load = kTRUE, Bool_t silent = kFALSE);
    static Bool_t         GetClass(DeclId_t id, std::vector<TClass*> &classes);
    static DictFuncPtr_t  GetDict (const char *cname);
    static DictFuncPtr_t  GetDict (const std::type_info &info);
@@ -572,6 +574,30 @@ public:
    ClassDef(TClass,0)  //Dictionary containing class information
 };
 
+namespace ROOT {
+namespace Internal {
+template <typename T>
+TClass *GetClassHelper(Bool_t, Bool_t, std::true_type)
+{
+   return T::Class();
+}
+
+template <typename T>
+TClass *GetClassHelper(Bool_t load, Bool_t silent, std::false_type)
+{
+   return TClass::GetClass(typeid(T), load, silent);
+}
+
+} // namespace Internal
+} // namespace ROOT
+
+template <typename T>
+TClass *TClass::GetClass(Bool_t load, Bool_t silent)
+{
+   typename std::is_base_of<TObject, T>::type tag;
+   return ROOT::Internal::GetClassHelper<T>(load, silent, tag);
+}
+
 namespace ROOT {
 
 template <typename T> TClass *GetClass(T * /* dummy */)       { return TClass::GetClass(typeid(T)); }
diff --git a/io/io/inc/TDirectoryFile.h b/io/io/inc/TDirectoryFile.h
index 919a0dec6a0..81e3b82f0e0 100644
--- a/io/io/inc/TDirectoryFile.h
+++ b/io/io/inc/TDirectoryFile.h
@@ -78,7 +78,7 @@ public:
    virtual TDirectory *GetDirectory(const char *apath, Bool_t printError = false, const char *funcname = "GetDirectory");
    template <class T> inline void GetObject(const char* namecycle, T*& ptr) // See TDirectory::Get for information
       {
-         ptr = (T*)GetObjectChecked(namecycle,TBuffer::GetClass(typeid(T)));
+         ptr = (T*)GetObjectChecked(namecycle,TClass::GetClass<T>());
       }
    virtual void       *GetObjectChecked(const char *namecycle, const char* classname);
    virtual void       *GetObjectChecked(const char *namecycle, const TClass* cl);
-- 
GitLab