Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
TContainerConverters.cxx
Go to the documentation of this file.
1 // @(#)root/io:$Id: 56ae10c519627872e1dd40872fd459c2dd89acf6 $
2 // Author: Philippe Canal 11/11/2004
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 //////////////////////////////////////////////////////////////////////////
13 // //
14 // Helper classes to convert collection from ROOT collection to STL //
15 // collections //
16 // //
17 //////////////////////////////////////////////////////////////////////////
18 
19 /**
20  \class TConvertClonesArrayToProxy TContainerConverters.cxx
21  \ingroup IO
22 
23  Small helper to read a TBuffer containing a TClonesArray into any valid
24  collection.
25 */
26 
27 #include "TContainerConverters.h"
28 #include "TClonesArray.h"
29 #include "TStreamerInfo.h"
31 #include "TError.h"
32 #include "TGenCollectionStreamer.h"
33 #include "TClassStreamer.h"
34 #include <stdlib.h>
35 
36 namespace {
37  const Int_t kMapOffset = 2;
38 }
39 
40 ////////////////////////////////////////////////////////////////////////////////
41 /// Constructor.
42 
43 TConvertClonesArrayToProxy::TConvertClonesArrayToProxy(
44  TVirtualCollectionProxy *proxy,
45  Bool_t isPointer, Bool_t isPrealloc) :
46  fIsPointer(isPointer),
47  fIsPrealloc(isPrealloc),
48  fCollectionClass(proxy?proxy->GetCollectionClass():0)
49 {
50  if (isPointer) fOffset = sizeof(TClonesArray*);
51  else fOffset = sizeof(TClonesArray);
52 }
53 
54 ////////////////////////////////////////////////////////////////////////////////
55 /// Destructor.
56 
57 TConvertClonesArrayToProxy::~TConvertClonesArrayToProxy()
58 {
59 }
60 
61 ////////////////////////////////////////////////////////////////////////////////
62 /// Read a TClonesArray from the TBuffer b and load it into a (stl) collection
63 
64 void TConvertClonesArrayToProxy::operator()(TBuffer &b, void *pmember, Int_t size)
65 {
66  // For thread-safety we need to go through TClass::GetCollectionProxy
67  // to get a thread local proxy.
68  TVirtualCollectionProxy *proxy = fCollectionClass->GetCollectionProxy();
69  TStreamerInfo *subinfo = (TStreamerInfo*)proxy->GetValueClass()->GetStreamerInfo();
70  R__ASSERT(subinfo);
71 
72  Int_t nobjects, dummy;
73  char nch;
74  TString s;
75  char classv[256];
76  void *env;
77  UInt_t start, bytecount;
78 
79  R__ASSERT(b.IsReading());
80 
81  Bool_t needAlloc = fIsPointer && !fIsPrealloc;
82 
83  if (needAlloc) {
84  char *addr = (char*)pmember;
85  for(Int_t k=0; k<size; ++k, addr += fOffset ) {
86  if (*(void**)addr && TStreamerInfo::CanDelete()) {
87  proxy->GetValueClass()->Destructor(*(void**)addr,kFALSE); // call delete and desctructor
88  }
89  //*(void**)addr = proxy->New();
90  //TClonesArray *clones = (TClonesArray*)ReadObjectAny(TClonesArray::Class());
91  }
92  }
93 
94  char *addr = (char*)pmember;
95  if (size==0) size=1;
96  for(Int_t k=0; k<size; ++k, addr += fOffset ) {
97 
98  if (needAlloc) {
99  // Read the class name.
100 
101  // make sure fMap is initialized
102  b.InitMap();
103 
104  // before reading object save start position
105  UInt_t startpos = b.Length();
106 
107  // attempt to load next object as TClass clCast
108  UInt_t tag; // either tag or byte count
109  TClass *clRef = b.ReadClass(TClonesArray::Class(), &tag);
110 
111  if (clRef==0) {
112  // Got a reference to an already read object.
113  if (b.GetBufferVersion() > 0) {
114  tag += b.GetBufferDisplacement();
115  } else {
116  if (tag > (UInt_t)b.GetMapCount()) {
117  Error("TConvertClonesArrayToProxy", "object tag too large, I/O buffer corrupted");
118  return;
119  }
120  }
121  void *objptr;
122  b.GetMappedObject( tag, objptr, clRef);
123  if ( objptr == (void*)-1 ) {
124  Error("TConvertClonesArrayToProxy",
125  "Object can not be found in the buffer's map (at %d)",tag);
126  continue;
127  }
128  if ( objptr == 0 ) {
129  if (b.GetBufferVersion()==0) continue;
130 
131  // No object found at this location in map. It might have been skipped
132  // as part of a skipped object. Try to explicitly read the object.
133  b.MapObject(*(void**)addr, fCollectionClass, 0);
134  Int_t currentpos = b.Length();
135  b.SetBufferOffset( tag - kMapOffset );
136 
137  (*this)(b,&objptr,1);
138  b.SetBufferOffset( currentpos);
139 
140  if (objptr==0) continue;
141 
142  clRef = fCollectionClass;
143 
144  }
145  R__ASSERT(clRef);
146  if (clRef==TClonesArray::Class()) {
147  Error("TConvertClonesArrayToProxy",
148  "Object refered to has not been converted from TClonesArray to %s",
149  fCollectionClass->GetName());
150  continue;
151  } else if (clRef!=fCollectionClass) {
152  Error("TConvertClonesArrayToProxy",
153  "Object refered to is of type %s instead of %s",
154  clRef->GetName(),fCollectionClass->GetName());
155  continue;
156  }
157  *(void**)addr = objptr;
158  continue;
159 
160  } else if (clRef != TClonesArray::Class()) {
161  Warning("TConvertClonesArrayToProxy",
162  "Only the TClonesArray part of %s will be read into %s!\n",
163  (clRef!=((TClass*)-1)&&clRef) ? clRef->GetName() : "N/A",
164  fCollectionClass->GetName());
165  } else {
166  *(void**)addr = proxy->New();
167  if (b.GetBufferVersion()>0) {
168  b.MapObject(*(void**)addr, fCollectionClass, startpos+kMapOffset);
169  } else {
170  b.MapObject(*(void**)addr, fCollectionClass, b.GetMapCount() );
171  }
172  }
173  }
174  void *obj;
175  if (fIsPointer) obj = *(void**)addr;
176  else obj = addr;
177 
178  TObject objdummy;
179  Version_t v = b.ReadVersion(&start, &bytecount);
180 
181  //if (v == 3) {
182  // const int_t koldbypassstreamer = bit(14);
183  // if (testbit(koldbypassstreamer)) bypassstreamer();
184  //}
185  if (v > 2) objdummy.Streamer(b);
186  TString fName;
187  if (v > 1) fName.Streamer(b);
188  s.Streamer(b);
189  strncpy(classv,s.Data(),255);
190  //Int_t clv = 0;
191  char *semicolon = strchr(classv,';');
192  if (semicolon) {
193  *semicolon = 0;
194  //clv = atoi(semicolon+1);
195  }
196  TClass *cl = TClass::GetClass(classv);
197  if (!cl) {
198  printf("TClonesArray::Streamer expecting class %s\n", classv);
199  b.CheckByteCount(start, bytecount, TClonesArray::Class());
200  return;
201  }
202 
203  b >> nobjects;
204  if (nobjects < 0) nobjects = -nobjects; // still there for backward compatibility
205  b >> dummy; // fLowerBound is ignored
206  if (cl != subinfo->GetClass()) {
207  Error("TClonesArray::Conversion to vector","Bad class");
208  }
209  TVirtualCollectionProxy::TPushPop helper( proxy, obj );
210  env = proxy->Allocate(nobjects,true);
211 
212  if (objdummy.TestBit(TClonesArray::kBypassStreamer)) {
213 
214  subinfo->ReadBufferSTL(b,proxy,nobjects,0);
215 
216  } else {
217  for (Int_t i = 0; i < nobjects; i++) {
218  b >> nch;
219  if (nch) {
220  void* elem = proxy->At(i);
221  b.StreamObject(elem,subinfo->GetClass());
222  }
223  }
224  }
225  proxy->Commit(env);
226  b.CheckByteCount(start, bytecount,TClonesArray::Class());
227  }
228 }
229 
230 ////////////////////////////////////////////////////////////////////////////////
231 /// Constructor.
232 
233 TConvertMapToProxy::TConvertMapToProxy(TClassStreamer *streamer,
234  Bool_t isPointer, Bool_t isPrealloc) :
235  fIsPointer(isPointer),
236  fIsPrealloc(isPrealloc),
237  fSizeOf(0),
238  fCollectionClass(0)
239 {
240  TCollectionClassStreamer *middleman = dynamic_cast<TCollectionClassStreamer*>(streamer);
241  if (middleman) {
242  TVirtualCollectionProxy *proxy = middleman->GetXYZ();
243  TGenCollectionStreamer *collStreamer = dynamic_cast<TGenCollectionStreamer*>(proxy);
244 
245  fCollectionClass = proxy->GetCollectionClass();
246 
247  if (isPointer) fSizeOf = sizeof(void*);
248  else fSizeOf = fCollectionClass->Size();
249 
250  if (proxy->GetValueClass()->GetStreamerInfo() == 0
251  || proxy->GetValueClass()->GetStreamerInfo()->GetElements()->At(1) == 0 ) {
252  // We do not have enough information on the pair (or its not a pair).
253  collStreamer = 0;
254  }
255  if (!collStreamer) fCollectionClass = 0;
256  }
257 }
258 
259 
260 
261 ////////////////////////////////////////////////////////////////////////////////
262 /// Read a std::map or std::multimap from the TBuffer b and load it into a (stl) collection
263 
264 void TConvertMapToProxy::operator()(TBuffer &b, void *pmember, Int_t size)
265 {
266  R__ASSERT(b.IsReading());
267  R__ASSERT(fCollectionClass);
268 
269  // For thread-safety we need to go through TClass::GetStreamer
270  // to get a thread local proxy.
271  TCollectionClassStreamer *middleman = dynamic_cast<TCollectionClassStreamer*>(fCollectionClass->GetStreamer());
272  TVirtualCollectionProxy *proxy = middleman->GetXYZ();
273  TGenCollectionStreamer *collStreamer = dynamic_cast<TGenCollectionStreamer*>(proxy);
274 
275  Bool_t needAlloc = fIsPointer && !fIsPrealloc;
276 
277  R__ASSERT(!needAlloc); // not yet implemented
278 
279  if (needAlloc) {
280  char *addr = (char*)pmember;
281  for(Int_t k=0; k<size; ++k, addr += fSizeOf ) {
282  if (*(void**)addr && TStreamerInfo::CanDelete()) {
283  proxy->GetValueClass()->Destructor(*(void**)addr,kFALSE); // call delete and desctructor
284  }
285  //*(void**)addr = proxy->New();
286  //TClonesArray *clones = (TClonesArray*)ReadObjectAny(TClonesArray::Class());
287  }
288  }
289 
290 
291  char *addr = (char*)pmember;
292  if (size==0) size=1;
293  for(Int_t k=0; k<size; ++k, addr += fSizeOf) {
294 
295  if (needAlloc) {
296 
297  // Read the class name.
298 
299  }
300 
301  void *obj;
302  if (fIsPointer) obj = *(void**)addr;
303  else obj = addr;
304 
305  TVirtualCollectionProxy::TPushPop env(proxy, obj);
306  collStreamer->StreamerAsMap(b);
307 
308  }
309 }