Logo ROOT   6.14/05
Reference Guide
TIsAProxy.cxx
Go to the documentation of this file.
1 // @(#)root/meta:$Id$
2 // Author: Markus Frank 20/05/2005
3 
4 /*************************************************************************
5 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers. *
6 * All rights reserved. *
7 * *
8 * For the licensing terms see $ROOTSYS/LICENSE. *
9 * For the list of contributors see $ROOTSYS/README/CREDITS. *
10 *************************************************************************/
11 
12 #include "TClass.h"
13 #include "TError.h"
14 #include "TInterpreter.h"
15 #include "TIsAProxy.h"
16 
17 #include <map>
18 #include <type_traits>
19 
20 /** \class TIsAProxy
21 TIsAProxy implementation class.
22 */
23 
24 namespace {
25  struct DynamicType {
26  // Helper class to enable typeid on any address
27  // Used in code similar to:
28  // typeid( * (DynamicType*) void_ptr );
29  virtual ~DynamicType() {}
30  };
31 
32  typedef std::map<const void*, TClass*> ClassMap_t; // Internal type map
33  inline ClassMap_t *GetMap(const void* p)
34  {
35  return (ClassMap_t*)p;
36  }
37 
38  inline ClassMap_t::value_type* ToPair(void*p)
39  {
40  return (ClassMap_t::value_type*)p;
41  }
42 }
43 
44 ////////////////////////////////////////////////////////////////////////////////
45 /// Standard initializing constructor
46 
47 TIsAProxy::TIsAProxy(const std::type_info& typ)
48  : fType(&typ), fClass(nullptr), fLast(nullptr),
49  fSubTypesReaders(0), fSubTypesWriteLockTaken(kFALSE),
50  fVirtual(kFALSE), fInit(kFALSE)
51 {
52  static_assert(sizeof(ClassMap_t)<=sizeof(fSubTypes), "ClassMap size is to large for array");
53 
54  ::new(fSubTypes) ClassMap_t();
55 }
56 
57 ////////////////////////////////////////////////////////////////////////////////
58 /// Standard destructor
59 
61 {
62  ClassMap_t* m = GetMap(fSubTypes);
63  m->clear();
64  m->~ClassMap_t();
65 }
66 
67 ////////////////////////////////////////////////////////////////////////////////
68 /// Set class pointer
69 /// This method is not thread safe
70 
72 {
73  GetMap(fSubTypes)->clear();
74  fClass = cl;
75  fLast = nullptr;
76 }
77 
78 ////////////////////////////////////////////////////////////////////////////////
79 /// IsA callback
80 
81 TClass* TIsAProxy::operator()(const void *obj)
82 {
83  if ( !fInit ) {
84  if ( !fClass.load() && fType ) {
85  auto cls = TClass::GetClass(*fType);
86  TClass* expected = nullptr;
87  fClass.compare_exchange_strong(expected,cls);
88  }
89  if ( !fClass.load() ) return nullptr;
90  fVirtual = (*fClass).ClassProperty() & kClassHasVirtual;
91  fInit = kTRUE;
92  }
93  if ( !obj || !fVirtual ) {
94  return fClass.load();
95  }
96  // Avoid the case that the first word is a virtual_base_offset_table instead of
97  // a virtual_function_table
98  Long_t offset = **(Long_t**)obj;
99  if ( offset == 0 ) {
100  return fClass.load();
101  }
102 
103  DynamicType* ptr = (DynamicType*)obj;
104  const std::type_info* typ = &typeid(*ptr);
105 
106  if ( typ == fType ) {
107  return fClass.load();
108  }
109  auto last = ToPair(fLast.load());
110  if ( last && typ == last->first ) {
111  return last->second;
112  }
113  // Check if type is already in sub-class cache
114  last = ToPair(FindSubType(typ));
115  if ( last == nullptr || last->second == nullptr ) {
116  // Last resort: lookup root class
117  auto cls = TClass::GetClass(*typ);
118  last = ToPair(CacheSubType(typ,cls));
119  }
120  fLast.store(last);
121 
122  return last == nullptr? nullptr: last->second;
123 }
124 
125 ////////////////////////////////////////////////////////////////////////////////
126 /// See if we have already cached the TClass that correspond to this std::type_info.
127 
128 inline void* TIsAProxy::FindSubType(const std::type_info* type) const
129 {
130  bool needToWait = kTRUE;
131  do {
133 
134  //See if there is a writer, if there is we need to release
135  // our reader count so that the writer can proceed
138  while(fSubTypesWriteLockTaken) {}
139  } else {
140  needToWait = kFALSE;
141  }
142  } while(needToWait);
143 
144  void* returnValue = nullptr;
145  auto const map = GetMap(fSubTypes);
146 
147  auto found = map->find(type);
148  if(found != map->end()) {
149  returnValue = &(*found);
150  }
152  return returnValue;
153 }
154 
155 ////////////////////////////////////////////////////////////////////////////////
156 /// Record the TClass found for a std::type_info, so that we can retrieved it faster.
157 
158 void* TIsAProxy::CacheSubType(const std::type_info* type, TClass* cls)
159 {
160  //See if another thread has the write lock, wait if it does
161  Bool_t expected = kFALSE;
162  while(! fSubTypesWriteLockTaken.compare_exchange_strong(expected,kTRUE) ) {
163  expected = kFALSE;
164  };
165 
166  //See if there are any readers
167  while(fSubTypesReaders > 0);
168 
169  auto map = GetMap(fSubTypes);
170  auto ret = map->emplace(type,cls);
171  if (!ret.second) {
172  // type is already in the map, let's update it.
173  (*ret.first).second = cls;
174  }
175 
177  return &(*(ret.first));
178 }
virtual ~TIsAProxy()
Standard destructor.
Definition: TIsAProxy.cxx:60
Atomic_t< TClass * > fClass
Definition: TIsAProxy.h:32
auto * m
Definition: textangle.C:8
TIsAProxy(const TIsAProxy &)=delete
void * FindSubType(const std::type_info *) const
See if we have already cached the TClass that correspond to this std::type_info.
Definition: TIsAProxy.cxx:128
bool Bool_t
Definition: RtypesCore.h:59
Bool_t fVirtual
Definition: TIsAProxy.h:37
static constexpr double second
virtual TClass * operator()(const void *obj)
IsA callback.
Definition: TIsAProxy.cxx:81
Atomic_t< Bool_t > fSubTypesWriteLockTaken
Definition: TIsAProxy.h:36
Atomic_t< Bool_t > fInit
Definition: TIsAProxy.h:38
The ROOT global object gROOT contains a list of all defined classes.
Definition: TClass.h:75
const Bool_t kFALSE
Definition: RtypesCore.h:88
const std::type_info * fType
Definition: TIsAProxy.h:31
PyObject * fType
long Long_t
Definition: RtypesCore.h:50
Atomic_t< UInt_t > fSubTypesReaders
Definition: TIsAProxy.h:35
int type
Definition: TGX11.cxx:120
virtual void SetClass(TClass *cl)
Set class pointer This method is not thread safe.
Definition: TIsAProxy.cxx:71
Char_t fSubTypes[72]
Definition: TIsAProxy.h:34
static TClass * GetClass(const char *name, Bool_t load=kTRUE, Bool_t silent=kFALSE)
Static method returning pointer to TClass of the specified class name.
Definition: TClass.cxx:2887
Atomic_t< void * > fLast
Definition: TIsAProxy.h:33
const Bool_t kTRUE
Definition: RtypesCore.h:87
void * CacheSubType(const std::type_info *, TClass *)
Record the TClass found for a std::type_info, so that we can retrieved it faster. ...
Definition: TIsAProxy.cxx:158