Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
TXMLPlayer.cxx
Go to the documentation of this file.
1// @(#)root/xml:$Id$
2// Author: Sergey Linev, Rene Brun 10.05.2004
3
4/*************************************************************************
5 * Copyright (C) 1995-2004, 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// Class for xml code generation
15// It should be used for generation of xml streamers, which could be used outside root
16// environment. This means, that with help of such streamers user can read and write
17// objects from/to xml file, which later can be accepted by ROOT.
18//
19// At the moment supported only classes, which are not inherited from TObject
20// and which not contains any TObject members.
21//
22// To generate xml code:
23//
24// 1. ROOT library with required classes should be created.
25// In general, without such library non of user objects can be stored and
26// retrieved from any ROOT file
27//
28// 2. Generate xml streamers by root script like:
29//
30// void generate() {
31// gSystem->Load("libRXML.so"); // load ROOT xml library
32// gSystem->Load("libuser.so"); // load user ROOT library
33//
34// TList lst;
35// lst.Add(TClass::GetClass("TUserClass1"));
36// lst.Add(TClass::GetClass("TUserClass2"));
37// ...
38// TXMLPlayer player;
39// player.ProduceCode(&lst, "streamers"); // create xml streamers
40// }
41//
42// 3. Copy "streamers.h", "streamers.cxx", "TXmlFile.h", "TXmlFile.cxx" files
43// to user project and compile them. TXmlFile class implementation can be taken
44// from http://web-docs.gsi.de/~linev/xmlfile.tar.gz
45//
46// TXMLPlayer class generates one function per class, which called class streamer.
47// Name of such function for class TExample will be TExample_streamer.
48//
49// Following data members for streamed classes are supported:
50// - simple data types (int, double, float)
51// - array of simple types (int[5], double[5][6])
52// - dynamic array of simple types (int* with comment field // [fSize])
53// - const char*
54// - object of any nonROOT class
55// - pointer on object
56// - array of objects
57// - array of pointers on objects
58// - stl string
59// - stl vector, list, deque, set, multiset, map, multimap
60// - allowed arguments for stl containers are: simple data types, string, object, pointer on object
61// Any other data member can not be (yet) read from xml file and write to xml file.
62//
63// If data member of class is private or protected, it can not be accessed via
64// member name. Two alternative way is supported. First, if for class member fValue
65// exists function GetValue(), it will be used to get value from the class, and if
66// exists SetValue(), it will be used to set appropriate data member. Names of setter
67// and getter methods can be specified in comments filed like:
68//
69// int fValue; // *OPTION={GetMethod="GetV";SetMethod="SetV"}
70//
71// If getter or setter methods does not available, address to data member will be
72// calculated as predefined offset to object start address. In that case generated code
73// should be used only on the same platform (OS + compiler), where it was generated.
74//
75// Generated streamers resolve inheritance tree for given class. This allows to have
76// array (or vector) of object pointers on some basic class, while objects of derived
77// class(es) are used.
78//
79// To access data from xml files, user should use TXmlFile class, which is different from
80// ROOT TXMLFile, but provides very similar functionality. For example, to read
81// object from xml file:
82//
83// TXmlFile file("test.xml"); // open xml file
84// file.ls(); // show list of keys in file
85// TExample* ex1 = (TExample*) file.Get("ex1", TExample_streamer); // get object
86// file.Close();
87//
88// To write object to file:
89//
90// TXmlFile outfile("test2.xml", "recreate"); // create xml file
91// TExample* ex1 = new TExample;
92// outfile.Write(ex1, "ex1", TExample_streamer); // write object to file
93// outfile.Close();
94//
95// Complete example for generating and using of external xml streamers can be taken from
96// http://www-docs.gsi.de/~linev/xmlreader.tar.gz
97//
98// Any bug reports and requests for additional functionality are welcome.
99//
100// Sergey Linev, S.Linev@gsi.de
101//
102//________________________________________________________________________
103
104#include "TXMLPlayer.h"
105
106#include "TROOT.h"
107#include "TList.h"
108#include "TClass.h"
109#include "TVirtualStreamerInfo.h"
110#include "TStreamerElement.h"
111#include "TObjArray.h"
112#include "TDataMember.h"
113#include "TMethod.h"
114#include "TDataType.h"
115#include "TMethodCall.h"
117#include "TClassEdit.h"
118#include "strlcpy.h"
119#include <iostream>
120#include <fstream>
121#include <string>
122#include <vector>
123
124const char *tab1 = " ";
125const char *tab2 = " ";
126const char *tab3 = " ";
127const char *tab4 = " ";
128
129const char *names_xmlfileclass = "TXmlFile";
130
131
132////////////////////////////////////////////////////////////////////////////////
133/// default constructor
134
138
139////////////////////////////////////////////////////////////////////////////////
140/// destructor of TXMLPlayer object
141
145
146////////////////////////////////////////////////////////////////////////////////
147/// returns streamer function name for given class
148
150{
151 if (!cl)
152 return "";
153 TString res = cl->GetName();
154 res += "_streamer";
155 return res;
156}
157
158////////////////////////////////////////////////////////////////////////////////
159/// Produce streamers for provide class list
160/// TList should include list of classes, for which code should be generated.
161/// filename specify name of file (without extension), where streamers should be
162/// created. Function produces two files: header file and source file.
163/// For instance, if filename is "streamers", files "streamers.h" and "streamers.cxx"
164/// will be created.
165
167{
168 if (!cllist || !filename)
169 return kFALSE;
170
171 std::ofstream fh(TString(filename) + ".h");
172 std::ofstream fs(TString(filename) + ".cxx");
173
174 fh << "// generated header file" << std::endl << std::endl;
175 fh << "#ifndef " << filename << "_h" << std::endl;
176 fh << "#define " << filename << "_h" << std::endl << std::endl;
177
178 fh << "#include \"" << names_xmlfileclass << ".h\"" << std::endl << std::endl;
179
180 fs << "// generated source file" << std::endl << std::endl;
181 fs << "#include \"" << filename << ".h\"" << std::endl << std::endl;
182
183 // produce appropriate include for all classes
184
186 TIter iter(cllist);
187 TClass *cl = nullptr;
188 while ((cl = (TClass *)iter()) != nullptr) {
189 if (!inclfiles.FindObject(cl->GetDeclFileName())) {
190 fs << "#include \"" << cl->GetDeclFileName() << "\"" << std::endl;
191 inclfiles.Add(new TNamed(cl->GetDeclFileName(), ""));
192 }
193 }
194 inclfiles.Delete();
195
196 fh << std::endl;
197 fs << std::endl;
198
199 // produce streamers declarations and implementations
200
201 iter.Reset();
202
203 while ((cl = (TClass *)iter()) != nullptr) {
204
205 fh << "extern void* " << GetStreamerName(cl) << "(" << names_xmlfileclass
206 << " &buf, void* ptr = 0, bool checktypes = true);" << std::endl
207 << std::endl;
208
210 }
211
212 fh << "#endif" << std::endl << std::endl;
213 fs << std::endl << std::endl;
214
215 return kTRUE;
216}
217
218////////////////////////////////////////////////////////////////////////////////
219/// returns name of simple data type for given data member
220
222{
223 if (!member)
224 return "int";
225
226 if (member->IsBasic())
227 switch (member->GetDataType()->GetType()) {
228 case kChar_t: return "char";
229 case kShort_t: return "short";
230 case kInt_t: return "int";
231 case kLong_t: return "long";
232 case kLong64_t: return "long long";
233 case kFloat16_t:
234 case kFloat_t: return "float";
235 case kDouble32_t:
236 case kDouble_t: return "double";
237 case kUChar_t: {
238 char first = member->GetDataType()->GetTypeName()[0];
239 if ((first == 'B') || (first == 'b'))
240 return "bool";
241 return "unsigned char";
242 }
243 case kBool_t: return "bool";
244 case kUShort_t: return "unsigned short";
245 case kUInt_t: return "unsigned int";
246 case kULong_t: return "unsigned long";
247 case kULong64_t: return "unsigned long long";
248 }
249
250 if (member->IsEnum())
251 return "int";
252
253 return member->GetTypeName();
254}
255
256////////////////////////////////////////////////////////////////////////////////
257/// return simple data types for given TStreamerElement object
258
260{
261 if (el->GetType() == TVirtualStreamerInfo::kCounter)
262 return "int";
263
264 switch (el->GetType() % 20) {
265 case TVirtualStreamerInfo::kChar: return "char";
266 case TVirtualStreamerInfo::kShort: return "short";
267 case TVirtualStreamerInfo::kInt: return "int";
268 case TVirtualStreamerInfo::kLong: return "long";
269 case TVirtualStreamerInfo::kLong64: return "long long";
271 case TVirtualStreamerInfo::kFloat: return "float";
273 case TVirtualStreamerInfo::kDouble: return "double";
275 char first = el->GetTypeNameBasic()[0];
276 if ((first == 'B') || (first == 'b'))
277 return "bool";
278 return "unsigned char";
279 }
280 case TVirtualStreamerInfo::kBool: return "bool";
281 case TVirtualStreamerInfo::kUShort: return "unsigned short";
282 case TVirtualStreamerInfo::kUInt: return "unsigned int";
283 case TVirtualStreamerInfo::kULong: return "unsigned long";
284 case TVirtualStreamerInfo::kULong64: return "unsigned long long";
285 }
286 return "int";
287}
288
289////////////////////////////////////////////////////////////////////////////////
290/// return functions name to read simple data type from xml file
291
293{
295 return "ReadInt";
296
297 switch (type % 20) {
298 case TVirtualStreamerInfo::kChar: return "ReadChar";
299 case TVirtualStreamerInfo::kShort: return "ReadShort";
300 case TVirtualStreamerInfo::kInt: return "ReadInt";
301 case TVirtualStreamerInfo::kLong: return "ReadLong";
302 case TVirtualStreamerInfo::kLong64: return "ReadLong64";
304 case TVirtualStreamerInfo::kFloat: return "ReadFloat";
306 case TVirtualStreamerInfo::kDouble: return "ReadDouble";
308 Bool_t isbool = false;
309 if (realname)
310 isbool = (TString(realname).Index("bool", 0, TString::kIgnoreCase) >= 0);
311 if (isbool)
312 return "ReadBool";
313 return "ReadUChar";
314 }
315 case TVirtualStreamerInfo::kBool: return "ReadBool";
316 case TVirtualStreamerInfo::kUShort: return "ReadUShort";
317 case TVirtualStreamerInfo::kUInt: return "ReadUInt";
318 case TVirtualStreamerInfo::kULong: return "ReadULong";
319 case TVirtualStreamerInfo::kULong64: return "ReadULong64";
320 }
321 return "ReadValue";
322}
323
324////////////////////////////////////////////////////////////////////////////////
325/// produce code to access member of given class.
326/// Parameter specials has following meaning:
327/// 0 - nothing special
328/// 1 - cast to data type
329/// 2 - produce pointer on given member
330/// 3 - skip casting when produce pointer by buf.P() function
331
332const char *TXMLPlayer::ElementGetter(TClass *cl, const char *membername, int specials)
333{
334 TClass *membercl = cl ? cl->GetBaseDataMember(membername) : nullptr;
335 TDataMember *member = membercl ? membercl->GetDataMember(membername) : nullptr;
336 TMethodCall *mgetter = member ? member->GetterMethod(nullptr) : nullptr;
337
338 if (mgetter && (mgetter->GetMethod()->Property() & kIsPublic)) {
339 fGetterName = "obj->";
340 fGetterName += mgetter->GetMethodName();
341 fGetterName += "()";
342 } else if (!member || ((member->Property() & kIsPublic) != 0)) {
343 fGetterName = "obj->";
345 } else {
346 fGetterName = "";
347 Bool_t deref = (member->GetArrayDim() == 0) && (specials != 2);
348 if (deref)
349 fGetterName += "*(";
350 if (specials != 3) {
351 fGetterName += "(";
352 if (member->Property() & kIsConstant)
353 fGetterName += "const ";
355 if (member->IsaPointer())
356 fGetterName += "*";
357 fGetterName += "*) ";
358 }
359 fGetterName += "buf.P(obj,";
360 fGetterName += member->GetOffset();
361 fGetterName += ")";
362 if (deref)
363 fGetterName += ")";
364 specials = 0;
365 }
366
367 if ((specials == 1) && member) {
368 TString cast = "(";
370 if (member->IsaPointer() || (member->GetArrayDim() > 0))
371 cast += "*";
372 cast += ") ";
373 cast += fGetterName;
375 }
376
377 if ((specials == 2) && member) {
378 TString buf = "&(";
379 buf += fGetterName;
380 buf += ")";
381 fGetterName = buf;
382 }
383
384 return fGetterName.Data();
385}
386
387////////////////////////////////////////////////////////////////////////////////
388/// Produce code to set value to given data member.
389/// endch should be output after value is specified.
390
391const char *TXMLPlayer::ElementSetter(TClass *cl, const char *membername, char *endch)
392{
393 strcpy(endch, ""); // NOLINT
394
395 TClass *membercl = cl ? cl->GetBaseDataMember(membername) : nullptr;
396 TDataMember *member = membercl ? membercl->GetDataMember(membername) : nullptr;
397 TMethodCall *msetter = member ? member->SetterMethod(cl) : nullptr;
398
399 if (msetter && (msetter->GetMethod()->Property() & kIsPublic)) {
400 fSetterName = "obj->";
401 fSetterName += msetter->GetMethodName();
402 fSetterName += "(";
403 strcpy(endch, ")"); // NOLINT
404 } else if (!member || (member->Property() & kIsPublic) != 0) {
405 fSetterName = "obj->";
407 fSetterName += " = ";
408 } else {
409 fSetterName = "";
410 if (member->GetArrayDim() == 0)
411 fSetterName += "*";
412 fSetterName += "((";
413 if (member->Property() & kIsConstant)
414 fSetterName += "const ";
416 if (member->IsaPointer())
417 fSetterName += "*";
418 fSetterName += "*) buf.P(obj,";
419 fSetterName += member->GetOffset();
420 fSetterName += ")) = ";
421 }
422 return fSetterName.Data();
423}
424
425////////////////////////////////////////////////////////////////////////////////
426/// Produce source code of streamer function for specified class
427
429{
430 if (!cl)
431 return;
433 TObjArray *elements = info->GetElements();
434 if (!elements)
435 return;
436
437 fs << "//__________________________________________________________________________" << std::endl;
438 fs << "void* " << GetStreamerName(cl) << "(" << names_xmlfileclass << " &buf, void* ptr, bool checktypes)"
439 << std::endl;
440 fs << "{" << std::endl;
441 fs << tab1 << cl->GetName() << " *obj = (" << cl->GetName() << "*) ptr;" << std::endl;
442
443 fs << tab1 << "if (buf.IsReading()) { " << std::endl;
444
445 TIter iter(cllist);
446 TClass *c1 = nullptr;
447 Bool_t firstchild = true;
448
449 while ((c1 = (TClass *)iter()) != nullptr) {
450 if (c1 == cl)
451 continue;
452 if (!c1->GetListOfBases()->FindObject(cl->GetName()))
453 continue;
454 if (firstchild) {
455 fs << tab2 << "if (checktypes) {" << std::endl;
456 fs << tab3 << "void* ";
457 firstchild = false;
458 } else
459 fs << tab3;
460 fs << "res = " << GetStreamerName(c1) << "(buf, dynamic_cast<" << c1->GetName() << "*>(obj));" << std::endl;
461 fs << tab3 << "if (res) return dynamic_cast<" << cl->GetName() << "*>((" << c1->GetName() << " *) res);"
462 << std::endl;
463 }
464 if (!firstchild)
465 fs << tab2 << "}" << std::endl;
466
467 fs << tab2 << "if (!buf.CheckClassNode(\"" << cl->GetName() << "\", " << info->GetClassVersion() << ")) return 0;"
468 << std::endl;
469
470 fs << tab2 << "if (obj==0) obj = new " << cl->GetName() << ";" << std::endl;
471
472 int n;
473 for (n = 0; n <= elements->GetLast(); n++) {
474
475 TStreamerElement *el = dynamic_cast<TStreamerElement *>(elements->At(n));
476 if (!el)
477 continue;
478
479 Int_t typ = el->GetType();
480
481 switch (typ) {
482 // basic types
499 char endch[5];
500 fs << tab2 << ElementSetter(cl, el->GetName(), endch);
501 fs << "buf." << GetBasicTypeReaderMethodName(el->GetType(), nullptr) << "(\"" << el->GetName() << "\")" << endch
502 << ";" << std::endl;
503 continue;
504 }
505
506 // array of basic types like bool[10]
522 fs << tab2 << "buf.ReadArray(" << ElementGetter(cl, el->GetName(), (el->GetArrayDim() > 1) ? 1 : 0);
523 fs << ", " << el->GetArrayLength() << ", \"" << el->GetName() << "\");" << std::endl;
524 continue;
525 }
526
527 // array of basic types like bool[n]
544 if (!elp) {
545 std::cout << "fatal error with TStreamerBasicPointer" << std::endl;
546 continue;
547 }
548 char endch[5];
549
550 fs << tab2 << ElementSetter(cl, el->GetName(), endch);
551 fs << "buf.ReadArray(" << ElementGetter(cl, el->GetName());
552 fs << ", " << ElementGetter(cl, elp->GetCountName());
553 fs << ", \"" << el->GetName() << "\", true)" << endch << ";" << std::endl;
554 continue;
555 }
556
558 char endch[5];
559 fs << tab2 << ElementSetter(cl, el->GetName(), endch);
560 fs << "buf.ReadCharStar(" << ElementGetter(cl, el->GetName());
561 fs << ", \"" << el->GetName() << "\")" << endch << ";" << std::endl;
562 continue;
563 }
564
566 fs << tab2 << GetStreamerName(el->GetClassPointer()) << "(buf, dynamic_cast<"
567 << el->GetClassPointer()->GetName() << "*>(obj), false);" << std::endl;
568 continue;
569 }
570
571 // Class* Class not derived from TObject and with comment field //->
574 if (el->GetArrayLength() > 0) {
575 fs << tab2 << "buf.ReadObjectArr(" << ElementGetter(cl, el->GetName());
576 fs << ", " << el->GetArrayLength() << ", -1"
577 << ", \"" << el->GetName() << "\", " << GetStreamerName(el->GetClassPointer()) << ");" << std::endl;
578 } else {
579 fs << tab2 << "buf.ReadObject(" << ElementGetter(cl, el->GetName());
580 fs << ", \"" << el->GetName() << "\", " << GetStreamerName(el->GetClassPointer()) << ");" << std::endl;
581 }
582 continue;
583 }
584
585 // Class* Class not derived from TObject and no comment
588 if (el->GetArrayLength() > 0) {
589 fs << tab2 << "for (int n=0;n<" << el->GetArrayLength() << ";n++) "
590 << "delete (" << ElementGetter(cl, el->GetName()) << ")[n];" << std::endl;
591 fs << tab2 << "buf.ReadObjectPtrArr((void**) " << ElementGetter(cl, el->GetName(), 3);
592 fs << ", " << el->GetArrayLength() << ", \"" << el->GetName() << "\", "
593 << GetStreamerName(el->GetClassPointer()) << ");" << std::endl;
594 } else {
595 char endch[5];
596
597 fs << tab2 << "delete " << ElementGetter(cl, el->GetName()) << ";" << std::endl;
598 fs << tab2 << ElementSetter(cl, el->GetName(), endch);
599 fs << "(" << el->GetClassPointer()->GetName() << "*) buf.ReadObjectPtr(\"" << el->GetName() << "\", "
600 << GetStreamerName(el->GetClassPointer()) << ")" << endch << ";" << std::endl;
601 }
602 continue;
603 }
604
605 // Class NOT derived from TObject
607 fs << tab2 << "buf.ReadObject(" << ElementGetter(cl, el->GetName(), 2);
608 fs << ", \"" << el->GetName() << "\", " << GetStreamerName(el->GetClassPointer()) << ");" << std::endl;
609 continue;
610 }
611
612 // Class NOT derived from TObject, array
614 fs << tab2 << "buf.ReadObjectArr(" << ElementGetter(cl, el->GetName());
615 fs << ", " << el->GetArrayLength() << ", sizeof(" << el->GetClassPointer()->GetName() << "), \""
616 << el->GetName() << "\", " << GetStreamerName(el->GetClassPointer()) << ");" << std::endl;
617 continue;
618 }
619
620 // container with no virtual table (stl) and no comment
625 TStreamerSTL *elstl = dynamic_cast<TStreamerSTL *>(el);
626 if (!elstl)
627 break; // to make skip
628
629 if (ProduceSTLstreamer(fs, cl, elstl, false))
630 continue;
631
632 fs << tab2 << "// STL type = " << elstl->GetSTLtype() << std::endl;
633 break;
634 }
635 }
636 fs << tab2 << "buf.SkipMember(\"" << el->GetName() << "\"); // sinfo type " << el->GetType() << " of class "
637 << el->GetClassPointer()->GetName() << " not supported" << std::endl;
638 }
639
640 fs << tab2 << "buf.EndClassNode();" << std::endl;
641
642 fs << tab1 << "} else {" << std::endl;
643
644 // generation of writing part of class streamer
645
646 fs << tab2 << "if (obj==0) return 0;" << std::endl;
647
648 firstchild = true;
649 iter.Reset();
650 while ((c1 = (TClass *)iter()) != nullptr) {
651 if (c1 == cl)
652 continue;
653 if (!c1->GetListOfBases()->FindObject(cl->GetName()))
654 continue;
655 if (firstchild) {
656 firstchild = false;
657 fs << tab2 << "if (checktypes) {" << std::endl;
658 }
659 fs << tab3 << "if (dynamic_cast<" << c1->GetName() << "*>(obj))" << std::endl;
660 fs << tab4 << "return " << GetStreamerName(c1) << "(buf, dynamic_cast<" << c1->GetName() << "*>(obj));"
661 << std::endl;
662 }
663 if (!firstchild)
664 fs << tab2 << "}" << std::endl;
665
666 fs << tab2 << "buf.StartClassNode(\"" << cl->GetName() << "\", " << info->GetClassVersion() << ");" << std::endl;
667
668 for (n = 0; n <= elements->GetLast(); n++) {
669
670 TStreamerElement *el = dynamic_cast<TStreamerElement *>(elements->At(n));
671 if (!el)
672 continue;
673
674 Int_t typ = el->GetType();
675
676 switch (typ) {
677 // write basic types
694 fs << tab2 << "buf.WriteValue(";
696 fs << "(unsigned char) " << ElementGetter(cl, el->GetName());
697 else
698 fs << ElementGetter(cl, el->GetName());
699 fs << ", \"" << el->GetName() << "\");" << std::endl;
700 continue;
701 }
702
703 // array of basic types
719 fs << tab2 << "buf.WriteArray(" << ElementGetter(cl, el->GetName(), (el->GetArrayDim() > 1) ? 1 : 0);
720 fs << ", " << el->GetArrayLength() << ", \"" << el->GetName() << "\");" << std::endl;
721 continue;
722 }
723
740 if (!elp) {
741 std::cout << "fatal error with TStreamerBasicPointer" << std::endl;
742 continue;
743 }
744 fs << tab2 << "buf.WriteArray(" << ElementGetter(cl, el->GetName());
745 fs << ", " << ElementGetter(cl, elp->GetCountName()) << ", \"" << el->GetName() << "\", true);" << std::endl;
746 continue;
747 }
748
750 fs << tab2 << "buf.WriteCharStar(" << ElementGetter(cl, el->GetName()) << ", \"" << el->GetName() << "\");"
751 << std::endl;
752 continue;
753 }
754
756 fs << tab2 << GetStreamerName(el->GetClassPointer()) << "(buf, dynamic_cast<"
757 << el->GetClassPointer()->GetName() << "*>(obj), false);" << std::endl;
758 continue;
759 }
760
761 // Class* Class not derived from TObject and with comment field //->
764 if (el->GetArrayLength() > 0) {
765 fs << tab2 << "buf.WriteObjectArr(" << ElementGetter(cl, el->GetName());
766 fs << ", " << el->GetArrayLength() << ", -1"
767 << ", \"" << el->GetName() << "\", " << GetStreamerName(el->GetClassPointer()) << ");" << std::endl;
768 } else {
769 fs << tab2 << "buf.WriteObject(" << ElementGetter(cl, el->GetName());
770 fs << ", \"" << el->GetName() << "\", " << GetStreamerName(el->GetClassPointer()) << ");" << std::endl;
771 }
772 continue;
773 }
774
775 // Class* Class not derived from TObject and no comment
778 if (el->GetArrayLength() > 0) {
779 fs << tab2 << "buf.WriteObjectPtrArr((void**) " << ElementGetter(cl, el->GetName(), 3);
780 fs << ", " << el->GetArrayLength() << ", \"" << el->GetName() << "\", "
781 << GetStreamerName(el->GetClassPointer()) << ");" << std::endl;
782 } else {
783 fs << tab2 << "buf.WriteObjectPtr(" << ElementGetter(cl, el->GetName());
784 fs << ", \"" << el->GetName() << "\", " << GetStreamerName(el->GetClassPointer()) << ");" << std::endl;
785 }
786 continue;
787 }
788
789 case TVirtualStreamerInfo::kAny: { // Class NOT derived from TObject
790 fs << tab2 << "buf.WriteObject(" << ElementGetter(cl, el->GetName(), 2);
791 fs << ", \"" << el->GetName() << "\", " << GetStreamerName(el->GetClassPointer()) << ");" << std::endl;
792 continue;
793 }
794
796 fs << tab2 << "buf.WriteObjectArr(" << ElementGetter(cl, el->GetName());
797 fs << ", " << el->GetArrayLength() << ", sizeof(" << el->GetClassPointer()->GetName() << "), \""
798 << el->GetName() << "\", " << GetStreamerName(el->GetClassPointer()) << ");" << std::endl;
799 continue;
800 }
801
802 // container with no virtual table (stl) and no comment
807 TStreamerSTL *elstl = dynamic_cast<TStreamerSTL *>(el);
808 if (!elstl)
809 break; // to make skip
810
811 if (ProduceSTLstreamer(fs, cl, elstl, true))
812 continue;
813 fs << tab2 << "// STL type = " << elstl->GetSTLtype() << std::endl;
814 break;
815 }
816 }
817 fs << tab2 << "buf.MakeEmptyMember(\"" << el->GetName() << "\"); // sinfo type " << el->GetType()
818 << " of class " << el->GetClassPointer()->GetName() << " not supported" << std::endl;
819 }
820
821 fs << tab2 << "buf.EndClassNode();" << std::endl;
822
823 fs << tab1 << "}" << std::endl;
824 fs << tab1 << "return obj;" << std::endl;
825 fs << "}" << std::endl << std::endl;
826}
827
828////////////////////////////////////////////////////////////////////////////////
829/// Produce code to read argument of stl container from xml file
830
833{
834 switch (argtyp) {
851 fs << tname << " " << argname << " = buf." << GetBasicTypeReaderMethodName(argtyp, tname.Data()) << "(0);"
852 << std::endl;
853 break;
854 }
855
857 fs << tname << (isargptr ? " " : " *") << argname << " = "
858 << "(" << argcl->GetName() << "*)"
859 << "buf.ReadObjectPtr(0, " << GetStreamerName(argcl) << ");" << std::endl;
860 if (!isargptr) {
861 if (ifcond.Length() > 0)
862 ifcond += " && ";
863 ifcond += argname;
864 TString buf = "*";
865 buf += argname;
866 argname = buf;
867 }
868 break;
869 }
870
872 fs << "string *" << argname << " = "
873 << "buf.ReadSTLstring();" << std::endl;
874 if (!isargptr) {
875 if (ifcond.Length() > 0)
876 ifcond += " && ";
877 ifcond += argname;
878 TString buf = "*";
879 buf += argname;
880 argname = buf;
881 }
882 break;
883 }
884
885 default: fs << "/* argument " << argname << " not supported */";
886 }
887}
888
889////////////////////////////////////////////////////////////////////////////////
890/// Produce code to write argument of stl container to xml file
891
892void TXMLPlayer::WriteSTLarg(std::ostream &fs, const char *accname, int argtyp, Bool_t isargptr, TClass *argcl)
893{
894 switch (argtyp) {
911 fs << "buf.WriteValue(" << accname << ", 0);" << std::endl;
912 break;
913 }
914
916 fs << "buf.WriteObjectPtr(";
917 if (isargptr)
918 fs << accname;
919 else
920 fs << "&(" << accname << ")";
921 fs << ", 0, " << GetStreamerName(argcl) << ");" << std::endl;
922 break;
923 }
924
926 fs << "buf.WriteSTLstring(";
927 if (isargptr)
928 fs << accname;
929 else
930 fs << "&(" << accname << ")";
931 fs << ");" << std::endl;
932 break;
933 }
934
935 default: fs << "/* argument not supported */" << std::endl;
936 }
937}
938
939////////////////////////////////////////////////////////////////////////////////
940/// Produce code of xml streamer for data member of stl type
941
943{
944 if (!cl || !el)
945 return false;
946
947 TClass *contcl = el->GetClassPointer();
948
949 Bool_t isstr = (el->GetSTLtype() == ROOT::kSTLstring);
950 Bool_t isptr = el->IsaPointer();
951 Bool_t isarr = (el->GetArrayLength() > 0);
952 Bool_t isparent = (strcmp(el->GetName(), contcl->GetName()) == 0);
953
954 int stltyp = -1;
955 int narg = 0;
956 int argtype[2];
957 Bool_t isargptr[2];
958 TClass *argcl[2];
959 TString argtname[2];
960
961 if (!isstr && contcl->GetCollectionType() != ROOT::kNotSTL) {
962 int nestedLoc = 0;
963 std::vector<std::string> splitName;
965
966 stltyp = contcl->GetCollectionType();
967 switch (stltyp) {
968 case ROOT::kSTLvector: narg = 1; break;
969 case ROOT::kSTLlist: narg = 1; break;
970 case ROOT::kSTLforwardlist: narg = 1; break;
971 case ROOT::kSTLdeque: narg = 1; break;
972 case ROOT::kSTLmap: narg = 2; break;
973 case ROOT::kSTLmultimap: narg = 2; break;
974 case ROOT::kSTLset: narg = 1; break;
975 case ROOT::kSTLmultiset: narg = 1; break;
976 case ROOT::kSTLunorderedset: narg = 1; break;
977 case ROOT::kSTLunorderedmultiset: narg = 1; break;
978 case ROOT::kSTLunorderedmap: narg = 2; break;
979 case ROOT::kSTLunorderedmultimap: narg = 2; break;
980 case ROOT::kROOTRVec: narg = 1; break;
981
982 default: return false;
983 }
984
985 for (int n = 0; n < narg; n++) {
986 argtype[n] = -1;
987 isargptr[n] = false;
988 argcl[n] = nullptr;
989 argtname[n] = "";
990
991 TString buf = splitName[n + 1];
992
993 argtname[n] = buf;
994
995 // nested STL containers not yet supported
996 if (TClassEdit::IsSTLCont(buf.Data()))
997 return false;
998
999 int pstar = buf.Index("*");
1000
1001 if (pstar > 0) {
1002 isargptr[n] = true;
1003 pstar--;
1004 while ((pstar > 0) && (buf[pstar] == ' '))
1005 pstar--;
1006 buf.Remove(pstar + 1);
1007 } else
1008 isargptr[n] = false;
1009
1010 if (buf.Index("const ") == 0) {
1011 buf.Remove(0, 6);
1012 while ((buf.Length() > 0) && (buf[0] == ' '))
1013 buf.Remove(0, 1);
1014 }
1015
1016 TDataType *dt = (TDataType *)gROOT->GetListOfTypes()->FindObject(buf);
1017 if (dt)
1018 argtype[n] = dt->GetType();
1019 else if (buf == "string")
1021 else {
1022 argcl[n] = TClass::GetClass(buf);
1023 if (argcl[n])
1025 }
1026 if (argtype[n] < 0)
1027 stltyp = -1;
1028 } // for narg
1029
1030 if (stltyp < 0)
1031 return false;
1032 }
1033
1034 Bool_t akaarrayaccess = (narg == 1) && (argtype[0] < 20);
1035
1036 char tabs[30], tabs2[30];
1037
1038 if (isWriting) {
1039
1040 fs << tab2 << "if (buf.StartSTLnode(\"" << fXmlSetup.XmlGetElementName(el) << "\")) {" << std::endl;
1041
1042 fs << tab3 << contcl->GetName() << " ";
1043
1045 if (isptr) {
1046 if (isarr) {
1047 fs << "**cont";
1048 accname = "(*cont)->";
1049 } else {
1050 fs << "*cont";
1051 accname = "cont->";
1052 }
1053 } else if (isarr) {
1054 fs << "*cont";
1055 accname = "cont->";
1056 } else {
1057 fs << "&cont";
1058 accname = "cont.";
1059 }
1060
1061 fs << " = ";
1062
1063 if (isparent)
1064 fs << "*dynamic_cast<" << contcl->GetName() << "*>(obj);" << std::endl;
1065 else
1066 fs << ElementGetter(cl, el->GetName()) << ";" << std::endl;
1067
1068 if (isarr && el->GetArrayLength()) {
1069 strlcpy(tabs, tab4, sizeof(tabs));
1070 fs << tab3 << "for(int n=0;n<" << el->GetArrayLength() << ";n++) {" << std::endl;
1071 } else
1072 strlcpy(tabs, tab3, sizeof(tabs));
1073
1074 strlcpy(tabs2, tabs, sizeof(tabs2));
1075
1076 if (isptr) {
1077 strlcat(tabs2, tab1, sizeof(tabs2));
1078 fs << tabs << "if (" << (isarr ? "*cont" : "cont") << "==0) {" << std::endl;
1079 fs << tabs2 << "buf.WriteSTLsize(0" << (isstr ? ",true);" : ");") << std::endl;
1080 fs << tabs << "} else {" << std::endl;
1081 }
1082
1083 fs << tabs2 << "buf.WriteSTLsize(" << accname << (isstr ? "length(), true);" : "size());") << std::endl;
1084
1085 if (isstr) {
1086 fs << tabs2 << "buf.WriteSTLstringData(" << accname << "c_str());" << std::endl;
1087 } else {
1088 if (akaarrayaccess) {
1089 fs << tabs2 << argtname[0] << "* arr = new " << argtname[0] << "[" << accname << "size()];" << std::endl;
1090 fs << tabs2 << "int k = 0;" << std::endl;
1091 }
1092
1093 fs << tabs2 << contcl->GetName() << "::const_iterator iter;" << std::endl;
1094 fs << tabs2 << "for (iter = " << accname << "begin(); iter != " << accname << "end(); iter++)";
1095 if (akaarrayaccess) {
1096 fs << std::endl << tabs2 << tab1 << "arr[k++] = *iter;" << std::endl;
1097 fs << tabs2 << "buf.WriteArray(arr, " << accname << "size(), 0, false);" << std::endl;
1098 fs << tabs2 << "delete[] arr;" << std::endl;
1099 } else if (narg == 1) {
1100 fs << std::endl << tabs2 << tab1;
1101 WriteSTLarg(fs, "*iter", argtype[0], isargptr[0], argcl[0]);
1102 } else if (narg == 2) {
1103 fs << " {" << std::endl;
1104 fs << tabs2 << tab1;
1105 WriteSTLarg(fs, "iter->first", argtype[0], isargptr[0], argcl[0]);
1106 fs << tabs2 << tab1;
1107 WriteSTLarg(fs, "iter->second", argtype[1], isargptr[1], argcl[1]);
1108 fs << tabs2 << "}" << std::endl;
1109 }
1110 } // if (isstr)
1111
1112 if (isptr)
1113 fs << tabs << "}" << std::endl;
1114
1115 if (isarr && el->GetArrayLength()) {
1116 if (isptr)
1117 fs << tabs << "cont++;" << std::endl;
1118 else
1119 fs << tabs << "(void*) cont = (char*) cont + sizeof(" << contcl->GetName() << ");" << std::endl;
1120 fs << tab3 << "}" << std::endl;
1121 }
1122
1123 fs << tab3 << "buf.EndSTLnode();" << std::endl;
1124 fs << tab2 << "}" << std::endl;
1125
1126 } else {
1127
1128 fs << tab2 << "if (buf.VerifySTLnode(\"" << fXmlSetup.XmlGetElementName(el) << "\")) {" << std::endl;
1129
1130 fs << tab3 << contcl->GetName() << " ";
1132 if (isptr) {
1133 if (isarr) {
1134 fs << "**cont";
1135 accname = "(*cont)->";
1136 accptr = "*cont";
1137 } else {
1138 fs << "*cont";
1139 accname = "cont->";
1140 accptr = "cont";
1141 }
1142 } else if (isarr) {
1143 fs << "*cont";
1144 accname = "cont->";
1145 } else {
1146 fs << "&cont";
1147 accname = "cont.";
1148 }
1149
1150 fs << " = ";
1151
1152 if (isparent)
1153 fs << "*dynamic_cast<" << contcl->GetName() << "*>(obj);" << std::endl;
1154 else
1155 fs << ElementGetter(cl, el->GetName()) << ";" << std::endl;
1156
1157 if (isarr && el->GetArrayLength()) {
1158 strlcpy(tabs, tab4, sizeof(tabs));
1159 fs << tab3 << "for(int n=0;n<" << el->GetArrayLength() << ";n++) {" << std::endl;
1160 } else
1161 strlcpy(tabs, tab3, sizeof(tabs));
1162
1163 fs << tabs << "int size = buf.ReadSTLsize(" << (isstr ? "true);" : ");") << std::endl;
1164
1165 if (isptr) {
1166 fs << tabs << "delete " << accptr << ";" << std::endl;
1167 fs << tabs << "if (size==0) " << accptr << " = 0;" << std::endl;
1168 fs << tabs << " else " << accptr << " = new " << contcl->GetName() << ";" << std::endl;
1169 if (!isarr) {
1170 char endch[5];
1171 fs << tabs << ElementSetter(cl, el->GetName(), endch);
1172 fs << "cont" << endch << ";" << std::endl;
1173 }
1174 } else {
1175 fs << tabs << accname << (isstr ? "erase();" : "clear();") << std::endl;
1176 }
1177
1178 if (isstr) {
1179 fs << tabs << "if (size>0) " << accname << "assign(buf.ReadSTLstringData(size));" << std::endl;
1180 } else {
1181 if (akaarrayaccess) {
1182 fs << tabs << argtname[0] << "* arr = new " << argtname[0] << "[size];" << std::endl;
1183 fs << tabs << "buf.ReadArray(arr, size, 0, false);" << std::endl;
1184 }
1185
1186 fs << tabs << "for(int k=0;k<size;k++)";
1187
1188 if (akaarrayaccess) {
1189 fs << std::endl << tabs << tab1 << accname;
1191 fs << "insert";
1192 else
1193 fs << "push_back";
1194 fs << "(arr[k]);" << std::endl;
1195 fs << tabs << "delete[] arr;" << std::endl;
1196 } else if (narg == 1) {
1197 TString arg1("arg"), ifcond;
1198 fs << " {" << std::endl << tabs << tab1;
1200 fs << tabs << tab1;
1201 if (ifcond.Length() > 0)
1202 fs << "if (" << ifcond << ") ";
1203 fs << accname;
1205 fs << "insert";
1206 else
1207 fs << "push_back";
1208 fs << "(" << arg1 << ");" << std::endl;
1209 fs << tabs << "}" << std::endl;
1210 } else if (narg == 2) {
1211 TString arg1("arg1"), arg2("arg2"), ifcond;
1212 fs << " {" << std::endl << tabs << tab1;
1214 fs << tabs << tab1;
1216 fs << tabs << tab1;
1217 if (ifcond.Length() > 0)
1218 fs << "if (" << ifcond << ") ";
1219 fs << accname << "insert(make_pair(" << arg1 << ", " << arg2 << "));" << std::endl;
1220 fs << tabs << "}" << std::endl;
1221 }
1222 }
1223
1224 if (isarr && el->GetArrayLength()) {
1225 if (isptr)
1226 fs << tabs << "cont++;" << std::endl;
1227 else
1228 fs << tabs << "(void*) cont = (char*) cont + sizeof(" << contcl->GetName() << ");" << std::endl;
1229 fs << tab3 << "}" << std::endl;
1230 }
1231
1232 fs << tab3 << "buf.EndSTLnode();" << std::endl;
1233 fs << tab2 << "}" << std::endl;
1234 }
1235 return true;
1236}
constexpr Bool_t kFALSE
Definition RtypesCore.h:108
constexpr Bool_t kTRUE
Definition RtypesCore.h:107
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
@ kFloat_t
Definition TDataType.h:31
@ kULong64_t
Definition TDataType.h:32
@ kInt_t
Definition TDataType.h:30
@ kLong_t
Definition TDataType.h:30
@ kDouble32_t
Definition TDataType.h:31
@ kShort_t
Definition TDataType.h:29
@ kBool_t
Definition TDataType.h:32
@ kULong_t
Definition TDataType.h:30
@ kLong64_t
Definition TDataType.h:32
@ kUShort_t
Definition TDataType.h:29
@ kDouble_t
Definition TDataType.h:31
@ kChar_t
Definition TDataType.h:29
@ kUChar_t
Definition TDataType.h:29
@ kUInt_t
Definition TDataType.h:30
@ kFloat16_t
Definition TDataType.h:33
@ kIsPublic
Definition TDictionary.h:75
@ kIsConstant
Definition TDictionary.h:88
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char filename
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize fs
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h Atom_t Int_t ULong_t ULong_t unsigned char prop_list Atom_t Atom_t Atom_t Time_t type
#define gROOT
Definition TROOT.h:411
const char * tab1
const char * tab3
const char * tab2
const char * tab4
const char * names_xmlfileclass
TClass instances represent classes, structs and namespaces in the ROOT type system.
Definition TClass.h:84
TVirtualStreamerInfo * GetStreamerInfo(Int_t version=0, Bool_t isTransient=kFALSE) const
returns a pointer to the TVirtualStreamerInfo object for version If the object does not exist,...
Definition TClass.cxx:4626
TClass * GetBaseDataMember(const char *datamember)
Return pointer to (base) class that contains datamember.
Definition TClass.cxx:2832
const char * GetDeclFileName() const
Return name of the file containing the declaration of this class.
Definition TClass.cxx:3494
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:2973
All ROOT classes may have RTTI (run time type identification) support added.
Definition TDataMember.h:31
Basic data type descriptor (datatype information is obtained from CINT).
Definition TDataType.h:44
void Reset()
A doubly linked list.
Definition TList.h:38
Method or function calling interface.
Definition TMethodCall.h:37
The TNamed class is the base class for all named ROOT classes.
Definition TNamed.h:29
const char * GetName() const override
Returns name of object.
Definition TNamed.h:49
An array of TObjects.
Definition TObjArray.h:31
TObject * At(Int_t idx) const override
Definition TObjArray.h:164
Int_t GetLast() const override
Return index of last object in array.
Mother of all ROOT objects.
Definition TObject.h:41
Describe one element (data member) to be Streamed.
Basic string class.
Definition TString.h:138
Ssiz_t Length() const
Definition TString.h:425
const char * Data() const
Definition TString.h:384
@ kIgnoreCase
Definition TString.h:285
TString & Remove(Ssiz_t pos)
Definition TString.h:693
Ssiz_t Index(const char *pat, Ssiz_t i=0, ECaseCompare cmp=kExact) const
Definition TString.h:659
Abstract Interface class describing Streamer information for one class.
@ kUChar
Equal to TDataType's kchar.
TString GetMemberTypeName(TDataMember *member)
returns name of simple data type for given data member
Bool_t ProduceCode(TList *cllist, const char *filename)
Produce streamers for provide class list TList should include list of classes, for which code should ...
TString GetStreamerName(TClass *cl)
returns streamer function name for given class
TString fSetterName
buffer for name of getter method
Definition TXMLPlayer.h:49
const char * ElementGetter(TClass *cl, const char *membername, int specials=0)
produce code to access member of given class.
TXMLSetup fXmlSetup
buffer for name of setter method
Definition TXMLPlayer.h:50
~TXMLPlayer() override
destructor of TXMLPlayer object
TString GetBasicTypeName(TStreamerElement *el)
return simple data types for given TStreamerElement object
void ReadSTLarg(std::ostream &fs, TString &argname, int argtyp, Bool_t isargptr, TClass *argcl, TString &tname, TString &ifcond)
Produce code to read argument of stl container from xml file.
TXMLPlayer()
default constructor
TString GetBasicTypeReaderMethodName(Int_t type, const char *realname)
return functions name to read simple data type from xml file
void ProduceStreamerSource(std::ostream &fs, TClass *cl, TList *cllist)
Produce source code of streamer function for specified class.
TString fGetterName
Definition TXMLPlayer.h:48
Bool_t ProduceSTLstreamer(std::ostream &fs, TClass *cl, TStreamerSTL *el, Bool_t isWriting)
Produce code of xml streamer for data member of stl type.
const char * ElementSetter(TClass *cl, const char *membername, char *endch)
Produce code to set value to given data member.
void WriteSTLarg(std::ostream &fs, const char *accname, int argtyp, Bool_t isargptr, TClass *argcl)
Produce code to write argument of stl container to xml file.
const char * XmlGetElementName(const TStreamerElement *el)
return converted name for TStreamerElement
return c1
Definition legend1.C:41
const Int_t n
Definition legend1.C:16
@ kSTLmap
Definition ESTLType.h:33
@ kSTLunorderedmultiset
Definition ESTLType.h:43
@ kROOTRVec
Definition ESTLType.h:46
@ kSTLstring
Definition ESTLType.h:49
@ kSTLset
Definition ESTLType.h:35
@ kSTLmultiset
Definition ESTLType.h:36
@ kSTLdeque
Definition ESTLType.h:32
@ kSTLvector
Definition ESTLType.h:30
@ kSTLunorderedmultimap
Definition ESTLType.h:45
@ kSTLunorderedset
Definition ESTLType.h:42
@ kSTLlist
Definition ESTLType.h:31
@ kSTLforwardlist
Definition ESTLType.h:41
@ kSTLunorderedmap
Definition ESTLType.h:44
@ kNotSTL
Definition ESTLType.h:29
@ kSTLmultimap
Definition ESTLType.h:34
ROOT::ESTLType IsSTLCont(std::string_view type)
type : type name: vector<list<classA,allocator>,allocator> result: 0 : not stl container code of cont...
int GetSplit(const char *type, std::vector< std::string > &output, int &nestedLoc, EModType mode=TClassEdit::kNone)
Stores in output (after emptying it) the split type.