Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
TOutputListSelectorDataMap.cxx
Go to the documentation of this file.
1 // @(#)root/proofplayer:$Id$
2 // Author: Axel Naumann, 2010-06-09
3 
4 /*************************************************************************
5  * Copyright (C) 1995-2010, 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 /** \class TOutputListSelectorDataMap
13 \ingroup proofkernel
14 
15 Set the selector's data members to the corresponding elements of the
16 output list.
17 
18 */
19 
21 
22 #include "TClass.h"
23 #include "TDataMember.h"
24 #include "TExMap.h"
25 #include "THashTable.h"
26 #include "TList.h"
27 #include "TMemberInspector.h"
28 #include "TProofDebug.h"
29 #include "TSelector.h"
30 
31 #include <cstddef>
32 
33 namespace {
34 
35  static TClass* IsSettableDataMember(TDataMember* dm) {
36  if (!dm || !dm->IsaPointer() || dm->IsBasic()) return 0;
37  TString dtTypeName = dm->GetFullTypeName();
38  if (!dtTypeName.EndsWith("*")) return 0;
39  dtTypeName.Remove(dtTypeName.Length()-1);
40  return TClass::GetClass(dtTypeName);
41  }
42 
43  class TSetSelDataMembers: public TMemberInspector {
44  public:
45  TSetSelDataMembers(const TOutputListSelectorDataMap& owner, TCollection* dmInfo, TList* output);
46  using TMemberInspector::Inspect;
47  void Inspect(TClass *cl, const char *parent, const char *name, const void *addr, Bool_t isTransient);
48  Ssiz_t GetNumSet() const { return fNumSet; }
49  private:
50  TCollection* fDMInfo; // output list object name / member name pairs for output list entries
51  TList* fOutputList; // merged output list
52  Ssiz_t fNumSet; // number of initialized data members
53  const TOutputListSelectorDataMap& fOwner; // owner, used for messaging
54  };
55 }
56 
57 ////////////////////////////////////////////////////////////////////////////////
58 
59 TSetSelDataMembers::TSetSelDataMembers(const TOutputListSelectorDataMap& owner,
60  TCollection* dmInfo, TList* output):
61  fDMInfo(dmInfo), fOutputList(output), fNumSet(0), fOwner(owner)
62 {}
63 
64 ////////////////////////////////////////////////////////////////////////////////
65 /// This method is called by the ShowMembers() method for each
66 /// data member to recursively collect all base classes' members.
67 ///
68 /// cl is the pointer to the current class
69 /// parent is the parent name (in case of composed objects)
70 /// name is the data member name
71 /// addr is the data member address
72 
73 void TSetSelDataMembers::Inspect(TClass *cl, const char* parent, const char *name, const void *addr, Bool_t /* isTransient */)
74 {
75  while (name[0] == '*') ++name;
76 
77  TObject* mapping = fDMInfo->FindObject(name);
78  if (!mapping) return;
79 
80  PDB(kOutput,1) fOwner.Info("SetDataMembers()",
81  "data member `%s%s::%s' maps to output list object `%s'",
82  cl->GetName(), parent, name, mapping->GetTitle());
83 
84  TObject* outputObj = fOutputList->FindObject(mapping->GetTitle());
85  if (!outputObj) {
86  PDB(kOutput,1) fOwner.Warning("SetDataMembers()",
87  "object `%s' not found in output list!",
88  mapping->GetTitle());
89  return;
90  }
91 
92  // Check data member type
93  TDataMember *dm = cl->GetDataMember(name);
94  TClass* cldt = IsSettableDataMember(dm);
95  if (!cldt) {
96  PDB(kOutput,1) fOwner.Warning("SetDataMembers()",
97  "unusable data member `%s' should have been detected by TCollectDataMembers!",
98  name);
99  return;
100  }
101 
102  char *pointer = (char*)addr;
103  char **ppointer = (char**)(pointer);
104  if (*ppointer) {
105  // member points to something - replace instead of delete to not crash on deleting uninitialized values.
106  fOwner.Warning("SetDataMembers()", "potential memory leak: replacing data member `%s' != 0. "
107  "Please initialize %s to 0 in constructor %s::%s()",
108  name, name, cl->GetName(), cl->GetName());
109  }
110  *ppointer = (char*)outputObj;
111  ++fNumSet;
112 }
113 
114 
115 namespace {
116  class TCollectDataMembers: public TMemberInspector {
117  public:
118  TCollectDataMembers(const TOutputListSelectorDataMap& owner): fOwner(owner) { }
119  ~TCollectDataMembers();
120  using TMemberInspector::Inspect;
121  void Inspect(TClass *cl, const char *parent, const char *name, const void *addr, Bool_t isTransient);
122  TExMap& GetMemberPointers() { return fMap; }
123  private:
124  TExMap fMap; //map of data member's value to TDataMember
125  const TOutputListSelectorDataMap& fOwner; //owner, used for messaging
126  };
127 }
128 
129 ////////////////////////////////////////////////////////////////////////////////
130 /// This method is called by the ShowMembers() method for each
131 /// data member to recursively collect all base classes' members.
132 ///
133 /// cl is the pointer to the current class
134 /// parent is the parent name (in case of composed objects)
135 /// name is the data member name
136 /// addr is the data member address
137 
138 void TCollectDataMembers::Inspect(TClass *cl, const char* /*parent*/, const char *name, const void *addr, Bool_t /* isTransient */)
139 {
140  TDataMember *dm = cl->GetDataMember(name);
141  if (!IsSettableDataMember(dm)) return;
142 
143  char *pointer = (char*)addr;
144  char **ppointer = (char**)(pointer);
145  char **p3pointer = (char**)(*ppointer);
146  if (p3pointer) {
147  // The data member points to something.
148  // Handle multiple pointers to the same output list object:
149  TObject* prev = (TObject*) (ptrdiff_t)fMap.GetValue((Long64_t)(ptrdiff_t)p3pointer);
150  if (prev) {
151  // We have a previous entry - is it a data member or already a TList (of data members)?
152  if (prev->InheritsFrom(TDataMember::Class())) {
153  fMap.Remove((Long64_t)(ptrdiff_t)p3pointer);
154  TList* dmList = new TList;
155  dmList->Add(prev);
156  dmList->Add(dm);
157  fMap.Add((Long64_t)(ptrdiff_t)p3pointer, (Long64_t)(ptrdiff_t)dmList);
158  } else {
159  TList* prevList = (TList*) prev;
160  prevList->Add(dm);
161  }
162  } else {
163  fMap.Add((Long64_t)(ptrdiff_t)p3pointer, (Long64_t)(ptrdiff_t)dm);
164  }
165  if (name[0] == '*') ++name;
166  PDB(kOutput,1) fOwner.Info("Init()", "considering data member `%s'", name);
167  }
168 }
169 
170 TCollectDataMembers::~TCollectDataMembers() {
171  // Destructor
172 
173  // Clean up collection of TDataMembers in fMap
174  TExMapIter iMembers(&fMap);
175  Long64_t key;
176  Long64_t value;
177  while (iMembers.Next(key, value)) {
178  TObject* obj = (TObject*) (ptrdiff_t) value;
179  if (obj->InheritsFrom(TList::Class())) {
180  delete obj;
181  }
182  }
183 }
184 
185 ClassImp(TOutputListSelectorDataMap);
186 
187 ////////////////////////////////////////////////////////////////////////////////
188 /// Create a mapper between output list items and TSelector data members.
189 
190 TOutputListSelectorDataMap::TOutputListSelectorDataMap(TSelector* sel /*= 0*/):
191  fMap(0)
192 {
193  if (sel) Init(sel);
194 }
195 
196 ////////////////////////////////////////////////////////////////////////////////
197 /// Return static name for TOutputListSelectorDataMap objects.
198 
199 const char* TOutputListSelectorDataMap::GetName() const
200 {
201  return "PROOF_TOutputListSelectorDataMap_object";
202 }
203 
204 ////////////////////////////////////////////////////////////////////////////////
205 /// Initialize the data member <-> output list mapping from a selector.
206 
207 Bool_t TOutputListSelectorDataMap::Init(TSelector* sel)
208 {
209  if (!sel) {
210  PDB(kOutput,1) Warning("Init","Leave (no selector!)");
211  return kFALSE;
212  }
213  TCollection* outList = sel->GetOutputList();
214  if (!outList) {
215  PDB(kOutput,1) Info("Init()","Leave (no output)");
216  return kFALSE;
217  }
218 
219  if (outList->FindObject(GetName())) {
220  // mapping already exists?!
221  PDB(kOutput,1) Warning("Init","Mapping already exists!");
222  return kFALSE;
223  }
224 
225  if (fMap) delete fMap;
226  fMap = new THashTable;
227  fMap->SetOwner();
228 
229  TCollectDataMembers cdm(*this);
230  if (!sel->IsA()->CallShowMembers(sel, cdm)) {
231  // failed to map
232  PDB(kOutput,1) Warning("Init","Failed to determine mapping!");
233  return kFALSE;
234  }
235  PDB(kOutput,1) Info("Init()","Found %d data members.",
236  cdm.GetMemberPointers().GetSize());
237 
238  // Iterate over output list entries and find data members pointing to the
239  // same value. Store that mapping (or a miss).
240  TIter iOutput(outList);
241  TObject* output;
242  TList oneDM;
243  while ((output = iOutput())) {
244  TObject* obj = (TObject*) (ptrdiff_t)cdm.GetMemberPointers().GetValue((Long64_t)(ptrdiff_t)output);
245  if (!obj) continue;
246 
247  TList* addAllDM = 0;
248  if (obj->InheritsFrom(TDataMember::Class())) {
249  oneDM.Add(obj);
250  addAllDM = &oneDM;
251  } else {
252  addAllDM = (TList*) obj;
253  }
254  TIter iDM(addAllDM);
255  TDataMember* dm = 0;
256  while ((dm = (TDataMember*) iDM())) {
257  fMap->Add(new TNamed(dm->GetName(), output->GetName()));
258  PDB(kOutput,1) Info("Init()","Data member `%s' corresponds to output `%s'",
259  dm->GetName(), output->GetName());
260  }
261  oneDM.Clear();
262  }
263 
264  return kTRUE;
265 }
266 
267 ////////////////////////////////////////////////////////////////////////////////
268 /// Given an output list, set the data members of a TSelector.
269 
270 Bool_t TOutputListSelectorDataMap::SetDataMembers(TSelector* sel) const
271 {
272  TList* output = sel->GetOutputList();
273  if (!output || output->IsEmpty()) return kTRUE;
274 
275  // Set fSelector's data members
276  TSetSelDataMembers ssdm(*this, fMap, output);
277  Bool_t res = sel->IsA()->CallShowMembers(sel, ssdm);
278  PDB(kOutput,1) Info("SetDataMembers()","%s, set %d data members.",
279  (res ? "success" : "failure"), ssdm.GetNumSet());
280  return res;
281 }
282 
283 ////////////////////////////////////////////////////////////////////////////////
284 /// Merge another TOutputListSelectorDataMap object, check
285 /// consistency.
286 
287 Bool_t TOutputListSelectorDataMap::Merge(TObject* obj)
288 {
289  TOutputListSelectorDataMap* other = dynamic_cast<TOutputListSelectorDataMap*>(obj);
290  if (!other) return kFALSE;
291 
292  // check for consistency
293  TIter iMapping(other->GetMap());
294  TNamed* mapping = 0;
295  while ((mapping = (TNamed*)iMapping())) {
296  TObject* oldMap = fMap->FindObject(mapping->GetName());
297  if (!oldMap) {
298  fMap->Add(new TNamed(*mapping));
299  } else {
300  if (strcmp(oldMap->GetTitle(), mapping->GetTitle())) {
301  // ouch, contradicting maps!
302  PDB(kOutput,1)
303  Warning("Merge()",
304  "contradicting mapping for data member `%s' (output list entry `%s' vs. `%s'). "
305  "Cancelling automatic TSelector data member setting!",
306  mapping->GetName(), oldMap->GetTitle(), mapping->GetTitle());
307  fMap->Clear();
308  return kFALSE;
309  }
310  }
311  }
312  return kTRUE;
313 }
314 
315 ////////////////////////////////////////////////////////////////////////////////
316 /// Find a TOutputListSelectorDataMap in a collection
317 
318 TOutputListSelectorDataMap* TOutputListSelectorDataMap::FindInList(TCollection* coll)
319 {
320  TIter iOutput(coll);
321  TObject* out = 0;
322  TOutputListSelectorDataMap* olsdm = 0;
323  while ((out = iOutput())) {
324  if (out->InheritsFrom(TOutputListSelectorDataMap::Class())) {
325  olsdm = dynamic_cast<TOutputListSelectorDataMap*>(out);
326  if (olsdm) break;
327  }
328  }
329  return olsdm;
330 }