Logo ROOT   6.18/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
21TIsAProxy implementation class.
22*/
23
24namespace {
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
47TIsAProxy::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
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
128inline 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
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
158void* 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}
PyObject * fType
const Bool_t kFALSE
Definition: RtypesCore.h:88
long Long_t
Definition: RtypesCore.h:50
bool Bool_t
Definition: RtypesCore.h:59
const Bool_t kTRUE
Definition: RtypesCore.h:87
@ kClassHasVirtual
Definition: TDictionary.h:137
int type
Definition: TGX11.cxx:120
TClass instances represent classes, structs and namespaces in the ROOT type system.
Definition: TClass.h:75
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:2895
Atomic_t< UInt_t > fSubTypesReaders
Definition: TIsAProxy.h:35
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
virtual void SetClass(TClass *cl)
Set class pointer This method is not thread safe.
Definition: TIsAProxy.cxx:71
virtual ~TIsAProxy()
Standard destructor.
Definition: TIsAProxy.cxx:60
Atomic_t< void * > fLast
Definition: TIsAProxy.h:33
Char_t fSubTypes[72]
Definition: TIsAProxy.h:34
virtual TClass * operator()(const void *obj)
IsA callback.
Definition: TIsAProxy.cxx:81
const std::type_info * fType
Definition: TIsAProxy.h:31
Atomic_t< Bool_t > fSubTypesWriteLockTaken
Definition: TIsAProxy.h:36
Bool_t fVirtual
Definition: TIsAProxy.h:37
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
Atomic_t< Bool_t > fInit
Definition: TIsAProxy.h:38
Atomic_t< TClass * > fClass
Definition: TIsAProxy.h:32
TIsAProxy(const TIsAProxy &)=delete
static constexpr double second
auto * m
Definition: textangle.C:8